From 3af63dcf4ab9f052fa7c72974d432bb515005d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Fri, 19 Apr 2024 12:47:59 +0200 Subject: [PATCH 001/548] fix(storage/littlefs): Bump version to v1.14.4 (core v2.9.1) Fixes a bug which causes DivideByZero exception when the filesystem is full --- examples/storage/littlefs/main/idf_component.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/storage/littlefs/main/idf_component.yml b/examples/storage/littlefs/main/idf_component.yml index 427e1c36bde..0056553732a 100644 --- a/examples/storage/littlefs/main/idf_component.yml +++ b/examples/storage/littlefs/main/idf_component.yml @@ -1,3 +1,3 @@ ## IDF Component Manager Manifest File dependencies: - joltwallet/littlefs: "~=1.14.2" + joltwallet/littlefs: "~=1.14.4" From f1b9b357e4863b33a9ec9e7ee7ab4455f1664145 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 23 Apr 2024 01:33:44 +0200 Subject: [PATCH 002/548] change(gitlab): simplify approvals for backports (v5.3) --- .gitlab/CODEOWNERS | 236 +-------------------------------------------- 1 file changed, 1 insertion(+), 235 deletions(-) diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index fc321c42878..b29aceb4050 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -2,239 +2,5 @@ # # https://docs.gitlab.com/ee/user/project/code_owners.html#the-syntax-of-code-owners-files # -# If more than one rule matches a given file, the latest rule is used. -# The file should be generally kept sorted, except when it is necessary -# to use a different order due to the fact above. In that case, use -# '# sort-order-reset' comment line to reset the sort order. -# -# Recipes for a few common cases: -# -# 1. Specific directory with all its contents: -# -# /components/app_trace/ -# -# Note the trailing slash! -# -# 2. File with certain extension in any subdirectory of a certain directory: -# -# /examples/**/*.py -# -# This includes an *.py files in /examples/ directory as well. -# -# 3. Contents of a directory with a certain name, anywhere in the tree: -# -# test_*_host/ -# -# Will match everything under components/efuse/test_efuse_host/, -# components/heap/test_multi_heap_host/, components/lwip/test_afl_host/, etc. -# -# 4. Same as above, except limited to a specific place in the tree: -# -# /components/esp32*/ -# -# Matches everything under /components/esp32, /components/esp32s2, etc. -# Doesn't match /tools/some-test/components/esp32s5. -# -# 5. Specific file: -# -# /tools/tools.json -# -# 6. File with a certain name anywhere in the tree -# -# .gitignore -# - -* @esp-idf-codeowners/other - -/.* @esp-idf-codeowners/tools -/.codespellrc @esp-idf-codeowners/ci -/.github/workflows/ @esp-idf-codeowners/ci -/.gitlab-ci.yml @esp-idf-codeowners/ci -/.gitlab/ci/ @esp-idf-codeowners/ci -/.pre-commit-config.yaml @esp-idf-codeowners/ci -/.readthedocs.yml @esp-idf-codeowners/docs -/.vale.ini @esp-idf-codeowners/docs -/CMakeLists.txt @esp-idf-codeowners/build-config -/COMPATIBILITY*.md @esp-idf-codeowners/peripherals -/CONTRIBUTING.md @esp-idf-codeowners/docs -/Kconfig @esp-idf-codeowners/build-config -/README*.md @esp-idf-codeowners/docs -/SUPPORT_POLICY*.md @esp-idf-codeowners/docs -/add_path.sh @esp-idf-codeowners/tools -/conftest.py @esp-idf-codeowners/ci -/export.* @esp-idf-codeowners/tools -/install.* @esp-idf-codeowners/tools -/pytest.ini @esp-idf-codeowners/ci -/sdkconfig.rename @esp-idf-codeowners/build-config -/sonar-project.properties @esp-idf-codeowners/ci - -# sort-order-reset - -/components/app_trace/ @esp-idf-codeowners/debugging -/components/app_update/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities -/components/bootloader*/ @esp-idf-codeowners/system @esp-idf-codeowners/security -/components/bootloader_support/bootloader_flash/ @esp-idf-codeowners/peripherals -/components/bt/ @esp-idf-codeowners/bluetooth -/components/cmock/ @esp-idf-codeowners/system -/components/console/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities/console -/components/cxx/ @esp-idf-codeowners/system -/components/driver/ @esp-idf-codeowners/peripherals -/components/efuse/ @esp-idf-codeowners/system -/components/esp_adc/ @esp-idf-codeowners/peripherals -/components/esp_app_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities -/components/esp_bootloader_format/ @esp-idf-codeowners/system @esp-idf-codeowners/app-utilities -/components/esp_coex/ @esp-idf-codeowners/wifi @esp-idf-codeowners/bluetooth @esp-idf-codeowners/ieee802154 -/components/esp_common/ @esp-idf-codeowners/system -/components/esp_driver_*/ @esp-idf-codeowners/peripherals -/components/esp_driver_sdmmc/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/storage -/components/esp_eth/ @esp-idf-codeowners/network -/components/esp_event/ @esp-idf-codeowners/system -/components/esp_gdbstub/ @esp-idf-codeowners/debugging -/components/esp_hid/ @esp-idf-codeowners/bluetooth -/components/esp_http_client/ @esp-idf-codeowners/app-utilities -/components/esp_http_server/ @esp-idf-codeowners/app-utilities -/components/esp_https_ota/ @esp-idf-codeowners/app-utilities -/components/esp_https_server/ @esp-idf-codeowners/app-utilities -/components/esp_hw_support/ @esp-idf-codeowners/system @esp-idf-codeowners/peripherals -/components/esp_hw_support/lowpower/ @esp-idf-codeowners/power-management -/components/esp_lcd/ @esp-idf-codeowners/peripherals -/components/esp_local_ctrl/ @esp-idf-codeowners/app-utilities -/components/esp_mm/ @esp-idf-codeowners/peripherals -/components/esp_netif/ @esp-idf-codeowners/network -/components/esp_netif_stack/ @esp-idf-codeowners/network -/components/esp_partition/ @esp-idf-codeowners/storage -/components/esp_phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154 -/components/esp_pm/ @esp-idf-codeowners/power-management @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/system -/components/esp_psram/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system -/components/esp_ringbuf/ @esp-idf-codeowners/system -/components/esp_rom/ @esp-idf-codeowners/system @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi -/components/esp_system/ @esp-idf-codeowners/system -/components/esp_timer/ @esp-idf-codeowners/system -/components/esp-tls/ @esp-idf-codeowners/app-utilities -/components/esp_vfs_*/ @esp-idf-codeowners/storage -/components/esp_vfs_console/ @esp-idf-codeowners/storage @esp-idf-codeowners/system -/components/esp_wifi/ @esp-idf-codeowners/wifi -/components/espcoredump/ @esp-idf-codeowners/debugging -/components/esptool_py/ @esp-idf-codeowners/tools -/components/fatfs/ @esp-idf-codeowners/storage -/components/freertos/ @esp-idf-codeowners/system -/components/hal/ @esp-idf-codeowners/peripherals -/components/heap/ @esp-idf-codeowners/system -/components/http_parser/ @esp-idf-codeowners/app-utilities -/components/idf_test/ @esp-idf-codeowners/ci -/components/ieee802154/ @esp-idf-codeowners/ieee802154 -/components/json/ @esp-idf-codeowners/app-utilities -/components/linux/ @esp-idf-codeowners/system -/components/log/ @esp-idf-codeowners/system -/components/lwip/ @esp-idf-codeowners/lwip -/components/mbedtls/ @esp-idf-codeowners/app-utilities/mbedtls @esp-idf-codeowners/security -/components/mqtt/ @esp-idf-codeowners/network -/components/newlib/ @esp-idf-codeowners/system @esp-idf-codeowners/toolchain -/components/nvs_flash/ @esp-idf-codeowners/storage -/components/nvs_sec_provider/ @esp-idf-codeowners/storage @esp-idf-codeowners/security -/components/openthread/ @esp-idf-codeowners/ieee802154 -/components/partition_table/ @esp-idf-codeowners/system -/components/perfmon/ @esp-idf-codeowners/debugging -/components/protobuf-c/ @esp-idf-codeowners/app-utilities -/components/protocomm/ @esp-idf-codeowners/app-utilities/provisioning -/components/pthread/ @esp-idf-codeowners/system -/components/riscv/ @esp-idf-codeowners/system -/components/sdmmc/ @esp-idf-codeowners/storage -/components/soc/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/system -/components/spi_flash/ @esp-idf-codeowners/peripherals -/components/spiffs/ @esp-idf-codeowners/storage -/components/tcp_transport/ @esp-idf-codeowners/network -/components/touch_element/ @esp-idf-codeowners/peripherals -/components/ulp/ @esp-idf-codeowners/system -/components/unity/ @esp-idf-codeowners/ci -/components/usb/ @esp-idf-codeowners/peripherals/usb -/components/vfs/ @esp-idf-codeowners/storage -/components/wear_levelling/ @esp-idf-codeowners/storage -/components/wifi_provisioning/ @esp-idf-codeowners/app-utilities/provisioning -/components/wpa_supplicant/ @esp-idf-codeowners/wifi @esp-idf-codeowners/app-utilities/mbedtls -/components/xtensa/ @esp-idf-codeowners/system - -/docs/ @esp-idf-codeowners/docs -/docs/**/api-guides/tools/ @esp-idf-codeowners/tools -/docs/en/api-guides/core_dump.rst @esp-idf-codeowners/debugging -/docs/en/api-guides/jtag-debugging/ @esp-idf-codeowners/debugging -/docs/**/api-reference/bluetooth/ @esp-idf-codeowners/bluetooth -/docs/**/api-reference/network/ @esp-idf-codeowners/network @esp-idf-codeowners/wifi -/docs/**/api-reference/peripherals/ @esp-idf-codeowners/peripherals -/docs/**/api-reference/peripherals/usb* @esp-idf-codeowners/peripherals @esp-idf-codeowners/peripherals/usb -/docs/**/api-reference/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities -/docs/**/api-reference/provisioning/ @esp-idf-codeowners/app-utilities/provisioning -/docs/**/api-reference/storage/ @esp-idf-codeowners/storage -/docs/**/api-reference/system/ @esp-idf-codeowners/system -/docs/**/security/ @esp-idf-codeowners/security -/docs/**/migration-guides/ @esp-idf-codeowners/docs @esp-idf-codeowners/all-maintainers - -/examples/README.md @esp-idf-codeowners/docs @esp-idf-codeowners/ci -/examples/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools -/examples/bluetooth/ @esp-idf-codeowners/bluetooth -/examples/build_system/ @esp-idf-codeowners/build-config -/examples/common_components/ @esp-idf-codeowners/system @esp-idf-codeowners/wifi @esp-idf-codeowners/lwip @esp-idf-codeowners/network -/examples/custom_bootloader/ @esp-idf-codeowners/system -/examples/cxx/ @esp-idf-codeowners/system -/examples/ethernet/ @esp-idf-codeowners/network -/examples/get-started/ @esp-idf-codeowners/system -/examples/ieee802154/ @esp-idf-codeowners/ieee802154 -/examples/mesh/ @esp-idf-codeowners/wifi -/examples/network/ @esp-idf-codeowners/network @esp-idf-codeowners/wifi -/examples/openthread/ @esp-idf-codeowners/ieee802154 -/examples/peripherals/ @esp-idf-codeowners/peripherals -/examples/peripherals/usb/ @esp-idf-codeowners/peripherals @esp-idf-codeowners/peripherals/usb -/examples/phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154 -/examples/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities -/examples/provisioning/ @esp-idf-codeowners/app-utilities/provisioning -/examples/security/ @esp-idf-codeowners/security -/examples/storage/ @esp-idf-codeowners/storage -/examples/system/ @esp-idf-codeowners/system -/examples/system/ota/ @esp-idf-codeowners/app-utilities -/examples/wifi/ @esp-idf-codeowners/wifi -/examples/zigbee/ @esp-idf-codeowners/ieee802154 - -/tools/ @esp-idf-codeowners/tools -/tools/ble/ @esp-idf-codeowners/app-utilities -/tools/catch/ @esp-idf-codeowners/ci -/tools/ci/ @esp-idf-codeowners/ci -/tools/cmake/ @esp-idf-codeowners/build-config -/tools/cmake/toolchain-*.cmake @esp-idf-codeowners/toolchain -/tools/esp_app_trace/ @esp-idf-codeowners/debugging -/tools/esp_prov/ @esp-idf-codeowners/app-utilities -/tools/gdb_panic_server.py @esp-idf-codeowners/debugging -/tools/kconfig*/ @esp-idf-codeowners/build-config -/tools/ldgen/ @esp-idf-codeowners/build-config -/tools/mass_mfg/ @esp-idf-codeowners/app-utilities -/tools/mocks/ @esp-idf-codeowners/system - -/tools/test_apps/ @esp-idf-codeowners/ci -/tools/test_apps/README.md @esp-idf-codeowners/docs @esp-idf-codeowners/ci - -## Note: owners here should be the same as the owners for the same example subdir, above -/tools/test_apps/build_system/ @esp-idf-codeowners/build-config -/tools/test_apps/configs/ @esp-idf-codeowners/system -/tools/test_apps/linux_compatible/ @esp-idf-codeowners/system -/tools/test_apps/peripherals/ @esp-idf-codeowners/peripherals -/tools/test_apps/phy/ @esp-idf-codeowners/bluetooth @esp-idf-codeowners/wifi @esp-idf-codeowners/ieee802154 -/tools/test_apps/protocols/ @esp-idf-codeowners/network @esp-idf-codeowners/app-utilities -/tools/test_apps/security/ @esp-idf-codeowners/security -/tools/test_apps/storage/ @esp-idf-codeowners/storage -/tools/test_apps/system/ @esp-idf-codeowners/system - -/tools/test_apps/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools - -/tools/test_build_system/ @esp-idf-codeowners/tools @esp-idf-codeowners/build-config - -/tools/tools.json @esp-idf-codeowners/tools @esp-idf-codeowners/toolchain @esp-idf-codeowners/debugging - -/tools/unit-test-app/ @esp-idf-codeowners/system @esp-idf-codeowners/tools - -# sort-order-reset - -/components/**/test_apps/**/*.py @esp-idf-codeowners/ci @esp-idf-codeowners/tools -# ignore lists -/tools/ci/check_copyright_config.yaml @esp-idf-codeowners/all-maintainers -/tools/ci/check_copyright_ignore.txt @esp-idf-codeowners/all-maintainers -/tools/ci/mypy_ignore_list.txt @esp-idf-codeowners/tools +* @esp-idf-codeowners/all-maintainers From cb5bc35f2e355189ac36449b0ffb13ed99ee9f20 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 28 Mar 2024 14:40:44 +0530 Subject: [PATCH 003/548] fix(nimble): Expose API to set RPA Timeout --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index cc997ecc33f..5adfd2d3c44 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit cc997ecc33fff506baa0629f784bad75be4f16fc +Subproject commit 5adfd2d3c446a25577970c9f767ab034aa517423 From ebe1141b25048949fe23dd3d7c2f6133e254faac Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Mon, 22 Apr 2024 09:56:58 -0500 Subject: [PATCH 004/548] docs: clarify ESP_RETURN_ON_ERROR result --- docs/en/api-guides/error-handling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api-guides/error-handling.rst b/docs/en/api-guides/error-handling.rst index b27fc2ec58d..90e72fe43c4 100644 --- a/docs/en/api-guides/error-handling.rst +++ b/docs/en/api-guides/error-handling.rst @@ -85,7 +85,7 @@ Error message will typically look like this:: ``ESP_RETURN_ON_ERROR`` Macro ----------------------------- -:c:macro:`ESP_RETURN_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message and returns. +:c:macro:`ESP_RETURN_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message and returns the error code. .. _esp-goto-on-error-macro: From fa866b49ca72b56bed4c4e5ad9ed75ba5e39e2a5 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 23 Apr 2024 02:34:25 +0800 Subject: [PATCH 005/548] docs(esp_common): Fix formatting issues in error-handling.rst This commit fixes the following formatting issues in error-handling.rst: - Incorrect indentation (3 spaces to 4 spaces) - Fixed some italics that were supposed to be inline literals - Used code-block directive for language highlighting --- docs/en/api-guides/error-handling.rst | 48 +++++++++++++++++---------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/docs/en/api-guides/error-handling.rst b/docs/en/api-guides/error-handling.rst index 90e72fe43c4..9d22768f45c 100644 --- a/docs/en/api-guides/error-handling.rst +++ b/docs/en/api-guides/error-handling.rst @@ -39,7 +39,7 @@ For the complete list of error codes, see :doc:`Error Code Reference <../api-ref Converting Error Codes to Error Messages ---------------------------------------- -For each error code defined in ESP-IDF components, :cpp:type:`esp_err_t` value can be converted to an error code name using :cpp:func:`esp_err_to_name` or :cpp:func:`esp_err_to_name_r` functions. For example, passing ``0x101`` to :cpp:func:`esp_err_to_name` will return "ESP_ERR_NO_MEM" string. Such strings can be used in log output to make it easier to understand which error has happened. +For each error code defined in ESP-IDF components, :cpp:type:`esp_err_t` value can be converted to an error code name using :cpp:func:`esp_err_to_name` or :cpp:func:`esp_err_to_name_r` functions. For example, passing ``0x101`` to :cpp:func:`esp_err_to_name` will return a ``ESP_ERR_NO_MEM`` string. Such strings can be used in log output to make it easier to understand which error has happened. Additionally, :cpp:func:`esp_err_to_name_r` function will attempt to interpret the error code as a `standard POSIX error code `_, if no matching ``ESP_ERR_`` value is found. This is done using ``strerror_r`` function. POSIX error codes (such as ``ENOENT``, ``ENOMEM``) are defined in ``errno.h`` and are typically obtained from ``errno`` variable. In ESP-IDF this variable is thread-local: multiple FreeRTOS tasks have their own copies of ``errno``. Functions which set ``errno`` only modify its value for the task they run in. @@ -53,7 +53,9 @@ This feature is enabled by default, but can be disabled to reduce application bi :c:macro:`ESP_ERROR_CHECK` macro serves similar purpose as ``assert``, except that it checks :cpp:type:`esp_err_t` value rather than a ``bool`` condition. If the argument of :c:macro:`ESP_ERROR_CHECK` is not equal :c:macro:`ESP_OK`, then an error message is printed on the console, and ``abort()`` is called. -Error message will typically look like this:: +Error message will typically look like this: + +.. code-block:: none ESP_ERROR_CHECK failed: esp_err_t 0x107 (ESP_ERR_TIMEOUT) at 0x400d1fdf @@ -63,7 +65,9 @@ Error message will typically look like this:: Backtrace: 0x40086e7c:0x3ffb4ff0 0x40087328:0x3ffb5010 0x400d1fdf:0x3ffb5030 0x400d0816:0x3ffb5050 -.. note:: If :doc:`ESP-IDF monitor ` is used, addresses in the backtrace will be converted to file names and line numbers. +.. note:: + + If :doc:`ESP-IDF monitor ` is used, addresses in the backtrace will be converted to file names and line numbers. - The first line mentions the error code as a hexadecimal value, and the identifier used for this error in source code. The latter depends on :ref:`CONFIG_ESP_ERR_TO_NAME_LOOKUP` option being set. Address in the program where error has occurred is printed as well. @@ -93,7 +97,7 @@ Error message will typically look like this:: ``ESP_GOTO_ON_ERROR`` Macro --------------------------- -:c:macro:`ESP_GOTO_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message, sets the local variable `ret` to the code, and then exits by jumping to `goto_tag`. +:c:macro:`ESP_GOTO_ON_ERROR` macro checks the error code, if the error code is not equal :c:macro:`ESP_OK`, it prints the message, sets the local variable ``ret`` to the code, and then exits by jumping to ``goto_tag``. .. _esp-return-on-false-macro: @@ -101,7 +105,7 @@ Error message will typically look like this:: ``ESP_RETURN_ON_FALSE`` Macro ----------------------------- -:c:macro:`ESP_RETURN_ON_FALSE` macro checks the condition, if the condition is not equal `true`, it prints the message and returns with the supplied `err_code`. +:c:macro:`ESP_RETURN_ON_FALSE` macro checks the condition, if the condition is not equal ``true``, it prints the message and returns with the supplied ``err_code``. .. _esp-goto-on-false-macro: @@ -109,15 +113,17 @@ Error message will typically look like this:: ``ESP_GOTO_ON_FALSE`` Macro --------------------------- -:c:macro:`ESP_GOTO_ON_FALSE` macro checks the condition, if the condition is not equal `true`, it prints the message, sets the local variable `ret` to the supplied `err_code`, and then exits by jumping to `goto_tag`. +:c:macro:`ESP_GOTO_ON_FALSE` macro checks the condition, if the condition is not equal ``true``, it prints the message, sets the local variable ``ret`` to the supplied ``err_code``, and then exits by jumping to ``goto_tag``. .. _check_macros_examples: -``CHECK MACROS Examples`` +``CHECK MACROS`` Examples ------------------------- -Some examples:: +Some examples + +.. code-block:: c static const char* TAG = "Test"; @@ -139,9 +145,9 @@ Some examples:: .. note:: - If the option :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` in Kconfig is enabled, the err message will be discarded, while the other action works as is. + If the option :ref:`CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT` in Kconfig is enabled, the error message will be discarded, while the other action works as is. - The ``ESP_RETURN_XX`` and ``ESP_GOTO_xx`` macros cannot be called from ISR. While there are ``xx_ISR`` versions for each of them, e.g., `ESP_RETURN_ON_ERROR_ISR`, these macros could be used in ISR. + The ``ESP_RETURN_XX`` and ``ESP_GOTO_xx`` macros cannot be called from ISR. While there are ``xx_ISR`` versions for each of them, e.g., ``ESP_RETURN_ON_ERROR_ISR``, these macros could be used in ISR. Error Handling Patterns @@ -149,11 +155,13 @@ Error Handling Patterns 1. Attempt to recover. Depending on the situation, we may try the following methods: - - retry the call after some time; - - attempt to de-initialize the driver and re-initialize it again; - - fix the error condition using an out-of-band mechanism (e.g reset an external peripheral which is not responding). + - retry the call after some time; + - attempt to de-initialize the driver and re-initialize it again; + - fix the error condition using an out-of-band mechanism (e.g reset an external peripheral which is not responding). - Example:: + Example: + + .. code-block:: c esp_err_t err; do { @@ -166,7 +174,9 @@ Error Handling Patterns 2. Propagate the error to the caller. In some middleware components this means that a function must exit with the same error code, making sure any resource allocations are rolled back. - Example:: + Example: + + .. code-block:: c sdmmc_card_t* card = calloc(1, sizeof(sdmmc_card_t)); if (card == NULL) { @@ -183,11 +193,13 @@ Error Handling Patterns 3. Convert into unrecoverable error, for example using ``ESP_ERROR_CHECK``. See `ESP_ERROR_CHECK macro`_ section for details. - Terminating the application in case of an error is usually undesirable behavior for middleware components, but is sometimes acceptable at application level. + Terminating the application in case of an error is usually undesirable behavior for middleware components, but is sometimes acceptable at application level. + + Many ESP-IDF examples use ``ESP_ERROR_CHECK`` to handle errors from various APIs. This is not the best practice for applications, and is done to make example code more concise. - Many ESP-IDF examples use ``ESP_ERROR_CHECK`` to handle errors from various APIs. This is not the best practice for applications, and is done to make example code more concise. + Example: - Example:: + .. code-block:: c ESP_ERROR_CHECK(spi_bus_initialize(host, bus_config, dma_chan)); From a85d1e1ecaa1c6dc9f820c40f09e2a62c77fe0f1 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Fri, 15 Dec 2023 10:57:53 +0000 Subject: [PATCH 006/548] fix(esp_eth): dp83848: correct link detection to use BMSR Reading the link state via PHYSTS was incorrect, as it only reflects the link state bit from BMSR. BMSR latches link down events, and are not cleared without being read. (See 802.3-2008 section 2, section 22.2.4.2.13) This leads to the original DP828xx code only supporting link up, then a single link down event. Switch to reading the link state via BMSR, but continuing to read the negotiation results via PHYSTS and ANLPAR. This is inline with LAN8720x, RTL8201, KSZ80xx phy drivers, and other opensource drivers for the DP838xx family of devices. Tested on a private board with a DP83825i PHY. No publically available boards using the original DP83848 are known of for testing. Signed-off-by: Karl Palsson --- components/esp_eth/src/esp_eth_phy_dp83848.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/esp_eth_phy_dp83848.c index fc771b072f7..7ae69b24bf1 100644 --- a/components/esp_eth/src/esp_eth_phy_dp83848.c +++ b/components/esp_eth/src/esp_eth_phy_dp83848.c @@ -77,13 +77,15 @@ static esp_err_t dp83848_update_link_duplex_speed(phy_dp83848_t *dp83848) uint32_t peer_pause_ability = false; anlpar_reg_t anlpar; physts_reg_t physts; - ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed"); - ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_STS_REG_ADDR, &(physts.val)), err, TAG, "read PHYSTS failed"); - eth_link_t link = physts.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + bmsr_reg_t bmsr; + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_BMSR_REG_ADDR, &(bmsr.val)), err, TAG, "read BMSR failed"); + eth_link_t link = bmsr.link_status ? ETH_LINK_UP : ETH_LINK_DOWN; /* check if link status changed */ if (dp83848->phy_802_3.link_status != link) { /* when link up, read negotiation result */ if (link == ETH_LINK_UP) { + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_ANLPAR_REG_ADDR, &(anlpar.val)), err, TAG, "read ANLPAR failed"); + ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, addr, ETH_PHY_STS_REG_ADDR, &(physts.val)), err, TAG, "read PHYSTS failed"); if (physts.speed_status) { speed = ETH_SPEED_10M; } else { From 665883229e1ce71226251760d3d4b38cc62c3b49 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 15 Apr 2024 12:12:52 +0800 Subject: [PATCH 007/548] fix(gpio_etm): allow one GPIO binds to multiple ETM tasks --- .../esp_driver_gpio/include/driver/gpio_etm.h | 40 +- components/esp_driver_gpio/src/gpio_etm.c | 381 ++++++++++++------ .../test_apps/etm/main/test_gpio_etm.c | 119 +++++- .../hal/esp32c6/include/hal/gpio_etm_ll.h | 37 +- .../hal/esp32h2/include/hal/gpio_etm_ll.h | 37 +- .../hal/esp32p4/include/hal/gpio_etm_ll.h | 37 +- .../beta3/include/soc/Kconfig.soc_caps.in | 8 - .../soc/esp32c5/beta3/include/soc/soc_caps.h | 2 - .../soc/esp32c5/mp/include/soc/soc_caps.h | 2 - .../esp32c6/include/soc/Kconfig.soc_caps.in | 8 - components/soc/esp32c6/include/soc/soc_caps.h | 2 - .../esp32c61/include/soc/Kconfig.soc_caps.in | 8 - .../soc/esp32c61/include/soc/soc_caps.h | 2 - .../esp32h2/include/soc/Kconfig.soc_caps.in | 8 - components/soc/esp32h2/include/soc/soc_caps.h | 2 - .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 - components/soc/esp32p4/include/soc/soc_caps.h | 2 - docs/en/api-reference/peripherals/etm.rst | 6 +- docs/zh_CN/api-reference/peripherals/etm.rst | 6 +- .../main/ana_cmpr_example_etm.c | 20 +- 20 files changed, 495 insertions(+), 240 deletions(-) diff --git a/components/esp_driver_gpio/include/driver/gpio_etm.h b/components/esp_driver_gpio/include/driver/gpio_etm.h index e7d4b0b7ad8..374f2920d0a 100644 --- a/components/esp_driver_gpio/include/driver/gpio_etm.h +++ b/components/esp_driver_gpio/include/driver/gpio_etm.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,20 +13,29 @@ extern "C" { #endif +#define GPIO_ETM_EVENT_EDGE_TYPES 3 /*!< GPIO ETM edge events are POS/NEG/ANY */ +#define GPIO_ETM_TASK_ACTION_TYPES 3 /*!< GPIO ETM action tasks are SET/CLEAR/TOGGLE */ + /** * @brief GPIO edges that can be used as ETM event */ typedef enum { - GPIO_ETM_EVENT_EDGE_POS, /*!< A rising edge on the GPIO will generate an ETM event signal */ - GPIO_ETM_EVENT_EDGE_NEG, /*!< A falling edge on the GPIO will generate an ETM event signal */ - GPIO_ETM_EVENT_EDGE_ANY, /*!< Any edge on the GPIO can generate an ETM event signal */ + GPIO_ETM_EVENT_EDGE_POS = 1, /*!< A rising edge on the GPIO will generate an ETM event signal */ + GPIO_ETM_EVENT_EDGE_NEG, /*!< A falling edge on the GPIO will generate an ETM event signal */ + GPIO_ETM_EVENT_EDGE_ANY, /*!< Any edge on the GPIO can generate an ETM event signal */ } gpio_etm_event_edge_t; /** * @brief GPIO ETM event configuration + * + * If more than one kind of ETM edge event want to be triggered on the same GPIO pin, you can configure them together. + * It helps to save GPIO ETM event channel resources for other GPIOs. */ typedef struct { - gpio_etm_event_edge_t edge; /*!< Which kind of edge can trigger the ETM event module */ + union { + gpio_etm_event_edge_t edge; /*!< Which kind of edge can trigger the ETM event module */ + gpio_etm_event_edge_t edges[GPIO_ETM_EVENT_EDGE_TYPES]; /*!< Array of kinds of edges to trigger the ETM event module on the same GPIO */ + }; } gpio_etm_event_config_t; /** @@ -34,9 +43,11 @@ typedef struct { * * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` * @note The newly created ETM event object is not bind to any GPIO, you need to call `gpio_etm_event_bind_gpio` to bind the wanted GPIO + * @note Every success call to this function will acquire a free GPIO ETM event channel * * @param[in] config GPIO ETM event configuration * @param[out] ret_event Returned ETM event handle + * @param[out] ... Other returned ETM event handles if any (the order of the returned event handles is aligned with the array order in field `edges` in `gpio_etm_event_config_t`) * @return * - ESP_OK: Create ETM event successfully * - ESP_ERR_INVALID_ARG: Create ETM event failed because of invalid argument @@ -44,7 +55,7 @@ typedef struct { * - ESP_ERR_NOT_FOUND: Create ETM event failed because all events are used up and no more free one * - ESP_FAIL: Create ETM event failed because of other reasons */ -esp_err_t gpio_new_etm_event(const gpio_etm_event_config_t *config, esp_etm_event_handle_t *ret_event); +esp_err_t gpio_new_etm_event(const gpio_etm_event_config_t *config, esp_etm_event_handle_t *ret_event, ...); /** * @brief Bind the GPIO with the ETM event @@ -65,16 +76,21 @@ esp_err_t gpio_etm_event_bind_gpio(esp_etm_event_handle_t event, int gpio_num); * @brief GPIO actions that can be taken by the ETM task */ typedef enum { - GPIO_ETM_TASK_ACTION_SET, /*!< Set the GPIO level to high */ - GPIO_ETM_TASK_ACTION_CLR, /*!< Clear the GPIO level to low */ - GPIO_ETM_TASK_ACTION_TOG, /*!< Toggle the GPIO level */ + GPIO_ETM_TASK_ACTION_SET = 1, /*!< Set the GPIO level to high */ + GPIO_ETM_TASK_ACTION_CLR, /*!< Clear the GPIO level to low */ + GPIO_ETM_TASK_ACTION_TOG, /*!< Toggle the GPIO level */ } gpio_etm_task_action_t; /** * @brief GPIO ETM task configuration + * + * If multiple actions wants to be added to the same GPIO pin, you have to configure all the GPIO ETM tasks together. */ typedef struct { - gpio_etm_task_action_t action; /*!< Which action to take by the ETM task module */ + union { + gpio_etm_task_action_t action; /*!< Action to take by the ETM task module */ + gpio_etm_task_action_t actions[GPIO_ETM_TASK_ACTION_TYPES]; /*!< Array of actions to take by the ETM task module on the same GPIO */ + }; } gpio_etm_task_config_t; /** @@ -83,9 +99,11 @@ typedef struct { * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` * @note The GPIO ETM task works like a container, a newly created ETM task object doesn't have GPIO members to be managed. * You need to call `gpio_etm_task_add_gpio` to put one or more GPIOs to the container. + * @note Every success call to this function will acquire a free GPIO ETM task channel * * @param[in] config GPIO ETM task configuration * @param[out] ret_task Returned ETM task handle + * @param[out] ... Other returned ETM task handles if any (the order of the returned task handles is aligned with the array order in field `actions` in `gpio_etm_task_config_t`) * @return * - ESP_OK: Create ETM task successfully * - ESP_ERR_INVALID_ARG: Create ETM task failed because of invalid argument @@ -93,7 +111,7 @@ typedef struct { * - ESP_ERR_NOT_FOUND: Create ETM task failed because all tasks are used up and no more free one * - ESP_FAIL: Create ETM task failed because of other reasons */ -esp_err_t gpio_new_etm_task(const gpio_etm_task_config_t *config, esp_etm_task_handle_t *ret_task); +esp_err_t gpio_new_etm_task(const gpio_etm_task_config_t *config, esp_etm_task_handle_t *ret_task, ...); /** * @brief Add GPIO to the ETM task. diff --git a/components/esp_driver_gpio/src/gpio_etm.c b/components/esp_driver_gpio/src/gpio_etm.c index 61fe15de98d..b0a3ea61ea4 100644 --- a/components/esp_driver_gpio/src/gpio_etm.c +++ b/components/esp_driver_gpio/src/gpio_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,19 +34,23 @@ typedef struct gpio_etm_event_t gpio_etm_event_t; typedef struct gpio_etm_group_t { portMUX_TYPE spinlock; gpio_etm_dev_t *dev; - gpio_etm_task_t *tasks[SOC_GPIO_ETM_TASKS_PER_GROUP]; - gpio_etm_event_t *events[SOC_GPIO_ETM_EVENTS_PER_GROUP]; + uint8_t tasks[GPIO_LL_ETM_TASK_CHANNELS_PER_GROUP]; // Array of the acquired action masks in each GPIO ETM task channel + uint8_t events[GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP]; // Array of the acquired event masks in each GPIO ETM event channel + uint8_t actions[SOC_GPIO_PIN_COUNT]; // Array of the masks of the added actions to each GPIO + uint8_t edges[GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP]; // Array of the masks of the bound event edges in each GPIO ETM event channel } gpio_etm_group_t; struct gpio_etm_event_t { esp_etm_event_t base; int chan_id; + gpio_etm_event_edge_t edge_id; gpio_etm_group_t *group; }; struct gpio_etm_task_t { esp_etm_task_t base; int chan_id; + gpio_etm_task_action_t action_id; gpio_etm_group_t *group; size_t num_of_gpios; // record the number of GPIOs that are bound to the etm task }; @@ -56,81 +60,65 @@ static gpio_etm_group_t s_gpio_etm_group = { .spinlock = portMUX_INITIALIZER_UNLOCKED, }; -static esp_err_t gpio_etm_event_register_to_group(gpio_etm_event_t *event) +static esp_err_t gpio_etm_acquire_event_channel(uint8_t event_mask, int *chan_id) { + assert(chan_id); gpio_etm_group_t *group = &s_gpio_etm_group; - int chan_id = -1; - // loop to search free one in the group + + int free_chan_id = -1; + // loop to search free event channel in the group portENTER_CRITICAL(&group->spinlock); - for (int j = 0; j < SOC_GPIO_ETM_EVENTS_PER_GROUP; j++) { + for (int j = 0; j < GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP; j++) { if (!group->events[j]) { - chan_id = j; - group->events[j] = event; + free_chan_id = j; + group->events[j] = event_mask; break; } } portEXIT_CRITICAL(&group->spinlock); - ESP_RETURN_ON_FALSE(chan_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free event channel"); - event->group = group; - event->chan_id = chan_id; + ESP_RETURN_ON_FALSE(free_chan_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free event channel"); + *chan_id = free_chan_id; return ESP_OK; } -static esp_err_t gpio_etm_task_register_to_group(gpio_etm_task_t *task) +static esp_err_t gpio_etm_release_event_channel(int chan_id, uint8_t event_mask) { gpio_etm_group_t *group = &s_gpio_etm_group; - int chan_id = -1; - // loop to search free one in the group portENTER_CRITICAL(&group->spinlock); - for (int j = 0; j < SOC_GPIO_ETM_TASKS_PER_GROUP; j++) { - if (!group->tasks[j]) { - chan_id = j; - group->tasks[j] = task; - break; - } - } + group->events[chan_id] &= ~event_mask; portEXIT_CRITICAL(&group->spinlock); - - ESP_RETURN_ON_FALSE(chan_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free task channel"); - task->group = group; - task->chan_id = chan_id; return ESP_OK; } -static void gpio_etm_event_unregister_from_group(gpio_etm_event_t *event) +static esp_err_t gpio_etm_acquire_task_channel(uint8_t task_mask, int *chan_id) { - gpio_etm_group_t *group = event->group; - int chan_id = event->chan_id; - portENTER_CRITICAL(&group->spinlock); - group->events[chan_id] = NULL; - portEXIT_CRITICAL(&group->spinlock); -} + assert(chan_id); + gpio_etm_group_t *group = &s_gpio_etm_group; -static void gpio_etm_task_unregister_from_group(gpio_etm_task_t *task) -{ - gpio_etm_group_t *group = task->group; - int chan_id = task->chan_id; + int free_chan_id = -1; + // loop to search free task channel in the group portENTER_CRITICAL(&group->spinlock); - group->tasks[chan_id] = NULL; + for (int j = 0; j < GPIO_LL_ETM_TASK_CHANNELS_PER_GROUP; j++) { + if (!group->tasks[j]) { + free_chan_id = j; + group->tasks[j] = task_mask; + break; + } + } portEXIT_CRITICAL(&group->spinlock); -} -static esp_err_t gpio_etm_event_destroy(gpio_etm_event_t *event) -{ - if (event->group) { - gpio_etm_event_unregister_from_group(event); - } - free(event); + ESP_RETURN_ON_FALSE(free_chan_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free task channel"); + *chan_id = free_chan_id; return ESP_OK; } -static esp_err_t gpio_etm_task_destroy(gpio_etm_task_t *task) +static esp_err_t gpio_etm_release_task_channel(int chan_id, uint8_t task_mask) { - if (task->group) { - gpio_etm_task_unregister_from_group(task); - } - free(task); + gpio_etm_group_t *group = &s_gpio_etm_group; + portENTER_CRITICAL(&group->spinlock); + group->tasks[chan_id] &= ~task_mask; + portEXIT_CRITICAL(&group->spinlock); return ESP_OK; } @@ -138,9 +126,16 @@ static esp_err_t gpio_del_etm_event(esp_etm_event_t *event) { gpio_etm_event_t *gpio_event = __containerof(event, gpio_etm_event_t, base); gpio_etm_group_t *group = gpio_event->group; - // disable event channel - gpio_ll_etm_enable_event_channel(group->dev, gpio_event->chan_id, false); - gpio_etm_event_destroy(gpio_event); + // unbind it from the GPIO and check if the GPIO ETM event channel can be disabled + portENTER_CRITICAL(&group->spinlock); + group->edges[gpio_event->chan_id] &= ~(1 << gpio_event->edge_id); + if (!group->edges[gpio_event->chan_id]) { + gpio_ll_etm_enable_event_channel(group->dev, gpio_event->chan_id, false); + } + portEXIT_CRITICAL(&group->spinlock); + + gpio_etm_release_event_channel(gpio_event->chan_id, 1 << gpio_event->edge_id); + free(gpio_event); return ESP_OK; } @@ -149,95 +144,192 @@ static esp_err_t gpio_del_etm_task(esp_etm_task_t *task) gpio_etm_task_t *gpio_task = __containerof(task, gpio_etm_task_t, base); // make sure user has called `gpio_etm_task_rm_gpio` to clean the etm task channel ESP_RETURN_ON_FALSE(gpio_task->num_of_gpios == 0, ESP_ERR_INVALID_STATE, TAG, "some GPIO till bounded to the etm task"); - gpio_etm_task_destroy(gpio_task); + gpio_etm_release_task_channel(gpio_task->chan_id, 1 << gpio_task->action_id); + free(gpio_task); return ESP_OK; } -esp_err_t gpio_new_etm_event(const gpio_etm_event_config_t *config, esp_etm_event_handle_t *ret_event) +esp_err_t gpio_new_etm_event(const gpio_etm_event_config_t *config, esp_etm_event_handle_t *ret_event, ...) { #if CONFIG_ETM_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); #endif esp_err_t ret = ESP_OK; - gpio_etm_event_t *event = NULL; - ESP_GOTO_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + int chan_id = -1; + uint8_t event_mask = 0; + esp_etm_event_handle_t *ret_event_itor = ret_event; + va_list args; + ESP_RETURN_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + for (int i = 0; i < GPIO_ETM_EVENT_EDGE_TYPES; i++) { + if (config->edges[i]) { + uint8_t msk = (1 << config->edges[i]); + ESP_RETURN_ON_FALSE(!(msk & event_mask), ESP_ERR_INVALID_ARG, TAG, "no identical edge event allowed in one call"); + event_mask |= msk; + } + } + ESP_RETURN_ON_FALSE(event_mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + uint32_t event_num = __builtin_popcount(event_mask); + gpio_etm_event_t *events[event_num]; - event = heap_caps_calloc(1, sizeof(gpio_etm_event_t), ETM_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no mem for event channel"); - // register the event channel to the group - ESP_GOTO_ON_ERROR(gpio_etm_event_register_to_group(event), err, TAG, "register event channel to group failed"); - int chan_id = event->chan_id; - - uint32_t event_id = 0; - switch (config->edge) { - case GPIO_ETM_EVENT_EDGE_ANY: - event_id = GPIO_LL_ETM_EVENT_ID_ANY_EDGE(chan_id); - break; - case GPIO_ETM_EVENT_EDGE_POS: - event_id = GPIO_LL_ETM_EVENT_ID_POS_EDGE(chan_id); - break; - case GPIO_ETM_EVENT_EDGE_NEG: - event_id = GPIO_LL_ETM_EVENT_ID_NEG_EDGE(chan_id); - break; - default: - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid edge"); + for (int i = 0; i < event_num; i++) { + events[i] = (gpio_etm_event_t *)heap_caps_calloc(1, sizeof(gpio_etm_event_t), ETM_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(events[i], ESP_ERR_NO_MEM, err, TAG, "no mem for event channel(s)"); } - event->base.del = gpio_del_etm_event; - event->base.event_id = event_id; - event->base.trig_periph = ETM_TRIG_PERIPH_GPIO; - ESP_LOGD(TAG, "new event @%p, event_id=%"PRIu32", chan_id=%d", event, event_id, chan_id); - *ret_event = &event->base; + // register the event channel to the group + ESP_GOTO_ON_ERROR(gpio_etm_acquire_event_channel(event_mask, &chan_id), err, TAG, "register event channel to group failed"); + + bool no_avail_ret_arg = false; + va_start(args, ret_event); + for (int i = 0, j = 0; i < event_num; i++, j++) { + if (!ret_event_itor) { + no_avail_ret_arg = true; + break; + } + // assign to the ret_event handles in the configuration order + gpio_etm_event_edge_t event_edge; + do { + event_edge = config->edges[j]; + } while (!event_edge && ++j); + uint32_t event_id = 0; + switch (event_edge) { + case GPIO_ETM_EVENT_EDGE_ANY: + event_id = GPIO_LL_ETM_EVENT_ID_ANY_EDGE(chan_id); + break; + case GPIO_ETM_EVENT_EDGE_POS: + event_id = GPIO_LL_ETM_EVENT_ID_POS_EDGE(chan_id); + break; + case GPIO_ETM_EVENT_EDGE_NEG: + event_id = GPIO_LL_ETM_EVENT_ID_NEG_EDGE(chan_id); + break; + default: + va_end(args); + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid edge"); + } + + gpio_etm_event_t *event = events[i]; + event->base.del = gpio_del_etm_event; + event->base.event_id = event_id; + event->base.trig_periph = ETM_TRIG_PERIPH_GPIO; + event->group = &s_gpio_etm_group; + event->chan_id = chan_id; + event->edge_id = event_edge; + ESP_LOGD(TAG, "new event @%p, event_id=%"PRIu32", chan_id=%d", event, event_id, chan_id); + *ret_event_itor = &event->base; + ret_event_itor = va_arg(args, esp_etm_event_handle_t *); + } + va_end(args); + ESP_GOTO_ON_FALSE(!no_avail_ret_arg, ESP_ERR_INVALID_ARG, err, TAG, "mismatch number of events with number of pointers to store event handles"); return ESP_OK; err: - if (event) { - gpio_etm_event_destroy(event); + if (chan_id != -1) { + gpio_etm_release_event_channel(chan_id, event_mask); + } + for (int i = 0; i < event_num; i++) { + if (events[i]) { + free(events[i]); + } } + ret_event_itor = ret_event; + va_start(args, ret_event); + while (ret_event_itor) { + *ret_event_itor = NULL; + ret_event_itor = va_arg(args, esp_etm_event_handle_t *); + } + va_end(args); return ret; } -esp_err_t gpio_new_etm_task(const gpio_etm_task_config_t *config, esp_etm_task_handle_t *ret_task) +esp_err_t gpio_new_etm_task(const gpio_etm_task_config_t *config, esp_etm_task_handle_t *ret_task, ...) { #if CONFIG_ETM_ENABLE_DEBUG_LOG esp_log_level_set(TAG, ESP_LOG_DEBUG); #endif esp_err_t ret = ESP_OK; - gpio_etm_task_t *task = NULL; - ESP_GOTO_ON_FALSE(config && ret_task, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + int chan_id = -1; + uint8_t task_mask = 0; + esp_etm_task_handle_t *ret_task_itor = ret_task; + va_list args; + ESP_RETURN_ON_FALSE(config && ret_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + for (int i = 0; i < GPIO_ETM_TASK_ACTION_TYPES; i++) { + if (config->actions[i]) { + uint8_t msk = (1 << config->actions[i]); + ESP_RETURN_ON_FALSE(!(msk & task_mask), ESP_ERR_INVALID_ARG, TAG, "no identical action allowed in one call"); + task_mask |= msk; + } + } + ESP_RETURN_ON_FALSE(task_mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + uint32_t task_num = __builtin_popcount(task_mask); + gpio_etm_task_t *tasks[task_num]; - task = heap_caps_calloc(1, sizeof(gpio_etm_task_t), ETM_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(task, ESP_ERR_NO_MEM, err, TAG, "no mem for task channel"); - // register the task channel to the group - ESP_GOTO_ON_ERROR(gpio_etm_task_register_to_group(task), err, TAG, "register task channel to group failed"); - int chan_id = task->chan_id; - - uint32_t task_id = 0; - switch (config->action) { - case GPIO_ETM_TASK_ACTION_SET: - task_id = GPIO_LL_ETM_TASK_ID_SET(chan_id); - break; - case GPIO_ETM_TASK_ACTION_CLR: - task_id = GPIO_LL_ETM_TASK_ID_CLR(chan_id); - break; - case GPIO_ETM_TASK_ACTION_TOG: - task_id = GPIO_LL_ETM_TASK_ID_TOG(chan_id); - break; - default: - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid action"); + for (int i = 0; i < task_num; i++) { + tasks[i] = (gpio_etm_task_t *)heap_caps_calloc(1, sizeof(gpio_etm_task_t), ETM_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(tasks[i], ESP_ERR_NO_MEM, err, TAG, "no mem for task channel(s)"); } - task->base.del = gpio_del_etm_task; - task->base.task_id = task_id; - task->base.trig_periph = ETM_TRIG_PERIPH_GPIO; - ESP_LOGD(TAG, "new task @%p, task_id=%"PRIu32", chan_id=%d", task, task_id, chan_id); - *ret_task = &task->base; + // register the task channel to the group + ESP_GOTO_ON_ERROR(gpio_etm_acquire_task_channel(task_mask, &chan_id), err, TAG, "register task channel to group failed"); + + bool no_avail_ret_arg = false; + va_start(args, ret_task); + for (int i = 0, j = 0; i < task_num; i++, j++) { + if (!ret_task_itor) { + no_avail_ret_arg = true; + break; + } + // assign to the ret_task handles in the configuration order + gpio_etm_task_action_t action; + do { + action = config->actions[i]; + } while (!action && ++j); + uint32_t task_id = 0; + switch (action) { + case GPIO_ETM_TASK_ACTION_SET: + task_id = GPIO_LL_ETM_TASK_ID_SET(chan_id); + break; + case GPIO_ETM_TASK_ACTION_CLR: + task_id = GPIO_LL_ETM_TASK_ID_CLR(chan_id); + break; + case GPIO_ETM_TASK_ACTION_TOG: + task_id = GPIO_LL_ETM_TASK_ID_TOG(chan_id); + break; + default: + va_end(args); + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid action"); + } + + gpio_etm_task_t *task = tasks[i]; + task->base.del = gpio_del_etm_task; + task->base.task_id = task_id; + task->base.trig_periph = ETM_TRIG_PERIPH_GPIO; + task->group = &s_gpio_etm_group; + task->chan_id = chan_id; + task->action_id = action; + ESP_LOGD(TAG, "new task @%p, task_id=%"PRIu32", gpio_etm_task_chan_id=%d", task, task_id, chan_id); + *ret_task_itor = &task->base; + ret_task_itor = va_arg(args, esp_etm_task_handle_t *); + } + va_end(args); + ESP_GOTO_ON_FALSE(!no_avail_ret_arg, ESP_ERR_INVALID_ARG, err, TAG, "mismatch number of tasks with number of pointers to store task handles"); return ESP_OK; err: - if (task) { - gpio_etm_task_destroy(task); + if (chan_id != -1) { + gpio_etm_release_task_channel(chan_id, task_mask); } + for (int i = 0; i < task_num; i++) { + if (tasks[i]) { + free(tasks[i]); + } + } + ret_task_itor = ret_task; + va_start(args, ret_task); + while (ret_task_itor) { + *ret_task_itor = NULL; + ret_task_itor = va_arg(args, esp_etm_task_handle_t *); + } + va_end(args); return ret; } @@ -248,12 +340,27 @@ esp_err_t gpio_etm_event_bind_gpio(esp_etm_event_handle_t event, int gpio_num) ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "gpio is not input capable"); gpio_etm_event_t *gpio_event = __containerof(event, gpio_etm_event_t, base); gpio_etm_group_t *group = gpio_event->group; - // disable gpio etm event channel first - gpio_ll_etm_enable_event_channel(group->dev, gpio_event->chan_id, false); - // then set the gpio number - gpio_ll_etm_event_channel_set_gpio(group->dev, gpio_event->chan_id, gpio_num); - // enable gpio etm event channel again - gpio_ll_etm_enable_event_channel(group->dev, gpio_event->chan_id, true); + + bool allowed = true; + portENTER_CRITICAL(&group->spinlock); + // check if the GPIO ETM event channel where the new event belongs to has previously been bound to another GPIO + // one GPIO ETM event channel can only be bound to one GPIO + if (group->edges[gpio_event->chan_id]) { + if (gpio_ll_etm_event_channel_get_gpio(group->dev, gpio_event->chan_id) != gpio_num) { + allowed = false; + } + } else { + // set the GPIO number + gpio_ll_etm_event_channel_set_gpio(group->dev, gpio_event->chan_id, gpio_num); + // enable GPIO ETM event channel + gpio_ll_etm_enable_event_channel(group->dev, gpio_event->chan_id, true); + } + + if (allowed) { + group->edges[gpio_event->chan_id] |= (1 << gpio_event->edge_id); + } + portEXIT_CRITICAL(&group->spinlock); + ESP_RETURN_ON_FALSE(allowed, ESP_ERR_INVALID_ARG, TAG, "the GPIO ETM event channel where the event belongs to has already been bound to another GPIO"); return ESP_OK; } @@ -264,19 +371,28 @@ esp_err_t gpio_etm_task_add_gpio(esp_etm_task_handle_t task, int gpio_num) ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "gpio is not output capable"); gpio_etm_task_t *gpio_task = __containerof(task, gpio_etm_task_t, base); gpio_etm_group_t *group = gpio_task->group; - bool gpio_not_enabled = true; + + bool allowed = true; // use spinlock as this function may be called with different task object in different threads // and the gpio_num might reside in the same register portENTER_CRITICAL(&group->spinlock); - // check if the gpio has been enabled - if (!gpio_ll_etm_is_task_gpio_enabled(group->dev, gpio_num)) { + // check if the new task is compatible with the tasks that has previously been added to the GPIO + // the tasks have to be from the same GPIO ETM task channel + if (group->actions[gpio_num]) { + if (gpio_ll_etm_gpio_get_task_channel(group->dev, gpio_num) != gpio_task->chan_id) { + allowed = false; + } + } else { + // first action added to the GPIO gpio_ll_etm_gpio_set_task_channel(group->dev, gpio_num, gpio_task->chan_id); gpio_ll_etm_enable_task_gpio(group->dev, gpio_num, true); - } else { - gpio_not_enabled = false; + } + + if (allowed) { + group->actions[gpio_num] |= (1 << gpio_task->action_id); } portEXIT_CRITICAL(&group->spinlock); - ESP_RETURN_ON_FALSE(gpio_not_enabled, ESP_ERR_INVALID_STATE, TAG, "gpio already enabled by other task channel"); + ESP_RETURN_ON_FALSE(allowed, ESP_ERR_INVALID_ARG, TAG, "the task does not belong to the GPIO ETM task channel that the GPIO has already binded to"); gpio_task->num_of_gpios++; return ESP_OK; } @@ -287,19 +403,24 @@ esp_err_t gpio_etm_task_rm_gpio(esp_etm_task_handle_t task, int gpio_num) ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "gpio is not output capable"); gpio_etm_task_t *gpio_task = __containerof(task, gpio_etm_task_t, base); gpio_etm_group_t *group = gpio_task->group; - bool gpio_enabled_by_this_task = true; + + bool allowed = true; // use spinlock as this function may be called with different task object in different threads // and the gpio_num might reside in the same register portENTER_CRITICAL(&group->spinlock); - // check if the gpio is managed by this etm task channel - if (gpio_ll_etm_is_task_gpio_enabled(group->dev, gpio_num) && + if ((group->actions[gpio_num] & (1 << gpio_task->action_id)) && + gpio_ll_etm_is_task_gpio_enabled(group->dev, gpio_num) && (gpio_ll_etm_gpio_get_task_channel(group->dev, gpio_num) == gpio_task->chan_id)) { - gpio_ll_etm_enable_task_gpio(group->dev, gpio_num, false); + group->actions[gpio_num] &= ~(1 << gpio_task->action_id); + if (!group->actions[gpio_num]) { + // all actions removed from the GPIO + gpio_ll_etm_enable_task_gpio(group->dev, gpio_num, false); + } } else { - gpio_enabled_by_this_task = false; + allowed = false; } portEXIT_CRITICAL(&group->spinlock); - ESP_RETURN_ON_FALSE(gpio_enabled_by_this_task, ESP_ERR_INVALID_STATE, TAG, "gpio is not enabled by this task channel"); + ESP_RETURN_ON_FALSE(allowed, ESP_ERR_INVALID_ARG, TAG, "the task was not added to the GPIO"); gpio_task->num_of_gpios--; return ESP_OK; } diff --git a/components/esp_hw_support/test_apps/etm/main/test_gpio_etm.c b/components/esp_hw_support/test_apps/etm/main/test_gpio_etm.c index ee80ca8a4dd..cd2c0d1bcb6 100644 --- a/components/esp_hw_support/test_apps/etm/main/test_gpio_etm.c +++ b/components/esp_hw_support/test_apps/etm/main/test_gpio_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -81,7 +81,7 @@ TEST_CASE("gpio_etm_self_trigger", "[etm]") // delete gpio etm task without remove all bounded GPIOs should fail TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_etm_del_task(gpio_task)); // remove unrelated GPIO from the task should fail - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gpio_etm_task_rm_gpio(gpio_task, 10)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, gpio_etm_task_rm_gpio(gpio_task, 10)); // delete etm primitives TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task, output_gpio)); @@ -90,3 +90,118 @@ TEST_CASE("gpio_etm_self_trigger", "[etm]") TEST_ESP_OK(esp_etm_del_event(gpio_event)); TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); } + +TEST_CASE("gpio_etm_self_trigger_multi_action", "[etm]") +{ + // GPIO 0 pos edge event ---> GPIO 1 set level task + // GPIO 22 pos edge event ---> GPIO 1 clear level task + + const uint32_t input_gpio1 = 0; + const uint32_t input_gpio2 = 22; + const uint32_t output_gpio = 1; + printf("allocate etm channels\r\n"); + esp_etm_channel_config_t etm_config = {}; + esp_etm_channel_handle_t etm_channel_a = NULL; + esp_etm_channel_handle_t etm_channel_b = NULL; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a)); + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_b)); + + printf("allocate GPIO etm event and task\r\n"); + esp_etm_task_handle_t gpio_task_a = NULL; + esp_etm_event_handle_t gpio_event_a = NULL; + esp_etm_task_handle_t gpio_task_b = NULL; + esp_etm_event_handle_t gpio_event_b = NULL; + gpio_etm_event_config_t gpio_event_config = {}; + gpio_event_config.edges[0] = GPIO_ETM_EVENT_EDGE_POS; + TEST_ESP_OK(gpio_new_etm_event(&gpio_event_config, &gpio_event_a)); + esp_etm_event_handle_t gpio_event_c = NULL; // an extra event only used for testing binding + gpio_event_config.edges[1] = GPIO_ETM_EVENT_EDGE_ANY; + TEST_ESP_OK(gpio_new_etm_event(&gpio_event_config, &gpio_event_b, &gpio_event_c)); + gpio_etm_task_config_t gpio_task_config = {}; + gpio_task_config.actions[0] = GPIO_ETM_TASK_ACTION_CLR; + gpio_task_config.actions[1] = GPIO_ETM_TASK_ACTION_SET; + TEST_ESP_OK(gpio_new_etm_task(&gpio_task_config, &gpio_task_b, &gpio_task_a)); + + // bind GPIO to the event and task + TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_a, input_gpio1)); + TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_b, input_gpio2)); + TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task_a, output_gpio)); + TEST_ESP_OK(gpio_etm_task_add_gpio(gpio_task_b, output_gpio)); + + // try an infeasible bind of second event to a GPIO + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, gpio_etm_event_bind_gpio(gpio_event_c, input_gpio1)); + // try a feasible bind of second event to a GPIO + TEST_ESP_OK(gpio_etm_event_bind_gpio(gpio_event_c, input_gpio2)); + // delete the event to unbind it from the GPIO + TEST_ESP_OK(esp_etm_del_event(gpio_event_c)); + + printf("initialize gpio\r\n"); + gpio_config_t task_gpio_config = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_INPUT_OUTPUT, // we want to read the GPIO value, so it should be input and output + .pin_bit_mask = 1ULL << output_gpio, + }; + TEST_ESP_OK(gpio_config(&task_gpio_config)); + // set the initial level + TEST_ESP_OK(gpio_set_level(output_gpio, 0)); + + gpio_config_t event_gpio_config = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_INPUT_OUTPUT, // we want to simulate the edge signal by software, so it should be input and output + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .pin_bit_mask = (1ULL << input_gpio1) | (1ULL << input_gpio2), + }; + TEST_ESP_OK(gpio_config(&event_gpio_config)); + // set the initial level + TEST_ESP_OK(gpio_set_level(input_gpio1, 0)); + TEST_ESP_OK(gpio_set_level(input_gpio2, 0)); + + printf("connect event and task to the channel\r\n"); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gpio_event_a, gpio_task_a)); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_b, gpio_event_b, gpio_task_b)); + + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_b)); + + // input_gpio1 pos edge ---> output_gpio level being set + TEST_ESP_OK(gpio_set_level(input_gpio1, 1)); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ASSERT_EQUAL(1, gpio_get_level(output_gpio)); + + // input_gpio1 neg edge does not affect output_gpio level + TEST_ESP_OK(gpio_set_level(input_gpio1, 0)); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ASSERT_EQUAL(1, gpio_get_level(output_gpio)); + + // input_gpio2 pos edge ---> output_gpio level being cleared + TEST_ESP_OK(gpio_set_level(input_gpio2, 1)); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ASSERT_EQUAL(0, gpio_get_level(output_gpio)); + + // input_gpio2 neg edge does not affect output_gpio level + TEST_ESP_OK(gpio_set_level(input_gpio2, 0)); + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ASSERT_EQUAL(0, gpio_get_level(output_gpio)); + + // Create a new gpio etm task separately, and add it to the output_gpio should fail (the task does not belong to the same GPIO ETM task channel as gpio_task_a and gpio_task_b) + esp_etm_task_handle_t gpio_task_c = NULL; + gpio_etm_task_config_t gpio_task_config_2 = { + .action = GPIO_ETM_TASK_ACTION_TOG, + }; + TEST_ESP_OK(gpio_new_etm_task(&gpio_task_config_2, &gpio_task_c)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, gpio_etm_task_add_gpio(gpio_task_c, output_gpio)); + + // delete etm primitives + TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task_a, output_gpio)); + TEST_ESP_OK(gpio_etm_task_rm_gpio(gpio_task_b, output_gpio)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_b)); + TEST_ESP_OK(esp_etm_del_task(gpio_task_a)); + TEST_ESP_OK(esp_etm_del_task(gpio_task_b)); + TEST_ESP_OK(esp_etm_del_task(gpio_task_c)); + TEST_ESP_OK(esp_etm_del_event(gpio_event_a)); + TEST_ESP_OK(esp_etm_del_event(gpio_event_b)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_b)); +} diff --git a/components/hal/esp32c6/include/hal/gpio_etm_ll.h b/components/hal/esp32c6/include/hal/gpio_etm_ll.h index eb311e09dc3..50b98b95a84 100644 --- a/components/hal/esp32c6/include/hal/gpio_etm_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_etm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,15 +22,20 @@ #define GPIO_LL_ETM_TASK_ID_CLR(ch) (GPIO_TASK_CH0_CLEAR + (ch)) #define GPIO_LL_ETM_TASK_ID_TOG(ch) (GPIO_TASK_CH0_TOGGLE + (ch)) +#define GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP 8 +#define GPIO_LL_ETM_TASK_CHANNELS_PER_GROUP 8 + #ifdef __cplusplus extern "C" { #endif /** - * @brief Set which GPIO to be bounded to the event channel + * @brief Set which GPIO to be bound to the event channel + * + * @note Different channels can be bound to one GPIO * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint32_t chan, uint32_t gpio_num) @@ -39,10 +44,10 @@ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint3 } /** - * @brief Wether to enable the event channel + * @brief Whether to enable the event channel * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param enable True to enable, false to disable */ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_t chan, bool enable) @@ -51,12 +56,24 @@ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Set which GPIO to be bounded to the task channel + * @brief Get which GPIO is bound to the event channel + * + * @param dev Register base address + * @param chan GPIO ETM Event channel number + * @return GPIO number + */ +static inline uint32_t gpio_ll_etm_event_channel_get_gpio(gpio_etm_dev_t *dev, uint32_t chan) +{ + return dev->event_chn_cfg[chan].etm_chn_event_sel; +} + +/** + * @brief Set which GPIO to be bound to the task channel * - * @note One channel can be bounded to multiple different GPIOs + * @note One channel can be bound to multiple different GPIOs * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Task channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32_t gpio_num, uint32_t chan) @@ -70,7 +87,7 @@ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32 } /** - * @brief Wether to enable the GPIO to be managed by the task channel + * @brief Whether to enable the GPIO to be managed by the task channel * * @param dev Register base address * @param gpio_num GPIO number @@ -101,7 +118,7 @@ static inline bool gpio_ll_etm_is_task_gpio_enabled(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Get the channel number that the GPIO is bounded to + * @brief Get the channel number that the GPIO is bound to * * @param dev Register base address * @param gpio_num GPIO number diff --git a/components/hal/esp32h2/include/hal/gpio_etm_ll.h b/components/hal/esp32h2/include/hal/gpio_etm_ll.h index 57101ba37fd..49281c3366f 100644 --- a/components/hal/esp32h2/include/hal/gpio_etm_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_etm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,15 +22,20 @@ #define GPIO_LL_ETM_TASK_ID_CLR(ch) (GPIO_TASK_CH0_CLEAR + (ch)) #define GPIO_LL_ETM_TASK_ID_TOG(ch) (GPIO_TASK_CH0_TOGGLE + (ch)) +#define GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP 8 +#define GPIO_LL_ETM_TASK_CHANNELS_PER_GROUP 8 + #ifdef __cplusplus extern "C" { #endif /** - * @brief Set which GPIO to be bounded to the event channel + * @brief Set which GPIO to be bound to the event channel + * + * @note Different channels can be bound to one GPIO * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint32_t chan, uint32_t gpio_num) @@ -39,10 +44,10 @@ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint3 } /** - * @brief Wether to enable the event channel + * @brief Whether to enable the event channel * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param enable True to enable, false to disable */ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_t chan, bool enable) @@ -51,12 +56,24 @@ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Set which GPIO to be bounded to the task channel + * @brief Get which GPIO is bound to the event channel + * + * @param dev Register base address + * @param chan GPIO ETM Event channel number + * @return GPIO number + */ +static inline uint32_t gpio_ll_etm_event_channel_get_gpio(gpio_etm_dev_t *dev, uint32_t chan) +{ + return dev->etm_event_chn_cfg[chan].etm_chn_event_sel; +} + +/** + * @brief Set which GPIO to be bound to the task channel * - * @note One channel can be bounded to multiple different GPIOs + * @note One channel can be bound to multiple different GPIOs * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Task channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32_t gpio_num, uint32_t chan) @@ -70,7 +87,7 @@ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32 } /** - * @brief Wether to enable the GPIO to be managed by the task channel + * @brief Whether to enable the GPIO to be managed by the task channel * * @param dev Register base address * @param gpio_num GPIO number @@ -101,7 +118,7 @@ static inline bool gpio_ll_etm_is_task_gpio_enabled(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Get the channel number that the GPIO is bounded to + * @brief Get the channel number that the GPIO is bound to * * @param dev Register base address * @param gpio_num GPIO number diff --git a/components/hal/esp32p4/include/hal/gpio_etm_ll.h b/components/hal/esp32p4/include/hal/gpio_etm_ll.h index 57101ba37fd..49281c3366f 100644 --- a/components/hal/esp32p4/include/hal/gpio_etm_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_etm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,15 +22,20 @@ #define GPIO_LL_ETM_TASK_ID_CLR(ch) (GPIO_TASK_CH0_CLEAR + (ch)) #define GPIO_LL_ETM_TASK_ID_TOG(ch) (GPIO_TASK_CH0_TOGGLE + (ch)) +#define GPIO_LL_ETM_EVENT_CHANNELS_PER_GROUP 8 +#define GPIO_LL_ETM_TASK_CHANNELS_PER_GROUP 8 + #ifdef __cplusplus extern "C" { #endif /** - * @brief Set which GPIO to be bounded to the event channel + * @brief Set which GPIO to be bound to the event channel + * + * @note Different channels can be bound to one GPIO * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint32_t chan, uint32_t gpio_num) @@ -39,10 +44,10 @@ static inline void gpio_ll_etm_event_channel_set_gpio(gpio_etm_dev_t *dev, uint3 } /** - * @brief Wether to enable the event channel + * @brief Whether to enable the event channel * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Event channel number * @param enable True to enable, false to disable */ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_t chan, bool enable) @@ -51,12 +56,24 @@ static inline void gpio_ll_etm_enable_event_channel(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Set which GPIO to be bounded to the task channel + * @brief Get which GPIO is bound to the event channel + * + * @param dev Register base address + * @param chan GPIO ETM Event channel number + * @return GPIO number + */ +static inline uint32_t gpio_ll_etm_event_channel_get_gpio(gpio_etm_dev_t *dev, uint32_t chan) +{ + return dev->etm_event_chn_cfg[chan].etm_chn_event_sel; +} + +/** + * @brief Set which GPIO to be bound to the task channel * - * @note One channel can be bounded to multiple different GPIOs + * @note One channel can be bound to multiple different GPIOs * * @param dev Register base address - * @param chan Channel number + * @param chan GPIO ETM Task channel number * @param gpio_num GPIO number */ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32_t gpio_num, uint32_t chan) @@ -70,7 +87,7 @@ static inline void gpio_ll_etm_gpio_set_task_channel(gpio_etm_dev_t *dev, uint32 } /** - * @brief Wether to enable the GPIO to be managed by the task channel + * @brief Whether to enable the GPIO to be managed by the task channel * * @param dev Register base address * @param gpio_num GPIO number @@ -101,7 +118,7 @@ static inline bool gpio_ll_etm_is_task_gpio_enabled(gpio_etm_dev_t *dev, uint32_ } /** - * @brief Get the channel number that the GPIO is bounded to + * @brief Get the channel number that the GPIO is bound to * * @param dev Register base address * @param gpio_num GPIO number diff --git a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in index ec09df500b9..d4ab7aaa2ce 100644 --- a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in @@ -251,14 +251,6 @@ config SOC_GPIO_SUPPORT_PIN_HYS_FILTER bool default y -config SOC_GPIO_ETM_EVENTS_PER_GROUP - int - default 8 - -config SOC_GPIO_ETM_TASKS_PER_GROUP - int - default 8 - config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index 74df08b4f3f..8862d8cee76 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -193,8 +193,6 @@ // GPIO peripheral has the ETM extension // #define SOC_GPIO_SUPPORT_ETM 1 -#define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -#define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has the full LP IO subsystem // On ESP32-C5, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index e63311e1e9d..b635b7f2399 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -183,8 +183,6 @@ // GPIO peripheral has the ETM extension // #define SOC_GPIO_SUPPORT_ETM 1 -// #define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -// #define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has the full LP IO subsystem // On ESP32-C5, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 986ac496d50..8b522a023ee 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -471,14 +471,6 @@ config SOC_GPIO_SUPPORT_ETM bool default y -config SOC_GPIO_ETM_EVENTS_PER_GROUP - int - default 8 - -config SOC_GPIO_ETM_TASKS_PER_GROUP - int - default 8 - config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 07deaadfa0a..d9fdc588ce0 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -186,8 +186,6 @@ // GPIO peripheral has the ETM extension #define SOC_GPIO_SUPPORT_ETM 1 -#define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -#define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has the full LP IO subsystem // On ESP32-C6, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 214bf3ec8d7..f77de6e2ff9 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -163,14 +163,6 @@ config SOC_GPIO_PIN_COUNT int default 25 -config SOC_GPIO_ETM_EVENTS_PER_GROUP - int - default 8 - -config SOC_GPIO_ETM_TASKS_PER_GROUP - int - default 8 - config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 12b054b07d8..f7462c9a6c6 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -187,8 +187,6 @@ // GPIO peripheral has the ETM extension // #define SOC_GPIO_SUPPORT_ETM 1 //TODO: [ESP32C61] IDF-9340 -#define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -#define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has the full LP IO subsystem // On ESP32-C61, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index d9eec8f6fd6..9606984626f 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -483,14 +483,6 @@ config SOC_GPIO_SUPPORT_ETM bool default y -config SOC_GPIO_ETM_EVENTS_PER_GROUP - int - default 8 - -config SOC_GPIO_ETM_TASKS_PER_GROUP - int - default 8 - config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 051657fa7b8..2181547f95b 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -190,8 +190,6 @@ // GPIO peripheral has the ETM extension #define SOC_GPIO_SUPPORT_ETM 1 -#define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -#define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has no full LP IO subsystem, GPIO7~14 remain LP function (powered by VDD3V3_LP, and can be used as ext1 wakeup pins) // Digital IOs have their own registers to control pullup/down/capability diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index e7694d453dc..6597ac120fb 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -519,14 +519,6 @@ config SOC_GPIO_SUPPORT_ETM bool default y -config SOC_GPIO_ETM_EVENTS_PER_GROUP - int - default 8 - -config SOC_GPIO_ETM_TASKS_PER_GROUP - int - default 8 - config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index ffe827f7393..2b8089c0f75 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -211,8 +211,6 @@ // GPIO peripheral has the ETM extension #define SOC_GPIO_SUPPORT_ETM 1 -#define SOC_GPIO_ETM_EVENTS_PER_GROUP 8 -#define SOC_GPIO_ETM_TASKS_PER_GROUP 8 // Target has the full LP IO subsystem // On ESP32-P4, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. diff --git a/docs/en/api-reference/peripherals/etm.rst b/docs/en/api-reference/peripherals/etm.rst index 8c9d901881d..467ed590ad2 100644 --- a/docs/en/api-reference/peripherals/etm.rst +++ b/docs/en/api-reference/peripherals/etm.rst @@ -56,7 +56,7 @@ GPIO Events GPIO **edge** event is the most common event type, it can be generated by any GPIO pin. You can call :cpp:func:`gpio_new_etm_event` to create a GPIO event handle, with the configurations provided in :cpp:type:`gpio_etm_event_config_t`: -- :cpp:member:`gpio_etm_event_config_t::edge` decides which edge to trigger the event, supported edge types are listed in the :cpp:type:`gpio_etm_event_edge_t`. +- :cpp:member:`gpio_etm_event_config_t::edge` or :cpp:member:`gpio_etm_event_config_t::edges` decides which edge(s) to trigger the event(s), supported edge types are listed in the :cpp:type:`gpio_etm_event_edge_t`. You need to build a connection between the GPIO ETM event handle and the GPIO number. So you should call :cpp:func:`gpio_etm_event_bind_gpio` afterwards. Please note, only the ETM event handle that created by :cpp:func:`gpio_new_etm_event` can set a GPIO number. Calling this function with other kinds of ETM events returns :c:macro:`ESP_ERR_INVALID_ARG` error. Needless to say, this function does not help with the GPIO initialization, you still need to call :cpp:func:`gpio_config` to set the property like direction, pull up/down mode separately. @@ -83,9 +83,9 @@ ETM Task abstracts the task action and is represented by :cpp:type:`esp_etm_task GPIO Tasks ~~~~~~~~~~ -GPIO task is the most common task type, one GPIO task can even manage multiple GPIOs. When the task gets activated by the ETM channel, all managed GPIOs can set/clear/toggle at the same time. You can call :cpp:func:`gpio_new_etm_task` to create a GPIO task handle, with the configurations provided in :cpp:type:`gpio_etm_task_config_t`: +GPIO task is the most common task type. One GPIO can take one or more GPIO ETM task actions, and one GPIO ETM task action can even manage multiple GPIOs. When the task gets activated by the ETM channel, all managed GPIOs can set/clear/toggle at the same time. You can call :cpp:func:`gpio_new_etm_task` to create a GPIO task handle, with the configurations provided in :cpp:type:`gpio_etm_task_config_t`: -- :cpp:member:`gpio_etm_task_config_t::action` decides what GPIO action would be taken by the ETM task. Supported actions are listed in the :cpp:type:`gpio_etm_task_action_t`. +- :cpp:member:`gpio_etm_task_config_t::action` or :cpp:member:`gpio_etm_task_config_t::actions` decides what GPIO action(s) would be taken by the ETM task. Supported actions are listed in the :cpp:type:`gpio_etm_task_action_t`. If one GPIO needs to take more than one actions, the action tasks have to be created in one :cpp:func:`gpio_new_etm_task` call with filling the actions into the array of :cpp:member:`gpio_etm_task_config_t::actions`. To build a connection between the GPIO ETM task and the GPIO number, you should call :cpp:func:`gpio_etm_task_add_gpio`. You can call this function by several times if you want the task handle to manage more GPIOs. Please note, only the ETM task handle that created by :cpp:func:`gpio_new_etm_task` can manage a GPIO. Calling this function with other kinds of ETM tasks returns :c:macro:`ESP_ERR_INVALID_ARG` error. Needless to say, this function does not help with the GPIO initialization, you still need to call :cpp:func:`gpio_config` to set the property like direction, pull up/down mode separately. diff --git a/docs/zh_CN/api-reference/peripherals/etm.rst b/docs/zh_CN/api-reference/peripherals/etm.rst index 8d56935aec3..4a490af6b50 100644 --- a/docs/zh_CN/api-reference/peripherals/etm.rst +++ b/docs/zh_CN/api-reference/peripherals/etm.rst @@ -56,7 +56,7 @@ GPIO 事件 GPIO **边沿** 事件是最常见的事件类型,任何 GPIO 管脚均可触发这类事件。要创建 GPIO 事件句柄,请调用 :cpp:func:`gpio_new_etm_event`,并使用 :cpp:type:`gpio_etm_event_config_t` 提供的配置信息: -- :cpp:member:`gpio_etm_event_config_t::edge` 决定触发事件的边沿类型,支持的边沿类型已在 :cpp:type:`gpio_etm_event_edge_t` 中列出。 +- :cpp:member:`gpio_etm_event_config_t::edge` 或 :cpp:member:`gpio_etm_event_config_t::edges` 决定触发事件的边沿类型,支持的边沿类型已在 :cpp:type:`gpio_etm_event_edge_t` 中列出。 接下来,请调用 :cpp:func:`gpio_etm_event_bind_gpio` 函数,连接 GPIO ETM 事件句柄与 GPIO 管脚。注意,要设置 GPIO 管脚,只能使用由 :cpp:func:`gpio_new_etm_event` 函数创建的 ETM 事件句柄。对于其他类型的 ETM 事件,调用此函数,将返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。该函数也无法完成 GPIO 的初始化,在使用 GPIO ETM 事件之前,仍需调用 :cpp:func:`gpio_config` 函数,设置 GPIO 管脚的属性,如方向、高/低电平模式等。 @@ -82,9 +82,9 @@ ETM 任务对其操作进行了抽象,在软件中表示为 :cpp:type:`esp_etm GPIO 任务 ~~~~~~~~~~ -GPIO 任务是最常见的任务类型,一个 GPIO 任务可以同时管理多个 GPIO 管脚。当 ETM 通道激活任务时,任务可以同时设置管理的所有 GPIO 引脚,使其设置/清除/切换状态。要创建 GPIO 任务句柄,请调用 :cpp:func:`gpio_new_etm_task`,并使用 :cpp:type:`gpio_etm_task_config_t` 提供的配置信息: +GPIO 任务是最常见的任务类型。一个 GPIO 可以采取一个或多个 GPIO 操作,而一个 GPIO 任务也可以同时管理多个 GPIO 管脚。当 ETM 通道激活任务时,任务可以同时设置管理的所有 GPIO 引脚,使其设置/清除/切换状态。要创建 GPIO 任务句柄,请调用 :cpp:func:`gpio_new_etm_task`,并使用 :cpp:type:`gpio_etm_task_config_t` 提供的配置信息: -- :cpp:member:`gpio_etm_task_config_t::action` 决定 ETM 任务将采取的 GPIO 操作,支持的操作类型在 :cpp:type:`gpio_etm_task_action_t` 中列出。 +- :cpp:member:`gpio_etm_task_config_t::action` 或 :cpp:member:`gpio_etm_task_config_t::actions` 决定 ETM 任务将采取的 GPIO 操作,支持的操作类型在 :cpp:type:`gpio_etm_task_action_t` 中列出。如果一个 GPIO 需要采取多个 GPIO 操作,这些操作任务的创建必须通过配置 :cpp:member:`gpio_etm_task_config_t::actions` 的数组并在一次 :cpp:func:`gpio_new_etm_task` 调用中一并完成。 接下来,需要连接 GPIO ETM 任务句柄与 GPIO 管脚。为此,请调用 :cpp:func:`gpio_etm_task_add_gpio` 函数。如果需要任务句柄管理更多的 GPIO 管脚,可以重复调用以上函数,注意,要设置 GPIO 管脚,只能使用由 :cpp:func:`gpio_new_etm_task` 函数创建的 ETM 任务句柄。对于其他类型的 ETM 任务,调用此函数,将返回 :c:macro:`ESP_ERR_INVALID_ARG` 错误。该函数也无法完成 GPIO 的初始化,在使用 GPIO ETM 任务之前,仍需调用 :cpp:func:`gpio_config` 函数,设置 GPIO 管脚的属性,如方向、高/低电平模式等。 diff --git a/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c b/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c index 46c827610cb..f5f8c42f07a 100644 --- a/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c +++ b/examples/peripherals/analog_comparator/main/ana_cmpr_example_etm.c @@ -26,17 +26,19 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp .event_type = ANA_CMPR_EVENT_POS_CROSS, }; ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &cmpr_pos_evt)); - evt_cfg.event_type = GPIO_ETM_EVENT_EDGE_NEG; + evt_cfg.event_type = ANA_CMPR_EVENT_NEG_CROSS; ESP_ERROR_CHECK(ana_cmpr_new_etm_event(cmpr, &evt_cfg, &cmpr_neg_evt)); /* Allocate the GPIO set & clear tasks */ - esp_etm_task_handle_t gpio_toggle_task = NULL; - gpio_etm_task_config_t task_cfg = { - .action = GPIO_ETM_TASK_ACTION_TOG, - }; - ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_toggle_task)); + esp_etm_task_handle_t gpio_set_task = NULL; + esp_etm_task_handle_t gpio_clr_task = NULL; + gpio_etm_task_config_t task_cfg = {}; + task_cfg.actions[0] = GPIO_ETM_TASK_ACTION_SET; + task_cfg.actions[1] = GPIO_ETM_TASK_ACTION_CLR; + ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_set_task, &gpio_clr_task)); /* Add task to the monitor GPIO */ - ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_toggle_task, EXAMPLE_MONITOR_GPIO_NUM)); + ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_set_task, EXAMPLE_MONITOR_GPIO_NUM)); + ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_clr_task, EXAMPLE_MONITOR_GPIO_NUM)); /* Allocate the Event Task Matrix channels */ esp_etm_channel_handle_t etm_pos_handle; @@ -45,8 +47,8 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_pos_handle)); ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_neg_handle)); /* Bind the events and tasks */ - ESP_ERROR_CHECK(esp_etm_channel_connect(etm_pos_handle, cmpr_pos_evt, gpio_toggle_task)); - ESP_ERROR_CHECK(esp_etm_channel_connect(etm_neg_handle, cmpr_neg_evt, gpio_toggle_task)); + ESP_ERROR_CHECK(esp_etm_channel_connect(etm_pos_handle, cmpr_pos_evt, gpio_set_task)); + ESP_ERROR_CHECK(esp_etm_channel_connect(etm_neg_handle, cmpr_neg_evt, gpio_clr_task)); /* Enable the ETM channels */ ESP_ERROR_CHECK(esp_etm_channel_enable(etm_pos_handle)); ESP_ERROR_CHECK(esp_etm_channel_enable(etm_neg_handle)); From 4fb58d56b416fd8010afaea7646debcf36cebb1b Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 22 Apr 2024 16:36:04 +0800 Subject: [PATCH 008/548] change(gdma): improve the test cases to be target agnostic --- .../test_apps/dma/main/CMakeLists.txt | 10 +- .../test_apps/dma/main/test_async_memcpy.c | 70 +++--- .../test_apps/dma/main/test_dw_gdma.c | 116 +++++----- .../test_apps/dma/main/test_gdma.c | 217 ++++-------------- .../test_apps/dma/main/test_gdma_crc.c | 136 +++++++++++ .../{etm => dma}/main/test_gdma_etm.c | 4 +- .../test_apps/etm/main/CMakeLists.txt | 4 - 7 files changed, 298 insertions(+), 259 deletions(-) create mode 100644 components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c rename components/esp_hw_support/test_apps/{etm => dma}/main/test_gdma_etm.c (96%) diff --git a/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt b/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt index d7baeb0936a..643898bfb5c 100644 --- a/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/dma/main/CMakeLists.txt @@ -8,12 +8,20 @@ if(CONFIG_SOC_GDMA_SUPPORTED) list(APPEND srcs "test_gdma.c") endif() +if(CONFIG_SOC_ETM_SUPPORTED AND CONFIG_SOC_GDMA_SUPPORT_ETM) + list(APPEND srcs "test_gdma_etm.c") +endif() + if(CONFIG_SOC_DW_GDMA_SUPPORTED) list(APPEND srcs "test_dw_gdma.c") endif() +if(CONFIG_SOC_GDMA_SUPPORT_CRC) + list(APPEND srcs "test_gdma_crc.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} - PRIV_REQUIRES unity esp_mm + PRIV_REQUIRES unity esp_mm esp_driver_gpio WHOLE_ARCHIVE) diff --git a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c index 8a166b3be6a..81939889d0c 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c +++ b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c @@ -18,6 +18,7 @@ #include "esp_async_memcpy.h" #include "soc/soc_caps.h" #include "hal/dma_types.h" +#include "esp_dma_utils.h" #define IDF_LOG_PERFORMANCE(item, value_fmt, value, ...) \ printf("[Performance][%s]: " value_fmt "\n", item, value, ##__VA_ARGS__) @@ -26,10 +27,7 @@ #define ALIGN_DOWN(size, align) ((size) & ~((align) - 1)) #if CONFIG_IDF_TARGET_ESP32P4 -#define TEST_MEMCPY_DST_BASE_ALIGN 64 #define TEST_MEMCPY_BUFFER_SIZE_MUST_ALIGN_CACHE 1 -#else -#define TEST_MEMCPY_DST_BASE_ALIGN 4 #endif typedef struct { @@ -56,23 +54,23 @@ static void async_memcpy_setup_testbench(memcpy_testbench_context_t *test_contex uint8_t *dst_buf = NULL; uint8_t *from_addr = NULL; uint8_t *to_addr = NULL; -#if CONFIG_SPIRAM && SOC_AHB_GDMA_SUPPORT_PSRAM + + esp_dma_mem_info_t mem_info = { + .dma_alignment_bytes = test_context->align, + }; if (test_context->src_in_psram) { - src_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_SPIRAM); + mem_info.extra_heap_caps = MALLOC_CAP_SPIRAM; } else { - src_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + mem_info.extra_heap_caps = 0; } + TEST_ESP_OK(esp_dma_capable_calloc(1, buffer_size, &mem_info, (void **)&src_buf, NULL)); if (test_context->dst_in_psram) { - dst_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_SPIRAM); + mem_info.extra_heap_caps = MALLOC_CAP_SPIRAM; } else { - dst_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + mem_info.extra_heap_caps = 0; } -#else - src_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - dst_buf = heap_caps_aligned_alloc(test_context->align, buffer_size, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); -#endif - TEST_ASSERT_NOT_NULL_MESSAGE(src_buf, "allocate source buffer failed"); - TEST_ASSERT_NOT_NULL_MESSAGE(dst_buf, "allocate destination buffer failed"); + TEST_ESP_OK(esp_dma_capable_calloc(1, buffer_size, &mem_info, (void **)&dst_buf, NULL)); + // adding extra offset from_addr = src_buf + test_context->offset; to_addr = dst_buf; @@ -113,8 +111,13 @@ TEST_CASE("memory copy the same buffer with different content", "[async mcp]") async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG(); async_memcpy_handle_t driver = NULL; TEST_ESP_OK(esp_async_memcpy_install(&config, &driver)); - uint8_t *sbuf = heap_caps_aligned_alloc(TEST_MEMCPY_DST_BASE_ALIGN, 256, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - uint8_t *dbuf = heap_caps_aligned_alloc(TEST_MEMCPY_DST_BASE_ALIGN, 256, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + uint8_t *sbuf = NULL; + uint8_t *dbuf = NULL; + esp_dma_mem_info_t mem_info = { + .dma_alignment_bytes = 4, + }; + TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&sbuf, NULL)); + TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&dbuf, NULL)); for (int j = 0; j < 20; j++) { TEST_ESP_OK(esp_async_memcpy(driver, dbuf, sbuf, 256, NULL, NULL)); vTaskDelay(pdMS_TO_TICKS(10)); @@ -136,7 +139,7 @@ static void test_memory_copy_one_by_one(async_memcpy_handle_t driver) { uint32_t aligned_test_buffer_size[] = {256, 512, 1024, 2048, 4096}; memcpy_testbench_context_t test_context = { - .align = TEST_MEMCPY_DST_BASE_ALIGN, + .align = 4, }; for (int i = 0; i < sizeof(aligned_test_buffer_size) / sizeof(aligned_test_buffer_size[0]); i++) { @@ -216,9 +219,13 @@ TEST_CASE("memory copy done callback", "[async mcp]") async_memcpy_handle_t driver = NULL; TEST_ESP_OK(esp_async_memcpy_install(&config, &driver)); - uint8_t *src_buf = heap_caps_aligned_alloc(TEST_MEMCPY_DST_BASE_ALIGN, 256, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); - // destination address should aligned to data cache line - uint8_t *dst_buf = heap_caps_aligned_alloc(TEST_MEMCPY_DST_BASE_ALIGN, 256, MALLOC_CAP_8BIT | MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + uint8_t *src_buf = NULL; + uint8_t *dst_buf = NULL; + esp_dma_mem_info_t mem_info = { + .dma_alignment_bytes = 4, + }; + TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&src_buf, NULL)); + TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&dst_buf, NULL)); SemaphoreHandle_t sem = xSemaphoreCreateBinary(); TEST_ESP_OK(esp_async_memcpy(driver, dst_buf, src_buf, 256, test_async_memcpy_cb_v1, sem)); @@ -235,38 +242,39 @@ TEST_CASE("memory copy by DMA on the fly", "[async mcp]") async_memcpy_handle_t driver = NULL; TEST_ESP_OK(esp_async_memcpy_install(&config, &driver)); - uint32_t test_buffer_len[] = {512, 1024, 2048, 4096, 5011}; + uint32_t aligned_test_buffer_size[] = {512, 1024, 2048, 4096, 4608}; memcpy_testbench_context_t test_context[5] = { [0 ... 4] = { - .align = TEST_MEMCPY_DST_BASE_ALIGN, + .align = 4, } }; // Aligned case - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(aligned_test_buffer_size) / sizeof(aligned_test_buffer_size[0]); i++) { test_context[i].seed = i; - test_context[i].buffer_size = test_buffer_len[i]; + test_context[i].buffer_size = aligned_test_buffer_size[i]; async_memcpy_setup_testbench(&test_context[i]); } - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(aligned_test_buffer_size) / sizeof(aligned_test_buffer_size[0]); i++) { TEST_ESP_OK(esp_async_memcpy(driver, test_context[i].to_addr, test_context[i].from_addr, test_context[i].copy_size, NULL, NULL)); } - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(aligned_test_buffer_size) / sizeof(aligned_test_buffer_size[0]); i++) { async_memcpy_verify_and_clear_testbench(i, test_context[i].copy_size, test_context[i].src_buf, test_context[i].dst_buf, test_context[i].from_addr, test_context[i].to_addr); } #if !TEST_MEMCPY_BUFFER_SIZE_MUST_ALIGN_CACHE + uint32_t unaligned_test_buffer_size[] = {511, 1023, 2047, 4095, 5011}; // Non-aligned case - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(unaligned_test_buffer_size) / sizeof(unaligned_test_buffer_size[0]); i++) { test_context[i].seed = i; - test_context[i].buffer_size = test_buffer_len[i]; + test_context[i].buffer_size = unaligned_test_buffer_size[i]; test_context[i].offset = 3; async_memcpy_setup_testbench(&test_context[i]); } - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(unaligned_test_buffer_size) / sizeof(unaligned_test_buffer_size[0]); i++) { TEST_ESP_OK(esp_async_memcpy(driver, test_context[i].to_addr, test_context[i].from_addr, test_context[i].copy_size, NULL, NULL)); } - for (int i = 0; i < sizeof(test_buffer_len) / sizeof(test_buffer_len[0]); i++) { + for (int i = 0; i < sizeof(unaligned_test_buffer_size) / sizeof(unaligned_test_buffer_size[0]); i++) { async_memcpy_verify_and_clear_testbench(i, test_context[i].copy_size, test_context[i].src_buf, test_context[i].dst_buf, test_context[i].from_addr, test_context[i].to_addr); } #endif @@ -328,7 +336,7 @@ static void memcpy_performance_test(uint32_t buffer_size) IDF_LOG_PERFORMANCE("CPU_COPY", "%.2f MB/s, dir: SRAM->SRAM, size: %zu Bytes", throughput, test_context.buffer_size); async_memcpy_verify_and_clear_testbench(test_context.seed, test_context.copy_size, test_context.src_buf, test_context.dst_buf, test_context.from_addr, test_context.to_addr); -#if CONFIG_SPIRAM && SOC_AHB_GDMA_SUPPORT_PSRAM +#if SOC_AHB_GDMA_SUPPORT_PSRAM // 2. PSRAM->PSRAM test_context.src_in_psram = true; test_context.dst_in_psram = true; diff --git a/components/esp_hw_support/test_apps/dma/main/test_dw_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_dw_gdma.c index d4b2b3cf28d..eb927a04b6a 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_dw_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_dw_gdma.c @@ -56,17 +56,20 @@ TEST_CASE("DW_GDMA M2M Test: Contiguous Mode", "[DW_GDMA]") TEST_ASSERT_NOT_NULL(done_sem); printf("prepare the source and destination buffers\r\n"); - uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t sram_alignment = 0; + TEST_ESP_OK(esp_cache_get_alignment(0, &sram_alignment)); + size_t alignment = MAX(sram_alignment, 8); + uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); for (int i = 0; i < 256; i++) { src_buf[i] = i; } -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + if (sram_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } printf("allocate a channel for memory copy\r\n"); dw_gdma_channel_static_config_t static_config = { @@ -117,10 +120,10 @@ TEST_CASE("DW_GDMA M2M Test: Contiguous Mode", "[DW_GDMA]") TEST_ASSERT_EQUAL(pdFALSE, xSemaphoreTake(done_sem, pdMS_TO_TICKS(100))); printf("check the memory copy result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(i, dst_buf[i]); } @@ -145,17 +148,20 @@ TEST_CASE("DW_GDMA M2M Test: Reload Mode", "[DW_GDMA]") TEST_ASSERT_NOT_NULL(done_sem); printf("prepare the source and destination buffers\r\n"); - uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t sram_alignment = 0; + TEST_ESP_OK(esp_cache_get_alignment(0, &sram_alignment)); + size_t alignment = MAX(sram_alignment, 8); + uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); for (int i = 0; i < 256; i++) { src_buf[i] = i; } -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + if (sram_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } printf("allocate a channel for memory copy\r\n"); dw_gdma_channel_static_config_t static_config = { @@ -212,10 +218,10 @@ TEST_CASE("DW_GDMA M2M Test: Reload Mode", "[DW_GDMA]") TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(done_sem, pdMS_TO_TICKS(100))); printf("check the memory copy result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(i, dst_buf[i]); } @@ -264,17 +270,20 @@ TEST_CASE("DW_GDMA M2M Test: Shadow Mode", "[DW_GDMA]") TEST_ASSERT_NOT_NULL(done_sem); printf("prepare the source and destination buffers\r\n"); - uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t sram_alignment = 0; + TEST_ESP_OK(esp_cache_get_alignment(0, &sram_alignment)); + size_t alignment = MAX(sram_alignment, 8); + uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); for (int i = 0; i < 256; i++) { src_buf[i] = i; } -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + if (sram_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } printf("allocate a channel for memory copy\r\n"); dw_gdma_channel_static_config_t static_config = { @@ -334,10 +343,10 @@ TEST_CASE("DW_GDMA M2M Test: Shadow Mode", "[DW_GDMA]") TEST_ASSERT_EQUAL_UINT8(1, user_data.count); printf("check the memory copy result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(i, dst_buf[i]); } @@ -387,17 +396,20 @@ TEST_CASE("DW_GDMA M2M Test: Link-List Mode", "[DW_GDMA]") TEST_ASSERT_NOT_NULL(done_sem); printf("prepare the source and destination buffers\r\n"); - uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + size_t sram_alignment = 0; + TEST_ESP_OK(esp_cache_get_alignment(0, &sram_alignment)); + size_t alignment = MAX(sram_alignment, 8); + uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); for (int i = 0; i < 256; i++) { src_buf[i] = i; } -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + if (sram_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } printf("allocate a channel for memory copy\r\n"); dw_gdma_channel_static_config_t static_config = { @@ -472,10 +484,10 @@ TEST_CASE("DW_GDMA M2M Test: Link-List Mode", "[DW_GDMA]") TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(done_sem, pdMS_TO_TICKS(1000))); printf("check the memory copy result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(i, dst_buf[i]); } @@ -504,10 +516,10 @@ TEST_CASE("DW_GDMA M2M Test: Link-List Mode", "[DW_GDMA]") TEST_ASSERT_EQUAL_UINT8(1, user_data.count); printf("check the memory copy result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(i, dst_buf[i]); } @@ -536,10 +548,10 @@ TEST_CASE("DW_GDMA M2M Test: memory set with fixed address", "[DW_GDMA]") src_buf[i] = 0; } src_buf[0] = 66; -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + if (ext_mem_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } printf("allocate a channel for memory set\r\n"); dw_gdma_channel_static_config_t static_config = { @@ -581,10 +593,10 @@ TEST_CASE("DW_GDMA M2M Test: memory set with fixed address", "[DW_GDMA]") vTaskDelay(pdMS_TO_TICKS(100)); printf("check the memory set result\r\n"); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (int_mem_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } for (int i = 0; i < 256; i++) { TEST_ASSERT_EQUAL_UINT8(66, dst_buf[i]); } diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_gdma.c index 6d3d909d1f8..03c46b1bbf0 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include +#include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -16,6 +17,7 @@ #include "soc/soc_caps.h" #include "hal/gdma_ll.h" #include "hal/cache_ll.h" +#include "hal/cache_hal.h" #include "esp_cache.h" TEST_CASE("GDMA channel allocation", "[GDMA]") @@ -174,80 +176,71 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); TEST_ESP_OK(gdma_connect(rx_chan, m2m_trigger)); - uint8_t *src_buf = heap_caps_aligned_alloc(64, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_alloc(64, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + // allocate the source and destination buffer from SRAM + // |--------------------------------------------------| + // | 128 bytes DMA descriptor | 128 bytes data buffer | + // |--------------------------------------------------| + size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + size_t alignment = MAX(sram_alignment, 8); + uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); - memset(src_buf, 0, 256); - memset(dst_buf, 0, 256); - dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; dma_descriptor_align8_t *rx_descs = (dma_descriptor_align8_t *) dst_buf; - uint8_t *src_data = src_buf + 64; - uint8_t *dst_data = dst_buf + 64; + uint8_t *src_data = src_buf + 128; + uint8_t *dst_data = dst_buf + 128; // prepare the source data for (int i = 0; i < 128; i++) { src_data[i] = i; } + if (sram_alignment) { + // do write-back for the source data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } -#if CONFIG_IDF_TARGET_ESP32P4 - // CPU and DMA both can write to the DMA descriptor, so if there is a cache, multiple descriptors may reside in the same cache line - // causing data inconsistency. To avoid this, we want to access the descriptor memory without the cache. - dma_descriptor_align8_t *tx_descs_noncache = (dma_descriptor_align8_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(tx_descs)); - dma_descriptor_align8_t *rx_descs_noncache = (dma_descriptor_align8_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(rx_descs)); - - tx_descs_noncache[0].buffer = src_data; - tx_descs_noncache[0].dw0.size = 64; - tx_descs_noncache[0].dw0.length = 64; - tx_descs_noncache[0].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - tx_descs_noncache[0].dw0.suc_eof = 0; - tx_descs_noncache[0].next = &tx_descs[1]; // Note, the DMA doesn't recognize a non-cacheable address, here must be the cached address - - tx_descs_noncache[1].buffer = src_data + 64; - tx_descs_noncache[1].dw0.size = 64; - tx_descs_noncache[1].dw0.length = 64; - tx_descs_noncache[1].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - tx_descs_noncache[1].dw0.suc_eof = 1; - tx_descs_noncache[1].next = NULL; - - rx_descs_noncache->buffer = dst_data; - rx_descs_noncache->dw0.size = 128; - rx_descs_noncache->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - rx_descs_noncache->dw0.suc_eof = 1; - rx_descs_noncache->next = NULL; +#ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR + dma_descriptor_align8_t *tx_descs_nc = (dma_descriptor_align8_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(tx_descs)); + dma_descriptor_align8_t *rx_descs_nc = (dma_descriptor_align8_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(rx_descs)); #else - tx_descs->buffer = src_data; - tx_descs->dw0.size = 128; - tx_descs->dw0.length = 128; - tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - tx_descs->dw0.suc_eof = 1; - tx_descs->next = NULL; - - rx_descs->buffer = dst_data; - rx_descs->dw0.size = 128; - rx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - rx_descs->next = NULL; + dma_descriptor_align8_t *tx_descs_nc = tx_descs; + dma_descriptor_align8_t *rx_descs_nc = rx_descs; #endif -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the source data because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); -#endif + tx_descs_nc[0].buffer = src_data; + tx_descs_nc[0].dw0.size = 64; + tx_descs_nc[0].dw0.length = 64; + tx_descs_nc[0].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + tx_descs_nc[0].dw0.suc_eof = 0; + tx_descs_nc[0].next = &tx_descs[1]; // Note, the DMA doesn't recognize a non-cacheable address, here must be the cached address + + tx_descs_nc[1].buffer = src_data + 64; + tx_descs_nc[1].dw0.size = 64; + tx_descs_nc[1].dw0.length = 64; + tx_descs_nc[1].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + tx_descs_nc[1].dw0.suc_eof = 1; + tx_descs_nc[1].next = NULL; + + rx_descs_nc->buffer = dst_data; + rx_descs_nc->dw0.size = 128; + rx_descs_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + rx_descs_nc->dw0.suc_eof = 1; + rx_descs_nc->next = NULL; TEST_ESP_OK(gdma_start(rx_chan, (intptr_t)rx_descs)); TEST_ESP_OK(gdma_start(tx_chan, (intptr_t)tx_descs)); xSemaphoreTake(done_sem, portMAX_DELAY); -#if CONFIG_IDF_TARGET_ESP32P4 - // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); -#endif + if (sram_alignment) { + // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data + TEST_ESP_OK(esp_cache_msync((void *)dst_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + } // check the DMA descriptor write-back feature - TEST_ASSERT_EQUAL(DMA_DESCRIPTOR_BUFFER_OWNER_CPU, tx_descs[0].dw0.owner); - TEST_ASSERT_EQUAL(DMA_DESCRIPTOR_BUFFER_OWNER_CPU, rx_descs[0].dw0.owner); + TEST_ASSERT_EQUAL(DMA_DESCRIPTOR_BUFFER_OWNER_CPU, tx_descs_nc[0].dw0.owner); + TEST_ASSERT_EQUAL(DMA_DESCRIPTOR_BUFFER_OWNER_CPU, rx_descs_nc[0].dw0.owner); for (int i = 0; i < 128; i++) { TEST_ASSERT_EQUAL(i, dst_data[i]); @@ -257,7 +250,7 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl vSemaphoreDelete(done_sem); } -TEST_CASE("GDMA M2M Mode", "[GDMA]") +TEST_CASE("GDMA M2M Mode", "[GDMA][M2M]") { gdma_channel_handle_t tx_chan = NULL; gdma_channel_handle_t rx_chan = NULL; @@ -300,117 +293,3 @@ TEST_CASE("GDMA M2M Mode", "[GDMA]") TEST_ESP_OK(gdma_del_channel(rx_chan)); #endif // SOC_AXI_GDMA_SUPPORTED } - -#if SOC_GDMA_SUPPORT_CRC -typedef struct { - uint32_t init_value; - uint32_t crc_bit_width; - uint32_t poly_hex; - bool reverse_data_mask; - uint32_t expected_result; -} test_crc_case_t; -static test_crc_case_t crc_test_cases[] = { - // CRC8, x^8+x^2+x+1 - [0] = { - .crc_bit_width = 8, - .init_value = 0x00, - .poly_hex = 0x07, - .expected_result = 0xC6, - }, - [1] = { - .crc_bit_width = 8, - .init_value = 0x00, - .poly_hex = 0x07, - .reverse_data_mask = true, // refin = true - .expected_result = 0xDE, - }, - // CRC16, x^16+x^12+x^5+1 - [2] = { - .crc_bit_width = 16, - .init_value = 0xFFFF, - .poly_hex = 0x1021, - .expected_result = 0x5289, - }, - // CRC32, x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 - [3] = { - .crc_bit_width = 32, - .init_value = 0xFFFFFFFF, - .poly_hex = 0x04C11DB7, - .expected_result = 0x63B3E283, - } -}; - -// CRC online: https://www.lddgo.net/en/encrypt/crc -static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_num_crc_algorithm) -{ - uint32_t crc_result = 0; - const char *test_input_string = "Share::Connect::Innovate"; - size_t input_data_size = strlen(test_input_string); - printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string); - - gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); - // get a free DMA trigger ID - uint32_t free_m2m_id_mask = 0; - gdma_get_free_m2m_trig_id_mask(tx_chan, &free_m2m_id_mask); - m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask); - TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); - - uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - TEST_ASSERT_NOT_NULL(src_buf); - dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; - uint8_t *src_data = src_buf + 64; - memcpy(src_data, test_input_string, input_data_size); - - tx_descs->buffer = src_data; - tx_descs->dw0.size = 256 - 64; - tx_descs->dw0.length = input_data_size; - tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - tx_descs->dw0.suc_eof = 1; - tx_descs->next = NULL; - -#if CONFIG_IDF_TARGET_ESP32P4 - // do write-back for the buffer because it's in the cache - Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)src_buf, 256); -#endif - - for (int i = 0; i < test_num_crc_algorithm; i++) { - gdma_crc_calculator_config_t crc_config = { - .crc_bit_width = crc_test_cases[i].crc_bit_width, - .init_value = crc_test_cases[i].init_value, - .poly_hex = crc_test_cases[i].poly_hex, - .reverse_data_mask = crc_test_cases[i].reverse_data_mask, - }; - TEST_ESP_OK(gdma_config_crc_calculator(tx_chan, &crc_config)); - TEST_ESP_OK(gdma_reset(tx_chan)); - TEST_ESP_OK(gdma_start(tx_chan, (intptr_t)tx_descs)); - // simply wait for the transfer done - vTaskDelay(pdMS_TO_TICKS(100)); - TEST_ESP_OK(gdma_crc_get_result(tx_chan, &crc_result)); - printf("CRC Result: 0x%"PRIx32"\r\n", crc_result); - TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result); - } - - free(src_buf); -} - -TEST_CASE("GDMA CRC Calculation", "[GDMA]") -{ - gdma_channel_handle_t tx_chan = NULL; - gdma_channel_alloc_config_t tx_chan_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; -#if SOC_AHB_GDMA_SUPPORTED - printf("Test CRC calculation for AHB GDMA\r\n"); - TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); - test_gdma_crc_calculation(tx_chan, 4); - TEST_ESP_OK(gdma_del_channel(tx_chan)); -#endif // SOC_AHB_GDMA_SUPPORTED - -#if SOC_AXI_GDMA_SUPPORTED - printf("Test CRC calculation for AXI GDMA\r\n"); - TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); - test_gdma_crc_calculation(tx_chan, 3); - TEST_ESP_OK(gdma_del_channel(tx_chan)); -#endif // SOC_AXI_GDMA_SUPPORTED -} -#endif // SOC_GDMA_SUPPORT_CRC diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c new file mode 100644 index 00000000000..b704aa9e662 --- /dev/null +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" +#include "esp_heap_caps.h" +#include "esp_private/gdma.h" +#include "hal/dma_types.h" +#include "soc/soc_caps.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "esp_cache.h" + +typedef struct { + uint32_t init_value; + uint32_t crc_bit_width; + uint32_t poly_hex; + bool reverse_data_mask; + uint32_t expected_result; +} test_crc_case_t; +static test_crc_case_t crc_test_cases[] = { + // CRC8, x^8+x^2+x+1 + [0] = { + .crc_bit_width = 8, + .init_value = 0x00, + .poly_hex = 0x07, + .expected_result = 0xC6, + }, + [1] = { + .crc_bit_width = 8, + .init_value = 0x00, + .poly_hex = 0x07, + .reverse_data_mask = true, // refin = true + .expected_result = 0xDE, + }, + // CRC16, x^16+x^12+x^5+1 + [2] = { + .crc_bit_width = 16, + .init_value = 0xFFFF, + .poly_hex = 0x1021, + .expected_result = 0x5289, + }, + // CRC32, x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + [3] = { + .crc_bit_width = 32, + .init_value = 0xFFFFFFFF, + .poly_hex = 0x04C11DB7, + .expected_result = 0x63B3E283, + } +}; + +// CRC online: https://www.lddgo.net/en/encrypt/crc +static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_num_crc_algorithm) +{ + uint32_t crc_result = 0; + const char *test_input_string = "Share::Connect::Innovate"; + size_t input_data_size = strlen(test_input_string); + printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string); + + gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); + // get a free DMA trigger ID + uint32_t free_m2m_id_mask = 0; + gdma_get_free_m2m_trig_id_mask(tx_chan, &free_m2m_id_mask); + m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask); + TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); + + // allocate the source and destination buffer from SRAM + // |--------------------------------------------------| + // | 128 bytes DMA descriptor | 128 bytes data buffer | + // |--------------------------------------------------| + size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + uint8_t *src_buf = heap_caps_aligned_calloc(sram_alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(src_buf); + dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; + uint8_t *src_data = src_buf + 64; + memcpy(src_data, test_input_string, input_data_size); + + tx_descs->buffer = src_data; + tx_descs->dw0.size = 256 - 64; + tx_descs->dw0.length = input_data_size; + tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + tx_descs->dw0.suc_eof = 1; + tx_descs->next = NULL; + + if (sram_alignment) { + // do write-back for the buffer because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } + + for (int i = 0; i < test_num_crc_algorithm; i++) { + gdma_crc_calculator_config_t crc_config = { + .crc_bit_width = crc_test_cases[i].crc_bit_width, + .init_value = crc_test_cases[i].init_value, + .poly_hex = crc_test_cases[i].poly_hex, + .reverse_data_mask = crc_test_cases[i].reverse_data_mask, + }; + TEST_ESP_OK(gdma_config_crc_calculator(tx_chan, &crc_config)); + TEST_ESP_OK(gdma_reset(tx_chan)); + TEST_ESP_OK(gdma_start(tx_chan, (intptr_t)tx_descs)); + // simply wait for the transfer done + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ESP_OK(gdma_crc_get_result(tx_chan, &crc_result)); + printf("CRC Result: 0x%"PRIx32"\r\n", crc_result); + TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result); + } + + free(src_buf); +} + +TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]") +{ + gdma_channel_handle_t tx_chan = NULL; + gdma_channel_alloc_config_t tx_chan_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_TX, + }; +#if SOC_AHB_GDMA_SUPPORTED + printf("Test CRC calculation for AHB GDMA\r\n"); + TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); + test_gdma_crc_calculation(tx_chan, 4); + TEST_ESP_OK(gdma_del_channel(tx_chan)); +#endif // SOC_AHB_GDMA_SUPPORTED + +#if SOC_AXI_GDMA_SUPPORTED + printf("Test CRC calculation for AXI GDMA\r\n"); + TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); + test_gdma_crc_calculation(tx_chan, 3); + TEST_ESP_OK(gdma_del_channel(tx_chan)); +#endif // SOC_AXI_GDMA_SUPPORTED +} diff --git a/components/esp_hw_support/test_apps/etm/main/test_gdma_etm.c b/components/esp_hw_support/test_apps/dma/main/test_gdma_etm.c similarity index 96% rename from components/esp_hw_support/test_apps/etm/main/test_gdma_etm.c rename to components/esp_hw_support/test_apps/dma/main/test_gdma_etm.c index 3ecedea8585..51e8a7d540b 100644 --- a/components/esp_hw_support/test_apps/etm/main/test_gdma_etm.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma_etm.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,7 @@ #include "driver/gpio.h" #include "esp_async_memcpy.h" -TEST_CASE("async_memcpy_eof_event", "[etm]") +TEST_CASE("async_memcpy_eof_event", "[GDMA][ETM]") { const uint32_t output_gpio = 1; // async_memcpy done ---> ETM channel A ---> GPIO toggle diff --git a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt index 214712238d3..e9207be15a1 100644 --- a/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/etm/main/CMakeLists.txt @@ -13,10 +13,6 @@ if(CONFIG_SOC_SYSTIMER_SUPPORT_ETM) list(APPEND srcs "test_systimer_etm.c") endif() -if(CONFIG_SOC_GDMA_SUPPORT_ETM) - list(APPEND srcs "test_gdma_etm.c") -endif() - if(CONFIG_SOC_MCPWM_SUPPORT_ETM) list(APPEND srcs "test_mcpwm_etm.c") endif() From 0440d582dced5dde7baf1136f1b4c29fcab010f8 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Fri, 19 Apr 2024 16:05:21 +0200 Subject: [PATCH 009/548] docs(performance): Add esp32p4/c5 relevant information to the performance guides in speed.rst: - add startup time increase info when spiram test is enabled - add startup time increase info when spiram is enabled and poisoning comprehensive is enabled - add L2 cache variable size info to optimize IRAM space / cache misses - update sections refencing bluetooth/wifi built-in tasks to not show related info for p4 targets. - Add IDF_TARGET_RF_TYPE for esp32c5 in ram-usage.rst: - add L2 cache variable size info to maximize RAM space Remove the files from esp32c5.txt and esp32p4.txt that are no longer in need of update. --- docs/docs_not_updated/esp32c5.txt | 4 -- docs/docs_not_updated/esp32p4.txt | 4 -- docs/en/api-guides/performance/ram-usage.rst | 17 +++++++ docs/en/api-guides/performance/speed.rst | 53 ++++++++++++++++++-- 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 326cbc716c5..583e7cec834 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -7,10 +7,6 @@ contribute/copyright-guide.rst contribute/install-pre-commit-hook.rst contribute/index.rst api-guides/core_dump_internals.rst -api-guides/performance/speed.rst -api-guides/performance/size.rst -api-guides/performance/ram-usage.rst -api-guides/performance/index.rst api-guides/jtag-debugging/debugging-examples.rst api-guides/jtag-debugging/configure-ft2232h-jtag.rst api-guides/jtag-debugging/tips-and-quirks.rst diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index c7e0c82202e..53c92113420 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -1,7 +1,3 @@ -api-guides/performance/speed.rst -api-guides/performance/size.rst -api-guides/performance/ram-usage.rst -api-guides/performance/index.rst api-guides/partition-tables.rst api-guides/app_trace.rst api-guides/thread-local-storage.rst diff --git a/docs/en/api-guides/performance/ram-usage.rst b/docs/en/api-guides/performance/ram-usage.rst index 6ef063cde75..68c7fefc4ae 100644 --- a/docs/en/api-guides/performance/ram-usage.rst +++ b/docs/en/api-guides/performance/ram-usage.rst @@ -183,6 +183,7 @@ The following options will reduce IRAM usage of some ESP-IDF features: Any memory that ends up unused for static IRAM will be added to the heap. + .. only:: esp32c3 Flash Suspend Feature @@ -233,3 +234,19 @@ The following options will reduce IRAM usage of some ESP-IDF features: .. note:: Other configuration options exist that will increase IRAM usage by moving some functionality into IRAM, usually for performance, but the default option is not to do this. These are not listed here. The IRAM size impact of enabling these options is usually noted in the configuration item help text. + + +.. only:: esp32s2 or esp32s3 or esp32p4 + + Change cache size + ^^^^^^^^^^^^^^^^^ + + The {IDF_TARGET_NAME} RAM memory available size is dependent on the size of cache. Decreasing the cache size in the Kconfig options listed below will result in increasing the available RAM. + + .. list:: + + :esp32s2: - :ref:`CONFIG_ESP32S2_INSTRUCTION_CACHE_SIZE` + :esp32s2: - :ref:`CONFIG_ESP32S2_DATA_CACHE_SIZE` + :esp32s3: - :ref:`CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE` + :esp32s3: - :ref:`CONFIG_ESP32S3_DATA_CACHE_SIZE` + :esp32p4: - :ref:`CONFIG_CACHE_L2_CACHE_SIZE` diff --git a/docs/en/api-guides/performance/speed.rst b/docs/en/api-guides/performance/speed.rst index 017707144e6..9f59ad065ee 100644 --- a/docs/en/api-guides/performance/speed.rst +++ b/docs/en/api-guides/performance/speed.rst @@ -4,7 +4,7 @@ Speed Optimization :link_to_translation:`zh_CN:[中文]` {IDF_TARGET_CONTROLLER_CORE_CONFIG:default="CONFIG_BT_CTRL_PINNED_TO_CORE", esp32="CONFIG_BTDM_CTRL_PINNED_TO_CORE_CHOICE", esp32s3="CONFIG_BT_CTRL_PINNED_TO_CORE_CHOICE"} -{IDF_TARGET_RF_TYPE:default="Wi-Fi/Bluetooth", esp32s2="Wi-Fi", esp32c6="Wi-Fi/Bluetooth/802.15.4", esp32h2="Bluetooth/802.15.4"} +{IDF_TARGET_RF_TYPE:default="Wi-Fi/Bluetooth", esp32s2="Wi-Fi", esp32c6="Wi-Fi/Bluetooth/802.15.4", esp32h2="Bluetooth/802.15.4, esp32c5="Wi-Fi/Bluetooth/802.15.4"} Overview -------- @@ -88,6 +88,36 @@ The following optimizations improve the execution of nearly all code, including :not SOC_CPU_HAS_FPU: - Avoid using floating point arithmetic ``float``. On {IDF_TARGET_NAME} these calculations are emulated in software and are very slow. If possible, use fixed point representations, a different method of integer representation, or convert part of the calculation to be integer only before switching to floating point. - Avoid using double precision floating point arithmetic ``double``. These calculations are emulated in software and are very slow. If possible then use an integer-based representation, or single-precision floating point. + +.. only:: esp32s2 or esp32s3 or esp32p4 + + Change cache size + ^^^^^^^^^^^^^^^^^ + + On {IDF_TARGET_NAME}, increasing the overall speed can be achieved to some degree by increasing the size of cache and thus potentially decreasing the frequency of "cache misses" through the Kconfig option(s) listed below. + + .. list:: + + :esp32s2: - :ref:`CONFIG_ESP32S2_INSTRUCTION_CACHE_SIZE`. + :esp32s2: - :ref:`CONFIG_ESP32S2_DATA_CACHE_SIZE`. + :esp32s3: - :ref:`CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE`. + :esp32s3: - :ref:`CONFIG_ESP32S3_DATA_CACHE_SIZE`. + :esp32p4: - :ref:`CONFIG_CACHE_L2_CACHE_SIZE`. + + + .. note:: + + Increasing the cache size will also result in reducing the amount of available RAM. + + +.. only:: SOC_CACHE_L2_CACHE_SIZE_CONFIGURABLE + + .. note:: + + On {IDF_TARGET_NAME}, the L2 cache size is configurable via the Kconfig option :ref:`CONFIG_CACHE_L2_CACHE_SIZE`. + Setting the L2 cache size to its smallest value will maximize the available RAM while also potentially augmenting the frequency of "cache misses". + Setting the L2 cache size to its largest value will potentially lower the frequency of "cache misses" at the cost of reducing the available RAM. + Reduce Logging Overhead ^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,6 +140,7 @@ The following options also increase execution speed, but are not recommended as .. _speed-targeted-optimizations: + Targeted Optimizations ---------------------- @@ -134,6 +165,8 @@ In addition to the overall performance improvements shown above, the following o :SOC_RTC_FAST_MEM_SUPPORTED: - If using Deep-sleep mode, setting :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` allows a faster wake from sleep. Note that if using Secure Boot, this represents a security compromise, as Secure Boot validation are not be performed on wake. - Setting :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON` skips verifying the binary on every boot from the power-on reset. How much time this saves depends on the binary size and the flash settings. Note that this setting carries some risk if the flash becomes corrupt unexpectedly. Read the help text of the :ref:`config item ` for an explanation and recommendations if using this option. - It is possible to save a small amount of time during boot by disabling RTC slow clock calibration. To do so, set :ref:`CONFIG_RTC_CLK_CAL_CYCLES` to 0. Any part of the firmware that uses RTC slow clock as a timing source will be less accurate as a result. + :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling memory test on the external memory (:ref:`CONFIG_SPIRAM_MEMTEST`) can have a large impact on startup time (approximately 1 second per 4MiB of memory tested). Disabling the memory tests will reduce startup time at the expense of testing the external memory. + :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling comprehensive poisoning will increase the startup time (approximately 300 milliseconds per 4MiB of memory set) since all the memory used as heap (including the external memory) will be set to a default value. The example project :example:`system/startup_time` is pre-configured to optimize startup time. The file :example_file:`system/startup_time/sdkconfig.defaults` contain all of these settings. You can append these to the end of your project's own ``sdkconfig`` file to merge the settings, but please read the documentation for each setting first. @@ -206,13 +239,25 @@ Choosing Task Priorities of the Application .. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES - In general, it is not recommended to set task priorities higher than the built-in {IDF_TARGET_RF_TYPE} operations as starving them of CPU may make the system unstable. For very short timing-critical operations that do not use the network, use an ISR or a very restricted task (with very short bursts of runtime only) at the highest priority (24). Choosing priority 19 allows lower-layer {IDF_TARGET_RF_TYPE} functionality to run without delays, but still preempts the lwIP TCP/IP stack and other less time-critical internal functionality - this is the best option for time-critical tasks that do not perform network operations. Any task that does TCP/IP network operations should run at a lower priority than the lwIP TCP/IP task (18) to avoid priority-inversion issues. + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED -.. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES + In general, it is not recommended to set task priorities higher than the built-in {IDF_TARGET_RF_TYPE} operations as starving them of CPU may make the system unstable. + + For very short timing-critical operations that do not use the network, use an ISR or a very restricted task (with very short bursts of runtime only) at the highest priority (24). + + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED + + Choosing priority 19 allows lower-layer {IDF_TARGET_RF_TYPE} functionality to run without delays, but still preempts the lwIP TCP/IP stack and other less time-critical internal functionality - this is the best option for time-critical tasks that do not perform network operations. + + Any task that does TCP/IP network operations should run at a lower priority than the lwIP TCP/IP task (18) to avoid priority-inversion issues. + +.. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES With a few exceptions, most importantly the lwIP TCP/IP task, in the default configuration most built-in tasks are pinned to Core 0. This makes it quite easy for the application to place high priority tasks on Core 1. Using priority 19 or higher guarantees that an application task can run on Core 1 without being preempted by any built-in task. To further isolate the tasks running on each CPU, configure the :ref:`lwIP task ` to only run on Core 0 instead of either core, which may reduce total TCP/IP throughput depending on what other tasks are running. - In general, it is not recommended to set task priorities on Core 0 higher than the built-in {IDF_TARGET_RF_TYPE} operations as starving them of CPU may make the system unstable. Choosing priority 19 and Core 0 allows lower-layer {IDF_TARGET_RF_TYPE} functionality to run without delays, but still pre-empts the lwIP TCP/IP stack and other less time-critical internal functionality. This is an option for time-critical tasks that do not perform network operations. Any task that does TCP/IP network operations should run at lower priority than the lwIP TCP/IP task (18) to avoid priority-inversion issues. + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED + + In general, it is not recommended to set task priorities on Core 0 higher than the built-in {IDF_TARGET_RF_TYPE} operations as starving them of CPU may make the system unstable. Choosing priority 19 and Core 0 allows lower-layer {IDF_TARGET_RF_TYPE} functionality to run without delays, but still pre-empts the lwIP TCP/IP stack and other less time-critical internal functionality. This is an option for time-critical tasks that do not perform network operations. Any task that does TCP/IP network operations should run at lower priority than the lwIP TCP/IP task (18) to avoid priority-inversion issues. .. note:: From 3386c594b4296d97edb5008855826edc62cce85c Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Wed, 24 Apr 2024 15:14:13 +0200 Subject: [PATCH 010/548] ci: fix size.json path for app --- tools/ci/idf_ci/uploader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/idf_ci/uploader.py b/tools/ci/idf_ci/uploader.py index 47dfcd7a433..e42837884d5 100644 --- a/tools/ci/idf_ci/uploader.py +++ b/tools/ci/idf_ci/uploader.py @@ -60,7 +60,7 @@ class AppUploader(AppDownloader): DEFAULT_BUILD_LOG_FILENAME, ], ArtifactType.SIZE_REPORTS: [ - '**/build*/size.json', + 'size.json', ], } From 5b3996885c20d5fe04ba6e47ee79bd3eaa8717fc Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Thu, 25 Apr 2024 16:54:48 +0800 Subject: [PATCH 011/548] ci: quote spec character in url --- conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conftest.py b/conftest.py index 17c5f11549c..79e5ad464a2 100644 --- a/conftest.py +++ b/conftest.py @@ -26,6 +26,7 @@ import zipfile from copy import deepcopy from datetime import datetime +from urllib.parse import quote import common_test_methods # noqa: F401 import gitlab_api @@ -478,7 +479,7 @@ def get_path(x: str) -> str: dut_artifacts_url.append('{}:'.format(_dut.test_case_name)) for file in logs_files: - dut_artifacts_url.append(' - {}'.format(file)) + dut_artifacts_url.append(' - {}'.format(quote(file, safe=':/'))) def pytest_terminal_summary(terminalreporter, exitstatus, config): # type: ignore From d910ca7fa8ad9bf8d246e780f42739efe324ab84 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 23 Apr 2024 18:12:35 +0800 Subject: [PATCH 012/548] feat(mipi_dsi): add pm lock for clock source --- components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c | 13 +++++++++++++ components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 13 +++++++++++++ components/esp_lcd/dsi/mipi_dsi_priv.h | 2 ++ .../test_apps/mipi_dsi_lcd/sdkconfig.ci.release | 5 +++++ 4 files changed, 33 insertions(+) create mode 100644 components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.release diff --git a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c index 9ecab59f6d7..1447a122a7e 100644 --- a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c +++ b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c @@ -55,6 +55,15 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc mipi_dsi_ll_enable_phy_reference_clock(bus_id, true); } +#if CONFIG_PM_ENABLE + // When MIPI DSI is working, we don't expect the clock source would be turned off + esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; + ret = esp_pm_lock_create(pm_lock_type, 0, "dsi_phy", &dsi_bus->pm_lock); + ESP_GOTO_ON_ERROR(ret, err, TAG, "create PM lock failed"); + // before we configure the PLL, we want the clock source to be stable + esp_pm_lock_acquire(dsi_bus->pm_lock); +#endif + // initialize HAL context mipi_dsi_hal_config_t hal_config = { .bus_id = bus_id, @@ -125,6 +134,10 @@ esp_err_t esp_lcd_del_dsi_bus(esp_lcd_dsi_bus_handle_t bus) DSI_RCC_ATOMIC() { mipi_dsi_ll_enable_bus_clock(bus_id, false); } + if (bus->pm_lock) { + esp_pm_lock_release(bus->pm_lock); + esp_pm_lock_delete(bus->pm_lock); + } free(bus); return ESP_OK; } diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 9c707920290..3eed7e6b347 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -42,6 +42,7 @@ struct esp_lcd_dpi_panel_t { dw_gdma_link_list_handle_t link_lists[DPI_PANEL_MAX_FB_NUM]; // DMA link list esp_async_fbcpy_handle_t fbcpy_handle; // Use DMA2D to do frame buffer copy SemaphoreHandle_t draw_sem; // A semaphore used to synchronize the draw operations when DMA2D is used + esp_pm_lock_handle_t pm_lock; // Power management lock esp_lcd_dpi_panel_color_trans_done_cb_t on_color_trans_done; // Callback invoked when color data transfer has finished esp_lcd_dpi_panel_refresh_done_cb_t on_refresh_done; // Callback invoked when one refresh operation finished (kinda like a vsync end) void *user_ctx; // User context for the callback @@ -232,6 +233,14 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ mipi_dsi_ll_enable_dpi_clock(bus_id, true); } +#if CONFIG_PM_ENABLE + // When MIPI DSI is working, we don't expect the clock source would be turned off + esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP; + ret = esp_pm_lock_create(pm_lock_type, 0, "dsi_dpi", &dpi_panel->pm_lock); + ESP_GOTO_ON_ERROR(ret, err, TAG, "create PM lock failed"); + esp_pm_lock_acquire(dpi_panel->pm_lock); +#endif + // create DMA resources ESP_GOTO_ON_ERROR(dpi_panel_create_dma_link(dpi_panel), err, TAG, "initialize DMA link failed"); @@ -318,6 +327,10 @@ static esp_err_t dpi_panel_del(esp_lcd_panel_t *panel) if (dpi_panel->draw_sem) { vSemaphoreDelete(dpi_panel->draw_sem); } + if (dpi_panel->pm_lock) { + esp_pm_lock_release(dpi_panel->pm_lock); + esp_pm_lock_delete(dpi_panel->pm_lock); + } free(dpi_panel); return ESP_OK; } diff --git a/components/esp_lcd/dsi/mipi_dsi_priv.h b/components/esp_lcd/dsi/mipi_dsi_priv.h index cdf89e30e30..57a7407864b 100644 --- a/components/esp_lcd/dsi/mipi_dsi_priv.h +++ b/components/esp_lcd/dsi/mipi_dsi_priv.h @@ -9,6 +9,7 @@ #include "hal/mipi_dsi_ll.h" #include "esp_heap_caps.h" #include "esp_private/periph_ctrl.h" +#include "esp_pm.h" #if SOC_PERIPH_CLK_CTRL_SHARED #define DSI_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() @@ -35,6 +36,7 @@ extern "C" { typedef struct esp_lcd_dsi_bus_t { int bus_id; mipi_dsi_hal_context_t hal; + esp_pm_lock_handle_t pm_lock; } esp_lcd_dsi_bus_t; #ifdef __cplusplus diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.release b/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.release new file mode 100644 index 00000000000..91d93f163e6 --- /dev/null +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y From 49aaac0013d3c52548a8ee2ae25d785790ba27b3 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 23 Apr 2024 17:30:35 +0800 Subject: [PATCH 013/548] feat(mipi_dsi): support isr iram safe --- components/esp_hw_support/dma/Kconfig.dma | 11 +- components/esp_hw_support/dma/linker.lf | 5 + components/esp_lcd/Kconfig | 15 +++ components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 12 ++ components/esp_lcd/dsi/mipi_dsi_priv.h | 6 +- .../esp_lcd/test_apps/.build-test-rules.yml | 2 +- .../test_apps/mipi_dsi_lcd/CMakeLists.txt | 13 ++ .../mipi_dsi_lcd/main/CMakeLists.txt | 4 + .../mipi_dsi_lcd/main/test_mipi_dsi_iram.c | 119 ++++++++++++++++++ .../mipi_dsi_lcd/pytest_mipi_dsi_lcd.py | 11 +- .../mipi_dsi_lcd/sdkconfig.ci.iram_safe | 8 ++ 11 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_iram.c create mode 100644 components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.iram_safe diff --git a/components/esp_hw_support/dma/Kconfig.dma b/components/esp_hw_support/dma/Kconfig.dma index 48aef8846a1..fa43dd6ea8e 100644 --- a/components/esp_hw_support/dma/Kconfig.dma +++ b/components/esp_hw_support/dma/Kconfig.dma @@ -19,7 +19,7 @@ menu "GDMA Configurations" bool "Enable debug log" default n help - Wether to enable the debug log message for GDMA driver. + Whether to enable the debug log message for GDMA driver. Note that, this option only controls the GDMA driver log, won't affect other drivers. endmenu # GDMA Configurations @@ -40,6 +40,13 @@ menu "DW_GDMA Configurations" Place DW_GDMA setter functions (e.g. dw_gdma_channel_set_block_markers) into IRAM, so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. + config DW_GDMA_GETTER_FUNC_IN_IRAM + bool + default n + help + Place DW_GDMA getter functions (e.g. dw_gdma_link_list_get_item) into IRAM, + so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. + config DW_GDMA_ISR_IRAM_SAFE bool default n @@ -52,7 +59,7 @@ menu "DW_GDMA Configurations" bool "Enable debug log" default n help - Wether to enable the debug log message for DW_GDMA driver. + Whether to enable the debug log message for DW_GDMA driver. Note that, this option only controls the DW_GDMA driver log, won't affect other drivers. endmenu # DW_GDMA Configurations diff --git a/components/esp_hw_support/dma/linker.lf b/components/esp_hw_support/dma/linker.lf index c4ace066f19..0acf4b6f212 100644 --- a/components/esp_hw_support/dma/linker.lf +++ b/components/esp_hw_support/dma/linker.lf @@ -78,10 +78,15 @@ entries: # put DW_GDMA control functions in IRAM if DW_GDMA_CTRL_FUNC_IN_IRAM = y: dw_gdma: dw_gdma_channel_continue (noflash) + dw_gdma: dw_gdma_channel_enable_ctrl (noflash) if DW_GDMA_SETTER_FUNC_IN_IRAM = y: dw_gdma: dw_gdma_channel_set_block_markers (noflash) dw_gdma: dw_gdma_lli_set_block_markers (noflash) + dw_gdma: dw_gdma_channel_use_link_list (noflash) + + if DW_GDMA_GETTER_FUNC_IN_IRAM = y: + dw_gdma: dw_gdma_link_list_get_item (noflash) [mapping:dma2d_driver] archive: libesp_hw_support.a diff --git a/components/esp_lcd/Kconfig b/components/esp_lcd/Kconfig index 60cde6973cb..1f93e5e0361 100644 --- a/components/esp_lcd/Kconfig +++ b/components/esp_lcd/Kconfig @@ -36,5 +36,20 @@ menu "LCD and Touch Panel" Only need to enable it when in your application, the DMA can't deliver data as fast as the LCD consumes it. endif # SOC_LCD_RGB_SUPPORTED + + if SOC_MIPI_DSI_SUPPORTED + config LCD_DSI_ISR_IRAM_SAFE + bool "DSI LCD ISR IRAM-Safe" + default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM + help + Ensure the LCD interrupt is IRAM-Safe by allowing the interrupt handler to be + executable when the cache is disabled (e.g. SPI Flash write). + If you want the LCD driver to keep flushing the screen even when cache ops disabled, + you can enable this option. Note, this will also increase the IRAM usage. + endif # SOC_MIPI_DSI_SUPPORTED endmenu endmenu diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 3eed7e6b347..71375bbf787 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -14,6 +14,7 @@ #include "esp_cache.h" #include "mipi_dsi_priv.h" #include "esp_async_fbcpy.h" +#include "esp_memory_utils.h" #include "esp_private/dw_gdma.h" #include "hal/cache_hal.h" #include "hal/cache_ll.h" @@ -528,6 +529,17 @@ esp_err_t esp_lcd_dpi_panel_register_event_callbacks(esp_lcd_panel_handle_t pane { ESP_RETURN_ON_FALSE(panel && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base); +#if CONFIG_LCD_DSI_ISR_IRAM_SAFE + if (cbs->on_color_trans_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_color_trans_done), ESP_ERR_INVALID_ARG, TAG, "on_color_trans_done callback not in IRAM"); + } + if (cbs->on_refresh_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_refresh_done), ESP_ERR_INVALID_ARG, TAG, "on_refresh_done callback not in IRAM"); + } + if (user_ctx) { + ESP_RETURN_ON_FALSE(esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); + } +#endif // CONFIG_LCD_RGB_ISR_IRAM_SAFE dpi_panel->on_color_trans_done = cbs->on_color_trans_done; dpi_panel->on_refresh_done = cbs->on_refresh_done; dpi_panel->user_ctx = user_ctx; diff --git a/components/esp_lcd/dsi/mipi_dsi_priv.h b/components/esp_lcd/dsi/mipi_dsi_priv.h index 57a7407864b..eebf93e2e89 100644 --- a/components/esp_lcd/dsi/mipi_dsi_priv.h +++ b/components/esp_lcd/dsi/mipi_dsi_priv.h @@ -23,7 +23,11 @@ #define DSI_RCC_ATOMIC() #endif -#define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#if CONFIG_LCD_DSI_ISR_IRAM_SAFE +#define DSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif #define DPI_PANEL_MAX_FB_NUM 3 // maximum number of supported frame buffers for DPI panel diff --git a/components/esp_lcd/test_apps/.build-test-rules.yml b/components/esp_lcd/test_apps/.build-test-rules.yml index a4c2fd49952..998917f0ab9 100644 --- a/components/esp_lcd/test_apps/.build-test-rules.yml +++ b/components/esp_lcd/test_apps/.build-test-rules.yml @@ -38,7 +38,7 @@ components/esp_lcd/test_apps/mipi_dsi_lcd: disable_test: - if: IDF_TARGET == "esp32p4" temporary: true - reason: lack of runners + reason: lack of runners, DSI can't work without an LCD connected components/esp_lcd/test_apps/rgb_lcd: depends_components: diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/CMakeLists.txt b/components/esp_lcd/test_apps/mipi_dsi_lcd/CMakeLists.txt index b28d8784fe7..9a4ba3eaaa2 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/CMakeLists.txt +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/CMakeLists.txt @@ -6,3 +6,16 @@ set(COMPONENTS main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(mipi_dsi_lcd_panel_test) + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target(check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_lcd/,${CMAKE_BINARY_DIR}/esp-idf/hal/ + --elf-file ${CMAKE_BINARY_DIR}/mipi_dsi_lcd_panel_test.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/CMakeLists.txt b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/CMakeLists.txt index ab9796d92d2..8ee501adaed 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/CMakeLists.txt +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/CMakeLists.txt @@ -2,6 +2,10 @@ set(srcs "test_app_main.c" "test_mipi_dsi_board.c" "test_mipi_dsi_panel.c") +if(CONFIG_LCD_DSI_ISR_IRAM_SAFE) + list(APPEND srcs "test_mipi_dsi_iram.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_iram.c b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_iram.c new file mode 100644 index 00000000000..85cef15288f --- /dev/null +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_iram.c @@ -0,0 +1,119 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_panel_io.h" +#include "esp_random.h" +#include "esp_attr.h" +#include "test_mipi_dsi_board.h" +#include "esp_lcd_ili9881c.h" + +IRAM_ATTR static bool test_rgb_panel_count_in_callback(esp_lcd_panel_handle_t panel, esp_lcd_dpi_panel_event_data_t *edata, void *user_ctx) +{ + uint32_t *count = (uint32_t *)user_ctx; + *count = *count + 1; + return false; +} + +static void IRAM_ATTR test_delay_post_cache_disable(void *args) +{ + esp_rom_delay_us(200000); +} + +#define TEST_IMG_SIZE (100 * 100 * sizeof(uint16_t)) + +TEST_CASE("MIPI DSI draw bitmap (ILI9881C) IRAM Safe", "[mipi_dsi]") +{ + esp_lcd_dsi_bus_handle_t mipi_dsi_bus; + esp_lcd_panel_io_handle_t mipi_dbi_io; + esp_lcd_panel_handle_t mipi_dpi_panel; + esp_lcd_panel_handle_t ili9881c_ctrl_panel; + + test_bsp_enable_dsi_phy_power(); + + uint8_t *img = malloc(TEST_IMG_SIZE); + TEST_ASSERT_NOT_NULL(img); + + esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = 2, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 1000, // 1000 Mbps + }; + TEST_ESP_OK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); + + esp_lcd_dbi_io_config_t dbi_config = { + .virtual_channel = 0, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + }; + TEST_ESP_OK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + esp_lcd_panel_dev_config_t lcd_dev_config = { + .bits_per_pixel = 16, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .reset_gpio_num = -1, + }; + TEST_ESP_OK(esp_lcd_new_panel_ili9881c(mipi_dbi_io, &lcd_dev_config, &ili9881c_ctrl_panel)); + TEST_ESP_OK(esp_lcd_panel_reset(ili9881c_ctrl_panel)); + TEST_ESP_OK(esp_lcd_panel_init(ili9881c_ctrl_panel)); + // turn on display + TEST_ESP_OK(esp_lcd_panel_disp_on_off(ili9881c_ctrl_panel, true)); + + esp_lcd_dpi_panel_config_t dpi_config = { + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = MIPI_DSI_DPI_CLK_MHZ, + .virtual_channel = 0, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, + .video_timing = { + .h_size = MIPI_DSI_LCD_H_RES, + .v_size = MIPI_DSI_LCD_V_RES, + .hsync_back_porch = MIPI_DSI_LCD_HBP, + .hsync_pulse_width = MIPI_DSI_LCD_HSYNC, + .hsync_front_porch = MIPI_DSI_LCD_HFP, + .vsync_back_porch = MIPI_DSI_LCD_VBP, + .vsync_pulse_width = MIPI_DSI_LCD_VSYNC, + .vsync_front_porch = MIPI_DSI_LCD_VFP, + }, + }; + TEST_ESP_OK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, &mipi_dpi_panel)); + TEST_ESP_OK(esp_lcd_panel_init(mipi_dpi_panel)); + uint32_t callback_calls = 0; + esp_lcd_dpi_panel_event_callbacks_t cbs = { + .on_refresh_done = test_rgb_panel_count_in_callback, + }; + TEST_ESP_OK(esp_lcd_dpi_panel_register_event_callbacks(mipi_dpi_panel, &cbs, &callback_calls)); + + uint8_t color_byte = rand() & 0xFF; + int x_start = rand() % (MIPI_DSI_LCD_H_RES - 100); + int y_start = rand() % (MIPI_DSI_LCD_V_RES - 100); + memset(img, color_byte, TEST_IMG_SIZE); + esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, img); + vTaskDelay(pdMS_TO_TICKS(100)); + + printf("The LCD driver should keep flushing the color block in the background\r\n"); + + // disable the cache for a while, the LCD driver should stay working + printf("disable the cache for a while\r\n"); + unity_utils_run_cache_disable_stub(test_delay_post_cache_disable, NULL); + printf("callback calls: %"PRIu32"\r\n", callback_calls); + TEST_ASSERT(callback_calls > 2); + + TEST_ESP_OK(esp_lcd_panel_del(mipi_dpi_panel)); + TEST_ESP_OK(esp_lcd_panel_del(ili9881c_ctrl_panel)); + TEST_ESP_OK(esp_lcd_panel_io_del(mipi_dbi_io)); + TEST_ESP_OK(esp_lcd_del_dsi_bus(mipi_dsi_bus)); + free(img); + + test_bsp_disable_dsi_phy_power(); +} diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/pytest_mipi_dsi_lcd.py b/components/esp_lcd/test_apps/mipi_dsi_lcd/pytest_mipi_dsi_lcd.py index eab77ed4c9f..7e4dc07e7d1 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/pytest_mipi_dsi_lcd.py +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/pytest_mipi_dsi_lcd.py @@ -1,11 +1,18 @@ # SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @pytest.mark.esp32p4 @pytest.mark.generic -def test_rgb_lcd(dut: Dut) -> None: +@pytest.mark.parametrize( + 'config', + [ + 'iram_safe', + 'release', + ], + indirect=True, +) +def test_dsi_lcd(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.iram_safe b/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.iram_safe new file mode 100644 index 00000000000..9d1d9f005f3 --- /dev/null +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/sdkconfig.ci.iram_safe @@ -0,0 +1,8 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +# silent the error check, as the error string are stored in rodata, causing RTL check failure +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y +# place non-ISR FreeRTOS functions in Flash +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_LCD_DSI_ISR_IRAM_SAFE=y From 0fcc940bc17b059965146978ff7398fe3f561849 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Wed, 24 Apr 2024 11:56:39 +0800 Subject: [PATCH 014/548] fix(ble/controller): Update esp32 bt-lib (4012cfb) - Fixed BLE coex assert - Fixed BLE DTM status and tx count --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 44341b15e58..43ecd22ec6b 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 44341b15e58792946cc65ed8d4483929194d182f +Subproject commit 43ecd22ec6b5b484709693ae8e86478a7f130f17 From 212f316f249085bf0e50bb1220064061e68b373f Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Fri, 26 Apr 2024 14:59:31 +0800 Subject: [PATCH 015/548] feat(ble/bluedroid): Support BLE command status debug log --- components/bt/host/bluedroid/stack/btu/btu_hcif.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 43ec8b1b7f0..e856594be4d 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1252,6 +1252,9 @@ static void btu_hcif_command_complete_evt(BT_HDR *response, void *context) static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_cmd, void *p_vsc_status_cback) { + if (status != HCI_SUCCESS){ + HCI_TRACE_WARNING("%s,opcode:0x%04x,status:0x%02x", __func__, opcode,status); + } BD_ADDR bd_addr; UINT16 handle; #if BTM_SCO_INCLUDED == TRUE From 6a5ab204899017ca5b96ea51e549b0fe745c21b8 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Thu, 25 Apr 2024 11:13:52 +0200 Subject: [PATCH 016/548] ci(tools): Fix IDF_MIRROR_PREFIX_MAP for including all tools from local --- .gitlab/ci/host-test.yml | 2 +- .gitlab/ci/test-win.yml | 2 +- tools/test_idf_tools/test_idf_tools.py | 17 ++++++++++------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index edca658bd4d..f4b3966d94a 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -133,7 +133,7 @@ test_cli_installer: script: # Tools must be downloaded for testing # We could use "idf_tools.py download all", but we don't want to install clang because of its huge size - - python3 ${IDF_PATH}/tools/idf_tools.py download required qemu-riscv32 qemu-xtensa + - python3 ${IDF_PATH}/tools/idf_tools.py download required qemu-riscv32 qemu-xtensa cmake - cd ${IDF_PATH}/tools/test_idf_tools - python3 -m pip install jsonschema - python3 ./test_idf_tools.py -v diff --git a/.gitlab/ci/test-win.yml b/.gitlab/ci/test-win.yml index 6949dda5ad3..42e24469333 100644 --- a/.gitlab/ci/test-win.yml +++ b/.gitlab/ci/test-win.yml @@ -31,7 +31,7 @@ test_cli_installer_win: IDF_PATH: "$CI_PROJECT_DIR" script: # Tools must be downloaded for testing - - python ${IDF_PATH}\tools\idf_tools.py download required qemu-riscv32 qemu-xtensa + - python ${IDF_PATH}\tools\idf_tools.py download required qemu-riscv32 qemu-xtensa cmake - cd ${IDF_PATH}\tools\test_idf_tools - python -m pip install jsonschema - python .\test_idf_tools.py diff --git a/tools/test_idf_tools/test_idf_tools.py b/tools/test_idf_tools/test_idf_tools.py index 09f2d195539..c83df0daa27 100755 --- a/tools/test_idf_tools/test_idf_tools.py +++ b/tools/test_idf_tools/test_idf_tools.py @@ -118,14 +118,17 @@ def setUpClass(cls): old_tools_dir = os.environ.get('IDF_TOOLS_PATH') or os.path.expanduser(idf_tools.IDF_TOOLS_PATH_DEFAULT) mirror_prefix_map = None - if os.path.exists(old_tools_dir): - mirror_prefix_map = 'https://dl.espressif.com/dl/toolchains/preview,file:' + os.path.join(old_tools_dir, - 'dist') - mirror_prefix_map += ';https://dl.espressif.com/dl,file:' + os.path.join(old_tools_dir, 'dist') - mirror_prefix_map += ';https://github.com/espressif/.*/releases/download/.*/,file:' + os.path.join( - old_tools_dir, 'dist', '') + if os.path.exists(old_tools_dir) and sys.platform != 'win32': + # These are are all mapping to filesystem. Windows cannot download from there not even if file:// is omitted + local = ''.join(['file://', os.path.join(old_tools_dir, 'dist', '')]) + + mirror_prefix_map = ';'.join([f'https://dl.espressif.com/dl,{local}', + f'https://github.com/.*/.*/releases/download/.*/,{local}']) + + # Windows will keep downloading the tools from default location or IDF_MIRROR_PREFIX_MAP if set globally + if mirror_prefix_map: - print('Using IDF_MIRROR_PREFIX_MAP={}'.format(mirror_prefix_map)) + print(f'Using IDF_MIRROR_PREFIX_MAP={mirror_prefix_map}') os.environ['IDF_MIRROR_PREFIX_MAP'] = mirror_prefix_map cls.temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') From ddc357fcca53d9d3b697acc59dff6740082fe0f7 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Mon, 29 Apr 2024 09:11:57 +0200 Subject: [PATCH 017/548] change(docs): Update checked tools doc pages for ESP32-P4 programming guide --- docs/docs_not_updated/esp32p4.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index c7e0c82202e..dd9af020508 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -6,15 +6,6 @@ api-guides/partition-tables.rst api-guides/app_trace.rst api-guides/thread-local-storage.rst api-guides/error-handling.rst -api-guides/tools/idf-tools.rst -api-guides/tools/idf-clang-tidy.rst -api-guides/tools/idf-component-manager.rst -api-guides/tools/idf-py.rst -api-guides/tools/idf-windows-installer.rst -api-guides/tools/idf-monitor.rst -api-guides/tools/idf-tools-notes.inc -api-guides/tools/idf-docker-image.rst -api-guides/tools/index.rst api-guides/RF_calibration.rst api-guides/deep-sleep-stub.rst api-guides/coexist.rst From a246aa2973c53c28096642250ea968a6d241d409 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 16 Apr 2024 20:02:46 +0800 Subject: [PATCH 018/548] fix(soc): fixed redefined soc reg names on P4 --- .../soc/esp32p4/include/soc/dma_pms_reg.h | 2964 +++++----- .../soc/esp32p4/include/soc/dma_pms_struct.h | 1799 ++---- .../esp32p4/include/soc/hp2lp_peri_pms_reg.h | 1672 +++--- .../include/soc/hp2lp_peri_pms_struct.h | 801 ++- .../soc/esp32p4/include/soc/hp_peri_pms_reg.h | 5025 ++++++++++------- .../esp32p4/include/soc/hp_peri_pms_struct.h | 2372 ++++---- .../esp32p4/include/soc/lp2hp_peri_pms_reg.h | 1291 +++-- .../include/soc/lp2hp_peri_pms_struct.h | 844 +-- .../soc/esp32p4/include/soc/lp_peri_pms_reg.h | 612 +- .../esp32p4/include/soc/lp_peri_pms_struct.h | 433 +- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 5 + 11 files changed, 9084 insertions(+), 8734 deletions(-) diff --git a/components/soc/esp32p4/include/soc/dma_pms_reg.h b/components/soc/esp32p4/include/soc/dma_pms_reg.h index d29425931e4..273935329d4 100644 --- a/components/soc/esp32p4/include/soc/dma_pms_reg.h +++ b/components/soc/esp32p4/include/soc/dma_pms_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,1565 +11,1759 @@ extern "C" { #endif -/** TEE_DATE_REG register - * NA +/** PMS_DMA_DATE_REG register + * Version control register */ -#define TEE_DATE_REG (DR_REG_TEE_BASE + 0x0) -/** TEE_TEE_DATE : R/W; bitpos: [31:0]; default: 539165460; - * NA +#define PMS_DMA_DATE_REG (DR_REG_PMS_DMA_BASE + 0x0) +/** PMS_DMA_DATE : R/W; bitpos: [31:0]; default: 539165460; + * Version control register. */ -#define TEE_TEE_DATE 0xFFFFFFFFU -#define TEE_TEE_DATE_M (TEE_TEE_DATE_V << TEE_TEE_DATE_S) -#define TEE_TEE_DATE_V 0xFFFFFFFFU -#define TEE_TEE_DATE_S 0 +#define PMS_DMA_DATE 0xFFFFFFFFU +#define PMS_DMA_DATE_M (PMS_DMA_DATE_V << PMS_DMA_DATE_S) +#define PMS_DMA_DATE_V 0xFFFFFFFFU +#define PMS_DMA_DATE_S 0 -/** TEE_CLK_EN_REG register - * NA +/** PMS_DMA_CLK_EN_REG register + * Clock gating register */ -#define TEE_CLK_EN_REG (DR_REG_TEE_BASE + 0x4) -/** TEE_CLK_EN : R/W; bitpos: [0]; default: 1; - * NA +#define PMS_DMA_CLK_EN_REG (DR_REG_PMS_DMA_BASE + 0x4) +/** PMS_DMA_CLK_EN : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating. + * 1: Keep the clock always on. */ -#define TEE_CLK_EN (BIT(0)) -#define TEE_CLK_EN_M (TEE_CLK_EN_V << TEE_CLK_EN_S) -#define TEE_CLK_EN_V 0x00000001U -#define TEE_CLK_EN_S 0 +#define PMS_DMA_CLK_EN (BIT(0)) +#define PMS_DMA_CLK_EN_M (PMS_DMA_CLK_EN_V << PMS_DMA_CLK_EN_S) +#define PMS_DMA_CLK_EN_V 0x00000001U +#define PMS_DMA_CLK_EN_S 0 -/** TEE_REGION0_LOW_REG register - * Region0 address low register. +/** PMS_DMA_REGION0_LOW_REG register + * Region0 start address configuration register */ -#define TEE_REGION0_LOW_REG (DR_REG_TEE_BASE + 0x8) -/** TEE_REGION0_LOW : R/W; bitpos: [31:12]; default: 0; - * Region0 address low. +#define PMS_DMA_REGION0_LOW_REG (DR_REG_PMS_DMA_BASE + 0x8) +/** PMS_DMA_REGION0_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region0. */ -#define TEE_REGION0_LOW 0x000FFFFFU -#define TEE_REGION0_LOW_M (TEE_REGION0_LOW_V << TEE_REGION0_LOW_S) -#define TEE_REGION0_LOW_V 0x000FFFFFU -#define TEE_REGION0_LOW_S 12 +#define PMS_DMA_REGION0_LOW 0x000FFFFFU +#define PMS_DMA_REGION0_LOW_M (PMS_DMA_REGION0_LOW_V << PMS_DMA_REGION0_LOW_S) +#define PMS_DMA_REGION0_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION0_LOW_S 12 -/** TEE_REGION0_HIGH_REG register - * Region0 address high register. +/** PMS_DMA_REGION0_HIGH_REG register + * Region0 end address configuration register */ -#define TEE_REGION0_HIGH_REG (DR_REG_TEE_BASE + 0xc) -/** TEE_REGION0_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region0 address high. +#define PMS_DMA_REGION0_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xc) +/** PMS_DMA_REGION0_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region0. */ -#define TEE_REGION0_HIGH 0x000FFFFFU -#define TEE_REGION0_HIGH_M (TEE_REGION0_HIGH_V << TEE_REGION0_HIGH_S) -#define TEE_REGION0_HIGH_V 0x000FFFFFU -#define TEE_REGION0_HIGH_S 12 +#define PMS_DMA_REGION0_HIGH 0x000FFFFFU +#define PMS_DMA_REGION0_HIGH_M (PMS_DMA_REGION0_HIGH_V << PMS_DMA_REGION0_HIGH_S) +#define PMS_DMA_REGION0_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION0_HIGH_S 12 -/** TEE_REGION1_LOW_REG register - * Region1 address low register. +/** PMS_DMA_REGION1_LOW_REG register + * Region1 start address configuration register */ -#define TEE_REGION1_LOW_REG (DR_REG_TEE_BASE + 0x10) -/** TEE_REGION1_LOW : R/W; bitpos: [31:12]; default: 0; - * Region1 address low. +#define PMS_DMA_REGION1_LOW_REG (DR_REG_PMS_DMA_BASE + 0x10) +/** PMS_DMA_REGION1_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region1. */ -#define TEE_REGION1_LOW 0x000FFFFFU -#define TEE_REGION1_LOW_M (TEE_REGION1_LOW_V << TEE_REGION1_LOW_S) -#define TEE_REGION1_LOW_V 0x000FFFFFU -#define TEE_REGION1_LOW_S 12 +#define PMS_DMA_REGION1_LOW 0x000FFFFFU +#define PMS_DMA_REGION1_LOW_M (PMS_DMA_REGION1_LOW_V << PMS_DMA_REGION1_LOW_S) +#define PMS_DMA_REGION1_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION1_LOW_S 12 -/** TEE_REGION1_HIGH_REG register - * Region1 address high register. +/** PMS_DMA_REGION1_HIGH_REG register + * Region1 end address configuration register */ -#define TEE_REGION1_HIGH_REG (DR_REG_TEE_BASE + 0x14) -/** TEE_REGION1_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region1 address high. +#define PMS_DMA_REGION1_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x14) +/** PMS_DMA_REGION1_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region1. */ -#define TEE_REGION1_HIGH 0x000FFFFFU -#define TEE_REGION1_HIGH_M (TEE_REGION1_HIGH_V << TEE_REGION1_HIGH_S) -#define TEE_REGION1_HIGH_V 0x000FFFFFU -#define TEE_REGION1_HIGH_S 12 +#define PMS_DMA_REGION1_HIGH 0x000FFFFFU +#define PMS_DMA_REGION1_HIGH_M (PMS_DMA_REGION1_HIGH_V << PMS_DMA_REGION1_HIGH_S) +#define PMS_DMA_REGION1_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION1_HIGH_S 12 -/** TEE_REGION2_LOW_REG register - * Region2 address low register. +/** PMS_DMA_REGION2_LOW_REG register + * Region2 start address configuration register */ -#define TEE_REGION2_LOW_REG (DR_REG_TEE_BASE + 0x18) -/** TEE_REGION2_LOW : R/W; bitpos: [31:12]; default: 0; - * Region2 address low. +#define PMS_DMA_REGION2_LOW_REG (DR_REG_PMS_DMA_BASE + 0x18) +/** PMS_DMA_REGION2_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region2. */ -#define TEE_REGION2_LOW 0x000FFFFFU -#define TEE_REGION2_LOW_M (TEE_REGION2_LOW_V << TEE_REGION2_LOW_S) -#define TEE_REGION2_LOW_V 0x000FFFFFU -#define TEE_REGION2_LOW_S 12 +#define PMS_DMA_REGION2_LOW 0x000FFFFFU +#define PMS_DMA_REGION2_LOW_M (PMS_DMA_REGION2_LOW_V << PMS_DMA_REGION2_LOW_S) +#define PMS_DMA_REGION2_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION2_LOW_S 12 -/** TEE_REGION2_HIGH_REG register - * Region2 address high register. +/** PMS_DMA_REGION2_HIGH_REG register + * Region2 end address configuration register */ -#define TEE_REGION2_HIGH_REG (DR_REG_TEE_BASE + 0x1c) -/** TEE_REGION2_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region2 address high. +#define PMS_DMA_REGION2_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x1c) +/** PMS_DMA_REGION2_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region2. */ -#define TEE_REGION2_HIGH 0x000FFFFFU -#define TEE_REGION2_HIGH_M (TEE_REGION2_HIGH_V << TEE_REGION2_HIGH_S) -#define TEE_REGION2_HIGH_V 0x000FFFFFU -#define TEE_REGION2_HIGH_S 12 +#define PMS_DMA_REGION2_HIGH 0x000FFFFFU +#define PMS_DMA_REGION2_HIGH_M (PMS_DMA_REGION2_HIGH_V << PMS_DMA_REGION2_HIGH_S) +#define PMS_DMA_REGION2_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION2_HIGH_S 12 -/** TEE_REGION3_LOW_REG register - * Region3 address low register. +/** PMS_DMA_REGION3_LOW_REG register + * Region3 start address configuration register */ -#define TEE_REGION3_LOW_REG (DR_REG_TEE_BASE + 0x20) -/** TEE_REGION3_LOW : R/W; bitpos: [31:12]; default: 0; - * Region3 address low. - */ -#define TEE_REGION3_LOW 0x000FFFFFU -#define TEE_REGION3_LOW_M (TEE_REGION3_LOW_V << TEE_REGION3_LOW_S) -#define TEE_REGION3_LOW_V 0x000FFFFFU -#define TEE_REGION3_LOW_S 12 - -/** TEE_REGION3_HIGH_REG register - * Region3 address high register. - */ -#define TEE_REGION3_HIGH_REG (DR_REG_TEE_BASE + 0x24) -/** TEE_REGION3_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region3 address high. - */ -#define TEE_REGION3_HIGH 0x000FFFFFU -#define TEE_REGION3_HIGH_M (TEE_REGION3_HIGH_V << TEE_REGION3_HIGH_S) -#define TEE_REGION3_HIGH_V 0x000FFFFFU -#define TEE_REGION3_HIGH_S 12 - -/** TEE_REGION4_LOW_REG register - * Region4 address low register. - */ -#define TEE_REGION4_LOW_REG (DR_REG_TEE_BASE + 0x28) -/** TEE_REGION4_LOW : R/W; bitpos: [31:12]; default: 0; - * Region4 address low. - */ -#define TEE_REGION4_LOW 0x000FFFFFU -#define TEE_REGION4_LOW_M (TEE_REGION4_LOW_V << TEE_REGION4_LOW_S) -#define TEE_REGION4_LOW_V 0x000FFFFFU -#define TEE_REGION4_LOW_S 12 - -/** TEE_REGION4_HIGH_REG register - * Region4 address high register. - */ -#define TEE_REGION4_HIGH_REG (DR_REG_TEE_BASE + 0x2c) -/** TEE_REGION4_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region4 address high. - */ -#define TEE_REGION4_HIGH 0x000FFFFFU -#define TEE_REGION4_HIGH_M (TEE_REGION4_HIGH_V << TEE_REGION4_HIGH_S) -#define TEE_REGION4_HIGH_V 0x000FFFFFU -#define TEE_REGION4_HIGH_S 12 - -/** TEE_REGION5_LOW_REG register - * Region5 address low register. - */ -#define TEE_REGION5_LOW_REG (DR_REG_TEE_BASE + 0x30) -/** TEE_REGION5_LOW : R/W; bitpos: [31:12]; default: 0; - * Region5 address low. - */ -#define TEE_REGION5_LOW 0x000FFFFFU -#define TEE_REGION5_LOW_M (TEE_REGION5_LOW_V << TEE_REGION5_LOW_S) -#define TEE_REGION5_LOW_V 0x000FFFFFU -#define TEE_REGION5_LOW_S 12 - -/** TEE_REGION5_HIGH_REG register - * Region5 address high register. - */ -#define TEE_REGION5_HIGH_REG (DR_REG_TEE_BASE + 0x34) -/** TEE_REGION5_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region5 address high. - */ -#define TEE_REGION5_HIGH 0x000FFFFFU -#define TEE_REGION5_HIGH_M (TEE_REGION5_HIGH_V << TEE_REGION5_HIGH_S) -#define TEE_REGION5_HIGH_V 0x000FFFFFU -#define TEE_REGION5_HIGH_S 12 - -/** TEE_REGION6_LOW_REG register - * Region6 address low register. - */ -#define TEE_REGION6_LOW_REG (DR_REG_TEE_BASE + 0x38) -/** TEE_REGION6_LOW : R/W; bitpos: [31:12]; default: 0; - * Region6 address low. - */ -#define TEE_REGION6_LOW 0x000FFFFFU -#define TEE_REGION6_LOW_M (TEE_REGION6_LOW_V << TEE_REGION6_LOW_S) -#define TEE_REGION6_LOW_V 0x000FFFFFU -#define TEE_REGION6_LOW_S 12 - -/** TEE_REGION6_HIGH_REG register - * Region6 address high register. - */ -#define TEE_REGION6_HIGH_REG (DR_REG_TEE_BASE + 0x3c) -/** TEE_REGION6_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region6 address high. - */ -#define TEE_REGION6_HIGH 0x000FFFFFU -#define TEE_REGION6_HIGH_M (TEE_REGION6_HIGH_V << TEE_REGION6_HIGH_S) -#define TEE_REGION6_HIGH_V 0x000FFFFFU -#define TEE_REGION6_HIGH_S 12 - -/** TEE_REGION7_LOW_REG register - * Region7 address low register. - */ -#define TEE_REGION7_LOW_REG (DR_REG_TEE_BASE + 0x40) -/** TEE_REGION7_LOW : R/W; bitpos: [31:12]; default: 0; - * Region7 address low. - */ -#define TEE_REGION7_LOW 0x000FFFFFU -#define TEE_REGION7_LOW_M (TEE_REGION7_LOW_V << TEE_REGION7_LOW_S) -#define TEE_REGION7_LOW_V 0x000FFFFFU -#define TEE_REGION7_LOW_S 12 - -/** TEE_REGION7_HIGH_REG register - * Region7 address high register. - */ -#define TEE_REGION7_HIGH_REG (DR_REG_TEE_BASE + 0x44) -/** TEE_REGION7_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region7 address high. - */ -#define TEE_REGION7_HIGH 0x000FFFFFU -#define TEE_REGION7_HIGH_M (TEE_REGION7_HIGH_V << TEE_REGION7_HIGH_S) -#define TEE_REGION7_HIGH_V 0x000FFFFFU -#define TEE_REGION7_HIGH_S 12 - -/** TEE_REGION8_LOW_REG register - * Region8 address low register. - */ -#define TEE_REGION8_LOW_REG (DR_REG_TEE_BASE + 0x48) -/** TEE_REGION8_LOW : R/W; bitpos: [31:12]; default: 0; - * Region8 address low. - */ -#define TEE_REGION8_LOW 0x000FFFFFU -#define TEE_REGION8_LOW_M (TEE_REGION8_LOW_V << TEE_REGION8_LOW_S) -#define TEE_REGION8_LOW_V 0x000FFFFFU -#define TEE_REGION8_LOW_S 12 - -/** TEE_REGION8_HIGH_REG register - * Region8 address high register. - */ -#define TEE_REGION8_HIGH_REG (DR_REG_TEE_BASE + 0x4c) -/** TEE_REGION8_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region8 address high. - */ -#define TEE_REGION8_HIGH 0x000FFFFFU -#define TEE_REGION8_HIGH_M (TEE_REGION8_HIGH_V << TEE_REGION8_HIGH_S) -#define TEE_REGION8_HIGH_V 0x000FFFFFU -#define TEE_REGION8_HIGH_S 12 - -/** TEE_REGION9_LOW_REG register - * Region9 address low register. - */ -#define TEE_REGION9_LOW_REG (DR_REG_TEE_BASE + 0x50) -/** TEE_REGION9_LOW : R/W; bitpos: [31:12]; default: 0; - * Region9 address low. - */ -#define TEE_REGION9_LOW 0x000FFFFFU -#define TEE_REGION9_LOW_M (TEE_REGION9_LOW_V << TEE_REGION9_LOW_S) -#define TEE_REGION9_LOW_V 0x000FFFFFU -#define TEE_REGION9_LOW_S 12 - -/** TEE_REGION9_HIGH_REG register - * Region9 address high register. - */ -#define TEE_REGION9_HIGH_REG (DR_REG_TEE_BASE + 0x54) -/** TEE_REGION9_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region9 address high. - */ -#define TEE_REGION9_HIGH 0x000FFFFFU -#define TEE_REGION9_HIGH_M (TEE_REGION9_HIGH_V << TEE_REGION9_HIGH_S) -#define TEE_REGION9_HIGH_V 0x000FFFFFU -#define TEE_REGION9_HIGH_S 12 - -/** TEE_REGION10_LOW_REG register - * Region10 address low register. - */ -#define TEE_REGION10_LOW_REG (DR_REG_TEE_BASE + 0x58) -/** TEE_REGION10_LOW : R/W; bitpos: [31:12]; default: 0; - * Region10 address low. - */ -#define TEE_REGION10_LOW 0x000FFFFFU -#define TEE_REGION10_LOW_M (TEE_REGION10_LOW_V << TEE_REGION10_LOW_S) -#define TEE_REGION10_LOW_V 0x000FFFFFU -#define TEE_REGION10_LOW_S 12 - -/** TEE_REGION10_HIGH_REG register - * Region10 address high register. - */ -#define TEE_REGION10_HIGH_REG (DR_REG_TEE_BASE + 0x5c) -/** TEE_REGION10_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region10 address high. - */ -#define TEE_REGION10_HIGH 0x000FFFFFU -#define TEE_REGION10_HIGH_M (TEE_REGION10_HIGH_V << TEE_REGION10_HIGH_S) -#define TEE_REGION10_HIGH_V 0x000FFFFFU -#define TEE_REGION10_HIGH_S 12 - -/** TEE_REGION11_LOW_REG register - * Region11 address low register. - */ -#define TEE_REGION11_LOW_REG (DR_REG_TEE_BASE + 0x60) -/** TEE_REGION11_LOW : R/W; bitpos: [31:12]; default: 0; - * Region11 address low. - */ -#define TEE_REGION11_LOW 0x000FFFFFU -#define TEE_REGION11_LOW_M (TEE_REGION11_LOW_V << TEE_REGION11_LOW_S) -#define TEE_REGION11_LOW_V 0x000FFFFFU -#define TEE_REGION11_LOW_S 12 - -/** TEE_REGION11_HIGH_REG register - * Region11 address high register. - */ -#define TEE_REGION11_HIGH_REG (DR_REG_TEE_BASE + 0x64) -/** TEE_REGION11_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region11 address high. - */ -#define TEE_REGION11_HIGH 0x000FFFFFU -#define TEE_REGION11_HIGH_M (TEE_REGION11_HIGH_V << TEE_REGION11_HIGH_S) -#define TEE_REGION11_HIGH_V 0x000FFFFFU -#define TEE_REGION11_HIGH_S 12 - -/** TEE_REGION12_LOW_REG register - * Region12 address low register. - */ -#define TEE_REGION12_LOW_REG (DR_REG_TEE_BASE + 0x68) -/** TEE_REGION12_LOW : R/W; bitpos: [31:12]; default: 0; - * Region12 address low. - */ -#define TEE_REGION12_LOW 0x000FFFFFU -#define TEE_REGION12_LOW_M (TEE_REGION12_LOW_V << TEE_REGION12_LOW_S) -#define TEE_REGION12_LOW_V 0x000FFFFFU -#define TEE_REGION12_LOW_S 12 - -/** TEE_REGION12_HIGH_REG register - * Region12 address high register. - */ -#define TEE_REGION12_HIGH_REG (DR_REG_TEE_BASE + 0x6c) -/** TEE_REGION12_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region12 address high. - */ -#define TEE_REGION12_HIGH 0x000FFFFFU -#define TEE_REGION12_HIGH_M (TEE_REGION12_HIGH_V << TEE_REGION12_HIGH_S) -#define TEE_REGION12_HIGH_V 0x000FFFFFU -#define TEE_REGION12_HIGH_S 12 - -/** TEE_REGION13_LOW_REG register - * Region13 address low register. - */ -#define TEE_REGION13_LOW_REG (DR_REG_TEE_BASE + 0x70) -/** TEE_REGION13_LOW : R/W; bitpos: [31:12]; default: 0; - * Region13 address low. - */ -#define TEE_REGION13_LOW 0x000FFFFFU -#define TEE_REGION13_LOW_M (TEE_REGION13_LOW_V << TEE_REGION13_LOW_S) -#define TEE_REGION13_LOW_V 0x000FFFFFU -#define TEE_REGION13_LOW_S 12 - -/** TEE_REGION13_HIGH_REG register - * Region13 address high register. - */ -#define TEE_REGION13_HIGH_REG (DR_REG_TEE_BASE + 0x74) -/** TEE_REGION13_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region13 address high. - */ -#define TEE_REGION13_HIGH 0x000FFFFFU -#define TEE_REGION13_HIGH_M (TEE_REGION13_HIGH_V << TEE_REGION13_HIGH_S) -#define TEE_REGION13_HIGH_V 0x000FFFFFU -#define TEE_REGION13_HIGH_S 12 - -/** TEE_REGION14_LOW_REG register - * Region14 address low register. - */ -#define TEE_REGION14_LOW_REG (DR_REG_TEE_BASE + 0x78) -/** TEE_REGION14_LOW : R/W; bitpos: [31:12]; default: 0; - * Region14 address low. - */ -#define TEE_REGION14_LOW 0x000FFFFFU -#define TEE_REGION14_LOW_M (TEE_REGION14_LOW_V << TEE_REGION14_LOW_S) -#define TEE_REGION14_LOW_V 0x000FFFFFU -#define TEE_REGION14_LOW_S 12 - -/** TEE_REGION14_HIGH_REG register - * Region14 address high register. - */ -#define TEE_REGION14_HIGH_REG (DR_REG_TEE_BASE + 0x7c) -/** TEE_REGION14_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region14 address high. - */ -#define TEE_REGION14_HIGH 0x000FFFFFU -#define TEE_REGION14_HIGH_M (TEE_REGION14_HIGH_V << TEE_REGION14_HIGH_S) -#define TEE_REGION14_HIGH_V 0x000FFFFFU -#define TEE_REGION14_HIGH_S 12 - -/** TEE_REGION15_LOW_REG register - * Region15 address low register. - */ -#define TEE_REGION15_LOW_REG (DR_REG_TEE_BASE + 0x80) -/** TEE_REGION15_LOW : R/W; bitpos: [31:12]; default: 0; - * Region15 address low. - */ -#define TEE_REGION15_LOW 0x000FFFFFU -#define TEE_REGION15_LOW_M (TEE_REGION15_LOW_V << TEE_REGION15_LOW_S) -#define TEE_REGION15_LOW_V 0x000FFFFFU -#define TEE_REGION15_LOW_S 12 - -/** TEE_REGION15_HIGH_REG register - * Region15 address high register. - */ -#define TEE_REGION15_HIGH_REG (DR_REG_TEE_BASE + 0x84) -/** TEE_REGION15_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region15 address high. - */ -#define TEE_REGION15_HIGH 0x000FFFFFU -#define TEE_REGION15_HIGH_M (TEE_REGION15_HIGH_V << TEE_REGION15_HIGH_S) -#define TEE_REGION15_HIGH_V 0x000FFFFFU -#define TEE_REGION15_HIGH_S 12 - -/** TEE_REGION16_LOW_REG register - * Region16 address low register. - */ -#define TEE_REGION16_LOW_REG (DR_REG_TEE_BASE + 0x88) -/** TEE_REGION16_LOW : R/W; bitpos: [31:12]; default: 0; - * Region16 address low. - */ -#define TEE_REGION16_LOW 0x000FFFFFU -#define TEE_REGION16_LOW_M (TEE_REGION16_LOW_V << TEE_REGION16_LOW_S) -#define TEE_REGION16_LOW_V 0x000FFFFFU -#define TEE_REGION16_LOW_S 12 - -/** TEE_REGION16_HIGH_REG register - * Region16 address high register. - */ -#define TEE_REGION16_HIGH_REG (DR_REG_TEE_BASE + 0x8c) -/** TEE_REGION16_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region16 address high. - */ -#define TEE_REGION16_HIGH 0x000FFFFFU -#define TEE_REGION16_HIGH_M (TEE_REGION16_HIGH_V << TEE_REGION16_HIGH_S) -#define TEE_REGION16_HIGH_V 0x000FFFFFU -#define TEE_REGION16_HIGH_S 12 - -/** TEE_REGION17_LOW_REG register - * Region17 address low register. - */ -#define TEE_REGION17_LOW_REG (DR_REG_TEE_BASE + 0x90) -/** TEE_REGION17_LOW : R/W; bitpos: [31:12]; default: 0; - * Region17 address low. - */ -#define TEE_REGION17_LOW 0x000FFFFFU -#define TEE_REGION17_LOW_M (TEE_REGION17_LOW_V << TEE_REGION17_LOW_S) -#define TEE_REGION17_LOW_V 0x000FFFFFU -#define TEE_REGION17_LOW_S 12 - -/** TEE_REGION17_HIGH_REG register - * Region17 address high register. - */ -#define TEE_REGION17_HIGH_REG (DR_REG_TEE_BASE + 0x94) -/** TEE_REGION17_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region17 address high. - */ -#define TEE_REGION17_HIGH 0x000FFFFFU -#define TEE_REGION17_HIGH_M (TEE_REGION17_HIGH_V << TEE_REGION17_HIGH_S) -#define TEE_REGION17_HIGH_V 0x000FFFFFU -#define TEE_REGION17_HIGH_S 12 - -/** TEE_REGION18_LOW_REG register - * Region18 address low register. - */ -#define TEE_REGION18_LOW_REG (DR_REG_TEE_BASE + 0x98) -/** TEE_REGION18_LOW : R/W; bitpos: [31:12]; default: 0; - * Region18 address low. - */ -#define TEE_REGION18_LOW 0x000FFFFFU -#define TEE_REGION18_LOW_M (TEE_REGION18_LOW_V << TEE_REGION18_LOW_S) -#define TEE_REGION18_LOW_V 0x000FFFFFU -#define TEE_REGION18_LOW_S 12 - -/** TEE_REGION18_HIGH_REG register - * Region18 address high register. - */ -#define TEE_REGION18_HIGH_REG (DR_REG_TEE_BASE + 0x9c) -/** TEE_REGION18_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region18 address high. - */ -#define TEE_REGION18_HIGH 0x000FFFFFU -#define TEE_REGION18_HIGH_M (TEE_REGION18_HIGH_V << TEE_REGION18_HIGH_S) -#define TEE_REGION18_HIGH_V 0x000FFFFFU -#define TEE_REGION18_HIGH_S 12 - -/** TEE_REGION19_LOW_REG register - * Region19 address low register. - */ -#define TEE_REGION19_LOW_REG (DR_REG_TEE_BASE + 0xa0) -/** TEE_REGION19_LOW : R/W; bitpos: [31:12]; default: 0; - * Region19 address low. - */ -#define TEE_REGION19_LOW 0x000FFFFFU -#define TEE_REGION19_LOW_M (TEE_REGION19_LOW_V << TEE_REGION19_LOW_S) -#define TEE_REGION19_LOW_V 0x000FFFFFU -#define TEE_REGION19_LOW_S 12 - -/** TEE_REGION19_HIGH_REG register - * Region19 address high register. - */ -#define TEE_REGION19_HIGH_REG (DR_REG_TEE_BASE + 0xa4) -/** TEE_REGION19_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region19 address high. - */ -#define TEE_REGION19_HIGH 0x000FFFFFU -#define TEE_REGION19_HIGH_M (TEE_REGION19_HIGH_V << TEE_REGION19_HIGH_S) -#define TEE_REGION19_HIGH_V 0x000FFFFFU -#define TEE_REGION19_HIGH_S 12 - -/** TEE_REGION20_LOW_REG register - * Region20 address low register. - */ -#define TEE_REGION20_LOW_REG (DR_REG_TEE_BASE + 0xa8) -/** TEE_REGION20_LOW : R/W; bitpos: [31:12]; default: 0; - * Region20 address low. - */ -#define TEE_REGION20_LOW 0x000FFFFFU -#define TEE_REGION20_LOW_M (TEE_REGION20_LOW_V << TEE_REGION20_LOW_S) -#define TEE_REGION20_LOW_V 0x000FFFFFU -#define TEE_REGION20_LOW_S 12 +#define PMS_DMA_REGION3_LOW_REG (DR_REG_PMS_DMA_BASE + 0x20) +/** PMS_DMA_REGION3_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region3. + */ +#define PMS_DMA_REGION3_LOW 0x000FFFFFU +#define PMS_DMA_REGION3_LOW_M (PMS_DMA_REGION3_LOW_V << PMS_DMA_REGION3_LOW_S) +#define PMS_DMA_REGION3_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION3_LOW_S 12 -/** TEE_REGION20_HIGH_REG register - * Region20 address high register. +/** PMS_DMA_REGION3_HIGH_REG register + * Region3 end address configuration register */ -#define TEE_REGION20_HIGH_REG (DR_REG_TEE_BASE + 0xac) -/** TEE_REGION20_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region20 address high. - */ -#define TEE_REGION20_HIGH 0x000FFFFFU -#define TEE_REGION20_HIGH_M (TEE_REGION20_HIGH_V << TEE_REGION20_HIGH_S) -#define TEE_REGION20_HIGH_V 0x000FFFFFU -#define TEE_REGION20_HIGH_S 12 - -/** TEE_REGION21_LOW_REG register - * Region21 address low register. - */ -#define TEE_REGION21_LOW_REG (DR_REG_TEE_BASE + 0xb0) -/** TEE_REGION21_LOW : R/W; bitpos: [31:12]; default: 0; - * Region21 address low. - */ -#define TEE_REGION21_LOW 0x000FFFFFU -#define TEE_REGION21_LOW_M (TEE_REGION21_LOW_V << TEE_REGION21_LOW_S) -#define TEE_REGION21_LOW_V 0x000FFFFFU -#define TEE_REGION21_LOW_S 12 - -/** TEE_REGION21_HIGH_REG register - * Region21 address high register. - */ -#define TEE_REGION21_HIGH_REG (DR_REG_TEE_BASE + 0xb4) -/** TEE_REGION21_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region21 address high. - */ -#define TEE_REGION21_HIGH 0x000FFFFFU -#define TEE_REGION21_HIGH_M (TEE_REGION21_HIGH_V << TEE_REGION21_HIGH_S) -#define TEE_REGION21_HIGH_V 0x000FFFFFU -#define TEE_REGION21_HIGH_S 12 - -/** TEE_REGION22_LOW_REG register - * Region22 address low register. - */ -#define TEE_REGION22_LOW_REG (DR_REG_TEE_BASE + 0xb8) -/** TEE_REGION22_LOW : R/W; bitpos: [31:12]; default: 0; - * Region22 address low. - */ -#define TEE_REGION22_LOW 0x000FFFFFU -#define TEE_REGION22_LOW_M (TEE_REGION22_LOW_V << TEE_REGION22_LOW_S) -#define TEE_REGION22_LOW_V 0x000FFFFFU -#define TEE_REGION22_LOW_S 12 - -/** TEE_REGION22_HIGH_REG register - * Region22 address high register. - */ -#define TEE_REGION22_HIGH_REG (DR_REG_TEE_BASE + 0xbc) -/** TEE_REGION22_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region22 address high. - */ -#define TEE_REGION22_HIGH 0x000FFFFFU -#define TEE_REGION22_HIGH_M (TEE_REGION22_HIGH_V << TEE_REGION22_HIGH_S) -#define TEE_REGION22_HIGH_V 0x000FFFFFU -#define TEE_REGION22_HIGH_S 12 - -/** TEE_REGION23_LOW_REG register - * Region23 address low register. - */ -#define TEE_REGION23_LOW_REG (DR_REG_TEE_BASE + 0xc0) -/** TEE_REGION23_LOW : R/W; bitpos: [31:12]; default: 0; - * Region23 address low. - */ -#define TEE_REGION23_LOW 0x000FFFFFU -#define TEE_REGION23_LOW_M (TEE_REGION23_LOW_V << TEE_REGION23_LOW_S) -#define TEE_REGION23_LOW_V 0x000FFFFFU -#define TEE_REGION23_LOW_S 12 - -/** TEE_REGION23_HIGH_REG register - * Region23 address high register. - */ -#define TEE_REGION23_HIGH_REG (DR_REG_TEE_BASE + 0xc4) -/** TEE_REGION23_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region23 address high. - */ -#define TEE_REGION23_HIGH 0x000FFFFFU -#define TEE_REGION23_HIGH_M (TEE_REGION23_HIGH_V << TEE_REGION23_HIGH_S) -#define TEE_REGION23_HIGH_V 0x000FFFFFU -#define TEE_REGION23_HIGH_S 12 - -/** TEE_REGION24_LOW_REG register - * Region24 address low register. - */ -#define TEE_REGION24_LOW_REG (DR_REG_TEE_BASE + 0xc8) -/** TEE_REGION24_LOW : R/W; bitpos: [31:12]; default: 0; - * Region24 address low. - */ -#define TEE_REGION24_LOW 0x000FFFFFU -#define TEE_REGION24_LOW_M (TEE_REGION24_LOW_V << TEE_REGION24_LOW_S) -#define TEE_REGION24_LOW_V 0x000FFFFFU -#define TEE_REGION24_LOW_S 12 - -/** TEE_REGION24_HIGH_REG register - * Region24 address high register. - */ -#define TEE_REGION24_HIGH_REG (DR_REG_TEE_BASE + 0xcc) -/** TEE_REGION24_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region24 address high. - */ -#define TEE_REGION24_HIGH 0x000FFFFFU -#define TEE_REGION24_HIGH_M (TEE_REGION24_HIGH_V << TEE_REGION24_HIGH_S) -#define TEE_REGION24_HIGH_V 0x000FFFFFU -#define TEE_REGION24_HIGH_S 12 - -/** TEE_REGION25_LOW_REG register - * Region25 address low register. - */ -#define TEE_REGION25_LOW_REG (DR_REG_TEE_BASE + 0xd0) -/** TEE_REGION25_LOW : R/W; bitpos: [31:12]; default: 0; - * Region25 address low. - */ -#define TEE_REGION25_LOW 0x000FFFFFU -#define TEE_REGION25_LOW_M (TEE_REGION25_LOW_V << TEE_REGION25_LOW_S) -#define TEE_REGION25_LOW_V 0x000FFFFFU -#define TEE_REGION25_LOW_S 12 - -/** TEE_REGION25_HIGH_REG register - * Region25 address high register. - */ -#define TEE_REGION25_HIGH_REG (DR_REG_TEE_BASE + 0xd4) -/** TEE_REGION25_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region25 address high. - */ -#define TEE_REGION25_HIGH 0x000FFFFFU -#define TEE_REGION25_HIGH_M (TEE_REGION25_HIGH_V << TEE_REGION25_HIGH_S) -#define TEE_REGION25_HIGH_V 0x000FFFFFU -#define TEE_REGION25_HIGH_S 12 - -/** TEE_REGION26_LOW_REG register - * Region26 address low register. - */ -#define TEE_REGION26_LOW_REG (DR_REG_TEE_BASE + 0xd8) -/** TEE_REGION26_LOW : R/W; bitpos: [31:12]; default: 0; - * Region26 address low. - */ -#define TEE_REGION26_LOW 0x000FFFFFU -#define TEE_REGION26_LOW_M (TEE_REGION26_LOW_V << TEE_REGION26_LOW_S) -#define TEE_REGION26_LOW_V 0x000FFFFFU -#define TEE_REGION26_LOW_S 12 - -/** TEE_REGION26_HIGH_REG register - * Region26 address high register. - */ -#define TEE_REGION26_HIGH_REG (DR_REG_TEE_BASE + 0xdc) -/** TEE_REGION26_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region26 address high. - */ -#define TEE_REGION26_HIGH 0x000FFFFFU -#define TEE_REGION26_HIGH_M (TEE_REGION26_HIGH_V << TEE_REGION26_HIGH_S) -#define TEE_REGION26_HIGH_V 0x000FFFFFU -#define TEE_REGION26_HIGH_S 12 - -/** TEE_REGION27_LOW_REG register - * Region27 address low register. - */ -#define TEE_REGION27_LOW_REG (DR_REG_TEE_BASE + 0xe0) -/** TEE_REGION27_LOW : R/W; bitpos: [31:12]; default: 0; - * Region27 address low. - */ -#define TEE_REGION27_LOW 0x000FFFFFU -#define TEE_REGION27_LOW_M (TEE_REGION27_LOW_V << TEE_REGION27_LOW_S) -#define TEE_REGION27_LOW_V 0x000FFFFFU -#define TEE_REGION27_LOW_S 12 - -/** TEE_REGION27_HIGH_REG register - * Region27 address high register. - */ -#define TEE_REGION27_HIGH_REG (DR_REG_TEE_BASE + 0xe4) -/** TEE_REGION27_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region27 address high. - */ -#define TEE_REGION27_HIGH 0x000FFFFFU -#define TEE_REGION27_HIGH_M (TEE_REGION27_HIGH_V << TEE_REGION27_HIGH_S) -#define TEE_REGION27_HIGH_V 0x000FFFFFU -#define TEE_REGION27_HIGH_S 12 - -/** TEE_REGION28_LOW_REG register - * Region28 address low register. - */ -#define TEE_REGION28_LOW_REG (DR_REG_TEE_BASE + 0xe8) -/** TEE_REGION28_LOW : R/W; bitpos: [31:12]; default: 0; - * Region28 address low. - */ -#define TEE_REGION28_LOW 0x000FFFFFU -#define TEE_REGION28_LOW_M (TEE_REGION28_LOW_V << TEE_REGION28_LOW_S) -#define TEE_REGION28_LOW_V 0x000FFFFFU -#define TEE_REGION28_LOW_S 12 - -/** TEE_REGION28_HIGH_REG register - * Region28 address high register. - */ -#define TEE_REGION28_HIGH_REG (DR_REG_TEE_BASE + 0xec) -/** TEE_REGION28_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region28 address high. - */ -#define TEE_REGION28_HIGH 0x000FFFFFU -#define TEE_REGION28_HIGH_M (TEE_REGION28_HIGH_V << TEE_REGION28_HIGH_S) -#define TEE_REGION28_HIGH_V 0x000FFFFFU -#define TEE_REGION28_HIGH_S 12 - -/** TEE_REGION29_LOW_REG register - * Region29 address low register. - */ -#define TEE_REGION29_LOW_REG (DR_REG_TEE_BASE + 0xf0) -/** TEE_REGION29_LOW : R/W; bitpos: [31:12]; default: 0; - * Region29 address low. - */ -#define TEE_REGION29_LOW 0x000FFFFFU -#define TEE_REGION29_LOW_M (TEE_REGION29_LOW_V << TEE_REGION29_LOW_S) -#define TEE_REGION29_LOW_V 0x000FFFFFU -#define TEE_REGION29_LOW_S 12 +#define PMS_DMA_REGION3_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x24) +/** PMS_DMA_REGION3_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region3. + */ +#define PMS_DMA_REGION3_HIGH 0x000FFFFFU +#define PMS_DMA_REGION3_HIGH_M (PMS_DMA_REGION3_HIGH_V << PMS_DMA_REGION3_HIGH_S) +#define PMS_DMA_REGION3_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION3_HIGH_S 12 -/** TEE_REGION29_HIGH_REG register - * Region29 address high register. +/** PMS_DMA_REGION4_LOW_REG register + * Region4 start address configuration register */ -#define TEE_REGION29_HIGH_REG (DR_REG_TEE_BASE + 0xf4) -/** TEE_REGION29_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region29 address high. +#define PMS_DMA_REGION4_LOW_REG (DR_REG_PMS_DMA_BASE + 0x28) +/** PMS_DMA_REGION4_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region4. */ -#define TEE_REGION29_HIGH 0x000FFFFFU -#define TEE_REGION29_HIGH_M (TEE_REGION29_HIGH_V << TEE_REGION29_HIGH_S) -#define TEE_REGION29_HIGH_V 0x000FFFFFU -#define TEE_REGION29_HIGH_S 12 +#define PMS_DMA_REGION4_LOW 0x000FFFFFU +#define PMS_DMA_REGION4_LOW_M (PMS_DMA_REGION4_LOW_V << PMS_DMA_REGION4_LOW_S) +#define PMS_DMA_REGION4_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION4_LOW_S 12 -/** TEE_REGION30_LOW_REG register - * Region30 address low register. +/** PMS_DMA_REGION4_HIGH_REG register + * Region4 end address configuration register */ -#define TEE_REGION30_LOW_REG (DR_REG_TEE_BASE + 0xf8) -/** TEE_REGION30_LOW : R/W; bitpos: [31:12]; default: 0; - * Region30 address low. +#define PMS_DMA_REGION4_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x2c) +/** PMS_DMA_REGION4_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region4. */ -#define TEE_REGION30_LOW 0x000FFFFFU -#define TEE_REGION30_LOW_M (TEE_REGION30_LOW_V << TEE_REGION30_LOW_S) -#define TEE_REGION30_LOW_V 0x000FFFFFU -#define TEE_REGION30_LOW_S 12 +#define PMS_DMA_REGION4_HIGH 0x000FFFFFU +#define PMS_DMA_REGION4_HIGH_M (PMS_DMA_REGION4_HIGH_V << PMS_DMA_REGION4_HIGH_S) +#define PMS_DMA_REGION4_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION4_HIGH_S 12 -/** TEE_REGION30_HIGH_REG register - * Region30 address high register. +/** PMS_DMA_REGION5_LOW_REG register + * Region5 start address configuration register */ -#define TEE_REGION30_HIGH_REG (DR_REG_TEE_BASE + 0xfc) -/** TEE_REGION30_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region30 address high. +#define PMS_DMA_REGION5_LOW_REG (DR_REG_PMS_DMA_BASE + 0x30) +/** PMS_DMA_REGION5_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region5. */ -#define TEE_REGION30_HIGH 0x000FFFFFU -#define TEE_REGION30_HIGH_M (TEE_REGION30_HIGH_V << TEE_REGION30_HIGH_S) -#define TEE_REGION30_HIGH_V 0x000FFFFFU -#define TEE_REGION30_HIGH_S 12 +#define PMS_DMA_REGION5_LOW 0x000FFFFFU +#define PMS_DMA_REGION5_LOW_M (PMS_DMA_REGION5_LOW_V << PMS_DMA_REGION5_LOW_S) +#define PMS_DMA_REGION5_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION5_LOW_S 12 -/** TEE_REGION31_LOW_REG register - * Region31 address low register. +/** PMS_DMA_REGION5_HIGH_REG register + * Region5 end address configuration register */ -#define TEE_REGION31_LOW_REG (DR_REG_TEE_BASE + 0x100) -/** TEE_REGION31_LOW : R/W; bitpos: [31:12]; default: 0; - * Region31 address low. +#define PMS_DMA_REGION5_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x34) +/** PMS_DMA_REGION5_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region5. */ -#define TEE_REGION31_LOW 0x000FFFFFU -#define TEE_REGION31_LOW_M (TEE_REGION31_LOW_V << TEE_REGION31_LOW_S) -#define TEE_REGION31_LOW_V 0x000FFFFFU -#define TEE_REGION31_LOW_S 12 +#define PMS_DMA_REGION5_HIGH 0x000FFFFFU +#define PMS_DMA_REGION5_HIGH_M (PMS_DMA_REGION5_HIGH_V << PMS_DMA_REGION5_HIGH_S) +#define PMS_DMA_REGION5_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION5_HIGH_S 12 -/** TEE_REGION31_HIGH_REG register - * Region31 address high register. +/** PMS_DMA_REGION6_LOW_REG register + * Region6 start address configuration register */ -#define TEE_REGION31_HIGH_REG (DR_REG_TEE_BASE + 0x104) -/** TEE_REGION31_HIGH : R/W; bitpos: [31:12]; default: 1048575; - * Region31 address high. +#define PMS_DMA_REGION6_LOW_REG (DR_REG_PMS_DMA_BASE + 0x38) +/** PMS_DMA_REGION6_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region6. */ -#define TEE_REGION31_HIGH 0x000FFFFFU -#define TEE_REGION31_HIGH_M (TEE_REGION31_HIGH_V << TEE_REGION31_HIGH_S) -#define TEE_REGION31_HIGH_V 0x000FFFFFU -#define TEE_REGION31_HIGH_S 12 +#define PMS_DMA_REGION6_LOW 0x000FFFFFU +#define PMS_DMA_REGION6_LOW_M (PMS_DMA_REGION6_LOW_V << PMS_DMA_REGION6_LOW_S) +#define PMS_DMA_REGION6_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION6_LOW_S 12 -/** TEE_GMDA_CH0_R_PMS_REG register - * GDMA ch0 read permission control registers. +/** PMS_DMA_REGION6_HIGH_REG register + * Region6 end address configuration register */ -#define TEE_GMDA_CH0_R_PMS_REG (DR_REG_TEE_BASE + 0x108) -/** TEE_GDMA_CH0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch0 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION6_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x3c) +/** PMS_DMA_REGION6_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region6. */ -#define TEE_GDMA_CH0_R_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH0_R_PMS_M (TEE_GDMA_CH0_R_PMS_V << TEE_GDMA_CH0_R_PMS_S) -#define TEE_GDMA_CH0_R_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH0_R_PMS_S 0 +#define PMS_DMA_REGION6_HIGH 0x000FFFFFU +#define PMS_DMA_REGION6_HIGH_M (PMS_DMA_REGION6_HIGH_V << PMS_DMA_REGION6_HIGH_S) +#define PMS_DMA_REGION6_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION6_HIGH_S 12 -/** TEE_GMDA_CH0_W_PMS_REG register - * GDMA ch0 write permission control registers. +/** PMS_DMA_REGION7_LOW_REG register + * Region7 start address configuration register */ -#define TEE_GMDA_CH0_W_PMS_REG (DR_REG_TEE_BASE + 0x10c) -/** TEE_GDMA_CH0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch0 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION7_LOW_REG (DR_REG_PMS_DMA_BASE + 0x40) +/** PMS_DMA_REGION7_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region7. */ -#define TEE_GDMA_CH0_W_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH0_W_PMS_M (TEE_GDMA_CH0_W_PMS_V << TEE_GDMA_CH0_W_PMS_S) -#define TEE_GDMA_CH0_W_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH0_W_PMS_S 0 +#define PMS_DMA_REGION7_LOW 0x000FFFFFU +#define PMS_DMA_REGION7_LOW_M (PMS_DMA_REGION7_LOW_V << PMS_DMA_REGION7_LOW_S) +#define PMS_DMA_REGION7_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION7_LOW_S 12 -/** TEE_GMDA_CH1_R_PMS_REG register - * GDMA ch1 read permission control registers. +/** PMS_DMA_REGION7_HIGH_REG register + * Region7 end address configuration register */ -#define TEE_GMDA_CH1_R_PMS_REG (DR_REG_TEE_BASE + 0x110) -/** TEE_GDMA_CH1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch1 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION7_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x44) +/** PMS_DMA_REGION7_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region7. */ -#define TEE_GDMA_CH1_R_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH1_R_PMS_M (TEE_GDMA_CH1_R_PMS_V << TEE_GDMA_CH1_R_PMS_S) -#define TEE_GDMA_CH1_R_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH1_R_PMS_S 0 +#define PMS_DMA_REGION7_HIGH 0x000FFFFFU +#define PMS_DMA_REGION7_HIGH_M (PMS_DMA_REGION7_HIGH_V << PMS_DMA_REGION7_HIGH_S) +#define PMS_DMA_REGION7_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION7_HIGH_S 12 -/** TEE_GMDA_CH1_W_PMS_REG register - * GDMA ch1 write permission control registers. +/** PMS_DMA_REGION8_LOW_REG register + * Region8 start address configuration register */ -#define TEE_GMDA_CH1_W_PMS_REG (DR_REG_TEE_BASE + 0x114) -/** TEE_GDMA_CH1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch1 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION8_LOW_REG (DR_REG_PMS_DMA_BASE + 0x48) +/** PMS_DMA_REGION8_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region8. */ -#define TEE_GDMA_CH1_W_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH1_W_PMS_M (TEE_GDMA_CH1_W_PMS_V << TEE_GDMA_CH1_W_PMS_S) -#define TEE_GDMA_CH1_W_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH1_W_PMS_S 0 +#define PMS_DMA_REGION8_LOW 0x000FFFFFU +#define PMS_DMA_REGION8_LOW_M (PMS_DMA_REGION8_LOW_V << PMS_DMA_REGION8_LOW_S) +#define PMS_DMA_REGION8_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION8_LOW_S 12 -/** TEE_GMDA_CH2_R_PMS_REG register - * GDMA ch2 read permission control registers. +/** PMS_DMA_REGION8_HIGH_REG register + * Region8 end address configuration register */ -#define TEE_GMDA_CH2_R_PMS_REG (DR_REG_TEE_BASE + 0x118) -/** TEE_GDMA_CH2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch2 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION8_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x4c) +/** PMS_DMA_REGION8_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region8. */ -#define TEE_GDMA_CH2_R_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH2_R_PMS_M (TEE_GDMA_CH2_R_PMS_V << TEE_GDMA_CH2_R_PMS_S) -#define TEE_GDMA_CH2_R_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH2_R_PMS_S 0 +#define PMS_DMA_REGION8_HIGH 0x000FFFFFU +#define PMS_DMA_REGION8_HIGH_M (PMS_DMA_REGION8_HIGH_V << PMS_DMA_REGION8_HIGH_S) +#define PMS_DMA_REGION8_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION8_HIGH_S 12 -/** TEE_GMDA_CH2_W_PMS_REG register - * GDMA ch2 write permission control registers. +/** PMS_DMA_REGION9_LOW_REG register + * Region9 start address configuration register */ -#define TEE_GMDA_CH2_W_PMS_REG (DR_REG_TEE_BASE + 0x11c) -/** TEE_GDMA_CH2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch2 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION9_LOW_REG (DR_REG_PMS_DMA_BASE + 0x50) +/** PMS_DMA_REGION9_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region9. */ -#define TEE_GDMA_CH2_W_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH2_W_PMS_M (TEE_GDMA_CH2_W_PMS_V << TEE_GDMA_CH2_W_PMS_S) -#define TEE_GDMA_CH2_W_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH2_W_PMS_S 0 +#define PMS_DMA_REGION9_LOW 0x000FFFFFU +#define PMS_DMA_REGION9_LOW_M (PMS_DMA_REGION9_LOW_V << PMS_DMA_REGION9_LOW_S) +#define PMS_DMA_REGION9_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION9_LOW_S 12 -/** TEE_GMDA_CH3_R_PMS_REG register - * GDMA ch3 read permission control registers. +/** PMS_DMA_REGION9_HIGH_REG register + * Region9 end address configuration register */ -#define TEE_GMDA_CH3_R_PMS_REG (DR_REG_TEE_BASE + 0x120) -/** TEE_GDMA_CH3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch3 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION9_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x54) +/** PMS_DMA_REGION9_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region9. */ -#define TEE_GDMA_CH3_R_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH3_R_PMS_M (TEE_GDMA_CH3_R_PMS_V << TEE_GDMA_CH3_R_PMS_S) -#define TEE_GDMA_CH3_R_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH3_R_PMS_S 0 +#define PMS_DMA_REGION9_HIGH 0x000FFFFFU +#define PMS_DMA_REGION9_HIGH_M (PMS_DMA_REGION9_HIGH_V << PMS_DMA_REGION9_HIGH_S) +#define PMS_DMA_REGION9_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION9_HIGH_S 12 -/** TEE_GMDA_CH3_W_PMS_REG register - * GDMA ch3 write permission control registers. +/** PMS_DMA_REGION10_LOW_REG register + * Region10 start address configuration register */ -#define TEE_GMDA_CH3_W_PMS_REG (DR_REG_TEE_BASE + 0x124) -/** TEE_GDMA_CH3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch3 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION10_LOW_REG (DR_REG_PMS_DMA_BASE + 0x58) +/** PMS_DMA_REGION10_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region10. */ -#define TEE_GDMA_CH3_W_PMS 0xFFFFFFFFU -#define TEE_GDMA_CH3_W_PMS_M (TEE_GDMA_CH3_W_PMS_V << TEE_GDMA_CH3_W_PMS_S) -#define TEE_GDMA_CH3_W_PMS_V 0xFFFFFFFFU -#define TEE_GDMA_CH3_W_PMS_S 0 +#define PMS_DMA_REGION10_LOW 0x000FFFFFU +#define PMS_DMA_REGION10_LOW_M (PMS_DMA_REGION10_LOW_V << PMS_DMA_REGION10_LOW_S) +#define PMS_DMA_REGION10_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION10_LOW_S 12 -/** TEE_AHB_PDMA_ADC_R_PMS_REG register - * AHB PDMA adc read permission control registers. +/** PMS_DMA_REGION10_HIGH_REG register + * Region10 end address configuration register */ -#define TEE_AHB_PDMA_ADC_R_PMS_REG (DR_REG_TEE_BASE + 0x128) -/** TEE_AHB_PDMA_ADC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA adc read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION10_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x5c) +/** PMS_DMA_REGION10_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region10. */ -#define TEE_AHB_PDMA_ADC_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_ADC_R_PMS_M (TEE_AHB_PDMA_ADC_R_PMS_V << TEE_AHB_PDMA_ADC_R_PMS_S) -#define TEE_AHB_PDMA_ADC_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_ADC_R_PMS_S 0 +#define PMS_DMA_REGION10_HIGH 0x000FFFFFU +#define PMS_DMA_REGION10_HIGH_M (PMS_DMA_REGION10_HIGH_V << PMS_DMA_REGION10_HIGH_S) +#define PMS_DMA_REGION10_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION10_HIGH_S 12 -/** TEE_AHB_PDMA_ADC_W_PMS_REG register - * AHB PDMA adc write permission control registers. +/** PMS_DMA_REGION11_LOW_REG register + * Region11 start address configuration register */ -#define TEE_AHB_PDMA_ADC_W_PMS_REG (DR_REG_TEE_BASE + 0x12c) -/** TEE_AHB_PDMA_ADC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA adc write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION11_LOW_REG (DR_REG_PMS_DMA_BASE + 0x60) +/** PMS_DMA_REGION11_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region11. */ -#define TEE_AHB_PDMA_ADC_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_ADC_W_PMS_M (TEE_AHB_PDMA_ADC_W_PMS_V << TEE_AHB_PDMA_ADC_W_PMS_S) -#define TEE_AHB_PDMA_ADC_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_ADC_W_PMS_S 0 +#define PMS_DMA_REGION11_LOW 0x000FFFFFU +#define PMS_DMA_REGION11_LOW_M (PMS_DMA_REGION11_LOW_V << PMS_DMA_REGION11_LOW_S) +#define PMS_DMA_REGION11_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION11_LOW_S 12 -/** TEE_AHB_PDMA_I2S0_R_PMS_REG register - * AHB PDMA i2s0 read permission control registers. +/** PMS_DMA_REGION11_HIGH_REG register + * Region11 end address configuration register */ -#define TEE_AHB_PDMA_I2S0_R_PMS_REG (DR_REG_TEE_BASE + 0x130) -/** TEE_AHB_PDMA_I2S0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s0 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION11_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x64) +/** PMS_DMA_REGION11_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region11. */ -#define TEE_AHB_PDMA_I2S0_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S0_R_PMS_M (TEE_AHB_PDMA_I2S0_R_PMS_V << TEE_AHB_PDMA_I2S0_R_PMS_S) -#define TEE_AHB_PDMA_I2S0_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S0_R_PMS_S 0 +#define PMS_DMA_REGION11_HIGH 0x000FFFFFU +#define PMS_DMA_REGION11_HIGH_M (PMS_DMA_REGION11_HIGH_V << PMS_DMA_REGION11_HIGH_S) +#define PMS_DMA_REGION11_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION11_HIGH_S 12 -/** TEE_AHB_PDMA_I2S0_W_PMS_REG register - * AHB PDMA i2s0 write permission control registers. +/** PMS_DMA_REGION12_LOW_REG register + * Region12 start address configuration register */ -#define TEE_AHB_PDMA_I2S0_W_PMS_REG (DR_REG_TEE_BASE + 0x134) -/** TEE_AHB_PDMA_I2S0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s0 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION12_LOW_REG (DR_REG_PMS_DMA_BASE + 0x68) +/** PMS_DMA_REGION12_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region12. */ -#define TEE_AHB_PDMA_I2S0_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S0_W_PMS_M (TEE_AHB_PDMA_I2S0_W_PMS_V << TEE_AHB_PDMA_I2S0_W_PMS_S) -#define TEE_AHB_PDMA_I2S0_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S0_W_PMS_S 0 +#define PMS_DMA_REGION12_LOW 0x000FFFFFU +#define PMS_DMA_REGION12_LOW_M (PMS_DMA_REGION12_LOW_V << PMS_DMA_REGION12_LOW_S) +#define PMS_DMA_REGION12_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION12_LOW_S 12 -/** TEE_AHB_PDMA_I2S1_R_PMS_REG register - * AHB PDMA i2s1 read permission control registers. +/** PMS_DMA_REGION12_HIGH_REG register + * Region12 end address configuration register */ -#define TEE_AHB_PDMA_I2S1_R_PMS_REG (DR_REG_TEE_BASE + 0x138) -/** TEE_AHB_PDMA_I2S1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s1 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION12_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x6c) +/** PMS_DMA_REGION12_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region12. */ -#define TEE_AHB_PDMA_I2S1_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S1_R_PMS_M (TEE_AHB_PDMA_I2S1_R_PMS_V << TEE_AHB_PDMA_I2S1_R_PMS_S) -#define TEE_AHB_PDMA_I2S1_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S1_R_PMS_S 0 +#define PMS_DMA_REGION12_HIGH 0x000FFFFFU +#define PMS_DMA_REGION12_HIGH_M (PMS_DMA_REGION12_HIGH_V << PMS_DMA_REGION12_HIGH_S) +#define PMS_DMA_REGION12_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION12_HIGH_S 12 -/** TEE_AHB_PDMA_I2S1_W_PMS_REG register - * AHB PDMA i2s1 write permission control registers. +/** PMS_DMA_REGION13_LOW_REG register + * Region13 start address configuration register */ -#define TEE_AHB_PDMA_I2S1_W_PMS_REG (DR_REG_TEE_BASE + 0x13c) -/** TEE_AHB_PDMA_I2S1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s1 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION13_LOW_REG (DR_REG_PMS_DMA_BASE + 0x70) +/** PMS_DMA_REGION13_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region13. */ -#define TEE_AHB_PDMA_I2S1_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S1_W_PMS_M (TEE_AHB_PDMA_I2S1_W_PMS_V << TEE_AHB_PDMA_I2S1_W_PMS_S) -#define TEE_AHB_PDMA_I2S1_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S1_W_PMS_S 0 +#define PMS_DMA_REGION13_LOW 0x000FFFFFU +#define PMS_DMA_REGION13_LOW_M (PMS_DMA_REGION13_LOW_V << PMS_DMA_REGION13_LOW_S) +#define PMS_DMA_REGION13_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION13_LOW_S 12 -/** TEE_AHB_PDMA_I2S2_R_PMS_REG register - * AHB PDMA i2s2 read permission control registers. +/** PMS_DMA_REGION13_HIGH_REG register + * Region13 end address configuration register */ -#define TEE_AHB_PDMA_I2S2_R_PMS_REG (DR_REG_TEE_BASE + 0x140) -/** TEE_AHB_PDMA_I2S2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s2 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION13_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x74) +/** PMS_DMA_REGION13_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region13. */ -#define TEE_AHB_PDMA_I2S2_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S2_R_PMS_M (TEE_AHB_PDMA_I2S2_R_PMS_V << TEE_AHB_PDMA_I2S2_R_PMS_S) -#define TEE_AHB_PDMA_I2S2_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S2_R_PMS_S 0 +#define PMS_DMA_REGION13_HIGH 0x000FFFFFU +#define PMS_DMA_REGION13_HIGH_M (PMS_DMA_REGION13_HIGH_V << PMS_DMA_REGION13_HIGH_S) +#define PMS_DMA_REGION13_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION13_HIGH_S 12 -/** TEE_AHB_PDMA_I2S2_W_PMS_REG register - * AHB PDMA i2s2 write permission control registers. +/** PMS_DMA_REGION14_LOW_REG register + * Region14 start address configuration register */ -#define TEE_AHB_PDMA_I2S2_W_PMS_REG (DR_REG_TEE_BASE + 0x144) -/** TEE_AHB_PDMA_I2S2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s2 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION14_LOW_REG (DR_REG_PMS_DMA_BASE + 0x78) +/** PMS_DMA_REGION14_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region14. */ -#define TEE_AHB_PDMA_I2S2_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S2_W_PMS_M (TEE_AHB_PDMA_I2S2_W_PMS_V << TEE_AHB_PDMA_I2S2_W_PMS_S) -#define TEE_AHB_PDMA_I2S2_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I2S2_W_PMS_S 0 +#define PMS_DMA_REGION14_LOW 0x000FFFFFU +#define PMS_DMA_REGION14_LOW_M (PMS_DMA_REGION14_LOW_V << PMS_DMA_REGION14_LOW_S) +#define PMS_DMA_REGION14_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION14_LOW_S 12 -/** TEE_AHB_PDMA_I3C_MST_R_PMS_REG register - * AHB PDMA i3s mst read permission control registers. +/** PMS_DMA_REGION14_HIGH_REG register + * Region14 end address configuration register */ -#define TEE_AHB_PDMA_I3C_MST_R_PMS_REG (DR_REG_TEE_BASE + 0x148) -/** TEE_AHB_PDMA_I3C_MST_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i3c mst read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION14_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x7c) +/** PMS_DMA_REGION14_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region14. */ -#define TEE_AHB_PDMA_I3C_MST_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I3C_MST_R_PMS_M (TEE_AHB_PDMA_I3C_MST_R_PMS_V << TEE_AHB_PDMA_I3C_MST_R_PMS_S) -#define TEE_AHB_PDMA_I3C_MST_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I3C_MST_R_PMS_S 0 +#define PMS_DMA_REGION14_HIGH 0x000FFFFFU +#define PMS_DMA_REGION14_HIGH_M (PMS_DMA_REGION14_HIGH_V << PMS_DMA_REGION14_HIGH_S) +#define PMS_DMA_REGION14_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION14_HIGH_S 12 -/** TEE_AHB_PDMA_I3C_MST_W_PMS_REG register - * AHB PDMA i3c mst write permission control registers. +/** PMS_DMA_REGION15_LOW_REG register + * Region15 start address configuration register */ -#define TEE_AHB_PDMA_I3C_MST_W_PMS_REG (DR_REG_TEE_BASE + 0x14c) -/** TEE_AHB_PDMA_I3C_MST_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i3c mst write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION15_LOW_REG (DR_REG_PMS_DMA_BASE + 0x80) +/** PMS_DMA_REGION15_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region15. */ -#define TEE_AHB_PDMA_I3C_MST_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_I3C_MST_W_PMS_M (TEE_AHB_PDMA_I3C_MST_W_PMS_V << TEE_AHB_PDMA_I3C_MST_W_PMS_S) -#define TEE_AHB_PDMA_I3C_MST_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_I3C_MST_W_PMS_S 0 +#define PMS_DMA_REGION15_LOW 0x000FFFFFU +#define PMS_DMA_REGION15_LOW_M (PMS_DMA_REGION15_LOW_V << PMS_DMA_REGION15_LOW_S) +#define PMS_DMA_REGION15_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION15_LOW_S 12 -/** TEE_AHB_PDMA_UHCI0_R_PMS_REG register - * AHB PDMA uhci0 read permission control registers. +/** PMS_DMA_REGION15_HIGH_REG register + * Region15 end address configuration register */ -#define TEE_AHB_PDMA_UHCI0_R_PMS_REG (DR_REG_TEE_BASE + 0x150) -/** TEE_AHB_PDMA_UHCI0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA uhci0 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION15_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x84) +/** PMS_DMA_REGION15_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region15. */ -#define TEE_AHB_PDMA_UHCI0_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_UHCI0_R_PMS_M (TEE_AHB_PDMA_UHCI0_R_PMS_V << TEE_AHB_PDMA_UHCI0_R_PMS_S) -#define TEE_AHB_PDMA_UHCI0_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_UHCI0_R_PMS_S 0 +#define PMS_DMA_REGION15_HIGH 0x000FFFFFU +#define PMS_DMA_REGION15_HIGH_M (PMS_DMA_REGION15_HIGH_V << PMS_DMA_REGION15_HIGH_S) +#define PMS_DMA_REGION15_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION15_HIGH_S 12 -/** TEE_AHB_PDMA_UHCI0_W_PMS_REG register - * AHB PDMA uhci0 write permission control registers. +/** PMS_DMA_REGION16_LOW_REG register + * Region16 start address configuration register */ -#define TEE_AHB_PDMA_UHCI0_W_PMS_REG (DR_REG_TEE_BASE + 0x154) -/** TEE_AHB_PDMA_UHCI0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA uhci0 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION16_LOW_REG (DR_REG_PMS_DMA_BASE + 0x88) +/** PMS_DMA_REGION16_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region16. */ -#define TEE_AHB_PDMA_UHCI0_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_UHCI0_W_PMS_M (TEE_AHB_PDMA_UHCI0_W_PMS_V << TEE_AHB_PDMA_UHCI0_W_PMS_S) -#define TEE_AHB_PDMA_UHCI0_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_UHCI0_W_PMS_S 0 +#define PMS_DMA_REGION16_LOW 0x000FFFFFU +#define PMS_DMA_REGION16_LOW_M (PMS_DMA_REGION16_LOW_V << PMS_DMA_REGION16_LOW_S) +#define PMS_DMA_REGION16_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION16_LOW_S 12 -/** TEE_AHB_PDMA_RMT_R_PMS_REG register - * AHB PDMA rmt read permission control registers. +/** PMS_DMA_REGION16_HIGH_REG register + * Region16 end address configuration register */ -#define TEE_AHB_PDMA_RMT_R_PMS_REG (DR_REG_TEE_BASE + 0x158) -/** TEE_AHB_PDMA_RMT_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA rmt read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION16_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x8c) +/** PMS_DMA_REGION16_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region16. */ -#define TEE_AHB_PDMA_RMT_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_RMT_R_PMS_M (TEE_AHB_PDMA_RMT_R_PMS_V << TEE_AHB_PDMA_RMT_R_PMS_S) -#define TEE_AHB_PDMA_RMT_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_RMT_R_PMS_S 0 +#define PMS_DMA_REGION16_HIGH 0x000FFFFFU +#define PMS_DMA_REGION16_HIGH_M (PMS_DMA_REGION16_HIGH_V << PMS_DMA_REGION16_HIGH_S) +#define PMS_DMA_REGION16_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION16_HIGH_S 12 -/** TEE_AHB_PDMA_RMT_W_PMS_REG register - * AHB PDMA rmt write permission control registers. +/** PMS_DMA_REGION17_LOW_REG register + * Region17 start address configuration register */ -#define TEE_AHB_PDMA_RMT_W_PMS_REG (DR_REG_TEE_BASE + 0x170) -/** TEE_AHB_PDMA_RMT_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA rmt write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION17_LOW_REG (DR_REG_PMS_DMA_BASE + 0x90) +/** PMS_DMA_REGION17_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region17. */ -#define TEE_AHB_PDMA_RMT_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_RMT_W_PMS_M (TEE_AHB_PDMA_RMT_W_PMS_V << TEE_AHB_PDMA_RMT_W_PMS_S) -#define TEE_AHB_PDMA_RMT_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_RMT_W_PMS_S 0 +#define PMS_DMA_REGION17_LOW 0x000FFFFFU +#define PMS_DMA_REGION17_LOW_M (PMS_DMA_REGION17_LOW_V << PMS_DMA_REGION17_LOW_S) +#define PMS_DMA_REGION17_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION17_LOW_S 12 -/** TEE_AXI_PDMA_LCDCAM_R_PMS_REG register - * AXI PDMA lcdcam read permission control registers. +/** PMS_DMA_REGION17_HIGH_REG register + * Region17 end address configuration register */ -#define TEE_AXI_PDMA_LCDCAM_R_PMS_REG (DR_REG_TEE_BASE + 0x174) -/** TEE_AXI_PDMA_LCDCAM_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA lcdcam read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION17_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x94) +/** PMS_DMA_REGION17_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region17. */ -#define TEE_AXI_PDMA_LCDCAM_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_LCDCAM_R_PMS_M (TEE_AXI_PDMA_LCDCAM_R_PMS_V << TEE_AXI_PDMA_LCDCAM_R_PMS_S) -#define TEE_AXI_PDMA_LCDCAM_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_LCDCAM_R_PMS_S 0 +#define PMS_DMA_REGION17_HIGH 0x000FFFFFU +#define PMS_DMA_REGION17_HIGH_M (PMS_DMA_REGION17_HIGH_V << PMS_DMA_REGION17_HIGH_S) +#define PMS_DMA_REGION17_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION17_HIGH_S 12 -/** TEE_AXI_PDMA_LCDCAM_W_PMS_REG register - * AXI PDMA lcdcam write permission control registers. +/** PMS_DMA_REGION18_LOW_REG register + * Region18 start address configuration register */ -#define TEE_AXI_PDMA_LCDCAM_W_PMS_REG (DR_REG_TEE_BASE + 0x178) -/** TEE_AXI_PDMA_LCDCAM_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA lcdcam write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION18_LOW_REG (DR_REG_PMS_DMA_BASE + 0x98) +/** PMS_DMA_REGION18_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region18. */ -#define TEE_AXI_PDMA_LCDCAM_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_LCDCAM_W_PMS_M (TEE_AXI_PDMA_LCDCAM_W_PMS_V << TEE_AXI_PDMA_LCDCAM_W_PMS_S) -#define TEE_AXI_PDMA_LCDCAM_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_LCDCAM_W_PMS_S 0 +#define PMS_DMA_REGION18_LOW 0x000FFFFFU +#define PMS_DMA_REGION18_LOW_M (PMS_DMA_REGION18_LOW_V << PMS_DMA_REGION18_LOW_S) +#define PMS_DMA_REGION18_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION18_LOW_S 12 -/** TEE_AXI_PDMA_GPSPI2_R_PMS_REG register - * AXI PDMA gpspi2 read permission control registers. +/** PMS_DMA_REGION18_HIGH_REG register + * Region18 end address configuration register */ -#define TEE_AXI_PDMA_GPSPI2_R_PMS_REG (DR_REG_TEE_BASE + 0x17c) -/** TEE_AXI_PDMA_GPSPI2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi2 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION18_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x9c) +/** PMS_DMA_REGION18_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region18. */ -#define TEE_AXI_PDMA_GPSPI2_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI2_R_PMS_M (TEE_AXI_PDMA_GPSPI2_R_PMS_V << TEE_AXI_PDMA_GPSPI2_R_PMS_S) -#define TEE_AXI_PDMA_GPSPI2_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI2_R_PMS_S 0 +#define PMS_DMA_REGION18_HIGH 0x000FFFFFU +#define PMS_DMA_REGION18_HIGH_M (PMS_DMA_REGION18_HIGH_V << PMS_DMA_REGION18_HIGH_S) +#define PMS_DMA_REGION18_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION18_HIGH_S 12 -/** TEE_AXI_PDMA_GPSPI2_W_PMS_REG register - * AXI PDMA gpspi2 write permission control registers. +/** PMS_DMA_REGION19_LOW_REG register + * Region19 start address configuration register */ -#define TEE_AXI_PDMA_GPSPI2_W_PMS_REG (DR_REG_TEE_BASE + 0x180) -/** TEE_AXI_PDMA_GPSPI2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi2 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION19_LOW_REG (DR_REG_PMS_DMA_BASE + 0xa0) +/** PMS_DMA_REGION19_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region19. */ -#define TEE_AXI_PDMA_GPSPI2_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI2_W_PMS_M (TEE_AXI_PDMA_GPSPI2_W_PMS_V << TEE_AXI_PDMA_GPSPI2_W_PMS_S) -#define TEE_AXI_PDMA_GPSPI2_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI2_W_PMS_S 0 +#define PMS_DMA_REGION19_LOW 0x000FFFFFU +#define PMS_DMA_REGION19_LOW_M (PMS_DMA_REGION19_LOW_V << PMS_DMA_REGION19_LOW_S) +#define PMS_DMA_REGION19_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION19_LOW_S 12 -/** TEE_AXI_PDMA_GPSPI3_R_PMS_REG register - * AXI PDMA gpspi3 read permission control registers. +/** PMS_DMA_REGION19_HIGH_REG register + * Region19 end address configuration register */ -#define TEE_AXI_PDMA_GPSPI3_R_PMS_REG (DR_REG_TEE_BASE + 0x184) -/** TEE_AXI_PDMA_GPSPI3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi3 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION19_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xa4) +/** PMS_DMA_REGION19_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region19. */ -#define TEE_AXI_PDMA_GPSPI3_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI3_R_PMS_M (TEE_AXI_PDMA_GPSPI3_R_PMS_V << TEE_AXI_PDMA_GPSPI3_R_PMS_S) -#define TEE_AXI_PDMA_GPSPI3_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI3_R_PMS_S 0 +#define PMS_DMA_REGION19_HIGH 0x000FFFFFU +#define PMS_DMA_REGION19_HIGH_M (PMS_DMA_REGION19_HIGH_V << PMS_DMA_REGION19_HIGH_S) +#define PMS_DMA_REGION19_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION19_HIGH_S 12 -/** TEE_AXI_PDMA_GPSPI3_W_PMS_REG register - * AXI PDMA gpspi3 write permission control registers. +/** PMS_DMA_REGION20_LOW_REG register + * Region20 start address configuration register */ -#define TEE_AXI_PDMA_GPSPI3_W_PMS_REG (DR_REG_TEE_BASE + 0x188) -/** TEE_AXI_PDMA_GPSPI3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi3 write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION20_LOW_REG (DR_REG_PMS_DMA_BASE + 0xa8) +/** PMS_DMA_REGION20_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region20. */ -#define TEE_AXI_PDMA_GPSPI3_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI3_W_PMS_M (TEE_AXI_PDMA_GPSPI3_W_PMS_V << TEE_AXI_PDMA_GPSPI3_W_PMS_S) -#define TEE_AXI_PDMA_GPSPI3_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_GPSPI3_W_PMS_S 0 +#define PMS_DMA_REGION20_LOW 0x000FFFFFU +#define PMS_DMA_REGION20_LOW_M (PMS_DMA_REGION20_LOW_V << PMS_DMA_REGION20_LOW_S) +#define PMS_DMA_REGION20_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION20_LOW_S 12 -/** TEE_AXI_PDMA_PARLIO_R_PMS_REG register - * AXI PDMA parl io read permission control registers. +/** PMS_DMA_REGION20_HIGH_REG register + * Region20 end address configuration register */ -#define TEE_AXI_PDMA_PARLIO_R_PMS_REG (DR_REG_TEE_BASE + 0x18c) -/** TEE_AXI_PDMA_PARLIO_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA parl io read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION20_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xac) +/** PMS_DMA_REGION20_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region20. */ -#define TEE_AXI_PDMA_PARLIO_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_PARLIO_R_PMS_M (TEE_AXI_PDMA_PARLIO_R_PMS_V << TEE_AXI_PDMA_PARLIO_R_PMS_S) -#define TEE_AXI_PDMA_PARLIO_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_PARLIO_R_PMS_S 0 +#define PMS_DMA_REGION20_HIGH 0x000FFFFFU +#define PMS_DMA_REGION20_HIGH_M (PMS_DMA_REGION20_HIGH_V << PMS_DMA_REGION20_HIGH_S) +#define PMS_DMA_REGION20_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION20_HIGH_S 12 -/** TEE_AXI_PDMA_PARLIO_W_PMS_REG register - * AXI PDMA parl io write permission control registers. +/** PMS_DMA_REGION21_LOW_REG register + * Region21 start address configuration register */ -#define TEE_AXI_PDMA_PARLIO_W_PMS_REG (DR_REG_TEE_BASE + 0x190) -/** TEE_AXI_PDMA_PARLIO_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA parl io write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION21_LOW_REG (DR_REG_PMS_DMA_BASE + 0xb0) +/** PMS_DMA_REGION21_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region21. */ -#define TEE_AXI_PDMA_PARLIO_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_PARLIO_W_PMS_M (TEE_AXI_PDMA_PARLIO_W_PMS_V << TEE_AXI_PDMA_PARLIO_W_PMS_S) -#define TEE_AXI_PDMA_PARLIO_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_PARLIO_W_PMS_S 0 +#define PMS_DMA_REGION21_LOW 0x000FFFFFU +#define PMS_DMA_REGION21_LOW_M (PMS_DMA_REGION21_LOW_V << PMS_DMA_REGION21_LOW_S) +#define PMS_DMA_REGION21_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION21_LOW_S 12 -/** TEE_AXI_PDMA_AES_R_PMS_REG register - * AXI PDMA aes read permission control registers. +/** PMS_DMA_REGION21_HIGH_REG register + * Region21 end address configuration register */ -#define TEE_AXI_PDMA_AES_R_PMS_REG (DR_REG_TEE_BASE + 0x194) -/** TEE_AXI_PDMA_AES_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA aes read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION21_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xb4) +/** PMS_DMA_REGION21_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region21. */ -#define TEE_AXI_PDMA_AES_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_AES_R_PMS_M (TEE_AXI_PDMA_AES_R_PMS_V << TEE_AXI_PDMA_AES_R_PMS_S) -#define TEE_AXI_PDMA_AES_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_AES_R_PMS_S 0 +#define PMS_DMA_REGION21_HIGH 0x000FFFFFU +#define PMS_DMA_REGION21_HIGH_M (PMS_DMA_REGION21_HIGH_V << PMS_DMA_REGION21_HIGH_S) +#define PMS_DMA_REGION21_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION21_HIGH_S 12 -/** TEE_AXI_PDMA_AES_W_PMS_REG register - * AXI PDMA aes write permission control registers. +/** PMS_DMA_REGION22_LOW_REG register + * Region22 start address configuration register */ -#define TEE_AXI_PDMA_AES_W_PMS_REG (DR_REG_TEE_BASE + 0x198) -/** TEE_AXI_PDMA_AES_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA aes write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION22_LOW_REG (DR_REG_PMS_DMA_BASE + 0xb8) +/** PMS_DMA_REGION22_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region22. */ -#define TEE_AXI_PDMA_AES_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_AES_W_PMS_M (TEE_AXI_PDMA_AES_W_PMS_V << TEE_AXI_PDMA_AES_W_PMS_S) -#define TEE_AXI_PDMA_AES_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_AES_W_PMS_S 0 +#define PMS_DMA_REGION22_LOW 0x000FFFFFU +#define PMS_DMA_REGION22_LOW_M (PMS_DMA_REGION22_LOW_V << PMS_DMA_REGION22_LOW_S) +#define PMS_DMA_REGION22_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION22_LOW_S 12 -/** TEE_AXI_PDMA_SHA_R_PMS_REG register - * AXI PDMA sha read permission control registers. +/** PMS_DMA_REGION22_HIGH_REG register + * Region22 end address configuration register */ -#define TEE_AXI_PDMA_SHA_R_PMS_REG (DR_REG_TEE_BASE + 0x19c) -/** TEE_AXI_PDMA_SHA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA sha read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION22_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xbc) +/** PMS_DMA_REGION22_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region22. */ -#define TEE_AXI_PDMA_SHA_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_SHA_R_PMS_M (TEE_AXI_PDMA_SHA_R_PMS_V << TEE_AXI_PDMA_SHA_R_PMS_S) -#define TEE_AXI_PDMA_SHA_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_SHA_R_PMS_S 0 +#define PMS_DMA_REGION22_HIGH 0x000FFFFFU +#define PMS_DMA_REGION22_HIGH_M (PMS_DMA_REGION22_HIGH_V << PMS_DMA_REGION22_HIGH_S) +#define PMS_DMA_REGION22_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION22_HIGH_S 12 -/** TEE_AXI_PDMA_SHA_W_PMS_REG register - * AXI PDMA sha write permission control registers. +/** PMS_DMA_REGION23_LOW_REG register + * Region23 start address configuration register */ -#define TEE_AXI_PDMA_SHA_W_PMS_REG (DR_REG_TEE_BASE + 0x1a0) -/** TEE_AXI_PDMA_SHA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA sha write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION23_LOW_REG (DR_REG_PMS_DMA_BASE + 0xc0) +/** PMS_DMA_REGION23_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region23. */ -#define TEE_AXI_PDMA_SHA_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_SHA_W_PMS_M (TEE_AXI_PDMA_SHA_W_PMS_V << TEE_AXI_PDMA_SHA_W_PMS_S) -#define TEE_AXI_PDMA_SHA_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_SHA_W_PMS_S 0 +#define PMS_DMA_REGION23_LOW 0x000FFFFFU +#define PMS_DMA_REGION23_LOW_M (PMS_DMA_REGION23_LOW_V << PMS_DMA_REGION23_LOW_S) +#define PMS_DMA_REGION23_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION23_LOW_S 12 -/** TEE_DMA2D_JPEG_PMS_R_REG register - * DMA2D JPEG read permission control registers. +/** PMS_DMA_REGION23_HIGH_REG register + * Region23 end address configuration register */ -#define TEE_DMA2D_JPEG_PMS_R_REG (DR_REG_TEE_BASE + 0x1a4) -/** TEE_DMA2D_JPEG_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D JPEG read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION23_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xc4) +/** PMS_DMA_REGION23_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region23. */ -#define TEE_DMA2D_JPEG_R_PMS 0xFFFFFFFFU -#define TEE_DMA2D_JPEG_R_PMS_M (TEE_DMA2D_JPEG_R_PMS_V << TEE_DMA2D_JPEG_R_PMS_S) -#define TEE_DMA2D_JPEG_R_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_JPEG_R_PMS_S 0 +#define PMS_DMA_REGION23_HIGH 0x000FFFFFU +#define PMS_DMA_REGION23_HIGH_M (PMS_DMA_REGION23_HIGH_V << PMS_DMA_REGION23_HIGH_S) +#define PMS_DMA_REGION23_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION23_HIGH_S 12 -/** TEE_DMA2D_JPEG_PMS_W_REG register - * DMA2D JPEG write permission control registers. +/** PMS_DMA_REGION24_LOW_REG register + * Region24 start address configuration register */ -#define TEE_DMA2D_JPEG_PMS_W_REG (DR_REG_TEE_BASE + 0x1a8) -/** TEE_DMA2D_JPEG_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D JPEG write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION24_LOW_REG (DR_REG_PMS_DMA_BASE + 0xc8) +/** PMS_DMA_REGION24_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region24. */ -#define TEE_DMA2D_JPEG_W_PMS 0xFFFFFFFFU -#define TEE_DMA2D_JPEG_W_PMS_M (TEE_DMA2D_JPEG_W_PMS_V << TEE_DMA2D_JPEG_W_PMS_S) -#define TEE_DMA2D_JPEG_W_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_JPEG_W_PMS_S 0 +#define PMS_DMA_REGION24_LOW 0x000FFFFFU +#define PMS_DMA_REGION24_LOW_M (PMS_DMA_REGION24_LOW_V << PMS_DMA_REGION24_LOW_S) +#define PMS_DMA_REGION24_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION24_LOW_S 12 -/** TEE_USB_PMS_R_REG register - * USB read permission control registers. +/** PMS_DMA_REGION24_HIGH_REG register + * Region24 end address configuration register */ -#define TEE_USB_PMS_R_REG (DR_REG_TEE_BASE + 0x1ac) -/** TEE_USB_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * USB read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION24_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xcc) +/** PMS_DMA_REGION24_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region24. */ -#define TEE_USB_R_PMS 0xFFFFFFFFU -#define TEE_USB_R_PMS_M (TEE_USB_R_PMS_V << TEE_USB_R_PMS_S) -#define TEE_USB_R_PMS_V 0xFFFFFFFFU -#define TEE_USB_R_PMS_S 0 +#define PMS_DMA_REGION24_HIGH 0x000FFFFFU +#define PMS_DMA_REGION24_HIGH_M (PMS_DMA_REGION24_HIGH_V << PMS_DMA_REGION24_HIGH_S) +#define PMS_DMA_REGION24_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION24_HIGH_S 12 -/** TEE_USB_PMS_W_REG register - * USB write permission control registers. +/** PMS_DMA_REGION25_LOW_REG register + * Region25 start address configuration register */ -#define TEE_USB_PMS_W_REG (DR_REG_TEE_BASE + 0x1b0) -/** TEE_USB_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * USB write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION25_LOW_REG (DR_REG_PMS_DMA_BASE + 0xd0) +/** PMS_DMA_REGION25_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region25. */ -#define TEE_USB_W_PMS 0xFFFFFFFFU -#define TEE_USB_W_PMS_M (TEE_USB_W_PMS_V << TEE_USB_W_PMS_S) -#define TEE_USB_W_PMS_V 0xFFFFFFFFU -#define TEE_USB_W_PMS_S 0 +#define PMS_DMA_REGION25_LOW 0x000FFFFFU +#define PMS_DMA_REGION25_LOW_M (PMS_DMA_REGION25_LOW_V << PMS_DMA_REGION25_LOW_S) +#define PMS_DMA_REGION25_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION25_LOW_S 12 -/** TEE_GMAC_PMS_R_REG register - * GMAC read permission control registers. +/** PMS_DMA_REGION25_HIGH_REG register + * Region25 end address configuration register */ -#define TEE_GMAC_PMS_R_REG (DR_REG_TEE_BASE + 0x1b4) -/** TEE_GMAC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GMAC read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION25_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xd4) +/** PMS_DMA_REGION25_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region25. */ -#define TEE_GMAC_R_PMS 0xFFFFFFFFU -#define TEE_GMAC_R_PMS_M (TEE_GMAC_R_PMS_V << TEE_GMAC_R_PMS_S) -#define TEE_GMAC_R_PMS_V 0xFFFFFFFFU -#define TEE_GMAC_R_PMS_S 0 +#define PMS_DMA_REGION25_HIGH 0x000FFFFFU +#define PMS_DMA_REGION25_HIGH_M (PMS_DMA_REGION25_HIGH_V << PMS_DMA_REGION25_HIGH_S) +#define PMS_DMA_REGION25_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION25_HIGH_S 12 -/** TEE_GMAC_PMS_W_REG register - * GMAC write permission control registers. +/** PMS_DMA_REGION26_LOW_REG register + * Region26 start address configuration register */ -#define TEE_GMAC_PMS_W_REG (DR_REG_TEE_BASE + 0x1b8) -/** TEE_GMAC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * GMAC write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION26_LOW_REG (DR_REG_PMS_DMA_BASE + 0xd8) +/** PMS_DMA_REGION26_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region26. */ -#define TEE_GMAC_W_PMS 0xFFFFFFFFU -#define TEE_GMAC_W_PMS_M (TEE_GMAC_W_PMS_V << TEE_GMAC_W_PMS_S) -#define TEE_GMAC_W_PMS_V 0xFFFFFFFFU -#define TEE_GMAC_W_PMS_S 0 +#define PMS_DMA_REGION26_LOW 0x000FFFFFU +#define PMS_DMA_REGION26_LOW_M (PMS_DMA_REGION26_LOW_V << PMS_DMA_REGION26_LOW_S) +#define PMS_DMA_REGION26_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION26_LOW_S 12 -/** TEE_SDMMC_PMS_R_REG register - * SDMMC read permission control registers. +/** PMS_DMA_REGION26_HIGH_REG register + * Region26 end address configuration register */ -#define TEE_SDMMC_PMS_R_REG (DR_REG_TEE_BASE + 0x1bc) -/** TEE_SDMMC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * SDMMC read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION26_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xdc) +/** PMS_DMA_REGION26_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region26. */ -#define TEE_SDMMC_R_PMS 0xFFFFFFFFU -#define TEE_SDMMC_R_PMS_M (TEE_SDMMC_R_PMS_V << TEE_SDMMC_R_PMS_S) -#define TEE_SDMMC_R_PMS_V 0xFFFFFFFFU -#define TEE_SDMMC_R_PMS_S 0 +#define PMS_DMA_REGION26_HIGH 0x000FFFFFU +#define PMS_DMA_REGION26_HIGH_M (PMS_DMA_REGION26_HIGH_V << PMS_DMA_REGION26_HIGH_S) +#define PMS_DMA_REGION26_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION26_HIGH_S 12 -/** TEE_SDMMC_PMS_W_REG register - * SDMMC write permission control registers. +/** PMS_DMA_REGION27_LOW_REG register + * Region27 start address configuration register */ -#define TEE_SDMMC_PMS_W_REG (DR_REG_TEE_BASE + 0x1c0) -/** TEE_SDMMC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * SDMMC write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION27_LOW_REG (DR_REG_PMS_DMA_BASE + 0xe0) +/** PMS_DMA_REGION27_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region27. */ -#define TEE_SDMMC_W_PMS 0xFFFFFFFFU -#define TEE_SDMMC_W_PMS_M (TEE_SDMMC_W_PMS_V << TEE_SDMMC_W_PMS_S) -#define TEE_SDMMC_W_PMS_V 0xFFFFFFFFU -#define TEE_SDMMC_W_PMS_S 0 +#define PMS_DMA_REGION27_LOW 0x000FFFFFU +#define PMS_DMA_REGION27_LOW_M (PMS_DMA_REGION27_LOW_V << PMS_DMA_REGION27_LOW_S) +#define PMS_DMA_REGION27_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION27_LOW_S 12 -/** TEE_USBOTG11_PMS_R_REG register - * USBOTG11 read permission control registers. +/** PMS_DMA_REGION27_HIGH_REG register + * Region27 end address configuration register */ -#define TEE_USBOTG11_PMS_R_REG (DR_REG_TEE_BASE + 0x1c4) -/** TEE_USBOTG11_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * USBOTG11 read permission control, each bit corresponds to a region. +#define PMS_DMA_REGION27_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xe4) +/** PMS_DMA_REGION27_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region27. */ -#define TEE_USBOTG11_R_PMS 0xFFFFFFFFU -#define TEE_USBOTG11_R_PMS_M (TEE_USBOTG11_R_PMS_V << TEE_USBOTG11_R_PMS_S) -#define TEE_USBOTG11_R_PMS_V 0xFFFFFFFFU -#define TEE_USBOTG11_R_PMS_S 0 +#define PMS_DMA_REGION27_HIGH 0x000FFFFFU +#define PMS_DMA_REGION27_HIGH_M (PMS_DMA_REGION27_HIGH_V << PMS_DMA_REGION27_HIGH_S) +#define PMS_DMA_REGION27_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION27_HIGH_S 12 -/** TEE_USBOTG11_PMS_W_REG register - * USBOTG11 write permission control registers. - */ -#define TEE_USBOTG11_PMS_W_REG (DR_REG_TEE_BASE + 0x1c8) -/** TEE_USBOTG11_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * USBOTG11 write permission control, each bit corresponds to a region. - */ -#define TEE_USBOTG11_W_PMS 0xFFFFFFFFU -#define TEE_USBOTG11_W_PMS_M (TEE_USBOTG11_W_PMS_V << TEE_USBOTG11_W_PMS_S) -#define TEE_USBOTG11_W_PMS_V 0xFFFFFFFFU -#define TEE_USBOTG11_W_PMS_S 0 - -/** TEE_TRACE0_PMS_R_REG register - * TRACE0 read permission control registers. - */ -#define TEE_TRACE0_PMS_R_REG (DR_REG_TEE_BASE + 0x1cc) -/** TEE_TRACE0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE0 read permission control, each bit corresponds to a region. - */ -#define TEE_TRACE0_R_PMS 0xFFFFFFFFU -#define TEE_TRACE0_R_PMS_M (TEE_TRACE0_R_PMS_V << TEE_TRACE0_R_PMS_S) -#define TEE_TRACE0_R_PMS_V 0xFFFFFFFFU -#define TEE_TRACE0_R_PMS_S 0 - -/** TEE_TRACE0_PMS_W_REG register - * TRACE0 write permission control registers. - */ -#define TEE_TRACE0_PMS_W_REG (DR_REG_TEE_BASE + 0x1d0) -/** TEE_TRACE0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE0 write permission control, each bit corresponds to a region. - */ -#define TEE_TRACE0_W_PMS 0xFFFFFFFFU -#define TEE_TRACE0_W_PMS_M (TEE_TRACE0_W_PMS_V << TEE_TRACE0_W_PMS_S) -#define TEE_TRACE0_W_PMS_V 0xFFFFFFFFU -#define TEE_TRACE0_W_PMS_S 0 - -/** TEE_TRACE1_PMS_R_REG register - * TRACE1 read permission control registers. - */ -#define TEE_TRACE1_PMS_R_REG (DR_REG_TEE_BASE + 0x1d4) -/** TEE_TRACE1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE1 read permission control, each bit corresponds to a region. - */ -#define TEE_TRACE1_R_PMS 0xFFFFFFFFU -#define TEE_TRACE1_R_PMS_M (TEE_TRACE1_R_PMS_V << TEE_TRACE1_R_PMS_S) -#define TEE_TRACE1_R_PMS_V 0xFFFFFFFFU -#define TEE_TRACE1_R_PMS_S 0 - -/** TEE_TRACE1_PMS_W_REG register - * TRACE1 write permission control registers. - */ -#define TEE_TRACE1_PMS_W_REG (DR_REG_TEE_BASE + 0x1d8) -/** TEE_TRACE1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE1 write permission control, each bit corresponds to a region. - */ -#define TEE_TRACE1_W_PMS 0xFFFFFFFFU -#define TEE_TRACE1_W_PMS_M (TEE_TRACE1_W_PMS_V << TEE_TRACE1_W_PMS_S) -#define TEE_TRACE1_W_PMS_V 0xFFFFFFFFU -#define TEE_TRACE1_W_PMS_S 0 - -/** TEE_L2MEM_MON_PMS_R_REG register - * L2MEM MON read permission control registers. - */ -#define TEE_L2MEM_MON_PMS_R_REG (DR_REG_TEE_BASE + 0x1dc) -/** TEE_L2MEM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * L2MEM MON read permission control, each bit corresponds to a region. - */ -#define TEE_L2MEM_MON_R_PMS 0xFFFFFFFFU -#define TEE_L2MEM_MON_R_PMS_M (TEE_L2MEM_MON_R_PMS_V << TEE_L2MEM_MON_R_PMS_S) -#define TEE_L2MEM_MON_R_PMS_V 0xFFFFFFFFU -#define TEE_L2MEM_MON_R_PMS_S 0 - -/** TEE_L2MEM_MON_PMS_W_REG register - * L2MEM MON write permission control registers. - */ -#define TEE_L2MEM_MON_PMS_W_REG (DR_REG_TEE_BASE + 0x1e0) -/** TEE_L2MEM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * L2MEM MON write permission control, each bit corresponds to a region. - */ -#define TEE_L2MEM_MON_W_PMS 0xFFFFFFFFU -#define TEE_L2MEM_MON_W_PMS_M (TEE_L2MEM_MON_W_PMS_V << TEE_L2MEM_MON_W_PMS_S) -#define TEE_L2MEM_MON_W_PMS_V 0xFFFFFFFFU -#define TEE_L2MEM_MON_W_PMS_S 0 - -/** TEE_TCM_MON_PMS_R_REG register - * TCM MON read permission control registers. - */ -#define TEE_TCM_MON_PMS_R_REG (DR_REG_TEE_BASE + 0x1e4) -/** TEE_TCM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TCM MON read permission control, each bit corresponds to a region. - */ -#define TEE_TCM_MON_R_PMS 0xFFFFFFFFU -#define TEE_TCM_MON_R_PMS_M (TEE_TCM_MON_R_PMS_V << TEE_TCM_MON_R_PMS_S) -#define TEE_TCM_MON_R_PMS_V 0xFFFFFFFFU -#define TEE_TCM_MON_R_PMS_S 0 - -/** TEE_TCM_MON_PMS_W_REG register - * TCM MON write permission control registers. - */ -#define TEE_TCM_MON_PMS_W_REG (DR_REG_TEE_BASE + 0x1e8) -/** TEE_TCM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * TCM MON write permission control, each bit corresponds to a region. - */ -#define TEE_TCM_MON_W_PMS 0xFFFFFFFFU -#define TEE_TCM_MON_W_PMS_M (TEE_TCM_MON_W_PMS_V << TEE_TCM_MON_W_PMS_S) -#define TEE_TCM_MON_W_PMS_V 0xFFFFFFFFU -#define TEE_TCM_MON_W_PMS_S 0 - -/** TEE_REGDMA_PMS_R_REG register - * REGDMA read permission control registers. - */ -#define TEE_REGDMA_PMS_R_REG (DR_REG_TEE_BASE + 0x1ec) -/** TEE_REGDMA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * REGDMA read permission control, each bit corresponds to a region. - */ -#define TEE_REGDMA_R_PMS 0xFFFFFFFFU -#define TEE_REGDMA_R_PMS_M (TEE_REGDMA_R_PMS_V << TEE_REGDMA_R_PMS_S) -#define TEE_REGDMA_R_PMS_V 0xFFFFFFFFU -#define TEE_REGDMA_R_PMS_S 0 - -/** TEE_REGDMA_PMS_W_REG register - * REGDMA write permission control registers. - */ -#define TEE_REGDMA_PMS_W_REG (DR_REG_TEE_BASE + 0x1f0) -/** TEE_REGDMA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * REGDMA write permission control, each bit corresponds to a region. - */ -#define TEE_REGDMA_W_PMS 0xFFFFFFFFU -#define TEE_REGDMA_W_PMS_M (TEE_REGDMA_W_PMS_V << TEE_REGDMA_W_PMS_S) -#define TEE_REGDMA_W_PMS_V 0xFFFFFFFFU -#define TEE_REGDMA_W_PMS_S 0 - -/** TEE_H264_PMS_R_REG register - * H264 read permission control registers. - */ -#define TEE_H264_PMS_R_REG (DR_REG_TEE_BASE + 0x1fc) -/** TEE_H264_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * H264 read permission control, each bit corresponds to a region. - */ -#define TEE_H264_R_PMS 0xFFFFFFFFU -#define TEE_H264_R_PMS_M (TEE_H264_R_PMS_V << TEE_H264_R_PMS_S) -#define TEE_H264_R_PMS_V 0xFFFFFFFFU -#define TEE_H264_R_PMS_S 0 - -/** TEE_H264_PMS_W_REG register - * H264 write permission control registers. - */ -#define TEE_H264_PMS_W_REG (DR_REG_TEE_BASE + 0x200) -/** TEE_H264_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * H264 write permission control, each bit corresponds to a region. - */ -#define TEE_H264_W_PMS 0xFFFFFFFFU -#define TEE_H264_W_PMS_M (TEE_H264_W_PMS_V << TEE_H264_W_PMS_S) -#define TEE_H264_W_PMS_V 0xFFFFFFFFU -#define TEE_H264_W_PMS_S 0 - -/** TEE_DMA2D_PPA_PMS_R_REG register - * DMA2D PPA read permission control registers. - */ -#define TEE_DMA2D_PPA_PMS_R_REG (DR_REG_TEE_BASE + 0x204) -/** TEE_DMA2D_PPA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D PPA read permission control, each bit corresponds to a region. - */ -#define TEE_DMA2D_PPA_R_PMS 0xFFFFFFFFU -#define TEE_DMA2D_PPA_R_PMS_M (TEE_DMA2D_PPA_R_PMS_V << TEE_DMA2D_PPA_R_PMS_S) -#define TEE_DMA2D_PPA_R_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_PPA_R_PMS_S 0 - -/** TEE_DMA2D_PPA_PMS_W_REG register - * DMA2D PPA write permission control registers. - */ -#define TEE_DMA2D_PPA_PMS_W_REG (DR_REG_TEE_BASE + 0x208) -/** TEE_DMA2D_PPA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D PPA write permission control, each bit corresponds to a region. - */ -#define TEE_DMA2D_PPA_W_PMS 0xFFFFFFFFU -#define TEE_DMA2D_PPA_W_PMS_M (TEE_DMA2D_PPA_W_PMS_V << TEE_DMA2D_PPA_W_PMS_S) -#define TEE_DMA2D_PPA_W_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_PPA_W_PMS_S 0 - -/** TEE_DMA2D_DUMMY_PMS_R_REG register - * DMA2D dummy read permission control registers. - */ -#define TEE_DMA2D_DUMMY_PMS_R_REG (DR_REG_TEE_BASE + 0x20c) -/** TEE_DMA2D_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D dummy read permission control, each bit corresponds to a region. - */ -#define TEE_DMA2D_DUMMY_R_PMS 0xFFFFFFFFU -#define TEE_DMA2D_DUMMY_R_PMS_M (TEE_DMA2D_DUMMY_R_PMS_V << TEE_DMA2D_DUMMY_R_PMS_S) -#define TEE_DMA2D_DUMMY_R_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_DUMMY_R_PMS_S 0 - -/** TEE_DMA2D_DUMMY_PMS_W_REG register - * DMA2D dummy write permission control registers. - */ -#define TEE_DMA2D_DUMMY_PMS_W_REG (DR_REG_TEE_BASE + 0x210) -/** TEE_DMA2D_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D dummy write permission control, each bit corresponds to a region. - */ -#define TEE_DMA2D_DUMMY_W_PMS 0xFFFFFFFFU -#define TEE_DMA2D_DUMMY_W_PMS_M (TEE_DMA2D_DUMMY_W_PMS_V << TEE_DMA2D_DUMMY_W_PMS_S) -#define TEE_DMA2D_DUMMY_W_PMS_V 0xFFFFFFFFU -#define TEE_DMA2D_DUMMY_W_PMS_S 0 - -/** TEE_AHB_PDMA_DUMMY_R_PMS_REG register - * AHB PDMA dummy read permission control registers. - */ -#define TEE_AHB_PDMA_DUMMY_R_PMS_REG (DR_REG_TEE_BASE + 0x214) -/** TEE_AHB_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA dummy read permission control, each bit corresponds to a region. - */ -#define TEE_AHB_PDMA_DUMMY_R_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_DUMMY_R_PMS_M (TEE_AHB_PDMA_DUMMY_R_PMS_V << TEE_AHB_PDMA_DUMMY_R_PMS_S) -#define TEE_AHB_PDMA_DUMMY_R_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_DUMMY_R_PMS_S 0 - -/** TEE_AHB_PDMA_DUMMY_W_PMS_REG register - * AHB PDMA dummy write permission control registers. - */ -#define TEE_AHB_PDMA_DUMMY_W_PMS_REG (DR_REG_TEE_BASE + 0x218) -/** TEE_AHB_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA dummy write permission control, each bit corresponds to a region. - */ -#define TEE_AHB_PDMA_DUMMY_W_PMS 0xFFFFFFFFU -#define TEE_AHB_PDMA_DUMMY_W_PMS_M (TEE_AHB_PDMA_DUMMY_W_PMS_V << TEE_AHB_PDMA_DUMMY_W_PMS_S) -#define TEE_AHB_PDMA_DUMMY_W_PMS_V 0xFFFFFFFFU -#define TEE_AHB_PDMA_DUMMY_W_PMS_S 0 - -/** TEE_AXI_PDMA_DUMMY_R_PMS_REG register - * AXI PDMA dummy read permission control registers. - */ -#define TEE_AXI_PDMA_DUMMY_R_PMS_REG (DR_REG_TEE_BASE + 0x21c) -/** TEE_AXI_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA dummy read permission control, each bit corresponds to a region. +/** PMS_DMA_REGION28_LOW_REG register + * Region28 start address configuration register */ -#define TEE_AXI_PDMA_DUMMY_R_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_DUMMY_R_PMS_M (TEE_AXI_PDMA_DUMMY_R_PMS_V << TEE_AXI_PDMA_DUMMY_R_PMS_S) -#define TEE_AXI_PDMA_DUMMY_R_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_DUMMY_R_PMS_S 0 - -/** TEE_AXI_PDMA_DUMMY_W_PMS_REG register - * AXI PDMA dummy write permission control registers. +#define PMS_DMA_REGION28_LOW_REG (DR_REG_PMS_DMA_BASE + 0xe8) +/** PMS_DMA_REGION28_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region28. */ -#define TEE_AXI_PDMA_DUMMY_W_PMS_REG (DR_REG_TEE_BASE + 0x220) -/** TEE_AXI_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA dummy write permission control, each bit corresponds to a region. +#define PMS_DMA_REGION28_LOW 0x000FFFFFU +#define PMS_DMA_REGION28_LOW_M (PMS_DMA_REGION28_LOW_V << PMS_DMA_REGION28_LOW_S) +#define PMS_DMA_REGION28_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION28_LOW_S 12 + +/** PMS_DMA_REGION28_HIGH_REG register + * Region28 end address configuration register */ -#define TEE_AXI_PDMA_DUMMY_W_PMS 0xFFFFFFFFU -#define TEE_AXI_PDMA_DUMMY_W_PMS_M (TEE_AXI_PDMA_DUMMY_W_PMS_V << TEE_AXI_PDMA_DUMMY_W_PMS_S) -#define TEE_AXI_PDMA_DUMMY_W_PMS_V 0xFFFFFFFFU -#define TEE_AXI_PDMA_DUMMY_W_PMS_S 0 +#define PMS_DMA_REGION28_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xec) +/** PMS_DMA_REGION28_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region28. + */ +#define PMS_DMA_REGION28_HIGH 0x000FFFFFU +#define PMS_DMA_REGION28_HIGH_M (PMS_DMA_REGION28_HIGH_V << PMS_DMA_REGION28_HIGH_S) +#define PMS_DMA_REGION28_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION28_HIGH_S 12 + +/** PMS_DMA_REGION29_LOW_REG register + * Region29 start address configuration register + */ +#define PMS_DMA_REGION29_LOW_REG (DR_REG_PMS_DMA_BASE + 0xf0) +/** PMS_DMA_REGION29_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region29. + */ +#define PMS_DMA_REGION29_LOW 0x000FFFFFU +#define PMS_DMA_REGION29_LOW_M (PMS_DMA_REGION29_LOW_V << PMS_DMA_REGION29_LOW_S) +#define PMS_DMA_REGION29_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION29_LOW_S 12 + +/** PMS_DMA_REGION29_HIGH_REG register + * Region29 end address configuration register + */ +#define PMS_DMA_REGION29_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xf4) +/** PMS_DMA_REGION29_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region29. + */ +#define PMS_DMA_REGION29_HIGH 0x000FFFFFU +#define PMS_DMA_REGION29_HIGH_M (PMS_DMA_REGION29_HIGH_V << PMS_DMA_REGION29_HIGH_S) +#define PMS_DMA_REGION29_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION29_HIGH_S 12 + +/** PMS_DMA_REGION30_LOW_REG register + * Region30 start address configuration register + */ +#define PMS_DMA_REGION30_LOW_REG (DR_REG_PMS_DMA_BASE + 0xf8) +/** PMS_DMA_REGION30_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region30. + */ +#define PMS_DMA_REGION30_LOW 0x000FFFFFU +#define PMS_DMA_REGION30_LOW_M (PMS_DMA_REGION30_LOW_V << PMS_DMA_REGION30_LOW_S) +#define PMS_DMA_REGION30_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION30_LOW_S 12 + +/** PMS_DMA_REGION30_HIGH_REG register + * Region30 end address configuration register + */ +#define PMS_DMA_REGION30_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xfc) +/** PMS_DMA_REGION30_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region30. + */ +#define PMS_DMA_REGION30_HIGH 0x000FFFFFU +#define PMS_DMA_REGION30_HIGH_M (PMS_DMA_REGION30_HIGH_V << PMS_DMA_REGION30_HIGH_S) +#define PMS_DMA_REGION30_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION30_HIGH_S 12 + +/** PMS_DMA_REGION31_LOW_REG register + * Region31 start address configuration register + */ +#define PMS_DMA_REGION31_LOW_REG (DR_REG_PMS_DMA_BASE + 0x100) +/** PMS_DMA_REGION31_LOW : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for region31. + */ +#define PMS_DMA_REGION31_LOW 0x000FFFFFU +#define PMS_DMA_REGION31_LOW_M (PMS_DMA_REGION31_LOW_V << PMS_DMA_REGION31_LOW_S) +#define PMS_DMA_REGION31_LOW_V 0x000FFFFFU +#define PMS_DMA_REGION31_LOW_S 12 + +/** PMS_DMA_REGION31_HIGH_REG register + * Region31 end address configuration register + */ +#define PMS_DMA_REGION31_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x104) +/** PMS_DMA_REGION31_HIGH : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for region31. + */ +#define PMS_DMA_REGION31_HIGH 0x000FFFFFU +#define PMS_DMA_REGION31_HIGH_M (PMS_DMA_REGION31_HIGH_V << PMS_DMA_REGION31_HIGH_S) +#define PMS_DMA_REGION31_HIGH_V 0x000FFFFFU +#define PMS_DMA_REGION31_HIGH_S 12 + +/** PMS_DMA_GDMA_CH0_R_PMS_REG register + * GDMA ch0 read permission control register + */ +#define PMS_DMA_GDMA_CH0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x108) +/** PMS_DMA_GDMA_CH0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch0 to read 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_GDMA_CH0_R_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH0_R_PMS_M (PMS_DMA_GDMA_CH0_R_PMS_V << PMS_DMA_GDMA_CH0_R_PMS_S) +#define PMS_DMA_GDMA_CH0_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH0_R_PMS_S 0 + +/** PMS_DMA_GDMA_CH0_W_PMS_REG register + * GDMA ch0 write permission control register + */ +#define PMS_DMA_GDMA_CH0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x10c) +/** PMS_DMA_GDMA_CH0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch0 to write 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_GDMA_CH0_W_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH0_W_PMS_M (PMS_DMA_GDMA_CH0_W_PMS_V << PMS_DMA_GDMA_CH0_W_PMS_S) +#define PMS_DMA_GDMA_CH0_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH0_W_PMS_S 0 + +/** PMS_DMA_GDMA_CH1_R_PMS_REG register + * GDMA ch1 read permission control register + */ +#define PMS_DMA_GDMA_CH1_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x110) +/** PMS_DMA_GDMA_CH1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch1 to read 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_GDMA_CH1_R_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH1_R_PMS_M (PMS_DMA_GDMA_CH1_R_PMS_V << PMS_DMA_GDMA_CH1_R_PMS_S) +#define PMS_DMA_GDMA_CH1_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH1_R_PMS_S 0 + +/** PMS_DMA_GDMA_CH1_W_PMS_REG register + * GDMA ch1 write permission control register + */ +#define PMS_DMA_GDMA_CH1_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x114) +/** PMS_DMA_GDMA_CH1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch1 to write 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_GDMA_CH1_W_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH1_W_PMS_M (PMS_DMA_GDMA_CH1_W_PMS_V << PMS_DMA_GDMA_CH1_W_PMS_S) +#define PMS_DMA_GDMA_CH1_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH1_W_PMS_S 0 + +/** PMS_DMA_GDMA_CH2_R_PMS_REG register + * GDMA ch2 read permission control register + */ +#define PMS_DMA_GDMA_CH2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x118) +/** PMS_DMA_GDMA_CH2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch2 to read 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_GDMA_CH2_R_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH2_R_PMS_M (PMS_DMA_GDMA_CH2_R_PMS_V << PMS_DMA_GDMA_CH2_R_PMS_S) +#define PMS_DMA_GDMA_CH2_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH2_R_PMS_S 0 + +/** PMS_DMA_GDMA_CH2_W_PMS_REG register + * GDMA ch2 write permission control register + */ +#define PMS_DMA_GDMA_CH2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x11c) +/** PMS_DMA_GDMA_CH2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch2 to write 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_GDMA_CH2_W_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH2_W_PMS_M (PMS_DMA_GDMA_CH2_W_PMS_V << PMS_DMA_GDMA_CH2_W_PMS_S) +#define PMS_DMA_GDMA_CH2_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH2_W_PMS_S 0 + +/** PMS_DMA_GDMA_CH3_R_PMS_REG register + * GDMA ch3 read permission control register + */ +#define PMS_DMA_GDMA_CH3_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x120) +/** PMS_DMA_GDMA_CH3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch3 to read 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_GDMA_CH3_R_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH3_R_PMS_M (PMS_DMA_GDMA_CH3_R_PMS_V << PMS_DMA_GDMA_CH3_R_PMS_S) +#define PMS_DMA_GDMA_CH3_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH3_R_PMS_S 0 + +/** PMS_DMA_GDMA_CH3_W_PMS_REG register + * GDMA ch3 write permission control register + */ +#define PMS_DMA_GDMA_CH3_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x124) +/** PMS_DMA_GDMA_CH3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA ch3 to write 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_GDMA_CH3_W_PMS 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH3_W_PMS_M (PMS_DMA_GDMA_CH3_W_PMS_V << PMS_DMA_GDMA_CH3_W_PMS_S) +#define PMS_DMA_GDMA_CH3_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GDMA_CH3_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_ADC_R_PMS_REG register + * GDMA-AHB ADC read permission control register + */ +#define PMS_DMA_AHB_PDMA_ADC_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x128) +/** PMS_DMA_AHB_PDMA_ADC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by ADC. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_ADC_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_ADC_R_PMS_M (PMS_DMA_AHB_PDMA_ADC_R_PMS_V << PMS_DMA_AHB_PDMA_ADC_R_PMS_S) +#define PMS_DMA_AHB_PDMA_ADC_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_ADC_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_ADC_W_PMS_REG register + * GDMA-AHB ADC write permission control register + */ +#define PMS_DMA_AHB_PDMA_ADC_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x12c) +/** PMS_DMA_AHB_PDMA_ADC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by ADC. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_ADC_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_ADC_W_PMS_M (PMS_DMA_AHB_PDMA_ADC_W_PMS_V << PMS_DMA_AHB_PDMA_ADC_W_PMS_S) +#define PMS_DMA_AHB_PDMA_ADC_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_ADC_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S0_R_PMS_REG register + * GDMA-AHB I2S0 read permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x130) +/** PMS_DMA_AHB_PDMA_I2S0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S0. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_M (PMS_DMA_AHB_PDMA_I2S0_R_PMS_V << PMS_DMA_AHB_PDMA_I2S0_R_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S0_W_PMS_REG register + * GDMA-AHB I2S0 write permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x134) +/** PMS_DMA_AHB_PDMA_I2S0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S0. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_M (PMS_DMA_AHB_PDMA_I2S0_W_PMS_V << PMS_DMA_AHB_PDMA_I2S0_W_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S1_R_PMS_REG register + * GDMA-AHB I2S1 read permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x138) +/** PMS_DMA_AHB_PDMA_I2S1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S1. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_M (PMS_DMA_AHB_PDMA_I2S1_R_PMS_V << PMS_DMA_AHB_PDMA_I2S1_R_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S1_W_PMS_REG register + * GDMA-AHB I2S1 write permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x13c) +/** PMS_DMA_AHB_PDMA_I2S1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S1. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_M (PMS_DMA_AHB_PDMA_I2S1_W_PMS_V << PMS_DMA_AHB_PDMA_I2S1_W_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S2_R_PMS_REG register + * GDMA-AHB I2S2 read permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x140) +/** PMS_DMA_AHB_PDMA_I2S2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S2. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_M (PMS_DMA_AHB_PDMA_I2S2_R_PMS_V << PMS_DMA_AHB_PDMA_I2S2_R_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I2S2_W_PMS_REG register + * GDMA-AHB I2S2 write permission control register + */ +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x144) +/** PMS_DMA_AHB_PDMA_I2S2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S2. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_M (PMS_DMA_AHB_PDMA_I2S2_W_PMS_V << PMS_DMA_AHB_PDMA_I2S2_W_PMS_S) +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_REG register + * GDMA-AHB I3C MST read permission control register + */ +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x148) +/** PMS_DMA_AHB_PDMA_I3C_MST_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by I3C master. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_M (PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_V << PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_S) +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_REG register + * GDMA-AHB I3C MST write permission control register + */ +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x14c) +/** PMS_DMA_AHB_PDMA_I3C_MST_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by I3C master. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_M (PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_V << PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_S) +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_UHCI0_R_PMS_REG register + * GDMA-AHB UHCI read permission control register + */ +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x150) +/** PMS_DMA_AHB_PDMA_UHCI0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by UHCI. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_M (PMS_DMA_AHB_PDMA_UHCI0_R_PMS_V << PMS_DMA_AHB_PDMA_UHCI0_R_PMS_S) +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_UHCI0_W_PMS_REG register + * GDMA-AHB UHCI write permission control register + */ +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x154) +/** PMS_DMA_AHB_PDMA_UHCI0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by UHCI. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_M (PMS_DMA_AHB_PDMA_UHCI0_W_PMS_V << PMS_DMA_AHB_PDMA_UHCI0_W_PMS_S) +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_RMT_R_PMS_REG register + * GDMA-AHB RMT read permission control register + */ +#define PMS_DMA_AHB_PDMA_RMT_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x158) +/** PMS_DMA_AHB_PDMA_RMT_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by RMT. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_RMT_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_RMT_R_PMS_M (PMS_DMA_AHB_PDMA_RMT_R_PMS_V << PMS_DMA_AHB_PDMA_RMT_R_PMS_S) +#define PMS_DMA_AHB_PDMA_RMT_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_RMT_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_RMT_W_PMS_REG register + * GDMA-AHB RMT write permission control register + */ +#define PMS_DMA_AHB_PDMA_RMT_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x170) +/** PMS_DMA_AHB_PDMA_RMT_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by RMT. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_RMT_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_RMT_W_PMS_M (PMS_DMA_AHB_PDMA_RMT_W_PMS_V << PMS_DMA_AHB_PDMA_RMT_W_PMS_S) +#define PMS_DMA_AHB_PDMA_RMT_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_RMT_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_REG register + * GDMA-AXI LCD_CAM read permission control register + */ +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x174) +/** PMS_DMA_AXI_PDMA_LCDCAM_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by LCD_CAM. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_M (PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_V << PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_S) +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_REG register + * GDMA-AXI LCD_CAM write permission control register + */ +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x178) +/** PMS_DMA_AXI_PDMA_LCDCAM_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by LCD_CAM. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_M (PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_V << PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_S) +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_REG register + * GDMA-AXI GPSPI2 read permission control register + */ +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x17c) +/** PMS_DMA_AXI_PDMA_GPSPI2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI2. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_M (PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_V << PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_S) +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_REG register + * GDMA-AXI GPSPI2 write permission control register + */ +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x180) +/** PMS_DMA_AXI_PDMA_GPSPI2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI2. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_M (PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_V << PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_S) +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_REG register + * GDMA-AXI GPSPI3 read permission control register + */ +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x184) +/** PMS_DMA_AXI_PDMA_GPSPI3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI3. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_M (PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_V << PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_S) +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_REG register + * AXI PDMA GPSPI3 write permission control register + */ +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x188) +/** PMS_DMA_AXI_PDMA_GPSPI3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI3. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_M (PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_V << PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_S) +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_PARLIO_R_PMS_REG register + * GDMA-AXI PARLIO read permission control register + */ +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x18c) +/** PMS_DMA_AXI_PDMA_PARLIO_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by PARLIO + * (Parallel IO Controller). Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_M (PMS_DMA_AXI_PDMA_PARLIO_R_PMS_V << PMS_DMA_AXI_PDMA_PARLIO_R_PMS_S) +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_PARLIO_W_PMS_REG register + * GDMA-AXI PARLIO write permission control register + */ +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x190) +/** PMS_DMA_AXI_PDMA_PARLIO_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by PARLIO. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_M (PMS_DMA_AXI_PDMA_PARLIO_W_PMS_V << PMS_DMA_AXI_PDMA_PARLIO_W_PMS_S) +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_AES_R_PMS_REG register + * GDMA-AXI AES read permission control register + */ +#define PMS_DMA_AXI_PDMA_AES_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x194) +/** PMS_DMA_AXI_PDMA_AES_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by AES. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_AES_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_AES_R_PMS_M (PMS_DMA_AXI_PDMA_AES_R_PMS_V << PMS_DMA_AXI_PDMA_AES_R_PMS_S) +#define PMS_DMA_AXI_PDMA_AES_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_AES_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_AES_W_PMS_REG register + * GDMA-AXI AES write permission control register + */ +#define PMS_DMA_AXI_PDMA_AES_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x198) +/** PMS_DMA_AXI_PDMA_AES_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by AES. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_AES_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_AES_W_PMS_M (PMS_DMA_AXI_PDMA_AES_W_PMS_V << PMS_DMA_AXI_PDMA_AES_W_PMS_S) +#define PMS_DMA_AXI_PDMA_AES_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_AES_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_SHA_R_PMS_REG register + * GDMA-AXI SHA read permission control register + */ +#define PMS_DMA_AXI_PDMA_SHA_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x19c) +/** PMS_DMA_AXI_PDMA_SHA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by SHA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_SHA_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_SHA_R_PMS_M (PMS_DMA_AXI_PDMA_SHA_R_PMS_V << PMS_DMA_AXI_PDMA_SHA_R_PMS_S) +#define PMS_DMA_AXI_PDMA_SHA_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_SHA_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_SHA_W_PMS_REG register + * GDMA-AXI SHA write permission control register + */ +#define PMS_DMA_AXI_PDMA_SHA_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x1a0) +/** PMS_DMA_AXI_PDMA_SHA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by SHA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_SHA_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_SHA_W_PMS_M (PMS_DMA_AXI_PDMA_SHA_W_PMS_V << PMS_DMA_AXI_PDMA_SHA_W_PMS_S) +#define PMS_DMA_AXI_PDMA_SHA_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_SHA_W_PMS_S 0 + +/** PMS_DMA_DMA2D_JPEG_PMS_R_REG register + * 2D-DMA JPEG read permission control register + */ +#define PMS_DMA_DMA2D_JPEG_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1a4) +/** PMS_DMA_DMA2D_JPEG_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to read 32 address ranges requested by JPEG. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_DMA2D_JPEG_R_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_JPEG_R_PMS_M (PMS_DMA_DMA2D_JPEG_R_PMS_V << PMS_DMA_DMA2D_JPEG_R_PMS_S) +#define PMS_DMA_DMA2D_JPEG_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_JPEG_R_PMS_S 0 + +/** PMS_DMA_DMA2D_JPEG_PMS_W_REG register + * 2D-DMA JPEG write permission control register + */ +#define PMS_DMA_DMA2D_JPEG_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1a8) +/** PMS_DMA_DMA2D_JPEG_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to write 32 address ranges requested by JPEG. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_DMA2D_JPEG_W_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_JPEG_W_PMS_M (PMS_DMA_DMA2D_JPEG_W_PMS_V << PMS_DMA_DMA2D_JPEG_W_PMS_S) +#define PMS_DMA_DMA2D_JPEG_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_JPEG_W_PMS_S 0 + +/** PMS_DMA_USB_PMS_R_REG register + * High-speed USB 2.0 OTG read permission control register + */ +#define PMS_DMA_USB_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1ac) +/** PMS_DMA_USB_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for high-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_USB_R_PMS 0xFFFFFFFFU +#define PMS_DMA_USB_R_PMS_M (PMS_DMA_USB_R_PMS_V << PMS_DMA_USB_R_PMS_S) +#define PMS_DMA_USB_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_USB_R_PMS_S 0 + +/** PMS_DMA_USB_PMS_W_REG register + * High-speed USB 2.0 OTG write permission control register + */ +#define PMS_DMA_USB_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1b0) +/** PMS_DMA_USB_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for high-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_USB_W_PMS 0xFFFFFFFFU +#define PMS_DMA_USB_W_PMS_M (PMS_DMA_USB_W_PMS_V << PMS_DMA_USB_W_PMS_S) +#define PMS_DMA_USB_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_USB_W_PMS_S 0 + +/** PMS_DMA_GMAC_PMS_R_REG register + * EMAC read permission control register + */ +#define PMS_DMA_GMAC_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1b4) +/** PMS_DMA_GMAC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for EMAC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_GMAC_R_PMS 0xFFFFFFFFU +#define PMS_DMA_GMAC_R_PMS_M (PMS_DMA_GMAC_R_PMS_V << PMS_DMA_GMAC_R_PMS_S) +#define PMS_DMA_GMAC_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GMAC_R_PMS_S 0 + +/** PMS_DMA_GMAC_PMS_W_REG register + * EMAC write permission control register + */ +#define PMS_DMA_GMAC_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1b8) +/** PMS_DMA_GMAC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for EMAC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_GMAC_W_PMS 0xFFFFFFFFU +#define PMS_DMA_GMAC_W_PMS_M (PMS_DMA_GMAC_W_PMS_V << PMS_DMA_GMAC_W_PMS_S) +#define PMS_DMA_GMAC_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_GMAC_W_PMS_S 0 + +/** PMS_DMA_SDMMC_PMS_R_REG register + * SDMMC read permission control register + */ +#define PMS_DMA_SDMMC_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1bc) +/** PMS_DMA_SDMMC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for SDMMC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_SDMMC_R_PMS 0xFFFFFFFFU +#define PMS_DMA_SDMMC_R_PMS_M (PMS_DMA_SDMMC_R_PMS_V << PMS_DMA_SDMMC_R_PMS_S) +#define PMS_DMA_SDMMC_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_SDMMC_R_PMS_S 0 + +/** PMS_DMA_SDMMC_PMS_W_REG register + * SDMMC write permission control register + */ +#define PMS_DMA_SDMMC_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1c0) +/** PMS_DMA_SDMMC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for SDMMC to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_SDMMC_W_PMS 0xFFFFFFFFU +#define PMS_DMA_SDMMC_W_PMS_M (PMS_DMA_SDMMC_W_PMS_V << PMS_DMA_SDMMC_W_PMS_S) +#define PMS_DMA_SDMMC_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_SDMMC_W_PMS_S 0 + +/** PMS_DMA_USBOTG11_PMS_R_REG register + * Full-speed USB 2.0 OTG full-speed read permission control register + */ +#define PMS_DMA_USBOTG11_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1c4) +/** PMS_DMA_USBOTG11_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for full-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_USBOTG11_R_PMS 0xFFFFFFFFU +#define PMS_DMA_USBOTG11_R_PMS_M (PMS_DMA_USBOTG11_R_PMS_V << PMS_DMA_USBOTG11_R_PMS_S) +#define PMS_DMA_USBOTG11_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_USBOTG11_R_PMS_S 0 + +/** PMS_DMA_USBOTG11_PMS_W_REG register + * Full-speed USB 2.0 OTG full-speed write permission control register + */ +#define PMS_DMA_USBOTG11_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1c8) +/** PMS_DMA_USBOTG11_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for full-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_USBOTG11_W_PMS 0xFFFFFFFFU +#define PMS_DMA_USBOTG11_W_PMS_M (PMS_DMA_USBOTG11_W_PMS_V << PMS_DMA_USBOTG11_W_PMS_S) +#define PMS_DMA_USBOTG11_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_USBOTG11_W_PMS_S 0 + +/** PMS_DMA_TRACE0_PMS_R_REG register + * TRACE0 read permission control register + */ +#define PMS_DMA_TRACE0_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1cc) +/** PMS_DMA_TRACE0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for TRACE0 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_TRACE0_R_PMS 0xFFFFFFFFU +#define PMS_DMA_TRACE0_R_PMS_M (PMS_DMA_TRACE0_R_PMS_V << PMS_DMA_TRACE0_R_PMS_S) +#define PMS_DMA_TRACE0_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TRACE0_R_PMS_S 0 + +/** PMS_DMA_TRACE0_PMS_W_REG register + * TRACE0 write permission control register + */ +#define PMS_DMA_TRACE0_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1d0) +/** PMS_DMA_TRACE0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for TRACE0 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_TRACE0_W_PMS 0xFFFFFFFFU +#define PMS_DMA_TRACE0_W_PMS_M (PMS_DMA_TRACE0_W_PMS_V << PMS_DMA_TRACE0_W_PMS_S) +#define PMS_DMA_TRACE0_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TRACE0_W_PMS_S 0 + +/** PMS_DMA_TRACE1_PMS_R_REG register + * TRACE1 read permission control register + */ +#define PMS_DMA_TRACE1_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1d4) +/** PMS_DMA_TRACE1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for TRACE1 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_TRACE1_R_PMS 0xFFFFFFFFU +#define PMS_DMA_TRACE1_R_PMS_M (PMS_DMA_TRACE1_R_PMS_V << PMS_DMA_TRACE1_R_PMS_S) +#define PMS_DMA_TRACE1_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TRACE1_R_PMS_S 0 + +/** PMS_DMA_TRACE1_PMS_W_REG register + * TRACE1 write permission control register + */ +#define PMS_DMA_TRACE1_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1d8) +/** PMS_DMA_TRACE1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for TRACE1 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_TRACE1_W_PMS 0xFFFFFFFFU +#define PMS_DMA_TRACE1_W_PMS_M (PMS_DMA_TRACE1_W_PMS_V << PMS_DMA_TRACE1_W_PMS_S) +#define PMS_DMA_TRACE1_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TRACE1_W_PMS_S 0 + +/** PMS_DMA_L2MEM_MON_PMS_R_REG register + * L2MEM Monitor read permission control register + */ +#define PMS_DMA_L2MEM_MON_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1dc) +/** PMS_DMA_L2MEM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for L2MEM MON. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_L2MEM_MON_R_PMS 0xFFFFFFFFU +#define PMS_DMA_L2MEM_MON_R_PMS_M (PMS_DMA_L2MEM_MON_R_PMS_V << PMS_DMA_L2MEM_MON_R_PMS_S) +#define PMS_DMA_L2MEM_MON_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_L2MEM_MON_R_PMS_S 0 + +/** PMS_DMA_L2MEM_MON_PMS_W_REG register + * L2MEM Monitor write permission control register + */ +#define PMS_DMA_L2MEM_MON_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1e0) +/** PMS_DMA_L2MEM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for L2MEM monitor to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_L2MEM_MON_W_PMS 0xFFFFFFFFU +#define PMS_DMA_L2MEM_MON_W_PMS_M (PMS_DMA_L2MEM_MON_W_PMS_V << PMS_DMA_L2MEM_MON_W_PMS_S) +#define PMS_DMA_L2MEM_MON_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_L2MEM_MON_W_PMS_S 0 + +/** PMS_DMA_TCM_MON_PMS_R_REG register + * TCM Monitor read permission control register + */ +#define PMS_DMA_TCM_MON_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1e4) +/** PMS_DMA_TCM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for TCM MON. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_TCM_MON_R_PMS 0xFFFFFFFFU +#define PMS_DMA_TCM_MON_R_PMS_M (PMS_DMA_TCM_MON_R_PMS_V << PMS_DMA_TCM_MON_R_PMS_S) +#define PMS_DMA_TCM_MON_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TCM_MON_R_PMS_S 0 + +/** PMS_DMA_TCM_MON_PMS_W_REG register + * TCM Monitor write permission control register + */ +#define PMS_DMA_TCM_MON_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1e8) +/** PMS_DMA_TCM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for TCM monitor to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_TCM_MON_W_PMS 0xFFFFFFFFU +#define PMS_DMA_TCM_MON_W_PMS_M (PMS_DMA_TCM_MON_W_PMS_V << PMS_DMA_TCM_MON_W_PMS_S) +#define PMS_DMA_TCM_MON_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_TCM_MON_W_PMS_S 0 + +/** PMS_DMA_REGDMA_PMS_R_REG register + * REGDMA read permission control register + */ +#define PMS_DMA_REGDMA_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1ec) +/** PMS_DMA_REGDMA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for REGDMA. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_REGDMA_R_PMS 0xFFFFFFFFU +#define PMS_DMA_REGDMA_R_PMS_M (PMS_DMA_REGDMA_R_PMS_V << PMS_DMA_REGDMA_R_PMS_S) +#define PMS_DMA_REGDMA_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_REGDMA_R_PMS_S 0 + +/** PMS_DMA_REGDMA_PMS_W_REG register + * REGDMA write permission control register + */ +#define PMS_DMA_REGDMA_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1f0) +/** PMS_DMA_REGDMA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for REGDMA. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_REGDMA_W_PMS 0xFFFFFFFFU +#define PMS_DMA_REGDMA_W_PMS_M (PMS_DMA_REGDMA_W_PMS_V << PMS_DMA_REGDMA_W_PMS_S) +#define PMS_DMA_REGDMA_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_REGDMA_W_PMS_S 0 + +/** PMS_DMA_H264_PMS_R_REG register + * H264 DMA read permission control register + */ +#define PMS_DMA_H264_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1fc) +/** PMS_DMA_H264_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures read permission for H264 DMA to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_H264_R_PMS 0xFFFFFFFFU +#define PMS_DMA_H264_R_PMS_M (PMS_DMA_H264_R_PMS_V << PMS_DMA_H264_R_PMS_S) +#define PMS_DMA_H264_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_H264_R_PMS_S 0 + +/** PMS_DMA_H264_PMS_W_REG register + * H264 DMA write permission control register + */ +#define PMS_DMA_H264_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x200) +/** PMS_DMA_H264_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures write permission for H264 DMA to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_H264_W_PMS 0xFFFFFFFFU +#define PMS_DMA_H264_W_PMS_M (PMS_DMA_H264_W_PMS_V << PMS_DMA_H264_W_PMS_S) +#define PMS_DMA_H264_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_H264_W_PMS_S 0 + +/** PMS_DMA_DMA2D_PPA_PMS_R_REG register + * 2D-DMA PPA read permission control register + */ +#define PMS_DMA_DMA2D_PPA_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x204) +/** PMS_DMA_DMA2D_PPA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to read 32 address ranges requested by PPA + * (Pixel-Processing Accelerator). Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_DMA2D_PPA_R_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_PPA_R_PMS_M (PMS_DMA_DMA2D_PPA_R_PMS_V << PMS_DMA_DMA2D_PPA_R_PMS_S) +#define PMS_DMA_DMA2D_PPA_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_PPA_R_PMS_S 0 + +/** PMS_DMA_DMA2D_PPA_PMS_W_REG register + * 2D-DMA PPA write permission control register + */ +#define PMS_DMA_DMA2D_PPA_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x208) +/** PMS_DMA_DMA2D_PPA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to write 32 address ranges requested by PPA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_DMA2D_PPA_W_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_PPA_W_PMS_M (PMS_DMA_DMA2D_PPA_W_PMS_V << PMS_DMA_DMA2D_PPA_W_PMS_S) +#define PMS_DMA_DMA2D_PPA_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_PPA_W_PMS_S 0 + +/** PMS_DMA_DMA2D_DUMMY_PMS_R_REG register + * 2D-DMA dummy read permission control register + */ +#define PMS_DMA_DMA2D_DUMMY_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x20c) +/** PMS_DMA_DMA2D_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_DMA2D_DUMMY_R_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_DUMMY_R_PMS_M (PMS_DMA_DMA2D_DUMMY_R_PMS_V << PMS_DMA_DMA2D_DUMMY_R_PMS_S) +#define PMS_DMA_DMA2D_DUMMY_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_DUMMY_R_PMS_S 0 + +/** PMS_DMA_DMA2D_DUMMY_PMS_W_REG register + * 2D-DMA dummy write permission control register + */ +#define PMS_DMA_DMA2D_DUMMY_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x210) +/** PMS_DMA_DMA2D_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures 2D-DMA permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_DMA2D_DUMMY_W_PMS 0xFFFFFFFFU +#define PMS_DMA_DMA2D_DUMMY_W_PMS_M (PMS_DMA_DMA2D_DUMMY_W_PMS_V << PMS_DMA_DMA2D_DUMMY_W_PMS_S) +#define PMS_DMA_DMA2D_DUMMY_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_DMA2D_DUMMY_W_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_DUMMY_R_PMS_REG register + * GDMA-AHB dummy read permission control register + */ +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x214) +/** PMS_DMA_AHB_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_M (PMS_DMA_AHB_PDMA_DUMMY_R_PMS_V << PMS_DMA_AHB_PDMA_DUMMY_R_PMS_S) +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_S 0 + +/** PMS_DMA_AHB_PDMA_DUMMY_W_PMS_REG register + * GDMA-AHB dummy write permission control register + */ +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x218) +/** PMS_DMA_AHB_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AHB permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_M (PMS_DMA_AHB_PDMA_DUMMY_W_PMS_V << PMS_DMA_AHB_PDMA_DUMMY_W_PMS_S) +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_DUMMY_R_PMS_REG register + * GDMA-AXI dummy read permission control register + */ +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x21c) +/** PMS_DMA_AXI_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. + */ +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_M (PMS_DMA_AXI_PDMA_DUMMY_R_PMS_V << PMS_DMA_AXI_PDMA_DUMMY_R_PMS_S) +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_S 0 + +/** PMS_DMA_AXI_PDMA_DUMMY_W_PMS_REG register + * GDMA-AXI dummy write permission control register + */ +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x220) +/** PMS_DMA_AXI_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; + * Configures GDMA-AXI permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. + */ +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_M (PMS_DMA_AXI_PDMA_DUMMY_W_PMS_V << PMS_DMA_AXI_PDMA_DUMMY_W_PMS_S) +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_V 0xFFFFFFFFU +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_S 0 #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/dma_pms_struct.h b/components/soc/esp32p4/include/soc/dma_pms_struct.h index 6ee07a7f39b..2d166207afd 100644 --- a/components/soc/esp32p4/include/soc/dma_pms_struct.h +++ b/components/soc/esp32p4/include/soc/dma_pms_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,1907 +10,1138 @@ extern "C" { #endif -/** Group: Tee version register. */ +/** Group: Version Control Registers */ /** Type of date register - * NA + * Version control register */ typedef union { struct { - /** tee_date : R/W; bitpos: [31:0]; default: 539165460; - * NA + /** date : R/W; bitpos: [31:0]; default: 539165460; + * Version control register. */ - uint32_t tee_date:32; + uint32_t date:32; }; uint32_t val; -} tee_date_reg_t; +} pms_dma_date_reg_t; -/** Group: Tee regbank clock gating control register. */ +/** Group: Clock Gating Registers */ /** Type of clk_en register - * NA + * Clock gating register */ typedef union { struct { /** clk_en : R/W; bitpos: [0]; default: 1; - * NA + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating. + * 1: Keep the clock always on. */ uint32_t clk_en:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_clk_en_reg_t; +} pms_dma_clk_en_reg_t; -/** Group: Tee region configuration registers. */ -/** Type of region0_low register - * Region0 address low register. +/** Group: Region Configuration Registers */ +/** Type of regionn_low register + * Regionn start address configuration register */ typedef union { struct { uint32_t reserved_0:12; - /** region0_low : R/W; bitpos: [31:12]; default: 0; - * Region0 address low. + /** regionn_low : R/W; bitpos: [31:12]; default: 0; + * Configures the high 20 bits of the start address for regionn. */ - uint32_t region0_low:20; + uint32_t regionn_low:20; }; uint32_t val; -} tee_region0_low_reg_t; +} pms_dma_regionn_low_reg_t; -/** Type of region0_high register - * Region0 address high register. +/** Type of regionn_high register + * Regionn end address configuration register */ typedef union { struct { uint32_t reserved_0:12; - /** region0_high : R/W; bitpos: [31:12]; default: 1048575; - * Region0 address high. + /** regionn_high : R/W; bitpos: [31:12]; default: 1048575; + * Configures the high 20 bits of the end address for regionn. */ - uint32_t region0_high:20; + uint32_t regionn_high:20; }; uint32_t val; -} tee_region0_high_reg_t; +} pms_dma_regionn_high_reg_t; -/** Type of region1_low register - * Region1 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region1_low : R/W; bitpos: [31:12]; default: 0; - * Region1 address low. - */ - uint32_t region1_low:20; - }; - uint32_t val; -} tee_region1_low_reg_t; - -/** Type of region1_high register - * Region1 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region1_high : R/W; bitpos: [31:12]; default: 1048575; - * Region1 address high. - */ - uint32_t region1_high:20; - }; - uint32_t val; -} tee_region1_high_reg_t; - -/** Type of region2_low register - * Region2 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region2_low : R/W; bitpos: [31:12]; default: 0; - * Region2 address low. - */ - uint32_t region2_low:20; - }; - uint32_t val; -} tee_region2_low_reg_t; - -/** Type of region2_high register - * Region2 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region2_high : R/W; bitpos: [31:12]; default: 1048575; - * Region2 address high. - */ - uint32_t region2_high:20; - }; - uint32_t val; -} tee_region2_high_reg_t; - -/** Type of region3_low register - * Region3 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region3_low : R/W; bitpos: [31:12]; default: 0; - * Region3 address low. - */ - uint32_t region3_low:20; - }; - uint32_t val; -} tee_region3_low_reg_t; - -/** Type of region3_high register - * Region3 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region3_high : R/W; bitpos: [31:12]; default: 1048575; - * Region3 address high. - */ - uint32_t region3_high:20; - }; - uint32_t val; -} tee_region3_high_reg_t; - -/** Type of region4_low register - * Region4 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region4_low : R/W; bitpos: [31:12]; default: 0; - * Region4 address low. - */ - uint32_t region4_low:20; - }; - uint32_t val; -} tee_region4_low_reg_t; - -/** Type of region4_high register - * Region4 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region4_high : R/W; bitpos: [31:12]; default: 1048575; - * Region4 address high. - */ - uint32_t region4_high:20; - }; - uint32_t val; -} tee_region4_high_reg_t; - -/** Type of region5_low register - * Region5 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region5_low : R/W; bitpos: [31:12]; default: 0; - * Region5 address low. - */ - uint32_t region5_low:20; - }; - uint32_t val; -} tee_region5_low_reg_t; - -/** Type of region5_high register - * Region5 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region5_high : R/W; bitpos: [31:12]; default: 1048575; - * Region5 address high. - */ - uint32_t region5_high:20; - }; - uint32_t val; -} tee_region5_high_reg_t; - -/** Type of region6_low register - * Region6 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region6_low : R/W; bitpos: [31:12]; default: 0; - * Region6 address low. - */ - uint32_t region6_low:20; - }; - uint32_t val; -} tee_region6_low_reg_t; - -/** Type of region6_high register - * Region6 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region6_high : R/W; bitpos: [31:12]; default: 1048575; - * Region6 address high. - */ - uint32_t region6_high:20; - }; - uint32_t val; -} tee_region6_high_reg_t; - -/** Type of region7_low register - * Region7 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region7_low : R/W; bitpos: [31:12]; default: 0; - * Region7 address low. - */ - uint32_t region7_low:20; - }; - uint32_t val; -} tee_region7_low_reg_t; - -/** Type of region7_high register - * Region7 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region7_high : R/W; bitpos: [31:12]; default: 1048575; - * Region7 address high. - */ - uint32_t region7_high:20; - }; - uint32_t val; -} tee_region7_high_reg_t; - -/** Type of region8_low register - * Region8 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region8_low : R/W; bitpos: [31:12]; default: 0; - * Region8 address low. - */ - uint32_t region8_low:20; - }; - uint32_t val; -} tee_region8_low_reg_t; - -/** Type of region8_high register - * Region8 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region8_high : R/W; bitpos: [31:12]; default: 1048575; - * Region8 address high. - */ - uint32_t region8_high:20; - }; - uint32_t val; -} tee_region8_high_reg_t; - -/** Type of region9_low register - * Region9 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region9_low : R/W; bitpos: [31:12]; default: 0; - * Region9 address low. - */ - uint32_t region9_low:20; - }; - uint32_t val; -} tee_region9_low_reg_t; - -/** Type of region9_high register - * Region9 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region9_high : R/W; bitpos: [31:12]; default: 1048575; - * Region9 address high. - */ - uint32_t region9_high:20; - }; - uint32_t val; -} tee_region9_high_reg_t; - -/** Type of region10_low register - * Region10 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region10_low : R/W; bitpos: [31:12]; default: 0; - * Region10 address low. - */ - uint32_t region10_low:20; - }; - uint32_t val; -} tee_region10_low_reg_t; - -/** Type of region10_high register - * Region10 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region10_high : R/W; bitpos: [31:12]; default: 1048575; - * Region10 address high. - */ - uint32_t region10_high:20; - }; - uint32_t val; -} tee_region10_high_reg_t; - -/** Type of region11_low register - * Region11 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region11_low : R/W; bitpos: [31:12]; default: 0; - * Region11 address low. - */ - uint32_t region11_low:20; - }; - uint32_t val; -} tee_region11_low_reg_t; - -/** Type of region11_high register - * Region11 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region11_high : R/W; bitpos: [31:12]; default: 1048575; - * Region11 address high. - */ - uint32_t region11_high:20; - }; - uint32_t val; -} tee_region11_high_reg_t; - -/** Type of region12_low register - * Region12 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region12_low : R/W; bitpos: [31:12]; default: 0; - * Region12 address low. - */ - uint32_t region12_low:20; - }; - uint32_t val; -} tee_region12_low_reg_t; - -/** Type of region12_high register - * Region12 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region12_high : R/W; bitpos: [31:12]; default: 1048575; - * Region12 address high. - */ - uint32_t region12_high:20; - }; - uint32_t val; -} tee_region12_high_reg_t; - -/** Type of region13_low register - * Region13 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region13_low : R/W; bitpos: [31:12]; default: 0; - * Region13 address low. - */ - uint32_t region13_low:20; - }; - uint32_t val; -} tee_region13_low_reg_t; - -/** Type of region13_high register - * Region13 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region13_high : R/W; bitpos: [31:12]; default: 1048575; - * Region13 address high. - */ - uint32_t region13_high:20; - }; - uint32_t val; -} tee_region13_high_reg_t; - -/** Type of region14_low register - * Region14 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region14_low : R/W; bitpos: [31:12]; default: 0; - * Region14 address low. - */ - uint32_t region14_low:20; - }; - uint32_t val; -} tee_region14_low_reg_t; - -/** Type of region14_high register - * Region14 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region14_high : R/W; bitpos: [31:12]; default: 1048575; - * Region14 address high. - */ - uint32_t region14_high:20; - }; - uint32_t val; -} tee_region14_high_reg_t; - -/** Type of region15_low register - * Region15 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region15_low : R/W; bitpos: [31:12]; default: 0; - * Region15 address low. - */ - uint32_t region15_low:20; - }; - uint32_t val; -} tee_region15_low_reg_t; - -/** Type of region15_high register - * Region15 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region15_high : R/W; bitpos: [31:12]; default: 1048575; - * Region15 address high. - */ - uint32_t region15_high:20; - }; - uint32_t val; -} tee_region15_high_reg_t; - -/** Type of region16_low register - * Region16 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region16_low : R/W; bitpos: [31:12]; default: 0; - * Region16 address low. - */ - uint32_t region16_low:20; - }; - uint32_t val; -} tee_region16_low_reg_t; - -/** Type of region16_high register - * Region16 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region16_high : R/W; bitpos: [31:12]; default: 1048575; - * Region16 address high. - */ - uint32_t region16_high:20; - }; - uint32_t val; -} tee_region16_high_reg_t; - -/** Type of region17_low register - * Region17 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region17_low : R/W; bitpos: [31:12]; default: 0; - * Region17 address low. - */ - uint32_t region17_low:20; - }; - uint32_t val; -} tee_region17_low_reg_t; - -/** Type of region17_high register - * Region17 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region17_high : R/W; bitpos: [31:12]; default: 1048575; - * Region17 address high. - */ - uint32_t region17_high:20; - }; - uint32_t val; -} tee_region17_high_reg_t; - -/** Type of region18_low register - * Region18 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region18_low : R/W; bitpos: [31:12]; default: 0; - * Region18 address low. - */ - uint32_t region18_low:20; - }; - uint32_t val; -} tee_region18_low_reg_t; - -/** Type of region18_high register - * Region18 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region18_high : R/W; bitpos: [31:12]; default: 1048575; - * Region18 address high. - */ - uint32_t region18_high:20; - }; - uint32_t val; -} tee_region18_high_reg_t; - -/** Type of region19_low register - * Region19 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region19_low : R/W; bitpos: [31:12]; default: 0; - * Region19 address low. - */ - uint32_t region19_low:20; - }; - uint32_t val; -} tee_region19_low_reg_t; - -/** Type of region19_high register - * Region19 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region19_high : R/W; bitpos: [31:12]; default: 1048575; - * Region19 address high. - */ - uint32_t region19_high:20; - }; - uint32_t val; -} tee_region19_high_reg_t; - -/** Type of region20_low register - * Region20 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region20_low : R/W; bitpos: [31:12]; default: 0; - * Region20 address low. - */ - uint32_t region20_low:20; - }; - uint32_t val; -} tee_region20_low_reg_t; - -/** Type of region20_high register - * Region20 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region20_high : R/W; bitpos: [31:12]; default: 1048575; - * Region20 address high. - */ - uint32_t region20_high:20; - }; - uint32_t val; -} tee_region20_high_reg_t; - -/** Type of region21_low register - * Region21 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region21_low : R/W; bitpos: [31:12]; default: 0; - * Region21 address low. - */ - uint32_t region21_low:20; - }; - uint32_t val; -} tee_region21_low_reg_t; - -/** Type of region21_high register - * Region21 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region21_high : R/W; bitpos: [31:12]; default: 1048575; - * Region21 address high. - */ - uint32_t region21_high:20; - }; - uint32_t val; -} tee_region21_high_reg_t; - -/** Type of region22_low register - * Region22 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region22_low : R/W; bitpos: [31:12]; default: 0; - * Region22 address low. - */ - uint32_t region22_low:20; - }; - uint32_t val; -} tee_region22_low_reg_t; - -/** Type of region22_high register - * Region22 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region22_high : R/W; bitpos: [31:12]; default: 1048575; - * Region22 address high. - */ - uint32_t region22_high:20; - }; - uint32_t val; -} tee_region22_high_reg_t; - -/** Type of region23_low register - * Region23 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region23_low : R/W; bitpos: [31:12]; default: 0; - * Region23 address low. - */ - uint32_t region23_low:20; - }; - uint32_t val; -} tee_region23_low_reg_t; - -/** Type of region23_high register - * Region23 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region23_high : R/W; bitpos: [31:12]; default: 1048575; - * Region23 address high. - */ - uint32_t region23_high:20; - }; - uint32_t val; -} tee_region23_high_reg_t; - -/** Type of region24_low register - * Region24 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region24_low : R/W; bitpos: [31:12]; default: 0; - * Region24 address low. - */ - uint32_t region24_low:20; - }; - uint32_t val; -} tee_region24_low_reg_t; - -/** Type of region24_high register - * Region24 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region24_high : R/W; bitpos: [31:12]; default: 1048575; - * Region24 address high. - */ - uint32_t region24_high:20; - }; - uint32_t val; -} tee_region24_high_reg_t; - -/** Type of region25_low register - * Region25 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region25_low : R/W; bitpos: [31:12]; default: 0; - * Region25 address low. - */ - uint32_t region25_low:20; - }; - uint32_t val; -} tee_region25_low_reg_t; - -/** Type of region25_high register - * Region25 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region25_high : R/W; bitpos: [31:12]; default: 1048575; - * Region25 address high. - */ - uint32_t region25_high:20; - }; - uint32_t val; -} tee_region25_high_reg_t; - -/** Type of region26_low register - * Region26 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region26_low : R/W; bitpos: [31:12]; default: 0; - * Region26 address low. - */ - uint32_t region26_low:20; - }; - uint32_t val; -} tee_region26_low_reg_t; - -/** Type of region26_high register - * Region26 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region26_high : R/W; bitpos: [31:12]; default: 1048575; - * Region26 address high. - */ - uint32_t region26_high:20; - }; - uint32_t val; -} tee_region26_high_reg_t; - -/** Type of region27_low register - * Region27 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region27_low : R/W; bitpos: [31:12]; default: 0; - * Region27 address low. - */ - uint32_t region27_low:20; - }; - uint32_t val; -} tee_region27_low_reg_t; - -/** Type of region27_high register - * Region27 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region27_high : R/W; bitpos: [31:12]; default: 1048575; - * Region27 address high. - */ - uint32_t region27_high:20; - }; - uint32_t val; -} tee_region27_high_reg_t; - -/** Type of region28_low register - * Region28 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region28_low : R/W; bitpos: [31:12]; default: 0; - * Region28 address low. - */ - uint32_t region28_low:20; - }; - uint32_t val; -} tee_region28_low_reg_t; - -/** Type of region28_high register - * Region28 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region28_high : R/W; bitpos: [31:12]; default: 1048575; - * Region28 address high. - */ - uint32_t region28_high:20; - }; - uint32_t val; -} tee_region28_high_reg_t; - -/** Type of region29_low register - * Region29 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region29_low : R/W; bitpos: [31:12]; default: 0; - * Region29 address low. - */ - uint32_t region29_low:20; - }; - uint32_t val; -} tee_region29_low_reg_t; - -/** Type of region29_high register - * Region29 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region29_high : R/W; bitpos: [31:12]; default: 1048575; - * Region29 address high. - */ - uint32_t region29_high:20; - }; - uint32_t val; -} tee_region29_high_reg_t; - -/** Type of region30_low register - * Region30 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region30_low : R/W; bitpos: [31:12]; default: 0; - * Region30 address low. - */ - uint32_t region30_low:20; - }; - uint32_t val; -} tee_region30_low_reg_t; - -/** Type of region30_high register - * Region30 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region30_high : R/W; bitpos: [31:12]; default: 1048575; - * Region30 address high. - */ - uint32_t region30_high:20; - }; - uint32_t val; -} tee_region30_high_reg_t; - -/** Type of region31_low register - * Region31 address low register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region31_low : R/W; bitpos: [31:12]; default: 0; - * Region31 address low. - */ - uint32_t region31_low:20; - }; - uint32_t val; -} tee_region31_low_reg_t; - -/** Type of region31_high register - * Region31 address high register. - */ -typedef union { - struct { - uint32_t reserved_0:12; - /** region31_high : R/W; bitpos: [31:12]; default: 1048575; - * Region31 address high. - */ - uint32_t region31_high:20; - }; - uint32_t val; -} tee_region31_high_reg_t; - - -/** Group: Tee permission control registers. */ -/** Type of gmda_ch0_r_pms register - * GDMA ch0 read permission control registers. - */ -typedef union { - struct { - /** gdma_ch0_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch0 read permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch0_r_pms:32; - }; - uint32_t val; -} tee_gmda_ch0_r_pms_reg_t; - -/** Type of gmda_ch0_w_pms register - * GDMA ch0 write permission control registers. - */ -typedef union { - struct { - /** gdma_ch0_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch0 write permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch0_w_pms:32; - }; - uint32_t val; -} tee_gmda_ch0_w_pms_reg_t; - -/** Type of gmda_ch1_r_pms register - * GDMA ch1 read permission control registers. - */ -typedef union { - struct { - /** gdma_ch1_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch1 read permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch1_r_pms:32; - }; - uint32_t val; -} tee_gmda_ch1_r_pms_reg_t; - -/** Type of gmda_ch1_w_pms register - * GDMA ch1 write permission control registers. - */ -typedef union { - struct { - /** gdma_ch1_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch1 write permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch1_w_pms:32; - }; - uint32_t val; -} tee_gmda_ch1_w_pms_reg_t; - -/** Type of gmda_ch2_r_pms register - * GDMA ch2 read permission control registers. - */ -typedef union { - struct { - /** gdma_ch2_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch2 read permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch2_r_pms:32; - }; - uint32_t val; -} tee_gmda_ch2_r_pms_reg_t; -/** Type of gmda_ch2_w_pms register - * GDMA ch2 write permission control registers. +/** Group: DMA Masters Read and Write Permission Control Registers */ +/** Type of gdma_chn_r_pms register + * GDMA chn read permission control register */ typedef union { struct { - /** gdma_ch2_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch2 write permission control, each bit corresponds to a region. + /** gdma_chn_r_pms : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA chn to read 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ - uint32_t gdma_ch2_w_pms:32; + uint32_t gdma_chn_r_pms:32; }; uint32_t val; -} tee_gmda_ch2_w_pms_reg_t; +} pms_dma_gdma_chn_r_pms_reg_t; -/** Type of gmda_ch3_r_pms register - * GDMA ch3 read permission control registers. +/** Type of gdma_chn_w_pms register + * GDMA chn write permission control register */ typedef union { struct { - /** gdma_ch3_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch3 read permission control, each bit corresponds to a region. + /** gdma_chn_w_pms : R/W; bitpos: [31:0]; default: 4294967295; + * Configures the permission for GDMA chn to write 32 address regions. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ - uint32_t gdma_ch3_r_pms:32; + uint32_t gdma_chn_w_pms:32; }; uint32_t val; -} tee_gmda_ch3_r_pms_reg_t; - -/** Type of gmda_ch3_w_pms register - * GDMA ch3 write permission control registers. - */ -typedef union { - struct { - /** gdma_ch3_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GDMA ch3 write permission control, each bit corresponds to a region. - */ - uint32_t gdma_ch3_w_pms:32; - }; - uint32_t val; -} tee_gmda_ch3_w_pms_reg_t; +} pms_dma_gdma_chn_w_pms_reg_t; /** Type of ahb_pdma_adc_r_pms register - * AHB PDMA adc read permission control registers. + * GDMA-AHB ADC read permission control register */ typedef union { struct { /** ahb_pdma_adc_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA adc read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by ADC. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_adc_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_adc_r_pms_reg_t; +} pms_dma_ahb_pdma_adc_r_pms_reg_t; /** Type of ahb_pdma_adc_w_pms register - * AHB PDMA adc write permission control registers. + * GDMA-AHB ADC write permission control register */ typedef union { struct { /** ahb_pdma_adc_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA adc write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by ADC. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_adc_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_adc_w_pms_reg_t; +} pms_dma_ahb_pdma_adc_w_pms_reg_t; /** Type of ahb_pdma_i2s0_r_pms register - * AHB PDMA i2s0 read permission control registers. + * GDMA-AHB I2S0 read permission control register */ typedef union { struct { /** ahb_pdma_i2s0_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s0 read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S0. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_i2s0_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s0_r_pms_reg_t; +} pms_dma_ahb_pdma_i2s0_r_pms_reg_t; /** Type of ahb_pdma_i2s0_w_pms register - * AHB PDMA i2s0 write permission control registers. + * GDMA-AHB I2S0 write permission control register */ typedef union { struct { /** ahb_pdma_i2s0_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s0 write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S0. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_i2s0_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s0_w_pms_reg_t; +} pms_dma_ahb_pdma_i2s0_w_pms_reg_t; /** Type of ahb_pdma_i2s1_r_pms register - * AHB PDMA i2s1 read permission control registers. + * GDMA-AHB I2S1 read permission control register */ typedef union { struct { /** ahb_pdma_i2s1_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s1 read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S1. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_i2s1_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s1_r_pms_reg_t; +} pms_dma_ahb_pdma_i2s1_r_pms_reg_t; /** Type of ahb_pdma_i2s1_w_pms register - * AHB PDMA i2s1 write permission control registers. + * GDMA-AHB I2S1 write permission control register */ typedef union { struct { /** ahb_pdma_i2s1_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s1 write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S1. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_i2s1_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s1_w_pms_reg_t; +} pms_dma_ahb_pdma_i2s1_w_pms_reg_t; /** Type of ahb_pdma_i2s2_r_pms register - * AHB PDMA i2s2 read permission control registers. + * GDMA-AHB I2S2 read permission control register */ typedef union { struct { /** ahb_pdma_i2s2_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s2 read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by I2S2. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_i2s2_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s2_r_pms_reg_t; +} pms_dma_ahb_pdma_i2s2_r_pms_reg_t; /** Type of ahb_pdma_i2s2_w_pms register - * AHB PDMA i2s2 write permission control registers. + * GDMA-AHB I2S2 write permission control register */ typedef union { struct { /** ahb_pdma_i2s2_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i2s2 write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by I2S2. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_i2s2_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_i2s2_w_pms_reg_t; +} pms_dma_ahb_pdma_i2s2_w_pms_reg_t; /** Type of ahb_pdma_i3c_mst_r_pms register - * AHB PDMA i3s mst read permission control registers. + * GDMA-AHB I3C MST read permission control register */ typedef union { struct { /** ahb_pdma_i3c_mst_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i3c mst read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by I3C master. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_i3c_mst_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_i3c_mst_r_pms_reg_t; +} pms_dma_ahb_pdma_i3c_mst_r_pms_reg_t; /** Type of ahb_pdma_i3c_mst_w_pms register - * AHB PDMA i3c mst write permission control registers. + * GDMA-AHB I3C MST write permission control register */ typedef union { struct { /** ahb_pdma_i3c_mst_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA i3c mst write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by I3C master. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_i3c_mst_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_i3c_mst_w_pms_reg_t; +} pms_dma_ahb_pdma_i3c_mst_w_pms_reg_t; /** Type of ahb_pdma_uhci0_r_pms register - * AHB PDMA uhci0 read permission control registers. + * GDMA-AHB UHCI read permission control register */ typedef union { struct { /** ahb_pdma_uhci0_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA uhci0 read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by UHCI. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_uhci0_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_uhci0_r_pms_reg_t; +} pms_dma_ahb_pdma_uhci0_r_pms_reg_t; /** Type of ahb_pdma_uhci0_w_pms register - * AHB PDMA uhci0 write permission control registers. + * GDMA-AHB UHCI write permission control register */ typedef union { struct { /** ahb_pdma_uhci0_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA uhci0 write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by UHCI. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_uhci0_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_uhci0_w_pms_reg_t; +} pms_dma_ahb_pdma_uhci0_w_pms_reg_t; /** Type of ahb_pdma_rmt_r_pms register - * AHB PDMA rmt read permission control registers. + * GDMA-AHB RMT read permission control register */ typedef union { struct { /** ahb_pdma_rmt_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA rmt read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by RMT. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_rmt_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_rmt_r_pms_reg_t; +} pms_dma_ahb_pdma_rmt_r_pms_reg_t; /** Type of ahb_pdma_rmt_w_pms register - * AHB PDMA rmt write permission control registers. + * GDMA-AHB RMT write permission control register */ typedef union { struct { /** ahb_pdma_rmt_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA rmt write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by RMT. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_rmt_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_rmt_w_pms_reg_t; +} pms_dma_ahb_pdma_rmt_w_pms_reg_t; /** Type of axi_pdma_lcdcam_r_pms register - * AXI PDMA lcdcam read permission control registers. + * GDMA-AXI LCD_CAM read permission control register */ typedef union { struct { /** axi_pdma_lcdcam_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA lcdcam read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by LCD_CAM. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_lcdcam_r_pms:32; }; uint32_t val; -} tee_axi_pdma_lcdcam_r_pms_reg_t; +} pms_dma_axi_pdma_lcdcam_r_pms_reg_t; /** Type of axi_pdma_lcdcam_w_pms register - * AXI PDMA lcdcam write permission control registers. + * GDMA-AXI LCD_CAM write permission control register */ typedef union { struct { /** axi_pdma_lcdcam_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA lcdcam write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by LCD_CAM. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_lcdcam_w_pms:32; }; uint32_t val; -} tee_axi_pdma_lcdcam_w_pms_reg_t; +} pms_dma_axi_pdma_lcdcam_w_pms_reg_t; /** Type of axi_pdma_gpspi2_r_pms register - * AXI PDMA gpspi2 read permission control registers. + * GDMA-AXI GPSPI2 read permission control register */ typedef union { struct { /** axi_pdma_gpspi2_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi2 read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI2. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_gpspi2_r_pms:32; }; uint32_t val; -} tee_axi_pdma_gpspi2_r_pms_reg_t; +} pms_dma_axi_pdma_gpspi2_r_pms_reg_t; /** Type of axi_pdma_gpspi2_w_pms register - * AXI PDMA gpspi2 write permission control registers. + * GDMA-AXI GPSPI2 write permission control register */ typedef union { struct { /** axi_pdma_gpspi2_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi2 write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI2. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_gpspi2_w_pms:32; }; uint32_t val; -} tee_axi_pdma_gpspi2_w_pms_reg_t; +} pms_dma_axi_pdma_gpspi2_w_pms_reg_t; /** Type of axi_pdma_gpspi3_r_pms register - * AXI PDMA gpspi3 read permission control registers. + * GDMA-AXI GPSPI3 read permission control register */ typedef union { struct { /** axi_pdma_gpspi3_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi3 read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI3. Bit + * 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_gpspi3_r_pms:32; }; uint32_t val; -} tee_axi_pdma_gpspi3_r_pms_reg_t; +} pms_dma_axi_pdma_gpspi3_r_pms_reg_t; /** Type of axi_pdma_gpspi3_w_pms register - * AXI PDMA gpspi3 write permission control registers. + * AXI PDMA GPSPI3 write permission control register */ typedef union { struct { /** axi_pdma_gpspi3_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA gpspi3 write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI3. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_gpspi3_w_pms:32; }; uint32_t val; -} tee_axi_pdma_gpspi3_w_pms_reg_t; +} pms_dma_axi_pdma_gpspi3_w_pms_reg_t; /** Type of axi_pdma_parlio_r_pms register - * AXI PDMA parl io read permission control registers. + * GDMA-AXI PARLIO read permission control register */ typedef union { struct { /** axi_pdma_parlio_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA parl io read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by PARLIO + * (Parallel IO Controller). Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_parlio_r_pms:32; }; uint32_t val; -} tee_axi_pdma_parlio_r_pms_reg_t; +} pms_dma_axi_pdma_parlio_r_pms_reg_t; /** Type of axi_pdma_parlio_w_pms register - * AXI PDMA parl io write permission control registers. + * GDMA-AXI PARLIO write permission control register */ typedef union { struct { /** axi_pdma_parlio_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA parl io write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by PARLIO. Bit + * 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_parlio_w_pms:32; }; uint32_t val; -} tee_axi_pdma_parlio_w_pms_reg_t; +} pms_dma_axi_pdma_parlio_w_pms_reg_t; /** Type of axi_pdma_aes_r_pms register - * AXI PDMA aes read permission control registers. + * GDMA-AXI AES read permission control register */ typedef union { struct { /** axi_pdma_aes_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA aes read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by AES. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_aes_r_pms:32; }; uint32_t val; -} tee_axi_pdma_aes_r_pms_reg_t; +} pms_dma_axi_pdma_aes_r_pms_reg_t; /** Type of axi_pdma_aes_w_pms register - * AXI PDMA aes write permission control registers. + * GDMA-AXI AES write permission control register */ typedef union { struct { /** axi_pdma_aes_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA aes write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by AES. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_aes_w_pms:32; }; uint32_t val; -} tee_axi_pdma_aes_w_pms_reg_t; +} pms_dma_axi_pdma_aes_w_pms_reg_t; /** Type of axi_pdma_sha_r_pms register - * AXI PDMA sha read permission control registers. + * GDMA-AXI SHA read permission control register */ typedef union { struct { /** axi_pdma_sha_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA sha read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by SHA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_sha_r_pms:32; }; uint32_t val; -} tee_axi_pdma_sha_r_pms_reg_t; +} pms_dma_axi_pdma_sha_r_pms_reg_t; /** Type of axi_pdma_sha_w_pms register - * AXI PDMA sha write permission control registers. + * GDMA-AXI SHA write permission control register */ typedef union { struct { /** axi_pdma_sha_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA sha write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by SHA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_sha_w_pms:32; }; uint32_t val; -} tee_axi_pdma_sha_w_pms_reg_t; +} pms_dma_axi_pdma_sha_w_pms_reg_t; /** Type of dma2d_jpeg_pms_r register - * DMA2D JPEG read permission control registers. + * 2D-DMA JPEG read permission control register */ typedef union { struct { /** dma2d_jpeg_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D JPEG read permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to read 32 address ranges requested by JPEG. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t dma2d_jpeg_r_pms:32; }; uint32_t val; -} tee_dma2d_jpeg_pms_r_reg_t; +} pms_dma_dma2d_jpeg_pms_r_reg_t; /** Type of dma2d_jpeg_pms_w register - * DMA2D JPEG write permission control registers. + * 2D-DMA JPEG write permission control register */ typedef union { struct { /** dma2d_jpeg_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D JPEG write permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to write 32 address ranges requested by JPEG. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t dma2d_jpeg_w_pms:32; }; uint32_t val; -} tee_dma2d_jpeg_pms_w_reg_t; +} pms_dma_dma2d_jpeg_pms_w_reg_t; /** Type of usb_pms_r register - * USB read permission control registers. + * High-speed USB 2.0 OTG read permission control register */ typedef union { struct { /** usb_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * USB read permission control, each bit corresponds to a region. + * Configures read permission for high-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t usb_r_pms:32; }; uint32_t val; -} tee_usb_pms_r_reg_t; +} pms_dma_usb_pms_r_reg_t; /** Type of usb_pms_w register - * USB write permission control registers. + * High-speed USB 2.0 OTG write permission control register */ typedef union { struct { /** usb_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * USB write permission control, each bit corresponds to a region. + * Configures write permission for high-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t usb_w_pms:32; }; uint32_t val; -} tee_usb_pms_w_reg_t; +} pms_dma_usb_pms_w_reg_t; /** Type of gmac_pms_r register - * GMAC read permission control registers. + * EMAC read permission control register */ typedef union { struct { /** gmac_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GMAC read permission control, each bit corresponds to a region. + * Configures read permission for EMAC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t gmac_r_pms:32; }; uint32_t val; -} tee_gmac_pms_r_reg_t; +} pms_dma_gmac_pms_r_reg_t; /** Type of gmac_pms_w register - * GMAC write permission control registers. + * EMAC write permission control register */ typedef union { struct { /** gmac_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * GMAC write permission control, each bit corresponds to a region. + * Configures write permission for EMAC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t gmac_w_pms:32; }; uint32_t val; -} tee_gmac_pms_w_reg_t; +} pms_dma_gmac_pms_w_reg_t; /** Type of sdmmc_pms_r register - * SDMMC read permission control registers. + * SDMMC read permission control register */ typedef union { struct { /** sdmmc_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * SDMMC read permission control, each bit corresponds to a region. + * Configures read permission for SDMMC to access 32 address ranges. Bit 0 corresponds + * to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t sdmmc_r_pms:32; }; uint32_t val; -} tee_sdmmc_pms_r_reg_t; +} pms_dma_sdmmc_pms_r_reg_t; /** Type of sdmmc_pms_w register - * SDMMC write permission control registers. + * SDMMC write permission control register */ typedef union { struct { /** sdmmc_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * SDMMC write permission control, each bit corresponds to a region. + * Configures write permission for SDMMC to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t sdmmc_w_pms:32; }; uint32_t val; -} tee_sdmmc_pms_w_reg_t; +} pms_dma_sdmmc_pms_w_reg_t; /** Type of usbotg11_pms_r register - * USBOTG11 read permission control registers. + * Full-speed USB 2.0 OTG full-speed read permission control register */ typedef union { struct { /** usbotg11_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * USBOTG11 read permission control, each bit corresponds to a region. + * Configures read permission for full-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t usbotg11_r_pms:32; }; uint32_t val; -} tee_usbotg11_pms_r_reg_t; +} pms_dma_usbotg11_pms_r_reg_t; /** Type of usbotg11_pms_w register - * USBOTG11 write permission control registers. + * Full-speed USB 2.0 OTG full-speed write permission control register */ typedef union { struct { /** usbotg11_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * USBOTG11 write permission control, each bit corresponds to a region. + * Configures write permission for full-speed USB 2.0 OTG to access 32 address ranges. + * Bit 0 corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t usbotg11_w_pms:32; }; uint32_t val; -} tee_usbotg11_pms_w_reg_t; +} pms_dma_usbotg11_pms_w_reg_t; /** Type of trace0_pms_r register - * TRACE0 read permission control registers. + * TRACE0 read permission control register */ typedef union { struct { /** trace0_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE0 read permission control, each bit corresponds to a region. + * Configures read permission for TRACE0 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t trace0_r_pms:32; }; uint32_t val; -} tee_trace0_pms_r_reg_t; +} pms_dma_trace0_pms_r_reg_t; /** Type of trace0_pms_w register - * TRACE0 write permission control registers. + * TRACE0 write permission control register */ typedef union { struct { /** trace0_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE0 write permission control, each bit corresponds to a region. + * Configures write permission for TRACE0 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t trace0_w_pms:32; }; uint32_t val; -} tee_trace0_pms_w_reg_t; +} pms_dma_trace0_pms_w_reg_t; /** Type of trace1_pms_r register - * TRACE1 read permission control registers. + * TRACE1 read permission control register */ typedef union { struct { /** trace1_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE1 read permission control, each bit corresponds to a region. + * Configures read permission for TRACE1 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t trace1_r_pms:32; }; uint32_t val; -} tee_trace1_pms_r_reg_t; +} pms_dma_trace1_pms_r_reg_t; /** Type of trace1_pms_w register - * TRACE1 write permission control registers. + * TRACE1 write permission control register */ typedef union { struct { /** trace1_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TRACE1 write permission control, each bit corresponds to a region. + * Configures write permission for TRACE1 to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t trace1_w_pms:32; }; uint32_t val; -} tee_trace1_pms_w_reg_t; +} pms_dma_trace1_pms_w_reg_t; /** Type of l2mem_mon_pms_r register - * L2MEM MON read permission control registers. + * L2MEM Monitor read permission control register */ typedef union { struct { /** l2mem_mon_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * L2MEM MON read permission control, each bit corresponds to a region. + * Configures read permission for L2MEM MON. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t l2mem_mon_r_pms:32; }; uint32_t val; -} tee_l2mem_mon_pms_r_reg_t; +} pms_dma_l2mem_mon_pms_r_reg_t; /** Type of l2mem_mon_pms_w register - * L2MEM MON write permission control registers. + * L2MEM Monitor write permission control register */ typedef union { struct { /** l2mem_mon_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * L2MEM MON write permission control, each bit corresponds to a region. + * Configures write permission for L2MEM monitor to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t l2mem_mon_w_pms:32; }; uint32_t val; -} tee_l2mem_mon_pms_w_reg_t; +} pms_dma_l2mem_mon_pms_w_reg_t; /** Type of tcm_mon_pms_r register - * TCM MON read permission control registers. + * TCM Monitor read permission control register */ typedef union { struct { /** tcm_mon_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TCM MON read permission control, each bit corresponds to a region. + * Configures read permission for TCM MON. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t tcm_mon_r_pms:32; }; uint32_t val; -} tee_tcm_mon_pms_r_reg_t; +} pms_dma_tcm_mon_pms_r_reg_t; /** Type of tcm_mon_pms_w register - * TCM MON write permission control registers. + * TCM Monitor write permission control register */ typedef union { struct { /** tcm_mon_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * TCM MON write permission control, each bit corresponds to a region. + * Configures write permission for TCM monitor to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t tcm_mon_w_pms:32; }; uint32_t val; -} tee_tcm_mon_pms_w_reg_t; +} pms_dma_tcm_mon_pms_w_reg_t; /** Type of regdma_pms_r register - * REGDMA read permission control registers. + * REGDMA read permission control register */ typedef union { struct { /** regdma_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * REGDMA read permission control, each bit corresponds to a region. + * Configures read permission for REGDMA. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t regdma_r_pms:32; }; uint32_t val; -} tee_regdma_pms_r_reg_t; +} pms_dma_regdma_pms_r_reg_t; /** Type of regdma_pms_w register - * REGDMA write permission control registers. + * REGDMA write permission control register */ typedef union { struct { /** regdma_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * REGDMA write permission control, each bit corresponds to a region. + * Configures write permission for REGDMA. Each bit corresponds to a region. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t regdma_w_pms:32; }; uint32_t val; -} tee_regdma_pms_w_reg_t; +} pms_dma_regdma_pms_w_reg_t; /** Type of h264_pms_r register - * H264 read permission control registers. + * H264 DMA read permission control register */ typedef union { struct { /** h264_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * H264 read permission control, each bit corresponds to a region. + * Configures read permission for H264 DMA to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t h264_r_pms:32; }; uint32_t val; -} tee_h264_pms_r_reg_t; +} pms_dma_h264_pms_r_reg_t; /** Type of h264_pms_w register - * H264 write permission control registers. + * H264 DMA write permission control register */ typedef union { struct { /** h264_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * H264 write permission control, each bit corresponds to a region. + * Configures write permission for H264 DMA to access 32 address ranges. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t h264_w_pms:32; }; uint32_t val; -} tee_h264_pms_w_reg_t; +} pms_dma_h264_pms_w_reg_t; /** Type of dma2d_ppa_pms_r register - * DMA2D PPA read permission control registers. + * 2D-DMA PPA read permission control register */ typedef union { struct { /** dma2d_ppa_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D PPA read permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to read 32 address ranges requested by PPA + * (Pixel-Processing Accelerator). Bit 0 corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t dma2d_ppa_r_pms:32; }; uint32_t val; -} tee_dma2d_ppa_pms_r_reg_t; +} pms_dma_dma2d_ppa_pms_r_reg_t; /** Type of dma2d_ppa_pms_w register - * DMA2D PPA write permission control registers. + * 2D-DMA PPA write permission control register */ typedef union { struct { /** dma2d_ppa_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D PPA write permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to write 32 address ranges requested by PPA. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t dma2d_ppa_w_pms:32; }; uint32_t val; -} tee_dma2d_ppa_pms_w_reg_t; +} pms_dma_dma2d_ppa_pms_w_reg_t; /** Type of dma2d_dummy_pms_r register - * DMA2D dummy read permission control registers. + * 2D-DMA dummy read permission control register */ typedef union { struct { /** dma2d_dummy_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D dummy read permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t dma2d_dummy_r_pms:32; }; uint32_t val; -} tee_dma2d_dummy_pms_r_reg_t; +} pms_dma_dma2d_dummy_pms_r_reg_t; /** Type of dma2d_dummy_pms_w register - * DMA2D dummy write permission control registers. + * 2D-DMA dummy write permission control register */ typedef union { struct { /** dma2d_dummy_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * DMA2D dummy write permission control, each bit corresponds to a region. + * Configures 2D-DMA permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t dma2d_dummy_w_pms:32; }; uint32_t val; -} tee_dma2d_dummy_pms_w_reg_t; +} pms_dma_dma2d_dummy_pms_w_reg_t; /** Type of ahb_pdma_dummy_r_pms register - * AHB PDMA dummy read permission control registers. + * GDMA-AHB dummy read permission control register */ typedef union { struct { /** ahb_pdma_dummy_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA dummy read permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t ahb_pdma_dummy_r_pms:32; }; uint32_t val; -} tee_ahb_pdma_dummy_r_pms_reg_t; +} pms_dma_ahb_pdma_dummy_r_pms_reg_t; /** Type of ahb_pdma_dummy_w_pms register - * AHB PDMA dummy write permission control registers. + * GDMA-AHB dummy write permission control register */ typedef union { struct { /** ahb_pdma_dummy_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AHB PDMA dummy write permission control, each bit corresponds to a region. + * Configures GDMA-AHB permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t ahb_pdma_dummy_w_pms:32; }; uint32_t val; -} tee_ahb_pdma_dummy_w_pms_reg_t; +} pms_dma_ahb_pdma_dummy_w_pms_reg_t; /** Type of axi_pdma_dummy_r_pms register - * AXI PDMA dummy read permission control registers. + * GDMA-AXI dummy read permission control register */ typedef union { struct { /** axi_pdma_dummy_r_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA dummy read permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to read 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable read permission. + * 1: Enable read permission. */ uint32_t axi_pdma_dummy_r_pms:32; }; uint32_t val; -} tee_axi_pdma_dummy_r_pms_reg_t; +} pms_dma_axi_pdma_dummy_r_pms_reg_t; /** Type of axi_pdma_dummy_w_pms register - * AXI PDMA dummy write permission control registers. + * GDMA-AXI dummy write permission control register */ typedef union { struct { /** axi_pdma_dummy_w_pms : R/W; bitpos: [31:0]; default: 4294967295; - * AXI PDMA dummy write permission control, each bit corresponds to a region. + * Configures GDMA-AXI permission to write 32 address ranges requested by Dummy. Bit 0 + * corresponds to region0, and so on. + * 0: Disable write permission. + * 1: Enable write permission. */ uint32_t axi_pdma_dummy_w_pms:32; }; uint32_t val; -} tee_axi_pdma_dummy_w_pms_reg_t; +} pms_dma_axi_pdma_dummy_w_pms_reg_t; typedef struct { - volatile tee_date_reg_t date; - volatile tee_clk_en_reg_t clk_en; - volatile tee_region0_low_reg_t region0_low; - volatile tee_region0_high_reg_t region0_high; - volatile tee_region1_low_reg_t region1_low; - volatile tee_region1_high_reg_t region1_high; - volatile tee_region2_low_reg_t region2_low; - volatile tee_region2_high_reg_t region2_high; - volatile tee_region3_low_reg_t region3_low; - volatile tee_region3_high_reg_t region3_high; - volatile tee_region4_low_reg_t region4_low; - volatile tee_region4_high_reg_t region4_high; - volatile tee_region5_low_reg_t region5_low; - volatile tee_region5_high_reg_t region5_high; - volatile tee_region6_low_reg_t region6_low; - volatile tee_region6_high_reg_t region6_high; - volatile tee_region7_low_reg_t region7_low; - volatile tee_region7_high_reg_t region7_high; - volatile tee_region8_low_reg_t region8_low; - volatile tee_region8_high_reg_t region8_high; - volatile tee_region9_low_reg_t region9_low; - volatile tee_region9_high_reg_t region9_high; - volatile tee_region10_low_reg_t region10_low; - volatile tee_region10_high_reg_t region10_high; - volatile tee_region11_low_reg_t region11_low; - volatile tee_region11_high_reg_t region11_high; - volatile tee_region12_low_reg_t region12_low; - volatile tee_region12_high_reg_t region12_high; - volatile tee_region13_low_reg_t region13_low; - volatile tee_region13_high_reg_t region13_high; - volatile tee_region14_low_reg_t region14_low; - volatile tee_region14_high_reg_t region14_high; - volatile tee_region15_low_reg_t region15_low; - volatile tee_region15_high_reg_t region15_high; - volatile tee_region16_low_reg_t region16_low; - volatile tee_region16_high_reg_t region16_high; - volatile tee_region17_low_reg_t region17_low; - volatile tee_region17_high_reg_t region17_high; - volatile tee_region18_low_reg_t region18_low; - volatile tee_region18_high_reg_t region18_high; - volatile tee_region19_low_reg_t region19_low; - volatile tee_region19_high_reg_t region19_high; - volatile tee_region20_low_reg_t region20_low; - volatile tee_region20_high_reg_t region20_high; - volatile tee_region21_low_reg_t region21_low; - volatile tee_region21_high_reg_t region21_high; - volatile tee_region22_low_reg_t region22_low; - volatile tee_region22_high_reg_t region22_high; - volatile tee_region23_low_reg_t region23_low; - volatile tee_region23_high_reg_t region23_high; - volatile tee_region24_low_reg_t region24_low; - volatile tee_region24_high_reg_t region24_high; - volatile tee_region25_low_reg_t region25_low; - volatile tee_region25_high_reg_t region25_high; - volatile tee_region26_low_reg_t region26_low; - volatile tee_region26_high_reg_t region26_high; - volatile tee_region27_low_reg_t region27_low; - volatile tee_region27_high_reg_t region27_high; - volatile tee_region28_low_reg_t region28_low; - volatile tee_region28_high_reg_t region28_high; - volatile tee_region29_low_reg_t region29_low; - volatile tee_region29_high_reg_t region29_high; - volatile tee_region30_low_reg_t region30_low; - volatile tee_region30_high_reg_t region30_high; - volatile tee_region31_low_reg_t region31_low; - volatile tee_region31_high_reg_t region31_high; - volatile tee_gmda_ch0_r_pms_reg_t gmda_ch0_r_pms; - volatile tee_gmda_ch0_w_pms_reg_t gmda_ch0_w_pms; - volatile tee_gmda_ch1_r_pms_reg_t gmda_ch1_r_pms; - volatile tee_gmda_ch1_w_pms_reg_t gmda_ch1_w_pms; - volatile tee_gmda_ch2_r_pms_reg_t gmda_ch2_r_pms; - volatile tee_gmda_ch2_w_pms_reg_t gmda_ch2_w_pms; - volatile tee_gmda_ch3_r_pms_reg_t gmda_ch3_r_pms; - volatile tee_gmda_ch3_w_pms_reg_t gmda_ch3_w_pms; - volatile tee_ahb_pdma_adc_r_pms_reg_t ahb_pdma_adc_r_pms; - volatile tee_ahb_pdma_adc_w_pms_reg_t ahb_pdma_adc_w_pms; - volatile tee_ahb_pdma_i2s0_r_pms_reg_t ahb_pdma_i2s0_r_pms; - volatile tee_ahb_pdma_i2s0_w_pms_reg_t ahb_pdma_i2s0_w_pms; - volatile tee_ahb_pdma_i2s1_r_pms_reg_t ahb_pdma_i2s1_r_pms; - volatile tee_ahb_pdma_i2s1_w_pms_reg_t ahb_pdma_i2s1_w_pms; - volatile tee_ahb_pdma_i2s2_r_pms_reg_t ahb_pdma_i2s2_r_pms; - volatile tee_ahb_pdma_i2s2_w_pms_reg_t ahb_pdma_i2s2_w_pms; - volatile tee_ahb_pdma_i3c_mst_r_pms_reg_t ahb_pdma_i3c_mst_r_pms; - volatile tee_ahb_pdma_i3c_mst_w_pms_reg_t ahb_pdma_i3c_mst_w_pms; - volatile tee_ahb_pdma_uhci0_r_pms_reg_t ahb_pdma_uhci0_r_pms; - volatile tee_ahb_pdma_uhci0_w_pms_reg_t ahb_pdma_uhci0_w_pms; - volatile tee_ahb_pdma_rmt_r_pms_reg_t ahb_pdma_rmt_r_pms; + volatile pms_dma_date_reg_t date; + volatile pms_dma_clk_en_reg_t clk_en; + volatile pms_dma_regionn_low_reg_t region0_low; + volatile pms_dma_regionn_high_reg_t region0_high; + volatile pms_dma_regionn_low_reg_t region1_low; + volatile pms_dma_regionn_high_reg_t region1_high; + volatile pms_dma_regionn_low_reg_t region2_low; + volatile pms_dma_regionn_high_reg_t region2_high; + volatile pms_dma_regionn_low_reg_t region3_low; + volatile pms_dma_regionn_high_reg_t region3_high; + volatile pms_dma_regionn_low_reg_t region4_low; + volatile pms_dma_regionn_high_reg_t region4_high; + volatile pms_dma_regionn_low_reg_t region5_low; + volatile pms_dma_regionn_high_reg_t region5_high; + volatile pms_dma_regionn_low_reg_t region6_low; + volatile pms_dma_regionn_high_reg_t region6_high; + volatile pms_dma_regionn_low_reg_t region7_low; + volatile pms_dma_regionn_high_reg_t region7_high; + volatile pms_dma_regionn_low_reg_t region8_low; + volatile pms_dma_regionn_high_reg_t region8_high; + volatile pms_dma_regionn_low_reg_t region9_low; + volatile pms_dma_regionn_high_reg_t region9_high; + volatile pms_dma_regionn_low_reg_t region10_low; + volatile pms_dma_regionn_high_reg_t region10_high; + volatile pms_dma_regionn_low_reg_t region11_low; + volatile pms_dma_regionn_high_reg_t region11_high; + volatile pms_dma_regionn_low_reg_t region12_low; + volatile pms_dma_regionn_high_reg_t region12_high; + volatile pms_dma_regionn_low_reg_t region13_low; + volatile pms_dma_regionn_high_reg_t region13_high; + volatile pms_dma_regionn_low_reg_t region14_low; + volatile pms_dma_regionn_high_reg_t region14_high; + volatile pms_dma_regionn_low_reg_t region15_low; + volatile pms_dma_regionn_high_reg_t region15_high; + volatile pms_dma_regionn_low_reg_t region16_low; + volatile pms_dma_regionn_high_reg_t region16_high; + volatile pms_dma_regionn_low_reg_t region17_low; + volatile pms_dma_regionn_high_reg_t region17_high; + volatile pms_dma_regionn_low_reg_t region18_low; + volatile pms_dma_regionn_high_reg_t region18_high; + volatile pms_dma_regionn_low_reg_t region19_low; + volatile pms_dma_regionn_high_reg_t region19_high; + volatile pms_dma_regionn_low_reg_t region20_low; + volatile pms_dma_regionn_high_reg_t region20_high; + volatile pms_dma_regionn_low_reg_t region21_low; + volatile pms_dma_regionn_high_reg_t region21_high; + volatile pms_dma_regionn_low_reg_t region22_low; + volatile pms_dma_regionn_high_reg_t region22_high; + volatile pms_dma_regionn_low_reg_t region23_low; + volatile pms_dma_regionn_high_reg_t region23_high; + volatile pms_dma_regionn_low_reg_t region24_low; + volatile pms_dma_regionn_high_reg_t region24_high; + volatile pms_dma_regionn_low_reg_t region25_low; + volatile pms_dma_regionn_high_reg_t region25_high; + volatile pms_dma_regionn_low_reg_t region26_low; + volatile pms_dma_regionn_high_reg_t region26_high; + volatile pms_dma_regionn_low_reg_t region27_low; + volatile pms_dma_regionn_high_reg_t region27_high; + volatile pms_dma_regionn_low_reg_t region28_low; + volatile pms_dma_regionn_high_reg_t region28_high; + volatile pms_dma_regionn_low_reg_t region29_low; + volatile pms_dma_regionn_high_reg_t region29_high; + volatile pms_dma_regionn_low_reg_t region30_low; + volatile pms_dma_regionn_high_reg_t region30_high; + volatile pms_dma_regionn_low_reg_t region31_low; + volatile pms_dma_regionn_high_reg_t region31_high; + volatile pms_dma_gdma_chn_r_pms_reg_t gdma_ch0_r_pms; + volatile pms_dma_gdma_chn_w_pms_reg_t gdma_ch0_w_pms; + volatile pms_dma_gdma_chn_r_pms_reg_t gdma_ch1_r_pms; + volatile pms_dma_gdma_chn_w_pms_reg_t gdma_ch1_w_pms; + volatile pms_dma_gdma_chn_r_pms_reg_t gdma_ch2_r_pms; + volatile pms_dma_gdma_chn_w_pms_reg_t gdma_ch2_w_pms; + volatile pms_dma_gdma_chn_r_pms_reg_t gdma_ch3_r_pms; + volatile pms_dma_gdma_chn_w_pms_reg_t gdma_ch3_w_pms; + volatile pms_dma_ahb_pdma_adc_r_pms_reg_t ahb_pdma_adc_r_pms; + volatile pms_dma_ahb_pdma_adc_w_pms_reg_t ahb_pdma_adc_w_pms; + volatile pms_dma_ahb_pdma_i2s0_r_pms_reg_t ahb_pdma_i2s0_r_pms; + volatile pms_dma_ahb_pdma_i2s0_w_pms_reg_t ahb_pdma_i2s0_w_pms; + volatile pms_dma_ahb_pdma_i2s1_r_pms_reg_t ahb_pdma_i2s1_r_pms; + volatile pms_dma_ahb_pdma_i2s1_w_pms_reg_t ahb_pdma_i2s1_w_pms; + volatile pms_dma_ahb_pdma_i2s2_r_pms_reg_t ahb_pdma_i2s2_r_pms; + volatile pms_dma_ahb_pdma_i2s2_w_pms_reg_t ahb_pdma_i2s2_w_pms; + volatile pms_dma_ahb_pdma_i3c_mst_r_pms_reg_t ahb_pdma_i3c_mst_r_pms; + volatile pms_dma_ahb_pdma_i3c_mst_w_pms_reg_t ahb_pdma_i3c_mst_w_pms; + volatile pms_dma_ahb_pdma_uhci0_r_pms_reg_t ahb_pdma_uhci0_r_pms; + volatile pms_dma_ahb_pdma_uhci0_w_pms_reg_t ahb_pdma_uhci0_w_pms; + volatile pms_dma_ahb_pdma_rmt_r_pms_reg_t ahb_pdma_rmt_r_pms; uint32_t reserved_15c[5]; - volatile tee_ahb_pdma_rmt_w_pms_reg_t ahb_pdma_rmt_w_pms; - volatile tee_axi_pdma_lcdcam_r_pms_reg_t axi_pdma_lcdcam_r_pms; - volatile tee_axi_pdma_lcdcam_w_pms_reg_t axi_pdma_lcdcam_w_pms; - volatile tee_axi_pdma_gpspi2_r_pms_reg_t axi_pdma_gpspi2_r_pms; - volatile tee_axi_pdma_gpspi2_w_pms_reg_t axi_pdma_gpspi2_w_pms; - volatile tee_axi_pdma_gpspi3_r_pms_reg_t axi_pdma_gpspi3_r_pms; - volatile tee_axi_pdma_gpspi3_w_pms_reg_t axi_pdma_gpspi3_w_pms; - volatile tee_axi_pdma_parlio_r_pms_reg_t axi_pdma_parlio_r_pms; - volatile tee_axi_pdma_parlio_w_pms_reg_t axi_pdma_parlio_w_pms; - volatile tee_axi_pdma_aes_r_pms_reg_t axi_pdma_aes_r_pms; - volatile tee_axi_pdma_aes_w_pms_reg_t axi_pdma_aes_w_pms; - volatile tee_axi_pdma_sha_r_pms_reg_t axi_pdma_sha_r_pms; - volatile tee_axi_pdma_sha_w_pms_reg_t axi_pdma_sha_w_pms; - volatile tee_dma2d_jpeg_pms_r_reg_t dma2d_jpeg_pms_r; - volatile tee_dma2d_jpeg_pms_w_reg_t dma2d_jpeg_pms_w; - volatile tee_usb_pms_r_reg_t usb_pms_r; - volatile tee_usb_pms_w_reg_t usb_pms_w; - volatile tee_gmac_pms_r_reg_t gmac_pms_r; - volatile tee_gmac_pms_w_reg_t gmac_pms_w; - volatile tee_sdmmc_pms_r_reg_t sdmmc_pms_r; - volatile tee_sdmmc_pms_w_reg_t sdmmc_pms_w; - volatile tee_usbotg11_pms_r_reg_t usbotg11_pms_r; - volatile tee_usbotg11_pms_w_reg_t usbotg11_pms_w; - volatile tee_trace0_pms_r_reg_t trace0_pms_r; - volatile tee_trace0_pms_w_reg_t trace0_pms_w; - volatile tee_trace1_pms_r_reg_t trace1_pms_r; - volatile tee_trace1_pms_w_reg_t trace1_pms_w; - volatile tee_l2mem_mon_pms_r_reg_t l2mem_mon_pms_r; - volatile tee_l2mem_mon_pms_w_reg_t l2mem_mon_pms_w; - volatile tee_tcm_mon_pms_r_reg_t tcm_mon_pms_r; - volatile tee_tcm_mon_pms_w_reg_t tcm_mon_pms_w; - volatile tee_regdma_pms_r_reg_t regdma_pms_r; - volatile tee_regdma_pms_w_reg_t regdma_pms_w; + volatile pms_dma_ahb_pdma_rmt_w_pms_reg_t ahb_pdma_rmt_w_pms; + volatile pms_dma_axi_pdma_lcdcam_r_pms_reg_t axi_pdma_lcdcam_r_pms; + volatile pms_dma_axi_pdma_lcdcam_w_pms_reg_t axi_pdma_lcdcam_w_pms; + volatile pms_dma_axi_pdma_gpspi2_r_pms_reg_t axi_pdma_gpspi2_r_pms; + volatile pms_dma_axi_pdma_gpspi2_w_pms_reg_t axi_pdma_gpspi2_w_pms; + volatile pms_dma_axi_pdma_gpspi3_r_pms_reg_t axi_pdma_gpspi3_r_pms; + volatile pms_dma_axi_pdma_gpspi3_w_pms_reg_t axi_pdma_gpspi3_w_pms; + volatile pms_dma_axi_pdma_parlio_r_pms_reg_t axi_pdma_parlio_r_pms; + volatile pms_dma_axi_pdma_parlio_w_pms_reg_t axi_pdma_parlio_w_pms; + volatile pms_dma_axi_pdma_aes_r_pms_reg_t axi_pdma_aes_r_pms; + volatile pms_dma_axi_pdma_aes_w_pms_reg_t axi_pdma_aes_w_pms; + volatile pms_dma_axi_pdma_sha_r_pms_reg_t axi_pdma_sha_r_pms; + volatile pms_dma_axi_pdma_sha_w_pms_reg_t axi_pdma_sha_w_pms; + volatile pms_dma_dma2d_jpeg_pms_r_reg_t dma2d_jpeg_pms_r; + volatile pms_dma_dma2d_jpeg_pms_w_reg_t dma2d_jpeg_pms_w; + volatile pms_dma_usb_pms_r_reg_t usb_pms_r; + volatile pms_dma_usb_pms_w_reg_t usb_pms_w; + volatile pms_dma_gmac_pms_r_reg_t gmac_pms_r; + volatile pms_dma_gmac_pms_w_reg_t gmac_pms_w; + volatile pms_dma_sdmmc_pms_r_reg_t sdmmc_pms_r; + volatile pms_dma_sdmmc_pms_w_reg_t sdmmc_pms_w; + volatile pms_dma_usbotg11_pms_r_reg_t usbotg11_pms_r; + volatile pms_dma_usbotg11_pms_w_reg_t usbotg11_pms_w; + volatile pms_dma_trace0_pms_r_reg_t trace0_pms_r; + volatile pms_dma_trace0_pms_w_reg_t trace0_pms_w; + volatile pms_dma_trace1_pms_r_reg_t trace1_pms_r; + volatile pms_dma_trace1_pms_w_reg_t trace1_pms_w; + volatile pms_dma_l2mem_mon_pms_r_reg_t l2mem_mon_pms_r; + volatile pms_dma_l2mem_mon_pms_w_reg_t l2mem_mon_pms_w; + volatile pms_dma_tcm_mon_pms_r_reg_t tcm_mon_pms_r; + volatile pms_dma_tcm_mon_pms_w_reg_t tcm_mon_pms_w; + volatile pms_dma_regdma_pms_r_reg_t regdma_pms_r; + volatile pms_dma_regdma_pms_w_reg_t regdma_pms_w; uint32_t reserved_1f4[2]; - volatile tee_h264_pms_r_reg_t h264_pms_r; - volatile tee_h264_pms_w_reg_t h264_pms_w; - volatile tee_dma2d_ppa_pms_r_reg_t dma2d_ppa_pms_r; - volatile tee_dma2d_ppa_pms_w_reg_t dma2d_ppa_pms_w; - volatile tee_dma2d_dummy_pms_r_reg_t dma2d_dummy_pms_r; - volatile tee_dma2d_dummy_pms_w_reg_t dma2d_dummy_pms_w; - volatile tee_ahb_pdma_dummy_r_pms_reg_t ahb_pdma_dummy_r_pms; - volatile tee_ahb_pdma_dummy_w_pms_reg_t ahb_pdma_dummy_w_pms; - volatile tee_axi_pdma_dummy_r_pms_reg_t axi_pdma_dummy_r_pms; - volatile tee_axi_pdma_dummy_w_pms_reg_t axi_pdma_dummy_w_pms; -} tee_dev_t; - + volatile pms_dma_h264_pms_r_reg_t h264_pms_r; + volatile pms_dma_h264_pms_w_reg_t h264_pms_w; + volatile pms_dma_dma2d_ppa_pms_r_reg_t dma2d_ppa_pms_r; + volatile pms_dma_dma2d_ppa_pms_w_reg_t dma2d_ppa_pms_w; + volatile pms_dma_dma2d_dummy_pms_r_reg_t dma2d_dummy_pms_r; + volatile pms_dma_dma2d_dummy_pms_w_reg_t dma2d_dummy_pms_w; + volatile pms_dma_ahb_pdma_dummy_r_pms_reg_t ahb_pdma_dummy_r_pms; + volatile pms_dma_ahb_pdma_dummy_w_pms_reg_t ahb_pdma_dummy_w_pms; + volatile pms_dma_axi_pdma_dummy_r_pms_reg_t axi_pdma_dummy_r_pms; + volatile pms_dma_axi_pdma_dummy_w_pms_reg_t axi_pdma_dummy_w_pms; +} pms_dma_dev_t; + +extern pms_dma_dev_t DMA_PMS; #ifndef __cplusplus -_Static_assert(sizeof(tee_dev_t) == 0x224, "Invalid size of tee_dev_t structure"); +_Static_assert(sizeof(pms_dma_dev_t) == 0x224, "Invalid size of pms_dma_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h index 29586b4b687..e4135f4f897 100644 --- a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,740 +11,958 @@ extern "C" { #endif -/** TEE_HP2LP_TEE_PMS_DATE_REG register - * NA +/** PMS_HP2LP_PERI_PMS_DATE_REG register + * Version control register */ -#define TEE_HP2LP_TEE_PMS_DATE_REG (DR_REG_TEE_BASE + 0x0) -/** TEE_TEE_DATE : R/W; bitpos: [31:0]; default: 2294790; - * NA +#define PMS_HP2LP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +/** PMS_HP2LP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294790; + * Version control register */ -#define TEE_TEE_DATE 0xFFFFFFFFU -#define TEE_TEE_DATE_M (TEE_TEE_DATE_V << TEE_TEE_DATE_S) -#define TEE_TEE_DATE_V 0xFFFFFFFFU -#define TEE_TEE_DATE_S 0 +#define PMS_HP2LP_PERI_PMS_DATE 0xFFFFFFFFU +#define PMS_HP2LP_PERI_PMS_DATE_M (PMS_HP2LP_PERI_PMS_DATE_V << PMS_HP2LP_PERI_PMS_DATE_S) +#define PMS_HP2LP_PERI_PMS_DATE_V 0xFFFFFFFFU +#define PMS_HP2LP_PERI_PMS_DATE_S 0 -/** TEE_PMS_CLK_EN_REG register - * NA - */ -#define TEE_PMS_CLK_EN_REG (DR_REG_TEE_BASE + 0x4) -/** TEE_REG_CLK_EN : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CLK_EN (BIT(0)) -#define TEE_REG_CLK_EN_M (TEE_REG_CLK_EN_V << TEE_REG_CLK_EN_S) -#define TEE_REG_CLK_EN_V 0x00000001U -#define TEE_REG_CLK_EN_S 0 +/** PMS_HP2LP_PERI_PMS_CLK_EN_REG register + * Clock gating register + */ +#define PMS_HP2LP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +/** PMS_HP2LP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on + */ +#define PMS_HP2LP_PERI_PMS_CLK_EN (BIT(0)) +#define PMS_HP2LP_PERI_PMS_CLK_EN_M (PMS_HP2LP_PERI_PMS_CLK_EN_V << PMS_HP2LP_PERI_PMS_CLK_EN_S) +#define PMS_HP2LP_PERI_PMS_CLK_EN_V 0x00000001U +#define PMS_HP2LP_PERI_PMS_CLK_EN_S 0 -/** TEE_HP_CORE0_MM_PMS_REG0_REG register - * NA - */ -#define TEE_HP_CORE0_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x8) -/** TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW (BIT(0)) -#define TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_SYSREG_ALLOW_S 0 -/** TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW (BIT(1)) -#define TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_AONCLKRST_ALLOW_S 1 -/** TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW (BIT(2)) -#define TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_TIMER_ALLOW_S 2 -/** TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW (BIT(3)) -#define TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_ANAPERI_ALLOW_S 3 -/** TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW (BIT(4)) -#define TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_PMU_ALLOW_S 4 -/** TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW (BIT(5)) -#define TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_WDT_ALLOW_S 5 -/** TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW (BIT(6)) -#define TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_MAILBOX_ALLOW_S 6 -/** TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW (BIT(7)) -#define TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_RTC_ALLOW_S 7 -/** TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW (BIT(8)) -#define TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_PERICLKRST_ALLOW_S 8 -/** TEE_REG_HP_CORE0_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_UART_ALLOW (BIT(9)) -#define TEE_REG_HP_CORE0_MM_LP_UART_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_UART_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_UART_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_UART_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_UART_ALLOW_S 9 -/** TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW (BIT(10)) -#define TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_I2C_ALLOW_S 10 -/** TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW (BIT(11)) -#define TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_SPI_ALLOW_S 11 -/** TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW (BIT(12)) -#define TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_I2CMST_ALLOW_S 12 -/** TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW (BIT(13)) -#define TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_I2S_ALLOW_S 13 -/** TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW (BIT(14)) -#define TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_ADC_ALLOW_S 14 -/** TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW (BIT(15)) -#define TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_TOUCH_ALLOW_S 15 -/** TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW (BIT(16)) -#define TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_IOMUX_ALLOW_S 16 -/** TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW (BIT(17)) -#define TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_INTR_ALLOW_S 17 -/** TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW (BIT(18)) -#define TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_EFUSE_ALLOW_S 18 -/** TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW (BIT(19)) -#define TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_PMS_ALLOW_S 19 -/** TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW (BIT(20)) -#define TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW_M (TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW_V << TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_HP2LP_PMS_ALLOW_S 20 -/** TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW (BIT(21)) -#define TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_TSENS_ALLOW_S 21 -/** TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW (BIT(22)) -#define TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_HUK_ALLOW_S 22 -/** TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW (BIT(23)) -#define TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW_M (TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW_V << TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW_S) -#define TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_MM_LP_TCM_RAM_ALLOW_S 23 +/** PMS_HP_CORE0_MM_PMS_REG0_REG register + * Permission control register0 for HP CPU0 in machine mode + */ +#define PMS_HP_CORE0_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +/** PMS_HP_CORE0_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_SYSREG_ALLOW (BIT(0)) +#define PMS_HP_CORE0_MM_LP_SYSREG_ALLOW_M (PMS_HP_CORE0_MM_LP_SYSREG_ALLOW_V << PMS_HP_CORE0_MM_LP_SYSREG_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_SYSREG_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_SYSREG_ALLOW_S 0 +/** PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW (BIT(1)) +#define PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW_M (PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW_V << PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_AONCLKRST_ALLOW_S 1 +/** PMS_HP_CORE0_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_TIMER_ALLOW (BIT(2)) +#define PMS_HP_CORE0_MM_LP_TIMER_ALLOW_M (PMS_HP_CORE0_MM_LP_TIMER_ALLOW_V << PMS_HP_CORE0_MM_LP_TIMER_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_TIMER_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_TIMER_ALLOW_S 2 +/** PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW (BIT(3)) +#define PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW_M (PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW_V << PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_ANAPERI_ALLOW_S 3 +/** PMS_HP_CORE0_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_PMU_ALLOW (BIT(4)) +#define PMS_HP_CORE0_MM_LP_PMU_ALLOW_M (PMS_HP_CORE0_MM_LP_PMU_ALLOW_V << PMS_HP_CORE0_MM_LP_PMU_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_PMU_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_PMU_ALLOW_S 4 +/** PMS_HP_CORE0_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_WDT_ALLOW (BIT(5)) +#define PMS_HP_CORE0_MM_LP_WDT_ALLOW_M (PMS_HP_CORE0_MM_LP_WDT_ALLOW_V << PMS_HP_CORE0_MM_LP_WDT_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_WDT_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_WDT_ALLOW_S 5 +/** PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW (BIT(6)) +#define PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW_M (PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW_V << PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_MAILBOX_ALLOW_S 6 +/** PMS_HP_CORE0_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE0_MM_LP_RTC_ALLOW (BIT(7)) +#define PMS_HP_CORE0_MM_LP_RTC_ALLOW_M (PMS_HP_CORE0_MM_LP_RTC_ALLOW_V << PMS_HP_CORE0_MM_LP_RTC_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_RTC_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_RTC_ALLOW_S 7 +/** PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW (BIT(8)) +#define PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW_M (PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW_V << PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_PERICLKRST_ALLOW_S 8 +/** PMS_HP_CORE0_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_UART_ALLOW (BIT(9)) +#define PMS_HP_CORE0_MM_LP_UART_ALLOW_M (PMS_HP_CORE0_MM_LP_UART_ALLOW_V << PMS_HP_CORE0_MM_LP_UART_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_UART_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_UART_ALLOW_S 9 +/** PMS_HP_CORE0_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_I2C_ALLOW (BIT(10)) +#define PMS_HP_CORE0_MM_LP_I2C_ALLOW_M (PMS_HP_CORE0_MM_LP_I2C_ALLOW_V << PMS_HP_CORE0_MM_LP_I2C_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_I2C_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_I2C_ALLOW_S 10 +/** PMS_HP_CORE0_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_SPI_ALLOW (BIT(11)) +#define PMS_HP_CORE0_MM_LP_SPI_ALLOW_M (PMS_HP_CORE0_MM_LP_SPI_ALLOW_V << PMS_HP_CORE0_MM_LP_SPI_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_SPI_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_SPI_ALLOW_S 11 +/** PMS_HP_CORE0_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_I2CMST_ALLOW (BIT(12)) +#define PMS_HP_CORE0_MM_LP_I2CMST_ALLOW_M (PMS_HP_CORE0_MM_LP_I2CMST_ALLOW_V << PMS_HP_CORE0_MM_LP_I2CMST_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_I2CMST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_I2CMST_ALLOW_S 12 +/** PMS_HP_CORE0_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_I2S_ALLOW (BIT(13)) +#define PMS_HP_CORE0_MM_LP_I2S_ALLOW_M (PMS_HP_CORE0_MM_LP_I2S_ALLOW_V << PMS_HP_CORE0_MM_LP_I2S_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_I2S_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_I2S_ALLOW_S 13 +/** PMS_HP_CORE0_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_ADC_ALLOW (BIT(14)) +#define PMS_HP_CORE0_MM_LP_ADC_ALLOW_M (PMS_HP_CORE0_MM_LP_ADC_ALLOW_V << PMS_HP_CORE0_MM_LP_ADC_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_ADC_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_ADC_ALLOW_S 14 +/** PMS_HP_CORE0_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP touch + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_TOUCH_ALLOW (BIT(15)) +#define PMS_HP_CORE0_MM_LP_TOUCH_ALLOW_M (PMS_HP_CORE0_MM_LP_TOUCH_ALLOW_V << PMS_HP_CORE0_MM_LP_TOUCH_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_TOUCH_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_TOUCH_ALLOW_S 15 +/** PMS_HP_CORE0_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_IOMUX_ALLOW (BIT(16)) +#define PMS_HP_CORE0_MM_LP_IOMUX_ALLOW_M (PMS_HP_CORE0_MM_LP_IOMUX_ALLOW_V << PMS_HP_CORE0_MM_LP_IOMUX_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_IOMUX_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_IOMUX_ALLOW_S 16 +/** PMS_HP_CORE0_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_INTR_ALLOW (BIT(17)) +#define PMS_HP_CORE0_MM_LP_INTR_ALLOW_M (PMS_HP_CORE0_MM_LP_INTR_ALLOW_V << PMS_HP_CORE0_MM_LP_INTR_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_INTR_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_INTR_ALLOW_S 17 +/** PMS_HP_CORE0_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_EFUSE_ALLOW (BIT(18)) +#define PMS_HP_CORE0_MM_LP_EFUSE_ALLOW_M (PMS_HP_CORE0_MM_LP_EFUSE_ALLOW_V << PMS_HP_CORE0_MM_LP_EFUSE_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_EFUSE_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_EFUSE_ALLOW_S 18 +/** PMS_HP_CORE0_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access + * LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_PMS_ALLOW (BIT(19)) +#define PMS_HP_CORE0_MM_LP_PMS_ALLOW_M (PMS_HP_CORE0_MM_LP_PMS_ALLOW_V << PMS_HP_CORE0_MM_LP_PMS_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_PMS_ALLOW_S 19 +/** PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW (BIT(20)) +#define PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW_M (PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW_V << PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW_S) +#define PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_HP2LP_PMS_ALLOW_S 20 +/** PMS_HP_CORE0_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_TSENS_ALLOW (BIT(21)) +#define PMS_HP_CORE0_MM_LP_TSENS_ALLOW_M (PMS_HP_CORE0_MM_LP_TSENS_ALLOW_V << PMS_HP_CORE0_MM_LP_TSENS_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_TSENS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_TSENS_ALLOW_S 21 +/** PMS_HP_CORE0_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_HUK_ALLOW (BIT(22)) +#define PMS_HP_CORE0_MM_LP_HUK_ALLOW_M (PMS_HP_CORE0_MM_LP_HUK_ALLOW_V << PMS_HP_CORE0_MM_LP_HUK_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_HUK_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_HUK_ALLOW_S 22 +/** PMS_HP_CORE0_MM_LP_SRAM_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_MM_LP_SRAM_ALLOW (BIT(23)) +#define PMS_HP_CORE0_MM_LP_SRAM_ALLOW_M (PMS_HP_CORE0_MM_LP_SRAM_ALLOW_V << PMS_HP_CORE0_MM_LP_SRAM_ALLOW_S) +#define PMS_HP_CORE0_MM_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_MM_LP_SRAM_ALLOW_S 23 -/** TEE_HP_CORE0_UM_PMS_REG0_REG register - * NA - */ -#define TEE_HP_CORE0_UM_PMS_REG0_REG (DR_REG_TEE_BASE + 0xc) -/** TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW (BIT(0)) -#define TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_SYSREG_ALLOW_S 0 -/** TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW (BIT(1)) -#define TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_AONCLKRST_ALLOW_S 1 -/** TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW (BIT(2)) -#define TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_TIMER_ALLOW_S 2 -/** TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW (BIT(3)) -#define TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_ANAPERI_ALLOW_S 3 -/** TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW (BIT(4)) -#define TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_PMU_ALLOW_S 4 -/** TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW (BIT(5)) -#define TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_WDT_ALLOW_S 5 -/** TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW (BIT(6)) -#define TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_MAILBOX_ALLOW_S 6 -/** TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW (BIT(7)) -#define TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_RTC_ALLOW_S 7 -/** TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW (BIT(8)) -#define TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_PERICLKRST_ALLOW_S 8 -/** TEE_REG_HP_CORE0_UM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_UART_ALLOW (BIT(9)) -#define TEE_REG_HP_CORE0_UM_LP_UART_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_UART_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_UART_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_UART_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_UART_ALLOW_S 9 -/** TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW (BIT(10)) -#define TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_I2C_ALLOW_S 10 -/** TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW (BIT(11)) -#define TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_SPI_ALLOW_S 11 -/** TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW (BIT(12)) -#define TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_I2CMST_ALLOW_S 12 -/** TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW (BIT(13)) -#define TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_I2S_ALLOW_S 13 -/** TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW (BIT(14)) -#define TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_ADC_ALLOW_S 14 -/** TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW (BIT(15)) -#define TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_TOUCH_ALLOW_S 15 -/** TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW (BIT(16)) -#define TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_IOMUX_ALLOW_S 16 -/** TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW (BIT(17)) -#define TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_INTR_ALLOW_S 17 -/** TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW (BIT(18)) -#define TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_EFUSE_ALLOW_S 18 -/** TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW (BIT(19)) -#define TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_PMS_ALLOW_S 19 -/** TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW (BIT(20)) -#define TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW_M (TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW_V << TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_HP2LP_PMS_ALLOW_S 20 -/** TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW (BIT(21)) -#define TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_TSENS_ALLOW_S 21 -/** TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW (BIT(22)) -#define TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_HUK_ALLOW_S 22 -/** TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW (BIT(23)) -#define TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW_M (TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW_V << TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW_S) -#define TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE0_UM_LP_TCM_RAM_ALLOW_S 23 +/** PMS_HP_CORE0_UM_PMS_REG0_REG register + * Permission control register0 for HP CPU0 in user mode + */ +#define PMS_HP_CORE0_UM_PMS_REG0_REG (DR_REG_PMS_BASE + 0xc) +/** PMS_HP_CORE0_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_SYSREG_ALLOW (BIT(0)) +#define PMS_HP_CORE0_UM_LP_SYSREG_ALLOW_M (PMS_HP_CORE0_UM_LP_SYSREG_ALLOW_V << PMS_HP_CORE0_UM_LP_SYSREG_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_SYSREG_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_SYSREG_ALLOW_S 0 +/** PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW (BIT(1)) +#define PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW_M (PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW_V << PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_AONCLKRST_ALLOW_S 1 +/** PMS_HP_CORE0_UM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_TIMER_ALLOW (BIT(2)) +#define PMS_HP_CORE0_UM_LP_TIMER_ALLOW_M (PMS_HP_CORE0_UM_LP_TIMER_ALLOW_V << PMS_HP_CORE0_UM_LP_TIMER_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_TIMER_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_TIMER_ALLOW_S 2 +/** PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW (BIT(3)) +#define PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW_M (PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW_V << PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_ANAPERI_ALLOW_S 3 +/** PMS_HP_CORE0_UM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_PMU_ALLOW (BIT(4)) +#define PMS_HP_CORE0_UM_LP_PMU_ALLOW_M (PMS_HP_CORE0_UM_LP_PMU_ALLOW_V << PMS_HP_CORE0_UM_LP_PMU_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_PMU_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_PMU_ALLOW_S 4 +/** PMS_HP_CORE0_UM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_WDT_ALLOW (BIT(5)) +#define PMS_HP_CORE0_UM_LP_WDT_ALLOW_M (PMS_HP_CORE0_UM_LP_WDT_ALLOW_V << PMS_HP_CORE0_UM_LP_WDT_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_WDT_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_WDT_ALLOW_S 5 +/** PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW (BIT(6)) +#define PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW_M (PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW_V << PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_MAILBOX_ALLOW_S 6 +/** PMS_HP_CORE0_UM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE0_UM_LP_RTC_ALLOW (BIT(7)) +#define PMS_HP_CORE0_UM_LP_RTC_ALLOW_M (PMS_HP_CORE0_UM_LP_RTC_ALLOW_V << PMS_HP_CORE0_UM_LP_RTC_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_RTC_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_RTC_ALLOW_S 7 +/** PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW (BIT(8)) +#define PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW_M (PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW_V << PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_PERICLKRST_ALLOW_S 8 +/** PMS_HP_CORE0_UM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_UART_ALLOW (BIT(9)) +#define PMS_HP_CORE0_UM_LP_UART_ALLOW_M (PMS_HP_CORE0_UM_LP_UART_ALLOW_V << PMS_HP_CORE0_UM_LP_UART_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_UART_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_UART_ALLOW_S 9 +/** PMS_HP_CORE0_UM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_I2C_ALLOW (BIT(10)) +#define PMS_HP_CORE0_UM_LP_I2C_ALLOW_M (PMS_HP_CORE0_UM_LP_I2C_ALLOW_V << PMS_HP_CORE0_UM_LP_I2C_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_I2C_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_I2C_ALLOW_S 10 +/** PMS_HP_CORE0_UM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_SPI_ALLOW (BIT(11)) +#define PMS_HP_CORE0_UM_LP_SPI_ALLOW_M (PMS_HP_CORE0_UM_LP_SPI_ALLOW_V << PMS_HP_CORE0_UM_LP_SPI_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_SPI_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_SPI_ALLOW_S 11 +/** PMS_HP_CORE0_UM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_I2CMST_ALLOW (BIT(12)) +#define PMS_HP_CORE0_UM_LP_I2CMST_ALLOW_M (PMS_HP_CORE0_UM_LP_I2CMST_ALLOW_V << PMS_HP_CORE0_UM_LP_I2CMST_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_I2CMST_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_I2CMST_ALLOW_S 12 +/** PMS_HP_CORE0_UM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_I2S_ALLOW (BIT(13)) +#define PMS_HP_CORE0_UM_LP_I2S_ALLOW_M (PMS_HP_CORE0_UM_LP_I2S_ALLOW_V << PMS_HP_CORE0_UM_LP_I2S_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_I2S_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_I2S_ALLOW_S 13 +/** PMS_HP_CORE0_UM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_ADC_ALLOW (BIT(14)) +#define PMS_HP_CORE0_UM_LP_ADC_ALLOW_M (PMS_HP_CORE0_UM_LP_ADC_ALLOW_V << PMS_HP_CORE0_UM_LP_ADC_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_ADC_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_ADC_ALLOW_S 14 +/** PMS_HP_CORE0_UM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP touch sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_TOUCH_ALLOW (BIT(15)) +#define PMS_HP_CORE0_UM_LP_TOUCH_ALLOW_M (PMS_HP_CORE0_UM_LP_TOUCH_ALLOW_V << PMS_HP_CORE0_UM_LP_TOUCH_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_TOUCH_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_TOUCH_ALLOW_S 15 +/** PMS_HP_CORE0_UM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_IOMUX_ALLOW (BIT(16)) +#define PMS_HP_CORE0_UM_LP_IOMUX_ALLOW_M (PMS_HP_CORE0_UM_LP_IOMUX_ALLOW_V << PMS_HP_CORE0_UM_LP_IOMUX_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_IOMUX_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_IOMUX_ALLOW_S 16 +/** PMS_HP_CORE0_UM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_INTR_ALLOW (BIT(17)) +#define PMS_HP_CORE0_UM_LP_INTR_ALLOW_M (PMS_HP_CORE0_UM_LP_INTR_ALLOW_V << PMS_HP_CORE0_UM_LP_INTR_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_INTR_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_INTR_ALLOW_S 17 +/** PMS_HP_CORE0_UM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_EFUSE_ALLOW (BIT(18)) +#define PMS_HP_CORE0_UM_LP_EFUSE_ALLOW_M (PMS_HP_CORE0_UM_LP_EFUSE_ALLOW_V << PMS_HP_CORE0_UM_LP_EFUSE_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_EFUSE_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_EFUSE_ALLOW_S 18 +/** PMS_HP_CORE0_UM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_PMS_ALLOW (BIT(19)) +#define PMS_HP_CORE0_UM_LP_PMS_ALLOW_M (PMS_HP_CORE0_UM_LP_PMS_ALLOW_V << PMS_HP_CORE0_UM_LP_PMS_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_PMS_ALLOW_S 19 +/** PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW (BIT(20)) +#define PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW_M (PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW_V << PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW_S) +#define PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_HP2LP_PMS_ALLOW_S 20 +/** PMS_HP_CORE0_UM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_TSENS_ALLOW (BIT(21)) +#define PMS_HP_CORE0_UM_LP_TSENS_ALLOW_M (PMS_HP_CORE0_UM_LP_TSENS_ALLOW_V << PMS_HP_CORE0_UM_LP_TSENS_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_TSENS_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_TSENS_ALLOW_S 21 +/** PMS_HP_CORE0_UM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in user mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_HUK_ALLOW (BIT(22)) +#define PMS_HP_CORE0_UM_LP_HUK_ALLOW_M (PMS_HP_CORE0_UM_LP_HUK_ALLOW_V << PMS_HP_CORE0_UM_LP_HUK_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_HUK_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_HUK_ALLOW_S 22 +/** PMS_HP_CORE0_UM_LP_SRAM_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE0_UM_LP_SRAM_ALLOW (BIT(23)) +#define PMS_HP_CORE0_UM_LP_SRAM_ALLOW_M (PMS_HP_CORE0_UM_LP_SRAM_ALLOW_V << PMS_HP_CORE0_UM_LP_SRAM_ALLOW_S) +#define PMS_HP_CORE0_UM_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_HP_CORE0_UM_LP_SRAM_ALLOW_S 23 -/** TEE_HP_CORE1_MM_PMS_REG0_REG register - * NA - */ -#define TEE_HP_CORE1_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x10) -/** TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW (BIT(0)) -#define TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_SYSREG_ALLOW_S 0 -/** TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW (BIT(1)) -#define TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_AONCLKRST_ALLOW_S 1 -/** TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW (BIT(2)) -#define TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_TIMER_ALLOW_S 2 -/** TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW (BIT(3)) -#define TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_ANAPERI_ALLOW_S 3 -/** TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW (BIT(4)) -#define TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_PMU_ALLOW_S 4 -/** TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW (BIT(5)) -#define TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_WDT_ALLOW_S 5 -/** TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW (BIT(6)) -#define TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_MAILBOX_ALLOW_S 6 -/** TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW (BIT(7)) -#define TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_RTC_ALLOW_S 7 -/** TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW (BIT(8)) -#define TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_PERICLKRST_ALLOW_S 8 -/** TEE_REG_HP_CORE1_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_UART_ALLOW (BIT(9)) -#define TEE_REG_HP_CORE1_MM_LP_UART_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_UART_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_UART_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_UART_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_UART_ALLOW_S 9 -/** TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW (BIT(10)) -#define TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_I2C_ALLOW_S 10 -/** TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW (BIT(11)) -#define TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_SPI_ALLOW_S 11 -/** TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW (BIT(12)) -#define TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_I2CMST_ALLOW_S 12 -/** TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW (BIT(13)) -#define TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_I2S_ALLOW_S 13 -/** TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW (BIT(14)) -#define TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_ADC_ALLOW_S 14 -/** TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW (BIT(15)) -#define TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_TOUCH_ALLOW_S 15 -/** TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW (BIT(16)) -#define TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_IOMUX_ALLOW_S 16 -/** TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW (BIT(17)) -#define TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_INTR_ALLOW_S 17 -/** TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW (BIT(18)) -#define TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_EFUSE_ALLOW_S 18 -/** TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW (BIT(19)) -#define TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_PMS_ALLOW_S 19 -/** TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW (BIT(20)) -#define TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW_M (TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW_V << TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_HP2LP_PMS_ALLOW_S 20 -/** TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW (BIT(21)) -#define TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_TSENS_ALLOW_S 21 -/** TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW (BIT(22)) -#define TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_HUK_ALLOW_S 22 -/** TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW (BIT(23)) -#define TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW_M (TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW_V << TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW_S) -#define TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_MM_LP_TCM_RAM_ALLOW_S 23 +/** PMS_HP_CORE1_MM_PMS_REG0_REG register + * Permission control register0 for HP CPU1 in machine mode + */ +#define PMS_HP_CORE1_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x10) +/** PMS_HP_CORE1_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_SYSREG_ALLOW (BIT(0)) +#define PMS_HP_CORE1_MM_LP_SYSREG_ALLOW_M (PMS_HP_CORE1_MM_LP_SYSREG_ALLOW_V << PMS_HP_CORE1_MM_LP_SYSREG_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_SYSREG_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_SYSREG_ALLOW_S 0 +/** PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW (BIT(1)) +#define PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW_M (PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW_V << PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_AONCLKRST_ALLOW_S 1 +/** PMS_HP_CORE1_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_TIMER_ALLOW (BIT(2)) +#define PMS_HP_CORE1_MM_LP_TIMER_ALLOW_M (PMS_HP_CORE1_MM_LP_TIMER_ALLOW_V << PMS_HP_CORE1_MM_LP_TIMER_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_TIMER_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_TIMER_ALLOW_S 2 +/** PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW (BIT(3)) +#define PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW_M (PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW_V << PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_ANAPERI_ALLOW_S 3 +/** PMS_HP_CORE1_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_PMU_ALLOW (BIT(4)) +#define PMS_HP_CORE1_MM_LP_PMU_ALLOW_M (PMS_HP_CORE1_MM_LP_PMU_ALLOW_V << PMS_HP_CORE1_MM_LP_PMU_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_PMU_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_PMU_ALLOW_S 4 +/** PMS_HP_CORE1_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_WDT_ALLOW (BIT(5)) +#define PMS_HP_CORE1_MM_LP_WDT_ALLOW_M (PMS_HP_CORE1_MM_LP_WDT_ALLOW_V << PMS_HP_CORE1_MM_LP_WDT_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_WDT_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_WDT_ALLOW_S 5 +/** PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW (BIT(6)) +#define PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW_M (PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW_V << PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_MAILBOX_ALLOW_S 6 +/** PMS_HP_CORE1_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE1_MM_LP_RTC_ALLOW (BIT(7)) +#define PMS_HP_CORE1_MM_LP_RTC_ALLOW_M (PMS_HP_CORE1_MM_LP_RTC_ALLOW_V << PMS_HP_CORE1_MM_LP_RTC_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_RTC_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_RTC_ALLOW_S 7 +/** PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW (BIT(8)) +#define PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW_M (PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW_V << PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_PERICLKRST_ALLOW_S 8 +/** PMS_HP_CORE1_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_UART_ALLOW (BIT(9)) +#define PMS_HP_CORE1_MM_LP_UART_ALLOW_M (PMS_HP_CORE1_MM_LP_UART_ALLOW_V << PMS_HP_CORE1_MM_LP_UART_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_UART_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_UART_ALLOW_S 9 +/** PMS_HP_CORE1_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_I2C_ALLOW (BIT(10)) +#define PMS_HP_CORE1_MM_LP_I2C_ALLOW_M (PMS_HP_CORE1_MM_LP_I2C_ALLOW_V << PMS_HP_CORE1_MM_LP_I2C_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_I2C_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_I2C_ALLOW_S 10 +/** PMS_HP_CORE1_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_SPI_ALLOW (BIT(11)) +#define PMS_HP_CORE1_MM_LP_SPI_ALLOW_M (PMS_HP_CORE1_MM_LP_SPI_ALLOW_V << PMS_HP_CORE1_MM_LP_SPI_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_SPI_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_SPI_ALLOW_S 11 +/** PMS_HP_CORE1_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_I2CMST_ALLOW (BIT(12)) +#define PMS_HP_CORE1_MM_LP_I2CMST_ALLOW_M (PMS_HP_CORE1_MM_LP_I2CMST_ALLOW_V << PMS_HP_CORE1_MM_LP_I2CMST_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_I2CMST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_I2CMST_ALLOW_S 12 +/** PMS_HP_CORE1_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_I2S_ALLOW (BIT(13)) +#define PMS_HP_CORE1_MM_LP_I2S_ALLOW_M (PMS_HP_CORE1_MM_LP_I2S_ALLOW_V << PMS_HP_CORE1_MM_LP_I2S_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_I2S_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_I2S_ALLOW_S 13 +/** PMS_HP_CORE1_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_ADC_ALLOW (BIT(14)) +#define PMS_HP_CORE1_MM_LP_ADC_ALLOW_M (PMS_HP_CORE1_MM_LP_ADC_ALLOW_V << PMS_HP_CORE1_MM_LP_ADC_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_ADC_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_ADC_ALLOW_S 14 +/** PMS_HP_CORE1_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP touch + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_TOUCH_ALLOW (BIT(15)) +#define PMS_HP_CORE1_MM_LP_TOUCH_ALLOW_M (PMS_HP_CORE1_MM_LP_TOUCH_ALLOW_V << PMS_HP_CORE1_MM_LP_TOUCH_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_TOUCH_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_TOUCH_ALLOW_S 15 +/** PMS_HP_CORE1_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_IOMUX_ALLOW (BIT(16)) +#define PMS_HP_CORE1_MM_LP_IOMUX_ALLOW_M (PMS_HP_CORE1_MM_LP_IOMUX_ALLOW_V << PMS_HP_CORE1_MM_LP_IOMUX_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_IOMUX_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_IOMUX_ALLOW_S 16 +/** PMS_HP_CORE1_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_INTR_ALLOW (BIT(17)) +#define PMS_HP_CORE1_MM_LP_INTR_ALLOW_M (PMS_HP_CORE1_MM_LP_INTR_ALLOW_V << PMS_HP_CORE1_MM_LP_INTR_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_INTR_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_INTR_ALLOW_S 17 +/** PMS_HP_CORE1_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_EFUSE_ALLOW (BIT(18)) +#define PMS_HP_CORE1_MM_LP_EFUSE_ALLOW_M (PMS_HP_CORE1_MM_LP_EFUSE_ALLOW_V << PMS_HP_CORE1_MM_LP_EFUSE_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_EFUSE_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_EFUSE_ALLOW_S 18 +/** PMS_HP_CORE1_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access + * LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_PMS_ALLOW (BIT(19)) +#define PMS_HP_CORE1_MM_LP_PMS_ALLOW_M (PMS_HP_CORE1_MM_LP_PMS_ALLOW_V << PMS_HP_CORE1_MM_LP_PMS_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_PMS_ALLOW_S 19 +/** PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW (BIT(20)) +#define PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW_M (PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW_V << PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW_S) +#define PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_HP2LP_PMS_ALLOW_S 20 +/** PMS_HP_CORE1_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_TSENS_ALLOW (BIT(21)) +#define PMS_HP_CORE1_MM_LP_TSENS_ALLOW_M (PMS_HP_CORE1_MM_LP_TSENS_ALLOW_V << PMS_HP_CORE1_MM_LP_TSENS_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_TSENS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_TSENS_ALLOW_S 21 +/** PMS_HP_CORE1_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_HUK_ALLOW (BIT(22)) +#define PMS_HP_CORE1_MM_LP_HUK_ALLOW_M (PMS_HP_CORE1_MM_LP_HUK_ALLOW_V << PMS_HP_CORE1_MM_LP_HUK_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_HUK_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_HUK_ALLOW_S 22 +/** PMS_HP_CORE1_MM_LP_SRAM_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_MM_LP_SRAM_ALLOW (BIT(23)) +#define PMS_HP_CORE1_MM_LP_SRAM_ALLOW_M (PMS_HP_CORE1_MM_LP_SRAM_ALLOW_V << PMS_HP_CORE1_MM_LP_SRAM_ALLOW_S) +#define PMS_HP_CORE1_MM_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_MM_LP_SRAM_ALLOW_S 23 -/** TEE_HP_CORE1_UM_PMS_REG0_REG register - * NA - */ -#define TEE_HP_CORE1_UM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x14) -/** TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW (BIT(0)) -#define TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_SYSREG_ALLOW_S 0 -/** TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW (BIT(1)) -#define TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_AONCLKRST_ALLOW_S 1 -/** TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW (BIT(2)) -#define TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_TIMER_ALLOW_S 2 -/** TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW (BIT(3)) -#define TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_ANAPERI_ALLOW_S 3 -/** TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW (BIT(4)) -#define TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_PMU_ALLOW_S 4 -/** TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW (BIT(5)) -#define TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_WDT_ALLOW_S 5 -/** TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW (BIT(6)) -#define TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_MAILBOX_ALLOW_S 6 -/** TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW (BIT(7)) -#define TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_RTC_ALLOW_S 7 -/** TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW (BIT(8)) -#define TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_PERICLKRST_ALLOW_S 8 -/** TEE_REG_HP_CORE1_UM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_UART_ALLOW (BIT(9)) -#define TEE_REG_HP_CORE1_UM_LP_UART_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_UART_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_UART_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_UART_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_UART_ALLOW_S 9 -/** TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW (BIT(10)) -#define TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_I2C_ALLOW_S 10 -/** TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW (BIT(11)) -#define TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_SPI_ALLOW_S 11 -/** TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW (BIT(12)) -#define TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_I2CMST_ALLOW_S 12 -/** TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW (BIT(13)) -#define TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_I2S_ALLOW_S 13 -/** TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW (BIT(14)) -#define TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_ADC_ALLOW_S 14 -/** TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW (BIT(15)) -#define TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_TOUCH_ALLOW_S 15 -/** TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW (BIT(16)) -#define TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_IOMUX_ALLOW_S 16 -/** TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW (BIT(17)) -#define TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_INTR_ALLOW_S 17 -/** TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW (BIT(18)) -#define TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_EFUSE_ALLOW_S 18 -/** TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW (BIT(19)) -#define TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_PMS_ALLOW_S 19 -/** TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW (BIT(20)) -#define TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW_M (TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW_V << TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_HP2LP_PMS_ALLOW_S 20 -/** TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW (BIT(21)) -#define TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_TSENS_ALLOW_S 21 -/** TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW (BIT(22)) -#define TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_HUK_ALLOW_S 22 -/** TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW (BIT(23)) -#define TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW_M (TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW_V << TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW_S) -#define TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW_V 0x00000001U -#define TEE_REG_HP_CORE1_UM_LP_TCM_RAM_ALLOW_S 23 +/** PMS_HP_CORE1_UM_PMS_REG0_REG register + * Permission control register0 for HP CPU1 in user mode + */ +#define PMS_HP_CORE1_UM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x14) +/** PMS_HP_CORE1_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_SYSREG_ALLOW (BIT(0)) +#define PMS_HP_CORE1_UM_LP_SYSREG_ALLOW_M (PMS_HP_CORE1_UM_LP_SYSREG_ALLOW_V << PMS_HP_CORE1_UM_LP_SYSREG_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_SYSREG_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_SYSREG_ALLOW_S 0 +/** PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW (BIT(1)) +#define PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW_M (PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW_V << PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_AONCLKRST_ALLOW_S 1 +/** PMS_HP_CORE1_UM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_TIMER_ALLOW (BIT(2)) +#define PMS_HP_CORE1_UM_LP_TIMER_ALLOW_M (PMS_HP_CORE1_UM_LP_TIMER_ALLOW_V << PMS_HP_CORE1_UM_LP_TIMER_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_TIMER_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_TIMER_ALLOW_S 2 +/** PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW (BIT(3)) +#define PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW_M (PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW_V << PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_ANAPERI_ALLOW_S 3 +/** PMS_HP_CORE1_UM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_PMU_ALLOW (BIT(4)) +#define PMS_HP_CORE1_UM_LP_PMU_ALLOW_M (PMS_HP_CORE1_UM_LP_PMU_ALLOW_V << PMS_HP_CORE1_UM_LP_PMU_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_PMU_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_PMU_ALLOW_S 4 +/** PMS_HP_CORE1_UM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_WDT_ALLOW (BIT(5)) +#define PMS_HP_CORE1_UM_LP_WDT_ALLOW_M (PMS_HP_CORE1_UM_LP_WDT_ALLOW_V << PMS_HP_CORE1_UM_LP_WDT_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_WDT_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_WDT_ALLOW_S 5 +/** PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW (BIT(6)) +#define PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW_M (PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW_V << PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_MAILBOX_ALLOW_S 6 +/** PMS_HP_CORE1_UM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE1_UM_LP_RTC_ALLOW (BIT(7)) +#define PMS_HP_CORE1_UM_LP_RTC_ALLOW_M (PMS_HP_CORE1_UM_LP_RTC_ALLOW_V << PMS_HP_CORE1_UM_LP_RTC_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_RTC_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_RTC_ALLOW_S 7 +/** PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW (BIT(8)) +#define PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW_M (PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW_V << PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_PERICLKRST_ALLOW_S 8 +/** PMS_HP_CORE1_UM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_UART_ALLOW (BIT(9)) +#define PMS_HP_CORE1_UM_LP_UART_ALLOW_M (PMS_HP_CORE1_UM_LP_UART_ALLOW_V << PMS_HP_CORE1_UM_LP_UART_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_UART_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_UART_ALLOW_S 9 +/** PMS_HP_CORE1_UM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_I2C_ALLOW (BIT(10)) +#define PMS_HP_CORE1_UM_LP_I2C_ALLOW_M (PMS_HP_CORE1_UM_LP_I2C_ALLOW_V << PMS_HP_CORE1_UM_LP_I2C_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_I2C_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_I2C_ALLOW_S 10 +/** PMS_HP_CORE1_UM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_SPI_ALLOW (BIT(11)) +#define PMS_HP_CORE1_UM_LP_SPI_ALLOW_M (PMS_HP_CORE1_UM_LP_SPI_ALLOW_V << PMS_HP_CORE1_UM_LP_SPI_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_SPI_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_SPI_ALLOW_S 11 +/** PMS_HP_CORE1_UM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_I2CMST_ALLOW (BIT(12)) +#define PMS_HP_CORE1_UM_LP_I2CMST_ALLOW_M (PMS_HP_CORE1_UM_LP_I2CMST_ALLOW_V << PMS_HP_CORE1_UM_LP_I2CMST_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_I2CMST_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_I2CMST_ALLOW_S 12 +/** PMS_HP_CORE1_UM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_I2S_ALLOW (BIT(13)) +#define PMS_HP_CORE1_UM_LP_I2S_ALLOW_M (PMS_HP_CORE1_UM_LP_I2S_ALLOW_V << PMS_HP_CORE1_UM_LP_I2S_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_I2S_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_I2S_ALLOW_S 13 +/** PMS_HP_CORE1_UM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_ADC_ALLOW (BIT(14)) +#define PMS_HP_CORE1_UM_LP_ADC_ALLOW_M (PMS_HP_CORE1_UM_LP_ADC_ALLOW_V << PMS_HP_CORE1_UM_LP_ADC_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_ADC_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_ADC_ALLOW_S 14 +/** PMS_HP_CORE1_UM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP touch sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_TOUCH_ALLOW (BIT(15)) +#define PMS_HP_CORE1_UM_LP_TOUCH_ALLOW_M (PMS_HP_CORE1_UM_LP_TOUCH_ALLOW_V << PMS_HP_CORE1_UM_LP_TOUCH_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_TOUCH_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_TOUCH_ALLOW_S 15 +/** PMS_HP_CORE1_UM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_IOMUX_ALLOW (BIT(16)) +#define PMS_HP_CORE1_UM_LP_IOMUX_ALLOW_M (PMS_HP_CORE1_UM_LP_IOMUX_ALLOW_V << PMS_HP_CORE1_UM_LP_IOMUX_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_IOMUX_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_IOMUX_ALLOW_S 16 +/** PMS_HP_CORE1_UM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_INTR_ALLOW (BIT(17)) +#define PMS_HP_CORE1_UM_LP_INTR_ALLOW_M (PMS_HP_CORE1_UM_LP_INTR_ALLOW_V << PMS_HP_CORE1_UM_LP_INTR_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_INTR_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_INTR_ALLOW_S 17 +/** PMS_HP_CORE1_UM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_EFUSE_ALLOW (BIT(18)) +#define PMS_HP_CORE1_UM_LP_EFUSE_ALLOW_M (PMS_HP_CORE1_UM_LP_EFUSE_ALLOW_V << PMS_HP_CORE1_UM_LP_EFUSE_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_EFUSE_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_EFUSE_ALLOW_S 18 +/** PMS_HP_CORE1_UM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_PMS_ALLOW (BIT(19)) +#define PMS_HP_CORE1_UM_LP_PMS_ALLOW_M (PMS_HP_CORE1_UM_LP_PMS_ALLOW_V << PMS_HP_CORE1_UM_LP_PMS_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_PMS_ALLOW_S 19 +/** PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW (BIT(20)) +#define PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW_M (PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW_V << PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW_S) +#define PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_HP2LP_PMS_ALLOW_S 20 +/** PMS_HP_CORE1_UM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_TSENS_ALLOW (BIT(21)) +#define PMS_HP_CORE1_UM_LP_TSENS_ALLOW_M (PMS_HP_CORE1_UM_LP_TSENS_ALLOW_V << PMS_HP_CORE1_UM_LP_TSENS_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_TSENS_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_TSENS_ALLOW_S 21 +/** PMS_HP_CORE1_UM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in user mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_HUK_ALLOW (BIT(22)) +#define PMS_HP_CORE1_UM_LP_HUK_ALLOW_M (PMS_HP_CORE1_UM_LP_HUK_ALLOW_V << PMS_HP_CORE1_UM_LP_HUK_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_HUK_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_HUK_ALLOW_S 22 +/** PMS_HP_CORE1_UM_LP_SRAM_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_HP_CORE1_UM_LP_SRAM_ALLOW (BIT(23)) +#define PMS_HP_CORE1_UM_LP_SRAM_ALLOW_M (PMS_HP_CORE1_UM_LP_SRAM_ALLOW_V << PMS_HP_CORE1_UM_LP_SRAM_ALLOW_S) +#define PMS_HP_CORE1_UM_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_HP_CORE1_UM_LP_SRAM_ALLOW_S 23 -/** TEE_REGDMA_PERI_PMS_REG register - * NA - */ -#define TEE_REGDMA_PERI_PMS_REG (DR_REG_TEE_BASE + 0x18) -/** TEE_REG_REGDMA_PERI_LP_RAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_REGDMA_PERI_LP_RAM_ALLOW (BIT(0)) -#define TEE_REG_REGDMA_PERI_LP_RAM_ALLOW_M (TEE_REG_REGDMA_PERI_LP_RAM_ALLOW_V << TEE_REG_REGDMA_PERI_LP_RAM_ALLOW_S) -#define TEE_REG_REGDMA_PERI_LP_RAM_ALLOW_V 0x00000001U -#define TEE_REG_REGDMA_PERI_LP_RAM_ALLOW_S 0 -/** TEE_REG_REGDMA_PERI_LP_PERI_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_REGDMA_PERI_LP_PERI_ALLOW (BIT(1)) -#define TEE_REG_REGDMA_PERI_LP_PERI_ALLOW_M (TEE_REG_REGDMA_PERI_LP_PERI_ALLOW_V << TEE_REG_REGDMA_PERI_LP_PERI_ALLOW_S) -#define TEE_REG_REGDMA_PERI_LP_PERI_ALLOW_V 0x00000001U -#define TEE_REG_REGDMA_PERI_LP_PERI_ALLOW_S 1 +/** PMS_REGDMA_LP_PERI_PMS_REG register + * LP Peripheral Permission register for REGDMA + */ +#define PMS_REGDMA_LP_PERI_PMS_REG (DR_REG_PMS_BASE + 0x18) +/** PMS_REGDMA_PERI_LP_SRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether REGDMA has permission to access LP SRAM. + * 0: Not allowed + * 1: Allow + */ +#define PMS_REGDMA_PERI_LP_SRAM_ALLOW (BIT(0)) +#define PMS_REGDMA_PERI_LP_SRAM_ALLOW_M (PMS_REGDMA_PERI_LP_SRAM_ALLOW_V << PMS_REGDMA_PERI_LP_SRAM_ALLOW_S) +#define PMS_REGDMA_PERI_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_REGDMA_PERI_LP_SRAM_ALLOW_S 0 +/** PMS_REGDMA_PERI_LP_PERI_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether REGDMA has permission to access all LP peripherals. + * 0: Not allowed + * 1: Allow + */ +#define PMS_REGDMA_PERI_LP_PERI_ALLOW (BIT(1)) +#define PMS_REGDMA_PERI_LP_PERI_ALLOW_M (PMS_REGDMA_PERI_LP_PERI_ALLOW_V << PMS_REGDMA_PERI_LP_PERI_ALLOW_S) +#define PMS_REGDMA_PERI_LP_PERI_ALLOW_V 0x00000001U +#define PMS_REGDMA_PERI_LP_PERI_ALLOW_S 1 #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_struct.h b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_struct.h index 3eb67ccc92d..0e65b4e64bc 100644 --- a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_struct.h +++ b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,502 +10,397 @@ extern "C" { #endif -/** Group: TEE HP2LP TEE PMS DATE REG */ -/** Type of hp2lp_tee_pms_date register - * NA +/** Group: Version Control Registers */ +/** Type of hp2lp_peri_pms_date register + * Version control register */ typedef union { struct { - /** tee_date : R/W; bitpos: [31:0]; default: 2294790; - * NA + /** hp2lp_peri_pms_date : R/W; bitpos: [31:0]; default: 2294790; + * Version control register */ - uint32_t tee_date:32; + uint32_t hp2lp_peri_pms_date:32; }; uint32_t val; -} tee_hp2lp_tee_pms_date_reg_t; +} pms_hp2lp_peri_pms_date_reg_t; -/** Group: TEE PMS CLK EN REG */ -/** Type of pms_clk_en register - * NA +/** Group: Clock Gating Registers */ +/** Type of hp2lp_peri_pms_clk_en register + * Clock gating register */ typedef union { struct { - /** reg_clk_en : R/W; bitpos: [0]; default: 1; - * NA + /** hp2lp_peri_pms_clk_en : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on */ - uint32_t reg_clk_en:1; + uint32_t hp2lp_peri_pms_clk_en:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_pms_clk_en_reg_t; +} pms_hp2lp_peri_pms_clk_en_reg_t; -/** Group: TEE HP CORE0 MM PMS REG0 REG */ -/** Type of hp_core0_mm_pms_reg0 register - * NA +/** Group: HP CPU Permission Control Registers */ +/** Type of hp_coren_mm_pms_reg0 register + * Permission control register0 for HP CPUn in machine mode */ typedef union { struct { - /** reg_hp_core0_mm_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_sysreg_allow:1; - /** reg_hp_core0_mm_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_aonclkrst_allow:1; - /** reg_hp_core0_mm_lp_timer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_timer_allow:1; - /** reg_hp_core0_mm_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_anaperi_allow:1; - /** reg_hp_core0_mm_lp_pmu_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_pmu_allow:1; - /** reg_hp_core0_mm_lp_wdt_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_wdt_allow:1; - /** reg_hp_core0_mm_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_mailbox_allow:1; - /** reg_hp_core0_mm_lp_rtc_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_rtc_allow:1; - /** reg_hp_core0_mm_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_periclkrst_allow:1; - /** reg_hp_core0_mm_lp_uart_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_uart_allow:1; - /** reg_hp_core0_mm_lp_i2c_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_i2c_allow:1; - /** reg_hp_core0_mm_lp_spi_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_spi_allow:1; - /** reg_hp_core0_mm_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_i2cmst_allow:1; - /** reg_hp_core0_mm_lp_i2s_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_i2s_allow:1; - /** reg_hp_core0_mm_lp_adc_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_adc_allow:1; - /** reg_hp_core0_mm_lp_touch_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_touch_allow:1; - /** reg_hp_core0_mm_lp_iomux_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_iomux_allow:1; - /** reg_hp_core0_mm_lp_intr_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_intr_allow:1; - /** reg_hp_core0_mm_lp_efuse_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_efuse_allow:1; - /** reg_hp_core0_mm_lp_pms_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_pms_allow:1; - /** reg_hp_core0_mm_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_hp2lp_pms_allow:1; - /** reg_hp_core0_mm_lp_tsens_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_tsens_allow:1; - /** reg_hp_core0_mm_lp_huk_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_huk_allow:1; - /** reg_hp_core0_mm_lp_tcm_ram_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_hp_core0_mm_lp_tcm_ram_allow:1; + /** hp_coren_mm_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_sysreg_allow:1; + /** hp_coren_mm_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_aonclkrst_allow:1; + /** hp_coren_mm_lp_timer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_timer_allow:1; + /** hp_coren_mm_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_anaperi_allow:1; + /** hp_coren_mm_lp_pmu_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_pmu_allow:1; + /** hp_coren_mm_lp_wdt_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_wdt_allow:1; + /** hp_coren_mm_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_mailbox_allow:1; + /** hp_coren_mm_lp_rtc_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_coren_mm_lp_rtc_allow:1; + /** hp_coren_mm_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_periclkrst_allow:1; + /** hp_coren_mm_lp_uart_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_uart_allow:1; + /** hp_coren_mm_lp_i2c_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_i2c_allow:1; + /** hp_coren_mm_lp_spi_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_spi_allow:1; + /** hp_coren_mm_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_i2cmst_allow:1; + /** hp_coren_mm_lp_i2s_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_i2s_allow:1; + /** hp_coren_mm_lp_adc_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_adc_allow:1; + /** hp_coren_mm_lp_touch_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP touch + * sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_touch_allow:1; + /** hp_coren_mm_lp_iomux_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_iomux_allow:1; + /** hp_coren_mm_lp_intr_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_intr_allow:1; + /** hp_coren_mm_lp_efuse_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_efuse_allow:1; + /** hp_coren_mm_lp_pms_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access + * LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_pms_allow:1; + /** hp_coren_mm_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_hp2lp_pms_allow:1; + /** hp_coren_mm_lp_tsens_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_tsens_allow:1; + /** hp_coren_mm_lp_huk_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in machine mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_huk_allow:1; + /** hp_coren_mm_lp_sram_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_mm_lp_sram_allow:1; uint32_t reserved_24:8; }; uint32_t val; -} tee_hp_core0_mm_pms_reg0_reg_t; +} pms_hp_coren_mm_pms_reg0_reg_t; - -/** Group: TEE HP CORE0 UM PMS REG0 REG */ -/** Type of hp_core0_um_pms_reg0 register - * NA +/** Type of hp_coren_um_pms_reg0 register + * Permission control register0 for HP CPUn in user mode */ typedef union { struct { - /** reg_hp_core0_um_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_sysreg_allow:1; - /** reg_hp_core0_um_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_aonclkrst_allow:1; - /** reg_hp_core0_um_lp_timer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_timer_allow:1; - /** reg_hp_core0_um_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_anaperi_allow:1; - /** reg_hp_core0_um_lp_pmu_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_pmu_allow:1; - /** reg_hp_core0_um_lp_wdt_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_wdt_allow:1; - /** reg_hp_core0_um_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_mailbox_allow:1; - /** reg_hp_core0_um_lp_rtc_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_rtc_allow:1; - /** reg_hp_core0_um_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_periclkrst_allow:1; - /** reg_hp_core0_um_lp_uart_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_uart_allow:1; - /** reg_hp_core0_um_lp_i2c_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_i2c_allow:1; - /** reg_hp_core0_um_lp_spi_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_spi_allow:1; - /** reg_hp_core0_um_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_i2cmst_allow:1; - /** reg_hp_core0_um_lp_i2s_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_i2s_allow:1; - /** reg_hp_core0_um_lp_adc_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_adc_allow:1; - /** reg_hp_core0_um_lp_touch_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_touch_allow:1; - /** reg_hp_core0_um_lp_iomux_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_iomux_allow:1; - /** reg_hp_core0_um_lp_intr_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_intr_allow:1; - /** reg_hp_core0_um_lp_efuse_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_efuse_allow:1; - /** reg_hp_core0_um_lp_pms_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_pms_allow:1; - /** reg_hp_core0_um_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_hp2lp_pms_allow:1; - /** reg_hp_core0_um_lp_tsens_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_tsens_allow:1; - /** reg_hp_core0_um_lp_huk_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_huk_allow:1; - /** reg_hp_core0_um_lp_tcm_ram_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_hp_core0_um_lp_tcm_ram_allow:1; + /** hp_coren_um_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP System + * Registers. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_sysreg_allow:1; + /** hp_coren_um_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP_AONCLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_aonclkrst_allow:1; + /** hp_coren_um_lp_timer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_timer_allow:1; + /** hp_coren_um_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP ANAPERI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_anaperi_allow:1; + /** hp_coren_um_lp_pmu_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP PMU. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_pmu_allow:1; + /** hp_coren_um_lp_wdt_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP WDT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_wdt_allow:1; + /** hp_coren_um_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_mailbox_allow:1; + /** hp_coren_um_lp_rtc_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_coren_um_lp_rtc_allow:1; + /** hp_coren_um_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP PERICLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_periclkrst_allow:1; + /** hp_coren_um_lp_uart_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_uart_allow:1; + /** hp_coren_um_lp_i2c_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP I2C. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_i2c_allow:1; + /** hp_coren_um_lp_spi_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_spi_allow:1; + /** hp_coren_um_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_i2cmst_allow:1; + /** hp_coren_um_lp_i2s_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_i2s_allow:1; + /** hp_coren_um_lp_adc_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_adc_allow:1; + /** hp_coren_um_lp_touch_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP touch sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_touch_allow:1; + /** hp_coren_um_lp_iomux_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_iomux_allow:1; + /** hp_coren_um_lp_intr_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP INTR. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_intr_allow:1; + /** hp_coren_um_lp_efuse_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_efuse_allow:1; + /** hp_coren_um_lp_pms_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_pms_allow:1; + /** hp_coren_um_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPUn in user mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_hp2lp_pms_allow:1; + /** hp_coren_um_lp_tsens_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_tsens_allow:1; + /** hp_coren_um_lp_huk_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in user mode has permission to LP HUK. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_huk_allow:1; + /** hp_coren_um_lp_sram_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in user mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t hp_coren_um_lp_sram_allow:1; uint32_t reserved_24:8; }; uint32_t val; -} tee_hp_core0_um_pms_reg0_reg_t; +} pms_hp_coren_um_pms_reg0_reg_t; -/** Group: TEE HP CORE1 MM PMS REG0 REG */ -/** Type of hp_core1_mm_pms_reg0 register - * NA +/** Group: TEE Peripheral Permission Control Register */ +/** Type of regdma_lp_peri_pms register + * LP Peripheral Permission register for REGDMA */ typedef union { struct { - /** reg_hp_core1_mm_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_sysreg_allow:1; - /** reg_hp_core1_mm_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_aonclkrst_allow:1; - /** reg_hp_core1_mm_lp_timer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_timer_allow:1; - /** reg_hp_core1_mm_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_anaperi_allow:1; - /** reg_hp_core1_mm_lp_pmu_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_pmu_allow:1; - /** reg_hp_core1_mm_lp_wdt_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_wdt_allow:1; - /** reg_hp_core1_mm_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_mailbox_allow:1; - /** reg_hp_core1_mm_lp_rtc_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_rtc_allow:1; - /** reg_hp_core1_mm_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_periclkrst_allow:1; - /** reg_hp_core1_mm_lp_uart_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_uart_allow:1; - /** reg_hp_core1_mm_lp_i2c_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_i2c_allow:1; - /** reg_hp_core1_mm_lp_spi_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_spi_allow:1; - /** reg_hp_core1_mm_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_i2cmst_allow:1; - /** reg_hp_core1_mm_lp_i2s_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_i2s_allow:1; - /** reg_hp_core1_mm_lp_adc_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_adc_allow:1; - /** reg_hp_core1_mm_lp_touch_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_touch_allow:1; - /** reg_hp_core1_mm_lp_iomux_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_iomux_allow:1; - /** reg_hp_core1_mm_lp_intr_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_intr_allow:1; - /** reg_hp_core1_mm_lp_efuse_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_efuse_allow:1; - /** reg_hp_core1_mm_lp_pms_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_pms_allow:1; - /** reg_hp_core1_mm_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_hp2lp_pms_allow:1; - /** reg_hp_core1_mm_lp_tsens_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_tsens_allow:1; - /** reg_hp_core1_mm_lp_huk_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_huk_allow:1; - /** reg_hp_core1_mm_lp_tcm_ram_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_hp_core1_mm_lp_tcm_ram_allow:1; - uint32_t reserved_24:8; - }; - uint32_t val; -} tee_hp_core1_mm_pms_reg0_reg_t; - - -/** Group: TEE HP CORE1 UM PMS REG0 REG */ -/** Type of hp_core1_um_pms_reg0 register - * NA - */ -typedef union { - struct { - /** reg_hp_core1_um_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_sysreg_allow:1; - /** reg_hp_core1_um_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_aonclkrst_allow:1; - /** reg_hp_core1_um_lp_timer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_timer_allow:1; - /** reg_hp_core1_um_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_anaperi_allow:1; - /** reg_hp_core1_um_lp_pmu_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_pmu_allow:1; - /** reg_hp_core1_um_lp_wdt_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_wdt_allow:1; - /** reg_hp_core1_um_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_mailbox_allow:1; - /** reg_hp_core1_um_lp_rtc_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_rtc_allow:1; - /** reg_hp_core1_um_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_periclkrst_allow:1; - /** reg_hp_core1_um_lp_uart_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_uart_allow:1; - /** reg_hp_core1_um_lp_i2c_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_i2c_allow:1; - /** reg_hp_core1_um_lp_spi_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_spi_allow:1; - /** reg_hp_core1_um_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_i2cmst_allow:1; - /** reg_hp_core1_um_lp_i2s_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_i2s_allow:1; - /** reg_hp_core1_um_lp_adc_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_adc_allow:1; - /** reg_hp_core1_um_lp_touch_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_touch_allow:1; - /** reg_hp_core1_um_lp_iomux_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_iomux_allow:1; - /** reg_hp_core1_um_lp_intr_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_intr_allow:1; - /** reg_hp_core1_um_lp_efuse_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_efuse_allow:1; - /** reg_hp_core1_um_lp_pms_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_pms_allow:1; - /** reg_hp_core1_um_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_hp2lp_pms_allow:1; - /** reg_hp_core1_um_lp_tsens_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_tsens_allow:1; - /** reg_hp_core1_um_lp_huk_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_huk_allow:1; - /** reg_hp_core1_um_lp_tcm_ram_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_hp_core1_um_lp_tcm_ram_allow:1; - uint32_t reserved_24:8; - }; - uint32_t val; -} tee_hp_core1_um_pms_reg0_reg_t; - - -/** Group: TEE REGDMA PERI PMS REG */ -/** Type of regdma_peri_pms register - * NA - */ -typedef union { - struct { - /** reg_regdma_peri_lp_ram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_regdma_peri_lp_ram_allow:1; - /** reg_regdma_peri_lp_peri_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_regdma_peri_lp_peri_allow:1; + /** regdma_peri_lp_sram_allow : R/W; bitpos: [0]; default: 1; + * Configures whether REGDMA has permission to access LP SRAM. + * 0: Not allowed + * 1: Allow + */ + uint32_t regdma_peri_lp_sram_allow:1; + /** regdma_peri_lp_peri_allow : R/W; bitpos: [1]; default: 1; + * Configures whether REGDMA has permission to access all LP peripherals. + * 0: Not allowed + * 1: Allow + */ + uint32_t regdma_peri_lp_peri_allow:1; uint32_t reserved_2:30; }; uint32_t val; -} tee_regdma_peri_pms_reg_t; +} pms_regdma_lp_peri_pms_reg_t; typedef struct { - volatile tee_hp2lp_tee_pms_date_reg_t hp2lp_tee_pms_date; - volatile tee_pms_clk_en_reg_t pms_clk_en; - volatile tee_hp_core0_mm_pms_reg0_reg_t hp_core0_mm_pms_reg0; - volatile tee_hp_core0_um_pms_reg0_reg_t hp_core0_um_pms_reg0; - volatile tee_hp_core1_mm_pms_reg0_reg_t hp_core1_mm_pms_reg0; - volatile tee_hp_core1_um_pms_reg0_reg_t hp_core1_um_pms_reg0; - volatile tee_regdma_peri_pms_reg_t regdma_peri_pms; -} tee_dev_t; + volatile pms_hp2lp_peri_pms_date_reg_t hp2lp_peri_pms_date; + volatile pms_hp2lp_peri_pms_clk_en_reg_t hp2lp_peri_pms_clk_en; + volatile pms_hp_coren_mm_pms_reg0_reg_t hp_core0_mm_pms_reg0; + volatile pms_hp_coren_um_pms_reg0_reg_t hp_core0_um_pms_reg0; + volatile pms_hp_coren_mm_pms_reg0_reg_t hp_core1_mm_pms_reg0; + volatile pms_hp_coren_um_pms_reg0_reg_t hp_core1_um_pms_reg0; + volatile pms_regdma_lp_peri_pms_reg_t regdma_lp_peri_pms; +} hp2lp_peri_pms_dev_t; +extern hp2lp_peri_pms_dev_t HP2LP_PERI_PMS; #ifndef __cplusplus -_Static_assert(sizeof(tee_dev_t) == 0x1c, "Invalid size of tee_dev_t structure"); +_Static_assert(sizeof(hp2lp_peri_pms_dev_t) == 0x1c, "Invalid size of hp2lp_peri_pms_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h index 31eeb620ddf..c7c82bec2fa 100644 --- a/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,2193 +11,2882 @@ extern "C" { #endif -/** TEE_PMS_DATE_REG register - * NA +/** PMS_HP_PERI_PMS_DATE_REG register + * Version control register */ -#define TEE_PMS_DATE_REG (DR_REG_TEE_BASE + 0x0) -/** TEE_TEE_DATE : R/W; bitpos: [31:0]; default: 2294537; - * NA +#define PMS_HP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +/** PMS_HP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294537; + * Version control register. */ -#define TEE_TEE_DATE 0xFFFFFFFFU -#define TEE_TEE_DATE_M (TEE_TEE_DATE_V << TEE_TEE_DATE_S) -#define TEE_TEE_DATE_V 0xFFFFFFFFU -#define TEE_TEE_DATE_S 0 +#define PMS_HP_PERI_PMS_DATE 0xFFFFFFFFU +#define PMS_HP_PERI_PMS_DATE_M (PMS_HP_PERI_PMS_DATE_V << PMS_HP_PERI_PMS_DATE_S) +#define PMS_HP_PERI_PMS_DATE_V 0xFFFFFFFFU +#define PMS_HP_PERI_PMS_DATE_S 0 -/** TEE_PMS_CLK_EN_REG register - * NA - */ -#define TEE_PMS_CLK_EN_REG (DR_REG_TEE_BASE + 0x4) -/** TEE_REG_CLK_EN : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CLK_EN (BIT(0)) -#define TEE_REG_CLK_EN_M (TEE_REG_CLK_EN_V << TEE_REG_CLK_EN_S) -#define TEE_REG_CLK_EN_V 0x00000001U -#define TEE_REG_CLK_EN_S 0 +/** PMS_HP_PERI_PMS_CLK_EN_REG register + * Clock gating register + */ +#define PMS_HP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +/** PMS_HP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on + */ +#define PMS_HP_PERI_PMS_CLK_EN (BIT(0)) +#define PMS_HP_PERI_PMS_CLK_EN_M (PMS_HP_PERI_PMS_CLK_EN_V << PMS_HP_PERI_PMS_CLK_EN_S) +#define PMS_HP_PERI_PMS_CLK_EN_V 0x00000001U +#define PMS_HP_PERI_PMS_CLK_EN_S 0 -/** TEE_CORE0_MM_PMS_REG0_REG register - * NA - */ -#define TEE_CORE0_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x8) -/** TEE_REG_CORE0_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_PSRAM_ALLOW (BIT(0)) -#define TEE_REG_CORE0_MM_PSRAM_ALLOW_M (TEE_REG_CORE0_MM_PSRAM_ALLOW_V << TEE_REG_CORE0_MM_PSRAM_ALLOW_S) -#define TEE_REG_CORE0_MM_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_PSRAM_ALLOW_S 0 -/** TEE_REG_CORE0_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_FLASH_ALLOW (BIT(1)) -#define TEE_REG_CORE0_MM_FLASH_ALLOW_M (TEE_REG_CORE0_MM_FLASH_ALLOW_V << TEE_REG_CORE0_MM_FLASH_ALLOW_S) -#define TEE_REG_CORE0_MM_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_FLASH_ALLOW_S 1 -/** TEE_REG_CORE0_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_L2MEM_ALLOW (BIT(2)) -#define TEE_REG_CORE0_MM_L2MEM_ALLOW_M (TEE_REG_CORE0_MM_L2MEM_ALLOW_V << TEE_REG_CORE0_MM_L2MEM_ALLOW_S) -#define TEE_REG_CORE0_MM_L2MEM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_L2MEM_ALLOW_S 2 -/** TEE_REG_CORE0_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_L2ROM_ALLOW (BIT(3)) -#define TEE_REG_CORE0_MM_L2ROM_ALLOW_M (TEE_REG_CORE0_MM_L2ROM_ALLOW_V << TEE_REG_CORE0_MM_L2ROM_ALLOW_S) -#define TEE_REG_CORE0_MM_L2ROM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_L2ROM_ALLOW_S 3 -/** TEE_REG_CORE0_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_TRACE0_ALLOW (BIT(6)) -#define TEE_REG_CORE0_MM_TRACE0_ALLOW_M (TEE_REG_CORE0_MM_TRACE0_ALLOW_V << TEE_REG_CORE0_MM_TRACE0_ALLOW_S) -#define TEE_REG_CORE0_MM_TRACE0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_TRACE0_ALLOW_S 6 -/** TEE_REG_CORE0_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_TRACE1_ALLOW (BIT(7)) -#define TEE_REG_CORE0_MM_TRACE1_ALLOW_M (TEE_REG_CORE0_MM_TRACE1_ALLOW_V << TEE_REG_CORE0_MM_TRACE1_ALLOW_S) -#define TEE_REG_CORE0_MM_TRACE1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_TRACE1_ALLOW_S 7 -/** TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW (BIT(8)) -#define TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW_M (TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW_V << TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW_S) -#define TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_CPU_BUS_MON_ALLOW_S 8 -/** TEE_REG_CORE0_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_L2MEM_MON_ALLOW (BIT(9)) -#define TEE_REG_CORE0_MM_L2MEM_MON_ALLOW_M (TEE_REG_CORE0_MM_L2MEM_MON_ALLOW_V << TEE_REG_CORE0_MM_L2MEM_MON_ALLOW_S) -#define TEE_REG_CORE0_MM_L2MEM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_L2MEM_MON_ALLOW_S 9 -/** TEE_REG_CORE0_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_TCM_MON_ALLOW (BIT(10)) -#define TEE_REG_CORE0_MM_TCM_MON_ALLOW_M (TEE_REG_CORE0_MM_TCM_MON_ALLOW_V << TEE_REG_CORE0_MM_TCM_MON_ALLOW_S) -#define TEE_REG_CORE0_MM_TCM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_TCM_MON_ALLOW_S 10 -/** TEE_REG_CORE0_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_CACHE_ALLOW (BIT(11)) -#define TEE_REG_CORE0_MM_CACHE_ALLOW_M (TEE_REG_CORE0_MM_CACHE_ALLOW_V << TEE_REG_CORE0_MM_CACHE_ALLOW_S) -#define TEE_REG_CORE0_MM_CACHE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_CACHE_ALLOW_S 11 +/** PMS_CORE0_MM_HP_PERI_PMS_REG0_REG register + * Permission control register0 for HP CPU0 in machine mode + */ +#define PMS_CORE0_MM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +/** PMS_CORE0_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_PSRAM_ALLOW (BIT(0)) +#define PMS_CORE0_MM_PSRAM_ALLOW_M (PMS_CORE0_MM_PSRAM_ALLOW_V << PMS_CORE0_MM_PSRAM_ALLOW_S) +#define PMS_CORE0_MM_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_PSRAM_ALLOW_S 0 +/** PMS_CORE0_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_FLASH_ALLOW (BIT(1)) +#define PMS_CORE0_MM_FLASH_ALLOW_M (PMS_CORE0_MM_FLASH_ALLOW_V << PMS_CORE0_MM_FLASH_ALLOW_S) +#define PMS_CORE0_MM_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_FLASH_ALLOW_S 1 +/** PMS_CORE0_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP L2MEM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_L2MEM_ALLOW (BIT(2)) +#define PMS_CORE0_MM_L2MEM_ALLOW_M (PMS_CORE0_MM_L2MEM_ALLOW_V << PMS_CORE0_MM_L2MEM_ALLOW_S) +#define PMS_CORE0_MM_L2MEM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_L2MEM_ALLOW_S 2 +/** PMS_CORE0_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_L2ROM_ALLOW (BIT(3)) +#define PMS_CORE0_MM_L2ROM_ALLOW_M (PMS_CORE0_MM_L2ROM_ALLOW_V << PMS_CORE0_MM_L2ROM_ALLOW_S) +#define PMS_CORE0_MM_L2ROM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_L2ROM_ALLOW_S 3 +/** PMS_CORE0_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_TRACE0_ALLOW (BIT(6)) +#define PMS_CORE0_MM_TRACE0_ALLOW_M (PMS_CORE0_MM_TRACE0_ALLOW_V << PMS_CORE0_MM_TRACE0_ALLOW_S) +#define PMS_CORE0_MM_TRACE0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_TRACE0_ALLOW_S 6 +/** PMS_CORE0_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_TRACE1_ALLOW (BIT(7)) +#define PMS_CORE0_MM_TRACE1_ALLOW_M (PMS_CORE0_MM_TRACE1_ALLOW_V << PMS_CORE0_MM_TRACE1_ALLOW_S) +#define PMS_CORE0_MM_TRACE1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_TRACE1_ALLOW_S 7 +/** PMS_CORE0_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access CPU bus + * monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_CPU_BUS_MON_ALLOW (BIT(8)) +#define PMS_CORE0_MM_CPU_BUS_MON_ALLOW_M (PMS_CORE0_MM_CPU_BUS_MON_ALLOW_V << PMS_CORE0_MM_CPU_BUS_MON_ALLOW_S) +#define PMS_CORE0_MM_CPU_BUS_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_CPU_BUS_MON_ALLOW_S 8 +/** PMS_CORE0_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_L2MEM_MON_ALLOW (BIT(9)) +#define PMS_CORE0_MM_L2MEM_MON_ALLOW_M (PMS_CORE0_MM_L2MEM_MON_ALLOW_V << PMS_CORE0_MM_L2MEM_MON_ALLOW_S) +#define PMS_CORE0_MM_L2MEM_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_L2MEM_MON_ALLOW_S 9 +/** PMS_CORE0_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_TCM_MON_ALLOW (BIT(10)) +#define PMS_CORE0_MM_TCM_MON_ALLOW_M (PMS_CORE0_MM_TCM_MON_ALLOW_V << PMS_CORE0_MM_TCM_MON_ALLOW_S) +#define PMS_CORE0_MM_TCM_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_TCM_MON_ALLOW_S 10 +/** PMS_CORE0_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_CACHE_ALLOW (BIT(11)) +#define PMS_CORE0_MM_CACHE_ALLOW_M (PMS_CORE0_MM_CACHE_ALLOW_V << PMS_CORE0_MM_CACHE_ALLOW_S) +#define PMS_CORE0_MM_CACHE_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_CACHE_ALLOW_S 11 -/** TEE_CORE0_MM_PMS_REG1_REG register - * NA - */ -#define TEE_CORE0_MM_PMS_REG1_REG (DR_REG_TEE_BASE + 0xc) -/** TEE_REG_CORE0_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_USBOTG_ALLOW (BIT(0)) -#define TEE_REG_CORE0_MM_HP_USBOTG_ALLOW_M (TEE_REG_CORE0_MM_HP_USBOTG_ALLOW_V << TEE_REG_CORE0_MM_HP_USBOTG_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_USBOTG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_USBOTG_ALLOW_S 0 -/** TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW (BIT(1)) -#define TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW_M (TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW_V << TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_USBOTG11_ALLOW_S 1 -/** TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) -#define TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_M (TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_V << TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_S 2 -/** TEE_REG_CORE0_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_GDMA_ALLOW (BIT(3)) -#define TEE_REG_CORE0_MM_HP_GDMA_ALLOW_M (TEE_REG_CORE0_MM_HP_GDMA_ALLOW_V << TEE_REG_CORE0_MM_HP_GDMA_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_GDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_GDMA_ALLOW_S 3 -/** TEE_REG_CORE0_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_REGDMA_ALLOW (BIT(4)) -#define TEE_REG_CORE0_MM_HP_REGDMA_ALLOW_M (TEE_REG_CORE0_MM_HP_REGDMA_ALLOW_V << TEE_REG_CORE0_MM_HP_REGDMA_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_REGDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_REGDMA_ALLOW_S 4 -/** TEE_REG_CORE0_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_SDMMC_ALLOW (BIT(5)) -#define TEE_REG_CORE0_MM_HP_SDMMC_ALLOW_M (TEE_REG_CORE0_MM_HP_SDMMC_ALLOW_V << TEE_REG_CORE0_MM_HP_SDMMC_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_SDMMC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_SDMMC_ALLOW_S 5 -/** TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW (BIT(6)) -#define TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW_M (TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW_V << TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_AHB_PDMA_ALLOW_S 6 -/** TEE_REG_CORE0_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_JPEG_ALLOW (BIT(7)) -#define TEE_REG_CORE0_MM_HP_JPEG_ALLOW_M (TEE_REG_CORE0_MM_HP_JPEG_ALLOW_V << TEE_REG_CORE0_MM_HP_JPEG_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_JPEG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_JPEG_ALLOW_S 7 -/** TEE_REG_CORE0_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PPA_ALLOW (BIT(8)) -#define TEE_REG_CORE0_MM_HP_PPA_ALLOW_M (TEE_REG_CORE0_MM_HP_PPA_ALLOW_V << TEE_REG_CORE0_MM_HP_PPA_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PPA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PPA_ALLOW_S 8 -/** TEE_REG_CORE0_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_DMA2D_ALLOW (BIT(9)) -#define TEE_REG_CORE0_MM_HP_DMA2D_ALLOW_M (TEE_REG_CORE0_MM_HP_DMA2D_ALLOW_V << TEE_REG_CORE0_MM_HP_DMA2D_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_DMA2D_ALLOW_S 9 -/** TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) -#define TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW_M (TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW_V << TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_KEY_MANAGER_ALLOW_S 10 -/** TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW (BIT(11)) -#define TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW_M (TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW_V << TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_AXI_PDMA_ALLOW_S 11 -/** TEE_REG_CORE0_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_FLASH_ALLOW (BIT(12)) -#define TEE_REG_CORE0_MM_HP_FLASH_ALLOW_M (TEE_REG_CORE0_MM_HP_FLASH_ALLOW_V << TEE_REG_CORE0_MM_HP_FLASH_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_FLASH_ALLOW_S 12 -/** TEE_REG_CORE0_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PSRAM_ALLOW (BIT(13)) -#define TEE_REG_CORE0_MM_HP_PSRAM_ALLOW_M (TEE_REG_CORE0_MM_HP_PSRAM_ALLOW_V << TEE_REG_CORE0_MM_HP_PSRAM_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PSRAM_ALLOW_S 13 -/** TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW (BIT(14)) -#define TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW_M (TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW_V << TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_CRYPTO_ALLOW_S 14 -/** TEE_REG_CORE0_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_GMAC_ALLOW (BIT(15)) -#define TEE_REG_CORE0_MM_HP_GMAC_ALLOW_M (TEE_REG_CORE0_MM_HP_GMAC_ALLOW_V << TEE_REG_CORE0_MM_HP_GMAC_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_GMAC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_GMAC_ALLOW_S 15 -/** TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW (BIT(16)) -#define TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW_M (TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW_V << TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_USB_PHY_ALLOW_S 16 -/** TEE_REG_CORE0_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PVT_ALLOW (BIT(17)) -#define TEE_REG_CORE0_MM_HP_PVT_ALLOW_M (TEE_REG_CORE0_MM_HP_PVT_ALLOW_V << TEE_REG_CORE0_MM_HP_PVT_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PVT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PVT_ALLOW_S 17 -/** TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW (BIT(18)) -#define TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW_M (TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW_V << TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_CSI_HOST_ALLOW_S 18 -/** TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW (BIT(19)) -#define TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW_M (TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW_V << TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_DSI_HOST_ALLOW_S 19 -/** TEE_REG_CORE0_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_ISP_ALLOW (BIT(20)) -#define TEE_REG_CORE0_MM_HP_ISP_ALLOW_M (TEE_REG_CORE0_MM_HP_ISP_ALLOW_V << TEE_REG_CORE0_MM_HP_ISP_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_ISP_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_ISP_ALLOW_S 20 -/** TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW (BIT(21)) -#define TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW_M (TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW_V << TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_H264_CORE_ALLOW_S 21 -/** TEE_REG_CORE0_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_RMT_ALLOW (BIT(22)) -#define TEE_REG_CORE0_MM_HP_RMT_ALLOW_M (TEE_REG_CORE0_MM_HP_RMT_ALLOW_V << TEE_REG_CORE0_MM_HP_RMT_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_RMT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_RMT_ALLOW_S 22 -/** TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) -#define TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW_M (TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW_V << TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_BITSRAMBLER_ALLOW_S 23 -/** TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW (BIT(24)) -#define TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW_M (TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW_V << TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_AXI_ICM_ALLOW_S 24 -/** TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW (BIT(25)) -#define TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW_M (TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW_V << TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PERI_PMS_ALLOW_S 25 -/** TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) -#define TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW_M (TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW_V << TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_LP2HP_PERI_PMS_ALLOW_S 26 -/** TEE_REG_CORE0_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_DMA_PMS_ALLOW (BIT(27)) -#define TEE_REG_CORE0_MM_DMA_PMS_ALLOW_M (TEE_REG_CORE0_MM_DMA_PMS_ALLOW_V << TEE_REG_CORE0_MM_DMA_PMS_ALLOW_S) -#define TEE_REG_CORE0_MM_DMA_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_DMA_PMS_ALLOW_S 27 -/** TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW (BIT(28)) -#define TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW_M (TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW_V << TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_H264_DMA2D_ALLOW_S 28 +/** PMS_CORE0_MM_HP_PERI_PMS_REG1_REG register + * Permission control register1 for HP CPU0 in machine mode + */ +#define PMS_CORE0_MM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0xc) +/** PMS_CORE0_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP high-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_USBOTG_ALLOW (BIT(0)) +#define PMS_CORE0_MM_HP_USBOTG_ALLOW_M (PMS_CORE0_MM_HP_USBOTG_ALLOW_V << PMS_CORE0_MM_HP_USBOTG_ALLOW_S) +#define PMS_CORE0_MM_HP_USBOTG_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_USBOTG_ALLOW_S 0 +/** PMS_CORE0_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP full-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_USBOTG11_ALLOW (BIT(1)) +#define PMS_CORE0_MM_HP_USBOTG11_ALLOW_M (PMS_CORE0_MM_HP_USBOTG11_ALLOW_V << PMS_CORE0_MM_HP_USBOTG11_ALLOW_S) +#define PMS_CORE0_MM_HP_USBOTG11_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_USBOTG11_ALLOW_S 1 +/** PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP full-speed + * USB 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) +#define PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_M (PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_V << PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_S) +#define PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_USBOTG11_WRAP_ALLOW_S 2 +/** PMS_CORE0_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_GDMA_ALLOW (BIT(3)) +#define PMS_CORE0_MM_HP_GDMA_ALLOW_M (PMS_CORE0_MM_HP_GDMA_ALLOW_V << PMS_CORE0_MM_HP_GDMA_ALLOW_S) +#define PMS_CORE0_MM_HP_GDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_GDMA_ALLOW_S 3 +/** PMS_CORE0_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP GDMA (DW + * GDMA). + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE0_MM_HP_REGDMA_ALLOW (BIT(4)) +#define PMS_CORE0_MM_HP_REGDMA_ALLOW_M (PMS_CORE0_MM_HP_REGDMA_ALLOW_V << PMS_CORE0_MM_HP_REGDMA_ALLOW_S) +#define PMS_CORE0_MM_HP_REGDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_REGDMA_ALLOW_S 4 +/** PMS_CORE0_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_SDMMC_ALLOW (BIT(5)) +#define PMS_CORE0_MM_HP_SDMMC_ALLOW_M (PMS_CORE0_MM_HP_SDMMC_ALLOW_V << PMS_CORE0_MM_HP_SDMMC_ALLOW_S) +#define PMS_CORE0_MM_HP_SDMMC_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_SDMMC_ALLOW_S 5 +/** PMS_CORE0_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_AHB_PDMA_ALLOW (BIT(6)) +#define PMS_CORE0_MM_HP_AHB_PDMA_ALLOW_M (PMS_CORE0_MM_HP_AHB_PDMA_ALLOW_V << PMS_CORE0_MM_HP_AHB_PDMA_ALLOW_S) +#define PMS_CORE0_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_AHB_PDMA_ALLOW_S 6 +/** PMS_CORE0_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_JPEG_ALLOW (BIT(7)) +#define PMS_CORE0_MM_HP_JPEG_ALLOW_M (PMS_CORE0_MM_HP_JPEG_ALLOW_V << PMS_CORE0_MM_HP_JPEG_ALLOW_S) +#define PMS_CORE0_MM_HP_JPEG_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_JPEG_ALLOW_S 7 +/** PMS_CORE0_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_PPA_ALLOW (BIT(8)) +#define PMS_CORE0_MM_HP_PPA_ALLOW_M (PMS_CORE0_MM_HP_PPA_ALLOW_V << PMS_CORE0_MM_HP_PPA_ALLOW_S) +#define PMS_CORE0_MM_HP_PPA_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PPA_ALLOW_S 8 +/** PMS_CORE0_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_DMA2D_ALLOW (BIT(9)) +#define PMS_CORE0_MM_HP_DMA2D_ALLOW_M (PMS_CORE0_MM_HP_DMA2D_ALLOW_V << PMS_CORE0_MM_HP_DMA2D_ALLOW_S) +#define PMS_CORE0_MM_HP_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_DMA2D_ALLOW_S 9 +/** PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) +#define PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW_M (PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW_V << PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW_S) +#define PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_KEY_MANAGER_ALLOW_S 10 +/** PMS_CORE0_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_AXI_PDMA_ALLOW (BIT(11)) +#define PMS_CORE0_MM_HP_AXI_PDMA_ALLOW_M (PMS_CORE0_MM_HP_AXI_PDMA_ALLOW_V << PMS_CORE0_MM_HP_AXI_PDMA_ALLOW_S) +#define PMS_CORE0_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_AXI_PDMA_ALLOW_S 11 +/** PMS_CORE0_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_FLASH_ALLOW (BIT(12)) +#define PMS_CORE0_MM_HP_FLASH_ALLOW_M (PMS_CORE0_MM_HP_FLASH_ALLOW_V << PMS_CORE0_MM_HP_FLASH_ALLOW_S) +#define PMS_CORE0_MM_HP_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_FLASH_ALLOW_S 12 +/** PMS_CORE0_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_PSRAM_ALLOW (BIT(13)) +#define PMS_CORE0_MM_HP_PSRAM_ALLOW_M (PMS_CORE0_MM_HP_PSRAM_ALLOW_V << PMS_CORE0_MM_HP_PSRAM_ALLOW_S) +#define PMS_CORE0_MM_HP_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PSRAM_ALLOW_S 13 +/** PMS_CORE0_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP CRYPTO + * (including AES/SHA/RSA/HMAC Accelerators). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_CRYPTO_ALLOW (BIT(14)) +#define PMS_CORE0_MM_HP_CRYPTO_ALLOW_M (PMS_CORE0_MM_HP_CRYPTO_ALLOW_V << PMS_CORE0_MM_HP_CRYPTO_ALLOW_S) +#define PMS_CORE0_MM_HP_CRYPTO_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_CRYPTO_ALLOW_S 14 +/** PMS_CORE0_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_GMAC_ALLOW (BIT(15)) +#define PMS_CORE0_MM_HP_GMAC_ALLOW_M (PMS_CORE0_MM_HP_GMAC_ALLOW_V << PMS_CORE0_MM_HP_GMAC_ALLOW_S) +#define PMS_CORE0_MM_HP_GMAC_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_GMAC_ALLOW_S 15 +/** PMS_CORE0_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP high-speed + * USB 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_USB_PHY_ALLOW (BIT(16)) +#define PMS_CORE0_MM_HP_USB_PHY_ALLOW_M (PMS_CORE0_MM_HP_USB_PHY_ALLOW_V << PMS_CORE0_MM_HP_USB_PHY_ALLOW_S) +#define PMS_CORE0_MM_HP_USB_PHY_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_USB_PHY_ALLOW_S 16 +/** PMS_CORE0_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE0_MM_HP_PVT_ALLOW (BIT(17)) +#define PMS_CORE0_MM_HP_PVT_ALLOW_M (PMS_CORE0_MM_HP_PVT_ALLOW_V << PMS_CORE0_MM_HP_PVT_ALLOW_S) +#define PMS_CORE0_MM_HP_PVT_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PVT_ALLOW_S 17 +/** PMS_CORE0_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP MIPI CSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_CSI_HOST_ALLOW (BIT(18)) +#define PMS_CORE0_MM_HP_CSI_HOST_ALLOW_M (PMS_CORE0_MM_HP_CSI_HOST_ALLOW_V << PMS_CORE0_MM_HP_CSI_HOST_ALLOW_S) +#define PMS_CORE0_MM_HP_CSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_CSI_HOST_ALLOW_S 18 +/** PMS_CORE0_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP MIPI DSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_DSI_HOST_ALLOW (BIT(19)) +#define PMS_CORE0_MM_HP_DSI_HOST_ALLOW_M (PMS_CORE0_MM_HP_DSI_HOST_ALLOW_V << PMS_CORE0_MM_HP_DSI_HOST_ALLOW_S) +#define PMS_CORE0_MM_HP_DSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_DSI_HOST_ALLOW_S 19 +/** PMS_CORE0_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP ISP (Image + * Signal Processor). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_ISP_ALLOW (BIT(20)) +#define PMS_CORE0_MM_HP_ISP_ALLOW_M (PMS_CORE0_MM_HP_ISP_ALLOW_V << PMS_CORE0_MM_HP_ISP_ALLOW_S) +#define PMS_CORE0_MM_HP_ISP_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_ISP_ALLOW_S 20 +/** PMS_CORE0_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP H264 + * Encoder. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_H264_CORE_ALLOW (BIT(21)) +#define PMS_CORE0_MM_HP_H264_CORE_ALLOW_M (PMS_CORE0_MM_HP_H264_CORE_ALLOW_V << PMS_CORE0_MM_HP_H264_CORE_ALLOW_S) +#define PMS_CORE0_MM_HP_H264_CORE_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_H264_CORE_ALLOW_S 21 +/** PMS_CORE0_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_RMT_ALLOW (BIT(22)) +#define PMS_CORE0_MM_HP_RMT_ALLOW_M (PMS_CORE0_MM_HP_RMT_ALLOW_V << PMS_CORE0_MM_HP_RMT_ALLOW_S) +#define PMS_CORE0_MM_HP_RMT_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_RMT_ALLOW_S 22 +/** PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP bit + * scrambler. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) +#define PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW_M (PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW_V << PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW_S) +#define PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_BITSRAMBLER_ALLOW_S 23 +/** PMS_CORE0_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_AXI_ICM_ALLOW (BIT(24)) +#define PMS_CORE0_MM_HP_AXI_ICM_ALLOW_M (PMS_CORE0_MM_HP_AXI_ICM_ALLOW_V << PMS_CORE0_MM_HP_AXI_ICM_ALLOW_S) +#define PMS_CORE0_MM_HP_AXI_ICM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_AXI_ICM_ALLOW_S 24 +/** PMS_CORE0_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access + * HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_PERI_PMS_ALLOW (BIT(25)) +#define PMS_CORE0_MM_HP_PERI_PMS_ALLOW_M (PMS_CORE0_MM_HP_PERI_PMS_ALLOW_V << PMS_CORE0_MM_HP_PERI_PMS_ALLOW_S) +#define PMS_CORE0_MM_HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PERI_PMS_ALLOW_S 25 +/** PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) +#define PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW_M (PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW_V << PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW_S) +#define PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_LP2HP_PERI_PMS_ALLOW_S 26 +/** PMS_CORE0_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_DMA_PMS_ALLOW (BIT(27)) +#define PMS_CORE0_MM_DMA_PMS_ALLOW_M (PMS_CORE0_MM_DMA_PMS_ALLOW_V << PMS_CORE0_MM_DMA_PMS_ALLOW_S) +#define PMS_CORE0_MM_DMA_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_DMA_PMS_ALLOW_S 27 +/** PMS_CORE0_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_H264_DMA2D_ALLOW (BIT(28)) +#define PMS_CORE0_MM_HP_H264_DMA2D_ALLOW_M (PMS_CORE0_MM_HP_H264_DMA2D_ALLOW_V << PMS_CORE0_MM_HP_H264_DMA2D_ALLOW_S) +#define PMS_CORE0_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_H264_DMA2D_ALLOW_S 28 -/** TEE_CORE0_MM_PMS_REG2_REG register - * NA - */ -#define TEE_CORE0_MM_PMS_REG2_REG (DR_REG_TEE_BASE + 0x10) -/** TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW (BIT(0)) -#define TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW_M (TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW_V << TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_MCPWM0_ALLOW_S 0 -/** TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW (BIT(1)) -#define TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW_M (TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW_V << TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_MCPWM1_ALLOW_S 1 -/** TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW_M (TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW_V << TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP0_ALLOW_S 2 -/** TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW_M (TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW_V << TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_TIMER_GROUP1_ALLOW_S 3 -/** TEE_REG_CORE0_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I2C0_ALLOW (BIT(4)) -#define TEE_REG_CORE0_MM_HP_I2C0_ALLOW_M (TEE_REG_CORE0_MM_HP_I2C0_ALLOW_V << TEE_REG_CORE0_MM_HP_I2C0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I2C0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I2C0_ALLOW_S 4 -/** TEE_REG_CORE0_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I2C1_ALLOW (BIT(5)) -#define TEE_REG_CORE0_MM_HP_I2C1_ALLOW_M (TEE_REG_CORE0_MM_HP_I2C1_ALLOW_V << TEE_REG_CORE0_MM_HP_I2C1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I2C1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I2C1_ALLOW_S 5 -/** TEE_REG_CORE0_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I2S0_ALLOW (BIT(6)) -#define TEE_REG_CORE0_MM_HP_I2S0_ALLOW_M (TEE_REG_CORE0_MM_HP_I2S0_ALLOW_V << TEE_REG_CORE0_MM_HP_I2S0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I2S0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I2S0_ALLOW_S 6 -/** TEE_REG_CORE0_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I2S1_ALLOW (BIT(7)) -#define TEE_REG_CORE0_MM_HP_I2S1_ALLOW_M (TEE_REG_CORE0_MM_HP_I2S1_ALLOW_V << TEE_REG_CORE0_MM_HP_I2S1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I2S1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I2S1_ALLOW_S 7 -/** TEE_REG_CORE0_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I2S2_ALLOW (BIT(8)) -#define TEE_REG_CORE0_MM_HP_I2S2_ALLOW_M (TEE_REG_CORE0_MM_HP_I2S2_ALLOW_V << TEE_REG_CORE0_MM_HP_I2S2_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I2S2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I2S2_ALLOW_S 8 -/** TEE_REG_CORE0_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PCNT_ALLOW (BIT(9)) -#define TEE_REG_CORE0_MM_HP_PCNT_ALLOW_M (TEE_REG_CORE0_MM_HP_PCNT_ALLOW_V << TEE_REG_CORE0_MM_HP_PCNT_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PCNT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PCNT_ALLOW_S 9 -/** TEE_REG_CORE0_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UART0_ALLOW (BIT(10)) -#define TEE_REG_CORE0_MM_HP_UART0_ALLOW_M (TEE_REG_CORE0_MM_HP_UART0_ALLOW_V << TEE_REG_CORE0_MM_HP_UART0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UART0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UART0_ALLOW_S 10 -/** TEE_REG_CORE0_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UART1_ALLOW (BIT(11)) -#define TEE_REG_CORE0_MM_HP_UART1_ALLOW_M (TEE_REG_CORE0_MM_HP_UART1_ALLOW_V << TEE_REG_CORE0_MM_HP_UART1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UART1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UART1_ALLOW_S 11 -/** TEE_REG_CORE0_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UART2_ALLOW (BIT(12)) -#define TEE_REG_CORE0_MM_HP_UART2_ALLOW_M (TEE_REG_CORE0_MM_HP_UART2_ALLOW_V << TEE_REG_CORE0_MM_HP_UART2_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UART2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UART2_ALLOW_S 12 -/** TEE_REG_CORE0_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UART3_ALLOW (BIT(13)) -#define TEE_REG_CORE0_MM_HP_UART3_ALLOW_M (TEE_REG_CORE0_MM_HP_UART3_ALLOW_V << TEE_REG_CORE0_MM_HP_UART3_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UART3_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UART3_ALLOW_S 13 -/** TEE_REG_CORE0_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UART4_ALLOW (BIT(14)) -#define TEE_REG_CORE0_MM_HP_UART4_ALLOW_M (TEE_REG_CORE0_MM_HP_UART4_ALLOW_V << TEE_REG_CORE0_MM_HP_UART4_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UART4_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UART4_ALLOW_S 14 -/** TEE_REG_CORE0_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_PARLIO_ALLOW (BIT(15)) -#define TEE_REG_CORE0_MM_HP_PARLIO_ALLOW_M (TEE_REG_CORE0_MM_HP_PARLIO_ALLOW_V << TEE_REG_CORE0_MM_HP_PARLIO_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_PARLIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_PARLIO_ALLOW_S 15 -/** TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW (BIT(16)) -#define TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW_M (TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW_V << TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_GPSPI2_ALLOW_S 16 -/** TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW (BIT(17)) -#define TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW_M (TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW_V << TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_GPSPI3_ALLOW_S 17 -/** TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW (BIT(18)) -#define TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW_M (TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW_V << TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_USBDEVICE_ALLOW_S 18 -/** TEE_REG_CORE0_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_LEDC_ALLOW (BIT(19)) -#define TEE_REG_CORE0_MM_HP_LEDC_ALLOW_M (TEE_REG_CORE0_MM_HP_LEDC_ALLOW_V << TEE_REG_CORE0_MM_HP_LEDC_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_LEDC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_LEDC_ALLOW_S 19 -/** TEE_REG_CORE0_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_ETM_ALLOW (BIT(21)) -#define TEE_REG_CORE0_MM_HP_ETM_ALLOW_M (TEE_REG_CORE0_MM_HP_ETM_ALLOW_V << TEE_REG_CORE0_MM_HP_ETM_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_ETM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_ETM_ALLOW_S 21 -/** TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW (BIT(22)) -#define TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW_M (TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW_V << TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_INTRMTX_ALLOW_S 22 -/** TEE_REG_CORE0_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_TWAI0_ALLOW (BIT(23)) -#define TEE_REG_CORE0_MM_HP_TWAI0_ALLOW_M (TEE_REG_CORE0_MM_HP_TWAI0_ALLOW_V << TEE_REG_CORE0_MM_HP_TWAI0_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_TWAI0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_TWAI0_ALLOW_S 23 -/** TEE_REG_CORE0_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_TWAI1_ALLOW (BIT(24)) -#define TEE_REG_CORE0_MM_HP_TWAI1_ALLOW_M (TEE_REG_CORE0_MM_HP_TWAI1_ALLOW_V << TEE_REG_CORE0_MM_HP_TWAI1_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_TWAI1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_TWAI1_ALLOW_S 24 -/** TEE_REG_CORE0_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_TWAI2_ALLOW (BIT(25)) -#define TEE_REG_CORE0_MM_HP_TWAI2_ALLOW_M (TEE_REG_CORE0_MM_HP_TWAI2_ALLOW_V << TEE_REG_CORE0_MM_HP_TWAI2_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_TWAI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_TWAI2_ALLOW_S 25 -/** TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW (BIT(26)) -#define TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW_M (TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW_V << TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I3C_MST_ALLOW_S 26 -/** TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW (BIT(27)) -#define TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW_M (TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW_V << TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_I3C_SLV_ALLOW_S 27 -/** TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW (BIT(28)) -#define TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW_M (TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW_V << TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_LCDCAM_ALLOW_S 28 -/** TEE_REG_CORE0_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_ADC_ALLOW (BIT(30)) -#define TEE_REG_CORE0_MM_HP_ADC_ALLOW_M (TEE_REG_CORE0_MM_HP_ADC_ALLOW_V << TEE_REG_CORE0_MM_HP_ADC_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_ADC_ALLOW_S 30 -/** TEE_REG_CORE0_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_UHCI_ALLOW (BIT(31)) -#define TEE_REG_CORE0_MM_HP_UHCI_ALLOW_M (TEE_REG_CORE0_MM_HP_UHCI_ALLOW_V << TEE_REG_CORE0_MM_HP_UHCI_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_UHCI_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_UHCI_ALLOW_S 31 +/** PMS_CORE0_MM_HP_PERI_PMS_REG2_REG register + * Permission control register2 for HP CPU0 in machine mode + */ +#define PMS_CORE0_MM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x10) +/** PMS_CORE0_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_MCPWM0_ALLOW (BIT(0)) +#define PMS_CORE0_MM_HP_MCPWM0_ALLOW_M (PMS_CORE0_MM_HP_MCPWM0_ALLOW_V << PMS_CORE0_MM_HP_MCPWM0_ALLOW_S) +#define PMS_CORE0_MM_HP_MCPWM0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_MCPWM0_ALLOW_S 0 +/** PMS_CORE0_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_MCPWM1_ALLOW (BIT(1)) +#define PMS_CORE0_MM_HP_MCPWM1_ALLOW_M (PMS_CORE0_MM_HP_MCPWM1_ALLOW_V << PMS_CORE0_MM_HP_MCPWM1_ALLOW_S) +#define PMS_CORE0_MM_HP_MCPWM1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_MCPWM1_ALLOW_S 1 +/** PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP timer + * group0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) +#define PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW_M (PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW_V << PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW_S) +#define PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_TIMER_GROUP0_ALLOW_S 2 +/** PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) +#define PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW_M (PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW_V << PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW_S) +#define PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_TIMER_GROUP1_ALLOW_S 3 +/** PMS_CORE0_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I2C0_ALLOW (BIT(4)) +#define PMS_CORE0_MM_HP_I2C0_ALLOW_M (PMS_CORE0_MM_HP_I2C0_ALLOW_V << PMS_CORE0_MM_HP_I2C0_ALLOW_S) +#define PMS_CORE0_MM_HP_I2C0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I2C0_ALLOW_S 4 +/** PMS_CORE0_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I2C1_ALLOW (BIT(5)) +#define PMS_CORE0_MM_HP_I2C1_ALLOW_M (PMS_CORE0_MM_HP_I2C1_ALLOW_V << PMS_CORE0_MM_HP_I2C1_ALLOW_S) +#define PMS_CORE0_MM_HP_I2C1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I2C1_ALLOW_S 5 +/** PMS_CORE0_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I2S0_ALLOW (BIT(6)) +#define PMS_CORE0_MM_HP_I2S0_ALLOW_M (PMS_CORE0_MM_HP_I2S0_ALLOW_V << PMS_CORE0_MM_HP_I2S0_ALLOW_S) +#define PMS_CORE0_MM_HP_I2S0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I2S0_ALLOW_S 6 +/** PMS_CORE0_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I2S1_ALLOW (BIT(7)) +#define PMS_CORE0_MM_HP_I2S1_ALLOW_M (PMS_CORE0_MM_HP_I2S1_ALLOW_V << PMS_CORE0_MM_HP_I2S1_ALLOW_S) +#define PMS_CORE0_MM_HP_I2S1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I2S1_ALLOW_S 7 +/** PMS_CORE0_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I2S2_ALLOW (BIT(8)) +#define PMS_CORE0_MM_HP_I2S2_ALLOW_M (PMS_CORE0_MM_HP_I2S2_ALLOW_V << PMS_CORE0_MM_HP_I2S2_ALLOW_S) +#define PMS_CORE0_MM_HP_I2S2_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I2S2_ALLOW_S 8 +/** PMS_CORE0_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_PCNT_ALLOW (BIT(9)) +#define PMS_CORE0_MM_HP_PCNT_ALLOW_M (PMS_CORE0_MM_HP_PCNT_ALLOW_V << PMS_CORE0_MM_HP_PCNT_ALLOW_S) +#define PMS_CORE0_MM_HP_PCNT_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PCNT_ALLOW_S 9 +/** PMS_CORE0_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UART0_ALLOW (BIT(10)) +#define PMS_CORE0_MM_HP_UART0_ALLOW_M (PMS_CORE0_MM_HP_UART0_ALLOW_V << PMS_CORE0_MM_HP_UART0_ALLOW_S) +#define PMS_CORE0_MM_HP_UART0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UART0_ALLOW_S 10 +/** PMS_CORE0_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UART1_ALLOW (BIT(11)) +#define PMS_CORE0_MM_HP_UART1_ALLOW_M (PMS_CORE0_MM_HP_UART1_ALLOW_V << PMS_CORE0_MM_HP_UART1_ALLOW_S) +#define PMS_CORE0_MM_HP_UART1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UART1_ALLOW_S 11 +/** PMS_CORE0_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UART2_ALLOW (BIT(12)) +#define PMS_CORE0_MM_HP_UART2_ALLOW_M (PMS_CORE0_MM_HP_UART2_ALLOW_V << PMS_CORE0_MM_HP_UART2_ALLOW_S) +#define PMS_CORE0_MM_HP_UART2_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UART2_ALLOW_S 12 +/** PMS_CORE0_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UART3_ALLOW (BIT(13)) +#define PMS_CORE0_MM_HP_UART3_ALLOW_M (PMS_CORE0_MM_HP_UART3_ALLOW_V << PMS_CORE0_MM_HP_UART3_ALLOW_S) +#define PMS_CORE0_MM_HP_UART3_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UART3_ALLOW_S 13 +/** PMS_CORE0_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UART4_ALLOW (BIT(14)) +#define PMS_CORE0_MM_HP_UART4_ALLOW_M (PMS_CORE0_MM_HP_UART4_ALLOW_V << PMS_CORE0_MM_HP_UART4_ALLOW_S) +#define PMS_CORE0_MM_HP_UART4_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UART4_ALLOW_S 14 +/** PMS_CORE0_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_PARLIO_ALLOW (BIT(15)) +#define PMS_CORE0_MM_HP_PARLIO_ALLOW_M (PMS_CORE0_MM_HP_PARLIO_ALLOW_V << PMS_CORE0_MM_HP_PARLIO_ALLOW_S) +#define PMS_CORE0_MM_HP_PARLIO_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_PARLIO_ALLOW_S 15 +/** PMS_CORE0_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_GPSPI2_ALLOW (BIT(16)) +#define PMS_CORE0_MM_HP_GPSPI2_ALLOW_M (PMS_CORE0_MM_HP_GPSPI2_ALLOW_V << PMS_CORE0_MM_HP_GPSPI2_ALLOW_S) +#define PMS_CORE0_MM_HP_GPSPI2_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_GPSPI2_ALLOW_S 16 +/** PMS_CORE0_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_GPSPI3_ALLOW (BIT(17)) +#define PMS_CORE0_MM_HP_GPSPI3_ALLOW_M (PMS_CORE0_MM_HP_GPSPI3_ALLOW_V << PMS_CORE0_MM_HP_GPSPI3_ALLOW_S) +#define PMS_CORE0_MM_HP_GPSPI3_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_GPSPI3_ALLOW_S 17 +/** PMS_CORE0_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP USB + * Serial/JTAG Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_USBDEVICE_ALLOW (BIT(18)) +#define PMS_CORE0_MM_HP_USBDEVICE_ALLOW_M (PMS_CORE0_MM_HP_USBDEVICE_ALLOW_V << PMS_CORE0_MM_HP_USBDEVICE_ALLOW_S) +#define PMS_CORE0_MM_HP_USBDEVICE_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_USBDEVICE_ALLOW_S 18 +/** PMS_CORE0_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_LEDC_ALLOW (BIT(19)) +#define PMS_CORE0_MM_HP_LEDC_ALLOW_M (PMS_CORE0_MM_HP_LEDC_ALLOW_V << PMS_CORE0_MM_HP_LEDC_ALLOW_S) +#define PMS_CORE0_MM_HP_LEDC_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_LEDC_ALLOW_S 19 +/** PMS_CORE0_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP ETM (Event + * Task Matrix). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_ETM_ALLOW (BIT(21)) +#define PMS_CORE0_MM_HP_ETM_ALLOW_M (PMS_CORE0_MM_HP_ETM_ALLOW_V << PMS_CORE0_MM_HP_ETM_ALLOW_S) +#define PMS_CORE0_MM_HP_ETM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_ETM_ALLOW_S 21 +/** PMS_CORE0_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_INTRMTX_ALLOW (BIT(22)) +#define PMS_CORE0_MM_HP_INTRMTX_ALLOW_M (PMS_CORE0_MM_HP_INTRMTX_ALLOW_V << PMS_CORE0_MM_HP_INTRMTX_ALLOW_S) +#define PMS_CORE0_MM_HP_INTRMTX_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_INTRMTX_ALLOW_S 22 +/** PMS_CORE0_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_TWAI0_ALLOW (BIT(23)) +#define PMS_CORE0_MM_HP_TWAI0_ALLOW_M (PMS_CORE0_MM_HP_TWAI0_ALLOW_V << PMS_CORE0_MM_HP_TWAI0_ALLOW_S) +#define PMS_CORE0_MM_HP_TWAI0_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_TWAI0_ALLOW_S 23 +/** PMS_CORE0_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_TWAI1_ALLOW (BIT(24)) +#define PMS_CORE0_MM_HP_TWAI1_ALLOW_M (PMS_CORE0_MM_HP_TWAI1_ALLOW_V << PMS_CORE0_MM_HP_TWAI1_ALLOW_S) +#define PMS_CORE0_MM_HP_TWAI1_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_TWAI1_ALLOW_S 24 +/** PMS_CORE0_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_TWAI2_ALLOW (BIT(25)) +#define PMS_CORE0_MM_HP_TWAI2_ALLOW_M (PMS_CORE0_MM_HP_TWAI2_ALLOW_V << PMS_CORE0_MM_HP_TWAI2_ALLOW_S) +#define PMS_CORE0_MM_HP_TWAI2_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_TWAI2_ALLOW_S 25 +/** PMS_CORE0_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I3C_MST_ALLOW (BIT(26)) +#define PMS_CORE0_MM_HP_I3C_MST_ALLOW_M (PMS_CORE0_MM_HP_I3C_MST_ALLOW_V << PMS_CORE0_MM_HP_I3C_MST_ALLOW_S) +#define PMS_CORE0_MM_HP_I3C_MST_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I3C_MST_ALLOW_S 26 +/** PMS_CORE0_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_I3C_SLV_ALLOW (BIT(27)) +#define PMS_CORE0_MM_HP_I3C_SLV_ALLOW_M (PMS_CORE0_MM_HP_I3C_SLV_ALLOW_V << PMS_CORE0_MM_HP_I3C_SLV_ALLOW_S) +#define PMS_CORE0_MM_HP_I3C_SLV_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_I3C_SLV_ALLOW_S 27 +/** PMS_CORE0_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_LCDCAM_ALLOW (BIT(28)) +#define PMS_CORE0_MM_HP_LCDCAM_ALLOW_M (PMS_CORE0_MM_HP_LCDCAM_ALLOW_V << PMS_CORE0_MM_HP_LCDCAM_ALLOW_S) +#define PMS_CORE0_MM_HP_LCDCAM_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_LCDCAM_ALLOW_S 28 +/** PMS_CORE0_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_ADC_ALLOW (BIT(30)) +#define PMS_CORE0_MM_HP_ADC_ALLOW_M (PMS_CORE0_MM_HP_ADC_ALLOW_V << PMS_CORE0_MM_HP_ADC_ALLOW_S) +#define PMS_CORE0_MM_HP_ADC_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_ADC_ALLOW_S 30 +/** PMS_CORE0_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_UHCI_ALLOW (BIT(31)) +#define PMS_CORE0_MM_HP_UHCI_ALLOW_M (PMS_CORE0_MM_HP_UHCI_ALLOW_V << PMS_CORE0_MM_HP_UHCI_ALLOW_S) +#define PMS_CORE0_MM_HP_UHCI_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_UHCI_ALLOW_S 31 -/** TEE_CORE0_MM_PMS_REG3_REG register - * NA - */ -#define TEE_CORE0_MM_PMS_REG3_REG (DR_REG_TEE_BASE + 0x14) -/** TEE_REG_CORE0_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_GPIO_ALLOW (BIT(0)) -#define TEE_REG_CORE0_MM_HP_GPIO_ALLOW_M (TEE_REG_CORE0_MM_HP_GPIO_ALLOW_V << TEE_REG_CORE0_MM_HP_GPIO_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_GPIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_GPIO_ALLOW_S 0 -/** TEE_REG_CORE0_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_IOMUX_ALLOW (BIT(1)) -#define TEE_REG_CORE0_MM_HP_IOMUX_ALLOW_M (TEE_REG_CORE0_MM_HP_IOMUX_ALLOW_V << TEE_REG_CORE0_MM_HP_IOMUX_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_IOMUX_ALLOW_S 1 -/** TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW (BIT(2)) -#define TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW_M (TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW_V << TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_SYSTIMER_ALLOW_S 2 -/** TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW (BIT(3)) -#define TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW_M (TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW_V << TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_SYS_REG_ALLOW_S 3 -/** TEE_REG_CORE0_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_MM_HP_CLKRST_ALLOW (BIT(4)) -#define TEE_REG_CORE0_MM_HP_CLKRST_ALLOW_M (TEE_REG_CORE0_MM_HP_CLKRST_ALLOW_V << TEE_REG_CORE0_MM_HP_CLKRST_ALLOW_S) -#define TEE_REG_CORE0_MM_HP_CLKRST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_MM_HP_CLKRST_ALLOW_S 4 +/** PMS_CORE0_MM_HP_PERI_PMS_REG3_REG register + * Permission control register3 for HP CPU0 in machine mode + */ +#define PMS_CORE0_MM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x14) +/** PMS_CORE0_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_GPIO_ALLOW (BIT(0)) +#define PMS_CORE0_MM_HP_GPIO_ALLOW_M (PMS_CORE0_MM_HP_GPIO_ALLOW_V << PMS_CORE0_MM_HP_GPIO_ALLOW_S) +#define PMS_CORE0_MM_HP_GPIO_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_GPIO_ALLOW_S 0 +/** PMS_CORE0_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_IOMUX_ALLOW (BIT(1)) +#define PMS_CORE0_MM_HP_IOMUX_ALLOW_M (PMS_CORE0_MM_HP_IOMUX_ALLOW_V << PMS_CORE0_MM_HP_IOMUX_ALLOW_S) +#define PMS_CORE0_MM_HP_IOMUX_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_IOMUX_ALLOW_S 1 +/** PMS_CORE0_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP system + * timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_SYSTIMER_ALLOW (BIT(2)) +#define PMS_CORE0_MM_HP_SYSTIMER_ALLOW_M (PMS_CORE0_MM_HP_SYSTIMER_ALLOW_V << PMS_CORE0_MM_HP_SYSTIMER_ALLOW_S) +#define PMS_CORE0_MM_HP_SYSTIMER_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_SYSTIMER_ALLOW_S 2 +/** PMS_CORE0_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_SYS_REG_ALLOW (BIT(3)) +#define PMS_CORE0_MM_HP_SYS_REG_ALLOW_M (PMS_CORE0_MM_HP_SYS_REG_ALLOW_V << PMS_CORE0_MM_HP_SYS_REG_ALLOW_S) +#define PMS_CORE0_MM_HP_SYS_REG_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_SYS_REG_ALLOW_S 3 +/** PMS_CORE0_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in machine mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_MM_HP_CLKRST_ALLOW (BIT(4)) +#define PMS_CORE0_MM_HP_CLKRST_ALLOW_M (PMS_CORE0_MM_HP_CLKRST_ALLOW_V << PMS_CORE0_MM_HP_CLKRST_ALLOW_S) +#define PMS_CORE0_MM_HP_CLKRST_ALLOW_V 0x00000001U +#define PMS_CORE0_MM_HP_CLKRST_ALLOW_S 4 -/** TEE_CORE0_UM_PMS_REG0_REG register - * NA - */ -#define TEE_CORE0_UM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x18) -/** TEE_REG_CORE0_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_PSRAM_ALLOW (BIT(0)) -#define TEE_REG_CORE0_UM_PSRAM_ALLOW_M (TEE_REG_CORE0_UM_PSRAM_ALLOW_V << TEE_REG_CORE0_UM_PSRAM_ALLOW_S) -#define TEE_REG_CORE0_UM_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_PSRAM_ALLOW_S 0 -/** TEE_REG_CORE0_UM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_FLASH_ALLOW (BIT(1)) -#define TEE_REG_CORE0_UM_FLASH_ALLOW_M (TEE_REG_CORE0_UM_FLASH_ALLOW_V << TEE_REG_CORE0_UM_FLASH_ALLOW_S) -#define TEE_REG_CORE0_UM_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_FLASH_ALLOW_S 1 -/** TEE_REG_CORE0_UM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_L2MEM_ALLOW (BIT(2)) -#define TEE_REG_CORE0_UM_L2MEM_ALLOW_M (TEE_REG_CORE0_UM_L2MEM_ALLOW_V << TEE_REG_CORE0_UM_L2MEM_ALLOW_S) -#define TEE_REG_CORE0_UM_L2MEM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_L2MEM_ALLOW_S 2 -/** TEE_REG_CORE0_UM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_L2ROM_ALLOW (BIT(3)) -#define TEE_REG_CORE0_UM_L2ROM_ALLOW_M (TEE_REG_CORE0_UM_L2ROM_ALLOW_V << TEE_REG_CORE0_UM_L2ROM_ALLOW_S) -#define TEE_REG_CORE0_UM_L2ROM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_L2ROM_ALLOW_S 3 -/** TEE_REG_CORE0_UM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_TRACE0_ALLOW (BIT(6)) -#define TEE_REG_CORE0_UM_TRACE0_ALLOW_M (TEE_REG_CORE0_UM_TRACE0_ALLOW_V << TEE_REG_CORE0_UM_TRACE0_ALLOW_S) -#define TEE_REG_CORE0_UM_TRACE0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_TRACE0_ALLOW_S 6 -/** TEE_REG_CORE0_UM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_TRACE1_ALLOW (BIT(7)) -#define TEE_REG_CORE0_UM_TRACE1_ALLOW_M (TEE_REG_CORE0_UM_TRACE1_ALLOW_V << TEE_REG_CORE0_UM_TRACE1_ALLOW_S) -#define TEE_REG_CORE0_UM_TRACE1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_TRACE1_ALLOW_S 7 -/** TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW (BIT(8)) -#define TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW_M (TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW_V << TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW_S) -#define TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_CPU_BUS_MON_ALLOW_S 8 -/** TEE_REG_CORE0_UM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_L2MEM_MON_ALLOW (BIT(9)) -#define TEE_REG_CORE0_UM_L2MEM_MON_ALLOW_M (TEE_REG_CORE0_UM_L2MEM_MON_ALLOW_V << TEE_REG_CORE0_UM_L2MEM_MON_ALLOW_S) -#define TEE_REG_CORE0_UM_L2MEM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_L2MEM_MON_ALLOW_S 9 -/** TEE_REG_CORE0_UM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_TCM_MON_ALLOW (BIT(10)) -#define TEE_REG_CORE0_UM_TCM_MON_ALLOW_M (TEE_REG_CORE0_UM_TCM_MON_ALLOW_V << TEE_REG_CORE0_UM_TCM_MON_ALLOW_S) -#define TEE_REG_CORE0_UM_TCM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_TCM_MON_ALLOW_S 10 -/** TEE_REG_CORE0_UM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_CACHE_ALLOW (BIT(11)) -#define TEE_REG_CORE0_UM_CACHE_ALLOW_M (TEE_REG_CORE0_UM_CACHE_ALLOW_V << TEE_REG_CORE0_UM_CACHE_ALLOW_S) -#define TEE_REG_CORE0_UM_CACHE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_CACHE_ALLOW_S 11 +/** PMS_CORE0_UM_HP_PERI_PMS_REG0_REG register + * Permission control register0 for HP CPU0 in user mode + */ +#define PMS_CORE0_UM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x18) +/** PMS_CORE0_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_PSRAM_ALLOW (BIT(0)) +#define PMS_CORE0_UM_PSRAM_ALLOW_M (PMS_CORE0_UM_PSRAM_ALLOW_V << PMS_CORE0_UM_PSRAM_ALLOW_S) +#define PMS_CORE0_UM_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_PSRAM_ALLOW_S 0 +/** PMS_CORE0_UM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_FLASH_ALLOW (BIT(1)) +#define PMS_CORE0_UM_FLASH_ALLOW_M (PMS_CORE0_UM_FLASH_ALLOW_V << PMS_CORE0_UM_FLASH_ALLOW_S) +#define PMS_CORE0_UM_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_FLASH_ALLOW_S 1 +/** PMS_CORE0_UM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP L2MEM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_L2MEM_ALLOW (BIT(2)) +#define PMS_CORE0_UM_L2MEM_ALLOW_M (PMS_CORE0_UM_L2MEM_ALLOW_V << PMS_CORE0_UM_L2MEM_ALLOW_S) +#define PMS_CORE0_UM_L2MEM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_L2MEM_ALLOW_S 2 +/** PMS_CORE0_UM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_L2ROM_ALLOW (BIT(3)) +#define PMS_CORE0_UM_L2ROM_ALLOW_M (PMS_CORE0_UM_L2ROM_ALLOW_V << PMS_CORE0_UM_L2ROM_ALLOW_S) +#define PMS_CORE0_UM_L2ROM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_L2ROM_ALLOW_S 3 +/** PMS_CORE0_UM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_TRACE0_ALLOW (BIT(6)) +#define PMS_CORE0_UM_TRACE0_ALLOW_M (PMS_CORE0_UM_TRACE0_ALLOW_V << PMS_CORE0_UM_TRACE0_ALLOW_S) +#define PMS_CORE0_UM_TRACE0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_TRACE0_ALLOW_S 6 +/** PMS_CORE0_UM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_TRACE1_ALLOW (BIT(7)) +#define PMS_CORE0_UM_TRACE1_ALLOW_M (PMS_CORE0_UM_TRACE1_ALLOW_V << PMS_CORE0_UM_TRACE1_ALLOW_S) +#define PMS_CORE0_UM_TRACE1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_TRACE1_ALLOW_S 7 +/** PMS_CORE0_UM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access CPU bus monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_CPU_BUS_MON_ALLOW (BIT(8)) +#define PMS_CORE0_UM_CPU_BUS_MON_ALLOW_M (PMS_CORE0_UM_CPU_BUS_MON_ALLOW_V << PMS_CORE0_UM_CPU_BUS_MON_ALLOW_S) +#define PMS_CORE0_UM_CPU_BUS_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_CPU_BUS_MON_ALLOW_S 8 +/** PMS_CORE0_UM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_L2MEM_MON_ALLOW (BIT(9)) +#define PMS_CORE0_UM_L2MEM_MON_ALLOW_M (PMS_CORE0_UM_L2MEM_MON_ALLOW_V << PMS_CORE0_UM_L2MEM_MON_ALLOW_S) +#define PMS_CORE0_UM_L2MEM_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_L2MEM_MON_ALLOW_S 9 +/** PMS_CORE0_UM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_TCM_MON_ALLOW (BIT(10)) +#define PMS_CORE0_UM_TCM_MON_ALLOW_M (PMS_CORE0_UM_TCM_MON_ALLOW_V << PMS_CORE0_UM_TCM_MON_ALLOW_S) +#define PMS_CORE0_UM_TCM_MON_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_TCM_MON_ALLOW_S 10 +/** PMS_CORE0_UM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_CACHE_ALLOW (BIT(11)) +#define PMS_CORE0_UM_CACHE_ALLOW_M (PMS_CORE0_UM_CACHE_ALLOW_V << PMS_CORE0_UM_CACHE_ALLOW_S) +#define PMS_CORE0_UM_CACHE_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_CACHE_ALLOW_S 11 -/** TEE_CORE0_UM_PMS_REG1_REG register - * NA - */ -#define TEE_CORE0_UM_PMS_REG1_REG (DR_REG_TEE_BASE + 0x1c) -/** TEE_REG_CORE0_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_USBOTG_ALLOW (BIT(0)) -#define TEE_REG_CORE0_UM_HP_USBOTG_ALLOW_M (TEE_REG_CORE0_UM_HP_USBOTG_ALLOW_V << TEE_REG_CORE0_UM_HP_USBOTG_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_USBOTG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_USBOTG_ALLOW_S 0 -/** TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW (BIT(1)) -#define TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW_M (TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW_V << TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_USBOTG11_ALLOW_S 1 -/** TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) -#define TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_M (TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_V << TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_S 2 -/** TEE_REG_CORE0_UM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_GDMA_ALLOW (BIT(3)) -#define TEE_REG_CORE0_UM_HP_GDMA_ALLOW_M (TEE_REG_CORE0_UM_HP_GDMA_ALLOW_V << TEE_REG_CORE0_UM_HP_GDMA_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_GDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_GDMA_ALLOW_S 3 -/** TEE_REG_CORE0_UM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_REGDMA_ALLOW (BIT(4)) -#define TEE_REG_CORE0_UM_HP_REGDMA_ALLOW_M (TEE_REG_CORE0_UM_HP_REGDMA_ALLOW_V << TEE_REG_CORE0_UM_HP_REGDMA_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_REGDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_REGDMA_ALLOW_S 4 -/** TEE_REG_CORE0_UM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_SDMMC_ALLOW (BIT(5)) -#define TEE_REG_CORE0_UM_HP_SDMMC_ALLOW_M (TEE_REG_CORE0_UM_HP_SDMMC_ALLOW_V << TEE_REG_CORE0_UM_HP_SDMMC_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_SDMMC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_SDMMC_ALLOW_S 5 -/** TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW (BIT(6)) -#define TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW_M (TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW_V << TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_AHB_PDMA_ALLOW_S 6 -/** TEE_REG_CORE0_UM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_JPEG_ALLOW (BIT(7)) -#define TEE_REG_CORE0_UM_HP_JPEG_ALLOW_M (TEE_REG_CORE0_UM_HP_JPEG_ALLOW_V << TEE_REG_CORE0_UM_HP_JPEG_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_JPEG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_JPEG_ALLOW_S 7 -/** TEE_REG_CORE0_UM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PPA_ALLOW (BIT(8)) -#define TEE_REG_CORE0_UM_HP_PPA_ALLOW_M (TEE_REG_CORE0_UM_HP_PPA_ALLOW_V << TEE_REG_CORE0_UM_HP_PPA_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PPA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PPA_ALLOW_S 8 -/** TEE_REG_CORE0_UM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_DMA2D_ALLOW (BIT(9)) -#define TEE_REG_CORE0_UM_HP_DMA2D_ALLOW_M (TEE_REG_CORE0_UM_HP_DMA2D_ALLOW_V << TEE_REG_CORE0_UM_HP_DMA2D_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_DMA2D_ALLOW_S 9 -/** TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW (BIT(10)) -#define TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW_M (TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW_V << TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_KEY_MANAGER_ALLOW_S 10 -/** TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW (BIT(11)) -#define TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW_M (TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW_V << TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_AXI_PDMA_ALLOW_S 11 -/** TEE_REG_CORE0_UM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_FLASH_ALLOW (BIT(12)) -#define TEE_REG_CORE0_UM_HP_FLASH_ALLOW_M (TEE_REG_CORE0_UM_HP_FLASH_ALLOW_V << TEE_REG_CORE0_UM_HP_FLASH_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_FLASH_ALLOW_S 12 -/** TEE_REG_CORE0_UM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PSRAM_ALLOW (BIT(13)) -#define TEE_REG_CORE0_UM_HP_PSRAM_ALLOW_M (TEE_REG_CORE0_UM_HP_PSRAM_ALLOW_V << TEE_REG_CORE0_UM_HP_PSRAM_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PSRAM_ALLOW_S 13 -/** TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW (BIT(14)) -#define TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW_M (TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW_V << TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_CRYPTO_ALLOW_S 14 -/** TEE_REG_CORE0_UM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_GMAC_ALLOW (BIT(15)) -#define TEE_REG_CORE0_UM_HP_GMAC_ALLOW_M (TEE_REG_CORE0_UM_HP_GMAC_ALLOW_V << TEE_REG_CORE0_UM_HP_GMAC_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_GMAC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_GMAC_ALLOW_S 15 -/** TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW (BIT(16)) -#define TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW_M (TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW_V << TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_USB_PHY_ALLOW_S 16 -/** TEE_REG_CORE0_UM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PVT_ALLOW (BIT(17)) -#define TEE_REG_CORE0_UM_HP_PVT_ALLOW_M (TEE_REG_CORE0_UM_HP_PVT_ALLOW_V << TEE_REG_CORE0_UM_HP_PVT_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PVT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PVT_ALLOW_S 17 -/** TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW (BIT(18)) -#define TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW_M (TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW_V << TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_CSI_HOST_ALLOW_S 18 -/** TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW (BIT(19)) -#define TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW_M (TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW_V << TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_DSI_HOST_ALLOW_S 19 -/** TEE_REG_CORE0_UM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_ISP_ALLOW (BIT(20)) -#define TEE_REG_CORE0_UM_HP_ISP_ALLOW_M (TEE_REG_CORE0_UM_HP_ISP_ALLOW_V << TEE_REG_CORE0_UM_HP_ISP_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_ISP_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_ISP_ALLOW_S 20 -/** TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW (BIT(21)) -#define TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW_M (TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW_V << TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_H264_CORE_ALLOW_S 21 -/** TEE_REG_CORE0_UM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_RMT_ALLOW (BIT(22)) -#define TEE_REG_CORE0_UM_HP_RMT_ALLOW_M (TEE_REG_CORE0_UM_HP_RMT_ALLOW_V << TEE_REG_CORE0_UM_HP_RMT_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_RMT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_RMT_ALLOW_S 22 -/** TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW (BIT(23)) -#define TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW_M (TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW_V << TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_BITSRAMBLER_ALLOW_S 23 -/** TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW (BIT(24)) -#define TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW_M (TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW_V << TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_AXI_ICM_ALLOW_S 24 -/** TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW (BIT(25)) -#define TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW_M (TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW_V << TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PERI_PMS_ALLOW_S 25 -/** TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW (BIT(26)) -#define TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW_M (TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW_V << TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_LP2HP_PERI_PMS_ALLOW_S 26 -/** TEE_REG_CORE0_UM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_DMA_PMS_ALLOW (BIT(27)) -#define TEE_REG_CORE0_UM_DMA_PMS_ALLOW_M (TEE_REG_CORE0_UM_DMA_PMS_ALLOW_V << TEE_REG_CORE0_UM_DMA_PMS_ALLOW_S) -#define TEE_REG_CORE0_UM_DMA_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_DMA_PMS_ALLOW_S 27 -/** TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW (BIT(28)) -#define TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW_M (TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW_V << TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_H264_DMA2D_ALLOW_S 28 +/** PMS_CORE0_UM_HP_PERI_PMS_REG1_REG register + * Permission control register1 for HP CPU0 in user mode + */ +#define PMS_CORE0_UM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x1c) +/** PMS_CORE0_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP high-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_USBOTG_ALLOW (BIT(0)) +#define PMS_CORE0_UM_HP_USBOTG_ALLOW_M (PMS_CORE0_UM_HP_USBOTG_ALLOW_V << PMS_CORE0_UM_HP_USBOTG_ALLOW_S) +#define PMS_CORE0_UM_HP_USBOTG_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_USBOTG_ALLOW_S 0 +/** PMS_CORE0_UM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP full-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_USBOTG11_ALLOW (BIT(1)) +#define PMS_CORE0_UM_HP_USBOTG11_ALLOW_M (PMS_CORE0_UM_HP_USBOTG11_ALLOW_V << PMS_CORE0_UM_HP_USBOTG11_ALLOW_S) +#define PMS_CORE0_UM_HP_USBOTG11_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_USBOTG11_ALLOW_S 1 +/** PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP full-speed USB + * 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) +#define PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_M (PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_V << PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_S) +#define PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_USBOTG11_WRAP_ALLOW_S 2 +/** PMS_CORE0_UM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_GDMA_ALLOW (BIT(3)) +#define PMS_CORE0_UM_HP_GDMA_ALLOW_M (PMS_CORE0_UM_HP_GDMA_ALLOW_V << PMS_CORE0_UM_HP_GDMA_ALLOW_S) +#define PMS_CORE0_UM_HP_GDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_GDMA_ALLOW_S 3 +/** PMS_CORE0_UM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP regdma. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE0_UM_HP_REGDMA_ALLOW (BIT(4)) +#define PMS_CORE0_UM_HP_REGDMA_ALLOW_M (PMS_CORE0_UM_HP_REGDMA_ALLOW_V << PMS_CORE0_UM_HP_REGDMA_ALLOW_S) +#define PMS_CORE0_UM_HP_REGDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_REGDMA_ALLOW_S 4 +/** PMS_CORE0_UM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_SDMMC_ALLOW (BIT(5)) +#define PMS_CORE0_UM_HP_SDMMC_ALLOW_M (PMS_CORE0_UM_HP_SDMMC_ALLOW_V << PMS_CORE0_UM_HP_SDMMC_ALLOW_S) +#define PMS_CORE0_UM_HP_SDMMC_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_SDMMC_ALLOW_S 5 +/** PMS_CORE0_UM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_AHB_PDMA_ALLOW (BIT(6)) +#define PMS_CORE0_UM_HP_AHB_PDMA_ALLOW_M (PMS_CORE0_UM_HP_AHB_PDMA_ALLOW_V << PMS_CORE0_UM_HP_AHB_PDMA_ALLOW_S) +#define PMS_CORE0_UM_HP_AHB_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_AHB_PDMA_ALLOW_S 6 +/** PMS_CORE0_UM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_JPEG_ALLOW (BIT(7)) +#define PMS_CORE0_UM_HP_JPEG_ALLOW_M (PMS_CORE0_UM_HP_JPEG_ALLOW_V << PMS_CORE0_UM_HP_JPEG_ALLOW_S) +#define PMS_CORE0_UM_HP_JPEG_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_JPEG_ALLOW_S 7 +/** PMS_CORE0_UM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_PPA_ALLOW (BIT(8)) +#define PMS_CORE0_UM_HP_PPA_ALLOW_M (PMS_CORE0_UM_HP_PPA_ALLOW_V << PMS_CORE0_UM_HP_PPA_ALLOW_S) +#define PMS_CORE0_UM_HP_PPA_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PPA_ALLOW_S 8 +/** PMS_CORE0_UM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_DMA2D_ALLOW (BIT(9)) +#define PMS_CORE0_UM_HP_DMA2D_ALLOW_M (PMS_CORE0_UM_HP_DMA2D_ALLOW_V << PMS_CORE0_UM_HP_DMA2D_ALLOW_S) +#define PMS_CORE0_UM_HP_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_DMA2D_ALLOW_S 9 +/** PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW (BIT(10)) +#define PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW_M (PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW_V << PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW_S) +#define PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_KEY_MANAGER_ALLOW_S 10 +/** PMS_CORE0_UM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_AXI_PDMA_ALLOW (BIT(11)) +#define PMS_CORE0_UM_HP_AXI_PDMA_ALLOW_M (PMS_CORE0_UM_HP_AXI_PDMA_ALLOW_V << PMS_CORE0_UM_HP_AXI_PDMA_ALLOW_S) +#define PMS_CORE0_UM_HP_AXI_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_AXI_PDMA_ALLOW_S 11 +/** PMS_CORE0_UM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_FLASH_ALLOW (BIT(12)) +#define PMS_CORE0_UM_HP_FLASH_ALLOW_M (PMS_CORE0_UM_HP_FLASH_ALLOW_V << PMS_CORE0_UM_HP_FLASH_ALLOW_S) +#define PMS_CORE0_UM_HP_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_FLASH_ALLOW_S 12 +/** PMS_CORE0_UM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_PSRAM_ALLOW (BIT(13)) +#define PMS_CORE0_UM_HP_PSRAM_ALLOW_M (PMS_CORE0_UM_HP_PSRAM_ALLOW_V << PMS_CORE0_UM_HP_PSRAM_ALLOW_S) +#define PMS_CORE0_UM_HP_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PSRAM_ALLOW_S 13 +/** PMS_CORE0_UM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP CRYPTO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_CRYPTO_ALLOW (BIT(14)) +#define PMS_CORE0_UM_HP_CRYPTO_ALLOW_M (PMS_CORE0_UM_HP_CRYPTO_ALLOW_V << PMS_CORE0_UM_HP_CRYPTO_ALLOW_S) +#define PMS_CORE0_UM_HP_CRYPTO_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_CRYPTO_ALLOW_S 14 +/** PMS_CORE0_UM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_GMAC_ALLOW (BIT(15)) +#define PMS_CORE0_UM_HP_GMAC_ALLOW_M (PMS_CORE0_UM_HP_GMAC_ALLOW_V << PMS_CORE0_UM_HP_GMAC_ALLOW_S) +#define PMS_CORE0_UM_HP_GMAC_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_GMAC_ALLOW_S 15 +/** PMS_CORE0_UM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP high-speed USB + * 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_USB_PHY_ALLOW (BIT(16)) +#define PMS_CORE0_UM_HP_USB_PHY_ALLOW_M (PMS_CORE0_UM_HP_USB_PHY_ALLOW_V << PMS_CORE0_UM_HP_USB_PHY_ALLOW_S) +#define PMS_CORE0_UM_HP_USB_PHY_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_USB_PHY_ALLOW_S 16 +/** PMS_CORE0_UM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE0_UM_HP_PVT_ALLOW (BIT(17)) +#define PMS_CORE0_UM_HP_PVT_ALLOW_M (PMS_CORE0_UM_HP_PVT_ALLOW_V << PMS_CORE0_UM_HP_PVT_ALLOW_S) +#define PMS_CORE0_UM_HP_PVT_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PVT_ALLOW_S 17 +/** PMS_CORE0_UM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP MIPI CSI host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_CSI_HOST_ALLOW (BIT(18)) +#define PMS_CORE0_UM_HP_CSI_HOST_ALLOW_M (PMS_CORE0_UM_HP_CSI_HOST_ALLOW_V << PMS_CORE0_UM_HP_CSI_HOST_ALLOW_S) +#define PMS_CORE0_UM_HP_CSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_CSI_HOST_ALLOW_S 18 +/** PMS_CORE0_UM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP MIPI DSI host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_DSI_HOST_ALLOW (BIT(19)) +#define PMS_CORE0_UM_HP_DSI_HOST_ALLOW_M (PMS_CORE0_UM_HP_DSI_HOST_ALLOW_V << PMS_CORE0_UM_HP_DSI_HOST_ALLOW_S) +#define PMS_CORE0_UM_HP_DSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_DSI_HOST_ALLOW_S 19 +/** PMS_CORE0_UM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP ISP. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_ISP_ALLOW (BIT(20)) +#define PMS_CORE0_UM_HP_ISP_ALLOW_M (PMS_CORE0_UM_HP_ISP_ALLOW_V << PMS_CORE0_UM_HP_ISP_ALLOW_S) +#define PMS_CORE0_UM_HP_ISP_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_ISP_ALLOW_S 20 +/** PMS_CORE0_UM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP H264 Encoder. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_H264_CORE_ALLOW (BIT(21)) +#define PMS_CORE0_UM_HP_H264_CORE_ALLOW_M (PMS_CORE0_UM_HP_H264_CORE_ALLOW_V << PMS_CORE0_UM_HP_H264_CORE_ALLOW_S) +#define PMS_CORE0_UM_HP_H264_CORE_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_H264_CORE_ALLOW_S 21 +/** PMS_CORE0_UM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_RMT_ALLOW (BIT(22)) +#define PMS_CORE0_UM_HP_RMT_ALLOW_M (PMS_CORE0_UM_HP_RMT_ALLOW_V << PMS_CORE0_UM_HP_RMT_ALLOW_S) +#define PMS_CORE0_UM_HP_RMT_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_RMT_ALLOW_S 22 +/** PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP bit scrambler. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW (BIT(23)) +#define PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW_M (PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW_V << PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW_S) +#define PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_BITSRAMBLER_ALLOW_S 23 +/** PMS_CORE0_UM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_AXI_ICM_ALLOW (BIT(24)) +#define PMS_CORE0_UM_HP_AXI_ICM_ALLOW_M (PMS_CORE0_UM_HP_AXI_ICM_ALLOW_V << PMS_CORE0_UM_HP_AXI_ICM_ALLOW_S) +#define PMS_CORE0_UM_HP_AXI_ICM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_AXI_ICM_ALLOW_S 24 +/** PMS_CORE0_UM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_PERI_PMS_ALLOW (BIT(25)) +#define PMS_CORE0_UM_HP_PERI_PMS_ALLOW_M (PMS_CORE0_UM_HP_PERI_PMS_ALLOW_V << PMS_CORE0_UM_HP_PERI_PMS_ALLOW_S) +#define PMS_CORE0_UM_HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PERI_PMS_ALLOW_S 25 +/** PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW (BIT(26)) +#define PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW_M (PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW_V << PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW_S) +#define PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_LP2HP_PERI_PMS_ALLOW_S 26 +/** PMS_CORE0_UM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_DMA_PMS_ALLOW (BIT(27)) +#define PMS_CORE0_UM_DMA_PMS_ALLOW_M (PMS_CORE0_UM_DMA_PMS_ALLOW_V << PMS_CORE0_UM_DMA_PMS_ALLOW_S) +#define PMS_CORE0_UM_DMA_PMS_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_DMA_PMS_ALLOW_S 27 +/** PMS_CORE0_UM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_H264_DMA2D_ALLOW (BIT(28)) +#define PMS_CORE0_UM_HP_H264_DMA2D_ALLOW_M (PMS_CORE0_UM_HP_H264_DMA2D_ALLOW_V << PMS_CORE0_UM_HP_H264_DMA2D_ALLOW_S) +#define PMS_CORE0_UM_HP_H264_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_H264_DMA2D_ALLOW_S 28 -/** TEE_CORE0_UM_PMS_REG2_REG register - * NA - */ -#define TEE_CORE0_UM_PMS_REG2_REG (DR_REG_TEE_BASE + 0x20) -/** TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW (BIT(0)) -#define TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW_M (TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW_V << TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_MCPWM0_ALLOW_S 0 -/** TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW (BIT(1)) -#define TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW_M (TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW_V << TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_MCPWM1_ALLOW_S 1 -/** TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW (BIT(2)) -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW_M (TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW_V << TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP0_ALLOW_S 2 -/** TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW (BIT(3)) -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW_M (TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW_V << TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_TIMER_GROUP1_ALLOW_S 3 -/** TEE_REG_CORE0_UM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I2C0_ALLOW (BIT(4)) -#define TEE_REG_CORE0_UM_HP_I2C0_ALLOW_M (TEE_REG_CORE0_UM_HP_I2C0_ALLOW_V << TEE_REG_CORE0_UM_HP_I2C0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I2C0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I2C0_ALLOW_S 4 -/** TEE_REG_CORE0_UM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I2C1_ALLOW (BIT(5)) -#define TEE_REG_CORE0_UM_HP_I2C1_ALLOW_M (TEE_REG_CORE0_UM_HP_I2C1_ALLOW_V << TEE_REG_CORE0_UM_HP_I2C1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I2C1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I2C1_ALLOW_S 5 -/** TEE_REG_CORE0_UM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I2S0_ALLOW (BIT(6)) -#define TEE_REG_CORE0_UM_HP_I2S0_ALLOW_M (TEE_REG_CORE0_UM_HP_I2S0_ALLOW_V << TEE_REG_CORE0_UM_HP_I2S0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I2S0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I2S0_ALLOW_S 6 -/** TEE_REG_CORE0_UM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I2S1_ALLOW (BIT(7)) -#define TEE_REG_CORE0_UM_HP_I2S1_ALLOW_M (TEE_REG_CORE0_UM_HP_I2S1_ALLOW_V << TEE_REG_CORE0_UM_HP_I2S1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I2S1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I2S1_ALLOW_S 7 -/** TEE_REG_CORE0_UM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I2S2_ALLOW (BIT(8)) -#define TEE_REG_CORE0_UM_HP_I2S2_ALLOW_M (TEE_REG_CORE0_UM_HP_I2S2_ALLOW_V << TEE_REG_CORE0_UM_HP_I2S2_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I2S2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I2S2_ALLOW_S 8 -/** TEE_REG_CORE0_UM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PCNT_ALLOW (BIT(9)) -#define TEE_REG_CORE0_UM_HP_PCNT_ALLOW_M (TEE_REG_CORE0_UM_HP_PCNT_ALLOW_V << TEE_REG_CORE0_UM_HP_PCNT_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PCNT_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PCNT_ALLOW_S 9 -/** TEE_REG_CORE0_UM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UART0_ALLOW (BIT(10)) -#define TEE_REG_CORE0_UM_HP_UART0_ALLOW_M (TEE_REG_CORE0_UM_HP_UART0_ALLOW_V << TEE_REG_CORE0_UM_HP_UART0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UART0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UART0_ALLOW_S 10 -/** TEE_REG_CORE0_UM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UART1_ALLOW (BIT(11)) -#define TEE_REG_CORE0_UM_HP_UART1_ALLOW_M (TEE_REG_CORE0_UM_HP_UART1_ALLOW_V << TEE_REG_CORE0_UM_HP_UART1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UART1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UART1_ALLOW_S 11 -/** TEE_REG_CORE0_UM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UART2_ALLOW (BIT(12)) -#define TEE_REG_CORE0_UM_HP_UART2_ALLOW_M (TEE_REG_CORE0_UM_HP_UART2_ALLOW_V << TEE_REG_CORE0_UM_HP_UART2_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UART2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UART2_ALLOW_S 12 -/** TEE_REG_CORE0_UM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UART3_ALLOW (BIT(13)) -#define TEE_REG_CORE0_UM_HP_UART3_ALLOW_M (TEE_REG_CORE0_UM_HP_UART3_ALLOW_V << TEE_REG_CORE0_UM_HP_UART3_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UART3_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UART3_ALLOW_S 13 -/** TEE_REG_CORE0_UM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UART4_ALLOW (BIT(14)) -#define TEE_REG_CORE0_UM_HP_UART4_ALLOW_M (TEE_REG_CORE0_UM_HP_UART4_ALLOW_V << TEE_REG_CORE0_UM_HP_UART4_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UART4_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UART4_ALLOW_S 14 -/** TEE_REG_CORE0_UM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_PARLIO_ALLOW (BIT(15)) -#define TEE_REG_CORE0_UM_HP_PARLIO_ALLOW_M (TEE_REG_CORE0_UM_HP_PARLIO_ALLOW_V << TEE_REG_CORE0_UM_HP_PARLIO_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_PARLIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_PARLIO_ALLOW_S 15 -/** TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW (BIT(16)) -#define TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW_M (TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW_V << TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_GPSPI2_ALLOW_S 16 -/** TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW (BIT(17)) -#define TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW_M (TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW_V << TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_GPSPI3_ALLOW_S 17 -/** TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW (BIT(18)) -#define TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW_M (TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW_V << TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_USBDEVICE_ALLOW_S 18 -/** TEE_REG_CORE0_UM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_LEDC_ALLOW (BIT(19)) -#define TEE_REG_CORE0_UM_HP_LEDC_ALLOW_M (TEE_REG_CORE0_UM_HP_LEDC_ALLOW_V << TEE_REG_CORE0_UM_HP_LEDC_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_LEDC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_LEDC_ALLOW_S 19 -/** TEE_REG_CORE0_UM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_ETM_ALLOW (BIT(21)) -#define TEE_REG_CORE0_UM_HP_ETM_ALLOW_M (TEE_REG_CORE0_UM_HP_ETM_ALLOW_V << TEE_REG_CORE0_UM_HP_ETM_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_ETM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_ETM_ALLOW_S 21 -/** TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW (BIT(22)) -#define TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW_M (TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW_V << TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_INTRMTX_ALLOW_S 22 -/** TEE_REG_CORE0_UM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_TWAI0_ALLOW (BIT(23)) -#define TEE_REG_CORE0_UM_HP_TWAI0_ALLOW_M (TEE_REG_CORE0_UM_HP_TWAI0_ALLOW_V << TEE_REG_CORE0_UM_HP_TWAI0_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_TWAI0_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_TWAI0_ALLOW_S 23 -/** TEE_REG_CORE0_UM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_TWAI1_ALLOW (BIT(24)) -#define TEE_REG_CORE0_UM_HP_TWAI1_ALLOW_M (TEE_REG_CORE0_UM_HP_TWAI1_ALLOW_V << TEE_REG_CORE0_UM_HP_TWAI1_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_TWAI1_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_TWAI1_ALLOW_S 24 -/** TEE_REG_CORE0_UM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_TWAI2_ALLOW (BIT(25)) -#define TEE_REG_CORE0_UM_HP_TWAI2_ALLOW_M (TEE_REG_CORE0_UM_HP_TWAI2_ALLOW_V << TEE_REG_CORE0_UM_HP_TWAI2_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_TWAI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_TWAI2_ALLOW_S 25 -/** TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW (BIT(26)) -#define TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW_M (TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW_V << TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I3C_MST_ALLOW_S 26 -/** TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW (BIT(27)) -#define TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW_M (TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW_V << TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_I3C_SLV_ALLOW_S 27 -/** TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW (BIT(28)) -#define TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW_M (TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW_V << TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_LCDCAM_ALLOW_S 28 -/** TEE_REG_CORE0_UM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_ADC_ALLOW (BIT(30)) -#define TEE_REG_CORE0_UM_HP_ADC_ALLOW_M (TEE_REG_CORE0_UM_HP_ADC_ALLOW_V << TEE_REG_CORE0_UM_HP_ADC_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_ADC_ALLOW_S 30 -/** TEE_REG_CORE0_UM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_UHCI_ALLOW (BIT(31)) -#define TEE_REG_CORE0_UM_HP_UHCI_ALLOW_M (TEE_REG_CORE0_UM_HP_UHCI_ALLOW_V << TEE_REG_CORE0_UM_HP_UHCI_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_UHCI_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_UHCI_ALLOW_S 31 +/** PMS_CORE0_UM_HP_PERI_PMS_REG2_REG register + * Permission control register2 for HP CPU0 in user mode + */ +#define PMS_CORE0_UM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x20) +/** PMS_CORE0_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_MCPWM0_ALLOW (BIT(0)) +#define PMS_CORE0_UM_HP_MCPWM0_ALLOW_M (PMS_CORE0_UM_HP_MCPWM0_ALLOW_V << PMS_CORE0_UM_HP_MCPWM0_ALLOW_S) +#define PMS_CORE0_UM_HP_MCPWM0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_MCPWM0_ALLOW_S 0 +/** PMS_CORE0_UM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_MCPWM1_ALLOW (BIT(1)) +#define PMS_CORE0_UM_HP_MCPWM1_ALLOW_M (PMS_CORE0_UM_HP_MCPWM1_ALLOW_V << PMS_CORE0_UM_HP_MCPWM1_ALLOW_S) +#define PMS_CORE0_UM_HP_MCPWM1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_MCPWM1_ALLOW_S 1 +/** PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP timer group0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW (BIT(2)) +#define PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW_M (PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW_V << PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW_S) +#define PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_TIMER_GROUP0_ALLOW_S 2 +/** PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW (BIT(3)) +#define PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW_M (PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW_V << PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW_S) +#define PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_TIMER_GROUP1_ALLOW_S 3 +/** PMS_CORE0_UM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I2C0_ALLOW (BIT(4)) +#define PMS_CORE0_UM_HP_I2C0_ALLOW_M (PMS_CORE0_UM_HP_I2C0_ALLOW_V << PMS_CORE0_UM_HP_I2C0_ALLOW_S) +#define PMS_CORE0_UM_HP_I2C0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I2C0_ALLOW_S 4 +/** PMS_CORE0_UM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I2C1_ALLOW (BIT(5)) +#define PMS_CORE0_UM_HP_I2C1_ALLOW_M (PMS_CORE0_UM_HP_I2C1_ALLOW_V << PMS_CORE0_UM_HP_I2C1_ALLOW_S) +#define PMS_CORE0_UM_HP_I2C1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I2C1_ALLOW_S 5 +/** PMS_CORE0_UM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I2S0_ALLOW (BIT(6)) +#define PMS_CORE0_UM_HP_I2S0_ALLOW_M (PMS_CORE0_UM_HP_I2S0_ALLOW_V << PMS_CORE0_UM_HP_I2S0_ALLOW_S) +#define PMS_CORE0_UM_HP_I2S0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I2S0_ALLOW_S 6 +/** PMS_CORE0_UM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I2S1_ALLOW (BIT(7)) +#define PMS_CORE0_UM_HP_I2S1_ALLOW_M (PMS_CORE0_UM_HP_I2S1_ALLOW_V << PMS_CORE0_UM_HP_I2S1_ALLOW_S) +#define PMS_CORE0_UM_HP_I2S1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I2S1_ALLOW_S 7 +/** PMS_CORE0_UM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I2S2_ALLOW (BIT(8)) +#define PMS_CORE0_UM_HP_I2S2_ALLOW_M (PMS_CORE0_UM_HP_I2S2_ALLOW_V << PMS_CORE0_UM_HP_I2S2_ALLOW_S) +#define PMS_CORE0_UM_HP_I2S2_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I2S2_ALLOW_S 8 +/** PMS_CORE0_UM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_PCNT_ALLOW (BIT(9)) +#define PMS_CORE0_UM_HP_PCNT_ALLOW_M (PMS_CORE0_UM_HP_PCNT_ALLOW_V << PMS_CORE0_UM_HP_PCNT_ALLOW_S) +#define PMS_CORE0_UM_HP_PCNT_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PCNT_ALLOW_S 9 +/** PMS_CORE0_UM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UART0_ALLOW (BIT(10)) +#define PMS_CORE0_UM_HP_UART0_ALLOW_M (PMS_CORE0_UM_HP_UART0_ALLOW_V << PMS_CORE0_UM_HP_UART0_ALLOW_S) +#define PMS_CORE0_UM_HP_UART0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UART0_ALLOW_S 10 +/** PMS_CORE0_UM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UART1_ALLOW (BIT(11)) +#define PMS_CORE0_UM_HP_UART1_ALLOW_M (PMS_CORE0_UM_HP_UART1_ALLOW_V << PMS_CORE0_UM_HP_UART1_ALLOW_S) +#define PMS_CORE0_UM_HP_UART1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UART1_ALLOW_S 11 +/** PMS_CORE0_UM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UART2_ALLOW (BIT(12)) +#define PMS_CORE0_UM_HP_UART2_ALLOW_M (PMS_CORE0_UM_HP_UART2_ALLOW_V << PMS_CORE0_UM_HP_UART2_ALLOW_S) +#define PMS_CORE0_UM_HP_UART2_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UART2_ALLOW_S 12 +/** PMS_CORE0_UM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UART3_ALLOW (BIT(13)) +#define PMS_CORE0_UM_HP_UART3_ALLOW_M (PMS_CORE0_UM_HP_UART3_ALLOW_V << PMS_CORE0_UM_HP_UART3_ALLOW_S) +#define PMS_CORE0_UM_HP_UART3_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UART3_ALLOW_S 13 +/** PMS_CORE0_UM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UART4_ALLOW (BIT(14)) +#define PMS_CORE0_UM_HP_UART4_ALLOW_M (PMS_CORE0_UM_HP_UART4_ALLOW_V << PMS_CORE0_UM_HP_UART4_ALLOW_S) +#define PMS_CORE0_UM_HP_UART4_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UART4_ALLOW_S 14 +/** PMS_CORE0_UM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_PARLIO_ALLOW (BIT(15)) +#define PMS_CORE0_UM_HP_PARLIO_ALLOW_M (PMS_CORE0_UM_HP_PARLIO_ALLOW_V << PMS_CORE0_UM_HP_PARLIO_ALLOW_S) +#define PMS_CORE0_UM_HP_PARLIO_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_PARLIO_ALLOW_S 15 +/** PMS_CORE0_UM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_GPSPI2_ALLOW (BIT(16)) +#define PMS_CORE0_UM_HP_GPSPI2_ALLOW_M (PMS_CORE0_UM_HP_GPSPI2_ALLOW_V << PMS_CORE0_UM_HP_GPSPI2_ALLOW_S) +#define PMS_CORE0_UM_HP_GPSPI2_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_GPSPI2_ALLOW_S 16 +/** PMS_CORE0_UM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_GPSPI3_ALLOW (BIT(17)) +#define PMS_CORE0_UM_HP_GPSPI3_ALLOW_M (PMS_CORE0_UM_HP_GPSPI3_ALLOW_V << PMS_CORE0_UM_HP_GPSPI3_ALLOW_S) +#define PMS_CORE0_UM_HP_GPSPI3_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_GPSPI3_ALLOW_S 17 +/** PMS_CORE0_UM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP USB/Serial JTAG + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_USBDEVICE_ALLOW (BIT(18)) +#define PMS_CORE0_UM_HP_USBDEVICE_ALLOW_M (PMS_CORE0_UM_HP_USBDEVICE_ALLOW_V << PMS_CORE0_UM_HP_USBDEVICE_ALLOW_S) +#define PMS_CORE0_UM_HP_USBDEVICE_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_USBDEVICE_ALLOW_S 18 +/** PMS_CORE0_UM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_LEDC_ALLOW (BIT(19)) +#define PMS_CORE0_UM_HP_LEDC_ALLOW_M (PMS_CORE0_UM_HP_LEDC_ALLOW_V << PMS_CORE0_UM_HP_LEDC_ALLOW_S) +#define PMS_CORE0_UM_HP_LEDC_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_LEDC_ALLOW_S 19 +/** PMS_CORE0_UM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP ETM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_ETM_ALLOW (BIT(21)) +#define PMS_CORE0_UM_HP_ETM_ALLOW_M (PMS_CORE0_UM_HP_ETM_ALLOW_V << PMS_CORE0_UM_HP_ETM_ALLOW_S) +#define PMS_CORE0_UM_HP_ETM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_ETM_ALLOW_S 21 +/** PMS_CORE0_UM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_INTRMTX_ALLOW (BIT(22)) +#define PMS_CORE0_UM_HP_INTRMTX_ALLOW_M (PMS_CORE0_UM_HP_INTRMTX_ALLOW_V << PMS_CORE0_UM_HP_INTRMTX_ALLOW_S) +#define PMS_CORE0_UM_HP_INTRMTX_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_INTRMTX_ALLOW_S 22 +/** PMS_CORE0_UM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_TWAI0_ALLOW (BIT(23)) +#define PMS_CORE0_UM_HP_TWAI0_ALLOW_M (PMS_CORE0_UM_HP_TWAI0_ALLOW_V << PMS_CORE0_UM_HP_TWAI0_ALLOW_S) +#define PMS_CORE0_UM_HP_TWAI0_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_TWAI0_ALLOW_S 23 +/** PMS_CORE0_UM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_TWAI1_ALLOW (BIT(24)) +#define PMS_CORE0_UM_HP_TWAI1_ALLOW_M (PMS_CORE0_UM_HP_TWAI1_ALLOW_V << PMS_CORE0_UM_HP_TWAI1_ALLOW_S) +#define PMS_CORE0_UM_HP_TWAI1_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_TWAI1_ALLOW_S 24 +/** PMS_CORE0_UM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_TWAI2_ALLOW (BIT(25)) +#define PMS_CORE0_UM_HP_TWAI2_ALLOW_M (PMS_CORE0_UM_HP_TWAI2_ALLOW_V << PMS_CORE0_UM_HP_TWAI2_ALLOW_S) +#define PMS_CORE0_UM_HP_TWAI2_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_TWAI2_ALLOW_S 25 +/** PMS_CORE0_UM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I3C_MST_ALLOW (BIT(26)) +#define PMS_CORE0_UM_HP_I3C_MST_ALLOW_M (PMS_CORE0_UM_HP_I3C_MST_ALLOW_V << PMS_CORE0_UM_HP_I3C_MST_ALLOW_S) +#define PMS_CORE0_UM_HP_I3C_MST_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I3C_MST_ALLOW_S 26 +/** PMS_CORE0_UM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_I3C_SLV_ALLOW (BIT(27)) +#define PMS_CORE0_UM_HP_I3C_SLV_ALLOW_M (PMS_CORE0_UM_HP_I3C_SLV_ALLOW_V << PMS_CORE0_UM_HP_I3C_SLV_ALLOW_S) +#define PMS_CORE0_UM_HP_I3C_SLV_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_I3C_SLV_ALLOW_S 27 +/** PMS_CORE0_UM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_LCDCAM_ALLOW (BIT(28)) +#define PMS_CORE0_UM_HP_LCDCAM_ALLOW_M (PMS_CORE0_UM_HP_LCDCAM_ALLOW_V << PMS_CORE0_UM_HP_LCDCAM_ALLOW_S) +#define PMS_CORE0_UM_HP_LCDCAM_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_LCDCAM_ALLOW_S 28 +/** PMS_CORE0_UM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_ADC_ALLOW (BIT(30)) +#define PMS_CORE0_UM_HP_ADC_ALLOW_M (PMS_CORE0_UM_HP_ADC_ALLOW_V << PMS_CORE0_UM_HP_ADC_ALLOW_S) +#define PMS_CORE0_UM_HP_ADC_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_ADC_ALLOW_S 30 +/** PMS_CORE0_UM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_UHCI_ALLOW (BIT(31)) +#define PMS_CORE0_UM_HP_UHCI_ALLOW_M (PMS_CORE0_UM_HP_UHCI_ALLOW_V << PMS_CORE0_UM_HP_UHCI_ALLOW_S) +#define PMS_CORE0_UM_HP_UHCI_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_UHCI_ALLOW_S 31 -/** TEE_CORE0_UM_PMS_REG3_REG register - * NA - */ -#define TEE_CORE0_UM_PMS_REG3_REG (DR_REG_TEE_BASE + 0x24) -/** TEE_REG_CORE0_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_GPIO_ALLOW (BIT(0)) -#define TEE_REG_CORE0_UM_HP_GPIO_ALLOW_M (TEE_REG_CORE0_UM_HP_GPIO_ALLOW_V << TEE_REG_CORE0_UM_HP_GPIO_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_GPIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_GPIO_ALLOW_S 0 -/** TEE_REG_CORE0_UM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_IOMUX_ALLOW (BIT(1)) -#define TEE_REG_CORE0_UM_HP_IOMUX_ALLOW_M (TEE_REG_CORE0_UM_HP_IOMUX_ALLOW_V << TEE_REG_CORE0_UM_HP_IOMUX_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_IOMUX_ALLOW_S 1 -/** TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW (BIT(2)) -#define TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW_M (TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW_V << TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_SYSTIMER_ALLOW_S 2 -/** TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW (BIT(3)) -#define TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW_M (TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW_V << TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_SYS_REG_ALLOW_S 3 -/** TEE_REG_CORE0_UM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE0_UM_HP_CLKRST_ALLOW (BIT(4)) -#define TEE_REG_CORE0_UM_HP_CLKRST_ALLOW_M (TEE_REG_CORE0_UM_HP_CLKRST_ALLOW_V << TEE_REG_CORE0_UM_HP_CLKRST_ALLOW_S) -#define TEE_REG_CORE0_UM_HP_CLKRST_ALLOW_V 0x00000001U -#define TEE_REG_CORE0_UM_HP_CLKRST_ALLOW_S 4 +/** PMS_CORE0_UM_HP_PERI_PMS_REG3_REG register + * Permission control register3 for HP CPU0 in user mode + */ +#define PMS_CORE0_UM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x24) +/** PMS_CORE0_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_GPIO_ALLOW (BIT(0)) +#define PMS_CORE0_UM_HP_GPIO_ALLOW_M (PMS_CORE0_UM_HP_GPIO_ALLOW_V << PMS_CORE0_UM_HP_GPIO_ALLOW_S) +#define PMS_CORE0_UM_HP_GPIO_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_GPIO_ALLOW_S 0 +/** PMS_CORE0_UM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_IOMUX_ALLOW (BIT(1)) +#define PMS_CORE0_UM_HP_IOMUX_ALLOW_M (PMS_CORE0_UM_HP_IOMUX_ALLOW_V << PMS_CORE0_UM_HP_IOMUX_ALLOW_S) +#define PMS_CORE0_UM_HP_IOMUX_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_IOMUX_ALLOW_S 1 +/** PMS_CORE0_UM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP system timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_SYSTIMER_ALLOW (BIT(2)) +#define PMS_CORE0_UM_HP_SYSTIMER_ALLOW_M (PMS_CORE0_UM_HP_SYSTIMER_ALLOW_V << PMS_CORE0_UM_HP_SYSTIMER_ALLOW_S) +#define PMS_CORE0_UM_HP_SYSTIMER_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_SYSTIMER_ALLOW_S 2 +/** PMS_CORE0_UM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_SYS_REG_ALLOW (BIT(3)) +#define PMS_CORE0_UM_HP_SYS_REG_ALLOW_M (PMS_CORE0_UM_HP_SYS_REG_ALLOW_V << PMS_CORE0_UM_HP_SYS_REG_ALLOW_S) +#define PMS_CORE0_UM_HP_SYS_REG_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_SYS_REG_ALLOW_S 3 +/** PMS_CORE0_UM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU0 in user mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE0_UM_HP_CLKRST_ALLOW (BIT(4)) +#define PMS_CORE0_UM_HP_CLKRST_ALLOW_M (PMS_CORE0_UM_HP_CLKRST_ALLOW_V << PMS_CORE0_UM_HP_CLKRST_ALLOW_S) +#define PMS_CORE0_UM_HP_CLKRST_ALLOW_V 0x00000001U +#define PMS_CORE0_UM_HP_CLKRST_ALLOW_S 4 -/** TEE_CORE1_MM_PMS_REG0_REG register - * NA - */ -#define TEE_CORE1_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x28) -/** TEE_REG_CORE1_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_PSRAM_ALLOW (BIT(0)) -#define TEE_REG_CORE1_MM_PSRAM_ALLOW_M (TEE_REG_CORE1_MM_PSRAM_ALLOW_V << TEE_REG_CORE1_MM_PSRAM_ALLOW_S) -#define TEE_REG_CORE1_MM_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_PSRAM_ALLOW_S 0 -/** TEE_REG_CORE1_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_FLASH_ALLOW (BIT(1)) -#define TEE_REG_CORE1_MM_FLASH_ALLOW_M (TEE_REG_CORE1_MM_FLASH_ALLOW_V << TEE_REG_CORE1_MM_FLASH_ALLOW_S) -#define TEE_REG_CORE1_MM_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_FLASH_ALLOW_S 1 -/** TEE_REG_CORE1_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_L2MEM_ALLOW (BIT(2)) -#define TEE_REG_CORE1_MM_L2MEM_ALLOW_M (TEE_REG_CORE1_MM_L2MEM_ALLOW_V << TEE_REG_CORE1_MM_L2MEM_ALLOW_S) -#define TEE_REG_CORE1_MM_L2MEM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_L2MEM_ALLOW_S 2 -/** TEE_REG_CORE1_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_L2ROM_ALLOW (BIT(3)) -#define TEE_REG_CORE1_MM_L2ROM_ALLOW_M (TEE_REG_CORE1_MM_L2ROM_ALLOW_V << TEE_REG_CORE1_MM_L2ROM_ALLOW_S) -#define TEE_REG_CORE1_MM_L2ROM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_L2ROM_ALLOW_S 3 -/** TEE_REG_CORE1_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_TRACE0_ALLOW (BIT(6)) -#define TEE_REG_CORE1_MM_TRACE0_ALLOW_M (TEE_REG_CORE1_MM_TRACE0_ALLOW_V << TEE_REG_CORE1_MM_TRACE0_ALLOW_S) -#define TEE_REG_CORE1_MM_TRACE0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_TRACE0_ALLOW_S 6 -/** TEE_REG_CORE1_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_TRACE1_ALLOW (BIT(7)) -#define TEE_REG_CORE1_MM_TRACE1_ALLOW_M (TEE_REG_CORE1_MM_TRACE1_ALLOW_V << TEE_REG_CORE1_MM_TRACE1_ALLOW_S) -#define TEE_REG_CORE1_MM_TRACE1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_TRACE1_ALLOW_S 7 -/** TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW (BIT(8)) -#define TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW_M (TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW_V << TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW_S) -#define TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_CPU_BUS_MON_ALLOW_S 8 -/** TEE_REG_CORE1_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_L2MEM_MON_ALLOW (BIT(9)) -#define TEE_REG_CORE1_MM_L2MEM_MON_ALLOW_M (TEE_REG_CORE1_MM_L2MEM_MON_ALLOW_V << TEE_REG_CORE1_MM_L2MEM_MON_ALLOW_S) -#define TEE_REG_CORE1_MM_L2MEM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_L2MEM_MON_ALLOW_S 9 -/** TEE_REG_CORE1_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_TCM_MON_ALLOW (BIT(10)) -#define TEE_REG_CORE1_MM_TCM_MON_ALLOW_M (TEE_REG_CORE1_MM_TCM_MON_ALLOW_V << TEE_REG_CORE1_MM_TCM_MON_ALLOW_S) -#define TEE_REG_CORE1_MM_TCM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_TCM_MON_ALLOW_S 10 -/** TEE_REG_CORE1_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_CACHE_ALLOW (BIT(11)) -#define TEE_REG_CORE1_MM_CACHE_ALLOW_M (TEE_REG_CORE1_MM_CACHE_ALLOW_V << TEE_REG_CORE1_MM_CACHE_ALLOW_S) -#define TEE_REG_CORE1_MM_CACHE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_CACHE_ALLOW_S 11 +/** PMS_CORE1_MM_HP_PERI_PMS_REG0_REG register + * Permission control register0 for HP CPU1 in machine mode + */ +#define PMS_CORE1_MM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x28) +/** PMS_CORE1_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_PSRAM_ALLOW (BIT(0)) +#define PMS_CORE1_MM_PSRAM_ALLOW_M (PMS_CORE1_MM_PSRAM_ALLOW_V << PMS_CORE1_MM_PSRAM_ALLOW_S) +#define PMS_CORE1_MM_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_PSRAM_ALLOW_S 0 +/** PMS_CORE1_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_FLASH_ALLOW (BIT(1)) +#define PMS_CORE1_MM_FLASH_ALLOW_M (PMS_CORE1_MM_FLASH_ALLOW_V << PMS_CORE1_MM_FLASH_ALLOW_S) +#define PMS_CORE1_MM_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_FLASH_ALLOW_S 1 +/** PMS_CORE1_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP L2MEM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_L2MEM_ALLOW (BIT(2)) +#define PMS_CORE1_MM_L2MEM_ALLOW_M (PMS_CORE1_MM_L2MEM_ALLOW_V << PMS_CORE1_MM_L2MEM_ALLOW_S) +#define PMS_CORE1_MM_L2MEM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_L2MEM_ALLOW_S 2 +/** PMS_CORE1_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_L2ROM_ALLOW (BIT(3)) +#define PMS_CORE1_MM_L2ROM_ALLOW_M (PMS_CORE1_MM_L2ROM_ALLOW_V << PMS_CORE1_MM_L2ROM_ALLOW_S) +#define PMS_CORE1_MM_L2ROM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_L2ROM_ALLOW_S 3 +/** PMS_CORE1_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_TRACE0_ALLOW (BIT(6)) +#define PMS_CORE1_MM_TRACE0_ALLOW_M (PMS_CORE1_MM_TRACE0_ALLOW_V << PMS_CORE1_MM_TRACE0_ALLOW_S) +#define PMS_CORE1_MM_TRACE0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_TRACE0_ALLOW_S 6 +/** PMS_CORE1_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_TRACE1_ALLOW (BIT(7)) +#define PMS_CORE1_MM_TRACE1_ALLOW_M (PMS_CORE1_MM_TRACE1_ALLOW_V << PMS_CORE1_MM_TRACE1_ALLOW_S) +#define PMS_CORE1_MM_TRACE1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_TRACE1_ALLOW_S 7 +/** PMS_CORE1_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access CPU bus + * monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_CPU_BUS_MON_ALLOW (BIT(8)) +#define PMS_CORE1_MM_CPU_BUS_MON_ALLOW_M (PMS_CORE1_MM_CPU_BUS_MON_ALLOW_V << PMS_CORE1_MM_CPU_BUS_MON_ALLOW_S) +#define PMS_CORE1_MM_CPU_BUS_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_CPU_BUS_MON_ALLOW_S 8 +/** PMS_CORE1_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_L2MEM_MON_ALLOW (BIT(9)) +#define PMS_CORE1_MM_L2MEM_MON_ALLOW_M (PMS_CORE1_MM_L2MEM_MON_ALLOW_V << PMS_CORE1_MM_L2MEM_MON_ALLOW_S) +#define PMS_CORE1_MM_L2MEM_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_L2MEM_MON_ALLOW_S 9 +/** PMS_CORE1_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_TCM_MON_ALLOW (BIT(10)) +#define PMS_CORE1_MM_TCM_MON_ALLOW_M (PMS_CORE1_MM_TCM_MON_ALLOW_V << PMS_CORE1_MM_TCM_MON_ALLOW_S) +#define PMS_CORE1_MM_TCM_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_TCM_MON_ALLOW_S 10 +/** PMS_CORE1_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_CACHE_ALLOW (BIT(11)) +#define PMS_CORE1_MM_CACHE_ALLOW_M (PMS_CORE1_MM_CACHE_ALLOW_V << PMS_CORE1_MM_CACHE_ALLOW_S) +#define PMS_CORE1_MM_CACHE_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_CACHE_ALLOW_S 11 -/** TEE_CORE1_MM_PMS_REG1_REG register - * NA - */ -#define TEE_CORE1_MM_PMS_REG1_REG (DR_REG_TEE_BASE + 0x2c) -/** TEE_REG_CORE1_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_USBOTG_ALLOW (BIT(0)) -#define TEE_REG_CORE1_MM_HP_USBOTG_ALLOW_M (TEE_REG_CORE1_MM_HP_USBOTG_ALLOW_V << TEE_REG_CORE1_MM_HP_USBOTG_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_USBOTG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_USBOTG_ALLOW_S 0 -/** TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW (BIT(1)) -#define TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW_M (TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW_V << TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_USBOTG11_ALLOW_S 1 -/** TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) -#define TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_M (TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_V << TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_S 2 -/** TEE_REG_CORE1_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_GDMA_ALLOW (BIT(3)) -#define TEE_REG_CORE1_MM_HP_GDMA_ALLOW_M (TEE_REG_CORE1_MM_HP_GDMA_ALLOW_V << TEE_REG_CORE1_MM_HP_GDMA_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_GDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_GDMA_ALLOW_S 3 -/** TEE_REG_CORE1_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_REGDMA_ALLOW (BIT(4)) -#define TEE_REG_CORE1_MM_HP_REGDMA_ALLOW_M (TEE_REG_CORE1_MM_HP_REGDMA_ALLOW_V << TEE_REG_CORE1_MM_HP_REGDMA_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_REGDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_REGDMA_ALLOW_S 4 -/** TEE_REG_CORE1_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_SDMMC_ALLOW (BIT(5)) -#define TEE_REG_CORE1_MM_HP_SDMMC_ALLOW_M (TEE_REG_CORE1_MM_HP_SDMMC_ALLOW_V << TEE_REG_CORE1_MM_HP_SDMMC_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_SDMMC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_SDMMC_ALLOW_S 5 -/** TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW (BIT(6)) -#define TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW_M (TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW_V << TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_AHB_PDMA_ALLOW_S 6 -/** TEE_REG_CORE1_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_JPEG_ALLOW (BIT(7)) -#define TEE_REG_CORE1_MM_HP_JPEG_ALLOW_M (TEE_REG_CORE1_MM_HP_JPEG_ALLOW_V << TEE_REG_CORE1_MM_HP_JPEG_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_JPEG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_JPEG_ALLOW_S 7 -/** TEE_REG_CORE1_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PPA_ALLOW (BIT(8)) -#define TEE_REG_CORE1_MM_HP_PPA_ALLOW_M (TEE_REG_CORE1_MM_HP_PPA_ALLOW_V << TEE_REG_CORE1_MM_HP_PPA_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PPA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PPA_ALLOW_S 8 -/** TEE_REG_CORE1_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_DMA2D_ALLOW (BIT(9)) -#define TEE_REG_CORE1_MM_HP_DMA2D_ALLOW_M (TEE_REG_CORE1_MM_HP_DMA2D_ALLOW_V << TEE_REG_CORE1_MM_HP_DMA2D_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_DMA2D_ALLOW_S 9 -/** TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) -#define TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW_M (TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW_V << TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_KEY_MANAGER_ALLOW_S 10 -/** TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW (BIT(11)) -#define TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW_M (TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW_V << TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_AXI_PDMA_ALLOW_S 11 -/** TEE_REG_CORE1_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_FLASH_ALLOW (BIT(12)) -#define TEE_REG_CORE1_MM_HP_FLASH_ALLOW_M (TEE_REG_CORE1_MM_HP_FLASH_ALLOW_V << TEE_REG_CORE1_MM_HP_FLASH_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_FLASH_ALLOW_S 12 -/** TEE_REG_CORE1_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PSRAM_ALLOW (BIT(13)) -#define TEE_REG_CORE1_MM_HP_PSRAM_ALLOW_M (TEE_REG_CORE1_MM_HP_PSRAM_ALLOW_V << TEE_REG_CORE1_MM_HP_PSRAM_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PSRAM_ALLOW_S 13 -/** TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW (BIT(14)) -#define TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW_M (TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW_V << TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_CRYPTO_ALLOW_S 14 -/** TEE_REG_CORE1_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_GMAC_ALLOW (BIT(15)) -#define TEE_REG_CORE1_MM_HP_GMAC_ALLOW_M (TEE_REG_CORE1_MM_HP_GMAC_ALLOW_V << TEE_REG_CORE1_MM_HP_GMAC_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_GMAC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_GMAC_ALLOW_S 15 -/** TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW (BIT(16)) -#define TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW_M (TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW_V << TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_USB_PHY_ALLOW_S 16 -/** TEE_REG_CORE1_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PVT_ALLOW (BIT(17)) -#define TEE_REG_CORE1_MM_HP_PVT_ALLOW_M (TEE_REG_CORE1_MM_HP_PVT_ALLOW_V << TEE_REG_CORE1_MM_HP_PVT_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PVT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PVT_ALLOW_S 17 -/** TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW (BIT(18)) -#define TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW_M (TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW_V << TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_CSI_HOST_ALLOW_S 18 -/** TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW (BIT(19)) -#define TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW_M (TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW_V << TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_DSI_HOST_ALLOW_S 19 -/** TEE_REG_CORE1_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_ISP_ALLOW (BIT(20)) -#define TEE_REG_CORE1_MM_HP_ISP_ALLOW_M (TEE_REG_CORE1_MM_HP_ISP_ALLOW_V << TEE_REG_CORE1_MM_HP_ISP_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_ISP_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_ISP_ALLOW_S 20 -/** TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW (BIT(21)) -#define TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW_M (TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW_V << TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_H264_CORE_ALLOW_S 21 -/** TEE_REG_CORE1_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_RMT_ALLOW (BIT(22)) -#define TEE_REG_CORE1_MM_HP_RMT_ALLOW_M (TEE_REG_CORE1_MM_HP_RMT_ALLOW_V << TEE_REG_CORE1_MM_HP_RMT_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_RMT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_RMT_ALLOW_S 22 -/** TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) -#define TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW_M (TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW_V << TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_BITSRAMBLER_ALLOW_S 23 -/** TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW (BIT(24)) -#define TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW_M (TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW_V << TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_AXI_ICM_ALLOW_S 24 -/** TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW (BIT(25)) -#define TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW_M (TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW_V << TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PERI_PMS_ALLOW_S 25 -/** TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) -#define TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW_M (TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW_V << TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_LP2HP_PERI_PMS_ALLOW_S 26 -/** TEE_REG_CORE1_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_DMA_PMS_ALLOW (BIT(27)) -#define TEE_REG_CORE1_MM_DMA_PMS_ALLOW_M (TEE_REG_CORE1_MM_DMA_PMS_ALLOW_V << TEE_REG_CORE1_MM_DMA_PMS_ALLOW_S) -#define TEE_REG_CORE1_MM_DMA_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_DMA_PMS_ALLOW_S 27 -/** TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW (BIT(28)) -#define TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW_M (TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW_V << TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_H264_DMA2D_ALLOW_S 28 +/** PMS_CORE1_MM_HP_PERI_PMS_REG1_REG register + * Permission control register1 for HP CPU1 in machine mode + */ +#define PMS_CORE1_MM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x2c) +/** PMS_CORE1_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP high-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_USBOTG_ALLOW (BIT(0)) +#define PMS_CORE1_MM_HP_USBOTG_ALLOW_M (PMS_CORE1_MM_HP_USBOTG_ALLOW_V << PMS_CORE1_MM_HP_USBOTG_ALLOW_S) +#define PMS_CORE1_MM_HP_USBOTG_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_USBOTG_ALLOW_S 0 +/** PMS_CORE1_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP full-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_USBOTG11_ALLOW (BIT(1)) +#define PMS_CORE1_MM_HP_USBOTG11_ALLOW_M (PMS_CORE1_MM_HP_USBOTG11_ALLOW_V << PMS_CORE1_MM_HP_USBOTG11_ALLOW_S) +#define PMS_CORE1_MM_HP_USBOTG11_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_USBOTG11_ALLOW_S 1 +/** PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP full-speed + * USB 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) +#define PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_M (PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_V << PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_S) +#define PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_USBOTG11_WRAP_ALLOW_S 2 +/** PMS_CORE1_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_GDMA_ALLOW (BIT(3)) +#define PMS_CORE1_MM_HP_GDMA_ALLOW_M (PMS_CORE1_MM_HP_GDMA_ALLOW_V << PMS_CORE1_MM_HP_GDMA_ALLOW_S) +#define PMS_CORE1_MM_HP_GDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_GDMA_ALLOW_S 3 +/** PMS_CORE1_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP GDMA (DW + * GDMA). + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE1_MM_HP_REGDMA_ALLOW (BIT(4)) +#define PMS_CORE1_MM_HP_REGDMA_ALLOW_M (PMS_CORE1_MM_HP_REGDMA_ALLOW_V << PMS_CORE1_MM_HP_REGDMA_ALLOW_S) +#define PMS_CORE1_MM_HP_REGDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_REGDMA_ALLOW_S 4 +/** PMS_CORE1_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_SDMMC_ALLOW (BIT(5)) +#define PMS_CORE1_MM_HP_SDMMC_ALLOW_M (PMS_CORE1_MM_HP_SDMMC_ALLOW_V << PMS_CORE1_MM_HP_SDMMC_ALLOW_S) +#define PMS_CORE1_MM_HP_SDMMC_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_SDMMC_ALLOW_S 5 +/** PMS_CORE1_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_AHB_PDMA_ALLOW (BIT(6)) +#define PMS_CORE1_MM_HP_AHB_PDMA_ALLOW_M (PMS_CORE1_MM_HP_AHB_PDMA_ALLOW_V << PMS_CORE1_MM_HP_AHB_PDMA_ALLOW_S) +#define PMS_CORE1_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_AHB_PDMA_ALLOW_S 6 +/** PMS_CORE1_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_JPEG_ALLOW (BIT(7)) +#define PMS_CORE1_MM_HP_JPEG_ALLOW_M (PMS_CORE1_MM_HP_JPEG_ALLOW_V << PMS_CORE1_MM_HP_JPEG_ALLOW_S) +#define PMS_CORE1_MM_HP_JPEG_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_JPEG_ALLOW_S 7 +/** PMS_CORE1_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_PPA_ALLOW (BIT(8)) +#define PMS_CORE1_MM_HP_PPA_ALLOW_M (PMS_CORE1_MM_HP_PPA_ALLOW_V << PMS_CORE1_MM_HP_PPA_ALLOW_S) +#define PMS_CORE1_MM_HP_PPA_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PPA_ALLOW_S 8 +/** PMS_CORE1_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_DMA2D_ALLOW (BIT(9)) +#define PMS_CORE1_MM_HP_DMA2D_ALLOW_M (PMS_CORE1_MM_HP_DMA2D_ALLOW_V << PMS_CORE1_MM_HP_DMA2D_ALLOW_S) +#define PMS_CORE1_MM_HP_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_DMA2D_ALLOW_S 9 +/** PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) +#define PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW_M (PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW_V << PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW_S) +#define PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_KEY_MANAGER_ALLOW_S 10 +/** PMS_CORE1_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_AXI_PDMA_ALLOW (BIT(11)) +#define PMS_CORE1_MM_HP_AXI_PDMA_ALLOW_M (PMS_CORE1_MM_HP_AXI_PDMA_ALLOW_V << PMS_CORE1_MM_HP_AXI_PDMA_ALLOW_S) +#define PMS_CORE1_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_AXI_PDMA_ALLOW_S 11 +/** PMS_CORE1_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_FLASH_ALLOW (BIT(12)) +#define PMS_CORE1_MM_HP_FLASH_ALLOW_M (PMS_CORE1_MM_HP_FLASH_ALLOW_V << PMS_CORE1_MM_HP_FLASH_ALLOW_S) +#define PMS_CORE1_MM_HP_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_FLASH_ALLOW_S 12 +/** PMS_CORE1_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_PSRAM_ALLOW (BIT(13)) +#define PMS_CORE1_MM_HP_PSRAM_ALLOW_M (PMS_CORE1_MM_HP_PSRAM_ALLOW_V << PMS_CORE1_MM_HP_PSRAM_ALLOW_S) +#define PMS_CORE1_MM_HP_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PSRAM_ALLOW_S 13 +/** PMS_CORE1_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP CRYPTO + * (including AES/SHA/RSA/HMAC Accelerators). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_CRYPTO_ALLOW (BIT(14)) +#define PMS_CORE1_MM_HP_CRYPTO_ALLOW_M (PMS_CORE1_MM_HP_CRYPTO_ALLOW_V << PMS_CORE1_MM_HP_CRYPTO_ALLOW_S) +#define PMS_CORE1_MM_HP_CRYPTO_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_CRYPTO_ALLOW_S 14 +/** PMS_CORE1_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_GMAC_ALLOW (BIT(15)) +#define PMS_CORE1_MM_HP_GMAC_ALLOW_M (PMS_CORE1_MM_HP_GMAC_ALLOW_V << PMS_CORE1_MM_HP_GMAC_ALLOW_S) +#define PMS_CORE1_MM_HP_GMAC_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_GMAC_ALLOW_S 15 +/** PMS_CORE1_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP high-speed + * USB 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_USB_PHY_ALLOW (BIT(16)) +#define PMS_CORE1_MM_HP_USB_PHY_ALLOW_M (PMS_CORE1_MM_HP_USB_PHY_ALLOW_V << PMS_CORE1_MM_HP_USB_PHY_ALLOW_S) +#define PMS_CORE1_MM_HP_USB_PHY_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_USB_PHY_ALLOW_S 16 +/** PMS_CORE1_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE1_MM_HP_PVT_ALLOW (BIT(17)) +#define PMS_CORE1_MM_HP_PVT_ALLOW_M (PMS_CORE1_MM_HP_PVT_ALLOW_V << PMS_CORE1_MM_HP_PVT_ALLOW_S) +#define PMS_CORE1_MM_HP_PVT_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PVT_ALLOW_S 17 +/** PMS_CORE1_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP MIPI CSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_CSI_HOST_ALLOW (BIT(18)) +#define PMS_CORE1_MM_HP_CSI_HOST_ALLOW_M (PMS_CORE1_MM_HP_CSI_HOST_ALLOW_V << PMS_CORE1_MM_HP_CSI_HOST_ALLOW_S) +#define PMS_CORE1_MM_HP_CSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_CSI_HOST_ALLOW_S 18 +/** PMS_CORE1_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP MIPI DSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_DSI_HOST_ALLOW (BIT(19)) +#define PMS_CORE1_MM_HP_DSI_HOST_ALLOW_M (PMS_CORE1_MM_HP_DSI_HOST_ALLOW_V << PMS_CORE1_MM_HP_DSI_HOST_ALLOW_S) +#define PMS_CORE1_MM_HP_DSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_DSI_HOST_ALLOW_S 19 +/** PMS_CORE1_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP ISP (Image + * Signal Processor). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_ISP_ALLOW (BIT(20)) +#define PMS_CORE1_MM_HP_ISP_ALLOW_M (PMS_CORE1_MM_HP_ISP_ALLOW_V << PMS_CORE1_MM_HP_ISP_ALLOW_S) +#define PMS_CORE1_MM_HP_ISP_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_ISP_ALLOW_S 20 +/** PMS_CORE1_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP H264 + * Encoder. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_H264_CORE_ALLOW (BIT(21)) +#define PMS_CORE1_MM_HP_H264_CORE_ALLOW_M (PMS_CORE1_MM_HP_H264_CORE_ALLOW_V << PMS_CORE1_MM_HP_H264_CORE_ALLOW_S) +#define PMS_CORE1_MM_HP_H264_CORE_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_H264_CORE_ALLOW_S 21 +/** PMS_CORE1_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_RMT_ALLOW (BIT(22)) +#define PMS_CORE1_MM_HP_RMT_ALLOW_M (PMS_CORE1_MM_HP_RMT_ALLOW_V << PMS_CORE1_MM_HP_RMT_ALLOW_S) +#define PMS_CORE1_MM_HP_RMT_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_RMT_ALLOW_S 22 +/** PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP bit + * scrambler. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) +#define PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW_M (PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW_V << PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW_S) +#define PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_BITSRAMBLER_ALLOW_S 23 +/** PMS_CORE1_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_AXI_ICM_ALLOW (BIT(24)) +#define PMS_CORE1_MM_HP_AXI_ICM_ALLOW_M (PMS_CORE1_MM_HP_AXI_ICM_ALLOW_V << PMS_CORE1_MM_HP_AXI_ICM_ALLOW_S) +#define PMS_CORE1_MM_HP_AXI_ICM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_AXI_ICM_ALLOW_S 24 +/** PMS_CORE1_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access + * HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_PERI_PMS_ALLOW (BIT(25)) +#define PMS_CORE1_MM_HP_PERI_PMS_ALLOW_M (PMS_CORE1_MM_HP_PERI_PMS_ALLOW_V << PMS_CORE1_MM_HP_PERI_PMS_ALLOW_S) +#define PMS_CORE1_MM_HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PERI_PMS_ALLOW_S 25 +/** PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) +#define PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW_M (PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW_V << PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW_S) +#define PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_LP2HP_PERI_PMS_ALLOW_S 26 +/** PMS_CORE1_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_DMA_PMS_ALLOW (BIT(27)) +#define PMS_CORE1_MM_DMA_PMS_ALLOW_M (PMS_CORE1_MM_DMA_PMS_ALLOW_V << PMS_CORE1_MM_DMA_PMS_ALLOW_S) +#define PMS_CORE1_MM_DMA_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_DMA_PMS_ALLOW_S 27 +/** PMS_CORE1_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_H264_DMA2D_ALLOW (BIT(28)) +#define PMS_CORE1_MM_HP_H264_DMA2D_ALLOW_M (PMS_CORE1_MM_HP_H264_DMA2D_ALLOW_V << PMS_CORE1_MM_HP_H264_DMA2D_ALLOW_S) +#define PMS_CORE1_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_H264_DMA2D_ALLOW_S 28 -/** TEE_CORE1_MM_PMS_REG2_REG register - * NA - */ -#define TEE_CORE1_MM_PMS_REG2_REG (DR_REG_TEE_BASE + 0x30) -/** TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW (BIT(0)) -#define TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW_M (TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW_V << TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_MCPWM0_ALLOW_S 0 -/** TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW (BIT(1)) -#define TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW_M (TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW_V << TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_MCPWM1_ALLOW_S 1 -/** TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW_M (TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW_V << TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP0_ALLOW_S 2 -/** TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW_M (TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW_V << TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_TIMER_GROUP1_ALLOW_S 3 -/** TEE_REG_CORE1_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I2C0_ALLOW (BIT(4)) -#define TEE_REG_CORE1_MM_HP_I2C0_ALLOW_M (TEE_REG_CORE1_MM_HP_I2C0_ALLOW_V << TEE_REG_CORE1_MM_HP_I2C0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I2C0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I2C0_ALLOW_S 4 -/** TEE_REG_CORE1_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I2C1_ALLOW (BIT(5)) -#define TEE_REG_CORE1_MM_HP_I2C1_ALLOW_M (TEE_REG_CORE1_MM_HP_I2C1_ALLOW_V << TEE_REG_CORE1_MM_HP_I2C1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I2C1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I2C1_ALLOW_S 5 -/** TEE_REG_CORE1_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I2S0_ALLOW (BIT(6)) -#define TEE_REG_CORE1_MM_HP_I2S0_ALLOW_M (TEE_REG_CORE1_MM_HP_I2S0_ALLOW_V << TEE_REG_CORE1_MM_HP_I2S0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I2S0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I2S0_ALLOW_S 6 -/** TEE_REG_CORE1_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I2S1_ALLOW (BIT(7)) -#define TEE_REG_CORE1_MM_HP_I2S1_ALLOW_M (TEE_REG_CORE1_MM_HP_I2S1_ALLOW_V << TEE_REG_CORE1_MM_HP_I2S1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I2S1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I2S1_ALLOW_S 7 -/** TEE_REG_CORE1_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I2S2_ALLOW (BIT(8)) -#define TEE_REG_CORE1_MM_HP_I2S2_ALLOW_M (TEE_REG_CORE1_MM_HP_I2S2_ALLOW_V << TEE_REG_CORE1_MM_HP_I2S2_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I2S2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I2S2_ALLOW_S 8 -/** TEE_REG_CORE1_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PCNT_ALLOW (BIT(9)) -#define TEE_REG_CORE1_MM_HP_PCNT_ALLOW_M (TEE_REG_CORE1_MM_HP_PCNT_ALLOW_V << TEE_REG_CORE1_MM_HP_PCNT_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PCNT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PCNT_ALLOW_S 9 -/** TEE_REG_CORE1_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UART0_ALLOW (BIT(10)) -#define TEE_REG_CORE1_MM_HP_UART0_ALLOW_M (TEE_REG_CORE1_MM_HP_UART0_ALLOW_V << TEE_REG_CORE1_MM_HP_UART0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UART0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UART0_ALLOW_S 10 -/** TEE_REG_CORE1_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UART1_ALLOW (BIT(11)) -#define TEE_REG_CORE1_MM_HP_UART1_ALLOW_M (TEE_REG_CORE1_MM_HP_UART1_ALLOW_V << TEE_REG_CORE1_MM_HP_UART1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UART1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UART1_ALLOW_S 11 -/** TEE_REG_CORE1_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UART2_ALLOW (BIT(12)) -#define TEE_REG_CORE1_MM_HP_UART2_ALLOW_M (TEE_REG_CORE1_MM_HP_UART2_ALLOW_V << TEE_REG_CORE1_MM_HP_UART2_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UART2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UART2_ALLOW_S 12 -/** TEE_REG_CORE1_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UART3_ALLOW (BIT(13)) -#define TEE_REG_CORE1_MM_HP_UART3_ALLOW_M (TEE_REG_CORE1_MM_HP_UART3_ALLOW_V << TEE_REG_CORE1_MM_HP_UART3_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UART3_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UART3_ALLOW_S 13 -/** TEE_REG_CORE1_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UART4_ALLOW (BIT(14)) -#define TEE_REG_CORE1_MM_HP_UART4_ALLOW_M (TEE_REG_CORE1_MM_HP_UART4_ALLOW_V << TEE_REG_CORE1_MM_HP_UART4_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UART4_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UART4_ALLOW_S 14 -/** TEE_REG_CORE1_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_PARLIO_ALLOW (BIT(15)) -#define TEE_REG_CORE1_MM_HP_PARLIO_ALLOW_M (TEE_REG_CORE1_MM_HP_PARLIO_ALLOW_V << TEE_REG_CORE1_MM_HP_PARLIO_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_PARLIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_PARLIO_ALLOW_S 15 -/** TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW (BIT(16)) -#define TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW_M (TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW_V << TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_GPSPI2_ALLOW_S 16 -/** TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW (BIT(17)) -#define TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW_M (TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW_V << TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_GPSPI3_ALLOW_S 17 -/** TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW (BIT(18)) -#define TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW_M (TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW_V << TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_USBDEVICE_ALLOW_S 18 -/** TEE_REG_CORE1_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_LEDC_ALLOW (BIT(19)) -#define TEE_REG_CORE1_MM_HP_LEDC_ALLOW_M (TEE_REG_CORE1_MM_HP_LEDC_ALLOW_V << TEE_REG_CORE1_MM_HP_LEDC_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_LEDC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_LEDC_ALLOW_S 19 -/** TEE_REG_CORE1_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_ETM_ALLOW (BIT(21)) -#define TEE_REG_CORE1_MM_HP_ETM_ALLOW_M (TEE_REG_CORE1_MM_HP_ETM_ALLOW_V << TEE_REG_CORE1_MM_HP_ETM_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_ETM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_ETM_ALLOW_S 21 -/** TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW (BIT(22)) -#define TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW_M (TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW_V << TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_INTRMTX_ALLOW_S 22 -/** TEE_REG_CORE1_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_TWAI0_ALLOW (BIT(23)) -#define TEE_REG_CORE1_MM_HP_TWAI0_ALLOW_M (TEE_REG_CORE1_MM_HP_TWAI0_ALLOW_V << TEE_REG_CORE1_MM_HP_TWAI0_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_TWAI0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_TWAI0_ALLOW_S 23 -/** TEE_REG_CORE1_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_TWAI1_ALLOW (BIT(24)) -#define TEE_REG_CORE1_MM_HP_TWAI1_ALLOW_M (TEE_REG_CORE1_MM_HP_TWAI1_ALLOW_V << TEE_REG_CORE1_MM_HP_TWAI1_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_TWAI1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_TWAI1_ALLOW_S 24 -/** TEE_REG_CORE1_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_TWAI2_ALLOW (BIT(25)) -#define TEE_REG_CORE1_MM_HP_TWAI2_ALLOW_M (TEE_REG_CORE1_MM_HP_TWAI2_ALLOW_V << TEE_REG_CORE1_MM_HP_TWAI2_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_TWAI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_TWAI2_ALLOW_S 25 -/** TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW (BIT(26)) -#define TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW_M (TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW_V << TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I3C_MST_ALLOW_S 26 -/** TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW (BIT(27)) -#define TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW_M (TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW_V << TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_I3C_SLV_ALLOW_S 27 -/** TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW (BIT(28)) -#define TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW_M (TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW_V << TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_LCDCAM_ALLOW_S 28 -/** TEE_REG_CORE1_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_ADC_ALLOW (BIT(30)) -#define TEE_REG_CORE1_MM_HP_ADC_ALLOW_M (TEE_REG_CORE1_MM_HP_ADC_ALLOW_V << TEE_REG_CORE1_MM_HP_ADC_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_ADC_ALLOW_S 30 -/** TEE_REG_CORE1_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_UHCI_ALLOW (BIT(31)) -#define TEE_REG_CORE1_MM_HP_UHCI_ALLOW_M (TEE_REG_CORE1_MM_HP_UHCI_ALLOW_V << TEE_REG_CORE1_MM_HP_UHCI_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_UHCI_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_UHCI_ALLOW_S 31 +/** PMS_CORE1_MM_HP_PERI_PMS_REG2_REG register + * Permission control register2 for HP CPU1 in machine mode + */ +#define PMS_CORE1_MM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x30) +/** PMS_CORE1_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_MCPWM0_ALLOW (BIT(0)) +#define PMS_CORE1_MM_HP_MCPWM0_ALLOW_M (PMS_CORE1_MM_HP_MCPWM0_ALLOW_V << PMS_CORE1_MM_HP_MCPWM0_ALLOW_S) +#define PMS_CORE1_MM_HP_MCPWM0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_MCPWM0_ALLOW_S 0 +/** PMS_CORE1_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_MCPWM1_ALLOW (BIT(1)) +#define PMS_CORE1_MM_HP_MCPWM1_ALLOW_M (PMS_CORE1_MM_HP_MCPWM1_ALLOW_V << PMS_CORE1_MM_HP_MCPWM1_ALLOW_S) +#define PMS_CORE1_MM_HP_MCPWM1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_MCPWM1_ALLOW_S 1 +/** PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP timer + * group0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) +#define PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW_M (PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW_V << PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW_S) +#define PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_TIMER_GROUP0_ALLOW_S 2 +/** PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) +#define PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW_M (PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW_V << PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW_S) +#define PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_TIMER_GROUP1_ALLOW_S 3 +/** PMS_CORE1_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I2C0_ALLOW (BIT(4)) +#define PMS_CORE1_MM_HP_I2C0_ALLOW_M (PMS_CORE1_MM_HP_I2C0_ALLOW_V << PMS_CORE1_MM_HP_I2C0_ALLOW_S) +#define PMS_CORE1_MM_HP_I2C0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I2C0_ALLOW_S 4 +/** PMS_CORE1_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I2C1_ALLOW (BIT(5)) +#define PMS_CORE1_MM_HP_I2C1_ALLOW_M (PMS_CORE1_MM_HP_I2C1_ALLOW_V << PMS_CORE1_MM_HP_I2C1_ALLOW_S) +#define PMS_CORE1_MM_HP_I2C1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I2C1_ALLOW_S 5 +/** PMS_CORE1_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I2S0_ALLOW (BIT(6)) +#define PMS_CORE1_MM_HP_I2S0_ALLOW_M (PMS_CORE1_MM_HP_I2S0_ALLOW_V << PMS_CORE1_MM_HP_I2S0_ALLOW_S) +#define PMS_CORE1_MM_HP_I2S0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I2S0_ALLOW_S 6 +/** PMS_CORE1_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I2S1_ALLOW (BIT(7)) +#define PMS_CORE1_MM_HP_I2S1_ALLOW_M (PMS_CORE1_MM_HP_I2S1_ALLOW_V << PMS_CORE1_MM_HP_I2S1_ALLOW_S) +#define PMS_CORE1_MM_HP_I2S1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I2S1_ALLOW_S 7 +/** PMS_CORE1_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I2S2_ALLOW (BIT(8)) +#define PMS_CORE1_MM_HP_I2S2_ALLOW_M (PMS_CORE1_MM_HP_I2S2_ALLOW_V << PMS_CORE1_MM_HP_I2S2_ALLOW_S) +#define PMS_CORE1_MM_HP_I2S2_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I2S2_ALLOW_S 8 +/** PMS_CORE1_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_PCNT_ALLOW (BIT(9)) +#define PMS_CORE1_MM_HP_PCNT_ALLOW_M (PMS_CORE1_MM_HP_PCNT_ALLOW_V << PMS_CORE1_MM_HP_PCNT_ALLOW_S) +#define PMS_CORE1_MM_HP_PCNT_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PCNT_ALLOW_S 9 +/** PMS_CORE1_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UART0_ALLOW (BIT(10)) +#define PMS_CORE1_MM_HP_UART0_ALLOW_M (PMS_CORE1_MM_HP_UART0_ALLOW_V << PMS_CORE1_MM_HP_UART0_ALLOW_S) +#define PMS_CORE1_MM_HP_UART0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UART0_ALLOW_S 10 +/** PMS_CORE1_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UART1_ALLOW (BIT(11)) +#define PMS_CORE1_MM_HP_UART1_ALLOW_M (PMS_CORE1_MM_HP_UART1_ALLOW_V << PMS_CORE1_MM_HP_UART1_ALLOW_S) +#define PMS_CORE1_MM_HP_UART1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UART1_ALLOW_S 11 +/** PMS_CORE1_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UART2_ALLOW (BIT(12)) +#define PMS_CORE1_MM_HP_UART2_ALLOW_M (PMS_CORE1_MM_HP_UART2_ALLOW_V << PMS_CORE1_MM_HP_UART2_ALLOW_S) +#define PMS_CORE1_MM_HP_UART2_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UART2_ALLOW_S 12 +/** PMS_CORE1_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UART3_ALLOW (BIT(13)) +#define PMS_CORE1_MM_HP_UART3_ALLOW_M (PMS_CORE1_MM_HP_UART3_ALLOW_V << PMS_CORE1_MM_HP_UART3_ALLOW_S) +#define PMS_CORE1_MM_HP_UART3_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UART3_ALLOW_S 13 +/** PMS_CORE1_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UART4_ALLOW (BIT(14)) +#define PMS_CORE1_MM_HP_UART4_ALLOW_M (PMS_CORE1_MM_HP_UART4_ALLOW_V << PMS_CORE1_MM_HP_UART4_ALLOW_S) +#define PMS_CORE1_MM_HP_UART4_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UART4_ALLOW_S 14 +/** PMS_CORE1_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_PARLIO_ALLOW (BIT(15)) +#define PMS_CORE1_MM_HP_PARLIO_ALLOW_M (PMS_CORE1_MM_HP_PARLIO_ALLOW_V << PMS_CORE1_MM_HP_PARLIO_ALLOW_S) +#define PMS_CORE1_MM_HP_PARLIO_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_PARLIO_ALLOW_S 15 +/** PMS_CORE1_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_GPSPI2_ALLOW (BIT(16)) +#define PMS_CORE1_MM_HP_GPSPI2_ALLOW_M (PMS_CORE1_MM_HP_GPSPI2_ALLOW_V << PMS_CORE1_MM_HP_GPSPI2_ALLOW_S) +#define PMS_CORE1_MM_HP_GPSPI2_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_GPSPI2_ALLOW_S 16 +/** PMS_CORE1_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_GPSPI3_ALLOW (BIT(17)) +#define PMS_CORE1_MM_HP_GPSPI3_ALLOW_M (PMS_CORE1_MM_HP_GPSPI3_ALLOW_V << PMS_CORE1_MM_HP_GPSPI3_ALLOW_S) +#define PMS_CORE1_MM_HP_GPSPI3_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_GPSPI3_ALLOW_S 17 +/** PMS_CORE1_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP USB + * Serial/JTAG Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_USBDEVICE_ALLOW (BIT(18)) +#define PMS_CORE1_MM_HP_USBDEVICE_ALLOW_M (PMS_CORE1_MM_HP_USBDEVICE_ALLOW_V << PMS_CORE1_MM_HP_USBDEVICE_ALLOW_S) +#define PMS_CORE1_MM_HP_USBDEVICE_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_USBDEVICE_ALLOW_S 18 +/** PMS_CORE1_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_LEDC_ALLOW (BIT(19)) +#define PMS_CORE1_MM_HP_LEDC_ALLOW_M (PMS_CORE1_MM_HP_LEDC_ALLOW_V << PMS_CORE1_MM_HP_LEDC_ALLOW_S) +#define PMS_CORE1_MM_HP_LEDC_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_LEDC_ALLOW_S 19 +/** PMS_CORE1_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP ETM (Event + * Task Matrix). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_ETM_ALLOW (BIT(21)) +#define PMS_CORE1_MM_HP_ETM_ALLOW_M (PMS_CORE1_MM_HP_ETM_ALLOW_V << PMS_CORE1_MM_HP_ETM_ALLOW_S) +#define PMS_CORE1_MM_HP_ETM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_ETM_ALLOW_S 21 +/** PMS_CORE1_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_INTRMTX_ALLOW (BIT(22)) +#define PMS_CORE1_MM_HP_INTRMTX_ALLOW_M (PMS_CORE1_MM_HP_INTRMTX_ALLOW_V << PMS_CORE1_MM_HP_INTRMTX_ALLOW_S) +#define PMS_CORE1_MM_HP_INTRMTX_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_INTRMTX_ALLOW_S 22 +/** PMS_CORE1_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_TWAI0_ALLOW (BIT(23)) +#define PMS_CORE1_MM_HP_TWAI0_ALLOW_M (PMS_CORE1_MM_HP_TWAI0_ALLOW_V << PMS_CORE1_MM_HP_TWAI0_ALLOW_S) +#define PMS_CORE1_MM_HP_TWAI0_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_TWAI0_ALLOW_S 23 +/** PMS_CORE1_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_TWAI1_ALLOW (BIT(24)) +#define PMS_CORE1_MM_HP_TWAI1_ALLOW_M (PMS_CORE1_MM_HP_TWAI1_ALLOW_V << PMS_CORE1_MM_HP_TWAI1_ALLOW_S) +#define PMS_CORE1_MM_HP_TWAI1_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_TWAI1_ALLOW_S 24 +/** PMS_CORE1_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_TWAI2_ALLOW (BIT(25)) +#define PMS_CORE1_MM_HP_TWAI2_ALLOW_M (PMS_CORE1_MM_HP_TWAI2_ALLOW_V << PMS_CORE1_MM_HP_TWAI2_ALLOW_S) +#define PMS_CORE1_MM_HP_TWAI2_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_TWAI2_ALLOW_S 25 +/** PMS_CORE1_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I3C_MST_ALLOW (BIT(26)) +#define PMS_CORE1_MM_HP_I3C_MST_ALLOW_M (PMS_CORE1_MM_HP_I3C_MST_ALLOW_V << PMS_CORE1_MM_HP_I3C_MST_ALLOW_S) +#define PMS_CORE1_MM_HP_I3C_MST_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I3C_MST_ALLOW_S 26 +/** PMS_CORE1_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_I3C_SLV_ALLOW (BIT(27)) +#define PMS_CORE1_MM_HP_I3C_SLV_ALLOW_M (PMS_CORE1_MM_HP_I3C_SLV_ALLOW_V << PMS_CORE1_MM_HP_I3C_SLV_ALLOW_S) +#define PMS_CORE1_MM_HP_I3C_SLV_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_I3C_SLV_ALLOW_S 27 +/** PMS_CORE1_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_LCDCAM_ALLOW (BIT(28)) +#define PMS_CORE1_MM_HP_LCDCAM_ALLOW_M (PMS_CORE1_MM_HP_LCDCAM_ALLOW_V << PMS_CORE1_MM_HP_LCDCAM_ALLOW_S) +#define PMS_CORE1_MM_HP_LCDCAM_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_LCDCAM_ALLOW_S 28 +/** PMS_CORE1_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_ADC_ALLOW (BIT(30)) +#define PMS_CORE1_MM_HP_ADC_ALLOW_M (PMS_CORE1_MM_HP_ADC_ALLOW_V << PMS_CORE1_MM_HP_ADC_ALLOW_S) +#define PMS_CORE1_MM_HP_ADC_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_ADC_ALLOW_S 30 +/** PMS_CORE1_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_UHCI_ALLOW (BIT(31)) +#define PMS_CORE1_MM_HP_UHCI_ALLOW_M (PMS_CORE1_MM_HP_UHCI_ALLOW_V << PMS_CORE1_MM_HP_UHCI_ALLOW_S) +#define PMS_CORE1_MM_HP_UHCI_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_UHCI_ALLOW_S 31 -/** TEE_CORE1_MM_PMS_REG3_REG register - * NA - */ -#define TEE_CORE1_MM_PMS_REG3_REG (DR_REG_TEE_BASE + 0x34) -/** TEE_REG_CORE1_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_GPIO_ALLOW (BIT(0)) -#define TEE_REG_CORE1_MM_HP_GPIO_ALLOW_M (TEE_REG_CORE1_MM_HP_GPIO_ALLOW_V << TEE_REG_CORE1_MM_HP_GPIO_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_GPIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_GPIO_ALLOW_S 0 -/** TEE_REG_CORE1_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_IOMUX_ALLOW (BIT(1)) -#define TEE_REG_CORE1_MM_HP_IOMUX_ALLOW_M (TEE_REG_CORE1_MM_HP_IOMUX_ALLOW_V << TEE_REG_CORE1_MM_HP_IOMUX_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_IOMUX_ALLOW_S 1 -/** TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW (BIT(2)) -#define TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW_M (TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW_V << TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_SYSTIMER_ALLOW_S 2 -/** TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW (BIT(3)) -#define TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW_M (TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW_V << TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_SYS_REG_ALLOW_S 3 -/** TEE_REG_CORE1_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_MM_HP_CLKRST_ALLOW (BIT(4)) -#define TEE_REG_CORE1_MM_HP_CLKRST_ALLOW_M (TEE_REG_CORE1_MM_HP_CLKRST_ALLOW_V << TEE_REG_CORE1_MM_HP_CLKRST_ALLOW_S) -#define TEE_REG_CORE1_MM_HP_CLKRST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_MM_HP_CLKRST_ALLOW_S 4 +/** PMS_CORE1_MM_HP_PERI_PMS_REG3_REG register + * Permission control register3 for HP CPU1 in machine mode + */ +#define PMS_CORE1_MM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x34) +/** PMS_CORE1_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_GPIO_ALLOW (BIT(0)) +#define PMS_CORE1_MM_HP_GPIO_ALLOW_M (PMS_CORE1_MM_HP_GPIO_ALLOW_V << PMS_CORE1_MM_HP_GPIO_ALLOW_S) +#define PMS_CORE1_MM_HP_GPIO_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_GPIO_ALLOW_S 0 +/** PMS_CORE1_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_IOMUX_ALLOW (BIT(1)) +#define PMS_CORE1_MM_HP_IOMUX_ALLOW_M (PMS_CORE1_MM_HP_IOMUX_ALLOW_V << PMS_CORE1_MM_HP_IOMUX_ALLOW_S) +#define PMS_CORE1_MM_HP_IOMUX_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_IOMUX_ALLOW_S 1 +/** PMS_CORE1_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP system + * timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_SYSTIMER_ALLOW (BIT(2)) +#define PMS_CORE1_MM_HP_SYSTIMER_ALLOW_M (PMS_CORE1_MM_HP_SYSTIMER_ALLOW_V << PMS_CORE1_MM_HP_SYSTIMER_ALLOW_S) +#define PMS_CORE1_MM_HP_SYSTIMER_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_SYSTIMER_ALLOW_S 2 +/** PMS_CORE1_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_SYS_REG_ALLOW (BIT(3)) +#define PMS_CORE1_MM_HP_SYS_REG_ALLOW_M (PMS_CORE1_MM_HP_SYS_REG_ALLOW_V << PMS_CORE1_MM_HP_SYS_REG_ALLOW_S) +#define PMS_CORE1_MM_HP_SYS_REG_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_SYS_REG_ALLOW_S 3 +/** PMS_CORE1_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in machine mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_MM_HP_CLKRST_ALLOW (BIT(4)) +#define PMS_CORE1_MM_HP_CLKRST_ALLOW_M (PMS_CORE1_MM_HP_CLKRST_ALLOW_V << PMS_CORE1_MM_HP_CLKRST_ALLOW_S) +#define PMS_CORE1_MM_HP_CLKRST_ALLOW_V 0x00000001U +#define PMS_CORE1_MM_HP_CLKRST_ALLOW_S 4 -/** TEE_CORE1_UM_PMS_REG0_REG register - * NA - */ -#define TEE_CORE1_UM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x38) -/** TEE_REG_CORE1_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_PSRAM_ALLOW (BIT(0)) -#define TEE_REG_CORE1_UM_PSRAM_ALLOW_M (TEE_REG_CORE1_UM_PSRAM_ALLOW_V << TEE_REG_CORE1_UM_PSRAM_ALLOW_S) -#define TEE_REG_CORE1_UM_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_PSRAM_ALLOW_S 0 -/** TEE_REG_CORE1_UM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_FLASH_ALLOW (BIT(1)) -#define TEE_REG_CORE1_UM_FLASH_ALLOW_M (TEE_REG_CORE1_UM_FLASH_ALLOW_V << TEE_REG_CORE1_UM_FLASH_ALLOW_S) -#define TEE_REG_CORE1_UM_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_FLASH_ALLOW_S 1 -/** TEE_REG_CORE1_UM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_L2MEM_ALLOW (BIT(2)) -#define TEE_REG_CORE1_UM_L2MEM_ALLOW_M (TEE_REG_CORE1_UM_L2MEM_ALLOW_V << TEE_REG_CORE1_UM_L2MEM_ALLOW_S) -#define TEE_REG_CORE1_UM_L2MEM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_L2MEM_ALLOW_S 2 -/** TEE_REG_CORE1_UM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_L2ROM_ALLOW (BIT(3)) -#define TEE_REG_CORE1_UM_L2ROM_ALLOW_M (TEE_REG_CORE1_UM_L2ROM_ALLOW_V << TEE_REG_CORE1_UM_L2ROM_ALLOW_S) -#define TEE_REG_CORE1_UM_L2ROM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_L2ROM_ALLOW_S 3 -/** TEE_REG_CORE1_UM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_TRACE0_ALLOW (BIT(6)) -#define TEE_REG_CORE1_UM_TRACE0_ALLOW_M (TEE_REG_CORE1_UM_TRACE0_ALLOW_V << TEE_REG_CORE1_UM_TRACE0_ALLOW_S) -#define TEE_REG_CORE1_UM_TRACE0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_TRACE0_ALLOW_S 6 -/** TEE_REG_CORE1_UM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_TRACE1_ALLOW (BIT(7)) -#define TEE_REG_CORE1_UM_TRACE1_ALLOW_M (TEE_REG_CORE1_UM_TRACE1_ALLOW_V << TEE_REG_CORE1_UM_TRACE1_ALLOW_S) -#define TEE_REG_CORE1_UM_TRACE1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_TRACE1_ALLOW_S 7 -/** TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW (BIT(8)) -#define TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW_M (TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW_V << TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW_S) -#define TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_CPU_BUS_MON_ALLOW_S 8 -/** TEE_REG_CORE1_UM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_L2MEM_MON_ALLOW (BIT(9)) -#define TEE_REG_CORE1_UM_L2MEM_MON_ALLOW_M (TEE_REG_CORE1_UM_L2MEM_MON_ALLOW_V << TEE_REG_CORE1_UM_L2MEM_MON_ALLOW_S) -#define TEE_REG_CORE1_UM_L2MEM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_L2MEM_MON_ALLOW_S 9 -/** TEE_REG_CORE1_UM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_TCM_MON_ALLOW (BIT(10)) -#define TEE_REG_CORE1_UM_TCM_MON_ALLOW_M (TEE_REG_CORE1_UM_TCM_MON_ALLOW_V << TEE_REG_CORE1_UM_TCM_MON_ALLOW_S) -#define TEE_REG_CORE1_UM_TCM_MON_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_TCM_MON_ALLOW_S 10 -/** TEE_REG_CORE1_UM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_CACHE_ALLOW (BIT(11)) -#define TEE_REG_CORE1_UM_CACHE_ALLOW_M (TEE_REG_CORE1_UM_CACHE_ALLOW_V << TEE_REG_CORE1_UM_CACHE_ALLOW_S) -#define TEE_REG_CORE1_UM_CACHE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_CACHE_ALLOW_S 11 +/** PMS_CORE1_UM_HP_PERI_PMS_REG0_REG register + * Permission control register0 for HP CPU1 in user mode + */ +#define PMS_CORE1_UM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x38) +/** PMS_CORE1_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_PSRAM_ALLOW (BIT(0)) +#define PMS_CORE1_UM_PSRAM_ALLOW_M (PMS_CORE1_UM_PSRAM_ALLOW_V << PMS_CORE1_UM_PSRAM_ALLOW_S) +#define PMS_CORE1_UM_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_PSRAM_ALLOW_S 0 +/** PMS_CORE1_UM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_FLASH_ALLOW (BIT(1)) +#define PMS_CORE1_UM_FLASH_ALLOW_M (PMS_CORE1_UM_FLASH_ALLOW_V << PMS_CORE1_UM_FLASH_ALLOW_S) +#define PMS_CORE1_UM_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_FLASH_ALLOW_S 1 +/** PMS_CORE1_UM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP L2MEM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_L2MEM_ALLOW (BIT(2)) +#define PMS_CORE1_UM_L2MEM_ALLOW_M (PMS_CORE1_UM_L2MEM_ALLOW_V << PMS_CORE1_UM_L2MEM_ALLOW_S) +#define PMS_CORE1_UM_L2MEM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_L2MEM_ALLOW_S 2 +/** PMS_CORE1_UM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_L2ROM_ALLOW (BIT(3)) +#define PMS_CORE1_UM_L2ROM_ALLOW_M (PMS_CORE1_UM_L2ROM_ALLOW_V << PMS_CORE1_UM_L2ROM_ALLOW_S) +#define PMS_CORE1_UM_L2ROM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_L2ROM_ALLOW_S 3 +/** PMS_CORE1_UM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_TRACE0_ALLOW (BIT(6)) +#define PMS_CORE1_UM_TRACE0_ALLOW_M (PMS_CORE1_UM_TRACE0_ALLOW_V << PMS_CORE1_UM_TRACE0_ALLOW_S) +#define PMS_CORE1_UM_TRACE0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_TRACE0_ALLOW_S 6 +/** PMS_CORE1_UM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_TRACE1_ALLOW (BIT(7)) +#define PMS_CORE1_UM_TRACE1_ALLOW_M (PMS_CORE1_UM_TRACE1_ALLOW_V << PMS_CORE1_UM_TRACE1_ALLOW_S) +#define PMS_CORE1_UM_TRACE1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_TRACE1_ALLOW_S 7 +/** PMS_CORE1_UM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access CPU bus monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_CPU_BUS_MON_ALLOW (BIT(8)) +#define PMS_CORE1_UM_CPU_BUS_MON_ALLOW_M (PMS_CORE1_UM_CPU_BUS_MON_ALLOW_V << PMS_CORE1_UM_CPU_BUS_MON_ALLOW_S) +#define PMS_CORE1_UM_CPU_BUS_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_CPU_BUS_MON_ALLOW_S 8 +/** PMS_CORE1_UM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_L2MEM_MON_ALLOW (BIT(9)) +#define PMS_CORE1_UM_L2MEM_MON_ALLOW_M (PMS_CORE1_UM_L2MEM_MON_ALLOW_V << PMS_CORE1_UM_L2MEM_MON_ALLOW_S) +#define PMS_CORE1_UM_L2MEM_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_L2MEM_MON_ALLOW_S 9 +/** PMS_CORE1_UM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_TCM_MON_ALLOW (BIT(10)) +#define PMS_CORE1_UM_TCM_MON_ALLOW_M (PMS_CORE1_UM_TCM_MON_ALLOW_V << PMS_CORE1_UM_TCM_MON_ALLOW_S) +#define PMS_CORE1_UM_TCM_MON_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_TCM_MON_ALLOW_S 10 +/** PMS_CORE1_UM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_CACHE_ALLOW (BIT(11)) +#define PMS_CORE1_UM_CACHE_ALLOW_M (PMS_CORE1_UM_CACHE_ALLOW_V << PMS_CORE1_UM_CACHE_ALLOW_S) +#define PMS_CORE1_UM_CACHE_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_CACHE_ALLOW_S 11 -/** TEE_CORE1_UM_PMS_REG1_REG register - * NA - */ -#define TEE_CORE1_UM_PMS_REG1_REG (DR_REG_TEE_BASE + 0x3c) -/** TEE_REG_CORE1_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_USBOTG_ALLOW (BIT(0)) -#define TEE_REG_CORE1_UM_HP_USBOTG_ALLOW_M (TEE_REG_CORE1_UM_HP_USBOTG_ALLOW_V << TEE_REG_CORE1_UM_HP_USBOTG_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_USBOTG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_USBOTG_ALLOW_S 0 -/** TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW (BIT(1)) -#define TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW_M (TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW_V << TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_USBOTG11_ALLOW_S 1 -/** TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) -#define TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_M (TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_V << TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_S 2 -/** TEE_REG_CORE1_UM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_GDMA_ALLOW (BIT(3)) -#define TEE_REG_CORE1_UM_HP_GDMA_ALLOW_M (TEE_REG_CORE1_UM_HP_GDMA_ALLOW_V << TEE_REG_CORE1_UM_HP_GDMA_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_GDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_GDMA_ALLOW_S 3 -/** TEE_REG_CORE1_UM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_REGDMA_ALLOW (BIT(4)) -#define TEE_REG_CORE1_UM_HP_REGDMA_ALLOW_M (TEE_REG_CORE1_UM_HP_REGDMA_ALLOW_V << TEE_REG_CORE1_UM_HP_REGDMA_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_REGDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_REGDMA_ALLOW_S 4 -/** TEE_REG_CORE1_UM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_SDMMC_ALLOW (BIT(5)) -#define TEE_REG_CORE1_UM_HP_SDMMC_ALLOW_M (TEE_REG_CORE1_UM_HP_SDMMC_ALLOW_V << TEE_REG_CORE1_UM_HP_SDMMC_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_SDMMC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_SDMMC_ALLOW_S 5 -/** TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW (BIT(6)) -#define TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW_M (TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW_V << TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_AHB_PDMA_ALLOW_S 6 -/** TEE_REG_CORE1_UM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_JPEG_ALLOW (BIT(7)) -#define TEE_REG_CORE1_UM_HP_JPEG_ALLOW_M (TEE_REG_CORE1_UM_HP_JPEG_ALLOW_V << TEE_REG_CORE1_UM_HP_JPEG_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_JPEG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_JPEG_ALLOW_S 7 -/** TEE_REG_CORE1_UM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PPA_ALLOW (BIT(8)) -#define TEE_REG_CORE1_UM_HP_PPA_ALLOW_M (TEE_REG_CORE1_UM_HP_PPA_ALLOW_V << TEE_REG_CORE1_UM_HP_PPA_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PPA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PPA_ALLOW_S 8 -/** TEE_REG_CORE1_UM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_DMA2D_ALLOW (BIT(9)) -#define TEE_REG_CORE1_UM_HP_DMA2D_ALLOW_M (TEE_REG_CORE1_UM_HP_DMA2D_ALLOW_V << TEE_REG_CORE1_UM_HP_DMA2D_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_DMA2D_ALLOW_S 9 -/** TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW (BIT(10)) -#define TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW_M (TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW_V << TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_KEY_MANAGER_ALLOW_S 10 -/** TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW (BIT(11)) -#define TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW_M (TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW_V << TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_AXI_PDMA_ALLOW_S 11 -/** TEE_REG_CORE1_UM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_FLASH_ALLOW (BIT(12)) -#define TEE_REG_CORE1_UM_HP_FLASH_ALLOW_M (TEE_REG_CORE1_UM_HP_FLASH_ALLOW_V << TEE_REG_CORE1_UM_HP_FLASH_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_FLASH_ALLOW_S 12 -/** TEE_REG_CORE1_UM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PSRAM_ALLOW (BIT(13)) -#define TEE_REG_CORE1_UM_HP_PSRAM_ALLOW_M (TEE_REG_CORE1_UM_HP_PSRAM_ALLOW_V << TEE_REG_CORE1_UM_HP_PSRAM_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PSRAM_ALLOW_S 13 -/** TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW (BIT(14)) -#define TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW_M (TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW_V << TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_CRYPTO_ALLOW_S 14 -/** TEE_REG_CORE1_UM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_GMAC_ALLOW (BIT(15)) -#define TEE_REG_CORE1_UM_HP_GMAC_ALLOW_M (TEE_REG_CORE1_UM_HP_GMAC_ALLOW_V << TEE_REG_CORE1_UM_HP_GMAC_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_GMAC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_GMAC_ALLOW_S 15 -/** TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW (BIT(16)) -#define TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW_M (TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW_V << TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_USB_PHY_ALLOW_S 16 -/** TEE_REG_CORE1_UM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PVT_ALLOW (BIT(17)) -#define TEE_REG_CORE1_UM_HP_PVT_ALLOW_M (TEE_REG_CORE1_UM_HP_PVT_ALLOW_V << TEE_REG_CORE1_UM_HP_PVT_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PVT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PVT_ALLOW_S 17 -/** TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW (BIT(18)) -#define TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW_M (TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW_V << TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_CSI_HOST_ALLOW_S 18 -/** TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW (BIT(19)) -#define TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW_M (TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW_V << TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_DSI_HOST_ALLOW_S 19 -/** TEE_REG_CORE1_UM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_ISP_ALLOW (BIT(20)) -#define TEE_REG_CORE1_UM_HP_ISP_ALLOW_M (TEE_REG_CORE1_UM_HP_ISP_ALLOW_V << TEE_REG_CORE1_UM_HP_ISP_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_ISP_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_ISP_ALLOW_S 20 -/** TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW (BIT(21)) -#define TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW_M (TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW_V << TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_H264_CORE_ALLOW_S 21 -/** TEE_REG_CORE1_UM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_RMT_ALLOW (BIT(22)) -#define TEE_REG_CORE1_UM_HP_RMT_ALLOW_M (TEE_REG_CORE1_UM_HP_RMT_ALLOW_V << TEE_REG_CORE1_UM_HP_RMT_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_RMT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_RMT_ALLOW_S 22 -/** TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW (BIT(23)) -#define TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW_M (TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW_V << TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_BITSRAMBLER_ALLOW_S 23 -/** TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW (BIT(24)) -#define TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW_M (TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW_V << TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_AXI_ICM_ALLOW_S 24 -/** TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW (BIT(25)) -#define TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW_M (TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW_V << TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PERI_PMS_ALLOW_S 25 -/** TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW (BIT(26)) -#define TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW_M (TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW_V << TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW_S) -#define TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_LP2HP_PERI_PMS_ALLOW_S 26 -/** TEE_REG_CORE1_UM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_DMA_PMS_ALLOW (BIT(27)) -#define TEE_REG_CORE1_UM_DMA_PMS_ALLOW_M (TEE_REG_CORE1_UM_DMA_PMS_ALLOW_V << TEE_REG_CORE1_UM_DMA_PMS_ALLOW_S) -#define TEE_REG_CORE1_UM_DMA_PMS_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_DMA_PMS_ALLOW_S 27 -/** TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW (BIT(28)) -#define TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW_M (TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW_V << TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_H264_DMA2D_ALLOW_S 28 +/** PMS_CORE1_UM_HP_PERI_PMS_REG1_REG register + * Permission control register1 for HP CPU1 in user mode + */ +#define PMS_CORE1_UM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x3c) +/** PMS_CORE1_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP high-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_USBOTG_ALLOW (BIT(0)) +#define PMS_CORE1_UM_HP_USBOTG_ALLOW_M (PMS_CORE1_UM_HP_USBOTG_ALLOW_V << PMS_CORE1_UM_HP_USBOTG_ALLOW_S) +#define PMS_CORE1_UM_HP_USBOTG_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_USBOTG_ALLOW_S 0 +/** PMS_CORE1_UM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP full-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_USBOTG11_ALLOW (BIT(1)) +#define PMS_CORE1_UM_HP_USBOTG11_ALLOW_M (PMS_CORE1_UM_HP_USBOTG11_ALLOW_V << PMS_CORE1_UM_HP_USBOTG11_ALLOW_S) +#define PMS_CORE1_UM_HP_USBOTG11_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_USBOTG11_ALLOW_S 1 +/** PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP full-speed USB + * 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) +#define PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_M (PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_V << PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_S) +#define PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_USBOTG11_WRAP_ALLOW_S 2 +/** PMS_CORE1_UM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_GDMA_ALLOW (BIT(3)) +#define PMS_CORE1_UM_HP_GDMA_ALLOW_M (PMS_CORE1_UM_HP_GDMA_ALLOW_V << PMS_CORE1_UM_HP_GDMA_ALLOW_S) +#define PMS_CORE1_UM_HP_GDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_GDMA_ALLOW_S 3 +/** PMS_CORE1_UM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP regdma. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE1_UM_HP_REGDMA_ALLOW (BIT(4)) +#define PMS_CORE1_UM_HP_REGDMA_ALLOW_M (PMS_CORE1_UM_HP_REGDMA_ALLOW_V << PMS_CORE1_UM_HP_REGDMA_ALLOW_S) +#define PMS_CORE1_UM_HP_REGDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_REGDMA_ALLOW_S 4 +/** PMS_CORE1_UM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_SDMMC_ALLOW (BIT(5)) +#define PMS_CORE1_UM_HP_SDMMC_ALLOW_M (PMS_CORE1_UM_HP_SDMMC_ALLOW_V << PMS_CORE1_UM_HP_SDMMC_ALLOW_S) +#define PMS_CORE1_UM_HP_SDMMC_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_SDMMC_ALLOW_S 5 +/** PMS_CORE1_UM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_AHB_PDMA_ALLOW (BIT(6)) +#define PMS_CORE1_UM_HP_AHB_PDMA_ALLOW_M (PMS_CORE1_UM_HP_AHB_PDMA_ALLOW_V << PMS_CORE1_UM_HP_AHB_PDMA_ALLOW_S) +#define PMS_CORE1_UM_HP_AHB_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_AHB_PDMA_ALLOW_S 6 +/** PMS_CORE1_UM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_JPEG_ALLOW (BIT(7)) +#define PMS_CORE1_UM_HP_JPEG_ALLOW_M (PMS_CORE1_UM_HP_JPEG_ALLOW_V << PMS_CORE1_UM_HP_JPEG_ALLOW_S) +#define PMS_CORE1_UM_HP_JPEG_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_JPEG_ALLOW_S 7 +/** PMS_CORE1_UM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_PPA_ALLOW (BIT(8)) +#define PMS_CORE1_UM_HP_PPA_ALLOW_M (PMS_CORE1_UM_HP_PPA_ALLOW_V << PMS_CORE1_UM_HP_PPA_ALLOW_S) +#define PMS_CORE1_UM_HP_PPA_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PPA_ALLOW_S 8 +/** PMS_CORE1_UM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_DMA2D_ALLOW (BIT(9)) +#define PMS_CORE1_UM_HP_DMA2D_ALLOW_M (PMS_CORE1_UM_HP_DMA2D_ALLOW_V << PMS_CORE1_UM_HP_DMA2D_ALLOW_S) +#define PMS_CORE1_UM_HP_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_DMA2D_ALLOW_S 9 +/** PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW (BIT(10)) +#define PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW_M (PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW_V << PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW_S) +#define PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_KEY_MANAGER_ALLOW_S 10 +/** PMS_CORE1_UM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_AXI_PDMA_ALLOW (BIT(11)) +#define PMS_CORE1_UM_HP_AXI_PDMA_ALLOW_M (PMS_CORE1_UM_HP_AXI_PDMA_ALLOW_V << PMS_CORE1_UM_HP_AXI_PDMA_ALLOW_S) +#define PMS_CORE1_UM_HP_AXI_PDMA_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_AXI_PDMA_ALLOW_S 11 +/** PMS_CORE1_UM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_FLASH_ALLOW (BIT(12)) +#define PMS_CORE1_UM_HP_FLASH_ALLOW_M (PMS_CORE1_UM_HP_FLASH_ALLOW_V << PMS_CORE1_UM_HP_FLASH_ALLOW_S) +#define PMS_CORE1_UM_HP_FLASH_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_FLASH_ALLOW_S 12 +/** PMS_CORE1_UM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_PSRAM_ALLOW (BIT(13)) +#define PMS_CORE1_UM_HP_PSRAM_ALLOW_M (PMS_CORE1_UM_HP_PSRAM_ALLOW_V << PMS_CORE1_UM_HP_PSRAM_ALLOW_S) +#define PMS_CORE1_UM_HP_PSRAM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PSRAM_ALLOW_S 13 +/** PMS_CORE1_UM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP CRYPTO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_CRYPTO_ALLOW (BIT(14)) +#define PMS_CORE1_UM_HP_CRYPTO_ALLOW_M (PMS_CORE1_UM_HP_CRYPTO_ALLOW_V << PMS_CORE1_UM_HP_CRYPTO_ALLOW_S) +#define PMS_CORE1_UM_HP_CRYPTO_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_CRYPTO_ALLOW_S 14 +/** PMS_CORE1_UM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_GMAC_ALLOW (BIT(15)) +#define PMS_CORE1_UM_HP_GMAC_ALLOW_M (PMS_CORE1_UM_HP_GMAC_ALLOW_V << PMS_CORE1_UM_HP_GMAC_ALLOW_S) +#define PMS_CORE1_UM_HP_GMAC_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_GMAC_ALLOW_S 15 +/** PMS_CORE1_UM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP high-speed USB + * 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_USB_PHY_ALLOW (BIT(16)) +#define PMS_CORE1_UM_HP_USB_PHY_ALLOW_M (PMS_CORE1_UM_HP_USB_PHY_ALLOW_V << PMS_CORE1_UM_HP_USB_PHY_ALLOW_S) +#define PMS_CORE1_UM_HP_USB_PHY_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_USB_PHY_ALLOW_S 16 +/** PMS_CORE1_UM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ +#define PMS_CORE1_UM_HP_PVT_ALLOW (BIT(17)) +#define PMS_CORE1_UM_HP_PVT_ALLOW_M (PMS_CORE1_UM_HP_PVT_ALLOW_V << PMS_CORE1_UM_HP_PVT_ALLOW_S) +#define PMS_CORE1_UM_HP_PVT_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PVT_ALLOW_S 17 +/** PMS_CORE1_UM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP MIPI CSI host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_CSI_HOST_ALLOW (BIT(18)) +#define PMS_CORE1_UM_HP_CSI_HOST_ALLOW_M (PMS_CORE1_UM_HP_CSI_HOST_ALLOW_V << PMS_CORE1_UM_HP_CSI_HOST_ALLOW_S) +#define PMS_CORE1_UM_HP_CSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_CSI_HOST_ALLOW_S 18 +/** PMS_CORE1_UM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP MIPI DSI host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_DSI_HOST_ALLOW (BIT(19)) +#define PMS_CORE1_UM_HP_DSI_HOST_ALLOW_M (PMS_CORE1_UM_HP_DSI_HOST_ALLOW_V << PMS_CORE1_UM_HP_DSI_HOST_ALLOW_S) +#define PMS_CORE1_UM_HP_DSI_HOST_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_DSI_HOST_ALLOW_S 19 +/** PMS_CORE1_UM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP ISP. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_ISP_ALLOW (BIT(20)) +#define PMS_CORE1_UM_HP_ISP_ALLOW_M (PMS_CORE1_UM_HP_ISP_ALLOW_V << PMS_CORE1_UM_HP_ISP_ALLOW_S) +#define PMS_CORE1_UM_HP_ISP_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_ISP_ALLOW_S 20 +/** PMS_CORE1_UM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP H264 Encoder. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_H264_CORE_ALLOW (BIT(21)) +#define PMS_CORE1_UM_HP_H264_CORE_ALLOW_M (PMS_CORE1_UM_HP_H264_CORE_ALLOW_V << PMS_CORE1_UM_HP_H264_CORE_ALLOW_S) +#define PMS_CORE1_UM_HP_H264_CORE_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_H264_CORE_ALLOW_S 21 +/** PMS_CORE1_UM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_RMT_ALLOW (BIT(22)) +#define PMS_CORE1_UM_HP_RMT_ALLOW_M (PMS_CORE1_UM_HP_RMT_ALLOW_V << PMS_CORE1_UM_HP_RMT_ALLOW_S) +#define PMS_CORE1_UM_HP_RMT_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_RMT_ALLOW_S 22 +/** PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP bit scrambler. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW (BIT(23)) +#define PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW_M (PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW_V << PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW_S) +#define PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_BITSRAMBLER_ALLOW_S 23 +/** PMS_CORE1_UM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_AXI_ICM_ALLOW (BIT(24)) +#define PMS_CORE1_UM_HP_AXI_ICM_ALLOW_M (PMS_CORE1_UM_HP_AXI_ICM_ALLOW_V << PMS_CORE1_UM_HP_AXI_ICM_ALLOW_S) +#define PMS_CORE1_UM_HP_AXI_ICM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_AXI_ICM_ALLOW_S 24 +/** PMS_CORE1_UM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_PERI_PMS_ALLOW (BIT(25)) +#define PMS_CORE1_UM_HP_PERI_PMS_ALLOW_M (PMS_CORE1_UM_HP_PERI_PMS_ALLOW_V << PMS_CORE1_UM_HP_PERI_PMS_ALLOW_S) +#define PMS_CORE1_UM_HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PERI_PMS_ALLOW_S 25 +/** PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW (BIT(26)) +#define PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW_M (PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW_V << PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW_S) +#define PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_LP2HP_PERI_PMS_ALLOW_S 26 +/** PMS_CORE1_UM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_DMA_PMS_ALLOW (BIT(27)) +#define PMS_CORE1_UM_DMA_PMS_ALLOW_M (PMS_CORE1_UM_DMA_PMS_ALLOW_V << PMS_CORE1_UM_DMA_PMS_ALLOW_S) +#define PMS_CORE1_UM_DMA_PMS_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_DMA_PMS_ALLOW_S 27 +/** PMS_CORE1_UM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_H264_DMA2D_ALLOW (BIT(28)) +#define PMS_CORE1_UM_HP_H264_DMA2D_ALLOW_M (PMS_CORE1_UM_HP_H264_DMA2D_ALLOW_V << PMS_CORE1_UM_HP_H264_DMA2D_ALLOW_S) +#define PMS_CORE1_UM_HP_H264_DMA2D_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_H264_DMA2D_ALLOW_S 28 -/** TEE_CORE1_UM_PMS_REG2_REG register - * NA - */ -#define TEE_CORE1_UM_PMS_REG2_REG (DR_REG_TEE_BASE + 0x40) -/** TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW (BIT(0)) -#define TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW_M (TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW_V << TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_MCPWM0_ALLOW_S 0 -/** TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW (BIT(1)) -#define TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW_M (TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW_V << TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_MCPWM1_ALLOW_S 1 -/** TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW (BIT(2)) -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW_M (TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW_V << TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP0_ALLOW_S 2 -/** TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW (BIT(3)) -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW_M (TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW_V << TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_TIMER_GROUP1_ALLOW_S 3 -/** TEE_REG_CORE1_UM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I2C0_ALLOW (BIT(4)) -#define TEE_REG_CORE1_UM_HP_I2C0_ALLOW_M (TEE_REG_CORE1_UM_HP_I2C0_ALLOW_V << TEE_REG_CORE1_UM_HP_I2C0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I2C0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I2C0_ALLOW_S 4 -/** TEE_REG_CORE1_UM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I2C1_ALLOW (BIT(5)) -#define TEE_REG_CORE1_UM_HP_I2C1_ALLOW_M (TEE_REG_CORE1_UM_HP_I2C1_ALLOW_V << TEE_REG_CORE1_UM_HP_I2C1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I2C1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I2C1_ALLOW_S 5 -/** TEE_REG_CORE1_UM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I2S0_ALLOW (BIT(6)) -#define TEE_REG_CORE1_UM_HP_I2S0_ALLOW_M (TEE_REG_CORE1_UM_HP_I2S0_ALLOW_V << TEE_REG_CORE1_UM_HP_I2S0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I2S0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I2S0_ALLOW_S 6 -/** TEE_REG_CORE1_UM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I2S1_ALLOW (BIT(7)) -#define TEE_REG_CORE1_UM_HP_I2S1_ALLOW_M (TEE_REG_CORE1_UM_HP_I2S1_ALLOW_V << TEE_REG_CORE1_UM_HP_I2S1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I2S1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I2S1_ALLOW_S 7 -/** TEE_REG_CORE1_UM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I2S2_ALLOW (BIT(8)) -#define TEE_REG_CORE1_UM_HP_I2S2_ALLOW_M (TEE_REG_CORE1_UM_HP_I2S2_ALLOW_V << TEE_REG_CORE1_UM_HP_I2S2_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I2S2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I2S2_ALLOW_S 8 -/** TEE_REG_CORE1_UM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PCNT_ALLOW (BIT(9)) -#define TEE_REG_CORE1_UM_HP_PCNT_ALLOW_M (TEE_REG_CORE1_UM_HP_PCNT_ALLOW_V << TEE_REG_CORE1_UM_HP_PCNT_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PCNT_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PCNT_ALLOW_S 9 -/** TEE_REG_CORE1_UM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UART0_ALLOW (BIT(10)) -#define TEE_REG_CORE1_UM_HP_UART0_ALLOW_M (TEE_REG_CORE1_UM_HP_UART0_ALLOW_V << TEE_REG_CORE1_UM_HP_UART0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UART0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UART0_ALLOW_S 10 -/** TEE_REG_CORE1_UM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UART1_ALLOW (BIT(11)) -#define TEE_REG_CORE1_UM_HP_UART1_ALLOW_M (TEE_REG_CORE1_UM_HP_UART1_ALLOW_V << TEE_REG_CORE1_UM_HP_UART1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UART1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UART1_ALLOW_S 11 -/** TEE_REG_CORE1_UM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UART2_ALLOW (BIT(12)) -#define TEE_REG_CORE1_UM_HP_UART2_ALLOW_M (TEE_REG_CORE1_UM_HP_UART2_ALLOW_V << TEE_REG_CORE1_UM_HP_UART2_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UART2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UART2_ALLOW_S 12 -/** TEE_REG_CORE1_UM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UART3_ALLOW (BIT(13)) -#define TEE_REG_CORE1_UM_HP_UART3_ALLOW_M (TEE_REG_CORE1_UM_HP_UART3_ALLOW_V << TEE_REG_CORE1_UM_HP_UART3_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UART3_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UART3_ALLOW_S 13 -/** TEE_REG_CORE1_UM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UART4_ALLOW (BIT(14)) -#define TEE_REG_CORE1_UM_HP_UART4_ALLOW_M (TEE_REG_CORE1_UM_HP_UART4_ALLOW_V << TEE_REG_CORE1_UM_HP_UART4_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UART4_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UART4_ALLOW_S 14 -/** TEE_REG_CORE1_UM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_PARLIO_ALLOW (BIT(15)) -#define TEE_REG_CORE1_UM_HP_PARLIO_ALLOW_M (TEE_REG_CORE1_UM_HP_PARLIO_ALLOW_V << TEE_REG_CORE1_UM_HP_PARLIO_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_PARLIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_PARLIO_ALLOW_S 15 -/** TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW (BIT(16)) -#define TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW_M (TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW_V << TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_GPSPI2_ALLOW_S 16 -/** TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW (BIT(17)) -#define TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW_M (TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW_V << TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_GPSPI3_ALLOW_S 17 -/** TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW (BIT(18)) -#define TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW_M (TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW_V << TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_USBDEVICE_ALLOW_S 18 -/** TEE_REG_CORE1_UM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_LEDC_ALLOW (BIT(19)) -#define TEE_REG_CORE1_UM_HP_LEDC_ALLOW_M (TEE_REG_CORE1_UM_HP_LEDC_ALLOW_V << TEE_REG_CORE1_UM_HP_LEDC_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_LEDC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_LEDC_ALLOW_S 19 -/** TEE_REG_CORE1_UM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_ETM_ALLOW (BIT(21)) -#define TEE_REG_CORE1_UM_HP_ETM_ALLOW_M (TEE_REG_CORE1_UM_HP_ETM_ALLOW_V << TEE_REG_CORE1_UM_HP_ETM_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_ETM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_ETM_ALLOW_S 21 -/** TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW (BIT(22)) -#define TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW_M (TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW_V << TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_INTRMTX_ALLOW_S 22 -/** TEE_REG_CORE1_UM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_TWAI0_ALLOW (BIT(23)) -#define TEE_REG_CORE1_UM_HP_TWAI0_ALLOW_M (TEE_REG_CORE1_UM_HP_TWAI0_ALLOW_V << TEE_REG_CORE1_UM_HP_TWAI0_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_TWAI0_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_TWAI0_ALLOW_S 23 -/** TEE_REG_CORE1_UM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_TWAI1_ALLOW (BIT(24)) -#define TEE_REG_CORE1_UM_HP_TWAI1_ALLOW_M (TEE_REG_CORE1_UM_HP_TWAI1_ALLOW_V << TEE_REG_CORE1_UM_HP_TWAI1_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_TWAI1_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_TWAI1_ALLOW_S 24 -/** TEE_REG_CORE1_UM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_TWAI2_ALLOW (BIT(25)) -#define TEE_REG_CORE1_UM_HP_TWAI2_ALLOW_M (TEE_REG_CORE1_UM_HP_TWAI2_ALLOW_V << TEE_REG_CORE1_UM_HP_TWAI2_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_TWAI2_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_TWAI2_ALLOW_S 25 -/** TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW (BIT(26)) -#define TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW_M (TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW_V << TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I3C_MST_ALLOW_S 26 -/** TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW (BIT(27)) -#define TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW_M (TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW_V << TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_I3C_SLV_ALLOW_S 27 -/** TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW (BIT(28)) -#define TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW_M (TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW_V << TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_LCDCAM_ALLOW_S 28 -/** TEE_REG_CORE1_UM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_ADC_ALLOW (BIT(30)) -#define TEE_REG_CORE1_UM_HP_ADC_ALLOW_M (TEE_REG_CORE1_UM_HP_ADC_ALLOW_V << TEE_REG_CORE1_UM_HP_ADC_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_ADC_ALLOW_S 30 -/** TEE_REG_CORE1_UM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_UHCI_ALLOW (BIT(31)) -#define TEE_REG_CORE1_UM_HP_UHCI_ALLOW_M (TEE_REG_CORE1_UM_HP_UHCI_ALLOW_V << TEE_REG_CORE1_UM_HP_UHCI_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_UHCI_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_UHCI_ALLOW_S 31 +/** PMS_CORE1_UM_HP_PERI_PMS_REG2_REG register + * Permission control register2 for HP CPU1 in user mode + */ +#define PMS_CORE1_UM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x40) +/** PMS_CORE1_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_MCPWM0_ALLOW (BIT(0)) +#define PMS_CORE1_UM_HP_MCPWM0_ALLOW_M (PMS_CORE1_UM_HP_MCPWM0_ALLOW_V << PMS_CORE1_UM_HP_MCPWM0_ALLOW_S) +#define PMS_CORE1_UM_HP_MCPWM0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_MCPWM0_ALLOW_S 0 +/** PMS_CORE1_UM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_MCPWM1_ALLOW (BIT(1)) +#define PMS_CORE1_UM_HP_MCPWM1_ALLOW_M (PMS_CORE1_UM_HP_MCPWM1_ALLOW_V << PMS_CORE1_UM_HP_MCPWM1_ALLOW_S) +#define PMS_CORE1_UM_HP_MCPWM1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_MCPWM1_ALLOW_S 1 +/** PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP timer group0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW (BIT(2)) +#define PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW_M (PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW_V << PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW_S) +#define PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_TIMER_GROUP0_ALLOW_S 2 +/** PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW (BIT(3)) +#define PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW_M (PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW_V << PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW_S) +#define PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_TIMER_GROUP1_ALLOW_S 3 +/** PMS_CORE1_UM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I2C0_ALLOW (BIT(4)) +#define PMS_CORE1_UM_HP_I2C0_ALLOW_M (PMS_CORE1_UM_HP_I2C0_ALLOW_V << PMS_CORE1_UM_HP_I2C0_ALLOW_S) +#define PMS_CORE1_UM_HP_I2C0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I2C0_ALLOW_S 4 +/** PMS_CORE1_UM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I2C1_ALLOW (BIT(5)) +#define PMS_CORE1_UM_HP_I2C1_ALLOW_M (PMS_CORE1_UM_HP_I2C1_ALLOW_V << PMS_CORE1_UM_HP_I2C1_ALLOW_S) +#define PMS_CORE1_UM_HP_I2C1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I2C1_ALLOW_S 5 +/** PMS_CORE1_UM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I2S0_ALLOW (BIT(6)) +#define PMS_CORE1_UM_HP_I2S0_ALLOW_M (PMS_CORE1_UM_HP_I2S0_ALLOW_V << PMS_CORE1_UM_HP_I2S0_ALLOW_S) +#define PMS_CORE1_UM_HP_I2S0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I2S0_ALLOW_S 6 +/** PMS_CORE1_UM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I2S1_ALLOW (BIT(7)) +#define PMS_CORE1_UM_HP_I2S1_ALLOW_M (PMS_CORE1_UM_HP_I2S1_ALLOW_V << PMS_CORE1_UM_HP_I2S1_ALLOW_S) +#define PMS_CORE1_UM_HP_I2S1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I2S1_ALLOW_S 7 +/** PMS_CORE1_UM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I2S2_ALLOW (BIT(8)) +#define PMS_CORE1_UM_HP_I2S2_ALLOW_M (PMS_CORE1_UM_HP_I2S2_ALLOW_V << PMS_CORE1_UM_HP_I2S2_ALLOW_S) +#define PMS_CORE1_UM_HP_I2S2_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I2S2_ALLOW_S 8 +/** PMS_CORE1_UM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_PCNT_ALLOW (BIT(9)) +#define PMS_CORE1_UM_HP_PCNT_ALLOW_M (PMS_CORE1_UM_HP_PCNT_ALLOW_V << PMS_CORE1_UM_HP_PCNT_ALLOW_S) +#define PMS_CORE1_UM_HP_PCNT_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PCNT_ALLOW_S 9 +/** PMS_CORE1_UM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UART0_ALLOW (BIT(10)) +#define PMS_CORE1_UM_HP_UART0_ALLOW_M (PMS_CORE1_UM_HP_UART0_ALLOW_V << PMS_CORE1_UM_HP_UART0_ALLOW_S) +#define PMS_CORE1_UM_HP_UART0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UART0_ALLOW_S 10 +/** PMS_CORE1_UM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UART1_ALLOW (BIT(11)) +#define PMS_CORE1_UM_HP_UART1_ALLOW_M (PMS_CORE1_UM_HP_UART1_ALLOW_V << PMS_CORE1_UM_HP_UART1_ALLOW_S) +#define PMS_CORE1_UM_HP_UART1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UART1_ALLOW_S 11 +/** PMS_CORE1_UM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UART2_ALLOW (BIT(12)) +#define PMS_CORE1_UM_HP_UART2_ALLOW_M (PMS_CORE1_UM_HP_UART2_ALLOW_V << PMS_CORE1_UM_HP_UART2_ALLOW_S) +#define PMS_CORE1_UM_HP_UART2_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UART2_ALLOW_S 12 +/** PMS_CORE1_UM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UART3_ALLOW (BIT(13)) +#define PMS_CORE1_UM_HP_UART3_ALLOW_M (PMS_CORE1_UM_HP_UART3_ALLOW_V << PMS_CORE1_UM_HP_UART3_ALLOW_S) +#define PMS_CORE1_UM_HP_UART3_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UART3_ALLOW_S 13 +/** PMS_CORE1_UM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UART4_ALLOW (BIT(14)) +#define PMS_CORE1_UM_HP_UART4_ALLOW_M (PMS_CORE1_UM_HP_UART4_ALLOW_V << PMS_CORE1_UM_HP_UART4_ALLOW_S) +#define PMS_CORE1_UM_HP_UART4_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UART4_ALLOW_S 14 +/** PMS_CORE1_UM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_PARLIO_ALLOW (BIT(15)) +#define PMS_CORE1_UM_HP_PARLIO_ALLOW_M (PMS_CORE1_UM_HP_PARLIO_ALLOW_V << PMS_CORE1_UM_HP_PARLIO_ALLOW_S) +#define PMS_CORE1_UM_HP_PARLIO_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_PARLIO_ALLOW_S 15 +/** PMS_CORE1_UM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_GPSPI2_ALLOW (BIT(16)) +#define PMS_CORE1_UM_HP_GPSPI2_ALLOW_M (PMS_CORE1_UM_HP_GPSPI2_ALLOW_V << PMS_CORE1_UM_HP_GPSPI2_ALLOW_S) +#define PMS_CORE1_UM_HP_GPSPI2_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_GPSPI2_ALLOW_S 16 +/** PMS_CORE1_UM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_GPSPI3_ALLOW (BIT(17)) +#define PMS_CORE1_UM_HP_GPSPI3_ALLOW_M (PMS_CORE1_UM_HP_GPSPI3_ALLOW_V << PMS_CORE1_UM_HP_GPSPI3_ALLOW_S) +#define PMS_CORE1_UM_HP_GPSPI3_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_GPSPI3_ALLOW_S 17 +/** PMS_CORE1_UM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP USB/Serial JTAG + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_USBDEVICE_ALLOW (BIT(18)) +#define PMS_CORE1_UM_HP_USBDEVICE_ALLOW_M (PMS_CORE1_UM_HP_USBDEVICE_ALLOW_V << PMS_CORE1_UM_HP_USBDEVICE_ALLOW_S) +#define PMS_CORE1_UM_HP_USBDEVICE_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_USBDEVICE_ALLOW_S 18 +/** PMS_CORE1_UM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_LEDC_ALLOW (BIT(19)) +#define PMS_CORE1_UM_HP_LEDC_ALLOW_M (PMS_CORE1_UM_HP_LEDC_ALLOW_V << PMS_CORE1_UM_HP_LEDC_ALLOW_S) +#define PMS_CORE1_UM_HP_LEDC_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_LEDC_ALLOW_S 19 +/** PMS_CORE1_UM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP ETM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_ETM_ALLOW (BIT(21)) +#define PMS_CORE1_UM_HP_ETM_ALLOW_M (PMS_CORE1_UM_HP_ETM_ALLOW_V << PMS_CORE1_UM_HP_ETM_ALLOW_S) +#define PMS_CORE1_UM_HP_ETM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_ETM_ALLOW_S 21 +/** PMS_CORE1_UM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_INTRMTX_ALLOW (BIT(22)) +#define PMS_CORE1_UM_HP_INTRMTX_ALLOW_M (PMS_CORE1_UM_HP_INTRMTX_ALLOW_V << PMS_CORE1_UM_HP_INTRMTX_ALLOW_S) +#define PMS_CORE1_UM_HP_INTRMTX_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_INTRMTX_ALLOW_S 22 +/** PMS_CORE1_UM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_TWAI0_ALLOW (BIT(23)) +#define PMS_CORE1_UM_HP_TWAI0_ALLOW_M (PMS_CORE1_UM_HP_TWAI0_ALLOW_V << PMS_CORE1_UM_HP_TWAI0_ALLOW_S) +#define PMS_CORE1_UM_HP_TWAI0_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_TWAI0_ALLOW_S 23 +/** PMS_CORE1_UM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_TWAI1_ALLOW (BIT(24)) +#define PMS_CORE1_UM_HP_TWAI1_ALLOW_M (PMS_CORE1_UM_HP_TWAI1_ALLOW_V << PMS_CORE1_UM_HP_TWAI1_ALLOW_S) +#define PMS_CORE1_UM_HP_TWAI1_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_TWAI1_ALLOW_S 24 +/** PMS_CORE1_UM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_TWAI2_ALLOW (BIT(25)) +#define PMS_CORE1_UM_HP_TWAI2_ALLOW_M (PMS_CORE1_UM_HP_TWAI2_ALLOW_V << PMS_CORE1_UM_HP_TWAI2_ALLOW_S) +#define PMS_CORE1_UM_HP_TWAI2_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_TWAI2_ALLOW_S 25 +/** PMS_CORE1_UM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I3C_MST_ALLOW (BIT(26)) +#define PMS_CORE1_UM_HP_I3C_MST_ALLOW_M (PMS_CORE1_UM_HP_I3C_MST_ALLOW_V << PMS_CORE1_UM_HP_I3C_MST_ALLOW_S) +#define PMS_CORE1_UM_HP_I3C_MST_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I3C_MST_ALLOW_S 26 +/** PMS_CORE1_UM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_I3C_SLV_ALLOW (BIT(27)) +#define PMS_CORE1_UM_HP_I3C_SLV_ALLOW_M (PMS_CORE1_UM_HP_I3C_SLV_ALLOW_V << PMS_CORE1_UM_HP_I3C_SLV_ALLOW_S) +#define PMS_CORE1_UM_HP_I3C_SLV_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_I3C_SLV_ALLOW_S 27 +/** PMS_CORE1_UM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_LCDCAM_ALLOW (BIT(28)) +#define PMS_CORE1_UM_HP_LCDCAM_ALLOW_M (PMS_CORE1_UM_HP_LCDCAM_ALLOW_V << PMS_CORE1_UM_HP_LCDCAM_ALLOW_S) +#define PMS_CORE1_UM_HP_LCDCAM_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_LCDCAM_ALLOW_S 28 +/** PMS_CORE1_UM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_ADC_ALLOW (BIT(30)) +#define PMS_CORE1_UM_HP_ADC_ALLOW_M (PMS_CORE1_UM_HP_ADC_ALLOW_V << PMS_CORE1_UM_HP_ADC_ALLOW_S) +#define PMS_CORE1_UM_HP_ADC_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_ADC_ALLOW_S 30 +/** PMS_CORE1_UM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_UHCI_ALLOW (BIT(31)) +#define PMS_CORE1_UM_HP_UHCI_ALLOW_M (PMS_CORE1_UM_HP_UHCI_ALLOW_V << PMS_CORE1_UM_HP_UHCI_ALLOW_S) +#define PMS_CORE1_UM_HP_UHCI_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_UHCI_ALLOW_S 31 -/** TEE_CORE1_UM_PMS_REG3_REG register - * NA - */ -#define TEE_CORE1_UM_PMS_REG3_REG (DR_REG_TEE_BASE + 0x44) -/** TEE_REG_CORE1_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_GPIO_ALLOW (BIT(0)) -#define TEE_REG_CORE1_UM_HP_GPIO_ALLOW_M (TEE_REG_CORE1_UM_HP_GPIO_ALLOW_V << TEE_REG_CORE1_UM_HP_GPIO_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_GPIO_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_GPIO_ALLOW_S 0 -/** TEE_REG_CORE1_UM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_IOMUX_ALLOW (BIT(1)) -#define TEE_REG_CORE1_UM_HP_IOMUX_ALLOW_M (TEE_REG_CORE1_UM_HP_IOMUX_ALLOW_V << TEE_REG_CORE1_UM_HP_IOMUX_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_IOMUX_ALLOW_S 1 -/** TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW (BIT(2)) -#define TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW_M (TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW_V << TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_SYSTIMER_ALLOW_S 2 -/** TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW (BIT(3)) -#define TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW_M (TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW_V << TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_SYS_REG_ALLOW_S 3 -/** TEE_REG_CORE1_UM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_CORE1_UM_HP_CLKRST_ALLOW (BIT(4)) -#define TEE_REG_CORE1_UM_HP_CLKRST_ALLOW_M (TEE_REG_CORE1_UM_HP_CLKRST_ALLOW_V << TEE_REG_CORE1_UM_HP_CLKRST_ALLOW_S) -#define TEE_REG_CORE1_UM_HP_CLKRST_ALLOW_V 0x00000001U -#define TEE_REG_CORE1_UM_HP_CLKRST_ALLOW_S 4 +/** PMS_CORE1_UM_HP_PERI_PMS_REG3_REG register + * Permission control register3 for HP CPU1 in user mode + */ +#define PMS_CORE1_UM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x44) +/** PMS_CORE1_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_GPIO_ALLOW (BIT(0)) +#define PMS_CORE1_UM_HP_GPIO_ALLOW_M (PMS_CORE1_UM_HP_GPIO_ALLOW_V << PMS_CORE1_UM_HP_GPIO_ALLOW_S) +#define PMS_CORE1_UM_HP_GPIO_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_GPIO_ALLOW_S 0 +/** PMS_CORE1_UM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_IOMUX_ALLOW (BIT(1)) +#define PMS_CORE1_UM_HP_IOMUX_ALLOW_M (PMS_CORE1_UM_HP_IOMUX_ALLOW_V << PMS_CORE1_UM_HP_IOMUX_ALLOW_S) +#define PMS_CORE1_UM_HP_IOMUX_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_IOMUX_ALLOW_S 1 +/** PMS_CORE1_UM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP system timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_SYSTIMER_ALLOW (BIT(2)) +#define PMS_CORE1_UM_HP_SYSTIMER_ALLOW_M (PMS_CORE1_UM_HP_SYSTIMER_ALLOW_V << PMS_CORE1_UM_HP_SYSTIMER_ALLOW_S) +#define PMS_CORE1_UM_HP_SYSTIMER_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_SYSTIMER_ALLOW_S 2 +/** PMS_CORE1_UM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_SYS_REG_ALLOW (BIT(3)) +#define PMS_CORE1_UM_HP_SYS_REG_ALLOW_M (PMS_CORE1_UM_HP_SYS_REG_ALLOW_V << PMS_CORE1_UM_HP_SYS_REG_ALLOW_S) +#define PMS_CORE1_UM_HP_SYS_REG_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_SYS_REG_ALLOW_S 3 +/** PMS_CORE1_UM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPU1 in user mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_CORE1_UM_HP_CLKRST_ALLOW (BIT(4)) +#define PMS_CORE1_UM_HP_CLKRST_ALLOW_M (PMS_CORE1_UM_HP_CLKRST_ALLOW_V << PMS_CORE1_UM_HP_CLKRST_ALLOW_S) +#define PMS_CORE1_UM_HP_CLKRST_ALLOW_V 0x00000001U +#define PMS_CORE1_UM_HP_CLKRST_ALLOW_S 4 -/** TEE_REGDMA_PERI_PMS_REG register - * NA - */ -#define TEE_REGDMA_PERI_PMS_REG (DR_REG_TEE_BASE + 0x48) -/** TEE_REG_REGDMA_PERI_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_REGDMA_PERI_ALLOW (BIT(0)) -#define TEE_REG_REGDMA_PERI_ALLOW_M (TEE_REG_REGDMA_PERI_ALLOW_V << TEE_REG_REGDMA_PERI_ALLOW_S) -#define TEE_REG_REGDMA_PERI_ALLOW_V 0x00000001U -#define TEE_REG_REGDMA_PERI_ALLOW_S 0 +/** PMS_REGDMA_PERI_PMS_REG register + * Permission register for REGDMA + */ +#define PMS_REGDMA_PERI_PMS_REG (DR_REG_PMS_BASE + 0x48) +/** PMS_REGDMA_PERI_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether REGDMA has permission to access all HP peripheral (including CPU + * peripherals). + * 0: Not allowed + * 1: Allow + */ +#define PMS_REGDMA_PERI_ALLOW (BIT(0)) +#define PMS_REGDMA_PERI_ALLOW_M (PMS_REGDMA_PERI_ALLOW_V << PMS_REGDMA_PERI_ALLOW_S) +#define PMS_REGDMA_PERI_ALLOW_V 0x00000001U +#define PMS_REGDMA_PERI_ALLOW_S 0 #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/hp_peri_pms_struct.h b/components/soc/esp32p4/include/soc/hp_peri_pms_struct.h index 85149ae6739..41091e040ea 100644 --- a/components/soc/esp32p4/include/soc/hp_peri_pms_struct.h +++ b/components/soc/esp32p4/include/soc/hp_peri_pms_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,1462 +10,1104 @@ extern "C" { #endif -/** Group: TEE PMS DATE REG */ -/** Type of pms_date register - * NA +/** Group: TEE HP Peripheral Version Control Registers */ +/** Type of hp_peri_pms_date register + * Version control register */ typedef union { struct { - /** tee_date : R/W; bitpos: [31:0]; default: 2294537; - * NA + /** hp_peri_pms_date : R/W; bitpos: [31:0]; default: 2294537; + * Version control register. */ - uint32_t tee_date:32; + uint32_t hp_peri_pms_date:32; }; uint32_t val; -} tee_pms_date_reg_t; +} pms_hp_peri_pms_date_reg_t; -/** Group: TEE PMS CLK EN REG */ -/** Type of pms_clk_en register - * NA +/** Group: Clock Gating Registers */ +/** Type of hp_peri_pms_clk_en register + * Clock gating register */ typedef union { struct { - /** reg_clk_en : R/W; bitpos: [0]; default: 1; - * NA + /** hp_peri_pms_clk_en : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on */ - uint32_t reg_clk_en:1; + uint32_t hp_peri_pms_clk_en:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_pms_clk_en_reg_t; +} pms_hp_peri_pms_clk_en_reg_t; -/** Group: TEE CORE0 MM PMS REG0 REG */ -/** Type of core0_mm_pms_reg0 register - * NA +/** Group: HP CPU Permission Control Registers */ +/** Type of coren_mm_hp_peri_pms_reg0 register + * Permission control register0 for HP CPUn in machine mode */ typedef union { struct { - /** reg_core0_mm_psram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_mm_psram_allow:1; - /** reg_core0_mm_flash_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_mm_flash_allow:1; - /** reg_core0_mm_l2mem_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_mm_l2mem_allow:1; - /** reg_core0_mm_l2rom_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_mm_l2rom_allow:1; + /** coren_mm_psram_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_psram_allow:1; + /** coren_mm_flash_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_flash_allow:1; + /** coren_mm_l2mem_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP L2MEM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_l2mem_allow:1; + /** coren_mm_l2rom_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_l2rom_allow:1; uint32_t reserved_4:2; - /** reg_core0_mm_trace0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_mm_trace0_allow:1; - /** reg_core0_mm_trace1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_mm_trace1_allow:1; - /** reg_core0_mm_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_mm_cpu_bus_mon_allow:1; - /** reg_core0_mm_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_mm_l2mem_mon_allow:1; - /** reg_core0_mm_tcm_mon_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_mm_tcm_mon_allow:1; - /** reg_core0_mm_cache_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_mm_cache_allow:1; + /** coren_mm_trace0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_trace0_allow:1; + /** coren_mm_trace1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_trace1_allow:1; + /** coren_mm_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access CPU bus + * monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_cpu_bus_mon_allow:1; + /** coren_mm_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_l2mem_mon_allow:1; + /** coren_mm_tcm_mon_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_tcm_mon_allow:1; + /** coren_mm_cache_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_cache_allow:1; uint32_t reserved_12:20; }; uint32_t val; -} tee_core0_mm_pms_reg0_reg_t; - +} pms_coren_mm_hp_peri_pms_reg0_reg_t; -/** Group: TEE CORE0 MM PMS REG1 REG */ -/** Type of core0_mm_pms_reg1 register - * NA +/** Type of coren_mm_hp_peri_pms_reg1 register + * Permission control register1 for HP CPUn in machine mode */ typedef union { struct { - /** reg_core0_mm_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_usbotg_allow:1; - /** reg_core0_mm_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_usbotg11_allow:1; - /** reg_core0_mm_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_usbotg11_wrap_allow:1; - /** reg_core0_mm_hp_gdma_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_gdma_allow:1; - /** reg_core0_mm_hp_regdma_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_regdma_allow:1; - /** reg_core0_mm_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_sdmmc_allow:1; - /** reg_core0_mm_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_ahb_pdma_allow:1; - /** reg_core0_mm_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_jpeg_allow:1; - /** reg_core0_mm_hp_ppa_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_ppa_allow:1; - /** reg_core0_mm_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_dma2d_allow:1; - /** reg_core0_mm_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_key_manager_allow:1; - /** reg_core0_mm_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_axi_pdma_allow:1; - /** reg_core0_mm_hp_flash_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_flash_allow:1; - /** reg_core0_mm_hp_psram_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_psram_allow:1; - /** reg_core0_mm_hp_crypto_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_crypto_allow:1; - /** reg_core0_mm_hp_gmac_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_gmac_allow:1; - /** reg_core0_mm_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_usb_phy_allow:1; - /** reg_core0_mm_hp_pvt_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_pvt_allow:1; - /** reg_core0_mm_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_csi_host_allow:1; - /** reg_core0_mm_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_dsi_host_allow:1; - /** reg_core0_mm_hp_isp_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_isp_allow:1; - /** reg_core0_mm_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_h264_core_allow:1; - /** reg_core0_mm_hp_rmt_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_rmt_allow:1; - /** reg_core0_mm_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_bitsrambler_allow:1; - /** reg_core0_mm_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_axi_icm_allow:1; - /** reg_core0_mm_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_peri_pms_allow:1; - /** reg_core0_mm_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core0_mm_lp2hp_peri_pms_allow:1; - /** reg_core0_mm_dma_pms_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core0_mm_dma_pms_allow:1; - /** reg_core0_mm_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_h264_dma2d_allow:1; + /** coren_mm_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP high-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_usbotg_allow:1; + /** coren_mm_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP full-speed + * USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_usbotg11_allow:1; + /** coren_mm_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP full-speed + * USB 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_usbotg11_wrap_allow:1; + /** coren_mm_hp_gdma_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_gdma_allow:1; + /** coren_mm_hp_regdma_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP GDMA (DW + * GDMA). + * 0: Not allowed + * 1: Allow + */ + uint32_t coren_mm_hp_regdma_allow:1; + /** coren_mm_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_sdmmc_allow:1; + /** coren_mm_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_ahb_pdma_allow:1; + /** coren_mm_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_jpeg_allow:1; + /** coren_mm_hp_ppa_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_ppa_allow:1; + /** coren_mm_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_dma2d_allow:1; + /** coren_mm_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_key_manager_allow:1; + /** coren_mm_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_axi_pdma_allow:1; + /** coren_mm_hp_flash_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_flash_allow:1; + /** coren_mm_hp_psram_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_psram_allow:1; + /** coren_mm_hp_crypto_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP CRYPTO + * (including AES/SHA/RSA/HMAC Accelerators). + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_crypto_allow:1; + /** coren_mm_hp_gmac_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_gmac_allow:1; + /** coren_mm_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP high-speed + * USB 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_usb_phy_allow:1; + /** coren_mm_hp_pvt_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ + uint32_t coren_mm_hp_pvt_allow:1; + /** coren_mm_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP MIPI CSI + * host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_csi_host_allow:1; + /** coren_mm_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP MIPI DSI + * host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_dsi_host_allow:1; + /** coren_mm_hp_isp_allow : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP ISP (Image + * Signal Processor). + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_isp_allow:1; + /** coren_mm_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP H264 + * Encoder. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_h264_core_allow:1; + /** coren_mm_hp_rmt_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_rmt_allow:1; + /** coren_mm_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP bit + * scrambler. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_bitsrambler_allow:1; + /** coren_mm_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_axi_icm_allow:1; + /** coren_mm_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access + * HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_peri_pms_allow:1; + /** coren_mm_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_lp2hp_peri_pms_allow:1; + /** coren_mm_dma_pms_allow : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_dma_pms_allow:1; + /** coren_mm_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_h264_dma2d_allow:1; uint32_t reserved_29:3; }; uint32_t val; -} tee_core0_mm_pms_reg1_reg_t; - +} pms_coren_mm_hp_peri_pms_reg1_reg_t; -/** Group: TEE CORE0 MM PMS REG2 REG */ -/** Type of core0_mm_pms_reg2 register - * NA +/** Type of coren_mm_hp_peri_pms_reg2 register + * Permission control register2 for HP CPUn in machine mode */ typedef union { struct { - /** reg_core0_mm_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_mcpwm0_allow:1; - /** reg_core0_mm_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_mcpwm1_allow:1; - /** reg_core0_mm_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_timer_group0_allow:1; - /** reg_core0_mm_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_timer_group1_allow:1; - /** reg_core0_mm_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i2c0_allow:1; - /** reg_core0_mm_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i2c1_allow:1; - /** reg_core0_mm_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i2s0_allow:1; - /** reg_core0_mm_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i2s1_allow:1; - /** reg_core0_mm_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i2s2_allow:1; - /** reg_core0_mm_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_pcnt_allow:1; - /** reg_core0_mm_hp_uart0_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uart0_allow:1; - /** reg_core0_mm_hp_uart1_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uart1_allow:1; - /** reg_core0_mm_hp_uart2_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uart2_allow:1; - /** reg_core0_mm_hp_uart3_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uart3_allow:1; - /** reg_core0_mm_hp_uart4_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uart4_allow:1; - /** reg_core0_mm_hp_parlio_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_parlio_allow:1; - /** reg_core0_mm_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_gpspi2_allow:1; - /** reg_core0_mm_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_gpspi3_allow:1; - /** reg_core0_mm_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_usbdevice_allow:1; - /** reg_core0_mm_hp_ledc_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_ledc_allow:1; + /** coren_mm_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_mcpwm0_allow:1; + /** coren_mm_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_mcpwm1_allow:1; + /** coren_mm_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP timer + * group0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_timer_group0_allow:1; + /** coren_mm_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_timer_group1_allow:1; + /** coren_mm_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i2c0_allow:1; + /** coren_mm_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i2c1_allow:1; + /** coren_mm_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i2s0_allow:1; + /** coren_mm_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i2s1_allow:1; + /** coren_mm_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i2s2_allow:1; + /** coren_mm_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_pcnt_allow:1; + /** coren_mm_hp_uart0_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uart0_allow:1; + /** coren_mm_hp_uart1_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uart1_allow:1; + /** coren_mm_hp_uart2_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uart2_allow:1; + /** coren_mm_hp_uart3_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uart3_allow:1; + /** coren_mm_hp_uart4_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uart4_allow:1; + /** coren_mm_hp_parlio_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_parlio_allow:1; + /** coren_mm_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_gpspi2_allow:1; + /** coren_mm_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_gpspi3_allow:1; + /** coren_mm_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP USB + * Serial/JTAG Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_usbdevice_allow:1; + /** coren_mm_hp_ledc_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_ledc_allow:1; uint32_t reserved_20:1; - /** reg_core0_mm_hp_etm_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_etm_allow:1; - /** reg_core0_mm_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_intrmtx_allow:1; - /** reg_core0_mm_hp_twai0_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_twai0_allow:1; - /** reg_core0_mm_hp_twai1_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_twai1_allow:1; - /** reg_core0_mm_hp_twai2_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_twai2_allow:1; - /** reg_core0_mm_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i3c_mst_allow:1; - /** reg_core0_mm_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_i3c_slv_allow:1; - /** reg_core0_mm_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_lcdcam_allow:1; + /** coren_mm_hp_etm_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP ETM (Event + * Task Matrix). + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_etm_allow:1; + /** coren_mm_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_intrmtx_allow:1; + /** coren_mm_hp_twai0_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_twai0_allow:1; + /** coren_mm_hp_twai1_allow : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_twai1_allow:1; + /** coren_mm_hp_twai2_allow : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_twai2_allow:1; + /** coren_mm_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i3c_mst_allow:1; + /** coren_mm_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_i3c_slv_allow:1; + /** coren_mm_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_lcdcam_allow:1; uint32_t reserved_29:1; - /** reg_core0_mm_hp_adc_allow : R/W; bitpos: [30]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_adc_allow:1; - /** reg_core0_mm_hp_uhci_allow : R/W; bitpos: [31]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_uhci_allow:1; + /** coren_mm_hp_adc_allow : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_adc_allow:1; + /** coren_mm_hp_uhci_allow : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_uhci_allow:1; }; uint32_t val; -} tee_core0_mm_pms_reg2_reg_t; - +} pms_coren_mm_hp_peri_pms_reg2_reg_t; -/** Group: TEE CORE0 MM PMS REG3 REG */ -/** Type of core0_mm_pms_reg3 register - * NA +/** Type of coren_mm_hp_peri_pms_reg3 register + * Permission control register3 for HP CPUn in machine mode */ typedef union { struct { - /** reg_core0_mm_hp_gpio_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_gpio_allow:1; - /** reg_core0_mm_hp_iomux_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_iomux_allow:1; - /** reg_core0_mm_hp_systimer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_systimer_allow:1; - /** reg_core0_mm_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_sys_reg_allow:1; - /** reg_core0_mm_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_mm_hp_clkrst_allow:1; + /** coren_mm_hp_gpio_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_gpio_allow:1; + /** coren_mm_hp_iomux_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_iomux_allow:1; + /** coren_mm_hp_systimer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP system + * timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_systimer_allow:1; + /** coren_mm_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_sys_reg_allow:1; + /** coren_mm_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in machine mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_mm_hp_clkrst_allow:1; uint32_t reserved_5:27; }; uint32_t val; -} tee_core0_mm_pms_reg3_reg_t; - +} pms_coren_mm_hp_peri_pms_reg3_reg_t; -/** Group: TEE CORE0 UM PMS REG0 REG */ -/** Type of core0_um_pms_reg0 register - * NA +/** Type of coren_um_hp_peri_pms_reg0 register + * Permission control register0 for HP CPUn in user mode */ typedef union { struct { - /** reg_core0_um_psram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_um_psram_allow:1; - /** reg_core0_um_flash_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_um_flash_allow:1; - /** reg_core0_um_l2mem_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_um_l2mem_allow:1; - /** reg_core0_um_l2rom_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_um_l2rom_allow:1; + /** coren_um_psram_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in user mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_psram_allow:1; + /** coren_um_flash_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in user mode has permission to access external flash + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_flash_allow:1; + /** coren_um_l2mem_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP L2MEM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_l2mem_allow:1; + /** coren_um_l2rom_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP ROM without + * going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_l2rom_allow:1; uint32_t reserved_4:2; - /** reg_core0_um_trace0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_um_trace0_allow:1; - /** reg_core0_um_trace1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_um_trace1_allow:1; - /** reg_core0_um_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_um_cpu_bus_mon_allow:1; - /** reg_core0_um_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_um_l2mem_mon_allow:1; - /** reg_core0_um_tcm_mon_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_um_tcm_mon_allow:1; - /** reg_core0_um_cache_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_um_cache_allow:1; + /** coren_um_trace0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in user mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_trace0_allow:1; + /** coren_um_trace1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in user mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_trace1_allow:1; + /** coren_um_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in user mode has permission to access CPU bus monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_cpu_bus_mon_allow:1; + /** coren_um_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in user mode has permission to access L2MEM monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_l2mem_mon_allow:1; + /** coren_um_tcm_mon_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in user mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_tcm_mon_allow:1; + /** coren_um_cache_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in user mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_cache_allow:1; uint32_t reserved_12:20; }; uint32_t val; -} tee_core0_um_pms_reg0_reg_t; +} pms_coren_um_hp_peri_pms_reg0_reg_t; - -/** Group: TEE CORE0 UM PMS REG1 REG */ -/** Type of core0_um_pms_reg1 register - * NA +/** Type of coren_um_hp_peri_pms_reg1 register + * Permission control register1 for HP CPUn in user mode */ typedef union { struct { - /** reg_core0_um_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_usbotg_allow:1; - /** reg_core0_um_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_usbotg11_allow:1; - /** reg_core0_um_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_usbotg11_wrap_allow:1; - /** reg_core0_um_hp_gdma_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_gdma_allow:1; - /** reg_core0_um_hp_regdma_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_regdma_allow:1; - /** reg_core0_um_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_sdmmc_allow:1; - /** reg_core0_um_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_ahb_pdma_allow:1; - /** reg_core0_um_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_jpeg_allow:1; - /** reg_core0_um_hp_ppa_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_ppa_allow:1; - /** reg_core0_um_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_dma2d_allow:1; - /** reg_core0_um_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_key_manager_allow:1; - /** reg_core0_um_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_axi_pdma_allow:1; - /** reg_core0_um_hp_flash_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_flash_allow:1; - /** reg_core0_um_hp_psram_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_psram_allow:1; - /** reg_core0_um_hp_crypto_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_crypto_allow:1; - /** reg_core0_um_hp_gmac_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_gmac_allow:1; - /** reg_core0_um_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_usb_phy_allow:1; - /** reg_core0_um_hp_pvt_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_pvt_allow:1; - /** reg_core0_um_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_csi_host_allow:1; - /** reg_core0_um_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_dsi_host_allow:1; - /** reg_core0_um_hp_isp_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_isp_allow:1; - /** reg_core0_um_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_h264_core_allow:1; - /** reg_core0_um_hp_rmt_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_rmt_allow:1; - /** reg_core0_um_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_bitsrambler_allow:1; - /** reg_core0_um_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_axi_icm_allow:1; - /** reg_core0_um_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_peri_pms_allow:1; - /** reg_core0_um_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core0_um_lp2hp_peri_pms_allow:1; - /** reg_core0_um_dma_pms_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core0_um_dma_pms_allow:1; - /** reg_core0_um_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_h264_dma2d_allow:1; + /** coren_um_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP high-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_usbotg_allow:1; + /** coren_um_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP full-speed USB + * 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_usbotg11_allow:1; + /** coren_um_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP full-speed USB + * 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_usbotg11_wrap_allow:1; + /** coren_um_hp_gdma_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_gdma_allow:1; + /** coren_um_hp_regdma_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP regdma. + * 0: Not allowed + * 1: Allow + */ + uint32_t coren_um_hp_regdma_allow:1; + /** coren_um_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_sdmmc_allow:1; + /** coren_um_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in user mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_ahb_pdma_allow:1; + /** coren_um_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_jpeg_allow:1; + /** coren_um_hp_ppa_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_ppa_allow:1; + /** coren_um_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_dma2d_allow:1; + /** coren_um_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP key manager. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_key_manager_allow:1; + /** coren_um_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_axi_pdma_allow:1; + /** coren_um_hp_flash_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP flash MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_flash_allow:1; + /** coren_um_hp_psram_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP PSRAM MSPI + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_psram_allow:1; + /** coren_um_hp_crypto_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP CRYPTO. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_crypto_allow:1; + /** coren_um_hp_gmac_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_gmac_allow:1; + /** coren_um_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP high-speed USB + * 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_usb_phy_allow:1; + /** coren_um_hp_pvt_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ + uint32_t coren_um_hp_pvt_allow:1; + /** coren_um_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP MIPI CSI host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_csi_host_allow:1; + /** coren_um_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP MIPI DSI host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_dsi_host_allow:1; + /** coren_um_hp_isp_allow : R/W; bitpos: [20]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP ISP. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_isp_allow:1; + /** coren_um_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP H264 Encoder. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_h264_core_allow:1; + /** coren_um_hp_rmt_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_rmt_allow:1; + /** coren_um_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP bit scrambler. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_bitsrambler_allow:1; + /** coren_um_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_axi_icm_allow:1; + /** coren_um_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_peri_pms_allow:1; + /** coren_um_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPUn in user mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_lp2hp_peri_pms_allow:1; + /** coren_um_dma_pms_allow : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_dma_pms_allow:1; + /** coren_um_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPUn in user mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_h264_dma2d_allow:1; uint32_t reserved_29:3; }; uint32_t val; -} tee_core0_um_pms_reg1_reg_t; - +} pms_coren_um_hp_peri_pms_reg1_reg_t; -/** Group: TEE CORE0 UM PMS REG2 REG */ -/** Type of core0_um_pms_reg2 register - * NA +/** Type of coren_um_hp_peri_pms_reg2 register + * Permission control register2 for HP CPUn in user mode */ typedef union { struct { - /** reg_core0_um_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_mcpwm0_allow:1; - /** reg_core0_um_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_mcpwm1_allow:1; - /** reg_core0_um_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_timer_group0_allow:1; - /** reg_core0_um_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_timer_group1_allow:1; - /** reg_core0_um_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i2c0_allow:1; - /** reg_core0_um_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i2c1_allow:1; - /** reg_core0_um_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i2s0_allow:1; - /** reg_core0_um_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i2s1_allow:1; - /** reg_core0_um_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i2s2_allow:1; - /** reg_core0_um_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_pcnt_allow:1; - /** reg_core0_um_hp_uart0_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uart0_allow:1; - /** reg_core0_um_hp_uart1_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uart1_allow:1; - /** reg_core0_um_hp_uart2_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uart2_allow:1; - /** reg_core0_um_hp_uart3_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uart3_allow:1; - /** reg_core0_um_hp_uart4_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uart4_allow:1; - /** reg_core0_um_hp_parlio_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_parlio_allow:1; - /** reg_core0_um_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_gpspi2_allow:1; - /** reg_core0_um_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_gpspi3_allow:1; - /** reg_core0_um_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_usbdevice_allow:1; - /** reg_core0_um_hp_ledc_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_ledc_allow:1; + /** coren_um_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_mcpwm0_allow:1; + /** coren_um_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_mcpwm1_allow:1; + /** coren_um_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP timer group0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_timer_group0_allow:1; + /** coren_um_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP timer group1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_timer_group1_allow:1; + /** coren_um_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i2c0_allow:1; + /** coren_um_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i2c1_allow:1; + /** coren_um_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i2s0_allow:1; + /** coren_um_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i2s1_allow:1; + /** coren_um_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i2s2_allow:1; + /** coren_um_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_pcnt_allow:1; + /** coren_um_hp_uart0_allow : R/W; bitpos: [10]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uart0_allow:1; + /** coren_um_hp_uart1_allow : R/W; bitpos: [11]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uart1_allow:1; + /** coren_um_hp_uart2_allow : R/W; bitpos: [12]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uart2_allow:1; + /** coren_um_hp_uart3_allow : R/W; bitpos: [13]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uart3_allow:1; + /** coren_um_hp_uart4_allow : R/W; bitpos: [14]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uart4_allow:1; + /** coren_um_hp_parlio_allow : R/W; bitpos: [15]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_parlio_allow:1; + /** coren_um_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_gpspi2_allow:1; + /** coren_um_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_gpspi3_allow:1; + /** coren_um_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP USB/Serial JTAG + * Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_usbdevice_allow:1; + /** coren_um_hp_ledc_allow : R/W; bitpos: [19]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_ledc_allow:1; uint32_t reserved_20:1; - /** reg_core0_um_hp_etm_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_etm_allow:1; - /** reg_core0_um_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_intrmtx_allow:1; - /** reg_core0_um_hp_twai0_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_twai0_allow:1; - /** reg_core0_um_hp_twai1_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_twai1_allow:1; - /** reg_core0_um_hp_twai2_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_twai2_allow:1; - /** reg_core0_um_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i3c_mst_allow:1; - /** reg_core0_um_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_i3c_slv_allow:1; - /** reg_core0_um_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_lcdcam_allow:1; + /** coren_um_hp_etm_allow : R/W; bitpos: [21]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP ETM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_etm_allow:1; + /** coren_um_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_intrmtx_allow:1; + /** coren_um_hp_twai0_allow : R/W; bitpos: [23]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_twai0_allow:1; + /** coren_um_hp_twai1_allow : R/W; bitpos: [24]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_twai1_allow:1; + /** coren_um_hp_twai2_allow : R/W; bitpos: [25]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_twai2_allow:1; + /** coren_um_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I3C master + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i3c_mst_allow:1; + /** coren_um_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_i3c_slv_allow:1; + /** coren_um_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_lcdcam_allow:1; uint32_t reserved_29:1; - /** reg_core0_um_hp_adc_allow : R/W; bitpos: [30]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_adc_allow:1; - /** reg_core0_um_hp_uhci_allow : R/W; bitpos: [31]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_uhci_allow:1; - }; - uint32_t val; -} tee_core0_um_pms_reg2_reg_t; - - -/** Group: TEE CORE0 UM PMS REG3 REG */ -/** Type of core0_um_pms_reg3 register - * NA - */ -typedef union { - struct { - /** reg_core0_um_hp_gpio_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_gpio_allow:1; - /** reg_core0_um_hp_iomux_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_iomux_allow:1; - /** reg_core0_um_hp_systimer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_systimer_allow:1; - /** reg_core0_um_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_sys_reg_allow:1; - /** reg_core0_um_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core0_um_hp_clkrst_allow:1; - uint32_t reserved_5:27; - }; - uint32_t val; -} tee_core0_um_pms_reg3_reg_t; - - -/** Group: TEE CORE1 MM PMS REG0 REG */ -/** Type of core1_mm_pms_reg0 register - * NA - */ -typedef union { - struct { - /** reg_core1_mm_psram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_mm_psram_allow:1; - /** reg_core1_mm_flash_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_mm_flash_allow:1; - /** reg_core1_mm_l2mem_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_mm_l2mem_allow:1; - /** reg_core1_mm_l2rom_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_mm_l2rom_allow:1; - uint32_t reserved_4:2; - /** reg_core1_mm_trace0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_mm_trace0_allow:1; - /** reg_core1_mm_trace1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_mm_trace1_allow:1; - /** reg_core1_mm_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_mm_cpu_bus_mon_allow:1; - /** reg_core1_mm_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_mm_l2mem_mon_allow:1; - /** reg_core1_mm_tcm_mon_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_mm_tcm_mon_allow:1; - /** reg_core1_mm_cache_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_mm_cache_allow:1; - uint32_t reserved_12:20; + /** coren_um_hp_adc_allow : R/W; bitpos: [30]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_adc_allow:1; + /** coren_um_hp_uhci_allow : R/W; bitpos: [31]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_uhci_allow:1; }; uint32_t val; -} tee_core1_mm_pms_reg0_reg_t; +} pms_coren_um_hp_peri_pms_reg2_reg_t; - -/** Group: TEE CORE1 MM PMS REG1 REG */ -/** Type of core1_mm_pms_reg1 register - * NA +/** Type of coren_um_hp_peri_pms_reg3 register + * Permission control register3 for HP CPUn in user mode */ typedef union { struct { - /** reg_core1_mm_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_usbotg_allow:1; - /** reg_core1_mm_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_usbotg11_allow:1; - /** reg_core1_mm_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_usbotg11_wrap_allow:1; - /** reg_core1_mm_hp_gdma_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_gdma_allow:1; - /** reg_core1_mm_hp_regdma_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_regdma_allow:1; - /** reg_core1_mm_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_sdmmc_allow:1; - /** reg_core1_mm_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_ahb_pdma_allow:1; - /** reg_core1_mm_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_jpeg_allow:1; - /** reg_core1_mm_hp_ppa_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_ppa_allow:1; - /** reg_core1_mm_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_dma2d_allow:1; - /** reg_core1_mm_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_key_manager_allow:1; - /** reg_core1_mm_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_axi_pdma_allow:1; - /** reg_core1_mm_hp_flash_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_flash_allow:1; - /** reg_core1_mm_hp_psram_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_psram_allow:1; - /** reg_core1_mm_hp_crypto_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_crypto_allow:1; - /** reg_core1_mm_hp_gmac_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_gmac_allow:1; - /** reg_core1_mm_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_usb_phy_allow:1; - /** reg_core1_mm_hp_pvt_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_pvt_allow:1; - /** reg_core1_mm_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_csi_host_allow:1; - /** reg_core1_mm_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_dsi_host_allow:1; - /** reg_core1_mm_hp_isp_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_isp_allow:1; - /** reg_core1_mm_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_h264_core_allow:1; - /** reg_core1_mm_hp_rmt_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_rmt_allow:1; - /** reg_core1_mm_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_bitsrambler_allow:1; - /** reg_core1_mm_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_axi_icm_allow:1; - /** reg_core1_mm_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_peri_pms_allow:1; - /** reg_core1_mm_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core1_mm_lp2hp_peri_pms_allow:1; - /** reg_core1_mm_dma_pms_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core1_mm_dma_pms_allow:1; - /** reg_core1_mm_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_h264_dma2d_allow:1; - uint32_t reserved_29:3; - }; - uint32_t val; -} tee_core1_mm_pms_reg1_reg_t; - - -/** Group: TEE CORE1 MM PMS REG2 REG */ -/** Type of core1_mm_pms_reg2 register - * NA - */ -typedef union { - struct { - /** reg_core1_mm_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_mcpwm0_allow:1; - /** reg_core1_mm_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_mcpwm1_allow:1; - /** reg_core1_mm_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_timer_group0_allow:1; - /** reg_core1_mm_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_timer_group1_allow:1; - /** reg_core1_mm_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i2c0_allow:1; - /** reg_core1_mm_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i2c1_allow:1; - /** reg_core1_mm_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i2s0_allow:1; - /** reg_core1_mm_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i2s1_allow:1; - /** reg_core1_mm_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i2s2_allow:1; - /** reg_core1_mm_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_pcnt_allow:1; - /** reg_core1_mm_hp_uart0_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uart0_allow:1; - /** reg_core1_mm_hp_uart1_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uart1_allow:1; - /** reg_core1_mm_hp_uart2_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uart2_allow:1; - /** reg_core1_mm_hp_uart3_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uart3_allow:1; - /** reg_core1_mm_hp_uart4_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uart4_allow:1; - /** reg_core1_mm_hp_parlio_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_parlio_allow:1; - /** reg_core1_mm_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_gpspi2_allow:1; - /** reg_core1_mm_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_gpspi3_allow:1; - /** reg_core1_mm_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_usbdevice_allow:1; - /** reg_core1_mm_hp_ledc_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_ledc_allow:1; - uint32_t reserved_20:1; - /** reg_core1_mm_hp_etm_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_etm_allow:1; - /** reg_core1_mm_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_intrmtx_allow:1; - /** reg_core1_mm_hp_twai0_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_twai0_allow:1; - /** reg_core1_mm_hp_twai1_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_twai1_allow:1; - /** reg_core1_mm_hp_twai2_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_twai2_allow:1; - /** reg_core1_mm_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i3c_mst_allow:1; - /** reg_core1_mm_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_i3c_slv_allow:1; - /** reg_core1_mm_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_lcdcam_allow:1; - uint32_t reserved_29:1; - /** reg_core1_mm_hp_adc_allow : R/W; bitpos: [30]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_adc_allow:1; - /** reg_core1_mm_hp_uhci_allow : R/W; bitpos: [31]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_uhci_allow:1; - }; - uint32_t val; -} tee_core1_mm_pms_reg2_reg_t; - - -/** Group: TEE CORE1 MM PMS REG3 REG */ -/** Type of core1_mm_pms_reg3 register - * NA - */ -typedef union { - struct { - /** reg_core1_mm_hp_gpio_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_gpio_allow:1; - /** reg_core1_mm_hp_iomux_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_iomux_allow:1; - /** reg_core1_mm_hp_systimer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_systimer_allow:1; - /** reg_core1_mm_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_sys_reg_allow:1; - /** reg_core1_mm_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_mm_hp_clkrst_allow:1; - uint32_t reserved_5:27; - }; - uint32_t val; -} tee_core1_mm_pms_reg3_reg_t; - - -/** Group: TEE CORE1 UM PMS REG0 REG */ -/** Type of core1_um_pms_reg0 register - * NA - */ -typedef union { - struct { - /** reg_core1_um_psram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_um_psram_allow:1; - /** reg_core1_um_flash_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_um_flash_allow:1; - /** reg_core1_um_l2mem_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_um_l2mem_allow:1; - /** reg_core1_um_l2rom_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_um_l2rom_allow:1; - uint32_t reserved_4:2; - /** reg_core1_um_trace0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_um_trace0_allow:1; - /** reg_core1_um_trace1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_um_trace1_allow:1; - /** reg_core1_um_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_um_cpu_bus_mon_allow:1; - /** reg_core1_um_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_um_l2mem_mon_allow:1; - /** reg_core1_um_tcm_mon_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_um_tcm_mon_allow:1; - /** reg_core1_um_cache_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_um_cache_allow:1; - uint32_t reserved_12:20; - }; - uint32_t val; -} tee_core1_um_pms_reg0_reg_t; - - -/** Group: TEE CORE1 UM PMS REG1 REG */ -/** Type of core1_um_pms_reg1 register - * NA - */ -typedef union { - struct { - /** reg_core1_um_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_usbotg_allow:1; - /** reg_core1_um_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_usbotg11_allow:1; - /** reg_core1_um_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_usbotg11_wrap_allow:1; - /** reg_core1_um_hp_gdma_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_gdma_allow:1; - /** reg_core1_um_hp_regdma_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_regdma_allow:1; - /** reg_core1_um_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_sdmmc_allow:1; - /** reg_core1_um_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_ahb_pdma_allow:1; - /** reg_core1_um_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_jpeg_allow:1; - /** reg_core1_um_hp_ppa_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_ppa_allow:1; - /** reg_core1_um_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_dma2d_allow:1; - /** reg_core1_um_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_key_manager_allow:1; - /** reg_core1_um_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_axi_pdma_allow:1; - /** reg_core1_um_hp_flash_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_flash_allow:1; - /** reg_core1_um_hp_psram_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_psram_allow:1; - /** reg_core1_um_hp_crypto_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_crypto_allow:1; - /** reg_core1_um_hp_gmac_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_gmac_allow:1; - /** reg_core1_um_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_usb_phy_allow:1; - /** reg_core1_um_hp_pvt_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_pvt_allow:1; - /** reg_core1_um_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_csi_host_allow:1; - /** reg_core1_um_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_dsi_host_allow:1; - /** reg_core1_um_hp_isp_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_isp_allow:1; - /** reg_core1_um_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_h264_core_allow:1; - /** reg_core1_um_hp_rmt_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_rmt_allow:1; - /** reg_core1_um_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_bitsrambler_allow:1; - /** reg_core1_um_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_axi_icm_allow:1; - /** reg_core1_um_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_peri_pms_allow:1; - /** reg_core1_um_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core1_um_lp2hp_peri_pms_allow:1; - /** reg_core1_um_dma_pms_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core1_um_dma_pms_allow:1; - /** reg_core1_um_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_h264_dma2d_allow:1; - uint32_t reserved_29:3; - }; - uint32_t val; -} tee_core1_um_pms_reg1_reg_t; - - -/** Group: TEE CORE1 UM PMS REG2 REG */ -/** Type of core1_um_pms_reg2 register - * NA - */ -typedef union { - struct { - /** reg_core1_um_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_mcpwm0_allow:1; - /** reg_core1_um_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_mcpwm1_allow:1; - /** reg_core1_um_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_timer_group0_allow:1; - /** reg_core1_um_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_timer_group1_allow:1; - /** reg_core1_um_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i2c0_allow:1; - /** reg_core1_um_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i2c1_allow:1; - /** reg_core1_um_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i2s0_allow:1; - /** reg_core1_um_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i2s1_allow:1; - /** reg_core1_um_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i2s2_allow:1; - /** reg_core1_um_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_pcnt_allow:1; - /** reg_core1_um_hp_uart0_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uart0_allow:1; - /** reg_core1_um_hp_uart1_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uart1_allow:1; - /** reg_core1_um_hp_uart2_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uart2_allow:1; - /** reg_core1_um_hp_uart3_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uart3_allow:1; - /** reg_core1_um_hp_uart4_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uart4_allow:1; - /** reg_core1_um_hp_parlio_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_parlio_allow:1; - /** reg_core1_um_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_gpspi2_allow:1; - /** reg_core1_um_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_gpspi3_allow:1; - /** reg_core1_um_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_usbdevice_allow:1; - /** reg_core1_um_hp_ledc_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_ledc_allow:1; - uint32_t reserved_20:1; - /** reg_core1_um_hp_etm_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_etm_allow:1; - /** reg_core1_um_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_intrmtx_allow:1; - /** reg_core1_um_hp_twai0_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_twai0_allow:1; - /** reg_core1_um_hp_twai1_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_twai1_allow:1; - /** reg_core1_um_hp_twai2_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_twai2_allow:1; - /** reg_core1_um_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i3c_mst_allow:1; - /** reg_core1_um_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_i3c_slv_allow:1; - /** reg_core1_um_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_lcdcam_allow:1; - uint32_t reserved_29:1; - /** reg_core1_um_hp_adc_allow : R/W; bitpos: [30]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_adc_allow:1; - /** reg_core1_um_hp_uhci_allow : R/W; bitpos: [31]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_uhci_allow:1; - }; - uint32_t val; -} tee_core1_um_pms_reg2_reg_t; - - -/** Group: TEE CORE1 UM PMS REG3 REG */ -/** Type of core1_um_pms_reg3 register - * NA - */ -typedef union { - struct { - /** reg_core1_um_hp_gpio_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_gpio_allow:1; - /** reg_core1_um_hp_iomux_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_iomux_allow:1; - /** reg_core1_um_hp_systimer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_systimer_allow:1; - /** reg_core1_um_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_sys_reg_allow:1; - /** reg_core1_um_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_core1_um_hp_clkrst_allow:1; + /** coren_um_hp_gpio_allow : R/W; bitpos: [0]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP GPIO Matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_gpio_allow:1; + /** coren_um_hp_iomux_allow : R/W; bitpos: [1]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_iomux_allow:1; + /** coren_um_hp_systimer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP system timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_systimer_allow:1; + /** coren_um_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_sys_reg_allow:1; + /** coren_um_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; + * Configures whether HP CPUn in user mode has permission to access HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t coren_um_hp_clkrst_allow:1; uint32_t reserved_5:27; }; uint32_t val; -} tee_core1_um_pms_reg3_reg_t; +} pms_coren_um_hp_peri_pms_reg3_reg_t; -/** Group: TEE REGDMA PERI PMS REG */ +/** Group: TEE Peripheral Permission Control Registers */ /** Type of regdma_peri_pms register - * NA + * Permission register for REGDMA */ typedef union { struct { - /** reg_regdma_peri_allow : R/W; bitpos: [0]; default: 1; - * NA + /** regdma_peri_allow : R/W; bitpos: [0]; default: 1; + * Configures whether REGDMA has permission to access all HP peripheral (including CPU + * peripherals). + * 0: Not allowed + * 1: Allow */ - uint32_t reg_regdma_peri_allow:1; + uint32_t regdma_peri_allow:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_regdma_peri_pms_reg_t; +} pms_regdma_peri_pms_reg_t; typedef struct { - volatile tee_pms_date_reg_t pms_date; - volatile tee_pms_clk_en_reg_t pms_clk_en; - volatile tee_core0_mm_pms_reg0_reg_t core0_mm_pms_reg0; - volatile tee_core0_mm_pms_reg1_reg_t core0_mm_pms_reg1; - volatile tee_core0_mm_pms_reg2_reg_t core0_mm_pms_reg2; - volatile tee_core0_mm_pms_reg3_reg_t core0_mm_pms_reg3; - volatile tee_core0_um_pms_reg0_reg_t core0_um_pms_reg0; - volatile tee_core0_um_pms_reg1_reg_t core0_um_pms_reg1; - volatile tee_core0_um_pms_reg2_reg_t core0_um_pms_reg2; - volatile tee_core0_um_pms_reg3_reg_t core0_um_pms_reg3; - volatile tee_core1_mm_pms_reg0_reg_t core1_mm_pms_reg0; - volatile tee_core1_mm_pms_reg1_reg_t core1_mm_pms_reg1; - volatile tee_core1_mm_pms_reg2_reg_t core1_mm_pms_reg2; - volatile tee_core1_mm_pms_reg3_reg_t core1_mm_pms_reg3; - volatile tee_core1_um_pms_reg0_reg_t core1_um_pms_reg0; - volatile tee_core1_um_pms_reg1_reg_t core1_um_pms_reg1; - volatile tee_core1_um_pms_reg2_reg_t core1_um_pms_reg2; - volatile tee_core1_um_pms_reg3_reg_t core1_um_pms_reg3; - volatile tee_regdma_peri_pms_reg_t regdma_peri_pms; -} tee_dev_t; + volatile pms_hp_peri_pms_date_reg_t hp_peri_pms_date; + volatile pms_hp_peri_pms_clk_en_reg_t hp_peri_pms_clk_en; + volatile pms_coren_mm_hp_peri_pms_reg0_reg_t core0_mm_hp_peri_pms_reg0; + volatile pms_coren_mm_hp_peri_pms_reg1_reg_t core0_mm_hp_peri_pms_reg1; + volatile pms_coren_mm_hp_peri_pms_reg2_reg_t core0_mm_hp_peri_pms_reg2; + volatile pms_coren_mm_hp_peri_pms_reg3_reg_t core0_mm_hp_peri_pms_reg3; + volatile pms_coren_um_hp_peri_pms_reg0_reg_t core0_um_hp_peri_pms_reg0; + volatile pms_coren_um_hp_peri_pms_reg1_reg_t core0_um_hp_peri_pms_reg1; + volatile pms_coren_um_hp_peri_pms_reg2_reg_t core0_um_hp_peri_pms_reg2; + volatile pms_coren_um_hp_peri_pms_reg3_reg_t core0_um_hp_peri_pms_reg3; + volatile pms_coren_mm_hp_peri_pms_reg0_reg_t core1_mm_hp_peri_pms_reg0; + volatile pms_coren_mm_hp_peri_pms_reg1_reg_t core1_mm_hp_peri_pms_reg1; + volatile pms_coren_mm_hp_peri_pms_reg2_reg_t core1_mm_hp_peri_pms_reg2; + volatile pms_coren_mm_hp_peri_pms_reg3_reg_t core1_mm_hp_peri_pms_reg3; + volatile pms_coren_um_hp_peri_pms_reg0_reg_t core1_um_hp_peri_pms_reg0; + volatile pms_coren_um_hp_peri_pms_reg1_reg_t core1_um_hp_peri_pms_reg1; + volatile pms_coren_um_hp_peri_pms_reg2_reg_t core1_um_hp_peri_pms_reg2; + volatile pms_coren_um_hp_peri_pms_reg3_reg_t core1_um_hp_peri_pms_reg3; + volatile pms_regdma_peri_pms_reg_t regdma_peri_pms; +} hp_peri_pms_dev_t; +extern hp_peri_pms_dev_t HP_PERI_PMS; #ifndef __cplusplus -_Static_assert(sizeof(tee_dev_t) == 0x4c, "Invalid size of tee_dev_t structure"); +_Static_assert(sizeof(hp_peri_pms_dev_t) == 0x4c, "Invalid size of hp_peri_pms_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h index 57d17419a70..6e115cb7037 100644 --- a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,567 +11,748 @@ extern "C" { #endif -/** TEE_LP2HP_PMS_DATE_REG register - * NA +/** PMS_LP2HP_PERI_PMS_DATE_REG register + * Version control register */ -#define TEE_LP2HP_PMS_DATE_REG (DR_REG_TEE_BASE + 0x0) -/** TEE_TEE_DATE : R/W; bitpos: [31:0]; default: 2294790; - * NA +#define PMS_LP2HP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +/** PMS_LP2HP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294790; + * Version control register. */ -#define TEE_TEE_DATE 0xFFFFFFFFU -#define TEE_TEE_DATE_M (TEE_TEE_DATE_V << TEE_TEE_DATE_S) -#define TEE_TEE_DATE_V 0xFFFFFFFFU -#define TEE_TEE_DATE_S 0 +#define PMS_LP2HP_PERI_PMS_DATE 0xFFFFFFFFU +#define PMS_LP2HP_PERI_PMS_DATE_M (PMS_LP2HP_PERI_PMS_DATE_V << PMS_LP2HP_PERI_PMS_DATE_S) +#define PMS_LP2HP_PERI_PMS_DATE_V 0xFFFFFFFFU +#define PMS_LP2HP_PERI_PMS_DATE_S 0 -/** TEE_PMS_CLK_EN_REG register - * NA - */ -#define TEE_PMS_CLK_EN_REG (DR_REG_TEE_BASE + 0x4) -/** TEE_REG_CLK_EN : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CLK_EN (BIT(0)) -#define TEE_REG_CLK_EN_M (TEE_REG_CLK_EN_V << TEE_REG_CLK_EN_S) -#define TEE_REG_CLK_EN_V 0x00000001U -#define TEE_REG_CLK_EN_S 0 +/** PMS_LP2HP_PERI_PMS_CLK_EN_REG register + * Clock gating register + */ +#define PMS_LP2HP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +/** PMS_LP2HP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating. + * 1: Keep the clock always on. + */ +#define PMS_LP2HP_PERI_PMS_CLK_EN (BIT(0)) +#define PMS_LP2HP_PERI_PMS_CLK_EN_M (PMS_LP2HP_PERI_PMS_CLK_EN_V << PMS_LP2HP_PERI_PMS_CLK_EN_S) +#define PMS_LP2HP_PERI_PMS_CLK_EN_V 0x00000001U +#define PMS_LP2HP_PERI_PMS_CLK_EN_S 0 -/** TEE_LP_MM_PMS_REG0_REG register - * NA - */ -#define TEE_LP_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x8) -/** TEE_REG_LP_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_PSRAM_ALLOW (BIT(0)) -#define TEE_REG_LP_MM_PSRAM_ALLOW_M (TEE_REG_LP_MM_PSRAM_ALLOW_V << TEE_REG_LP_MM_PSRAM_ALLOW_S) -#define TEE_REG_LP_MM_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_PSRAM_ALLOW_S 0 -/** TEE_REG_LP_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_FLASH_ALLOW (BIT(1)) -#define TEE_REG_LP_MM_FLASH_ALLOW_M (TEE_REG_LP_MM_FLASH_ALLOW_V << TEE_REG_LP_MM_FLASH_ALLOW_S) -#define TEE_REG_LP_MM_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_FLASH_ALLOW_S 1 -/** TEE_REG_LP_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_L2MEM_ALLOW (BIT(2)) -#define TEE_REG_LP_MM_L2MEM_ALLOW_M (TEE_REG_LP_MM_L2MEM_ALLOW_V << TEE_REG_LP_MM_L2MEM_ALLOW_S) -#define TEE_REG_LP_MM_L2MEM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_L2MEM_ALLOW_S 2 -/** TEE_REG_LP_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_L2ROM_ALLOW (BIT(3)) -#define TEE_REG_LP_MM_L2ROM_ALLOW_M (TEE_REG_LP_MM_L2ROM_ALLOW_V << TEE_REG_LP_MM_L2ROM_ALLOW_S) -#define TEE_REG_LP_MM_L2ROM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_L2ROM_ALLOW_S 3 -/** TEE_REG_LP_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_TRACE0_ALLOW (BIT(6)) -#define TEE_REG_LP_MM_TRACE0_ALLOW_M (TEE_REG_LP_MM_TRACE0_ALLOW_V << TEE_REG_LP_MM_TRACE0_ALLOW_S) -#define TEE_REG_LP_MM_TRACE0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_TRACE0_ALLOW_S 6 -/** TEE_REG_LP_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_TRACE1_ALLOW (BIT(7)) -#define TEE_REG_LP_MM_TRACE1_ALLOW_M (TEE_REG_LP_MM_TRACE1_ALLOW_V << TEE_REG_LP_MM_TRACE1_ALLOW_S) -#define TEE_REG_LP_MM_TRACE1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_TRACE1_ALLOW_S 7 -/** TEE_REG_LP_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_CPU_BUS_MON_ALLOW (BIT(8)) -#define TEE_REG_LP_MM_CPU_BUS_MON_ALLOW_M (TEE_REG_LP_MM_CPU_BUS_MON_ALLOW_V << TEE_REG_LP_MM_CPU_BUS_MON_ALLOW_S) -#define TEE_REG_LP_MM_CPU_BUS_MON_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_CPU_BUS_MON_ALLOW_S 8 -/** TEE_REG_LP_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_L2MEM_MON_ALLOW (BIT(9)) -#define TEE_REG_LP_MM_L2MEM_MON_ALLOW_M (TEE_REG_LP_MM_L2MEM_MON_ALLOW_V << TEE_REG_LP_MM_L2MEM_MON_ALLOW_S) -#define TEE_REG_LP_MM_L2MEM_MON_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_L2MEM_MON_ALLOW_S 9 -/** TEE_REG_LP_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_TCM_MON_ALLOW (BIT(10)) -#define TEE_REG_LP_MM_TCM_MON_ALLOW_M (TEE_REG_LP_MM_TCM_MON_ALLOW_V << TEE_REG_LP_MM_TCM_MON_ALLOW_S) -#define TEE_REG_LP_MM_TCM_MON_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_TCM_MON_ALLOW_S 10 -/** TEE_REG_LP_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_CACHE_ALLOW (BIT(11)) -#define TEE_REG_LP_MM_CACHE_ALLOW_M (TEE_REG_LP_MM_CACHE_ALLOW_V << TEE_REG_LP_MM_CACHE_ALLOW_S) -#define TEE_REG_LP_MM_CACHE_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_CACHE_ALLOW_S 11 +/** PMS_LP_MM_PMS_REG0_REG register + * Permission control register0 for the LP CPU in machine mode + */ +#define PMS_LP_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +/** PMS_LP_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_PSRAM_ALLOW (BIT(0)) +#define PMS_LP_MM_PSRAM_ALLOW_M (PMS_LP_MM_PSRAM_ALLOW_V << PMS_LP_MM_PSRAM_ALLOW_S) +#define PMS_LP_MM_PSRAM_ALLOW_V 0x00000001U +#define PMS_LP_MM_PSRAM_ALLOW_S 0 +/** PMS_LP_MM_FLASH_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access external + * flash without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_FLASH_ALLOW (BIT(1)) +#define PMS_LP_MM_FLASH_ALLOW_M (PMS_LP_MM_FLASH_ALLOW_V << PMS_LP_MM_FLASH_ALLOW_S) +#define PMS_LP_MM_FLASH_ALLOW_V 0x00000001U +#define PMS_LP_MM_FLASH_ALLOW_S 1 +/** PMS_LP_MM_L2MEM_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP L2M2M + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_L2MEM_ALLOW (BIT(2)) +#define PMS_LP_MM_L2MEM_ALLOW_M (PMS_LP_MM_L2MEM_ALLOW_V << PMS_LP_MM_L2MEM_ALLOW_S) +#define PMS_LP_MM_L2MEM_ALLOW_V 0x00000001U +#define PMS_LP_MM_L2MEM_ALLOW_S 2 +/** PMS_LP_MM_L2ROM_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ROM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_L2ROM_ALLOW (BIT(3)) +#define PMS_LP_MM_L2ROM_ALLOW_M (PMS_LP_MM_L2ROM_ALLOW_V << PMS_LP_MM_L2ROM_ALLOW_S) +#define PMS_LP_MM_L2ROM_ALLOW_V 0x00000001U +#define PMS_LP_MM_L2ROM_ALLOW_S 3 +/** PMS_LP_MM_TRACE0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_TRACE0_ALLOW (BIT(6)) +#define PMS_LP_MM_TRACE0_ALLOW_M (PMS_LP_MM_TRACE0_ALLOW_V << PMS_LP_MM_TRACE0_ALLOW_S) +#define PMS_LP_MM_TRACE0_ALLOW_V 0x00000001U +#define PMS_LP_MM_TRACE0_ALLOW_S 6 +/** PMS_LP_MM_TRACE1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_TRACE1_ALLOW (BIT(7)) +#define PMS_LP_MM_TRACE1_ALLOW_M (PMS_LP_MM_TRACE1_ALLOW_V << PMS_LP_MM_TRACE1_ALLOW_S) +#define PMS_LP_MM_TRACE1_ALLOW_V 0x00000001U +#define PMS_LP_MM_TRACE1_ALLOW_S 7 +/** PMS_LP_MM_CPU_BUS_MON_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access CPU bus + * monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_CPU_BUS_MON_ALLOW (BIT(8)) +#define PMS_LP_MM_CPU_BUS_MON_ALLOW_M (PMS_LP_MM_CPU_BUS_MON_ALLOW_V << PMS_LP_MM_CPU_BUS_MON_ALLOW_S) +#define PMS_LP_MM_CPU_BUS_MON_ALLOW_V 0x00000001U +#define PMS_LP_MM_CPU_BUS_MON_ALLOW_S 8 +/** PMS_LP_MM_L2MEM_MON_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access L2MEM + * monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_L2MEM_MON_ALLOW (BIT(9)) +#define PMS_LP_MM_L2MEM_MON_ALLOW_M (PMS_LP_MM_L2MEM_MON_ALLOW_V << PMS_LP_MM_L2MEM_MON_ALLOW_S) +#define PMS_LP_MM_L2MEM_MON_ALLOW_V 0x00000001U +#define PMS_LP_MM_L2MEM_MON_ALLOW_S 9 +/** PMS_LP_MM_TCM_MON_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_TCM_MON_ALLOW (BIT(10)) +#define PMS_LP_MM_TCM_MON_ALLOW_M (PMS_LP_MM_TCM_MON_ALLOW_V << PMS_LP_MM_TCM_MON_ALLOW_S) +#define PMS_LP_MM_TCM_MON_ALLOW_V 0x00000001U +#define PMS_LP_MM_TCM_MON_ALLOW_S 10 +/** PMS_LP_MM_CACHE_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_CACHE_ALLOW (BIT(11)) +#define PMS_LP_MM_CACHE_ALLOW_M (PMS_LP_MM_CACHE_ALLOW_V << PMS_LP_MM_CACHE_ALLOW_S) +#define PMS_LP_MM_CACHE_ALLOW_V 0x00000001U +#define PMS_LP_MM_CACHE_ALLOW_S 11 -/** TEE_LP_MM_PMS_REG1_REG register - * NA - */ -#define TEE_LP_MM_PMS_REG1_REG (DR_REG_TEE_BASE + 0x30) -/** TEE_REG_LP_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_USBOTG_ALLOW (BIT(0)) -#define TEE_REG_LP_MM_HP_USBOTG_ALLOW_M (TEE_REG_LP_MM_HP_USBOTG_ALLOW_V << TEE_REG_LP_MM_HP_USBOTG_ALLOW_S) -#define TEE_REG_LP_MM_HP_USBOTG_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_USBOTG_ALLOW_S 0 -/** TEE_REG_LP_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_USBOTG11_ALLOW (BIT(1)) -#define TEE_REG_LP_MM_HP_USBOTG11_ALLOW_M (TEE_REG_LP_MM_HP_USBOTG11_ALLOW_V << TEE_REG_LP_MM_HP_USBOTG11_ALLOW_S) -#define TEE_REG_LP_MM_HP_USBOTG11_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_USBOTG11_ALLOW_S 1 -/** TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) -#define TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW_M (TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW_V << TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW_S) -#define TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_USBOTG11_WRAP_ALLOW_S 2 -/** TEE_REG_LP_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_GDMA_ALLOW (BIT(3)) -#define TEE_REG_LP_MM_HP_GDMA_ALLOW_M (TEE_REG_LP_MM_HP_GDMA_ALLOW_V << TEE_REG_LP_MM_HP_GDMA_ALLOW_S) -#define TEE_REG_LP_MM_HP_GDMA_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_GDMA_ALLOW_S 3 -/** TEE_REG_LP_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_REGDMA_ALLOW (BIT(4)) -#define TEE_REG_LP_MM_HP_REGDMA_ALLOW_M (TEE_REG_LP_MM_HP_REGDMA_ALLOW_V << TEE_REG_LP_MM_HP_REGDMA_ALLOW_S) -#define TEE_REG_LP_MM_HP_REGDMA_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_REGDMA_ALLOW_S 4 -/** TEE_REG_LP_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_SDMMC_ALLOW (BIT(5)) -#define TEE_REG_LP_MM_HP_SDMMC_ALLOW_M (TEE_REG_LP_MM_HP_SDMMC_ALLOW_V << TEE_REG_LP_MM_HP_SDMMC_ALLOW_S) -#define TEE_REG_LP_MM_HP_SDMMC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_SDMMC_ALLOW_S 5 -/** TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW (BIT(6)) -#define TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW_M (TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW_V << TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW_S) -#define TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_AHB_PDMA_ALLOW_S 6 -/** TEE_REG_LP_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_JPEG_ALLOW (BIT(7)) -#define TEE_REG_LP_MM_HP_JPEG_ALLOW_M (TEE_REG_LP_MM_HP_JPEG_ALLOW_V << TEE_REG_LP_MM_HP_JPEG_ALLOW_S) -#define TEE_REG_LP_MM_HP_JPEG_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_JPEG_ALLOW_S 7 -/** TEE_REG_LP_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PPA_ALLOW (BIT(8)) -#define TEE_REG_LP_MM_HP_PPA_ALLOW_M (TEE_REG_LP_MM_HP_PPA_ALLOW_V << TEE_REG_LP_MM_HP_PPA_ALLOW_S) -#define TEE_REG_LP_MM_HP_PPA_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PPA_ALLOW_S 8 -/** TEE_REG_LP_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_DMA2D_ALLOW (BIT(9)) -#define TEE_REG_LP_MM_HP_DMA2D_ALLOW_M (TEE_REG_LP_MM_HP_DMA2D_ALLOW_V << TEE_REG_LP_MM_HP_DMA2D_ALLOW_S) -#define TEE_REG_LP_MM_HP_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_DMA2D_ALLOW_S 9 -/** TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) -#define TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW_M (TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW_V << TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW_S) -#define TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_KEY_MANAGER_ALLOW_S 10 -/** TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW (BIT(11)) -#define TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW_M (TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW_V << TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW_S) -#define TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_AXI_PDMA_ALLOW_S 11 -/** TEE_REG_LP_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_FLASH_ALLOW (BIT(12)) -#define TEE_REG_LP_MM_HP_FLASH_ALLOW_M (TEE_REG_LP_MM_HP_FLASH_ALLOW_V << TEE_REG_LP_MM_HP_FLASH_ALLOW_S) -#define TEE_REG_LP_MM_HP_FLASH_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_FLASH_ALLOW_S 12 -/** TEE_REG_LP_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PSRAM_ALLOW (BIT(13)) -#define TEE_REG_LP_MM_HP_PSRAM_ALLOW_M (TEE_REG_LP_MM_HP_PSRAM_ALLOW_V << TEE_REG_LP_MM_HP_PSRAM_ALLOW_S) -#define TEE_REG_LP_MM_HP_PSRAM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PSRAM_ALLOW_S 13 -/** TEE_REG_LP_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_CRYPTO_ALLOW (BIT(14)) -#define TEE_REG_LP_MM_HP_CRYPTO_ALLOW_M (TEE_REG_LP_MM_HP_CRYPTO_ALLOW_V << TEE_REG_LP_MM_HP_CRYPTO_ALLOW_S) -#define TEE_REG_LP_MM_HP_CRYPTO_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_CRYPTO_ALLOW_S 14 -/** TEE_REG_LP_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_GMAC_ALLOW (BIT(15)) -#define TEE_REG_LP_MM_HP_GMAC_ALLOW_M (TEE_REG_LP_MM_HP_GMAC_ALLOW_V << TEE_REG_LP_MM_HP_GMAC_ALLOW_S) -#define TEE_REG_LP_MM_HP_GMAC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_GMAC_ALLOW_S 15 -/** TEE_REG_LP_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_USB_PHY_ALLOW (BIT(16)) -#define TEE_REG_LP_MM_HP_USB_PHY_ALLOW_M (TEE_REG_LP_MM_HP_USB_PHY_ALLOW_V << TEE_REG_LP_MM_HP_USB_PHY_ALLOW_S) -#define TEE_REG_LP_MM_HP_USB_PHY_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_USB_PHY_ALLOW_S 16 -/** TEE_REG_LP_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PVT_ALLOW (BIT(17)) -#define TEE_REG_LP_MM_HP_PVT_ALLOW_M (TEE_REG_LP_MM_HP_PVT_ALLOW_V << TEE_REG_LP_MM_HP_PVT_ALLOW_S) -#define TEE_REG_LP_MM_HP_PVT_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PVT_ALLOW_S 17 -/** TEE_REG_LP_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_CSI_HOST_ALLOW (BIT(18)) -#define TEE_REG_LP_MM_HP_CSI_HOST_ALLOW_M (TEE_REG_LP_MM_HP_CSI_HOST_ALLOW_V << TEE_REG_LP_MM_HP_CSI_HOST_ALLOW_S) -#define TEE_REG_LP_MM_HP_CSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_CSI_HOST_ALLOW_S 18 -/** TEE_REG_LP_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_DSI_HOST_ALLOW (BIT(19)) -#define TEE_REG_LP_MM_HP_DSI_HOST_ALLOW_M (TEE_REG_LP_MM_HP_DSI_HOST_ALLOW_V << TEE_REG_LP_MM_HP_DSI_HOST_ALLOW_S) -#define TEE_REG_LP_MM_HP_DSI_HOST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_DSI_HOST_ALLOW_S 19 -/** TEE_REG_LP_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_ISP_ALLOW (BIT(20)) -#define TEE_REG_LP_MM_HP_ISP_ALLOW_M (TEE_REG_LP_MM_HP_ISP_ALLOW_V << TEE_REG_LP_MM_HP_ISP_ALLOW_S) -#define TEE_REG_LP_MM_HP_ISP_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_ISP_ALLOW_S 20 -/** TEE_REG_LP_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_H264_CORE_ALLOW (BIT(21)) -#define TEE_REG_LP_MM_HP_H264_CORE_ALLOW_M (TEE_REG_LP_MM_HP_H264_CORE_ALLOW_V << TEE_REG_LP_MM_HP_H264_CORE_ALLOW_S) -#define TEE_REG_LP_MM_HP_H264_CORE_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_H264_CORE_ALLOW_S 21 -/** TEE_REG_LP_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_RMT_ALLOW (BIT(22)) -#define TEE_REG_LP_MM_HP_RMT_ALLOW_M (TEE_REG_LP_MM_HP_RMT_ALLOW_V << TEE_REG_LP_MM_HP_RMT_ALLOW_S) -#define TEE_REG_LP_MM_HP_RMT_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_RMT_ALLOW_S 22 -/** TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) -#define TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW_M (TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW_V << TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW_S) -#define TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_BITSRAMBLER_ALLOW_S 23 -/** TEE_REG_LP_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_AXI_ICM_ALLOW (BIT(24)) -#define TEE_REG_LP_MM_HP_AXI_ICM_ALLOW_M (TEE_REG_LP_MM_HP_AXI_ICM_ALLOW_V << TEE_REG_LP_MM_HP_AXI_ICM_ALLOW_S) -#define TEE_REG_LP_MM_HP_AXI_ICM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_AXI_ICM_ALLOW_S 24 -/** TEE_REG_LP_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PERI_PMS_ALLOW (BIT(25)) -#define TEE_REG_LP_MM_HP_PERI_PMS_ALLOW_M (TEE_REG_LP_MM_HP_PERI_PMS_ALLOW_V << TEE_REG_LP_MM_HP_PERI_PMS_ALLOW_S) -#define TEE_REG_LP_MM_HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PERI_PMS_ALLOW_S 25 -/** TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) -#define TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW_M (TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW_V << TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW_S) -#define TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP2HP_PERI_PMS_ALLOW_S 26 -/** TEE_REG_LP_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_DMA_PMS_ALLOW (BIT(27)) -#define TEE_REG_LP_MM_DMA_PMS_ALLOW_M (TEE_REG_LP_MM_DMA_PMS_ALLOW_V << TEE_REG_LP_MM_DMA_PMS_ALLOW_S) -#define TEE_REG_LP_MM_DMA_PMS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_DMA_PMS_ALLOW_S 27 -/** TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW (BIT(28)) -#define TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW_M (TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW_V << TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW_S) -#define TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_H264_DMA2D_ALLOW_S 28 +/** PMS_LP_MM_PMS_REG1_REG register + * Permission control register1 for the LP CPU in machine mode + */ +#define PMS_LP_MM_PMS_REG1_REG (DR_REG_PMS_BASE + 0x30) +/** PMS_LP_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * high-speed USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_USBOTG_ALLOW (BIT(0)) +#define PMS_LP_MM_HP_USBOTG_ALLOW_M (PMS_LP_MM_HP_USBOTG_ALLOW_V << PMS_LP_MM_HP_USBOTG_ALLOW_S) +#define PMS_LP_MM_HP_USBOTG_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_USBOTG_ALLOW_S 0 +/** PMS_LP_MM_HP_USBOTG11_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * full-speed USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_USBOTG11_ALLOW (BIT(1)) +#define PMS_LP_MM_HP_USBOTG11_ALLOW_M (PMS_LP_MM_HP_USBOTG11_ALLOW_V << PMS_LP_MM_HP_USBOTG11_ALLOW_S) +#define PMS_LP_MM_HP_USBOTG11_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_USBOTG11_ALLOW_S 1 +/** PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * full-speed USB 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW (BIT(2)) +#define PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW_M (PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW_V << PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW_S) +#define PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_USBOTG11_WRAP_ALLOW_S 2 +/** PMS_LP_MM_HP_GDMA_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_GDMA_ALLOW (BIT(3)) +#define PMS_LP_MM_HP_GDMA_ALLOW_M (PMS_LP_MM_HP_GDMA_ALLOW_V << PMS_LP_MM_HP_GDMA_ALLOW_S) +#define PMS_LP_MM_HP_GDMA_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_GDMA_ALLOW_S 3 +/** PMS_LP_MM_HP_REGDMA_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GDMA (DW + * GDMA). + * 0: Not allowed + * 1: Allow + */ +#define PMS_LP_MM_HP_REGDMA_ALLOW (BIT(4)) +#define PMS_LP_MM_HP_REGDMA_ALLOW_M (PMS_LP_MM_HP_REGDMA_ALLOW_V << PMS_LP_MM_HP_REGDMA_ALLOW_S) +#define PMS_LP_MM_HP_REGDMA_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_REGDMA_ALLOW_S 4 +/** PMS_LP_MM_HP_SDMMC_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_SDMMC_ALLOW (BIT(5)) +#define PMS_LP_MM_HP_SDMMC_ALLOW_M (PMS_LP_MM_HP_SDMMC_ALLOW_V << PMS_LP_MM_HP_SDMMC_ALLOW_S) +#define PMS_LP_MM_HP_SDMMC_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_SDMMC_ALLOW_S 5 +/** PMS_LP_MM_HP_AHB_PDMA_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_AHB_PDMA_ALLOW (BIT(6)) +#define PMS_LP_MM_HP_AHB_PDMA_ALLOW_M (PMS_LP_MM_HP_AHB_PDMA_ALLOW_V << PMS_LP_MM_HP_AHB_PDMA_ALLOW_S) +#define PMS_LP_MM_HP_AHB_PDMA_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_AHB_PDMA_ALLOW_S 6 +/** PMS_LP_MM_HP_JPEG_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_JPEG_ALLOW (BIT(7)) +#define PMS_LP_MM_HP_JPEG_ALLOW_M (PMS_LP_MM_HP_JPEG_ALLOW_V << PMS_LP_MM_HP_JPEG_ALLOW_S) +#define PMS_LP_MM_HP_JPEG_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_JPEG_ALLOW_S 7 +/** PMS_LP_MM_HP_PPA_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_PPA_ALLOW (BIT(8)) +#define PMS_LP_MM_HP_PPA_ALLOW_M (PMS_LP_MM_HP_PPA_ALLOW_V << PMS_LP_MM_HP_PPA_ALLOW_S) +#define PMS_LP_MM_HP_PPA_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PPA_ALLOW_S 8 +/** PMS_LP_MM_HP_DMA2D_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_DMA2D_ALLOW (BIT(9)) +#define PMS_LP_MM_HP_DMA2D_ALLOW_M (PMS_LP_MM_HP_DMA2D_ALLOW_V << PMS_LP_MM_HP_DMA2D_ALLOW_S) +#define PMS_LP_MM_HP_DMA2D_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_DMA2D_ALLOW_S 9 +/** PMS_LP_MM_HP_KEY_MANAGER_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP key + * manager. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_KEY_MANAGER_ALLOW (BIT(10)) +#define PMS_LP_MM_HP_KEY_MANAGER_ALLOW_M (PMS_LP_MM_HP_KEY_MANAGER_ALLOW_V << PMS_LP_MM_HP_KEY_MANAGER_ALLOW_S) +#define PMS_LP_MM_HP_KEY_MANAGER_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_KEY_MANAGER_ALLOW_S 10 +/** PMS_LP_MM_HP_AXI_PDMA_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_AXI_PDMA_ALLOW (BIT(11)) +#define PMS_LP_MM_HP_AXI_PDMA_ALLOW_M (PMS_LP_MM_HP_AXI_PDMA_ALLOW_V << PMS_LP_MM_HP_AXI_PDMA_ALLOW_S) +#define PMS_LP_MM_HP_AXI_PDMA_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_AXI_PDMA_ALLOW_S 11 +/** PMS_LP_MM_HP_FLASH_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP flash + * MSPI controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_FLASH_ALLOW (BIT(12)) +#define PMS_LP_MM_HP_FLASH_ALLOW_M (PMS_LP_MM_HP_FLASH_ALLOW_V << PMS_LP_MM_HP_FLASH_ALLOW_S) +#define PMS_LP_MM_HP_FLASH_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_FLASH_ALLOW_S 12 +/** PMS_LP_MM_HP_PSRAM_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PSRAM + * MSPI controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_PSRAM_ALLOW (BIT(13)) +#define PMS_LP_MM_HP_PSRAM_ALLOW_M (PMS_LP_MM_HP_PSRAM_ALLOW_V << PMS_LP_MM_HP_PSRAM_ALLOW_S) +#define PMS_LP_MM_HP_PSRAM_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PSRAM_ALLOW_S 13 +/** PMS_LP_MM_HP_CRYPTO_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP CRYPTO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_CRYPTO_ALLOW (BIT(14)) +#define PMS_LP_MM_HP_CRYPTO_ALLOW_M (PMS_LP_MM_HP_CRYPTO_ALLOW_V << PMS_LP_MM_HP_CRYPTO_ALLOW_S) +#define PMS_LP_MM_HP_CRYPTO_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_CRYPTO_ALLOW_S 14 +/** PMS_LP_MM_HP_GMAC_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_GMAC_ALLOW (BIT(15)) +#define PMS_LP_MM_HP_GMAC_ALLOW_M (PMS_LP_MM_HP_GMAC_ALLOW_V << PMS_LP_MM_HP_GMAC_ALLOW_S) +#define PMS_LP_MM_HP_GMAC_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_GMAC_ALLOW_S 15 +/** PMS_LP_MM_HP_USB_PHY_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * high-speed USB 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_USB_PHY_ALLOW (BIT(16)) +#define PMS_LP_MM_HP_USB_PHY_ALLOW_M (PMS_LP_MM_HP_USB_PHY_ALLOW_V << PMS_LP_MM_HP_USB_PHY_ALLOW_S) +#define PMS_LP_MM_HP_USB_PHY_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_USB_PHY_ALLOW_S 16 +/** PMS_LP_MM_HP_PVT_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ +#define PMS_LP_MM_HP_PVT_ALLOW (BIT(17)) +#define PMS_LP_MM_HP_PVT_ALLOW_M (PMS_LP_MM_HP_PVT_ALLOW_V << PMS_LP_MM_HP_PVT_ALLOW_S) +#define PMS_LP_MM_HP_PVT_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PVT_ALLOW_S 17 +/** PMS_LP_MM_HP_CSI_HOST_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MIPI CSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_CSI_HOST_ALLOW (BIT(18)) +#define PMS_LP_MM_HP_CSI_HOST_ALLOW_M (PMS_LP_MM_HP_CSI_HOST_ALLOW_V << PMS_LP_MM_HP_CSI_HOST_ALLOW_S) +#define PMS_LP_MM_HP_CSI_HOST_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_CSI_HOST_ALLOW_S 18 +/** PMS_LP_MM_HP_DSI_HOST_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MIPI DSI + * host. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_DSI_HOST_ALLOW (BIT(19)) +#define PMS_LP_MM_HP_DSI_HOST_ALLOW_M (PMS_LP_MM_HP_DSI_HOST_ALLOW_V << PMS_LP_MM_HP_DSI_HOST_ALLOW_S) +#define PMS_LP_MM_HP_DSI_HOST_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_DSI_HOST_ALLOW_S 19 +/** PMS_LP_MM_HP_ISP_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ISP. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_ISP_ALLOW (BIT(20)) +#define PMS_LP_MM_HP_ISP_ALLOW_M (PMS_LP_MM_HP_ISP_ALLOW_V << PMS_LP_MM_HP_ISP_ALLOW_S) +#define PMS_LP_MM_HP_ISP_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_ISP_ALLOW_S 20 +/** PMS_LP_MM_HP_H264_CORE_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP H264 + * Encoder. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_H264_CORE_ALLOW (BIT(21)) +#define PMS_LP_MM_HP_H264_CORE_ALLOW_M (PMS_LP_MM_HP_H264_CORE_ALLOW_V << PMS_LP_MM_HP_H264_CORE_ALLOW_S) +#define PMS_LP_MM_HP_H264_CORE_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_H264_CORE_ALLOW_S 21 +/** PMS_LP_MM_HP_RMT_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_RMT_ALLOW (BIT(22)) +#define PMS_LP_MM_HP_RMT_ALLOW_M (PMS_LP_MM_HP_RMT_ALLOW_V << PMS_LP_MM_HP_RMT_ALLOW_S) +#define PMS_LP_MM_HP_RMT_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_RMT_ALLOW_S 22 +/** PMS_LP_MM_HP_BITSRAMBLER_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP bit + * scrambler. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_BITSRAMBLER_ALLOW (BIT(23)) +#define PMS_LP_MM_HP_BITSRAMBLER_ALLOW_M (PMS_LP_MM_HP_BITSRAMBLER_ALLOW_V << PMS_LP_MM_HP_BITSRAMBLER_ALLOW_S) +#define PMS_LP_MM_HP_BITSRAMBLER_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_BITSRAMBLER_ALLOW_S 23 +/** PMS_LP_MM_HP_AXI_ICM_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_AXI_ICM_ALLOW (BIT(24)) +#define PMS_LP_MM_HP_AXI_ICM_ALLOW_M (PMS_LP_MM_HP_AXI_ICM_ALLOW_V << PMS_LP_MM_HP_AXI_ICM_ALLOW_S) +#define PMS_LP_MM_HP_AXI_ICM_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_AXI_ICM_ALLOW_S 24 +/** PMS_LP_MM_HP_PERI_PMS_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_PERI_PMS_ALLOW (BIT(25)) +#define PMS_LP_MM_HP_PERI_PMS_ALLOW_M (PMS_LP_MM_HP_PERI_PMS_ALLOW_V << PMS_LP_MM_HP_PERI_PMS_ALLOW_S) +#define PMS_LP_MM_HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PERI_PMS_ALLOW_S 25 +/** PMS_LP_MM_LP2HP_PERI_PMS_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP2HP_PERI_PMS_ALLOW (BIT(26)) +#define PMS_LP_MM_LP2HP_PERI_PMS_ALLOW_M (PMS_LP_MM_LP2HP_PERI_PMS_ALLOW_V << PMS_LP_MM_LP2HP_PERI_PMS_ALLOW_S) +#define PMS_LP_MM_LP2HP_PERI_PMS_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP2HP_PERI_PMS_ALLOW_S 26 +/** PMS_LP_MM_DMA_PMS_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_DMA_PMS_ALLOW (BIT(27)) +#define PMS_LP_MM_DMA_PMS_ALLOW_M (PMS_LP_MM_DMA_PMS_ALLOW_V << PMS_LP_MM_DMA_PMS_ALLOW_S) +#define PMS_LP_MM_DMA_PMS_ALLOW_V 0x00000001U +#define PMS_LP_MM_DMA_PMS_ALLOW_S 27 +/** PMS_LP_MM_HP_H264_DMA2D_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_H264_DMA2D_ALLOW (BIT(28)) +#define PMS_LP_MM_HP_H264_DMA2D_ALLOW_M (PMS_LP_MM_HP_H264_DMA2D_ALLOW_V << PMS_LP_MM_HP_H264_DMA2D_ALLOW_S) +#define PMS_LP_MM_HP_H264_DMA2D_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_H264_DMA2D_ALLOW_S 28 -/** TEE_LP_MM_PMS_REG2_REG register - * NA - */ -#define TEE_LP_MM_PMS_REG2_REG (DR_REG_TEE_BASE + 0xa4) -/** TEE_REG_LP_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_MCPWM0_ALLOW (BIT(0)) -#define TEE_REG_LP_MM_HP_MCPWM0_ALLOW_M (TEE_REG_LP_MM_HP_MCPWM0_ALLOW_V << TEE_REG_LP_MM_HP_MCPWM0_ALLOW_S) -#define TEE_REG_LP_MM_HP_MCPWM0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_MCPWM0_ALLOW_S 0 -/** TEE_REG_LP_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_MCPWM1_ALLOW (BIT(1)) -#define TEE_REG_LP_MM_HP_MCPWM1_ALLOW_M (TEE_REG_LP_MM_HP_MCPWM1_ALLOW_V << TEE_REG_LP_MM_HP_MCPWM1_ALLOW_S) -#define TEE_REG_LP_MM_HP_MCPWM1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_MCPWM1_ALLOW_S 1 -/** TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) -#define TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW_M (TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW_V << TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW_S) -#define TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_TIMER_GROUP0_ALLOW_S 2 -/** TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) -#define TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW_M (TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW_V << TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW_S) -#define TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_TIMER_GROUP1_ALLOW_S 3 -/** TEE_REG_LP_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I2C0_ALLOW (BIT(4)) -#define TEE_REG_LP_MM_HP_I2C0_ALLOW_M (TEE_REG_LP_MM_HP_I2C0_ALLOW_V << TEE_REG_LP_MM_HP_I2C0_ALLOW_S) -#define TEE_REG_LP_MM_HP_I2C0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I2C0_ALLOW_S 4 -/** TEE_REG_LP_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I2C1_ALLOW (BIT(5)) -#define TEE_REG_LP_MM_HP_I2C1_ALLOW_M (TEE_REG_LP_MM_HP_I2C1_ALLOW_V << TEE_REG_LP_MM_HP_I2C1_ALLOW_S) -#define TEE_REG_LP_MM_HP_I2C1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I2C1_ALLOW_S 5 -/** TEE_REG_LP_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I2S0_ALLOW (BIT(6)) -#define TEE_REG_LP_MM_HP_I2S0_ALLOW_M (TEE_REG_LP_MM_HP_I2S0_ALLOW_V << TEE_REG_LP_MM_HP_I2S0_ALLOW_S) -#define TEE_REG_LP_MM_HP_I2S0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I2S0_ALLOW_S 6 -/** TEE_REG_LP_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I2S1_ALLOW (BIT(7)) -#define TEE_REG_LP_MM_HP_I2S1_ALLOW_M (TEE_REG_LP_MM_HP_I2S1_ALLOW_V << TEE_REG_LP_MM_HP_I2S1_ALLOW_S) -#define TEE_REG_LP_MM_HP_I2S1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I2S1_ALLOW_S 7 -/** TEE_REG_LP_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I2S2_ALLOW (BIT(8)) -#define TEE_REG_LP_MM_HP_I2S2_ALLOW_M (TEE_REG_LP_MM_HP_I2S2_ALLOW_V << TEE_REG_LP_MM_HP_I2S2_ALLOW_S) -#define TEE_REG_LP_MM_HP_I2S2_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I2S2_ALLOW_S 8 -/** TEE_REG_LP_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PCNT_ALLOW (BIT(9)) -#define TEE_REG_LP_MM_HP_PCNT_ALLOW_M (TEE_REG_LP_MM_HP_PCNT_ALLOW_V << TEE_REG_LP_MM_HP_PCNT_ALLOW_S) -#define TEE_REG_LP_MM_HP_PCNT_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PCNT_ALLOW_S 9 -/** TEE_REG_LP_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UART0_ALLOW (BIT(10)) -#define TEE_REG_LP_MM_HP_UART0_ALLOW_M (TEE_REG_LP_MM_HP_UART0_ALLOW_V << TEE_REG_LP_MM_HP_UART0_ALLOW_S) -#define TEE_REG_LP_MM_HP_UART0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UART0_ALLOW_S 10 -/** TEE_REG_LP_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UART1_ALLOW (BIT(11)) -#define TEE_REG_LP_MM_HP_UART1_ALLOW_M (TEE_REG_LP_MM_HP_UART1_ALLOW_V << TEE_REG_LP_MM_HP_UART1_ALLOW_S) -#define TEE_REG_LP_MM_HP_UART1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UART1_ALLOW_S 11 -/** TEE_REG_LP_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UART2_ALLOW (BIT(12)) -#define TEE_REG_LP_MM_HP_UART2_ALLOW_M (TEE_REG_LP_MM_HP_UART2_ALLOW_V << TEE_REG_LP_MM_HP_UART2_ALLOW_S) -#define TEE_REG_LP_MM_HP_UART2_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UART2_ALLOW_S 12 -/** TEE_REG_LP_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UART3_ALLOW (BIT(13)) -#define TEE_REG_LP_MM_HP_UART3_ALLOW_M (TEE_REG_LP_MM_HP_UART3_ALLOW_V << TEE_REG_LP_MM_HP_UART3_ALLOW_S) -#define TEE_REG_LP_MM_HP_UART3_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UART3_ALLOW_S 13 -/** TEE_REG_LP_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UART4_ALLOW (BIT(14)) -#define TEE_REG_LP_MM_HP_UART4_ALLOW_M (TEE_REG_LP_MM_HP_UART4_ALLOW_V << TEE_REG_LP_MM_HP_UART4_ALLOW_S) -#define TEE_REG_LP_MM_HP_UART4_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UART4_ALLOW_S 14 -/** TEE_REG_LP_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_PARLIO_ALLOW (BIT(15)) -#define TEE_REG_LP_MM_HP_PARLIO_ALLOW_M (TEE_REG_LP_MM_HP_PARLIO_ALLOW_V << TEE_REG_LP_MM_HP_PARLIO_ALLOW_S) -#define TEE_REG_LP_MM_HP_PARLIO_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_PARLIO_ALLOW_S 15 -/** TEE_REG_LP_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_GPSPI2_ALLOW (BIT(16)) -#define TEE_REG_LP_MM_HP_GPSPI2_ALLOW_M (TEE_REG_LP_MM_HP_GPSPI2_ALLOW_V << TEE_REG_LP_MM_HP_GPSPI2_ALLOW_S) -#define TEE_REG_LP_MM_HP_GPSPI2_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_GPSPI2_ALLOW_S 16 -/** TEE_REG_LP_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_GPSPI3_ALLOW (BIT(17)) -#define TEE_REG_LP_MM_HP_GPSPI3_ALLOW_M (TEE_REG_LP_MM_HP_GPSPI3_ALLOW_V << TEE_REG_LP_MM_HP_GPSPI3_ALLOW_S) -#define TEE_REG_LP_MM_HP_GPSPI3_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_GPSPI3_ALLOW_S 17 -/** TEE_REG_LP_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_USBDEVICE_ALLOW (BIT(18)) -#define TEE_REG_LP_MM_HP_USBDEVICE_ALLOW_M (TEE_REG_LP_MM_HP_USBDEVICE_ALLOW_V << TEE_REG_LP_MM_HP_USBDEVICE_ALLOW_S) -#define TEE_REG_LP_MM_HP_USBDEVICE_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_USBDEVICE_ALLOW_S 18 -/** TEE_REG_LP_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_LEDC_ALLOW (BIT(19)) -#define TEE_REG_LP_MM_HP_LEDC_ALLOW_M (TEE_REG_LP_MM_HP_LEDC_ALLOW_V << TEE_REG_LP_MM_HP_LEDC_ALLOW_S) -#define TEE_REG_LP_MM_HP_LEDC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_LEDC_ALLOW_S 19 -/** TEE_REG_LP_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_ETM_ALLOW (BIT(21)) -#define TEE_REG_LP_MM_HP_ETM_ALLOW_M (TEE_REG_LP_MM_HP_ETM_ALLOW_V << TEE_REG_LP_MM_HP_ETM_ALLOW_S) -#define TEE_REG_LP_MM_HP_ETM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_ETM_ALLOW_S 21 -/** TEE_REG_LP_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_INTRMTX_ALLOW (BIT(22)) -#define TEE_REG_LP_MM_HP_INTRMTX_ALLOW_M (TEE_REG_LP_MM_HP_INTRMTX_ALLOW_V << TEE_REG_LP_MM_HP_INTRMTX_ALLOW_S) -#define TEE_REG_LP_MM_HP_INTRMTX_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_INTRMTX_ALLOW_S 22 -/** TEE_REG_LP_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_TWAI0_ALLOW (BIT(23)) -#define TEE_REG_LP_MM_HP_TWAI0_ALLOW_M (TEE_REG_LP_MM_HP_TWAI0_ALLOW_V << TEE_REG_LP_MM_HP_TWAI0_ALLOW_S) -#define TEE_REG_LP_MM_HP_TWAI0_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_TWAI0_ALLOW_S 23 -/** TEE_REG_LP_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_TWAI1_ALLOW (BIT(24)) -#define TEE_REG_LP_MM_HP_TWAI1_ALLOW_M (TEE_REG_LP_MM_HP_TWAI1_ALLOW_V << TEE_REG_LP_MM_HP_TWAI1_ALLOW_S) -#define TEE_REG_LP_MM_HP_TWAI1_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_TWAI1_ALLOW_S 24 -/** TEE_REG_LP_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_TWAI2_ALLOW (BIT(25)) -#define TEE_REG_LP_MM_HP_TWAI2_ALLOW_M (TEE_REG_LP_MM_HP_TWAI2_ALLOW_V << TEE_REG_LP_MM_HP_TWAI2_ALLOW_S) -#define TEE_REG_LP_MM_HP_TWAI2_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_TWAI2_ALLOW_S 25 -/** TEE_REG_LP_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I3C_MST_ALLOW (BIT(26)) -#define TEE_REG_LP_MM_HP_I3C_MST_ALLOW_M (TEE_REG_LP_MM_HP_I3C_MST_ALLOW_V << TEE_REG_LP_MM_HP_I3C_MST_ALLOW_S) -#define TEE_REG_LP_MM_HP_I3C_MST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I3C_MST_ALLOW_S 26 -/** TEE_REG_LP_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_I3C_SLV_ALLOW (BIT(27)) -#define TEE_REG_LP_MM_HP_I3C_SLV_ALLOW_M (TEE_REG_LP_MM_HP_I3C_SLV_ALLOW_V << TEE_REG_LP_MM_HP_I3C_SLV_ALLOW_S) -#define TEE_REG_LP_MM_HP_I3C_SLV_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_I3C_SLV_ALLOW_S 27 -/** TEE_REG_LP_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_LCDCAM_ALLOW (BIT(28)) -#define TEE_REG_LP_MM_HP_LCDCAM_ALLOW_M (TEE_REG_LP_MM_HP_LCDCAM_ALLOW_V << TEE_REG_LP_MM_HP_LCDCAM_ALLOW_S) -#define TEE_REG_LP_MM_HP_LCDCAM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_LCDCAM_ALLOW_S 28 -/** TEE_REG_LP_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_ADC_ALLOW (BIT(30)) -#define TEE_REG_LP_MM_HP_ADC_ALLOW_M (TEE_REG_LP_MM_HP_ADC_ALLOW_V << TEE_REG_LP_MM_HP_ADC_ALLOW_S) -#define TEE_REG_LP_MM_HP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_ADC_ALLOW_S 30 -/** TEE_REG_LP_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_UHCI_ALLOW (BIT(31)) -#define TEE_REG_LP_MM_HP_UHCI_ALLOW_M (TEE_REG_LP_MM_HP_UHCI_ALLOW_V << TEE_REG_LP_MM_HP_UHCI_ALLOW_S) -#define TEE_REG_LP_MM_HP_UHCI_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_UHCI_ALLOW_S 31 +/** PMS_LP_MM_PMS_REG2_REG register + * Permission control register2 for the LP CPU in machine mode + */ +#define PMS_LP_MM_PMS_REG2_REG (DR_REG_PMS_BASE + 0xa4) +/** PMS_LP_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_MCPWM0_ALLOW (BIT(0)) +#define PMS_LP_MM_HP_MCPWM0_ALLOW_M (PMS_LP_MM_HP_MCPWM0_ALLOW_V << PMS_LP_MM_HP_MCPWM0_ALLOW_S) +#define PMS_LP_MM_HP_MCPWM0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_MCPWM0_ALLOW_S 0 +/** PMS_LP_MM_HP_MCPWM1_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_MCPWM1_ALLOW (BIT(1)) +#define PMS_LP_MM_HP_MCPWM1_ALLOW_M (PMS_LP_MM_HP_MCPWM1_ALLOW_V << PMS_LP_MM_HP_MCPWM1_ALLOW_S) +#define PMS_LP_MM_HP_MCPWM1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_MCPWM1_ALLOW_S 1 +/** PMS_LP_MM_HP_TIMER_GROUP0_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP timer + * group0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_TIMER_GROUP0_ALLOW (BIT(2)) +#define PMS_LP_MM_HP_TIMER_GROUP0_ALLOW_M (PMS_LP_MM_HP_TIMER_GROUP0_ALLOW_V << PMS_LP_MM_HP_TIMER_GROUP0_ALLOW_S) +#define PMS_LP_MM_HP_TIMER_GROUP0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_TIMER_GROUP0_ALLOW_S 2 +/** PMS_LP_MM_HP_TIMER_GROUP1_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP timer + * group1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_TIMER_GROUP1_ALLOW (BIT(3)) +#define PMS_LP_MM_HP_TIMER_GROUP1_ALLOW_M (PMS_LP_MM_HP_TIMER_GROUP1_ALLOW_V << PMS_LP_MM_HP_TIMER_GROUP1_ALLOW_S) +#define PMS_LP_MM_HP_TIMER_GROUP1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_TIMER_GROUP1_ALLOW_S 3 +/** PMS_LP_MM_HP_I2C0_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I2C0_ALLOW (BIT(4)) +#define PMS_LP_MM_HP_I2C0_ALLOW_M (PMS_LP_MM_HP_I2C0_ALLOW_V << PMS_LP_MM_HP_I2C0_ALLOW_S) +#define PMS_LP_MM_HP_I2C0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I2C0_ALLOW_S 4 +/** PMS_LP_MM_HP_I2C1_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I2C1_ALLOW (BIT(5)) +#define PMS_LP_MM_HP_I2C1_ALLOW_M (PMS_LP_MM_HP_I2C1_ALLOW_V << PMS_LP_MM_HP_I2C1_ALLOW_S) +#define PMS_LP_MM_HP_I2C1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I2C1_ALLOW_S 5 +/** PMS_LP_MM_HP_I2S0_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I2S0_ALLOW (BIT(6)) +#define PMS_LP_MM_HP_I2S0_ALLOW_M (PMS_LP_MM_HP_I2S0_ALLOW_V << PMS_LP_MM_HP_I2S0_ALLOW_S) +#define PMS_LP_MM_HP_I2S0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I2S0_ALLOW_S 6 +/** PMS_LP_MM_HP_I2S1_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I2S1_ALLOW (BIT(7)) +#define PMS_LP_MM_HP_I2S1_ALLOW_M (PMS_LP_MM_HP_I2S1_ALLOW_V << PMS_LP_MM_HP_I2S1_ALLOW_S) +#define PMS_LP_MM_HP_I2S1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I2S1_ALLOW_S 7 +/** PMS_LP_MM_HP_I2S2_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I2S2_ALLOW (BIT(8)) +#define PMS_LP_MM_HP_I2S2_ALLOW_M (PMS_LP_MM_HP_I2S2_ALLOW_V << PMS_LP_MM_HP_I2S2_ALLOW_S) +#define PMS_LP_MM_HP_I2S2_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I2S2_ALLOW_S 8 +/** PMS_LP_MM_HP_PCNT_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_PCNT_ALLOW (BIT(9)) +#define PMS_LP_MM_HP_PCNT_ALLOW_M (PMS_LP_MM_HP_PCNT_ALLOW_V << PMS_LP_MM_HP_PCNT_ALLOW_S) +#define PMS_LP_MM_HP_PCNT_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PCNT_ALLOW_S 9 +/** PMS_LP_MM_HP_UART0_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UART0_ALLOW (BIT(10)) +#define PMS_LP_MM_HP_UART0_ALLOW_M (PMS_LP_MM_HP_UART0_ALLOW_V << PMS_LP_MM_HP_UART0_ALLOW_S) +#define PMS_LP_MM_HP_UART0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UART0_ALLOW_S 10 +/** PMS_LP_MM_HP_UART1_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UART1_ALLOW (BIT(11)) +#define PMS_LP_MM_HP_UART1_ALLOW_M (PMS_LP_MM_HP_UART1_ALLOW_V << PMS_LP_MM_HP_UART1_ALLOW_S) +#define PMS_LP_MM_HP_UART1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UART1_ALLOW_S 11 +/** PMS_LP_MM_HP_UART2_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UART2_ALLOW (BIT(12)) +#define PMS_LP_MM_HP_UART2_ALLOW_M (PMS_LP_MM_HP_UART2_ALLOW_V << PMS_LP_MM_HP_UART2_ALLOW_S) +#define PMS_LP_MM_HP_UART2_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UART2_ALLOW_S 12 +/** PMS_LP_MM_HP_UART3_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UART3_ALLOW (BIT(13)) +#define PMS_LP_MM_HP_UART3_ALLOW_M (PMS_LP_MM_HP_UART3_ALLOW_V << PMS_LP_MM_HP_UART3_ALLOW_S) +#define PMS_LP_MM_HP_UART3_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UART3_ALLOW_S 13 +/** PMS_LP_MM_HP_UART4_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UART4_ALLOW (BIT(14)) +#define PMS_LP_MM_HP_UART4_ALLOW_M (PMS_LP_MM_HP_UART4_ALLOW_V << PMS_LP_MM_HP_UART4_ALLOW_S) +#define PMS_LP_MM_HP_UART4_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UART4_ALLOW_S 14 +/** PMS_LP_MM_HP_PARLIO_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_PARLIO_ALLOW (BIT(15)) +#define PMS_LP_MM_HP_PARLIO_ALLOW_M (PMS_LP_MM_HP_PARLIO_ALLOW_V << PMS_LP_MM_HP_PARLIO_ALLOW_S) +#define PMS_LP_MM_HP_PARLIO_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_PARLIO_ALLOW_S 15 +/** PMS_LP_MM_HP_GPSPI2_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_GPSPI2_ALLOW (BIT(16)) +#define PMS_LP_MM_HP_GPSPI2_ALLOW_M (PMS_LP_MM_HP_GPSPI2_ALLOW_V << PMS_LP_MM_HP_GPSPI2_ALLOW_S) +#define PMS_LP_MM_HP_GPSPI2_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_GPSPI2_ALLOW_S 16 +/** PMS_LP_MM_HP_GPSPI3_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_GPSPI3_ALLOW (BIT(17)) +#define PMS_LP_MM_HP_GPSPI3_ALLOW_M (PMS_LP_MM_HP_GPSPI3_ALLOW_V << PMS_LP_MM_HP_GPSPI3_ALLOW_S) +#define PMS_LP_MM_HP_GPSPI3_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_GPSPI3_ALLOW_S 17 +/** PMS_LP_MM_HP_USBDEVICE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * USB/Serial JTAG Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_USBDEVICE_ALLOW (BIT(18)) +#define PMS_LP_MM_HP_USBDEVICE_ALLOW_M (PMS_LP_MM_HP_USBDEVICE_ALLOW_V << PMS_LP_MM_HP_USBDEVICE_ALLOW_S) +#define PMS_LP_MM_HP_USBDEVICE_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_USBDEVICE_ALLOW_S 18 +/** PMS_LP_MM_HP_LEDC_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_LEDC_ALLOW (BIT(19)) +#define PMS_LP_MM_HP_LEDC_ALLOW_M (PMS_LP_MM_HP_LEDC_ALLOW_V << PMS_LP_MM_HP_LEDC_ALLOW_S) +#define PMS_LP_MM_HP_LEDC_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_LEDC_ALLOW_S 19 +/** PMS_LP_MM_HP_ETM_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ETM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_ETM_ALLOW (BIT(21)) +#define PMS_LP_MM_HP_ETM_ALLOW_M (PMS_LP_MM_HP_ETM_ALLOW_V << PMS_LP_MM_HP_ETM_ALLOW_S) +#define PMS_LP_MM_HP_ETM_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_ETM_ALLOW_S 21 +/** PMS_LP_MM_HP_INTRMTX_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_INTRMTX_ALLOW (BIT(22)) +#define PMS_LP_MM_HP_INTRMTX_ALLOW_M (PMS_LP_MM_HP_INTRMTX_ALLOW_V << PMS_LP_MM_HP_INTRMTX_ALLOW_S) +#define PMS_LP_MM_HP_INTRMTX_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_INTRMTX_ALLOW_S 22 +/** PMS_LP_MM_HP_TWAI0_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_TWAI0_ALLOW (BIT(23)) +#define PMS_LP_MM_HP_TWAI0_ALLOW_M (PMS_LP_MM_HP_TWAI0_ALLOW_V << PMS_LP_MM_HP_TWAI0_ALLOW_S) +#define PMS_LP_MM_HP_TWAI0_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_TWAI0_ALLOW_S 23 +/** PMS_LP_MM_HP_TWAI1_ALLOW : R/W; bitpos: [24]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_TWAI1_ALLOW (BIT(24)) +#define PMS_LP_MM_HP_TWAI1_ALLOW_M (PMS_LP_MM_HP_TWAI1_ALLOW_V << PMS_LP_MM_HP_TWAI1_ALLOW_S) +#define PMS_LP_MM_HP_TWAI1_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_TWAI1_ALLOW_S 24 +/** PMS_LP_MM_HP_TWAI2_ALLOW : R/W; bitpos: [25]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_TWAI2_ALLOW (BIT(25)) +#define PMS_LP_MM_HP_TWAI2_ALLOW_M (PMS_LP_MM_HP_TWAI2_ALLOW_V << PMS_LP_MM_HP_TWAI2_ALLOW_S) +#define PMS_LP_MM_HP_TWAI2_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_TWAI2_ALLOW_S 25 +/** PMS_LP_MM_HP_I3C_MST_ALLOW : R/W; bitpos: [26]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I3C + * master controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I3C_MST_ALLOW (BIT(26)) +#define PMS_LP_MM_HP_I3C_MST_ALLOW_M (PMS_LP_MM_HP_I3C_MST_ALLOW_V << PMS_LP_MM_HP_I3C_MST_ALLOW_S) +#define PMS_LP_MM_HP_I3C_MST_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I3C_MST_ALLOW_S 26 +/** PMS_LP_MM_HP_I3C_SLV_ALLOW : R/W; bitpos: [27]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_I3C_SLV_ALLOW (BIT(27)) +#define PMS_LP_MM_HP_I3C_SLV_ALLOW_M (PMS_LP_MM_HP_I3C_SLV_ALLOW_V << PMS_LP_MM_HP_I3C_SLV_ALLOW_S) +#define PMS_LP_MM_HP_I3C_SLV_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_I3C_SLV_ALLOW_S 27 +/** PMS_LP_MM_HP_LCDCAM_ALLOW : R/W; bitpos: [28]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_LCDCAM_ALLOW (BIT(28)) +#define PMS_LP_MM_HP_LCDCAM_ALLOW_M (PMS_LP_MM_HP_LCDCAM_ALLOW_V << PMS_LP_MM_HP_LCDCAM_ALLOW_S) +#define PMS_LP_MM_HP_LCDCAM_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_LCDCAM_ALLOW_S 28 +/** PMS_LP_MM_HP_ADC_ALLOW : R/W; bitpos: [30]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_ADC_ALLOW (BIT(30)) +#define PMS_LP_MM_HP_ADC_ALLOW_M (PMS_LP_MM_HP_ADC_ALLOW_V << PMS_LP_MM_HP_ADC_ALLOW_S) +#define PMS_LP_MM_HP_ADC_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_ADC_ALLOW_S 30 +/** PMS_LP_MM_HP_UHCI_ALLOW : R/W; bitpos: [31]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_UHCI_ALLOW (BIT(31)) +#define PMS_LP_MM_HP_UHCI_ALLOW_M (PMS_LP_MM_HP_UHCI_ALLOW_V << PMS_LP_MM_HP_UHCI_ALLOW_S) +#define PMS_LP_MM_HP_UHCI_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_UHCI_ALLOW_S 31 -/** TEE_LP_MM_PMS_REG3_REG register - * NA - */ -#define TEE_LP_MM_PMS_REG3_REG (DR_REG_TEE_BASE + 0x11c) -/** TEE_REG_LP_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_GPIO_ALLOW (BIT(0)) -#define TEE_REG_LP_MM_HP_GPIO_ALLOW_M (TEE_REG_LP_MM_HP_GPIO_ALLOW_V << TEE_REG_LP_MM_HP_GPIO_ALLOW_S) -#define TEE_REG_LP_MM_HP_GPIO_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_GPIO_ALLOW_S 0 -/** TEE_REG_LP_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_IOMUX_ALLOW (BIT(1)) -#define TEE_REG_LP_MM_HP_IOMUX_ALLOW_M (TEE_REG_LP_MM_HP_IOMUX_ALLOW_V << TEE_REG_LP_MM_HP_IOMUX_ALLOW_S) -#define TEE_REG_LP_MM_HP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_IOMUX_ALLOW_S 1 -/** TEE_REG_LP_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_SYSTIMER_ALLOW (BIT(2)) -#define TEE_REG_LP_MM_HP_SYSTIMER_ALLOW_M (TEE_REG_LP_MM_HP_SYSTIMER_ALLOW_V << TEE_REG_LP_MM_HP_SYSTIMER_ALLOW_S) -#define TEE_REG_LP_MM_HP_SYSTIMER_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_SYSTIMER_ALLOW_S 2 -/** TEE_REG_LP_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_SYS_REG_ALLOW (BIT(3)) -#define TEE_REG_LP_MM_HP_SYS_REG_ALLOW_M (TEE_REG_LP_MM_HP_SYS_REG_ALLOW_V << TEE_REG_LP_MM_HP_SYS_REG_ALLOW_S) -#define TEE_REG_LP_MM_HP_SYS_REG_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_SYS_REG_ALLOW_S 3 -/** TEE_REG_LP_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP_CLKRST_ALLOW (BIT(4)) -#define TEE_REG_LP_MM_HP_CLKRST_ALLOW_M (TEE_REG_LP_MM_HP_CLKRST_ALLOW_V << TEE_REG_LP_MM_HP_CLKRST_ALLOW_S) -#define TEE_REG_LP_MM_HP_CLKRST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP_CLKRST_ALLOW_S 4 +/** PMS_LP_MM_PMS_REG3_REG register + * Permission control register3 for the LP CPU in machine mode + */ +#define PMS_LP_MM_PMS_REG3_REG (DR_REG_PMS_BASE + 0x11c) +/** PMS_LP_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GPIO + * Matrix. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_GPIO_ALLOW (BIT(0)) +#define PMS_LP_MM_HP_GPIO_ALLOW_M (PMS_LP_MM_HP_GPIO_ALLOW_V << PMS_LP_MM_HP_GPIO_ALLOW_S) +#define PMS_LP_MM_HP_GPIO_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_GPIO_ALLOW_S 0 +/** PMS_LP_MM_HP_IOMUX_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_IOMUX_ALLOW (BIT(1)) +#define PMS_LP_MM_HP_IOMUX_ALLOW_M (PMS_LP_MM_HP_IOMUX_ALLOW_V << PMS_LP_MM_HP_IOMUX_ALLOW_S) +#define PMS_LP_MM_HP_IOMUX_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_IOMUX_ALLOW_S 1 +/** PMS_LP_MM_HP_SYSTIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP system + * timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_SYSTIMER_ALLOW (BIT(2)) +#define PMS_LP_MM_HP_SYSTIMER_ALLOW_M (PMS_LP_MM_HP_SYSTIMER_ALLOW_V << PMS_LP_MM_HP_SYSTIMER_ALLOW_S) +#define PMS_LP_MM_HP_SYSTIMER_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_SYSTIMER_ALLOW_S 2 +/** PMS_LP_MM_HP_SYS_REG_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_SYS_REG_ALLOW (BIT(3)) +#define PMS_LP_MM_HP_SYS_REG_ALLOW_M (PMS_LP_MM_HP_SYS_REG_ALLOW_V << PMS_LP_MM_HP_SYS_REG_ALLOW_S) +#define PMS_LP_MM_HP_SYS_REG_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_SYS_REG_ALLOW_S 3 +/** PMS_LP_MM_HP_CLKRST_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP_CLKRST_ALLOW (BIT(4)) +#define PMS_LP_MM_HP_CLKRST_ALLOW_M (PMS_LP_MM_HP_CLKRST_ALLOW_V << PMS_LP_MM_HP_CLKRST_ALLOW_S) +#define PMS_LP_MM_HP_CLKRST_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP_CLKRST_ALLOW_S 4 #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_struct.h b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_struct.h index 59ee73ee1c1..8f852dc7aea 100644 --- a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_struct.h +++ b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,398 +10,574 @@ extern "C" { #endif -/** Group: TEE LP2HP PMS DATE REG */ -/** Type of lp2hp_pms_date register - * NA +/** Group: Version Control Registers */ +/** Type of lp2hp_peri_pms_date register + * Version control register */ typedef union { struct { - /** tee_date : R/W; bitpos: [31:0]; default: 2294790; - * NA + /** lp2hp_peri_pms_date : R/W; bitpos: [31:0]; default: 2294790; + * Version control register. */ - uint32_t tee_date:32; + uint32_t lp2hp_peri_pms_date:32; }; uint32_t val; -} tee_lp2hp_pms_date_reg_t; +} pms_lp2hp_peri_pms_date_reg_t; -/** Group: TEE PMS CLK EN REG */ -/** Type of pms_clk_en register - * NA +/** Group: Clock Gating Registers */ +/** Type of lp2hp_peri_pms_clk_en register + * Clock gating register */ typedef union { struct { - /** reg_clk_en : R/W; bitpos: [0]; default: 1; - * NA + /** lp2hp_peri_pms_clk_en : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating. + * 1: Keep the clock always on. */ - uint32_t reg_clk_en:1; + uint32_t lp2hp_peri_pms_clk_en:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_pms_clk_en_reg_t; +} pms_lp2hp_peri_pms_clk_en_reg_t; -/** Group: TEE LP MM PMS REG0 REG */ +/** Group: LP CPU Permission Control Registers */ /** Type of lp_mm_pms_reg0 register - * NA + * Permission control register0 for the LP CPU in machine mode */ typedef union { struct { - /** reg_lp_mm_psram_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_lp_mm_psram_allow:1; - /** reg_lp_mm_flash_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_lp_mm_flash_allow:1; - /** reg_lp_mm_l2mem_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_lp_mm_l2mem_allow:1; - /** reg_lp_mm_l2rom_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_lp_mm_l2rom_allow:1; + /** lp_mm_psram_allow : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access external RAM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_psram_allow:1; + /** lp_mm_flash_allow : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access external + * flash without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_flash_allow:1; + /** lp_mm_l2mem_allow : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP L2M2M + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_l2mem_allow:1; + /** lp_mm_l2rom_allow : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ROM + * without going through cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_l2rom_allow:1; uint32_t reserved_4:2; - /** reg_lp_mm_trace0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_lp_mm_trace0_allow:1; - /** reg_lp_mm_trace1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_lp_mm_trace1_allow:1; - /** reg_lp_mm_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_lp_mm_cpu_bus_mon_allow:1; - /** reg_lp_mm_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_lp_mm_l2mem_mon_allow:1; - /** reg_lp_mm_tcm_mon_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_lp_mm_tcm_mon_allow:1; - /** reg_lp_mm_cache_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_lp_mm_cache_allow:1; + /** lp_mm_trace0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TRACE0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_trace0_allow:1; + /** lp_mm_trace1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TRACE1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_trace1_allow:1; + /** lp_mm_cpu_bus_mon_allow : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access CPU bus + * monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_cpu_bus_mon_allow:1; + /** lp_mm_l2mem_mon_allow : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access L2MEM + * monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_l2mem_mon_allow:1; + /** lp_mm_tcm_mon_allow : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access TCM monitor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_tcm_mon_allow:1; + /** lp_mm_cache_allow : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access cache. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_cache_allow:1; uint32_t reserved_12:20; }; uint32_t val; -} tee_lp_mm_pms_reg0_reg_t; +} pms_lp_mm_pms_reg0_reg_t; - -/** Group: TEE LP MM PMS REG1 REG */ /** Type of lp_mm_pms_reg1 register - * NA + * Permission control register1 for the LP CPU in machine mode */ typedef union { struct { - /** reg_lp_mm_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_usbotg_allow:1; - /** reg_lp_mm_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_usbotg11_allow:1; - /** reg_lp_mm_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_usbotg11_wrap_allow:1; - /** reg_lp_mm_hp_gdma_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_gdma_allow:1; - /** reg_lp_mm_hp_regdma_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_regdma_allow:1; - /** reg_lp_mm_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_sdmmc_allow:1; - /** reg_lp_mm_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_ahb_pdma_allow:1; - /** reg_lp_mm_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_jpeg_allow:1; - /** reg_lp_mm_hp_ppa_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_ppa_allow:1; - /** reg_lp_mm_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_dma2d_allow:1; - /** reg_lp_mm_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_key_manager_allow:1; - /** reg_lp_mm_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_axi_pdma_allow:1; - /** reg_lp_mm_hp_flash_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_flash_allow:1; - /** reg_lp_mm_hp_psram_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_psram_allow:1; - /** reg_lp_mm_hp_crypto_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_crypto_allow:1; - /** reg_lp_mm_hp_gmac_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_gmac_allow:1; - /** reg_lp_mm_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_usb_phy_allow:1; - /** reg_lp_mm_hp_pvt_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_pvt_allow:1; - /** reg_lp_mm_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_csi_host_allow:1; - /** reg_lp_mm_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_dsi_host_allow:1; - /** reg_lp_mm_hp_isp_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_isp_allow:1; - /** reg_lp_mm_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_h264_core_allow:1; - /** reg_lp_mm_hp_rmt_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_rmt_allow:1; - /** reg_lp_mm_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_bitsrambler_allow:1; - /** reg_lp_mm_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_axi_icm_allow:1; - /** reg_lp_mm_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_peri_pms_allow:1; - /** reg_lp_mm_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp2hp_peri_pms_allow:1; - /** reg_lp_mm_dma_pms_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_lp_mm_dma_pms_allow:1; - /** reg_lp_mm_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_h264_dma2d_allow:1; + /** lp_mm_hp_usbotg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * high-speed USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_usbotg_allow:1; + /** lp_mm_hp_usbotg11_allow : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * full-speed USB 2.0 OTG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_usbotg11_allow:1; + /** lp_mm_hp_usbotg11_wrap_allow : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * full-speed USB 2.0 OTG's wrap. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_usbotg11_wrap_allow:1; + /** lp_mm_hp_gdma_allow : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP DW-GDMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_gdma_allow:1; + /** lp_mm_hp_regdma_allow : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GDMA (DW + * GDMA). + * 0: Not allowed + * 1: Allow + */ + uint32_t lp_mm_hp_regdma_allow:1; + /** lp_mm_hp_sdmmc_allow : R/W; bitpos: [5]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP SDMMC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_sdmmc_allow:1; + /** lp_mm_hp_ahb_pdma_allow : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access GDMA-AHB. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_ahb_pdma_allow:1; + /** lp_mm_hp_jpeg_allow : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP JPEG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_jpeg_allow:1; + /** lp_mm_hp_ppa_allow : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PPA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_ppa_allow:1; + /** lp_mm_hp_dma2d_allow : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_dma2d_allow:1; + /** lp_mm_hp_key_manager_allow : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP key + * manager. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_key_manager_allow:1; + /** lp_mm_hp_axi_pdma_allow : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GDMA-AXI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_axi_pdma_allow:1; + /** lp_mm_hp_flash_allow : R/W; bitpos: [12]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP flash + * MSPI controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_flash_allow:1; + /** lp_mm_hp_psram_allow : R/W; bitpos: [13]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PSRAM + * MSPI controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_psram_allow:1; + /** lp_mm_hp_crypto_allow : R/W; bitpos: [14]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP CRYPTO. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_crypto_allow:1; + /** lp_mm_hp_gmac_allow : R/W; bitpos: [15]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP EMAC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_gmac_allow:1; + /** lp_mm_hp_usb_phy_allow : R/W; bitpos: [16]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * high-speed USB 2.0 OTG PHY. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_usb_phy_allow:1; + /** lp_mm_hp_pvt_allow : R/W; bitpos: [17]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PVT. + * 0: Not allowed + * 1: Allow + */ + uint32_t lp_mm_hp_pvt_allow:1; + /** lp_mm_hp_csi_host_allow : R/W; bitpos: [18]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MIPI CSI + * host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_csi_host_allow:1; + /** lp_mm_hp_dsi_host_allow : R/W; bitpos: [19]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MIPI DSI + * host. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_dsi_host_allow:1; + /** lp_mm_hp_isp_allow : R/W; bitpos: [20]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ISP. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_isp_allow:1; + /** lp_mm_hp_h264_core_allow : R/W; bitpos: [21]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP H264 + * Encoder. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_h264_core_allow:1; + /** lp_mm_hp_rmt_allow : R/W; bitpos: [22]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP RMT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_rmt_allow:1; + /** lp_mm_hp_bitsrambler_allow : R/W; bitpos: [23]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP bit + * scrambler. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_bitsrambler_allow:1; + /** lp_mm_hp_axi_icm_allow : R/W; bitpos: [24]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP AXI ICM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_axi_icm_allow:1; + /** lp_mm_hp_peri_pms_allow : R/W; bitpos: [25]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_peri_pms_allow:1; + /** lp_mm_lp2hp_peri_pms_allow : R/W; bitpos: [26]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * LP2HP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp2hp_peri_pms_allow:1; + /** lp_mm_dma_pms_allow : R/W; bitpos: [27]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_DMA_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_dma_pms_allow:1; + /** lp_mm_hp_h264_dma2d_allow : R/W; bitpos: [28]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access 2D-DMA. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_h264_dma2d_allow:1; uint32_t reserved_29:3; }; uint32_t val; -} tee_lp_mm_pms_reg1_reg_t; - +} pms_lp_mm_pms_reg1_reg_t; -/** Group: TEE LP MM PMS REG2 REG */ /** Type of lp_mm_pms_reg2 register - * NA + * Permission control register2 for the LP CPU in machine mode */ typedef union { struct { - /** reg_lp_mm_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_mcpwm0_allow:1; - /** reg_lp_mm_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_mcpwm1_allow:1; - /** reg_lp_mm_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_timer_group0_allow:1; - /** reg_lp_mm_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_timer_group1_allow:1; - /** reg_lp_mm_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i2c0_allow:1; - /** reg_lp_mm_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i2c1_allow:1; - /** reg_lp_mm_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i2s0_allow:1; - /** reg_lp_mm_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i2s1_allow:1; - /** reg_lp_mm_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i2s2_allow:1; - /** reg_lp_mm_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_pcnt_allow:1; - /** reg_lp_mm_hp_uart0_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uart0_allow:1; - /** reg_lp_mm_hp_uart1_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uart1_allow:1; - /** reg_lp_mm_hp_uart2_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uart2_allow:1; - /** reg_lp_mm_hp_uart3_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uart3_allow:1; - /** reg_lp_mm_hp_uart4_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uart4_allow:1; - /** reg_lp_mm_hp_parlio_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_parlio_allow:1; - /** reg_lp_mm_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_gpspi2_allow:1; - /** reg_lp_mm_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_gpspi3_allow:1; - /** reg_lp_mm_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_usbdevice_allow:1; - /** reg_lp_mm_hp_ledc_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_ledc_allow:1; + /** lp_mm_hp_mcpwm0_allow : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MCPWM0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_mcpwm0_allow:1; + /** lp_mm_hp_mcpwm1_allow : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP MCPWM1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_mcpwm1_allow:1; + /** lp_mm_hp_timer_group0_allow : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP timer + * group0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_timer_group0_allow:1; + /** lp_mm_hp_timer_group1_allow : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP timer + * group1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_timer_group1_allow:1; + /** lp_mm_hp_i2c0_allow : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2C0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i2c0_allow:1; + /** lp_mm_hp_i2c1_allow : R/W; bitpos: [5]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2C1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i2c1_allow:1; + /** lp_mm_hp_i2s0_allow : R/W; bitpos: [6]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i2s0_allow:1; + /** lp_mm_hp_i2s1_allow : R/W; bitpos: [7]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i2s1_allow:1; + /** lp_mm_hp_i2s2_allow : R/W; bitpos: [8]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I2S2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i2s2_allow:1; + /** lp_mm_hp_pcnt_allow : R/W; bitpos: [9]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PCNT. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_pcnt_allow:1; + /** lp_mm_hp_uart0_allow : R/W; bitpos: [10]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uart0_allow:1; + /** lp_mm_hp_uart1_allow : R/W; bitpos: [11]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uart1_allow:1; + /** lp_mm_hp_uart2_allow : R/W; bitpos: [12]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uart2_allow:1; + /** lp_mm_hp_uart3_allow : R/W; bitpos: [13]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uart3_allow:1; + /** lp_mm_hp_uart4_allow : R/W; bitpos: [14]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UART4. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uart4_allow:1; + /** lp_mm_hp_parlio_allow : R/W; bitpos: [15]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP PARLIO. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_parlio_allow:1; + /** lp_mm_hp_gpspi2_allow : R/W; bitpos: [16]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GP-SPI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_gpspi2_allow:1; + /** lp_mm_hp_gpspi3_allow : R/W; bitpos: [17]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GP-SPI3. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_gpspi3_allow:1; + /** lp_mm_hp_usbdevice_allow : R/W; bitpos: [18]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP + * USB/Serial JTAG Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_usbdevice_allow:1; + /** lp_mm_hp_ledc_allow : R/W; bitpos: [19]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP LEDC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_ledc_allow:1; uint32_t reserved_20:1; - /** reg_lp_mm_hp_etm_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_etm_allow:1; - /** reg_lp_mm_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_intrmtx_allow:1; - /** reg_lp_mm_hp_twai0_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_twai0_allow:1; - /** reg_lp_mm_hp_twai1_allow : R/W; bitpos: [24]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_twai1_allow:1; - /** reg_lp_mm_hp_twai2_allow : R/W; bitpos: [25]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_twai2_allow:1; - /** reg_lp_mm_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i3c_mst_allow:1; - /** reg_lp_mm_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_i3c_slv_allow:1; - /** reg_lp_mm_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_lcdcam_allow:1; + /** lp_mm_hp_etm_allow : R/W; bitpos: [21]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ETM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_etm_allow:1; + /** lp_mm_hp_intrmtx_allow : R/W; bitpos: [22]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP interrupt + * matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_intrmtx_allow:1; + /** lp_mm_hp_twai0_allow : R/W; bitpos: [23]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI0. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_twai0_allow:1; + /** lp_mm_hp_twai1_allow : R/W; bitpos: [24]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI1. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_twai1_allow:1; + /** lp_mm_hp_twai2_allow : R/W; bitpos: [25]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP TWAI2. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_twai2_allow:1; + /** lp_mm_hp_i3c_mst_allow : R/W; bitpos: [26]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I3C + * master controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i3c_mst_allow:1; + /** lp_mm_hp_i3c_slv_allow : R/W; bitpos: [27]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP I3C slave + * controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_i3c_slv_allow:1; + /** lp_mm_hp_lcdcam_allow : R/W; bitpos: [28]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP LCD_CAM. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_lcdcam_allow:1; uint32_t reserved_29:1; - /** reg_lp_mm_hp_adc_allow : R/W; bitpos: [30]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_adc_allow:1; - /** reg_lp_mm_hp_uhci_allow : R/W; bitpos: [31]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_uhci_allow:1; + /** lp_mm_hp_adc_allow : R/W; bitpos: [30]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_adc_allow:1; + /** lp_mm_hp_uhci_allow : R/W; bitpos: [31]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP UHCI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_uhci_allow:1; }; uint32_t val; -} tee_lp_mm_pms_reg2_reg_t; +} pms_lp_mm_pms_reg2_reg_t; - -/** Group: TEE LP MM PMS REG3 REG */ /** Type of lp_mm_pms_reg3 register - * NA + * Permission control register3 for the LP CPU in machine mode */ typedef union { struct { - /** reg_lp_mm_hp_gpio_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_gpio_allow:1; - /** reg_lp_mm_hp_iomux_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_iomux_allow:1; - /** reg_lp_mm_hp_systimer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_systimer_allow:1; - /** reg_lp_mm_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_sys_reg_allow:1; - /** reg_lp_mm_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp_clkrst_allow:1; + /** lp_mm_hp_gpio_allow : R/W; bitpos: [0]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP GPIO + * Matrix. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_gpio_allow:1; + /** lp_mm_hp_iomux_allow : R/W; bitpos: [1]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_iomux_allow:1; + /** lp_mm_hp_systimer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP system + * timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_systimer_allow:1; + /** lp_mm_hp_sys_reg_allow : R/W; bitpos: [3]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access HP system + * register. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_sys_reg_allow:1; + /** lp_mm_hp_clkrst_allow : R/W; bitpos: [4]; default: 1; + * Configures whether the LP CPU in machine mode has permission to access + * HP_SYS_CLKRST. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp_clkrst_allow:1; uint32_t reserved_5:27; }; uint32_t val; -} tee_lp_mm_pms_reg3_reg_t; +} pms_lp_mm_pms_reg3_reg_t; typedef struct { - volatile tee_lp2hp_pms_date_reg_t lp2hp_pms_date; - volatile tee_pms_clk_en_reg_t pms_clk_en; - volatile tee_lp_mm_pms_reg0_reg_t lp_mm_pms_reg0; + volatile pms_lp2hp_peri_pms_date_reg_t lp2hp_peri_pms_date; + volatile pms_lp2hp_peri_pms_clk_en_reg_t lp2hp_peri_pms_clk_en; + volatile pms_lp_mm_pms_reg0_reg_t lp_mm_pms_reg0; uint32_t reserved_00c[9]; - volatile tee_lp_mm_pms_reg1_reg_t lp_mm_pms_reg1; + volatile pms_lp_mm_pms_reg1_reg_t lp_mm_pms_reg1; uint32_t reserved_034[28]; - volatile tee_lp_mm_pms_reg2_reg_t lp_mm_pms_reg2; + volatile pms_lp_mm_pms_reg2_reg_t lp_mm_pms_reg2; uint32_t reserved_0a8[29]; - volatile tee_lp_mm_pms_reg3_reg_t lp_mm_pms_reg3; -} tee_dev_t; + volatile pms_lp_mm_pms_reg3_reg_t lp_mm_pms_reg3; +} lp2hp_peri_pms_dev_t; +extern lp2hp_peri_pms_dev_t LP2HP_PERI_PMS; #ifndef __cplusplus -_Static_assert(sizeof(tee_dev_t) == 0x120, "Invalid size of tee_dev_t structure"); +_Static_assert(sizeof(lp2hp_peri_pms_dev_t) == 0x120, "Invalid size of lp2hp_peri_pms_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h index 37c84db8f90..f95a5a3b853 100644 --- a/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,290 +11,366 @@ extern "C" { #endif -/** TEE_PMS_DATE_REG register - * NA +/** PMS_LP_PERI_PMS_DATE_REG register + * Version control register */ -#define TEE_PMS_DATE_REG (DR_REG_TEE_BASE + 0x0) -/** TEE_TEE_DATE : R/W; bitpos: [31:0]; default: 2294537; - * NA +#define PMS_LP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +/** PMS_LP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294537; + * Version control register */ -#define TEE_TEE_DATE 0xFFFFFFFFU -#define TEE_TEE_DATE_M (TEE_TEE_DATE_V << TEE_TEE_DATE_S) -#define TEE_TEE_DATE_V 0xFFFFFFFFU -#define TEE_TEE_DATE_S 0 +#define PMS_LP_PERI_PMS_DATE 0xFFFFFFFFU +#define PMS_LP_PERI_PMS_DATE_M (PMS_LP_PERI_PMS_DATE_V << PMS_LP_PERI_PMS_DATE_S) +#define PMS_LP_PERI_PMS_DATE_V 0xFFFFFFFFU +#define PMS_LP_PERI_PMS_DATE_S 0 -/** TEE_PMS_CLK_EN_REG register - * NA - */ -#define TEE_PMS_CLK_EN_REG (DR_REG_TEE_BASE + 0x4) -/** TEE_REG_CLK_EN : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_CLK_EN (BIT(0)) -#define TEE_REG_CLK_EN_M (TEE_REG_CLK_EN_V << TEE_REG_CLK_EN_S) -#define TEE_REG_CLK_EN_V 0x00000001U -#define TEE_REG_CLK_EN_S 0 +/** PMS_LP_PERI_PMS_CLK_EN_REG register + * Clock gating register + */ +#define PMS_LP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +/** PMS_LP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on + */ +#define PMS_LP_PERI_PMS_CLK_EN (BIT(0)) +#define PMS_LP_PERI_PMS_CLK_EN_M (PMS_LP_PERI_PMS_CLK_EN_V << PMS_LP_PERI_PMS_CLK_EN_S) +#define PMS_LP_PERI_PMS_CLK_EN_V 0x00000001U +#define PMS_LP_PERI_PMS_CLK_EN_S 0 -/** TEE_LP_MM_PMS_REG0_REG register - * NA - */ -#define TEE_LP_MM_PMS_REG0_REG (DR_REG_TEE_BASE + 0x8) -/** TEE_REG_LP_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_SYSREG_ALLOW (BIT(0)) -#define TEE_REG_LP_MM_LP_SYSREG_ALLOW_M (TEE_REG_LP_MM_LP_SYSREG_ALLOW_V << TEE_REG_LP_MM_LP_SYSREG_ALLOW_S) -#define TEE_REG_LP_MM_LP_SYSREG_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_SYSREG_ALLOW_S 0 -/** TEE_REG_LP_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_AONCLKRST_ALLOW (BIT(1)) -#define TEE_REG_LP_MM_LP_AONCLKRST_ALLOW_M (TEE_REG_LP_MM_LP_AONCLKRST_ALLOW_V << TEE_REG_LP_MM_LP_AONCLKRST_ALLOW_S) -#define TEE_REG_LP_MM_LP_AONCLKRST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_AONCLKRST_ALLOW_S 1 -/** TEE_REG_LP_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_TIMER_ALLOW (BIT(2)) -#define TEE_REG_LP_MM_LP_TIMER_ALLOW_M (TEE_REG_LP_MM_LP_TIMER_ALLOW_V << TEE_REG_LP_MM_LP_TIMER_ALLOW_S) -#define TEE_REG_LP_MM_LP_TIMER_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_TIMER_ALLOW_S 2 -/** TEE_REG_LP_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_ANAPERI_ALLOW (BIT(3)) -#define TEE_REG_LP_MM_LP_ANAPERI_ALLOW_M (TEE_REG_LP_MM_LP_ANAPERI_ALLOW_V << TEE_REG_LP_MM_LP_ANAPERI_ALLOW_S) -#define TEE_REG_LP_MM_LP_ANAPERI_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_ANAPERI_ALLOW_S 3 -/** TEE_REG_LP_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_PMU_ALLOW (BIT(4)) -#define TEE_REG_LP_MM_LP_PMU_ALLOW_M (TEE_REG_LP_MM_LP_PMU_ALLOW_V << TEE_REG_LP_MM_LP_PMU_ALLOW_S) -#define TEE_REG_LP_MM_LP_PMU_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_PMU_ALLOW_S 4 -/** TEE_REG_LP_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_WDT_ALLOW (BIT(5)) -#define TEE_REG_LP_MM_LP_WDT_ALLOW_M (TEE_REG_LP_MM_LP_WDT_ALLOW_V << TEE_REG_LP_MM_LP_WDT_ALLOW_S) -#define TEE_REG_LP_MM_LP_WDT_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_WDT_ALLOW_S 5 -/** TEE_REG_LP_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_MAILBOX_ALLOW (BIT(6)) -#define TEE_REG_LP_MM_LP_MAILBOX_ALLOW_M (TEE_REG_LP_MM_LP_MAILBOX_ALLOW_V << TEE_REG_LP_MM_LP_MAILBOX_ALLOW_S) -#define TEE_REG_LP_MM_LP_MAILBOX_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_MAILBOX_ALLOW_S 6 -/** TEE_REG_LP_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_RTC_ALLOW (BIT(7)) -#define TEE_REG_LP_MM_LP_RTC_ALLOW_M (TEE_REG_LP_MM_LP_RTC_ALLOW_V << TEE_REG_LP_MM_LP_RTC_ALLOW_S) -#define TEE_REG_LP_MM_LP_RTC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_RTC_ALLOW_S 7 -/** TEE_REG_LP_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_PERICLKRST_ALLOW (BIT(8)) -#define TEE_REG_LP_MM_LP_PERICLKRST_ALLOW_M (TEE_REG_LP_MM_LP_PERICLKRST_ALLOW_V << TEE_REG_LP_MM_LP_PERICLKRST_ALLOW_S) -#define TEE_REG_LP_MM_LP_PERICLKRST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_PERICLKRST_ALLOW_S 8 -/** TEE_REG_LP_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_UART_ALLOW (BIT(9)) -#define TEE_REG_LP_MM_LP_UART_ALLOW_M (TEE_REG_LP_MM_LP_UART_ALLOW_V << TEE_REG_LP_MM_LP_UART_ALLOW_S) -#define TEE_REG_LP_MM_LP_UART_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_UART_ALLOW_S 9 -/** TEE_REG_LP_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_I2C_ALLOW (BIT(10)) -#define TEE_REG_LP_MM_LP_I2C_ALLOW_M (TEE_REG_LP_MM_LP_I2C_ALLOW_V << TEE_REG_LP_MM_LP_I2C_ALLOW_S) -#define TEE_REG_LP_MM_LP_I2C_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_I2C_ALLOW_S 10 -/** TEE_REG_LP_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_SPI_ALLOW (BIT(11)) -#define TEE_REG_LP_MM_LP_SPI_ALLOW_M (TEE_REG_LP_MM_LP_SPI_ALLOW_V << TEE_REG_LP_MM_LP_SPI_ALLOW_S) -#define TEE_REG_LP_MM_LP_SPI_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_SPI_ALLOW_S 11 -/** TEE_REG_LP_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_I2CMST_ALLOW (BIT(12)) -#define TEE_REG_LP_MM_LP_I2CMST_ALLOW_M (TEE_REG_LP_MM_LP_I2CMST_ALLOW_V << TEE_REG_LP_MM_LP_I2CMST_ALLOW_S) -#define TEE_REG_LP_MM_LP_I2CMST_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_I2CMST_ALLOW_S 12 -/** TEE_REG_LP_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_I2S_ALLOW (BIT(13)) -#define TEE_REG_LP_MM_LP_I2S_ALLOW_M (TEE_REG_LP_MM_LP_I2S_ALLOW_V << TEE_REG_LP_MM_LP_I2S_ALLOW_S) -#define TEE_REG_LP_MM_LP_I2S_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_I2S_ALLOW_S 13 -/** TEE_REG_LP_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_ADC_ALLOW (BIT(14)) -#define TEE_REG_LP_MM_LP_ADC_ALLOW_M (TEE_REG_LP_MM_LP_ADC_ALLOW_V << TEE_REG_LP_MM_LP_ADC_ALLOW_S) -#define TEE_REG_LP_MM_LP_ADC_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_ADC_ALLOW_S 14 -/** TEE_REG_LP_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_TOUCH_ALLOW (BIT(15)) -#define TEE_REG_LP_MM_LP_TOUCH_ALLOW_M (TEE_REG_LP_MM_LP_TOUCH_ALLOW_V << TEE_REG_LP_MM_LP_TOUCH_ALLOW_S) -#define TEE_REG_LP_MM_LP_TOUCH_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_TOUCH_ALLOW_S 15 -/** TEE_REG_LP_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_IOMUX_ALLOW (BIT(16)) -#define TEE_REG_LP_MM_LP_IOMUX_ALLOW_M (TEE_REG_LP_MM_LP_IOMUX_ALLOW_V << TEE_REG_LP_MM_LP_IOMUX_ALLOW_S) -#define TEE_REG_LP_MM_LP_IOMUX_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_IOMUX_ALLOW_S 16 -/** TEE_REG_LP_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_INTR_ALLOW (BIT(17)) -#define TEE_REG_LP_MM_LP_INTR_ALLOW_M (TEE_REG_LP_MM_LP_INTR_ALLOW_V << TEE_REG_LP_MM_LP_INTR_ALLOW_S) -#define TEE_REG_LP_MM_LP_INTR_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_INTR_ALLOW_S 17 -/** TEE_REG_LP_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_EFUSE_ALLOW (BIT(18)) -#define TEE_REG_LP_MM_LP_EFUSE_ALLOW_M (TEE_REG_LP_MM_LP_EFUSE_ALLOW_V << TEE_REG_LP_MM_LP_EFUSE_ALLOW_S) -#define TEE_REG_LP_MM_LP_EFUSE_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_EFUSE_ALLOW_S 18 -/** TEE_REG_LP_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_PMS_ALLOW (BIT(19)) -#define TEE_REG_LP_MM_LP_PMS_ALLOW_M (TEE_REG_LP_MM_LP_PMS_ALLOW_V << TEE_REG_LP_MM_LP_PMS_ALLOW_S) -#define TEE_REG_LP_MM_LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_PMS_ALLOW_S 19 -/** TEE_REG_LP_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_HP2LP_PMS_ALLOW (BIT(20)) -#define TEE_REG_LP_MM_HP2LP_PMS_ALLOW_M (TEE_REG_LP_MM_HP2LP_PMS_ALLOW_V << TEE_REG_LP_MM_HP2LP_PMS_ALLOW_S) -#define TEE_REG_LP_MM_HP2LP_PMS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_HP2LP_PMS_ALLOW_S 20 -/** TEE_REG_LP_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_TSENS_ALLOW (BIT(21)) -#define TEE_REG_LP_MM_LP_TSENS_ALLOW_M (TEE_REG_LP_MM_LP_TSENS_ALLOW_V << TEE_REG_LP_MM_LP_TSENS_ALLOW_S) -#define TEE_REG_LP_MM_LP_TSENS_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_TSENS_ALLOW_S 21 -/** TEE_REG_LP_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_HUK_ALLOW (BIT(22)) -#define TEE_REG_LP_MM_LP_HUK_ALLOW_M (TEE_REG_LP_MM_LP_HUK_ALLOW_V << TEE_REG_LP_MM_LP_HUK_ALLOW_S) -#define TEE_REG_LP_MM_LP_HUK_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_HUK_ALLOW_S 22 -/** TEE_REG_LP_MM_LP_TCM_RAM_ALLOW : R/W; bitpos: [23]; default: 1; - * NA - */ -#define TEE_REG_LP_MM_LP_TCM_RAM_ALLOW (BIT(23)) -#define TEE_REG_LP_MM_LP_TCM_RAM_ALLOW_M (TEE_REG_LP_MM_LP_TCM_RAM_ALLOW_V << TEE_REG_LP_MM_LP_TCM_RAM_ALLOW_S) -#define TEE_REG_LP_MM_LP_TCM_RAM_ALLOW_V 0x00000001U -#define TEE_REG_LP_MM_LP_TCM_RAM_ALLOW_S 23 +/** PMS_LP_MM_LP_PERI_PMS_REG0_REG register + * Permission control register0 for LP CPU in machine mode + */ +#define PMS_LP_MM_LP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +/** PMS_LP_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP system + * registers. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_SYSREG_ALLOW (BIT(0)) +#define PMS_LP_MM_LP_SYSREG_ALLOW_M (PMS_LP_MM_LP_SYSREG_ALLOW_V << PMS_LP_MM_LP_SYSREG_ALLOW_S) +#define PMS_LP_MM_LP_SYSREG_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_SYSREG_ALLOW_S 0 +/** PMS_LP_MM_LP_AONCLKRST_ALLOW : R/W; bitpos: [1]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP_AONCLKRST (LP + * always-on clock and reset). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_AONCLKRST_ALLOW (BIT(1)) +#define PMS_LP_MM_LP_AONCLKRST_ALLOW_M (PMS_LP_MM_LP_AONCLKRST_ALLOW_V << PMS_LP_MM_LP_AONCLKRST_ALLOW_S) +#define PMS_LP_MM_LP_AONCLKRST_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_AONCLKRST_ALLOW_S 1 +/** PMS_LP_MM_LP_TIMER_ALLOW : R/W; bitpos: [2]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_TIMER_ALLOW (BIT(2)) +#define PMS_LP_MM_LP_TIMER_ALLOW_M (PMS_LP_MM_LP_TIMER_ALLOW_V << PMS_LP_MM_LP_TIMER_ALLOW_S) +#define PMS_LP_MM_LP_TIMER_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_TIMER_ALLOW_S 2 +/** PMS_LP_MM_LP_ANAPERI_ALLOW : R/W; bitpos: [3]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP ANAPERI + * (analog peripherals). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_ANAPERI_ALLOW (BIT(3)) +#define PMS_LP_MM_LP_ANAPERI_ALLOW_M (PMS_LP_MM_LP_ANAPERI_ALLOW_V << PMS_LP_MM_LP_ANAPERI_ALLOW_S) +#define PMS_LP_MM_LP_ANAPERI_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_ANAPERI_ALLOW_S 3 +/** PMS_LP_MM_LP_PMU_ALLOW : R/W; bitpos: [4]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP PMU (Power + * Management Unit). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_PMU_ALLOW (BIT(4)) +#define PMS_LP_MM_LP_PMU_ALLOW_M (PMS_LP_MM_LP_PMU_ALLOW_V << PMS_LP_MM_LP_PMU_ALLOW_S) +#define PMS_LP_MM_LP_PMU_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_PMU_ALLOW_S 4 +/** PMS_LP_MM_LP_WDT_ALLOW : R/W; bitpos: [5]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP WDT (watchdog + * timer). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_WDT_ALLOW (BIT(5)) +#define PMS_LP_MM_LP_WDT_ALLOW_M (PMS_LP_MM_LP_WDT_ALLOW_V << PMS_LP_MM_LP_WDT_ALLOW_S) +#define PMS_LP_MM_LP_WDT_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_WDT_ALLOW_S 5 +/** PMS_LP_MM_LP_MAILBOX_ALLOW : R/W; bitpos: [6]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_MAILBOX_ALLOW (BIT(6)) +#define PMS_LP_MM_LP_MAILBOX_ALLOW_M (PMS_LP_MM_LP_MAILBOX_ALLOW_V << PMS_LP_MM_LP_MAILBOX_ALLOW_S) +#define PMS_LP_MM_LP_MAILBOX_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_MAILBOX_ALLOW_S 6 +/** PMS_LP_MM_LP_RTC_ALLOW : R/W; bitpos: [7]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ +#define PMS_LP_MM_LP_RTC_ALLOW (BIT(7)) +#define PMS_LP_MM_LP_RTC_ALLOW_M (PMS_LP_MM_LP_RTC_ALLOW_V << PMS_LP_MM_LP_RTC_ALLOW_S) +#define PMS_LP_MM_LP_RTC_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_RTC_ALLOW_S 7 +/** PMS_LP_MM_LP_PERICLKRST_ALLOW : R/W; bitpos: [8]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP PREICLKRST + * (peripheral clock and reset). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_PERICLKRST_ALLOW (BIT(8)) +#define PMS_LP_MM_LP_PERICLKRST_ALLOW_M (PMS_LP_MM_LP_PERICLKRST_ALLOW_V << PMS_LP_MM_LP_PERICLKRST_ALLOW_S) +#define PMS_LP_MM_LP_PERICLKRST_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_PERICLKRST_ALLOW_S 8 +/** PMS_LP_MM_LP_UART_ALLOW : R/W; bitpos: [9]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_UART_ALLOW (BIT(9)) +#define PMS_LP_MM_LP_UART_ALLOW_M (PMS_LP_MM_LP_UART_ALLOW_V << PMS_LP_MM_LP_UART_ALLOW_S) +#define PMS_LP_MM_LP_UART_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_UART_ALLOW_S 9 +/** PMS_LP_MM_LP_I2C_ALLOW : R/W; bitpos: [10]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_I2C_ALLOW (BIT(10)) +#define PMS_LP_MM_LP_I2C_ALLOW_M (PMS_LP_MM_LP_I2C_ALLOW_V << PMS_LP_MM_LP_I2C_ALLOW_S) +#define PMS_LP_MM_LP_I2C_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_I2C_ALLOW_S 10 +/** PMS_LP_MM_LP_SPI_ALLOW : R/W; bitpos: [11]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_SPI_ALLOW (BIT(11)) +#define PMS_LP_MM_LP_SPI_ALLOW_M (PMS_LP_MM_LP_SPI_ALLOW_V << PMS_LP_MM_LP_SPI_ALLOW_S) +#define PMS_LP_MM_LP_SPI_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_SPI_ALLOW_S 11 +/** PMS_LP_MM_LP_I2CMST_ALLOW : R/W; bitpos: [12]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_I2CMST_ALLOW (BIT(12)) +#define PMS_LP_MM_LP_I2CMST_ALLOW_M (PMS_LP_MM_LP_I2CMST_ALLOW_V << PMS_LP_MM_LP_I2CMST_ALLOW_S) +#define PMS_LP_MM_LP_I2CMST_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_I2CMST_ALLOW_S 12 +/** PMS_LP_MM_LP_I2S_ALLOW : R/W; bitpos: [13]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_I2S_ALLOW (BIT(13)) +#define PMS_LP_MM_LP_I2S_ALLOW_M (PMS_LP_MM_LP_I2S_ALLOW_V << PMS_LP_MM_LP_I2S_ALLOW_S) +#define PMS_LP_MM_LP_I2S_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_I2S_ALLOW_S 13 +/** PMS_LP_MM_LP_ADC_ALLOW : R/W; bitpos: [14]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_ADC_ALLOW (BIT(14)) +#define PMS_LP_MM_LP_ADC_ALLOW_M (PMS_LP_MM_LP_ADC_ALLOW_V << PMS_LP_MM_LP_ADC_ALLOW_S) +#define PMS_LP_MM_LP_ADC_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_ADC_ALLOW_S 14 +/** PMS_LP_MM_LP_TOUCH_ALLOW : R/W; bitpos: [15]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP touch sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_TOUCH_ALLOW (BIT(15)) +#define PMS_LP_MM_LP_TOUCH_ALLOW_M (PMS_LP_MM_LP_TOUCH_ALLOW_V << PMS_LP_MM_LP_TOUCH_ALLOW_S) +#define PMS_LP_MM_LP_TOUCH_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_TOUCH_ALLOW_S 15 +/** PMS_LP_MM_LP_IOMUX_ALLOW : R/W; bitpos: [16]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_IOMUX_ALLOW (BIT(16)) +#define PMS_LP_MM_LP_IOMUX_ALLOW_M (PMS_LP_MM_LP_IOMUX_ALLOW_V << PMS_LP_MM_LP_IOMUX_ALLOW_S) +#define PMS_LP_MM_LP_IOMUX_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_IOMUX_ALLOW_S 16 +/** PMS_LP_MM_LP_INTR_ALLOW : R/W; bitpos: [17]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP INTR + * (interrupt). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_INTR_ALLOW (BIT(17)) +#define PMS_LP_MM_LP_INTR_ALLOW_M (PMS_LP_MM_LP_INTR_ALLOW_V << PMS_LP_MM_LP_INTR_ALLOW_S) +#define PMS_LP_MM_LP_INTR_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_INTR_ALLOW_S 17 +/** PMS_LP_MM_LP_EFUSE_ALLOW : R/W; bitpos: [18]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_EFUSE_ALLOW (BIT(18)) +#define PMS_LP_MM_LP_EFUSE_ALLOW_M (PMS_LP_MM_LP_EFUSE_ALLOW_V << PMS_LP_MM_LP_EFUSE_ALLOW_S) +#define PMS_LP_MM_LP_EFUSE_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_EFUSE_ALLOW_S 18 +/** PMS_LP_MM_LP_PMS_ALLOW : R/W; bitpos: [19]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_PMS_ALLOW (BIT(19)) +#define PMS_LP_MM_LP_PMS_ALLOW_M (PMS_LP_MM_LP_PMS_ALLOW_V << PMS_LP_MM_LP_PMS_ALLOW_S) +#define PMS_LP_MM_LP_PMS_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_PMS_ALLOW_S 19 +/** PMS_LP_MM_HP2LP_PMS_ALLOW : R/W; bitpos: [20]; default: 1; + * Configures whether LP CPU in machine mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_HP2LP_PMS_ALLOW (BIT(20)) +#define PMS_LP_MM_HP2LP_PMS_ALLOW_M (PMS_LP_MM_HP2LP_PMS_ALLOW_V << PMS_LP_MM_HP2LP_PMS_ALLOW_S) +#define PMS_LP_MM_HP2LP_PMS_ALLOW_V 0x00000001U +#define PMS_LP_MM_HP2LP_PMS_ALLOW_S 20 +/** PMS_LP_MM_LP_TSENS_ALLOW : R/W; bitpos: [21]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_TSENS_ALLOW (BIT(21)) +#define PMS_LP_MM_LP_TSENS_ALLOW_M (PMS_LP_MM_LP_TSENS_ALLOW_V << PMS_LP_MM_LP_TSENS_ALLOW_S) +#define PMS_LP_MM_LP_TSENS_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_TSENS_ALLOW_S 21 +/** PMS_LP_MM_LP_HUK_ALLOW : R/W; bitpos: [22]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP HUK (Hardware + * Unique Key). + * 0: Not allowed + * 1: Allowed + */ +#define PMS_LP_MM_LP_HUK_ALLOW (BIT(22)) +#define PMS_LP_MM_LP_HUK_ALLOW_M (PMS_LP_MM_LP_HUK_ALLOW_V << PMS_LP_MM_LP_HUK_ALLOW_S) +#define PMS_LP_MM_LP_HUK_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_HUK_ALLOW_S 22 +/** PMS_LP_MM_LP_SRAM_ALLOW : R/W; bitpos: [23]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allow + */ +#define PMS_LP_MM_LP_SRAM_ALLOW (BIT(23)) +#define PMS_LP_MM_LP_SRAM_ALLOW_M (PMS_LP_MM_LP_SRAM_ALLOW_V << PMS_LP_MM_LP_SRAM_ALLOW_S) +#define PMS_LP_MM_LP_SRAM_ALLOW_V 0x00000001U +#define PMS_LP_MM_LP_SRAM_ALLOW_S 23 -/** TEE_PERI_REGION0_LOW_REG register - * NA +/** PMS_PERI_REGION0_LOW_REG register + * Region0 start address configuration register */ -#define TEE_PERI_REGION0_LOW_REG (DR_REG_TEE_BASE + 0xc) -/** TEE_REG_PERI_REGION0_LOW : R/W; bitpos: [31:2]; default: 0; - * NA +#define PMS_PERI_REGION0_LOW_REG (DR_REG_PMS_BASE + 0xc) +/** PMS_PERI_REGION0_LOW : R/W; bitpos: [31:2]; default: 0; + * Configures the high 30 bits of the start address of peripheral register's region0. */ -#define TEE_REG_PERI_REGION0_LOW 0x3FFFFFFFU -#define TEE_REG_PERI_REGION0_LOW_M (TEE_REG_PERI_REGION0_LOW_V << TEE_REG_PERI_REGION0_LOW_S) -#define TEE_REG_PERI_REGION0_LOW_V 0x3FFFFFFFU -#define TEE_REG_PERI_REGION0_LOW_S 2 +#define PMS_PERI_REGION0_LOW 0x3FFFFFFFU +#define PMS_PERI_REGION0_LOW_M (PMS_PERI_REGION0_LOW_V << PMS_PERI_REGION0_LOW_S) +#define PMS_PERI_REGION0_LOW_V 0x3FFFFFFFU +#define PMS_PERI_REGION0_LOW_S 2 -/** TEE_PERI_REGION0_HIGH_REG register - * NA +/** PMS_PERI_REGION0_HIGH_REG register + * Region0 end address configuration register */ -#define TEE_PERI_REGION0_HIGH_REG (DR_REG_TEE_BASE + 0x10) -/** TEE_REG_PERI_REGION0_HIGH : R/W; bitpos: [31:2]; default: 1073741823; - * NA +#define PMS_PERI_REGION0_HIGH_REG (DR_REG_PMS_BASE + 0x10) +/** PMS_PERI_REGION0_HIGH : R/W; bitpos: [31:2]; default: 1073741823; + * Configures the high 30 bits of the end address of peripheral register's region0. */ -#define TEE_REG_PERI_REGION0_HIGH 0x3FFFFFFFU -#define TEE_REG_PERI_REGION0_HIGH_M (TEE_REG_PERI_REGION0_HIGH_V << TEE_REG_PERI_REGION0_HIGH_S) -#define TEE_REG_PERI_REGION0_HIGH_V 0x3FFFFFFFU -#define TEE_REG_PERI_REGION0_HIGH_S 2 +#define PMS_PERI_REGION0_HIGH 0x3FFFFFFFU +#define PMS_PERI_REGION0_HIGH_M (PMS_PERI_REGION0_HIGH_V << PMS_PERI_REGION0_HIGH_S) +#define PMS_PERI_REGION0_HIGH_V 0x3FFFFFFFU +#define PMS_PERI_REGION0_HIGH_S 2 -/** TEE_PERI_REGION1_LOW_REG register - * NA +/** PMS_PERI_REGION1_LOW_REG register + * Region1 start address configuration register */ -#define TEE_PERI_REGION1_LOW_REG (DR_REG_TEE_BASE + 0x14) -/** TEE_REG_PERI_REGION1_LOW : R/W; bitpos: [31:2]; default: 0; - * NA +#define PMS_PERI_REGION1_LOW_REG (DR_REG_PMS_BASE + 0x14) +/** PMS_PERI_REGION1_LOW : R/W; bitpos: [31:2]; default: 0; + * Configures the high 30 bits of the start address of peripheral register's region1. */ -#define TEE_REG_PERI_REGION1_LOW 0x3FFFFFFFU -#define TEE_REG_PERI_REGION1_LOW_M (TEE_REG_PERI_REGION1_LOW_V << TEE_REG_PERI_REGION1_LOW_S) -#define TEE_REG_PERI_REGION1_LOW_V 0x3FFFFFFFU -#define TEE_REG_PERI_REGION1_LOW_S 2 +#define PMS_PERI_REGION1_LOW 0x3FFFFFFFU +#define PMS_PERI_REGION1_LOW_M (PMS_PERI_REGION1_LOW_V << PMS_PERI_REGION1_LOW_S) +#define PMS_PERI_REGION1_LOW_V 0x3FFFFFFFU +#define PMS_PERI_REGION1_LOW_S 2 -/** TEE_PERI_REGION1_HIGH_REG register - * NA +/** PMS_PERI_REGION1_HIGH_REG register + * Region1 end address configuration register */ -#define TEE_PERI_REGION1_HIGH_REG (DR_REG_TEE_BASE + 0x18) -/** TEE_REG_PERI_REGION1_HIGH : R/W; bitpos: [31:2]; default: 1073741823; - * NA +#define PMS_PERI_REGION1_HIGH_REG (DR_REG_PMS_BASE + 0x18) +/** PMS_PERI_REGION1_HIGH : R/W; bitpos: [31:2]; default: 1073741823; + * Configures the high 30 bits of the end address of peripheral register's region1. */ -#define TEE_REG_PERI_REGION1_HIGH 0x3FFFFFFFU -#define TEE_REG_PERI_REGION1_HIGH_M (TEE_REG_PERI_REGION1_HIGH_V << TEE_REG_PERI_REGION1_HIGH_S) -#define TEE_REG_PERI_REGION1_HIGH_V 0x3FFFFFFFU -#define TEE_REG_PERI_REGION1_HIGH_S 2 +#define PMS_PERI_REGION1_HIGH 0x3FFFFFFFU +#define PMS_PERI_REGION1_HIGH_M (PMS_PERI_REGION1_HIGH_V << PMS_PERI_REGION1_HIGH_S) +#define PMS_PERI_REGION1_HIGH_V 0x3FFFFFFFU +#define PMS_PERI_REGION1_HIGH_S 2 -/** TEE_PERI_REGION_PMS_REG register - * NA - */ -#define TEE_PERI_REGION_PMS_REG (DR_REG_TEE_BASE + 0x1c) -/** TEE_REG_LP_CORE_REGION_PMS : R/W; bitpos: [1:0]; default: 3; - * NA - */ -#define TEE_REG_LP_CORE_REGION_PMS 0x00000003U -#define TEE_REG_LP_CORE_REGION_PMS_M (TEE_REG_LP_CORE_REGION_PMS_V << TEE_REG_LP_CORE_REGION_PMS_S) -#define TEE_REG_LP_CORE_REGION_PMS_V 0x00000003U -#define TEE_REG_LP_CORE_REGION_PMS_S 0 -/** TEE_REG_HP_CORE0_UM_REGION_PMS : R/W; bitpos: [3:2]; default: 3; - * NA - */ -#define TEE_REG_HP_CORE0_UM_REGION_PMS 0x00000003U -#define TEE_REG_HP_CORE0_UM_REGION_PMS_M (TEE_REG_HP_CORE0_UM_REGION_PMS_V << TEE_REG_HP_CORE0_UM_REGION_PMS_S) -#define TEE_REG_HP_CORE0_UM_REGION_PMS_V 0x00000003U -#define TEE_REG_HP_CORE0_UM_REGION_PMS_S 2 -/** TEE_REG_HP_CORE0_MM_REGION_PMS : R/W; bitpos: [5:4]; default: 3; - * NA - */ -#define TEE_REG_HP_CORE0_MM_REGION_PMS 0x00000003U -#define TEE_REG_HP_CORE0_MM_REGION_PMS_M (TEE_REG_HP_CORE0_MM_REGION_PMS_V << TEE_REG_HP_CORE0_MM_REGION_PMS_S) -#define TEE_REG_HP_CORE0_MM_REGION_PMS_V 0x00000003U -#define TEE_REG_HP_CORE0_MM_REGION_PMS_S 4 -/** TEE_REG_HP_CORE1_UM_REGION_PMS : R/W; bitpos: [7:6]; default: 3; - * NA - */ -#define TEE_REG_HP_CORE1_UM_REGION_PMS 0x00000003U -#define TEE_REG_HP_CORE1_UM_REGION_PMS_M (TEE_REG_HP_CORE1_UM_REGION_PMS_V << TEE_REG_HP_CORE1_UM_REGION_PMS_S) -#define TEE_REG_HP_CORE1_UM_REGION_PMS_V 0x00000003U -#define TEE_REG_HP_CORE1_UM_REGION_PMS_S 6 -/** TEE_REG_HP_CORE1_MM_REGION_PMS : R/W; bitpos: [9:8]; default: 3; - * NA - */ -#define TEE_REG_HP_CORE1_MM_REGION_PMS 0x00000003U -#define TEE_REG_HP_CORE1_MM_REGION_PMS_M (TEE_REG_HP_CORE1_MM_REGION_PMS_V << TEE_REG_HP_CORE1_MM_REGION_PMS_S) -#define TEE_REG_HP_CORE1_MM_REGION_PMS_V 0x00000003U -#define TEE_REG_HP_CORE1_MM_REGION_PMS_S 8 +/** PMS_PERI_REGION_PMS_REG register + * Permission register of region + */ +#define PMS_PERI_REGION_PMS_REG (DR_REG_PMS_BASE + 0x1c) +/** PMS_LP_CORE_REGION_PMS : R/W; bitpos: [1:0]; default: 3; + * Configures whether LP core in machine mode has permission to access address region0 + * and address region1. Bit0 corresponds to region0 and bit1 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ +#define PMS_LP_CORE_REGION_PMS 0x00000003U +#define PMS_LP_CORE_REGION_PMS_M (PMS_LP_CORE_REGION_PMS_V << PMS_LP_CORE_REGION_PMS_S) +#define PMS_LP_CORE_REGION_PMS_V 0x00000003U +#define PMS_LP_CORE_REGION_PMS_S 0 +/** PMS_HP_CORE0_UM_REGION_PMS : R/W; bitpos: [3:2]; default: 3; + * Configures whether HP CPU0 in user mode has permission to access address region0 + * and address region1. Bit2 corresponds to region0 and bit3 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE0_UM_REGION_PMS 0x00000003U +#define PMS_HP_CORE0_UM_REGION_PMS_M (PMS_HP_CORE0_UM_REGION_PMS_V << PMS_HP_CORE0_UM_REGION_PMS_S) +#define PMS_HP_CORE0_UM_REGION_PMS_V 0x00000003U +#define PMS_HP_CORE0_UM_REGION_PMS_S 2 +/** PMS_HP_CORE0_MM_REGION_PMS : R/W; bitpos: [5:4]; default: 3; + * Configures whether HP CPU0 in machine mode has permission to access address region0 + * and address region1. Bit4 corresponds to region0 and bit5 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE0_MM_REGION_PMS 0x00000003U +#define PMS_HP_CORE0_MM_REGION_PMS_M (PMS_HP_CORE0_MM_REGION_PMS_V << PMS_HP_CORE0_MM_REGION_PMS_S) +#define PMS_HP_CORE0_MM_REGION_PMS_V 0x00000003U +#define PMS_HP_CORE0_MM_REGION_PMS_S 4 +/** PMS_HP_CORE1_UM_REGION_PMS : R/W; bitpos: [7:6]; default: 3; + * Configures whether HP CPU1 in user mode has permission to access address region0 + * and address region1. Bit6 corresponds to region0 and bit7 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE1_UM_REGION_PMS 0x00000003U +#define PMS_HP_CORE1_UM_REGION_PMS_M (PMS_HP_CORE1_UM_REGION_PMS_V << PMS_HP_CORE1_UM_REGION_PMS_S) +#define PMS_HP_CORE1_UM_REGION_PMS_V 0x00000003U +#define PMS_HP_CORE1_UM_REGION_PMS_S 6 +/** PMS_HP_CORE1_MM_REGION_PMS : R/W; bitpos: [9:8]; default: 3; + * Configures whether HP CPU1 in machine mode has permission to access address region0 + * and address region1. Bit8 corresponds to region0 and bit9 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ +#define PMS_HP_CORE1_MM_REGION_PMS 0x00000003U +#define PMS_HP_CORE1_MM_REGION_PMS_M (PMS_HP_CORE1_MM_REGION_PMS_V << PMS_HP_CORE1_MM_REGION_PMS_S) +#define PMS_HP_CORE1_MM_REGION_PMS_V 0x00000003U +#define PMS_HP_CORE1_MM_REGION_PMS_S 8 #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/lp_peri_pms_struct.h b/components/soc/esp32p4/include/soc/lp_peri_pms_struct.h index 1e2c83e59e1..90ab5323b53 100644 --- a/components/soc/esp32p4/include/soc/lp_peri_pms_struct.h +++ b/components/soc/esp32p4/include/soc/lp_peri_pms_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,255 +10,298 @@ extern "C" { #endif -/** Group: TEE PMS DATE REG */ -/** Type of pms_date register - * NA +/** Group: Version Control Registers */ +/** Type of lp_peri_pms_date register + * Version control register */ typedef union { struct { - /** tee_date : R/W; bitpos: [31:0]; default: 2294537; - * NA + /** lp_peri_pms_date : R/W; bitpos: [31:0]; default: 2294537; + * Version control register */ - uint32_t tee_date:32; + uint32_t lp_peri_pms_date:32; }; uint32_t val; -} tee_pms_date_reg_t; +} pms_lp_peri_pms_date_reg_t; -/** Group: TEE PMS CLK EN REG */ -/** Type of pms_clk_en register - * NA +/** Group: Clock Gating Registers */ +/** Type of lp_peri_pms_clk_en register + * Clock gating register */ typedef union { struct { - /** reg_clk_en : R/W; bitpos: [0]; default: 1; - * NA + /** lp_peri_pms_clk_en : R/W; bitpos: [0]; default: 1; + * Configures whether to keep the clock always on. + * 0: Enable automatic clock gating + * 1: Keep the clock always on */ - uint32_t reg_clk_en:1; + uint32_t lp_peri_pms_clk_en:1; uint32_t reserved_1:31; }; uint32_t val; -} tee_pms_clk_en_reg_t; +} pms_lp_peri_pms_clk_en_reg_t; -/** Group: TEE LP MM PMS REG0 REG */ -/** Type of lp_mm_pms_reg0 register - * NA +/** Group: LP CPU Permission Control Registers */ +/** Type of lp_mm_lp_peri_pms_reg0 register + * Permission control register0 for LP CPU in machine mode */ typedef union { struct { - /** reg_lp_mm_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_sysreg_allow:1; - /** reg_lp_mm_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_aonclkrst_allow:1; - /** reg_lp_mm_lp_timer_allow : R/W; bitpos: [2]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_timer_allow:1; - /** reg_lp_mm_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_anaperi_allow:1; - /** reg_lp_mm_lp_pmu_allow : R/W; bitpos: [4]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_pmu_allow:1; - /** reg_lp_mm_lp_wdt_allow : R/W; bitpos: [5]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_wdt_allow:1; - /** reg_lp_mm_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_mailbox_allow:1; - /** reg_lp_mm_lp_rtc_allow : R/W; bitpos: [7]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_rtc_allow:1; - /** reg_lp_mm_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_periclkrst_allow:1; - /** reg_lp_mm_lp_uart_allow : R/W; bitpos: [9]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_uart_allow:1; - /** reg_lp_mm_lp_i2c_allow : R/W; bitpos: [10]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_i2c_allow:1; - /** reg_lp_mm_lp_spi_allow : R/W; bitpos: [11]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_spi_allow:1; - /** reg_lp_mm_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_i2cmst_allow:1; - /** reg_lp_mm_lp_i2s_allow : R/W; bitpos: [13]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_i2s_allow:1; - /** reg_lp_mm_lp_adc_allow : R/W; bitpos: [14]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_adc_allow:1; - /** reg_lp_mm_lp_touch_allow : R/W; bitpos: [15]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_touch_allow:1; - /** reg_lp_mm_lp_iomux_allow : R/W; bitpos: [16]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_iomux_allow:1; - /** reg_lp_mm_lp_intr_allow : R/W; bitpos: [17]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_intr_allow:1; - /** reg_lp_mm_lp_efuse_allow : R/W; bitpos: [18]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_efuse_allow:1; - /** reg_lp_mm_lp_pms_allow : R/W; bitpos: [19]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_pms_allow:1; - /** reg_lp_mm_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; - * NA - */ - uint32_t reg_lp_mm_hp2lp_pms_allow:1; - /** reg_lp_mm_lp_tsens_allow : R/W; bitpos: [21]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_tsens_allow:1; - /** reg_lp_mm_lp_huk_allow : R/W; bitpos: [22]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_huk_allow:1; - /** reg_lp_mm_lp_tcm_ram_allow : R/W; bitpos: [23]; default: 1; - * NA - */ - uint32_t reg_lp_mm_lp_tcm_ram_allow:1; + /** lp_mm_lp_sysreg_allow : R/W; bitpos: [0]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP system + * registers. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_sysreg_allow:1; + /** lp_mm_lp_aonclkrst_allow : R/W; bitpos: [1]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP_AONCLKRST (LP + * always-on clock and reset). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_aonclkrst_allow:1; + /** lp_mm_lp_timer_allow : R/W; bitpos: [2]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP timer. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_timer_allow:1; + /** lp_mm_lp_anaperi_allow : R/W; bitpos: [3]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP ANAPERI + * (analog peripherals). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_anaperi_allow:1; + /** lp_mm_lp_pmu_allow : R/W; bitpos: [4]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP PMU (Power + * Management Unit). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_pmu_allow:1; + /** lp_mm_lp_wdt_allow : R/W; bitpos: [5]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP WDT (watchdog + * timer). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_wdt_allow:1; + /** lp_mm_lp_mailbox_allow : R/W; bitpos: [6]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP Mailbox + * Controller. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_mailbox_allow:1; + /** lp_mm_lp_rtc_allow : R/W; bitpos: [7]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP RTC. + * 0: Not allowed + * 1: Allow + */ + uint32_t lp_mm_lp_rtc_allow:1; + /** lp_mm_lp_periclkrst_allow : R/W; bitpos: [8]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP PREICLKRST + * (peripheral clock and reset). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_periclkrst_allow:1; + /** lp_mm_lp_uart_allow : R/W; bitpos: [9]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP UART. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_uart_allow:1; + /** lp_mm_lp_i2c_allow : R/W; bitpos: [10]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_i2c_allow:1; + /** lp_mm_lp_spi_allow : R/W; bitpos: [11]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP SPI. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_spi_allow:1; + /** lp_mm_lp_i2cmst_allow : R/W; bitpos: [12]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2C master. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_i2cmst_allow:1; + /** lp_mm_lp_i2s_allow : R/W; bitpos: [13]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP I2S. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_i2s_allow:1; + /** lp_mm_lp_adc_allow : R/W; bitpos: [14]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP ADC. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_adc_allow:1; + /** lp_mm_lp_touch_allow : R/W; bitpos: [15]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP touch sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_touch_allow:1; + /** lp_mm_lp_iomux_allow : R/W; bitpos: [16]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP IO MUX. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_iomux_allow:1; + /** lp_mm_lp_intr_allow : R/W; bitpos: [17]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP INTR + * (interrupt). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_intr_allow:1; + /** lp_mm_lp_efuse_allow : R/W; bitpos: [18]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP eFuse. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_efuse_allow:1; + /** lp_mm_lp_pms_allow : R/W; bitpos: [19]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_pms_allow:1; + /** lp_mm_hp2lp_pms_allow : R/W; bitpos: [20]; default: 1; + * Configures whether LP CPU in machine mode has permission to access + * HP2LP_PERI_PMS_REG. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_hp2lp_pms_allow:1; + /** lp_mm_lp_tsens_allow : R/W; bitpos: [21]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP temperature + * sensor. + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_tsens_allow:1; + /** lp_mm_lp_huk_allow : R/W; bitpos: [22]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP HUK (Hardware + * Unique Key). + * 0: Not allowed + * 1: Allowed + */ + uint32_t lp_mm_lp_huk_allow:1; + /** lp_mm_lp_sram_allow : R/W; bitpos: [23]; default: 1; + * Configures whether LP CPU in machine mode has permission to access LP SRAM. + * 0: Not allowed + * 1: Allow + */ + uint32_t lp_mm_lp_sram_allow:1; uint32_t reserved_24:8; }; uint32_t val; -} tee_lp_mm_pms_reg0_reg_t; +} pms_lp_mm_lp_peri_pms_reg0_reg_t; -/** Group: TEE PERI REGION0 LOW REG */ -/** Type of peri_region0_low register - * NA +/** Group: Configurable Address Range Configuration Registers */ +/** Type of peri_regionn_low register + * Regionn start address configuration register */ typedef union { struct { uint32_t reserved_0:2; - /** reg_peri_region0_low : R/W; bitpos: [31:2]; default: 0; - * NA + /** peri_regionn_low : R/W; bitpos: [31:2]; default: 0; + * Configures the high 30 bits of the start address of peripheral register's regionn. */ - uint32_t reg_peri_region0_low:30; + uint32_t peri_regionn_low:30; }; uint32_t val; -} tee_peri_region0_low_reg_t; +} pms_peri_regionn_low_reg_t; - -/** Group: TEE PERI REGION0 HIGH REG */ -/** Type of peri_region0_high register - * NA - */ -typedef union { - struct { - uint32_t reserved_0:2; - /** reg_peri_region0_high : R/W; bitpos: [31:2]; default: 1073741823; - * NA - */ - uint32_t reg_peri_region0_high:30; - }; - uint32_t val; -} tee_peri_region0_high_reg_t; - - -/** Group: TEE PERI REGION1 LOW REG */ -/** Type of peri_region1_low register - * NA - */ -typedef union { - struct { - uint32_t reserved_0:2; - /** reg_peri_region1_low : R/W; bitpos: [31:2]; default: 0; - * NA - */ - uint32_t reg_peri_region1_low:30; - }; - uint32_t val; -} tee_peri_region1_low_reg_t; - - -/** Group: TEE PERI REGION1 HIGH REG */ -/** Type of peri_region1_high register - * NA +/** Type of peri_regionn_high register + * Regionn end address configuration register */ typedef union { struct { uint32_t reserved_0:2; - /** reg_peri_region1_high : R/W; bitpos: [31:2]; default: 1073741823; - * NA + /** peri_regionn_high : R/W; bitpos: [31:2]; default: 1073741823; + * Configures the high 30 bits of the end address of peripheral register's regionn. */ - uint32_t reg_peri_region1_high:30; + uint32_t peri_regionn_high:30; }; uint32_t val; -} tee_peri_region1_high_reg_t; +} pms_peri_regionn_high_reg_t; -/** Group: TEE PERI REGION PMS REG */ +/** Group: PMS Peripheral Region Permission Control Registers */ /** Type of peri_region_pms register - * NA + * Permission register of region */ typedef union { struct { - /** reg_lp_core_region_pms : R/W; bitpos: [1:0]; default: 3; - * NA - */ - uint32_t reg_lp_core_region_pms:2; - /** reg_hp_core0_um_region_pms : R/W; bitpos: [3:2]; default: 3; - * NA - */ - uint32_t reg_hp_core0_um_region_pms:2; - /** reg_hp_core0_mm_region_pms : R/W; bitpos: [5:4]; default: 3; - * NA - */ - uint32_t reg_hp_core0_mm_region_pms:2; - /** reg_hp_core1_um_region_pms : R/W; bitpos: [7:6]; default: 3; - * NA - */ - uint32_t reg_hp_core1_um_region_pms:2; - /** reg_hp_core1_mm_region_pms : R/W; bitpos: [9:8]; default: 3; - * NA - */ - uint32_t reg_hp_core1_mm_region_pms:2; + /** lp_core_region_pms : R/W; bitpos: [1:0]; default: 3; + * Configures whether LP core in machine mode has permission to access address region0 + * and address region1. Bit0 corresponds to region0 and bit1 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ + uint32_t lp_core_region_pms:2; + /** hp_core0_um_region_pms : R/W; bitpos: [3:2]; default: 3; + * Configures whether HP CPU0 in user mode has permission to access address region0 + * and address region1. Bit2 corresponds to region0 and bit3 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_core0_um_region_pms:2; + /** hp_core0_mm_region_pms : R/W; bitpos: [5:4]; default: 3; + * Configures whether HP CPU0 in machine mode has permission to access address region0 + * and address region1. Bit4 corresponds to region0 and bit5 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_core0_mm_region_pms:2; + /** hp_core1_um_region_pms : R/W; bitpos: [7:6]; default: 3; + * Configures whether HP CPU1 in user mode has permission to access address region0 + * and address region1. Bit6 corresponds to region0 and bit7 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_core1_um_region_pms:2; + /** hp_core1_mm_region_pms : R/W; bitpos: [9:8]; default: 3; + * Configures whether HP CPU1 in machine mode has permission to access address region0 + * and address region1. Bit8 corresponds to region0 and bit9 corresponds to region1. + * 0: Not allowed + * 1: Allow + */ + uint32_t hp_core1_mm_region_pms:2; uint32_t reserved_10:22; }; uint32_t val; -} tee_peri_region_pms_reg_t; +} pms_peri_region_pms_reg_t; typedef struct { - volatile tee_pms_date_reg_t pms_date; - volatile tee_pms_clk_en_reg_t pms_clk_en; - volatile tee_lp_mm_pms_reg0_reg_t lp_mm_pms_reg0; - volatile tee_peri_region0_low_reg_t peri_region0_low; - volatile tee_peri_region0_high_reg_t peri_region0_high; - volatile tee_peri_region1_low_reg_t peri_region1_low; - volatile tee_peri_region1_high_reg_t peri_region1_high; - volatile tee_peri_region_pms_reg_t peri_region_pms; -} tee_dev_t; + volatile pms_lp_peri_pms_date_reg_t lp_peri_pms_date; + volatile pms_lp_peri_pms_clk_en_reg_t lp_peri_pms_clk_en; + volatile pms_lp_mm_lp_peri_pms_reg0_reg_t lp_mm_lp_peri_pms_reg0; + volatile pms_peri_regionn_low_reg_t peri_region0_low; + volatile pms_peri_regionn_high_reg_t peri_region0_high; + volatile pms_peri_regionn_low_reg_t peri_region1_low; + volatile pms_peri_regionn_high_reg_t peri_region1_high; + volatile pms_peri_region_pms_reg_t peri_region_pms; +} lp_peri_pms_dev_t; +extern lp_peri_pms_dev_t LP_PERI_PMS; #ifndef __cplusplus -_Static_assert(sizeof(tee_dev_t) == 0x20, "Invalid size of tee_dev_t structure"); +_Static_assert(sizeof(lp_peri_pms_dev_t) == 0x20, "Invalid size of lp_peri_pms_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index 50493812f22..c706f5da5d1 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -19,6 +19,9 @@ PROVIDE ( I2C1 = 0x500C5000 ); PROVIDE ( UHCI0 = 0x500DF000 ); PROVIDE ( RMT = 0x500A2000 ); PROVIDE ( RMTMEM = 0x500A2800 ); +PROVIDE ( HP_PERI_PMS = 0x500A5000 ); +PROVIDE ( LP2HP_PERI_PMS = 0x500A5800 ); +PROVIDE ( DMA_PMS = 0x500A6000 ); PROVIDE ( LEDC = 0x500D3000 ); PROVIDE ( LEDC_GAMMA_RAM = 0x500D3400 ); PROVIDE ( TIMERG0 = 0x500C2000 ); @@ -79,6 +82,8 @@ PROVIDE ( LP_WDT = 0x50116000 ); PROVIDE ( LP_I2S = 0x50125000 ); PROVIDE ( LP_TOUCH = 0x50128000 ); PROVIDE ( LP_GPIO = 0x5012A000 ); +PROVIDE ( LP_PERI_PMS = 0x5012E000 ); +PROVIDE ( HP2LP_PERI_PMS = 0x5012E800 ); PROVIDE ( LP_I2C_ANA_MST = 0x50124000 ); PROVIDE ( LP_ANA_PERI = 0x50113000 ); PROVIDE ( LP_APM = 0x600B3800 ); /* TODO: IDF-7542 */ From 0ee7d4d17adaee0452149d540a6689ba43393127 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 18 Apr 2024 15:45:24 +0800 Subject: [PATCH 019/548] docs(programming-guide): clean up misc leftover doc updates for P4 --- docs/docs_not_updated/esp32p4.txt | 24 ------------------------ docs/en/hw-reference/index.rst | 4 ++++ docs/zh_CN/hw-reference/index.rst | 4 ++++ 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index dd9af020508..d622285560c 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -4,8 +4,6 @@ api-guides/performance/ram-usage.rst api-guides/performance/index.rst api-guides/partition-tables.rst api-guides/app_trace.rst -api-guides/thread-local-storage.rst -api-guides/error-handling.rst api-guides/RF_calibration.rst api-guides/deep-sleep-stub.rst api-guides/coexist.rst @@ -13,15 +11,11 @@ api-guides/flash_psram_config.rst api-guides/usb-serial-jtag-console.rst api-guides/wifi.rst api-guides/usb-otg-console.rst -api-guides/wireshark-user-guide.rst api-guides/esp-wifi-mesh.rst api-guides/SYSVIEW_FreeRTOS.txt api-guides/dfu.rst api-guides/current-consumption-measurement-modules.rst api-guides/wifi-security.rst -api-guides/host-apps.rst -api-guides/index.rst -api-guides/openthread.rst api-reference/storage/vfs.rst api-reference/storage/spiffs.rst api-reference/storage/nvs_encryption.rst @@ -43,23 +37,11 @@ api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst api-reference/peripherals/usb_host/usb_host_notes_design.rst api-reference/peripherals/usb_device.rst api-reference/peripherals/touch_element.rst -api-reference/peripherals/ana_cmpr.rst -api-reference/peripherals/temp_sensor.rst api-reference/peripherals/spi_flash/xip_from_psram.inc -api-reference/peripherals/spi_flash/spi_flash_concurrency.rst -api-reference/peripherals/spi_flash/spi_flash_override_driver.rst -api-reference/peripherals/spi_flash/spi_flash_optional_feature.rst -api-reference/peripherals/spi_flash/spi_flash_idf_vs_rom.rst -api-reference/peripherals/spi_flash/index.rst -api-reference/peripherals/spi_flash/auto_suspend.inc -api-reference/peripherals/sdm.rst api-reference/peripherals/touch_pad.rst api-reference/peripherals/adc_calibration.rst api-reference/peripherals/parlio.rst -api-reference/peripherals/i2c.rst api-reference/peripherals/sd_pullup_requirements.rst -api-reference/peripherals/index.rst -api-reference/network/esp_openthread.rst api-reference/network/esp_dpp.rst api-reference/network/esp_now.rst api-reference/network/esp-wifi-mesh.rst @@ -71,12 +53,7 @@ api-reference/system/sleep_modes.rst api-reference/system/app_trace.rst api-reference/system/random.rst api-reference/system/power_management.rst -api-reference/system/misc_system_api.rst api-reference/system/inc/power_management_esp32p4.rst -api-reference/index.rst -api-reference/protocols/icmp_echo.rst -api-reference/protocols/esp_serial_slave_link.rst -api-reference/protocols/index.rst get-started/establish-serial-connection.rst get-started/linux-macos-setup.rst get-started/linux-macos-start-project.rst @@ -86,4 +63,3 @@ get-started/flashing-troubleshooting.rst get-started/windows-start-project.rst get-started/index.rst get-started/windows-setup-update.rst -hw-reference/index.rst diff --git a/docs/en/hw-reference/index.rst b/docs/en/hw-reference/index.rst index 29f262c063b..3f8b92b1439 100644 --- a/docs/en/hw-reference/index.rst +++ b/docs/en/hw-reference/index.rst @@ -15,6 +15,7 @@ Hardware Reference :esp32c3: Chip Datasheet (PDF) :esp32c6: Chip Datasheet (PDF) :esp32h2: Chip Datasheet (PDF) + :esp32p4: Chip Datasheet (PDF) :esp32: Hardware Design Guidelines (PDF) :esp32s2: Hardware Design Guidelines (PDF) :esp32s3: Hardware Design Guidelines (PDF) @@ -22,11 +23,14 @@ Hardware Reference :esp32c3: Hardware Design Guidelines (PDF) :esp32c6: Hardware Design Guidelines (PDF) :esp32h2: Hardware Design Guidelines (PDF) + :esp32p4: Hardware Design Guidelines (PDF) :esp32: Silicon Errata (PDF) :esp32s2: Silicon Errata (PDF) :esp32s3: Silicon Errata (PDF) :esp32c3: Silicon Errata (PDF) :esp32c2: Silicon Errata (PDF) + :esp32c6: Silicon Errata (PDF) + :esp32h2: Silicon Errata (PDF) Chip Variants Modules Development Boards diff --git a/docs/zh_CN/hw-reference/index.rst b/docs/zh_CN/hw-reference/index.rst index fa139e62a0e..8ee7f2fa33f 100644 --- a/docs/zh_CN/hw-reference/index.rst +++ b/docs/zh_CN/hw-reference/index.rst @@ -15,6 +15,7 @@ H/W 硬件参考 :esp32c3: 技术规格书 (PDF) :esp32c6: 技术规格书 (PDF) :esp32h2: 技术规格书 (PDF) + :esp32p4: 技术规格书 (PDF) :esp32: 硬件设计指南 (PDF) :esp32s2: 硬件设计指南 (PDF) :esp32s3: 硬件设计指南 (PDF) @@ -22,11 +23,14 @@ H/W 硬件参考 :esp32c3: 硬件设计指南 (PDF) :esp32c6: 硬件设计指南 (PDF) :esp32h2: 硬件设计指南 (PDF) + :esp32p4: 硬件设计指南 (PDF) :esp32: 勘误表及解决方法 (PDF) :esp32s2: 勘误表及解决方法 (PDF) :esp32s3: 勘误表及解决方法 (PDF) :esp32c3: 勘误表及解决方法 (PDF) :esp32c2: 勘误表及解决方法 (PDF) + :esp32c6: 勘误表及解决方法 (PDF) + :esp32h2: 勘误表及解决方法 (PDF) 芯片变型 模组 开发板 From ccca8b74ebf6ee0c5b57359879a94cdbec6e985a Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Sun, 28 Apr 2024 14:39:44 +0800 Subject: [PATCH 020/548] fix(esp_system): increase 26Mhz esp32c2 slow clock calibration timeout watchdog threshold --- components/esp_system/port/soc/esp32c2/clk.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/components/esp_system/port/soc/esp32c2/clk.c b/components/esp_system/port/soc/esp32c2/clk.c index 25d79e21993..ef75764dacb 100644 --- a/components/esp_system/port/soc/esp32c2/clk.c +++ b/components/esp_system/port/soc/esp32c2/clk.c @@ -77,11 +77,16 @@ __attribute__((weak)) void esp_clk_init(void) #ifdef CONFIG_BOOTLOADER_WDT_ENABLE // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. - // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec on 40MHz XTAL and 2.5 sec on 26MHz XTAL). // This prevents excessive delay before resetting in case the supply voltage is drawdown. - // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec 40MHz XTAL, + // or 11.72 sec on 26MHz XTAL). wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; +#ifdef CONFIG_XTAL_FREQ_26 + uint32_t stage_timeout_ticks = (uint32_t)(2500ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); +#else uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); +#endif wdt_hal_write_protect_disable(&rtc_wdt_ctx); wdt_hal_feed(&rtc_wdt_ctx); //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same From df211933ff3c6a041dc1d9b8b8e43c91b61edd74 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 29 Apr 2024 18:37:50 +0800 Subject: [PATCH 021/548] fix(mipi_dsi): only wait ready for enabled data lane --- components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c | 11 +++++++++-- components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h | 2 +- components/hal/esp32p4/include/hal/mipi_dsi_ll.h | 3 ++- components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h | 11 +++++++++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c index 1447a122a7e..8583a27682f 100644 --- a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c +++ b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c @@ -21,6 +21,8 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc { esp_err_t ret = ESP_OK; ESP_RETURN_ON_FALSE(bus_config && ret_bus, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(bus_config->num_data_lanes <= MIPI_DSI_LL_MAX_DATA_LANES, + ESP_ERR_INVALID_ARG, TAG, "invalid number of data lanes %d", bus_config->num_data_lanes); ESP_RETURN_ON_FALSE(bus_config->lane_bit_rate_mbps >= MIPI_DSI_LL_MIN_PHY_MBPS && bus_config->lane_bit_rate_mbps <= MIPI_DSI_LL_MAX_PHY_MBPS, ESP_ERR_INVALID_ARG, TAG, "invalid lane bit rate %"PRIu32, bus_config->lane_bit_rate_mbps); @@ -64,11 +66,16 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc esp_pm_lock_acquire(dsi_bus->pm_lock); #endif + // if the number of data lanes is not assigned, fallback to the maximum number of data lanes + int num_data_lanes = bus_config->num_data_lanes; + if (num_data_lanes == 0) { + num_data_lanes = MIPI_DSI_LL_MAX_DATA_LANES; + } // initialize HAL context mipi_dsi_hal_config_t hal_config = { .bus_id = bus_id, .lane_bit_rate_mbps = bus_config->lane_bit_rate_mbps, - .num_data_lanes = bus_config->num_data_lanes, + .num_data_lanes = num_data_lanes, }; mipi_dsi_hal_init(&dsi_bus->hal, &hal_config); mipi_dsi_hal_context_t *hal = &dsi_bus->hal; @@ -84,7 +91,7 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc while (!mipi_dsi_phy_ll_is_pll_locked(hal->host)) { vTaskDelay(pdMS_TO_TICKS(1)); } - while (!mipi_dsi_phy_ll_are_lanes_stopped(hal->host)) { + while (!mipi_dsi_phy_ll_are_lanes_stopped(hal->host, num_data_lanes)) { vTaskDelay(pdMS_TO_TICKS(1)); } diff --git a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h index bd7e50d2846..0977468d221 100644 --- a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h +++ b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h @@ -21,7 +21,7 @@ extern "C" { */ typedef struct { int bus_id; /*!< Select which DSI controller, index from 0 */ - uint8_t num_data_lanes; /*!< Number of data lanes */ + uint8_t num_data_lanes; /*!< Number of data lanes, if set to 0, the driver will fallback to use maximum number of lanes */ mipi_dsi_phy_clock_source_t phy_clk_src; /*!< MIPI DSI PHY clock source */ uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ } esp_lcd_dsi_bus_config_t; diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_ll.h index 6c37ea589b5..e876817684e 100644 --- a/components/hal/esp32p4/include/hal/mipi_dsi_ll.h +++ b/components/hal/esp32p4/include/hal/mipi_dsi_ll.h @@ -14,7 +14,8 @@ #include "hal/mipi_dsi_brg_ll.h" #include "hal/mipi_dsi_phy_ll.h" -#define MIPI_DSI_LL_NUM_BUS 1 // 1 MIPI DSI bus +#define MIPI_DSI_LL_NUM_BUS 1 // support only 1 MIPI DSI bus +#define MIPI_DSI_LL_MAX_DATA_LANES 2 // support up to 2 data lanes #ifdef __cplusplus extern "C" { diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h index b89de14d87d..9cb2d1e1fbd 100644 --- a/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h +++ b/components/hal/esp32p4/include/hal/mipi_dsi_phy_ll.h @@ -81,12 +81,19 @@ static inline bool mipi_dsi_phy_ll_is_pll_locked(dsi_host_dev_t *dev) * @brief Check if the all active lanes are in the stop state * * @param dev Pointer to the DSI Host controller register base address + * @param num_data_lanes Number of data lanes * @return True if the lanes are all in stop state, False otherwise */ -static inline bool mipi_dsi_phy_ll_are_lanes_stopped(dsi_host_dev_t *dev) +static inline bool mipi_dsi_phy_ll_are_lanes_stopped(dsi_host_dev_t *dev, uint8_t num_data_lanes) { uint32_t status = dev->phy_status.val; - const uint32_t mask = 1 << 2 | 1 << 4 | 1 << 7; + uint32_t mask = 1 << 2; + if (num_data_lanes > 0) { + mask |= 1 << 4; + } + if (num_data_lanes > 1) { + mask |= 1 << 7; + } return (status & mask) == mask; } From 91c4a94f6127ba27c182d34848edb05a27788605 Mon Sep 17 00:00:00 2001 From: liqigan Date: Tue, 23 Apr 2024 15:08:27 +0800 Subject: [PATCH 022/548] fix(bt/bluedroid): Fix HID Device connection failed bug Closes https://github.com/espressif/esp-idf/issues/13671 --- .../bt/host/bluedroid/bta/hd/bta_hd_act.c | 20 +++++++++++ .../bt/host/bluedroid/bta/hd/bta_hd_main.c | 5 +-- .../bluedroid/bta/hd/include/bta_hd_int.h | 1 + .../bluedroid/btc/profile/std/hid/btc_hd.c | 4 ++- .../bt/host/bluedroid/stack/hid/hidd_conn.c | 35 +++++++++++-------- .../bt/host/bluedroid/stack/hid/hidh_api.c | 4 +-- .../bt/host/bluedroid/stack/hid/hidh_conn.c | 24 ++++++++++--- .../bluedroid/stack/hid/include/hid_int.h | 2 +- 8 files changed, 69 insertions(+), 26 deletions(-) diff --git a/components/bt/host/bluedroid/bta/hd/bta_hd_act.c b/components/bt/host/bluedroid/bta/hd/bta_hd_act.c index 8f655d73fe2..220b86cf2f6 100644 --- a/components/bt/host/bluedroid/bta/hd/bta_hd_act.c +++ b/components/bt/host/bluedroid/bta/hd/bta_hd_act.c @@ -722,6 +722,26 @@ extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data) bta_sys_idle(BTA_ID_HD, 1, p_cback->addr); } +/******************************************************************************* + * + * Function bta_hd_open_failure + * + * Description + * + * Returns void + * + ******************************************************************************/ +extern void bta_hd_open_failure(tBTA_HD_DATA *p_data) +{ + tBTA_HD_CBACK_DATA *p_cback = (tBTA_HD_CBACK_DATA *)p_data; + tBTA_HD cback_data = {0}; + + bdcpy(cback_data.conn.bda, p_cback->addr); + cback_data.conn.status = BTA_HD_ERROR; + cback_data.conn.conn_status = BTA_HD_CONN_STATE_DISCONNECTED; + bta_hd_cb.p_cback(BTA_HD_OPEN_EVT, &cback_data); +} + /******************************************************************************* * * Function bta_hd_cback diff --git a/components/bt/host/bluedroid/bta/hd/bta_hd_main.c b/components/bt/host/bluedroid/bta/hd/bta_hd_main.c index a6a3b634c18..7faaf2d6cd3 100644 --- a/components/bt/host/bluedroid/bta/hd/bta_hd_main.c +++ b/components/bt/host/bluedroid/bta/hd/bta_hd_main.c @@ -62,6 +62,7 @@ enum { BTA_HD_VC_UNPLUG_DONE_ACT, BTA_HD_SUSPEND_ACT, BTA_HD_EXIT_SUSPEND_ACT, + BTA_HD_OPEN_FAILURE, BTA_HD_NUM_ACTIONS }; @@ -74,7 +75,7 @@ const tBTA_HD_ACTION bta_hd_action[] = { bta_hd_disconnect_act, bta_hd_add_device_act, bta_hd_remove_device_act, bta_hd_send_report_act, bta_hd_report_error_act, bta_hd_vc_unplug_act, bta_hd_open_act, bta_hd_close_act, bta_hd_intr_data_act, bta_hd_get_report_act, bta_hd_set_report_act, bta_hd_set_protocol_act, - bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act, + bta_hd_vc_unplug_done_act, bta_hd_suspend_act, bta_hd_exit_suspend_act, bta_hd_open_failure }; /* state table information */ @@ -118,7 +119,7 @@ const uint8_t bta_hd_st_idle[][BTA_HD_NUM_COLS] = { /* BTA_HD_API_REPORT_ERROR_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_API_VC_UNPLUG_EVT */ {BTA_HD_VC_UNPLUG_ACT, BTA_HD_IDLE_ST}, /* BTA_HD_INT_OPEN_EVT */ {BTA_HD_OPEN_ACT, BTA_HD_CONN_ST}, - /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, + /* BTA_HD_INT_CLOSE_EVT */ {BTA_HD_OPEN_FAILURE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_INTR_DATA_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_GET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, /* BTA_HD_INT_SET_REPORT_EVT */ {BTA_HD_IGNORE, BTA_HD_IDLE_ST}, diff --git a/components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h b/components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h index 7a515970e68..48ac7ed846f 100644 --- a/components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h +++ b/components/bt/host/bluedroid/bta/hd/include/bta_hd_int.h @@ -164,5 +164,6 @@ extern void bta_hd_set_protocol_act(tBTA_HD_DATA *p_data); extern void bta_hd_vc_unplug_done_act(tBTA_HD_DATA *p_data); extern void bta_hd_suspend_act(tBTA_HD_DATA *p_data); extern void bta_hd_exit_suspend_act(tBTA_HD_DATA *p_data); +extern void bta_hd_open_failure(tBTA_HD_DATA *p_data); #endif diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c index d280f8f7ebc..0d99c030b66 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c @@ -261,7 +261,7 @@ static void btc_hd_deinit(void) } btc_hd_cb.service_dereg_active = FALSE; - // unresgister app will also relase the connection + // unregister app will also release the connection // and disable after receiving unregister event from lower layer if (is_hidd_app_register()) { btc_hd_unregister_app(true); @@ -844,6 +844,8 @@ void btc_hd_cb_handler(btc_msg_t *msg) // } // btc_storage_set_hidd((bt_bdaddr_t *)&p_data->conn.bda); btc_hd_cb.status = BTC_HD_CONNECTED; + } else if (p_data->conn.conn_status == BTA_HD_CONN_STATE_DISCONNECTED) { + btc_hd_cb.status = BTC_HD_DISCONNECTED; } param.open.status = p_data->conn.status; param.open.conn_status = p_data->conn.conn_status; diff --git a/components/bt/host/bluedroid/stack/hid/hidd_conn.c b/components/bt/host/bluedroid/stack/hid/hidd_conn.c index 3b44402eed1..5a8e36ee599 100644 --- a/components/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -231,7 +231,7 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) tHID_CONN *p_hcon = &hd_cb.device.conn; HIDD_TRACE_EVENT("%s: cid=%04x result=%d, conn_state=%d", __func__, cid, result, p_hcon->conn_state); if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) || @@ -243,10 +243,12 @@ static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) } if (result != L2CAP_CONN_OK) { HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__); - if (cid == p_hcon->ctrl_cid) + if (cid == p_hcon->ctrl_cid) { p_hcon->ctrl_cid = 0; - else + } else { p_hcon->intr_cid = 0; + } + hidd_conn_disconnect(); hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL); return; @@ -278,7 +280,7 @@ static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE)) @@ -297,7 +299,8 @@ static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) // update flags if (cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) { p_hcon->conn_state = HID_CONN_STATE_UNUSED; @@ -330,7 +333,7 @@ static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result); p_hcon = &hd_cb.device.conn; if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) { @@ -357,7 +360,8 @@ static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg) // update flags if (cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) { p_hcon->conn_state = HID_CONN_STATE_UNUSED; @@ -389,11 +393,14 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } - if (ack_needed) + + if (ack_needed) { L2CA_DisconnectRsp(cid); + } + if (cid == p_hcon->ctrl_cid) { p_hcon->ctrl_cid = 0; p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL; @@ -417,7 +424,7 @@ static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) * * Function hidd_l2cif_disconnect_cfm * - * Description Handles L2CAP disconection response + * Description Handles L2CAP disconnection response * * Returns void * @@ -428,7 +435,7 @@ static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (cid == p_hcon->ctrl_cid) { @@ -465,7 +472,7 @@ static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); return; } if (congested) { @@ -492,7 +499,7 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg) HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid); p_hcon = &hd_cb.device.conn; if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) { - HIDD_TRACE_WARNING("%s: unknown cid", __func__); + HIDD_TRACE_WARNING("%s: unknown cid=%04x", __func__, cid); osi_free(p_msg); return; } @@ -645,7 +652,7 @@ tHID_STATUS hidd_conn_initiate(void) p_dev->conn.ctrl_cid = 0; p_dev->conn.intr_cid = 0; p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; - p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG; + p_dev->conn.conn_flags |= HID_CONN_FLAGS_IS_ORIG; BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN); /* Check if L2CAP started the connection process */ if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) { diff --git a/components/bt/host/bluedroid/stack/hid/hidh_api.c b/components/bt/host/bluedroid/stack/hid/hidh_api.c index bacc5a016af..ec072845ea6 100644 --- a/components/bt/host/bluedroid/stack/hid/hidh_api.c +++ b/components/bt/host/bluedroid/stack/hid/hidh_api.c @@ -379,7 +379,6 @@ tHID_STATUS HID_HostAddDev ( BD_ADDR addr, UINT16 attr_mask, UINT8 *handle ) if (!hh_cb.devices[i].in_use) { hh_cb.devices[i].in_use = TRUE; hh_cb.devices[i].delay_remove = FALSE; - hh_cb.devices[i].is_orig = FALSE; memcpy( hh_cb.devices[i].addr, addr, sizeof( BD_ADDR ) ) ; hh_cb.devices[i].state = HID_DEV_NO_CONN; hh_cb.devices[i].conn_tries = 0 ; @@ -487,7 +486,6 @@ tHID_STATUS HID_HostOpenDev ( UINT8 dev_handle ) } hh_cb.devices[dev_handle].conn_tries = 1; - hh_cb.devices[dev_handle].is_orig = TRUE; return hidh_conn_initiate( dev_handle ); } @@ -666,7 +664,7 @@ BOOLEAN HID_HostConnectOrig(UINT8 dev_handle) break; } - ret = hh_cb.devices[dev_handle].is_orig; + ret = hidh_conn_is_orig(dev_handle); } while (0); return ret; diff --git a/components/bt/host/bluedroid/stack/hid/hidh_conn.c b/components/bt/host/bluedroid/stack/hid/hidh_conn.c index 801f087cc5a..f9d4a47b631 100644 --- a/components/bt/host/bluedroid/stack/hid/hidh_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidh_conn.c @@ -457,8 +457,8 @@ static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) if (l2cap_cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && - (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { /* Connect interrupt channel */ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0) { @@ -528,8 +528,8 @@ static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg) if (l2cap_cid == p_hcon->ctrl_cid) { p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE; - if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && - (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) { + if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE) && + (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)) { /* Connect interrupt channel */ p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0) { @@ -968,7 +968,7 @@ tHID_STATUS hidh_conn_initiate (UINT8 dhandle) p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */ /* We are the originator of this connection */ - p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG; + p_dev->conn.conn_flags |= HID_CONN_FLAGS_IS_ORIG; if (p_dev->attr_mask & HID_SEC_REQUIRED) { service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL; @@ -989,6 +989,20 @@ tHID_STATUS hidh_conn_initiate (UINT8 dhandle) return ( HID_SUCCESS ); } +/******************************************************************************* +** +** Function hidh_conn_is_orig +** +** Description This function check if we are the originator of this connection +** +** Returns BOOLEAN +** +*******************************************************************************/ +BOOLEAN hidh_conn_is_orig(UINT8 dhandle) +{ + tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle]; + return (p_dev->conn.conn_flags & HID_CONN_FLAGS_IS_ORIG); +} /******************************************************************************* ** diff --git a/components/bt/host/bluedroid/stack/hid/include/hid_int.h b/components/bt/host/bluedroid/stack/hid/include/hid_int.h index 865aadf966b..beaca21e72c 100644 --- a/components/bt/host/bluedroid/stack/hid/include/hid_int.h +++ b/components/bt/host/bluedroid/stack/hid/include/hid_int.h @@ -35,7 +35,6 @@ enum { HID_DEV_NO_CONN, HID_DEV_CONNECTED }; typedef struct per_device_ctb { BOOLEAN in_use; BOOLEAN delay_remove; - BOOLEAN is_orig; BD_ADDR addr; /* BD-Addr of the host device */ UINT16 attr_mask; /* 0x01- virtual_cable; 0x02- normally_connectable; 0x03- reconn_initiate; 0x04- sdp_disable; */ @@ -66,6 +65,7 @@ extern tHID_STATUS hidh_conn_reg (void); extern void hidh_conn_dereg( void ); extern tHID_STATUS hidh_conn_disconnect (UINT8 dhandle); extern tHID_STATUS hidh_conn_initiate (UINT8 dhandle); +extern BOOLEAN hidh_conn_is_orig(UINT8 dhandle); extern void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle); #ifdef __cplusplus extern "C" { From 60ab9631d7f645d17ed543d1dbdb69e799fac230 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Thu, 2 May 2024 13:23:35 +0530 Subject: [PATCH 023/548] fix(tests): remove unused partition NVS bin file --- .../test_apps/main/partition_plaintext.bin | Bin 8192 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 components/nvs_flash/test_apps/main/partition_plaintext.bin diff --git a/components/nvs_flash/test_apps/main/partition_plaintext.bin b/components/nvs_flash/test_apps/main/partition_plaintext.bin deleted file mode 100644 index 76fe7122269f0d1f8c8e8a379f7801d4fb062690..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 zcmezO|NnmmAOKPr;E>qeJFD=6Ukr?l|4-U2VNWT|&8_rH%uOvWNK8&;U|@ur#t4+R zmFPPRmJhY?POSvl#=uYylNV(C|9GC22Uy+{A>RO#XJY*SWlF$fh<-yexB*ZFj4X`* zqm}oGLgbB&VDeDy{~1LX|EC*QO@^3{kOw*eYyzVq)BiJZy|cmc!6ikRdFfyygn%Kk z+FD$}z|qRU$;!al%D~0Sz}3pY4JeKb7@e3H*^C~H|7UCZtiaR{3`3w9AoEW>k?aG@J0%vUnwfyz2Qt5p|L|c$Bjd!R zWK=Vec_8z*o_)O;Q$ND|jO4ZU8L1U+nK`Mj;A7wbns4z@Y7?WfYkDUhAArm+w|epk zQ$ND|quNEnNnocVtl$BfKZ83b3m85utZeKYoH*t{i7|^(W_y_6(0sA}P&JY^$wD?CXYWM#YnhH?= z$%=8l7Sl@f{*wax|NqkGEM#fz{!#Ns`=6uz@6qvx(eanj@h8woAHC~OLiJB-UJ8bj z-~vEN(D Date: Thu, 2 May 2024 13:24:45 +0530 Subject: [PATCH 024/548] fix(tests): correct the flash write length for NVS encrypted test Write only till the embedded file size in the NVS partition. Earlier the length was kept as the whole partition size and it could result in accessing embedded rodata beyond the MMU mapped range. --- components/nvs_flash/test_apps/main/test_nvs.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/components/nvs_flash/test_apps/main/test_nvs.c b/components/nvs_flash/test_apps/main/test_nvs.c index 4c4f4ef7edc..b0687b608f7 100644 --- a/components/nvs_flash/test_apps/main/test_nvs.c +++ b/components/nvs_flash/test_apps/main/test_nvs.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include #include #include +#include #include #include @@ -587,6 +588,7 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena extern const char nvs_key_start[] asm("_binary_encryption_keys_bin_start"); extern const char nvs_key_end[] asm("_binary_encryption_keys_bin_end"); extern const char nvs_data_sch0_start[] asm("_binary_partition_encrypted_bin_start"); + extern const char nvs_data_sch0_end[] asm("_binary_partition_encrypted_bin_end"); const esp_partition_t* key_part = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); @@ -600,15 +602,24 @@ TEST_CASE("test nvs apis for nvs partition generator utility with encryption ena ESP_ERROR_CHECK( esp_partition_write(key_part, i, nvs_key_start + i, SPI_FLASH_SEC_SIZE) ); } - for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) { + const int content_size = nvs_data_sch0_end - nvs_data_sch0_start - 1; + TEST_ASSERT_TRUE((content_size % SPI_FLASH_SEC_SIZE) == 0); + + const int size_to_write = MIN(content_size, nvs_part->size); + for (int i = 0; i < size_to_write; i+= SPI_FLASH_SEC_SIZE) { ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch0_start + i, SPI_FLASH_SEC_SIZE) ); } err = nvs_flash_read_security_cfg(key_part, &xts_cfg); #elif CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC extern const char nvs_data_sch1_start[] asm("_binary_partition_encrypted_hmac_bin_start"); + extern const char nvs_data_sch1_end[] asm("_binary_partition_encrypted_hmac_bin_end"); + + const int content_size = nvs_data_sch1_end - nvs_data_sch1_start - 1; + TEST_ASSERT_TRUE((content_size % SPI_FLASH_SEC_SIZE) == 0); - for (int i = 0; i < nvs_part->size; i+= SPI_FLASH_SEC_SIZE) { + const int size_to_write = MIN(content_size, nvs_part->size); + for (int i = 0; i < size_to_write; i+= SPI_FLASH_SEC_SIZE) { ESP_ERROR_CHECK( esp_partition_write(nvs_part, i, nvs_data_sch1_start + i, SPI_FLASH_SEC_SIZE) ); } From b026a7c91577cc79fc820d5ee016f892930ffe52 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Fri, 26 Apr 2024 10:14:47 +0200 Subject: [PATCH 025/548] fix(linux): calling getrandom() outside assert() * Expressions inside assert are completely removed in release builds --- components/esp_hw_support/port/linux/esp_random.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/port/linux/esp_random.c b/components/esp_hw_support/port/linux/esp_random.c index e1dc505a2ee..19bed4dc65f 100644 --- a/components/esp_hw_support/port/linux/esp_random.c +++ b/components/esp_hw_support/port/linux/esp_random.c @@ -17,13 +17,16 @@ static void __attribute__((constructor)) esp_random_init(void) { } uint32_t esp_random(void) { uint32_t random_number; - assert(getentropy(&random_number, sizeof(random_number)) == 0); + int result = getentropy(&random_number, sizeof(random_number)); + assert(result == 0); + (void)result; return random_number; } void esp_fill_random(void *buf, size_t len) { assert(buf != NULL); + int result; // Note that we can't use getentropy() with len > 256 directly (see getentropy man page), // hence reading in chunks @@ -31,8 +34,12 @@ void esp_fill_random(void *buf, size_t len) const size_t REST_CHUNK_SIZE = len % GETENTROPY_MAX_LEN; for (size_t chunk_num = 0; chunk_num < FULL_CHUNKS_NUM; chunk_num++) { - assert(getentropy(buf + chunk_num * GETENTROPY_MAX_LEN, GETENTROPY_MAX_LEN) == 0); + result = getentropy(buf + chunk_num * GETENTROPY_MAX_LEN, GETENTROPY_MAX_LEN); + assert(result == 0); + (void)result; } - assert(getentropy(buf + FULL_CHUNKS_NUM * GETENTROPY_MAX_LEN, REST_CHUNK_SIZE) == 0); + result = getentropy(buf + FULL_CHUNKS_NUM * GETENTROPY_MAX_LEN, REST_CHUNK_SIZE); + assert(result == 0); + (void)result; } From 39771b6c81c3bb77b8f6d1f3393f4c7b7bf52a57 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Tue, 23 Apr 2024 12:04:45 +0530 Subject: [PATCH 026/548] fix(esp-tls): Use 64 bit variable for time instead of 32 bit Use appropriate API available on respective platform for obtaining time Closes https://github.com/espressif/esp-idf/issues/13593 --- components/esp-tls/CMakeLists.txt | 6 ++-- components/esp-tls/esp_tls.c | 12 ++++---- components/esp-tls/esp_tls_platform_port.c | 28 +++++++++++++++++++ .../private_include/esp_tls_platform_port.h | 24 ++++++++++++++++ 4 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 components/esp-tls/esp_tls_platform_port.c create mode 100644 components/esp-tls/private_include/esp_tls_platform_port.h diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index 10c16fcb87c..3809b6473b6 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -1,4 +1,4 @@ -set(srcs esp_tls.c esp-tls-crypto/esp_tls_crypto.c esp_tls_error_capture.c) +set(srcs esp_tls.c esp-tls-crypto/esp_tls_crypto.c esp_tls_error_capture.c esp_tls_platform_port.c) if(CONFIG_ESP_TLS_USING_MBEDTLS) list(APPEND srcs "esp_tls_mbedtls.c") @@ -9,7 +9,7 @@ if(CONFIG_ESP_TLS_USING_WOLFSSL) "esp_tls_wolfssl.c") endif() -set(priv_req http_parser) +set(priv_req http_parser esp_timer) if(NOT ${IDF_TARGET} STREQUAL "linux") list(APPEND priv_req lwip) endif() @@ -17,7 +17,7 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} esp-tls-crypto PRIV_INCLUDE_DIRS "private_include" - # mbedtls is public requirements becasue esp_tls.h + # mbedtls is public requirements because esp_tls.h # includes mbedtls header files. REQUIRES mbedtls PRIV_REQUIRES ${priv_req}) diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 483ca294720..a23eb27e8e8 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -16,6 +16,7 @@ #include "sdkconfig.h" #include "esp_tls.h" #include "esp_tls_private.h" +#include "esp_tls_platform_port.h" #include "esp_tls_error_capture_internal.h" #include #include @@ -537,9 +538,8 @@ int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp if (!cfg || !tls || !hostname || hostlen < 0) { return -1; } - struct timeval time = {}; - gettimeofday(&time, NULL); - uint32_t start_time_ms = (time.tv_sec * 1000) + (time.tv_usec / 1000); + uint64_t start_time_us; + start_time_us = esp_tls_get_platform_time(); while (1) { int ret = esp_tls_low_level_conn(hostname, hostlen, port, cfg, tls); if (ret == 1) { @@ -548,10 +548,8 @@ int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp ESP_LOGE(TAG, "Failed to open new connection"); return -1; } else if (ret == 0 && cfg->timeout_ms >= 0) { - gettimeofday(&time, NULL); - uint32_t current_time_ms = (time.tv_sec * 1000) + (time.tv_usec / 1000); - uint32_t elapsed_time_ms = current_time_ms - start_time_ms; - if (elapsed_time_ms >= cfg->timeout_ms) { + uint64_t elapsed_time_us = esp_tls_get_platform_time() - start_time_us; + if ((elapsed_time_us / 1000) >= cfg->timeout_ms) { ESP_LOGW(TAG, "Failed to open new connection in specified timeout"); ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ESP_TLS_ERR_TYPE_ESP, ESP_ERR_ESP_TLS_CONNECTION_TIMEOUT); return 0; diff --git a/components/esp-tls/esp_tls_platform_port.c b/components/esp-tls/esp_tls_platform_port.c new file mode 100644 index 00000000000..3067a0976ea --- /dev/null +++ b/components/esp-tls/esp_tls_platform_port.c @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_LINUX +#include +#include +#else +#include "esp_timer.h" +#endif + +uint64_t esp_tls_get_platform_time(void) +{ +#if CONFIG_IDF_TARGET_LINUX + // Use gettimeofday for Linux/MacOS, Ideally esp_timer should be used but it is not implemented for Linux/MacOS. + struct timeval time = {}; + gettimeofday(&time, NULL); + uint64_t curr_time = ((uint64_t)time.tv_sec * 1000000) + (time.tv_usec); + return curr_time; +#else + // For all other esp targets use esp_timer + return esp_timer_get_time(); +#endif +} diff --git a/components/esp-tls/private_include/esp_tls_platform_port.h b/components/esp-tls/private_include/esp_tls_platform_port.h new file mode 100644 index 00000000000..44bc0f3d3bb --- /dev/null +++ b/components/esp-tls/private_include/esp_tls_platform_port.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +// This file contains APIs which have different implementation across different targets e.g., Linux, ESP. + +#pragma once + +#include + +/* @brief + * + * Behaviour + * Linux: + * Returns the system time (64 bit) using gettimeofday in microseconds. This shall get changed if someone changes the system time using settimeofday + * ESP targets: + * Returns the time (64 bit) since boot obtained using esp_timer_get_time() in microseconds + * @return + * time uint64_t bit time value + * + */ +uint64_t esp_tls_get_platform_time(void); From 027193ca07ab38190ef29ee9cbc4b354532bd2b2 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 24 Apr 2024 17:01:24 +0800 Subject: [PATCH 027/548] fix(freertos): Fix vTaskList() parameter print order xCoreID was previously printed as the last parameter priority to IDF v5.1, but was changed to the third paramtere from v5.2 onwards. This commit restores the correct ordering. Closes https://github.com/espressif/esp-idf/issues/13675 --- components/freertos/FreeRTOS-Kernel/tasks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index fd5511828ae..5341549b83a 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -5478,7 +5478,7 @@ static void prvResetNextTaskUnblockTime( void ) #if ( configTASKLIST_INCLUDE_COREID == 1 ) { const BaseType_t xCoreID = ( pxTaskStatusArray[ x ].xCoreID == tskNO_AFFINITY ) ? -1 : pxTaskStatusArray[ x ].xCoreID; - sprintf( pcWriteBuffer, "\t%c\t%u\t%d\t%u\t%u\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( int ) xCoreID, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ + sprintf( pcWriteBuffer, "\t%c\t%u\t%u\t%u\t%d\r\n", cStatus, ( unsigned int ) pxTaskStatusArray[ x ].uxCurrentPriority, ( unsigned int ) pxTaskStatusArray[ x ].usStackHighWaterMark, ( unsigned int ) pxTaskStatusArray[ x ].xTaskNumber, ( int ) xCoreID ); /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */ } #else /* configTASKLIST_INCLUDE_COREID == 1 */ { From 6fea6aae8c20d3c1b66bffc85f545f490069f30c Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Thu, 2 May 2024 16:10:21 +0200 Subject: [PATCH 028/548] docs(esp_ringbuf): Corrected example code block * Closes https://github.com/espressif/esp-idf/issues/13730 --- docs/en/api-reference/system/freertos_additions.rst | 6 +++--- docs/zh_CN/api-reference/system/freertos_additions.rst | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/en/api-reference/system/freertos_additions.rst b/docs/en/api-reference/system/freertos_additions.rst index 832baf43b30..a4e8ea8f110 100644 --- a/docs/en/api-reference/system/freertos_additions.rst +++ b/docs/en/api-reference/system/freertos_additions.rst @@ -97,9 +97,9 @@ The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquir //Retrieve space for DMA descriptor and corresponding data buffer //This has to be done with SendAcquire, or the address may be different when we copy - dma_item_t item; + dma_item_t *item; UBaseType_t res = xRingbufferSendAcquire(buf_handle, - &item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000)); + (void**) &item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000)); if (res != pdTRUE) { printf("Failed to acquire memory for item\n"); } @@ -108,7 +108,7 @@ The following example demonstrates the usage of :cpp:func:`xRingbufferSendAcquir .length = buffer_size, .eof = 0, .owner = 1, - .buf = &item->buf, + .buf = item->buf, }; //Actually send to the ring buffer for consumer to use res = xRingbufferSendComplete(buf_handle, &item); diff --git a/docs/zh_CN/api-reference/system/freertos_additions.rst b/docs/zh_CN/api-reference/system/freertos_additions.rst index 0f8db58e71b..eb2f0f41b46 100644 --- a/docs/zh_CN/api-reference/system/freertos_additions.rst +++ b/docs/zh_CN/api-reference/system/freertos_additions.rst @@ -97,9 +97,9 @@ ESP-IDF 环形 buffer 是一个典型的 FIFO buffer,支持任意大小的数 //为 DMA 描述符和相应的数据 buffer 检索空间 //此步骤必须通过 SendAcquire 完成,否则,复制时地址可能会不同 - dma_item_t item; + dma_item_t *item; UBaseType_t res = xRingbufferSendAcquire(buf_handle, - &item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000)); + (void**) &item, DMA_ITEM_SIZE(buffer_size), pdMS_TO_TICKS(1000)); if (res != pdTRUE) { printf("Failed to acquire memory for item\n"); } @@ -108,7 +108,7 @@ ESP-IDF 环形 buffer 是一个典型的 FIFO buffer,支持任意大小的数 .length = buffer_size, .eof = 0, .owner = 1, - .buf = &item->buf, + .buf = item->buf, }; //实际发送到环形 buffer 以供使用 res = xRingbufferSendComplete(buf_handle, &item); From a61a367bc45e7aadf1bb45f86526b78710edf287 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 25 Apr 2024 14:22:04 +0530 Subject: [PATCH 029/548] fix(nimble): Deselect MBEDTLS_ECP_RESTARTABLE when mbedTLS is used --- components/bt/controller/esp32c2/Kconfig.in | 1 - components/bt/controller/esp32c5/Kconfig.in | 1 - components/bt/controller/esp32c6/Kconfig.in | 1 - components/bt/controller/esp32h2/Kconfig.in | 1 - components/bt/host/nimble/Kconfig.in | 5 ++--- 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index 9543582b9c4..9a04ae6394c 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -349,7 +349,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index e8c1c0b8e2e..02ac4995d27 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -365,7 +365,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 94721bbf08a..0dcc8996bf6 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -365,7 +365,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index 9c91e4ddc3a..e0c4936156e 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -356,7 +356,6 @@ config BT_LE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on !BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index ac5a288f2a6..616dd20fc15 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -498,7 +498,6 @@ config BT_NIMBLE_CRYPTO_STACK_MBEDTLS bool "Override TinyCrypt with mbedTLS for crypto computations" default y depends on BT_NIMBLE_ENABLED - select MBEDTLS_ECP_RESTARTABLE select MBEDTLS_CMAC_C help Enable this option to choose mbedTLS instead of TinyCrypt for crypto @@ -597,7 +596,7 @@ if BT_NIMBLE_EXT_ADV Enable this option to start periodic advertisement. config BT_NIMBLE_PERIODIC_ADV_SYNC_TRANSFER - bool "Enable Transer Sync Events" + bool "Enable Transfer Sync Events" depends on BT_NIMBLE_ENABLE_PERIODIC_ADV default y help @@ -666,7 +665,7 @@ config BT_NIMBLE_GATT_CACHING_MAX_DSCS depends on BT_NIMBLE_GATT_CACHING default 64 help - Set this option to set the upper limit on number of discriptors per connection to be cached. + Set this option to set the upper limit on number of descriptors per connection to be cached. config BT_NIMBLE_WHITELIST_SIZE int "BLE white list size" From d42e894a744a5469ffa2e7733d3e6ab9cfe000a8 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 24 Apr 2024 20:39:52 +0400 Subject: [PATCH 030/548] fix(system): discard eh_frame sections if disabled in sdkconfig --- components/esp_system/ld/esp32/sections.ld.in | 14 ++++++++-- .../esp_system/ld/esp32c2/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32c3/sections.ld.in | 27 ++++++++++++++----- .../ld/esp32c5/beta3/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32c5/mp/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32c6/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32c61/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32h2/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32p4/sections.ld.in | 27 ++++++++++++++----- .../esp_system/ld/esp32s2/sections.ld.in | 14 ++++++++-- .../esp_system/ld/esp32s3/sections.ld.in | 14 ++++++++-- 11 files changed, 196 insertions(+), 62 deletions(-) diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index 19c395cbe50..b67d6af10d5 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -352,6 +352,7 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) +#if CONFIG_COMPILER_CXX_EXCEPTIONS ALIGNED_SYMBOL(4, __eh_frame) KEEP(*(.eh_frame)) /** @@ -359,6 +360,7 @@ SECTIONS * (see __FRAME_END__ in libgcc sources), it is manually provided here. */ LONG(0); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS /** * C++ constructor tables. @@ -500,12 +502,20 @@ SECTIONS */ .xt.prop 0 : { - KEEP (*(.xt.prop .gnu.linkonce.prop.*)) + KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) } .xt.lit 0 : { - KEEP (*(.xt.lit .gnu.linkonce.p.*)) + KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) + } + + /DISCARD/ : + { + *(.eh_frame_hdr) +#if !CONFIG_COMPILER_CXX_EXCEPTIONS + *(.eh_frame) +#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS } } diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index 42c906acad1..43255d8d933 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -233,17 +233,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -254,6 +258,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -339,13 +345,20 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index f5962dd6f07..c8c29d8cd54 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -351,17 +351,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -372,6 +376,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -451,13 +457,20 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c5/beta3/sections.ld.in b/components/esp_system/ld/esp32c5/beta3/sections.ld.in index c18b9510f23..16533c7af6d 100644 --- a/components/esp_system/ld/esp32c5/beta3/sections.ld.in +++ b/components/esp_system/ld/esp32c5/beta3/sections.ld.in @@ -374,17 +374,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -395,6 +399,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -442,13 +448,20 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c5/mp/sections.ld.in b/components/esp_system/ld/esp32c5/mp/sections.ld.in index c0b76d0af28..91013909f6d 100644 --- a/components/esp_system/ld/esp32c5/mp/sections.ld.in +++ b/components/esp_system/ld/esp32c5/mp/sections.ld.in @@ -374,17 +374,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -395,6 +399,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -442,13 +448,20 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index 2af34051548..cfd95dd74d9 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -364,17 +364,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -385,6 +389,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -432,11 +438,18 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } diff --git a/components/esp_system/ld/esp32c61/sections.ld.in b/components/esp_system/ld/esp32c61/sections.ld.in index c0b76d0af28..91013909f6d 100644 --- a/components/esp_system/ld/esp32c61/sections.ld.in +++ b/components/esp_system/ld/esp32c61/sections.ld.in @@ -374,17 +374,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -395,6 +399,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -442,13 +448,20 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index 2af34051548..cfd95dd74d9 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -364,17 +364,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -385,6 +389,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > default_rodata_seg ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -432,11 +438,18 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index 2f0ff2d0f00..9b5667b18ef 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -406,17 +406,21 @@ SECTIONS .eh_frame_hdr : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame_hdr) KEEP (*(.eh_frame_hdr)) __eh_frame_hdr_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.eh_frame)); } > rodata_seg_low ASSERT_SECTIONS_GAP(.eh_frame_hdr, .eh_frame) .eh_frame : { +#if CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME ALIGNED_SYMBOL(4, __eh_frame) KEEP (*(.eh_frame)) @@ -427,6 +431,8 @@ SECTIONS LONG(0); __eh_frame_end = ABSOLUTE(.); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME + . = ALIGN(ALIGNOF(.flash.tdata)); } > rodata_seg_low ASSERT_SECTIONS_GAP(.eh_frame, .flash.tdata) @@ -508,11 +514,18 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start_high) } > sram_high - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - /DISCARD/ : { *(.rela.*) } + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } } diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index f177a766fef..a6a5e4c806e 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -335,6 +335,7 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) +#if CONFIG_COMPILER_CXX_EXCEPTIONS ALIGNED_SYMBOL(4, __eh_frame) KEEP(*(.eh_frame)) /** @@ -342,6 +343,7 @@ SECTIONS * (see __FRAME_END__ in libgcc sources), it is manually provided here. */ LONG(0); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS /** * C++ constructor tables. @@ -464,12 +466,20 @@ SECTIONS */ .xt.prop 0 : { - KEEP (*(.xt.prop .gnu.linkonce.prop.*)) + KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) } .xt.lit 0 : { - KEEP (*(.xt.lit .gnu.linkonce.p.*)) + KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) + } + + /DISCARD/ : + { + *(.eh_frame_hdr) +#if !CONFIG_COMPILER_CXX_EXCEPTIONS + *(.eh_frame) +#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS } } diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index 553c4f2e255..6eabbd5026b 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -362,6 +362,7 @@ SECTIONS __XT_EXCEPTION_DESCS_END__ = ABSOLUTE(.); *(.xt_except_desc_end) +#if CONFIG_COMPILER_CXX_EXCEPTIONS ALIGNED_SYMBOL(4, __eh_frame) KEEP(*(.eh_frame)) /** @@ -369,6 +370,7 @@ SECTIONS * (see __FRAME_END__ in libgcc sources), it is manually provided here. */ LONG(0); +#endif // CONFIG_COMPILER_CXX_EXCEPTIONS /** * C++ constructor tables. @@ -497,12 +499,20 @@ SECTIONS */ .xt.prop 0 : { - KEEP (*(.xt.prop .gnu.linkonce.prop.*)) + KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) } .xt.lit 0 : { - KEEP (*(.xt.lit .gnu.linkonce.p.*)) + KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) + } + + /DISCARD/ : + { + *(.eh_frame_hdr) +#if !CONFIG_COMPILER_CXX_EXCEPTIONS + *(.eh_frame) +#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS } } From 9fd92e8bf44333aaac1b95f3768ca89107ac041d Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 25 Apr 2024 23:44:22 +0400 Subject: [PATCH 031/548] fix(cxx): use __cxa_throw() stub in case exceptions disabled Reduces binary size since the linker will drop some code due to --gc-sections. --- components/cxx/CMakeLists.txt | 4 +++- components/cxx/cxx_exception_stubs.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/components/cxx/CMakeLists.txt b/components/cxx/CMakeLists.txt index 228414599cd..a14aa9b148d 100644 --- a/components/cxx/CMakeLists.txt +++ b/components/cxx/CMakeLists.txt @@ -39,7 +39,9 @@ if(NOT CONFIG_CXX_EXCEPTIONS) _Unwind_Resume_or_Rethrow _Unwind_Backtrace __cxa_call_unexpected - __gxx_personality_v0) + __gxx_personality_v0 + __cxa_throw + __cxa_allocate_exception) foreach(wrap ${WRAP_FUNCTIONS}) target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") diff --git a/components/cxx/cxx_exception_stubs.cpp b/components/cxx/cxx_exception_stubs.cpp index 827d40dd814..7e794755c07 100644 --- a/components/cxx/cxx_exception_stubs.cpp +++ b/components/cxx/cxx_exception_stubs.cpp @@ -178,4 +178,16 @@ extern "C" _Unwind_Reason_Code __wrap___gxx_personality_v0(int version, return abort_return<_Unwind_Reason_Code>(); } +// Reduces binary size since the linker will drop some code due to --gc-sections. +extern "C" void __wrap___cxa_allocate_exception(void) +{ + abort(); +} + +// Reduces binary size since the linker will drop some code due to --gc-sections. +extern "C" void __wrap___cxa_throw(void) +{ + abort(); +} + #endif // CONFIG_COMPILER_CXX_EXCEPTIONS From a6d82513664995792cda0315581643e697469448 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 25 Apr 2024 15:20:48 +0800 Subject: [PATCH 032/548] feat(gdma): set default valid memory range for gdma --- components/hal/esp32p4/include/hal/ahb_dma_ll.h | 12 ++++++++++++ components/hal/esp32p4/include/hal/axi_dma_ll.h | 14 ++++++++++++++ components/hal/gdma_hal_ahb_v2.c | 1 + components/hal/gdma_hal_axi.c | 1 + 4 files changed, 28 insertions(+) diff --git a/components/hal/esp32p4/include/hal/ahb_dma_ll.h b/components/hal/esp32p4/include/hal/ahb_dma_ll.h index b7a4667ed15..acf76923e04 100644 --- a/components/hal/esp32p4/include/hal/ahb_dma_ll.h +++ b/components/hal/esp32p4/include/hal/ahb_dma_ll.h @@ -57,6 +57,18 @@ static inline void ahb_dma_ll_reset_fsm(ahb_dma_dev_t *dev) dev->misc_conf.ahbm_rst_inter = 0; } +/** + * @brief Preset valid memory range for AHB-DMA + * + * @param dev DMA register base address + */ +static inline void ahb_dma_ll_set_default_memory_range(ahb_dma_dev_t *dev) +{ + // AHB-DMA can access L2MEM, L2ROM, MSPI Flash, MSPI PSRAM + dev->intr_mem_start_addr.val = 0x40000000; + dev->intr_mem_end_addr.val = 0x4FFC0000; +} + ///////////////////////////////////// RX ///////////////////////////////////////// /** * @brief Get DMA RX channel interrupt status word diff --git a/components/hal/esp32p4/include/hal/axi_dma_ll.h b/components/hal/esp32p4/include/hal/axi_dma_ll.h index 171b2045277..5cd68088720 100644 --- a/components/hal/esp32p4/include/hal/axi_dma_ll.h +++ b/components/hal/esp32p4/include/hal/axi_dma_ll.h @@ -59,6 +59,20 @@ static inline void axi_dma_ll_reset_fsm(axi_dma_dev_t *dev) dev->misc_conf.axim_rst_wr_inter = 0; } +/** + * @brief Preset valid memory range for AXI-DMA + * + * @param dev DMA register base address + */ +static inline void axi_dma_ll_set_default_memory_range(axi_dma_dev_t *dev) +{ + // AXI-DMA can access L2MEM, L2ROM, MSPI Flash, MSPI PSRAM + dev->intr_mem_start_addr.val = 0x4FC00000; + dev->intr_mem_end_addr.val = 0x4FFC0000; + dev->extr_mem_start_addr.val = 0x40000000; + dev->extr_mem_end_addr.val = 0x4C000000; +} + ///////////////////////////////////// RX ///////////////////////////////////////// /** * @brief Get DMA RX channel interrupt status word diff --git a/components/hal/gdma_hal_ahb_v2.c b/components/hal/gdma_hal_ahb_v2.c index 2b4f7a9e90f..71385465fea 100644 --- a/components/hal/gdma_hal_ahb_v2.c +++ b/components/hal/gdma_hal_ahb_v2.c @@ -244,4 +244,5 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_ahb_hal_enable_etm_task; #endif // SOC_GDMA_SUPPORT_ETM + ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev); } diff --git a/components/hal/gdma_hal_axi.c b/components/hal/gdma_hal_axi.c index 67e3aeae404..da31498cad3 100644 --- a/components/hal/gdma_hal_axi.c +++ b/components/hal/gdma_hal_axi.c @@ -244,4 +244,5 @@ void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_axi_hal_enable_etm_task; #endif // SOC_GDMA_SUPPORT_ETM + axi_dma_ll_set_default_memory_range(hal->axi_dma_dev); } From a04f786380eb18dbce1df0537ff5f75ad73fbfa5 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 24 Apr 2024 18:04:36 +0800 Subject: [PATCH 033/548] test(gdma): can read data from flash rodata --- .../test_apps/dma/main/test_gdma_crc.c | 28 +++++++++---------- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 +++ components/soc/esp32p4/include/soc/soc_caps.h | 3 ++ .../spi_flash/spi_flash_concurrency.rst | 7 +++++ .../spi_flash/spi_flash_concurrency.rst | 7 +++++ 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c index b704aa9e662..fd0e75a5fdf 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c @@ -11,6 +11,7 @@ #include "freertos/semphr.h" #include "unity.h" #include "esp_heap_caps.h" +#include "esp_memory_utils.h" #include "esp_private/gdma.h" #include "hal/dma_types.h" #include "soc/soc_caps.h" @@ -62,6 +63,8 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu uint32_t crc_result = 0; const char *test_input_string = "Share::Connect::Innovate"; size_t input_data_size = strlen(test_input_string); + // this test case also test the GDMA can fetch data from MSPI Flash + TEST_ASSERT_TRUE(esp_ptr_in_drom(test_input_string)); printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string); gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); @@ -71,27 +74,22 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask); TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); - // allocate the source and destination buffer from SRAM - // |--------------------------------------------------| - // | 128 bytes DMA descriptor | 128 bytes data buffer | - // |--------------------------------------------------| - size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - uint8_t *src_buf = heap_caps_aligned_calloc(sram_alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - TEST_ASSERT_NOT_NULL(src_buf); - dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; - uint8_t *src_data = src_buf + 64; - memcpy(src_data, test_input_string, input_data_size); + size_t sram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + size_t alignment = MAX(sram_cache_line_size, 8); + dma_descriptor_align8_t *tx_descs = heap_caps_aligned_calloc(alignment, 1, sizeof(dma_descriptor_align8_t), + MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(tx_descs); - tx_descs->buffer = src_data; - tx_descs->dw0.size = 256 - 64; + tx_descs->buffer = (void *)test_input_string; + tx_descs->dw0.size = input_data_size + 1; // +1 for '\0' tx_descs->dw0.length = input_data_size; tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; tx_descs->dw0.suc_eof = 1; tx_descs->next = NULL; - if (sram_alignment) { + if (sram_cache_line_size) { // do write-back for the buffer because it's in the cache - TEST_ESP_OK(esp_cache_msync((void *)src_buf, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + TEST_ESP_OK(esp_cache_msync((void *)tx_descs, sizeof(dma_descriptor_align8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED)); } for (int i = 0; i < test_num_crc_algorithm; i++) { @@ -111,7 +109,7 @@ static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_nu TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result); } - free(src_buf); + free(tx_descs); } TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]") diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6597ac120fb..3fb643d379f 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -451,6 +451,10 @@ config SOC_DS_KEY_CHECK_MAX_WAIT_US int default 1100 +config SOC_DMA_CAN_ACCESS_MSPI_MEM + bool + default y + config SOC_AHB_GDMA_VERSION int default 2 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 2b8089c0f75..c2706a0ba1b 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -182,6 +182,9 @@ See TRM DS chapter for more details */ #define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100) +/*-------------------------- DMA Common CAPS ----------------------------------------*/ +#define SOC_DMA_CAN_ACCESS_MSPI_MEM 1 /*!< DMA can access MSPI memory (e.g. Flash, PSRAM) */ + /*-------------------------- GDMA CAPS -------------------------------------*/ #define SOC_AHB_GDMA_VERSION 2 #define SOC_GDMA_SUPPORT_CRC 1 diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index dcd5198928f..b20dc9bb82f 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,6 +77,13 @@ Non-IRAM-Safe Interrupt Handlers If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not get executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, users will not see the corresponding hardware event happening. +.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM + + When DMA Read Data from Flash + ----------------------------- + + When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM. + .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index a222654aa8f..7e45a61373e 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,6 +77,13 @@ IRAM 安全中断处理程序 如果在注册时没有设置 ``ESP_INTR_FLAG_IRAM`` 标志,当禁用 cache 时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要禁用了 cache,就不会发生相应的硬件事件。 +.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM + + 当 DMA 也可以访问 Flash 中的数据时 + ---------------------------------- + + 当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。 + .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND From 6b0a815b78927ed1368cfba1152c541a911c1780 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Sun, 28 Apr 2024 15:16:08 +0800 Subject: [PATCH 034/548] fix(jpeg): Fix several issues reported recently, 1. Fix decode images with dri marker failed, 2. Fix encode sometimes get length error --- components/esp_driver_jpeg/jpeg_decode.c | 2 +- components/esp_driver_jpeg/jpeg_encode.c | 3 ++- components/esp_driver_jpeg/jpeg_parse_marker.c | 4 ++-- components/esp_driver_jpeg/jpeg_private.h | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esp_driver_jpeg/jpeg_decode.c b/components/esp_driver_jpeg/jpeg_decode.c index 422c2afd2b6..6ab993c616f 100644 --- a/components/esp_driver_jpeg/jpeg_decode.c +++ b/components/esp_driver_jpeg/jpeg_decode.c @@ -271,7 +271,6 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_ esp_err_t jpeg_del_decoder_engine(jpeg_decoder_handle_t decoder_engine) { ESP_RETURN_ON_FALSE(decoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg decode handle is null"); - ESP_RETURN_ON_ERROR(jpeg_release_codec_handle(decoder_engine->codec_base), TAG, "release codec failed"); if (decoder_engine) { if (decoder_engine->rxlink) { @@ -295,6 +294,7 @@ esp_err_t jpeg_del_decoder_engine(jpeg_decoder_handle_t decoder_engine) if (decoder_engine->intr_handle) { jpeg_isr_deregister(decoder_engine->codec_base, decoder_engine->intr_handle); } + ESP_RETURN_ON_ERROR(jpeg_release_codec_handle(decoder_engine->codec_base), TAG, "release codec failed"); free(decoder_engine); } return ESP_OK; diff --git a/components/esp_driver_jpeg/jpeg_encode.c b/components/esp_driver_jpeg/jpeg_encode.c index d4df1137ec7..e0b959691bf 100644 --- a/components/esp_driver_jpeg/jpeg_encode.c +++ b/components/esp_driver_jpeg/jpeg_encode.c @@ -262,6 +262,7 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ } if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_EOF) { + ESP_GOTO_ON_ERROR(esp_cache_msync((void*)encoder_engine->rxlink, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "sync memory to cache failed"); compressed_size = s_dma_desc_get_len(encoder_engine->rxlink); uint32_t _compressed_size = JPEG_ALIGN_UP(compressed_size, cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)); ESP_GOTO_ON_ERROR(esp_cache_msync((void*)(bit_stream + encoder_engine->header_info->header_len), _compressed_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "sync memory to cache failed"); @@ -283,7 +284,6 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ esp_err_t jpeg_del_encoder_engine(jpeg_encoder_handle_t encoder_engine) { ESP_RETURN_ON_FALSE(encoder_engine, ESP_ERR_INVALID_ARG, TAG, "jpeg encoder handle is null"); - ESP_RETURN_ON_ERROR(jpeg_release_codec_handle(encoder_engine->codec_base), TAG, "release codec failed"); if (encoder_engine) { if (encoder_engine->rxlink) { @@ -307,6 +307,7 @@ esp_err_t jpeg_del_encoder_engine(jpeg_encoder_handle_t encoder_engine) if (encoder_engine->intr_handle) { jpeg_isr_deregister(encoder_engine->codec_base, encoder_engine->intr_handle); } + ESP_RETURN_ON_ERROR(jpeg_release_codec_handle(encoder_engine->codec_base), TAG, "release codec failed"); free(encoder_engine); } return ESP_OK; diff --git a/components/esp_driver_jpeg/jpeg_parse_marker.c b/components/esp_driver_jpeg/jpeg_parse_marker.c index e457ccfd5f3..13fcc831d0a 100644 --- a/components/esp_driver_jpeg/jpeg_parse_marker.c +++ b/components/esp_driver_jpeg/jpeg_parse_marker.c @@ -130,10 +130,10 @@ esp_err_t jpeg_parse_sof_marker(jpeg_dec_header_info_t *header_info) // The vertical and horizontal in process must be divided by mcu block. if (header_info->origin_v % header_info->mcuy != 0) { - header_info->process_v = (ceil(header_info->origin_v / header_info->mcuy) + 1) * header_info->mcuy; + header_info->process_v = (uint32_t)(ceil(header_info->origin_v / header_info->mcuy) + 1) * header_info->mcuy; } if (header_info->origin_h % header_info->mcux != 0) { - header_info->process_h = (ceil(header_info->origin_h / header_info->mcux) + 1) * header_info->mcux; + header_info->process_h = (uint32_t)(ceil(header_info->origin_h / header_info->mcux) + 1) * header_info->mcux; } return ESP_OK; diff --git a/components/esp_driver_jpeg/jpeg_private.h b/components/esp_driver_jpeg/jpeg_private.h index 01a489f930a..2c43cdd06fa 100644 --- a/components/esp_driver_jpeg/jpeg_private.h +++ b/components/esp_driver_jpeg/jpeg_private.h @@ -87,7 +87,7 @@ typedef struct { uint8_t huffcode[2][2][JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // Huffman decoded data tables [id][dcac] uint32_t tmp_huff[JPEG_HUFFMAN_AC_VALUE_TABLE_LEN]; // temp buffer to store huffman code bool dri_marker; // If we have dri marker in table - uint8_t ri; // Restart interval + uint16_t ri; // Restart interval } jpeg_dec_header_info_t; struct jpeg_decoder_t { From ae0eabec53d5fa1d826a7f95aff42191694949de Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Mon, 6 May 2024 12:30:08 +0200 Subject: [PATCH 035/548] fix: display correct help in the idf_size.py wrapper Currently the wrapper tries to figure out which version of the esp-idf-size should be started. The legacy version is used if explicitly requested by the -l/--legacy option or if json format is specified. This works fine, but if help is requested, it is printed for the wrapper as shown bellow $ idf_size.py -h usage: idf_size.py [-h] [--format FORMAT] [-l] options: -h, --help show this help message and exit --format FORMAT -l, --legacy This is not convenient and the full help from the underlying version should be displayed. Fix this by only peeking into the args to figure out if legacy or refactored version should be started and always spawn the underlying esp_idf_size python module. This is done by using exit_on_error=False and add_help=False for the ArgumentParser. When help for refactored version is requested a note as following is printed to notify users that the legacy version can still be used. $ idf_size.py -h Note: legacy esp_idf_size version can be invoked by specifying the -l/--legacy option or by setting the ESP_IDF_SIZE_LEGACY environment variable. Signed-off-by: Frantisek Hrbata --- tools/idf_size.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tools/idf_size.py b/tools/idf_size.py index 342340002ca..80c968239a4 100755 --- a/tools/idf_size.py +++ b/tools/idf_size.py @@ -1,22 +1,30 @@ #!/usr/bin/env python # -# SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD # # SPDX-License-Identifier: Apache-2.0 # - import argparse import os import subprocess import sys if __name__ == '__main__': - parser = argparse.ArgumentParser() + # Here the argparse is used only to "peek" into arguments if + # legacy version is requested or if old json format is specified. + # In these two cases the esp_idf_size legacy version is spawned. + parser = argparse.ArgumentParser(exit_on_error=False, add_help=False) parser.add_argument('--format') parser.add_argument('-l', '--legacy', action='store_true', default=os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1') + + # The sys.argv is parsed with "exit_on_error", but the argparse.ArgumentError + # exception should never occur, because unknown args should be put into + # the rest variable, since the parse_known_args() method is used. args, rest = parser.parse_known_args() if not args.legacy and args.format != 'json': + # By default start the refactored version, unless legacy version is explicitly requested with + # -l/--legacy option or if old json format is specified. try: import esp_idf_size.ng # noqa: F401 except ImportError: @@ -24,9 +32,9 @@ args.legacy = True else: os.environ['ESP_IDF_SIZE_NG'] = '1' - - if args.legacy and args.format in ['json2', 'raw', 'tree']: - sys.exit(f'Legacy esp-idf-size does not support {args.format} format') + if not rest or '-h' in rest or '--help' in rest: + print(('Note: legacy esp_idf_size version can be invoked by specifying the -l/--legacy ' + 'option or by setting the ESP_IDF_SIZE_LEGACY environment variable.')) if args.format is not None: rest = ['--format', args.format] + rest From 54285550926acb7b6122130cc716a34d2f3d5a11 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Mon, 15 Apr 2024 12:08:48 +0530 Subject: [PATCH 036/548] fix(esp_https_server): fix memory leak during configuring http server This MR This restructured code to prevent memory leak during the starting HTTP server. Closes https://github.com/espressif/esp-idf/issues/13526 --- components/esp_https_server/src/https_server.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/components/esp_https_server/src/https_server.c b/components/esp_https_server/src/https_server.c index f8693ffb946..058faab30e8 100644 --- a/components/esp_https_server/src/https_server.c +++ b/components/esp_https_server/src/https_server.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -366,7 +366,6 @@ static esp_err_t create_secure_context(const struct httpd_ssl_config *config, ht free((void *) cfg->cacert_buf); } free(cfg); - free(*ssl_ctx); return ret; } @@ -379,14 +378,17 @@ esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *conf ESP_LOGI(TAG, "Starting server"); esp_err_t ret = ESP_OK; + httpd_ssl_ctx_t *ssl_ctx = NULL; + if (HTTPD_SSL_TRANSPORT_SECURE == config->transport_mode) { - httpd_ssl_ctx_t *ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t)); + ssl_ctx = calloc(1, sizeof(httpd_ssl_ctx_t)); if (!ssl_ctx) { return ESP_ERR_NO_MEM; } ret = create_secure_context(config, &ssl_ctx); if (ret != ESP_OK) { + free(ssl_ctx); return ret; } @@ -411,7 +413,11 @@ esp_err_t httpd_ssl_start(httpd_handle_t *pHandle, struct httpd_ssl_config *conf httpd_handle_t handle = NULL; ret = httpd_start(&handle, &config->httpd); - if (ret != ESP_OK) return ret; + if (ret != ESP_OK) { + free(ssl_ctx); + ssl_ctx = NULL; + return ret; + } *pHandle = handle; From 855d1eb170db486389d4994aa47dd31cfe51349c Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Mon, 15 Apr 2024 14:52:37 +0530 Subject: [PATCH 037/548] fix: Refactored script for initiating Python-based HTTPS server This commit refactors the script responsible for starting a Python-based HTTPS server to align with the latest Python version's requirements and best practices. Closes https://github.com/espressif/esp-idf/issues/13575 --- .../https_request/pytest_https_request.py | 8 +-- .../advanced_https_ota/pytest_advanced_ota.py | 52 ++++++++++--------- .../native_ota_example/pytest_native_ota.py | 27 +++++----- .../pytest_pre_encrypted_ota.py | 9 ++-- .../simple_ota_example/pytest_simple_ota.py | 7 +-- 5 files changed, 55 insertions(+), 48 deletions(-) diff --git a/examples/protocols/https_request/pytest_https_request.py b/examples/protocols/https_request/pytest_https_request.py index 0afcda609e5..340945937ec 100644 --- a/examples/protocols/https_request/pytest_https_request.py +++ b/examples/protocols/https_request/pytest_https_request.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import http.server import logging @@ -50,8 +50,10 @@ def start_https_server(server_file: str, key_file: str, server_ip: str, server_p requestHandler = https_request_handler() httpd = http.server.HTTPServer((server_ip, server_port), requestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() diff --git a/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py b/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py index d25ca408e43..fbabc2c4e7e 100644 --- a/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py +++ b/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py @@ -50,9 +50,10 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int) -> requestHandler = https_request_handler() httpd = http.server.HTTPServer((server_ip, server_port), requestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, - keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() @@ -88,9 +89,10 @@ def start_redirect_server(ota_image_dir: str, server_ip: str, server_port: int, httpd = http.server.HTTPServer((server_ip, server_port), redirectHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, - keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() @@ -154,8 +156,8 @@ def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) -> truncated_bin_size = 64000 binary_file = os.path.join(dut.app.binary_path, bin_name) with open(binary_file, 'rb+') as f: - with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo: - fo.write(f.read(truncated_bin_size)) + with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as output_file: + output_file.write(f.read(truncated_bin_size)) binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) @@ -187,7 +189,7 @@ def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) -> @pytest.mark.ethernet_ota def test_examples_protocol_advanced_https_ota_example_truncated_header(dut: Dut) -> None: """ - Working of OTA if headers of binary file are truncated is vaildated in this test case. + Working of OTA if headers of binary file are truncated is validated in this test case. Application should return with error message in this case. steps: | 1. join AP/Ethernet @@ -205,8 +207,8 @@ def test_examples_protocol_advanced_https_ota_example_truncated_header(dut: Dut) # check and log bin size binary_file = os.path.join(dut.app.binary_path, bin_name) with open(binary_file, 'rb+') as f: - with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo: - fo.write(f.read(truncated_bin_size)) + with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as output_file: + output_file.write(f.read(truncated_bin_size)) binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) @@ -249,16 +251,16 @@ def test_examples_protocol_advanced_https_ota_example_random(dut: Dut) -> None: server_port = 8001 # Random binary file to be generated random_bin_name = 'random.bin' - # Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case + # Size of random binary file. 32000 is chosen, to reduce the time required to run the test-case random_bin_size = 32000 # check and log bin size binary_file = os.path.join(dut.app.binary_path, random_bin_name) - with open(binary_file, 'wb+') as fo: + with open(binary_file, 'wb+') as output_file: # First byte of binary file is always set to zero. If first byte is generated randomly, # in some cases it may generate 0xE9 which will result in failure of testcase. - fo.write(struct.pack('B', 0)) + output_file.write(struct.pack('B', 0)) for i in range(random_bin_size - 1): - fo.write(struct.pack('B', random.randrange(0,255,1))) + output_file.write(struct.pack('B', random.randrange(0,255,1))) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) thread1.daemon = True @@ -302,7 +304,7 @@ def test_examples_protocol_advanced_https_ota_example_invalid_chip_id(dut: Dut) # Random binary file to be generated random_bin_name = 'random.bin' random_binary_file = os.path.join(dut.app.binary_path, random_bin_name) - # Size of random binary file. 2000 is choosen, to reduce the time required to run the test-case + # Size of random binary file. 2000 is chosen, to reduce the time required to run the test-case random_bin_size = 2000 binary_file = os.path.join(dut.app.binary_path, bin_name) @@ -310,8 +312,8 @@ def test_examples_protocol_advanced_https_ota_example_invalid_chip_id(dut: Dut) data = list(f.read(random_bin_size)) # Changing Chip id data[13] = 0xfe - with open(random_binary_file, 'wb+') as fo: - fo.write(bytearray(data)) + with open(random_binary_file, 'wb+') as output_file: + output_file.write(bytearray(data)) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) thread1.daemon = True @@ -452,11 +454,11 @@ def test_examples_protocol_advanced_https_ota_example_anti_rollback(dut: Dut) -> binary_file = os.path.join(dut.app.binary_path, bin_name) file_size = os.path.getsize(binary_file) with open(binary_file, 'rb+') as f: - with open(os.path.join(dut.app.binary_path, anti_rollback_bin_name), 'wb+') as fo: - fo.write(f.read(file_size)) + with open(os.path.join(dut.app.binary_path, anti_rollback_bin_name), 'wb+') as output_file: + output_file.write(f.read(file_size)) # Change security_version to 0 for negative test case - fo.seek(36) - fo.write(b'\x00') + output_file.seek(36) + output_file.write(b'\x00') binary_file = os.path.join(dut.app.binary_path, anti_rollback_bin_name) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) @@ -666,10 +668,10 @@ def test_examples_protocol_advanced_https_ota_example_openssl_aligned_bin(dut: D # Dummy data required to align binary size to 289 bytes boundary dummy_data_size = 289 - (bin_size % 289) with open(binary_file, 'rb+') as f: - with open(os.path.join(dut.app.binary_path, aligned_bin_name), 'wb+') as fo: - fo.write(f.read(bin_size)) + with open(os.path.join(dut.app.binary_path, aligned_bin_name), 'wb+') as output_file: + output_file.write(f.read(bin_size)) for _ in range(dummy_data_size): - fo.write(struct.pack('B', random.randrange(0,255,1))) + output_file.write(struct.pack('B', random.randrange(0,255,1))) # Start server chunked_server = start_chunked_server(dut.app.binary_path, 8070) try: diff --git a/examples/system/ota/native_ota_example/pytest_native_ota.py b/examples/system/ota/native_ota_example/pytest_native_ota.py index ba61b6c75c3..3c0fcfe6dbb 100644 --- a/examples/system/ota/native_ota_example/pytest_native_ota.py +++ b/examples/system/ota/native_ota_example/pytest_native_ota.py @@ -110,9 +110,10 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int) -> requestHandler = https_request_handler() httpd = http.server.HTTPServer((server_ip, server_port), requestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, - keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() @@ -186,8 +187,8 @@ def test_examples_protocol_native_ota_example_truncated_bin(dut: Dut) -> None: with open(binary_file, 'rb+') as fr: bin_data = fr.read(truncated_bin_size) binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) - with open(binary_file, 'wb+') as fo: - fo.write(bin_data) + with open(binary_file, 'wb+') as output_file: + output_file.write(bin_data) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) thread1.daemon = True @@ -215,7 +216,7 @@ def test_examples_protocol_native_ota_example_truncated_bin(dut: Dut) -> None: @pytest.mark.ethernet_ota def test_examples_protocol_native_ota_example_truncated_header(dut: Dut) -> None: """ - Working of OTA if headers of binary file are truncated is vaildated in this test case. + Working of OTA if headers of binary file are truncated is validated in this test case. Application should return with error message in this case. steps: | 1. join AP/Ethernet @@ -235,8 +236,8 @@ def test_examples_protocol_native_ota_example_truncated_header(dut: Dut) -> None with open(binary_file, 'rb+') as fr: bin_data = fr.read(truncated_bin_size) binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) - with open(binary_file, 'wb+') as fo: - fo.write(bin_data) + with open(binary_file, 'wb+') as output_file: + output_file.write(bin_data) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) thread1.daemon = True @@ -275,17 +276,17 @@ def test_examples_protocol_native_ota_example_random(dut: Dut) -> None: server_port = 8002 # Random binary file to be generated random_bin_name = 'random.bin' - # Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case + # Size of random binary file. 32000 is chosen, to reduce the time required to run the test-case random_bin_size = 32000 # check and log bin size binary_file = os.path.join(dut.app.binary_path, random_bin_name) - fo = open(binary_file, 'wb+') + output_file = open(binary_file, 'wb+') # First byte of binary file is always set to zero. If first byte is generated randomly, # in some cases it may generate 0xE9 which will result in failure of testcase. - with open(binary_file, 'wb+') as fo: - fo.write(struct.pack('B', 0)) + with open(binary_file, 'wb+') as output_file: + output_file.write(struct.pack('B', 0)) for _ in range(random_bin_size - 1): - fo.write(struct.pack('B', random.randrange(0,255,1))) + output_file.write(struct.pack('B', random.randrange(0,255,1))) # Start server thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) thread1.daemon = True diff --git a/examples/system/ota/pre_encrypted_ota/pytest_pre_encrypted_ota.py b/examples/system/ota/pre_encrypted_ota/pytest_pre_encrypted_ota.py index 85f27c31486..c2321735743 100644 --- a/examples/system/ota/pre_encrypted_ota/pytest_pre_encrypted_ota.py +++ b/examples/system/ota/pre_encrypted_ota/pytest_pre_encrypted_ota.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import http.server import multiprocessing @@ -46,9 +46,10 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int) -> requestHandler = https_request_handler() httpd = http.server.HTTPServer((server_ip, server_port), requestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, - keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() diff --git a/examples/system/ota/simple_ota_example/pytest_simple_ota.py b/examples/system/ota/simple_ota_example/pytest_simple_ota.py index a6f4a326796..0595a9c2f76 100644 --- a/examples/system/ota/simple_ota_example/pytest_simple_ota.py +++ b/examples/system/ota/simple_ota_example/pytest_simple_ota.py @@ -87,9 +87,10 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, ser httpd = http.server.HTTPServer((server_ip, server_port), http.server.SimpleHTTPRequestHandler) - httpd.socket = ssl.wrap_socket(httpd.socket, - keyfile=key_file, - certfile=server_file, server_side=True) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + ssl_context.load_cert_chain(certfile=server_file, keyfile=key_file) + + httpd.socket = ssl_context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() From fe628d59513534d19f3d652c48879dda87e75a36 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Wed, 3 Apr 2024 11:45:09 +0530 Subject: [PATCH 038/548] feat(mbedtls): updated mbedtls version from 3.5.2 to 3.6.0 This MR updated MbedTLS version to latest version 3.6.0. --- components/mbedtls/mbedtls | 2 +- components/mbedtls/port/ecc/ecc_alt.c | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/components/mbedtls/mbedtls b/components/mbedtls/mbedtls index 09bba150d0d..72aa687352a 160000 --- a/components/mbedtls/mbedtls +++ b/components/mbedtls/mbedtls @@ -1 +1 @@ -Subproject commit 09bba150d0d822aad2e58d71723f5407da5c21e0 +Subproject commit 72aa687352a469044cbb946f3fdb261430e41ce1 diff --git a/components/mbedtls/port/ecc/ecc_alt.c b/components/mbedtls/port/ecc/ecc_alt.c index ad3c1d63e9c..ef0b76fe05a 100644 --- a/components/mbedtls/port/ecc/ecc_alt.c +++ b/components/mbedtls/port/ecc/ecc_alt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,11 +11,6 @@ #include "mbedtls/ecp.h" #include "mbedtls/platform_util.h" -#define ECP_VALIDATE_RET( cond ) \ - MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) -#define ECP_VALIDATE( cond ) \ - MBEDTLS_INTERNAL_VALIDATE( cond ) - #if defined(MBEDTLS_ECP_MUL_ALT) || defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK) #define MAX_SIZE 32 // 256 bits @@ -94,8 +89,9 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, #endif } - ECP_VALIDATE_RET( grp != NULL ); - ECP_VALIDATE_RET( pt != NULL ); + if (grp == NULL || pt == NULL) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } /* Must use affine coordinates */ if( mbedtls_mpi_cmp_int( &pt->MBEDTLS_PRIVATE(Z), 1 ) != 0 ) From 7aed3eb3bce787162dacc68c0accb5aeb8e92a23 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 7 May 2024 12:01:28 +0800 Subject: [PATCH 039/548] fix(esp_pm): fix esp_pm test cases high fail ratio --- components/esp_pm/test_apps/esp_pm/main/test_pm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/esp_pm/test_apps/esp_pm/main/test_pm.c b/components/esp_pm/test_apps/esp_pm/main/test_pm.c index 8ce1178db80..dfba174a243 100644 --- a/components/esp_pm/test_apps/esp_pm/main/test_pm.c +++ b/components/esp_pm/test_apps/esp_pm/main/test_pm.c @@ -226,8 +226,9 @@ TEST_CASE("Can wake up from automatic light sleep by GPIO", "[pm][ignore]") printf("%lld %lld %u\n", end_rtc - start_rtc, end_hs - start_hs, end_tick - start_tick); TEST_ASSERT_INT32_WITHIN(3, delay_ticks, end_tick - start_tick); - TEST_ASSERT_INT32_WITHIN(2 * portTICK_PERIOD_MS * 1000, delay_ms * 1000, end_hs - start_hs); - TEST_ASSERT_INT32_WITHIN(2 * portTICK_PERIOD_MS * 1000, delay_ms * 1000, end_rtc - start_rtc); + // Error tolerance is 2 tick + duration * 5% + TEST_ASSERT_INT32_WITHIN((2 * portTICK_PERIOD_MS + delay_ms / 20) * 1000, delay_ms * 1000, end_hs - start_hs); + TEST_ASSERT_INT32_WITHIN((2 * portTICK_PERIOD_MS + delay_ms / 20) * 1000, delay_ms * 1000, end_rtc - start_rtc); } REG_CLR_BIT(rtc_io_desc[rtcio_num].reg, rtc_io_desc[rtcio_num].hold_force); rtc_gpio_deinit(ext1_wakeup_gpio); @@ -277,13 +278,15 @@ TEST_CASE("vTaskDelay duration is correct with light sleep enabled", "[pm]") xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void *) &args, 3, NULL, 0); TEST_ASSERT( xSemaphoreTake(done_sem, delay_ms * 10 / portTICK_PERIOD_MS) ); printf("CPU0: %d %d\n", args.delay_us, args.result); - TEST_ASSERT_INT32_WITHIN(1000 * portTICK_PERIOD_MS * 2, args.delay_us, args.result); + // Error tolerance is 2 tick + duration * 5% + TEST_ASSERT_INT32_WITHIN((portTICK_PERIOD_MS * 2 + args.delay_us / 20) * 1000, args.delay_us, args.result); #if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 xTaskCreatePinnedToCore(test_delay_task, "", 2048, (void *) &args, 3, NULL, 1); TEST_ASSERT( xSemaphoreTake(done_sem, delay_ms * 10 / portTICK_PERIOD_MS) ); printf("CPU1: %d %d\n", args.delay_us, args.result); - TEST_ASSERT_INT32_WITHIN(1000 * portTICK_PERIOD_MS * 2, args.delay_us, args.result); + // Error tolerance is 2 tick + duration * 5% + TEST_ASSERT_INT32_WITHIN((portTICK_PERIOD_MS * 2 + args.delay_us / 20) * 1000, args.delay_us, args.result); #endif } vSemaphoreDelete(done_sem); From 840ec6579f270d407c4e37bfa84c96fd04a12c5a Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Tue, 7 May 2024 09:16:54 +0200 Subject: [PATCH 040/548] ci: update mypy check for python 3.12, check under python 3.8 rules --- .pre-commit-config.yaml | 8 ++++---- tools/ci/check_type_comments.py | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3d2ffe3385c..92c9949680b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -103,10 +103,10 @@ repos: name: Check type annotations in python files entry: tools/ci/check_type_comments.py additional_dependencies: - - 'mypy==0.940' - - 'mypy-extensions==0.4.3' - - 'types-setuptools==57.4.14' - - 'types-PyYAML==0.1.9' + - 'mypy' + - 'mypy-extensions' + - 'types-setuptools' + - 'types-PyYAML' - 'types-requests' exclude: > (?x)^( diff --git a/tools/ci/check_type_comments.py b/tools/ci/check_type_comments.py index d89bf562b24..38865b08426 100755 --- a/tools/ci/check_type_comments.py +++ b/tools/ci/check_type_comments.py @@ -2,7 +2,6 @@ # # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - import argparse import subprocess from sys import exit @@ -30,7 +29,7 @@ def types_valid_ignored_rules(file_name): # type: (str) -> bool """ Run Mypy check with rules for ignore list on the given file, return TRUE if Mypy check passes """ - mypy_exit_code = subprocess.call('mypy {} --allow-untyped-defs'.format(file_name), shell=True) + mypy_exit_code = subprocess.call('mypy {} --python-version 3.8 --allow-untyped-defs'.format(file_name), shell=True) return not bool(mypy_exit_code) From b8ed93eec087bca5effafe2b2427c4128263df1e Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Tue, 7 May 2024 09:19:00 +0200 Subject: [PATCH 041/548] ci: apply new fix in pytest-embedded 1.10 --- conftest.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/conftest.py b/conftest.py index 79e5ad464a2..5270eb2dba2 100644 --- a/conftest.py +++ b/conftest.py @@ -25,7 +25,6 @@ import typing as t import zipfile from copy import deepcopy -from datetime import datetime from urllib.parse import quote import common_test_methods # noqa: F401 @@ -56,15 +55,10 @@ def idf_path() -> str: return os.path.dirname(__file__) -@pytest.fixture(scope='session', autouse=True) -def session_tempdir() -> str: - _tmpdir = os.path.join( - os.path.dirname(__file__), - 'pytest_embedded_log', - datetime.now().strftime('%Y-%m-%d_%H-%M-%S'), - ) - os.makedirs(_tmpdir, exist_ok=True) - return _tmpdir +@pytest.fixture(scope='session') +def session_root_logdir(idf_path: str) -> str: + """Session scoped log dir for pytest-embedded""" + return idf_path @pytest.fixture From a22d0df155952749da57f1e98e32454c56873a67 Mon Sep 17 00:00:00 2001 From: xuxiao Date: Tue, 23 Apr 2024 19:08:22 +0800 Subject: [PATCH 042/548] fix(wifi): fix esp32c6 wdt issues when recv/send tcp packages --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 516ae8c5868..1a7db846115 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 516ae8c586881cc71c9f5a464e4f40cb3014b58f +Subproject commit 1a7db846115dcb237dd3c81f93b0d7007fce509b From 8545eeb4ef25dab588270c332adda60f9014efbd Mon Sep 17 00:00:00 2001 From: alanmaxwell Date: Tue, 23 Apr 2024 20:59:42 +0800 Subject: [PATCH 043/548] fix(wifi): clear wifi buffer to fix ampdu compatibility issue --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 1a7db846115..d8e20e3cf35 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 1a7db846115dcb237dd3c81f93b0d7007fce509b +Subproject commit d8e20e3cf3585469bc327857092d3f5a56263675 From 209fbfc18bc4590c5829ff154630c166558eedf8 Mon Sep 17 00:00:00 2001 From: xuxiao Date: Sun, 28 Apr 2024 15:56:01 +0800 Subject: [PATCH 044/548] fix(wifi): fix trc_ampdu_stop_rateidx value errors when DUT under softap + sta mode --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index d8e20e3cf35..e09543aef59 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit d8e20e3cf3585469bc327857092d3f5a56263675 +Subproject commit e09543aef5949a156b264a88e94fdd7625f61ef9 From 7c54373146e29f3393a67b9eeb52cb02c460a9c4 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 23 Apr 2024 18:20:39 +0530 Subject: [PATCH 045/548] feat(esp_wifi): Update FTM PHY Compensation with calibration --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index e09543aef59..1221569e8f5 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit e09543aef5949a156b264a88e94fdd7625f61ef9 +Subproject commit 1221569e8f507febe888764237aafcc4c015473e From ea1a10da176d1d1b375dcfeb030fe400208ba2f9 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Mon, 6 May 2024 11:43:27 +0530 Subject: [PATCH 046/548] fix(wifi): Fix issue in scan when AP advertises WPA and WPA2 with SAE AKM --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 1221569e8f5..1c42c89e1a8 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 1221569e8f507febe888764237aafcc4c015473e +Subproject commit 1c42c89e1a81d94f047dc19685ba0db1925df704 From 90188040fb514ed2cdf702ab21cc940fb3a1046c Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 8 May 2024 10:40:16 +0800 Subject: [PATCH 047/548] fix(esp_wifi): clear soc wakeup request signal at tbtt process --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 1c42c89e1a8..a9c6727926f 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 1c42c89e1a81d94f047dc19685ba0db1925df704 +Subproject commit a9c6727926f9d0e13804e2340d93a57d4dfa0b0a From d22f9a97aab0bad2cc98749cb97f1673eefe3d6c Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 26 Apr 2024 16:04:18 +0800 Subject: [PATCH 048/548] change(camera): change esp_cam_del_ctlr to esp_cam_ctlr_del --- components/esp_driver_cam/esp_cam_ctlr.c | 2 +- components/esp_driver_cam/include/esp_cam_ctlr.h | 2 +- .../esp_driver_cam/test_apps/csi/main/test_csi_driver.c | 4 ++-- docs/en/api-reference/peripherals/camera_driver.rst | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esp_driver_cam/esp_cam_ctlr.c b/components/esp_driver_cam/esp_cam_ctlr.c index 51a1b3c3088..a2a4e2e9d0d 100644 --- a/components/esp_driver_cam/esp_cam_ctlr.c +++ b/components/esp_driver_cam/esp_cam_ctlr.c @@ -84,7 +84,7 @@ esp_err_t esp_cam_ctlr_get_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t return handle->get_buffer_len(handle, ret_fb_len); } -esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle) +esp_err_t esp_cam_ctlr_del(esp_cam_ctlr_handle_t handle) { ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(handle->del, ESP_ERR_NOT_SUPPORTED, TAG, "controller driver function not supported"); diff --git a/components/esp_driver_cam/include/esp_cam_ctlr.h b/components/esp_driver_cam/include/esp_cam_ctlr.h index 3c7cbe2ae17..6365ad6b738 100644 --- a/components/esp_driver_cam/include/esp_cam_ctlr.h +++ b/components/esp_driver_cam/include/esp_cam_ctlr.h @@ -87,7 +87,7 @@ esp_err_t esp_cam_ctlr_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_ * - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_INVALID_STATE: Invalid state */ -esp_err_t esp_cam_del_ctlr(esp_cam_ctlr_handle_t handle); +esp_err_t esp_cam_ctlr_del(esp_cam_ctlr_handle_t handle); /** * @brief Register ESP CAM controller event callbacks diff --git a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c index e7b42583ce3..f9890e9c21b 100644 --- a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c +++ b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c @@ -32,7 +32,7 @@ TEST_CASE("TEST CSI driver allocation", "[csi]") TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); TEST_ASSERT_NOT_NULL(bk_buffer); TEST_ASSERT_EQUAL((csi_config.h_res * csi_config.v_res * 2), bk_buffer_len); // out type RGB565 using 2 byte / pixel - TEST_ESP_OK(esp_cam_del_ctlr(handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); } TEST_CASE("TEST CSI driver no backup buffer usage", "[csi]") @@ -59,5 +59,5 @@ TEST_CASE("TEST CSI driver no backup buffer usage", "[csi]") TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); TEST_ASSERT_NULL(bk_buffer); TEST_ASSERT_EQUAL(0, bk_buffer_len); - TEST_ESP_OK(esp_cam_del_ctlr(handle)); + TEST_ESP_OK(esp_cam_ctlr_del(handle)); } diff --git a/docs/en/api-reference/peripherals/camera_driver.rst b/docs/en/api-reference/peripherals/camera_driver.rst index 6707535827b..18bb537b8b4 100644 --- a/docs/en/api-reference/peripherals/camera_driver.rst +++ b/docs/en/api-reference/peripherals/camera_driver.rst @@ -60,7 +60,7 @@ Resource Allocation Uninstall Camera Controller Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If a previously installed Camera Controller Driver is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`esp_cam_del_ctlr`, so that to release the underlying hardware. +If a previously installed Camera Controller Driver is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`esp_cam_ctlr_del`, so that to release the underlying hardware. .. _cam-enable-disable: @@ -127,7 +127,7 @@ After the Camera Controller Driver starts receiving, it can generate a specific Thread Safety ^^^^^^^^^^^^^ -The factory function :cpp:func:`esp_cam_new_csi_ctlr` and :cpp:func:`esp_cam_del_ctlr` are guaranteed to be thread safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks. +The factory function :cpp:func:`esp_cam_new_csi_ctlr` and :cpp:func:`esp_cam_ctlr_del` are guaranteed to be thread safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks. .. _cam-kconfig-options: From b9f15ba3ab7360fabab46e4eafc53779775f2cea Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 30 Apr 2024 18:52:25 +0800 Subject: [PATCH 049/548] feat(mipi_dsi): round to boundary when draw pixel --- components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 9 +++++++++ components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 12 ++++++------ components/esp_lcd/src/esp_lcd_panel_nt35510.c | 1 - components/esp_lcd/src/esp_lcd_panel_ops.c | 1 + components/esp_lcd/src/esp_lcd_panel_ssd1306.c | 1 - components/esp_lcd/src/esp_lcd_panel_st7789.c | 1 - 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 71375bbf787..4db6af27690 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" @@ -417,6 +418,14 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int size_t frame_buffer_size = dpi_panel->frame_buffer_size; size_t bytes_per_pixel = dpi_panel->bytes_per_pixel; + // clip to boundaries + int h_res = dpi_panel->h_pixels; + int v_res = dpi_panel->v_pixels; + x_start = MAX(x_start, 0); + x_end = MIN(x_end, h_res); + y_start = MAX(y_start, 0); + y_end = MIN(y_end, v_res); + bool do_copy = false; uint8_t draw_buf_fb_index = 0; // check if the user draw buffer resides in any frame buffer's memory range diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 16d189e0a4c..03161e1a96b 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -706,7 +706,6 @@ static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int { esp_rgb_panel_t *rgb_panel = __containerof(panel, esp_rgb_panel_t, base); ESP_RETURN_ON_FALSE(rgb_panel->num_fbs > 0, ESP_ERR_NOT_SUPPORTED, TAG, "no frame buffer installed"); - assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position"); // check if we need to copy the draw buffer (pointed by the color_data) to the driver's frame buffer bool do_copy = false; @@ -726,18 +725,19 @@ static esp_err_t rgb_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start += rgb_panel->y_gap; x_end += rgb_panel->x_gap; y_end += rgb_panel->y_gap; - // round the boundary + + // clip to boundaries int h_res = rgb_panel->timings.h_res; int v_res = rgb_panel->timings.v_res; if (rgb_panel->rotate_mask & ROTATE_MASK_SWAP_XY) { - x_start = MIN(x_start, v_res); + x_start = MAX(x_start, 0); x_end = MIN(x_end, v_res); - y_start = MIN(y_start, h_res); + y_start = MAX(y_start, 0); y_end = MIN(y_end, h_res); } else { - x_start = MIN(x_start, h_res); + x_start = MAX(x_start, 0); x_end = MIN(x_end, h_res); - y_start = MIN(y_start, v_res); + y_start = MAX(y_start, 0); y_end = MIN(y_end, v_res); } diff --git a/components/esp_lcd/src/esp_lcd_panel_nt35510.c b/components/esp_lcd/src/esp_lcd_panel_nt35510.c index aa2a472b232..5a9e3427389 100644 --- a/components/esp_lcd/src/esp_lcd_panel_nt35510.c +++ b/components/esp_lcd/src/esp_lcd_panel_nt35510.c @@ -188,7 +188,6 @@ static esp_err_t panel_nt35510_draw_bitmap(esp_lcd_panel_t *panel, int x_start, const void *color_data) { nt35510_panel_t *nt35510 = __containerof(panel, nt35510_panel_t, base); - assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position"); esp_lcd_panel_io_handle_t io = nt35510->io; x_start += nt35510->x_gap; diff --git a/components/esp_lcd/src/esp_lcd_panel_ops.c b/components/esp_lcd/src/esp_lcd_panel_ops.c index ef19e3d328a..d4e6bd9aded 100644 --- a/components/esp_lcd/src/esp_lcd_panel_ops.c +++ b/components/esp_lcd/src/esp_lcd_panel_ops.c @@ -32,6 +32,7 @@ esp_err_t esp_lcd_panel_del(esp_lcd_panel_handle_t panel) esp_err_t esp_lcd_panel_draw_bitmap(esp_lcd_panel_handle_t panel, int x_start, int y_start, int x_end, int y_end, const void *color_data) { ESP_RETURN_ON_FALSE(panel, ESP_ERR_INVALID_ARG, TAG, "invalid panel handle"); + ESP_RETURN_ON_FALSE((x_start < x_end) && (y_start < y_end), ESP_ERR_INVALID_ARG, TAG, "start position must be smaller than end position"); ESP_RETURN_ON_FALSE(panel->draw_bitmap, ESP_ERR_NOT_SUPPORTED, TAG, "draw_bitmap is not supported by this panel"); return panel->draw_bitmap(panel, x_start, y_start, x_end, y_end, color_data); } diff --git a/components/esp_lcd/src/esp_lcd_panel_ssd1306.c b/components/esp_lcd/src/esp_lcd_panel_ssd1306.c index 4ccb6710a50..fbac5c0884b 100644 --- a/components/esp_lcd/src/esp_lcd_panel_ssd1306.c +++ b/components/esp_lcd/src/esp_lcd_panel_ssd1306.c @@ -168,7 +168,6 @@ static esp_err_t panel_ssd1306_init(esp_lcd_panel_t *panel) static esp_err_t panel_ssd1306_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data) { ssd1306_panel_t *ssd1306 = __containerof(panel, ssd1306_panel_t, base); - assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position"); esp_lcd_panel_io_handle_t io = ssd1306->io; // adding extra gap diff --git a/components/esp_lcd/src/esp_lcd_panel_st7789.c b/components/esp_lcd/src/esp_lcd_panel_st7789.c index e6cd329d13b..8076fce67ab 100644 --- a/components/esp_lcd/src/esp_lcd_panel_st7789.c +++ b/components/esp_lcd/src/esp_lcd_panel_st7789.c @@ -198,7 +198,6 @@ static esp_err_t panel_st7789_draw_bitmap(esp_lcd_panel_t *panel, int x_start, i const void *color_data) { st7789_panel_t *st7789 = __containerof(panel, st7789_panel_t, base); - assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position"); esp_lcd_panel_io_handle_t io = st7789->io; x_start += st7789->x_gap; From ebc9d021468d8a5fbd9dceb6c398319376b983c5 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 8 May 2024 11:21:10 +0200 Subject: [PATCH 050/548] fix: make idf_size.py compatible with python3.8 Previous 6caa4a17ace9 ("fix: display correct help in the idf_size.py wrapper") introduced a regression, because it uses exit_on_error parameter for argparse.ArgumentParser, which was added in python3.9, making idf_size.py incompatible with idf.py minimal required python3.8. The objective is to inspect the arguments of idf_size.py using a wrapper argparse to determine whether the legacy or refactored version should be initiated, while always displaying help for the underlying version. The exit_on_error function was previously utilized to prevent argparse from exiting and displaying help/usage. This replaces exit_on_error with a workaround that makes the --format argument optional. Since this is the sole instance where the wrapper argparse might fail, it achieves the same outcome as using exit_on_error. Fixes: 6caa4a17ace9 ("fix: display correct help in the idf_size.py wrapper") Signed-off-by: Frantisek Hrbata --- tools/idf_size.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/idf_size.py b/tools/idf_size.py index 80c968239a4..a3cb75c7dab 100755 --- a/tools/idf_size.py +++ b/tools/idf_size.py @@ -13,8 +13,13 @@ # Here the argparse is used only to "peek" into arguments if # legacy version is requested or if old json format is specified. # In these two cases the esp_idf_size legacy version is spawned. - parser = argparse.ArgumentParser(exit_on_error=False, add_help=False) - parser.add_argument('--format') + parser = argparse.ArgumentParser(add_help=False) + # Make the --format arg optional, so this argparse instance does not + # fail with an error and the proper underlying help is displayed. + # Note that exit_on_error is supported from python3.9, so this is + # a workaround how to make sure that the args parsing doesn't fail here if idf_size.py + # is invoked e.g. without specifying the format, like "idf_size.py --format". + parser.add_argument('--format', nargs='?') parser.add_argument('-l', '--legacy', action='store_true', default=os.environ.get('ESP_IDF_SIZE_LEGACY', '0') == '1') # The sys.argv is parsed with "exit_on_error", but the argparse.ArgumentError @@ -34,7 +39,9 @@ os.environ['ESP_IDF_SIZE_NG'] = '1' if not rest or '-h' in rest or '--help' in rest: print(('Note: legacy esp_idf_size version can be invoked by specifying the -l/--legacy ' - 'option or by setting the ESP_IDF_SIZE_LEGACY environment variable.')) + 'option or by setting the ESP_IDF_SIZE_LEGACY environment variable. Additionally, the ' + 'legacy version is automatically employed when the JSON format is specified for ' + 'compatibility with previous versions.')) if args.format is not None: rest = ['--format', args.format] + rest From fe4b401ab271933d63d5bc8ab1f52ff438f21baf Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 8 May 2024 13:38:19 +0200 Subject: [PATCH 051/548] ci: add simple test for idf_size.py python compatibility This adds a simple test that tries to run idf_size.py help and check if the process does not exit with error. This is just to make sure that idf_size.py can be used with minimum required python version. Signed-off-by: Frantisek Hrbata --- .gitlab/ci/host-test.yml | 2 ++ .gitlab/ci/rules.yml | 1 + tools/test_idf_size/pytest.ini | 12 ++++++++++++ tools/test_idf_size/test_idf_size.py | 17 +++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 tools/test_idf_size/pytest.ini create mode 100644 tools/test_idf_size/test_idf_size.py diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index f4b3966d94a..f054b8236ff 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -228,6 +228,8 @@ test_tools: - pytest --noconftest test_idf_qemu.py --junitxml=${IDF_PATH}/XUNIT_IDF_PY_QEMU.xml || stat=1 - cd ${IDF_PATH}/tools/test_mkdfu - pytest --noconftest test_mkdfu.py --junitxml=${IDF_PATH}/XUNIT_MKDFU.xml || stat=1 + - cd ${IDF_PATH}/tools/test_idf_size + - pytest --noconftest test_idf_size.py --junitxml=${IDF_PATH}/XUNIT_IDF_SIZE.xml || stat=1 - cd ${IDF_PATH} - shellcheck -s sh tools/detect_python.sh || stat=1 - shellcheck -s bash tools/detect_python.sh || stat=1 diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index a49c5795a90..b492bdc60c8 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -86,6 +86,7 @@ - "tools/test_idf_py/**/*" - "tools/idf_size.py" + - "tools/test_idf_size/**/*" - "tools/tools.json" - "tools/tools_schema.json" diff --git a/tools/test_idf_size/pytest.ini b/tools/test_idf_size/pytest.ini new file mode 100644 index 00000000000..d95e773e5cd --- /dev/null +++ b/tools/test_idf_size/pytest.ini @@ -0,0 +1,12 @@ +[pytest] +addopts = -s -p no:pytest_embedded + +# log related +log_cli = True +log_cli_level = INFO +log_cli_format = %(asctime)s %(levelname)s %(message)s +log_cli_date_format = %Y-%m-%d %H:%M:%S + +## log all to `system-out` when case fail +junit_logging = stdout +junit_log_passing_tests = False diff --git a/tools/test_idf_size/test_idf_size.py b/tools/test_idf_size/test_idf_size.py new file mode 100644 index 00000000000..2a3baabbe0a --- /dev/null +++ b/tools/test_idf_size/test_idf_size.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import logging +import os +import sys +from pathlib import Path +from subprocess import DEVNULL +from subprocess import run + + +def test_idf_size() -> None: + # Simple test to make sure that the idf_size.py wrapper is compatible + # with idf.py minimum required python version. + logging.info('idf_size.py python compatibility check') + idf_size_path = Path(os.environ['IDF_PATH']) / 'tools' / 'idf_size.py' + run([sys.executable, idf_size_path, '--help'], stdout=DEVNULL, stderr=DEVNULL, check=True) From 9eb61ef5a775c61b38e82da1e8d2944bfdf956be Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 22 Apr 2024 16:49:13 +0800 Subject: [PATCH 052/548] docs: Update the process of Bluetooth entering sleep in the sleep_modes.rst --- docs/en/api-reference/system/sleep_modes.rst | 2 +- docs/zh_CN/api-reference/system/sleep_modes.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/api-reference/system/sleep_modes.rst b/docs/en/api-reference/system/sleep_modes.rst index e3a4bc2b793..2fb87648fbd 100644 --- a/docs/en/api-reference/system/sleep_modes.rst +++ b/docs/en/api-reference/system/sleep_modes.rst @@ -37,7 +37,7 @@ In Deep-sleep mode, the CPUs, most of the RAM, and all digital peripherals that Wi-Fi/Bluetooth and Sleep Modes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, the application must disable Wi-Fi and Bluetooth using the appropriate calls (i.e., :cpp:func:`esp_bluedroid_disable`, :cpp:func:`esp_bt_controller_disable`, :cpp:func:`esp_wifi_stop`). Wi-Fi and Bluetooth connections are not maintained in Deep-sleep or Light-sleep mode, even if these functions are not called. + In Deep-sleep and Light-sleep modes, the wireless peripherals are powered down. Before entering Deep-sleep or Light-sleep modes, the application must disable Wi-Fi and Bluetooth using the appropriate calls (i.e., :cpp:func:`nimble_port_stop`, :cpp:func:`nimble_port_deinit`, :cpp:func:`esp_bluedroid_disable`, :cpp:func:`esp_bluedroid_deinit`, :cpp:func:`esp_bt_controller_disable`, :cpp:func:`esp_bt_controller_deinit`, :cpp:func:`esp_wifi_stop`). Wi-Fi and Bluetooth connections are not maintained in Deep-sleep or Light-sleep mode, even if these functions are not called. If Wi-Fi/Bluetooth connections need to be maintained, enable Wi-Fi/Bluetooth Modem-sleep mode and automatic Light-sleep feature (see :doc:`Power Management APIs `). This allows the system to wake up from sleep automatically when required by the Wi-Fi/Bluetooth driver, thereby maintaining the connection. diff --git a/docs/zh_CN/api-reference/system/sleep_modes.rst b/docs/zh_CN/api-reference/system/sleep_modes.rst index ae61e1b1860..10a67020d52 100644 --- a/docs/zh_CN/api-reference/system/sleep_modes.rst +++ b/docs/zh_CN/api-reference/system/sleep_modes.rst @@ -37,7 +37,7 @@ 睡眠模式下的 Wi-Fi 和 Bluetooth 功能 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - 在 Light-sleep 和 Deep-sleep 模式下,无线外设会被断电。因此,在进入这两种睡眠模式前,应用程序必须调用恰当的函数(:cpp:func:`esp_bluedroid_disable`、:cpp:func:`esp_bt_controller_disable` 或 :cpp:func:`esp_wifi_stop`)来禁用 Wi-Fi 和 Bluetooth。在 Light-sleep 或 Deep-sleep 模式下,即使不调用这些函数也无法连接 Wi-Fi 和 Bluetooth。 + 在 Light-sleep 和 Deep-sleep 模式下,无线外设会被断电。因此,在进入这两种睡眠模式前,应用程序必须调用恰当的函数(:cpp:func:`nimble_port_stop`、:cpp:func:`nimble_port_deinit`、:cpp:func:`esp_bluedroid_disable`、:cpp:func:`esp_bluedroid_deinit`、:cpp:func:`esp_bt_controller_disable`、:cpp:func:`esp_bt_controller_deinit` 或 :cpp:func:`esp_wifi_stop`)来禁用 Wi-Fi 和 Bluetooth。在 Light-sleep 或 Deep-sleep 模式下,即使不调用这些函数也无法连接 Wi-Fi 和 Bluetooth。 如需保持 Wi-Fi 和 Bluetooth 连接,请启用 Wi-Fi 和 Bluetooth Modem-sleep 模式和自动 Light-sleep 模式(请参阅 :doc:`电源管理 API `)。在这两种模式下,Wi-Fi 和 Bluetooth 驱动程序发出请求时,系统将自动从睡眠中被唤醒,从而保持连接。 From 4eacfd6ee1718d36e0c894696eaeb9498052f7d6 Mon Sep 17 00:00:00 2001 From: liuning Date: Tue, 30 Apr 2024 11:40:32 +0800 Subject: [PATCH 053/548] update c3 s3 c6 libphy fix coex reset and bug --- components/esp_phy/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_phy/lib b/components/esp_phy/lib index c28825eb1be..792ba5917ee 160000 --- a/components/esp_phy/lib +++ b/components/esp_phy/lib @@ -1 +1 @@ -Subproject commit c28825eb1be6bbe30e0ee8cfcd54614bf86273e7 +Subproject commit 792ba5917ee8191e7264143e69f9e6f8c1c0eacc From a9dcc3964d16c289b448bad0978f9fd54530ea36 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Wed, 8 May 2024 17:11:34 +0530 Subject: [PATCH 054/548] fix(wifi): Fix issue of wrong Rx control information of espnow packets Only for esp32 and esp32s2 --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index a9c6727926f..97373dacc24 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit a9c6727926f9d0e13804e2340d93a57d4dfa0b0a +Subproject commit 97373dacc24433574f1b13ab6f7f564d50a7c78a From 89a612aea04be07391d13ab4591ab8d03e2ecba3 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 8 May 2024 09:57:22 +0530 Subject: [PATCH 055/548] fix(nimble): Free controller memory if init fails --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 5adfd2d3c44..fdc35261939 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 5adfd2d3c446a25577970c9f767ab034aa517423 +Subproject commit fdc352619392a6f67622d7d07403de4794051362 From 4e850f158ec8ce5e26e18ed033eeaf3612fa99c4 Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Thu, 9 May 2024 10:32:52 +0200 Subject: [PATCH 056/548] ci: move log dir from pytest_embedded_log to pytest-embedded --- .gitignore | 2 ++ .gitlab/ci/host-test.yml | 4 ++-- conftest.py | 8 +++++--- pytest.ini | 2 +- tools/ci/dynamic_pipelines/templates/.dynamic_jobs.yml | 2 +- tools/ci/idf_ci_utils.py | 2 +- tools/ci/idf_pytest/constants.py | 9 +++++---- tools/ci/idf_pytest/tests/conftest.py | 5 +++-- 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index b8a8909c377..f70980b703f 100644 --- a/.gitignore +++ b/.gitignore @@ -96,6 +96,8 @@ dependencies.lock managed_components # pytest log +pytest-embedded/ +# legacy one pytest_embedded_log/ list_job*.txt size_info*.txt diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index f4b3966d94a..5658b97ac61 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -296,7 +296,7 @@ test_pytest_qemu: artifacts: paths: - XUNIT_RESULT.xml - - pytest_embedded_log/ + - pytest-embedded/ reports: junit: XUNIT_RESULT.xml allow_failure: true # IDFCI-1752 @@ -330,7 +330,7 @@ test_pytest_linux: artifacts: paths: - XUNIT_RESULT.xml - - pytest_embedded_log/ + - pytest-embedded/ - "**/build*/build_log.txt" reports: junit: XUNIT_RESULT.xml diff --git a/conftest.py b/conftest.py index 5270eb2dba2..1fac842312a 100644 --- a/conftest.py +++ b/conftest.py @@ -39,7 +39,8 @@ from idf_ci.app import import_apps_from_txt from idf_ci.uploader import AppDownloader, AppUploader from idf_ci_utils import IDF_PATH, idf_relpath -from idf_pytest.constants import DEFAULT_SDKCONFIG, ENV_MARKERS, SPECIAL_MARKERS, TARGET_MARKERS, PytestCase +from idf_pytest.constants import DEFAULT_SDKCONFIG, ENV_MARKERS, SPECIAL_MARKERS, TARGET_MARKERS, PytestCase, \ + DEFAULT_LOGDIR from idf_pytest.plugin import IDF_PYTEST_EMBEDDED_KEY, ITEM_PYTEST_CASE_KEY, IdfPytestEmbedded from idf_pytest.utils import format_case_id from pytest_embedded.plugin import multi_dut_argument, multi_dut_fixture @@ -460,11 +461,12 @@ def pytest_runtest_makereport(item, call): # type: ignore job_id = os.getenv('CI_JOB_ID', 0) url = os.getenv('CI_PAGES_URL', '').replace('esp-idf', '-/esp-idf') - template = f'{url}/-/jobs/{job_id}/artifacts/pytest_embedded_log/{{}}' + template = f'{url}/-/jobs/{job_id}/artifacts/{DEFAULT_LOGDIR}/{{}}' logs_files = [] def get_path(x: str) -> str: - return x.split('pytest_embedded_log/', 1)[1] + return x.split(f'{DEFAULT_LOGDIR}/', 1)[1] + if isinstance(_dut, list): logs_files.extend([template.format(get_path(d.logfile)) for d in _dut]) dut_artifacts_url.append('{}:'.format(_dut[0].test_case_name)) diff --git a/pytest.ini b/pytest.ini index 82e028d894d..069d1cf4158 100644 --- a/pytest.ini +++ b/pytest.ini @@ -13,7 +13,7 @@ addopts = --logfile-extension ".txt" --check-duplicates y --ignore-glob */managed_components/* - --ignore pytest_embedded_log + --ignore pytest-embedded # ignore DeprecationWarning filterwarnings = diff --git a/tools/ci/dynamic_pipelines/templates/.dynamic_jobs.yml b/tools/ci/dynamic_pipelines/templates/.dynamic_jobs.yml index 72f0b76c209..43166486723 100644 --- a/tools/ci/dynamic_pipelines/templates/.dynamic_jobs.yml +++ b/tools/ci/dynamic_pipelines/templates/.dynamic_jobs.yml @@ -60,7 +60,7 @@ artifacts: paths: - XUNIT_RESULT*.xml - - pytest_embedded_log/ + - pytest-embedded/ # Child pipeline reports won't be collected in the main one # https://gitlab.com/groups/gitlab-org/-/epics/8205 # reports: diff --git a/tools/ci/idf_ci_utils.py b/tools/ci/idf_ci_utils.py index c865690a193..b355090ffc7 100644 --- a/tools/ci/idf_ci_utils.py +++ b/tools/ci/idf_ci_utils.py @@ -11,7 +11,7 @@ from functools import cached_property from pathlib import Path -IDF_PATH = os.path.abspath(os.getenv('IDF_PATH', os.path.join(os.path.dirname(__file__), '..', '..'))) +IDF_PATH: str = os.path.abspath(os.getenv('IDF_PATH', os.path.join(os.path.dirname(__file__), '..', '..'))) def get_submodule_dirs(full_path: bool = False) -> t.List[str]: diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index 4ff0687e54b..89f3bbe1c1e 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -19,6 +19,7 @@ SUPPORTED_TARGETS = ['esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4'] PREVIEW_TARGETS: t.List[str] = [] # this PREVIEW_TARGETS excludes 'linux' target DEFAULT_SDKCONFIG = 'default' +DEFAULT_LOGDIR = 'pytest-embedded' TARGET_MARKERS = { 'esp32': 'support esp32 target', @@ -200,7 +201,7 @@ def targets(self) -> t.List[str]: for _t in [app.target for app in self.apps]: if _t in self.target_markers: skip = False - warnings.warn(f'`pytest.mark.[TARGET]` defined in parametrize for multi-dut test cases is deprecated. ' + warnings.warn(f'`pytest.mark.[TARGET]` defined in parametrize for multi-dut test cases is deprecated. ' # noqa: W604 f'Please use parametrize instead for test case {self.item.nodeid}') break @@ -233,7 +234,7 @@ def _get_temp_markers_disabled_targets(marker_name: str) -> t.Set[str]: # temp markers should always use keyword arguments `targets` and `reason` if not temp_marker.kwargs.get('targets') or not temp_marker.kwargs.get('reason'): raise ValueError( - f'`{marker_name}` should always use keyword arguments `targets` and `reason`. ' + f'`{marker_name}` should always use keyword arguments `targets` and `reason`. ' # noqa: W604 f'For example: ' f'`@pytest.mark.{marker_name}(targets=["esp32"], reason="IDF-xxxx, will fix it ASAP")`' ) @@ -292,7 +293,7 @@ def all_built_in_app_lists(self, app_lists: t.Optional[t.List[str]] = None) -> t bin_found[i] = 1 if sum(bin_found) == 0: - msg = f'Skip test case {self.name} because all following binaries are not listed in the app lists: ' + msg = f'Skip test case {self.name} because all following binaries are not listed in the app lists: ' # noqa: E713 for app in self.apps: msg += f'\n - {app.build_dir}' @@ -303,7 +304,7 @@ def all_built_in_app_lists(self, app_lists: t.Optional[t.List[str]] = None) -> t return None # some found, some not, looks suspicious - msg = f'Found some binaries of test case {self.name} are not listed in the app lists.' + msg = f'Found some binaries of test case {self.name} are not listed in the app lists.' # noqa: E713 for i, app in enumerate(self.apps): if bin_found[i] == 0: msg += f'\n - {app.build_dir}' diff --git a/tools/ci/idf_pytest/tests/conftest.py b/tools/ci/idf_pytest/tests/conftest.py index bd85b7f4dfc..e0def5265b6 100644 --- a/tools/ci/idf_pytest/tests/conftest.py +++ b/tools/ci/idf_pytest/tests/conftest.py @@ -19,6 +19,7 @@ sys.path.append(tools_dir) from idf_ci_utils import IDF_PATH # noqa: E402 +from idf_pytest.constants import DEFAULT_LOGDIR # noqa: E402 def create_project(name: str, folder: Path) -> Path: @@ -57,9 +58,9 @@ def create_project(name: str, folder: Path) -> Path: @pytest.fixture def work_dirpath() -> t.Generator[Path, None, None]: - os.makedirs(os.path.join(IDF_PATH, 'pytest_embedded_log'), exist_ok=True) + os.makedirs(os.path.join(IDF_PATH, DEFAULT_LOGDIR), exist_ok=True) - p = Path(tempfile.mkdtemp(prefix=os.path.join(IDF_PATH, 'pytest_embedded_log') + os.sep)) + p = Path(tempfile.mkdtemp(prefix=os.path.join(IDF_PATH, DEFAULT_LOGDIR) + os.sep)) try: yield p From dd20d1f2b51a2c1d519b9c723c1b5e9e6b06ab2a Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 11 Apr 2024 11:12:26 +0800 Subject: [PATCH 057/548] refactor(isp): refactor the interrupt and callback solution - Added async API - Replaced the polling API - Supported one more callback and event data --- components/esp_driver_isp/CMakeLists.txt | 2 +- .../esp_driver_isp/include/driver/isp.h | 82 +------- .../esp_driver_isp/include/driver/isp_af.h | 64 ++++-- .../esp_driver_isp/include/driver/isp_core.h | 86 ++++++++ components/esp_driver_isp/src/isp_af.c | 186 +++++++++++++----- .../esp_driver_isp/src/{isp.c => isp_core.c} | 114 +---------- components/esp_driver_isp/src/isp_internal.h | 48 ++--- components/hal/esp32p4/include/hal/isp_ll.h | 14 ++ components/hal/include/hal/isp_hal.h | 10 +- components/hal/include/hal/isp_types.h | 14 +- components/hal/isp_hal.c | 18 +- docs/en/api-reference/peripherals/isp.rst | 40 +++- 12 files changed, 358 insertions(+), 320 deletions(-) create mode 100644 components/esp_driver_isp/include/driver/isp_core.h rename components/esp_driver_isp/src/{isp.c => isp_core.c} (69%) diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index b75c9bfc4a8..a5316bd90eb 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -3,7 +3,7 @@ set(srcs) set(public_include "include") if(CONFIG_SOC_ISP_SUPPORTED) - list(APPEND srcs "src/isp.c" + list(APPEND srcs "src/isp_core.c" "src/isp_af.c") endif() diff --git a/components/esp_driver_isp/include/driver/isp.h b/components/esp_driver_isp/include/driver/isp.h index 436ba24dbe2..5909bf0fac8 100644 --- a/components/esp_driver_isp/include/driver/isp.h +++ b/components/esp_driver_isp/include/driver/isp.h @@ -4,84 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#pragma once - -#include -#include -#include "esp_err.h" -#include "driver/isp_types.h" -#include "driver/isp_af.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief ISP configurations - */ -typedef struct { - isp_clk_src_t clk_src; ///< Clock source - uint32_t clk_hz; ///< Clock frequency in Hz, suggest twice higher than cam sensor speed - isp_input_data_source_t input_data_source; ///< Input data source - isp_color_t input_data_color_type; ///< Input color type - isp_color_t output_data_color_type; ///< Output color type - bool has_line_start_packet; ///< Enable line start packet - bool has_line_end_packet; ///< Enable line end packet - uint32_t h_res; ///< Input horizontal resolution, i.e. the number of pixels in a line - uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame -} esp_isp_processor_cfg_t; - -/** - * @brief New an ISP processor - * - * @param[in] proc_config Pointer to ISP config. Refer to ``esp_isp_processor_cfg_t``. - * @param[out] ret_proc Processor handle - * - * @return - * - ESP_OK On success - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. - * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags - * - ESP_ERR_NOT_SUPPORTED Not supported mode - * - ESP_ERR_NO_MEM If out of memory - */ -esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_proc_handle_t *ret_proc); - /** - * @brief Delete an ISP processor - * - * @param[in] proc Processor handle - * - * @return - * - ESP_OK On success - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. - * - ESP_ERR_INVALID_STATE Driver state is invalid. - */ -esp_err_t esp_isp_del_processor(isp_proc_handle_t proc); - -/** - * @brief Enable an ISP processor - * - * @param[in] proc Processor handle - * - * @return - * - ESP_OK On success - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. - * - ESP_ERR_INVALID_STATE Driver state is invalid. + * @brief ISP peripheral contains many submodules, whose drivers are scattered in different header files. + * This header file serves as a prelude, contains every thing that is needed to work with the ISP peripheral. */ -esp_err_t esp_isp_enable(isp_proc_handle_t proc); -/** - * @brief Disable an ISP processor - * - * @param[in] proc Processor handle - * - * @return - * - ESP_OK On success - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. - * - ESP_ERR_INVALID_STATE Driver state is invalid. - */ -esp_err_t esp_isp_disable(isp_proc_handle_t proc); +#pragma once -#ifdef __cplusplus -} -#endif +#include "driver/isp_core.h" +#include "driver/isp_af.h" diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 9e448b133f4..23348117d5d 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -10,8 +10,6 @@ #include #include "esp_err.h" #include "driver/isp_types.h" -#include "driver/isp.h" -#include "soc/soc_caps.h" #ifdef __cplusplus extern "C" { @@ -21,10 +19,9 @@ extern "C" { * @brief AF controller config */ typedef struct { -#if SOC_ISP_AF_WINDOW_NUMS - isp_af_window_t window[SOC_ISP_AF_WINDOW_NUMS]; ///< AF window settings -#endif + isp_af_window_t window[ISP_AF_WINDOW_NUM]; ///< The sampling windows of AF int edge_thresh; ///< Edge threshold, definition higher than this value will be counted as a valid pixel for calculating AF result + int intr_priority; ///< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) otherwise the larger the higher, 7 is NMI } esp_isp_af_config_t; /** @@ -80,17 +77,57 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctrlr); esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctrlr); /** - * @brief Get AF result + * @brief Trigger AF luminance and definition statistics for one time and get the result + * @note This function is a synchronous and block function, + * it only returns when AF luminance and definition statistics is done or timeout. + * It's a simple method to get the result directly for one time. + * + * @param[in] af_ctrlr AF controller handle + * @param[in] timeout_ms Timeout in millisecond + * - timeout_ms < 0: Won't return until finished + * - timeout_ms = 0: No timeout, trigger one time statistics and return immediately, + * in this case, the result won't be assigned in this function, + * but you can get the result in the callback `esp_isp_af_env_detector_evt_cbs_t::on_env_statistics_done` + * - timeout_ms > 0: Wait for specified milliseconds, if not finished, then return timeout error + * @param[out] out_res AF luminance and definition statistics result, can be NULL if `timeout_ms = 0` + * + * @return + * - ESP_OK On success + * - ESP_ERR_TIMEOUT If the waiting time exceeds the specified timeout. + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res); + +/** @cond */ +#define esp_isp_af_controller_get_oneshot_result(af_ctrlr, out_res) \ + esp_isp_af_controller_get_oneshot_statistics(af_ctrlr, -1, out_res) // Alias +/** @endcond */ + +/** + * @brief Start AF continuous statistics of the luminance and definition in the windows + * @note This function is an asynchronous and non-block function, + * it will start the continuous statistics and return immediately. + * You have to register the AF callback and get the result from the callback event data. * * @param[in] af_ctrlr AF controller handle - * @param[out] out_res AF result + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Null pointer + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr); + +/** + * @brief Stop AF continuous statistics of the luminance and definition in the windows * + * @param[in] af_ctrlr AF controller handle * @return * - ESP_OK On success - * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_ARG Null pointer * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_get_oneshot_result(isp_af_ctrlr_t af_ctrlr, isp_af_result_t *out_res); +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr); /*--------------------------------------------- AF Env Monitor @@ -99,7 +136,9 @@ esp_err_t esp_isp_af_controller_get_oneshot_result(isp_af_ctrlr_t af_ctrlr, isp_ * @brief AF environment detector config */ typedef struct { - int interval; ///< Interval between environment detection, in frames + int interval; /*!< Interval between environment detection, in frames. + * i.e., AF controller will trigger the statistic periodically to detect the environment change. + */ } esp_isp_af_env_config_t; /** @@ -133,7 +172,7 @@ esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctr * @brief Event data structure */ typedef struct { - //empty for future proof + isp_af_result_t af_result; /*!< The AF statistics result */ } esp_isp_af_env_detector_evt_data_t; /** @@ -155,7 +194,8 @@ typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_ctrlr_t af_ctrlr, cons * Involved variables should be in internal RAM as well. */ typedef struct { - esp_isp_af_env_detector_callback_t on_env_change; ///< Event callback, invoked when environment change happens. + esp_isp_af_env_detector_callback_t on_env_statistics_done; ///< Event callback, invoked when environment sample done. + esp_isp_af_env_detector_callback_t on_env_change; ///< Event callback, invoked when environment change happens. } esp_isp_af_env_detector_evt_cbs_t; /** diff --git a/components/esp_driver_isp/include/driver/isp_core.h b/components/esp_driver_isp/include/driver/isp_core.h new file mode 100644 index 00000000000..8081e945fe0 --- /dev/null +++ b/components/esp_driver_isp/include/driver/isp_core.h @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "driver/isp_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ISP configurations + */ +typedef struct { + isp_clk_src_t clk_src; ///< Clock source + uint32_t clk_hz; ///< Clock frequency in Hz, suggest twice higher than cam sensor speed + isp_input_data_source_t input_data_source; ///< Input data source + isp_color_t input_data_color_type; ///< Input color type + isp_color_t output_data_color_type; ///< Output color type + bool has_line_start_packet; ///< Enable line start packet + bool has_line_end_packet; ///< Enable line end packet + uint32_t h_res; ///< Input horizontal resolution, i.e. the number of pixels in a line + uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame +} esp_isp_processor_cfg_t; + +/** + * @brief New an ISP processor + * + * @param[in] proc_config Pointer to ISP config. Refer to ``esp_isp_processor_cfg_t``. + * @param[out] ret_proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags + * - ESP_ERR_NOT_SUPPORTED Not supported mode + * - ESP_ERR_NO_MEM If out of memory + */ +esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_proc_handle_t *ret_proc); + +/** + * @brief Delete an ISP processor + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_del_processor(isp_proc_handle_t proc); + +/** + * @brief Enable an ISP processor + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_enable(isp_proc_handle_t proc); + +/** + * @brief Disable an ISP processor + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_disable(isp_proc_handle_t proc); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index f2e0087a3d6..fa7c067e6c4 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -11,23 +11,29 @@ #include "esp_check.h" #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" -#include "driver/isp.h" -#include "hal/isp_hal.h" -#include "hal/isp_ll.h" +#include "driver/isp_af.h" #include "isp_internal.h" -#if CONFIG_ISP_ISR_IRAM_SAFE -#define ISP_AF_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) -#else -#define ISP_AF_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#endif - static const char *TAG = "ISP_AF"; +typedef struct isp_af_controller_t { + int id; + isp_fsm_t fsm; + portMUX_TYPE spinlock; + intr_handle_t intr_handle; + isp_proc_handle_t isp_proc; + QueueHandle_t evt_que; + esp_isp_af_env_config_t config; + esp_isp_af_env_detector_evt_cbs_t cbs; + void *user_data; +} isp_af_controller_t; + +static void s_isp_af_default_isr(void *arg); + /*--------------------------------------------- AF ----------------------------------------------*/ -static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_controller_t *af_ctlr) +static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ctrlr_t af_ctlr) { assert(isp_proc && af_ctlr); @@ -50,15 +56,26 @@ static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_co return ESP_OK; } -static esp_err_t s_isp_declaim_af_controller(isp_af_controller_t *af_ctlr) +static void s_isp_declaim_af_controller(isp_af_ctrlr_t af_ctlr) { assert(af_ctlr && af_ctlr->isp_proc); portENTER_CRITICAL(&af_ctlr->isp_proc->spinlock); af_ctlr->isp_proc->af_ctlr[af_ctlr->id] = NULL; portEXIT_CRITICAL(&af_ctlr->isp_proc->spinlock); +} - return ESP_OK; +static void s_isp_af_free_controller(isp_af_ctrlr_t af_ctlr) +{ + if (af_ctlr) { + if (af_ctlr->intr_handle) { + esp_intr_free(af_ctlr->intr_handle); + } + if (af_ctlr->evt_que) { + vQueueDelete(af_ctlr->evt_que); + } + free(af_ctlr); + } } esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl) @@ -85,16 +102,23 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af } ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0"); - isp_af_controller_t *af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_AF_MEM_ALLOC_CAPS); + isp_af_ctrlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem"); - - //claim an AF controller - ESP_GOTO_ON_ERROR(s_isp_claim_af_controller(isp_proc, af_ctlr), err, TAG, "no available controller"); - + af_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_af_result_t), ISP_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(af_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for af event queue"); af_ctlr->fsm = ISP_FSM_INIT; af_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; af_ctlr->isp_proc = isp_proc; + //claim an AF controller + ESP_GOTO_ON_ERROR(s_isp_claim_af_controller(isp_proc, af_ctlr), err1, TAG, "no available controller"); + + // Register the AF ISR + uint32_t intr_st_reg_addr = isp_ll_get_intr_status_reg_addr(isp_proc->hal.hw); + int intr_priority = af_config->intr_priority > 0 && af_config->intr_priority <= 7 ? BIT(af_config->intr_priority) : ESP_INTR_FLAG_LOWMED; + ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(isp_hw_info.instances[isp_proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | intr_priority, intr_st_reg_addr, ISP_LL_EVENT_AF_MASK, + s_isp_af_default_isr, af_ctlr, &af_ctlr->intr_handle), err2, TAG, "allocate interrupt failed"); + isp_ll_af_enable_auto_update(isp_proc->hal.hw, false); isp_ll_af_enable(isp_proc->hal.hw, false); @@ -109,9 +133,10 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af *ret_hdl = af_ctlr; return ESP_OK; - -err: - free(af_ctlr); +err2: + s_isp_declaim_af_controller(af_ctlr); +err1: + s_isp_af_free_controller(af_ctlr); return ret; } @@ -119,10 +144,17 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_ERROR(s_isp_declaim_af_controller(af_ctlr), TAG, "controller isn't in use"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); - - free(af_ctlr); + bool exist = false; + for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) { + if (af_ctlr->isp_proc->af_ctlr[i] == af_ctlr) { + exist = true; + break; + } + } + ESP_RETURN_ON_FALSE(exist, ESP_ERR_INVALID_ARG, TAG, "controller isn't in use"); + s_isp_declaim_af_controller(af_ctlr); + s_isp_af_free_controller(af_ctlr); return ESP_OK; } @@ -132,7 +164,9 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr) ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + esp_intr_enable(af_ctlr->intr_handle); isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, true); + isp_ll_enable_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_MASK, true); isp_ll_af_enable(af_ctlr->isp_proc->hal.hw, true); af_ctlr->fsm = ISP_FSM_ENABLE; @@ -145,18 +179,51 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr) ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); isp_ll_af_clk_enable(af_ctlr->isp_proc->hal.hw, false); + isp_ll_enable_intr(af_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_MASK, false); isp_ll_af_enable(af_ctlr->isp_proc->hal.hw, false); + esp_intr_disable(af_ctlr->intr_handle); af_ctlr->fsm = ISP_FSM_INIT; return ESP_OK; } -esp_err_t esp_isp_af_controller_get_oneshot_result(isp_af_ctrlr_t af_ctlr, isp_af_result_t *out_res) +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res) { - ESP_RETURN_ON_FALSE_ISR(af_ctlr && out_res, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE_ISR(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + ESP_RETURN_ON_FALSE_ISR(af_ctrlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has started"); + + esp_err_t ret = ESP_OK; + TickType_t ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + // Reset the queue in case receiving the legacy data in the queue + xQueueReset(af_ctrlr->evt_que); + // Trigger the AF statistics manually + isp_ll_af_manual_update(af_ctrlr->isp_proc->hal.hw); + // Wait the statistics to finish and receive the result from the queue + if ((ticks > 0) && xQueueReceive(af_ctrlr->evt_que, out_res, ticks) != pdTRUE) { + ret = ESP_ERR_TIMEOUT; + } - isp_hal_af_get_oneshot_result(&af_ctlr->isp_proc->hal, out_res); + return ret; +} + +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +{ + ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + + af_ctrlr->fsm = ISP_FSM_START; + isp_ll_af_enable_auto_update(af_ctrlr->isp_proc->hal.hw, true); + + return ESP_OK; +} + +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +{ + ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); + + isp_ll_af_enable_auto_update(af_ctrlr->isp_proc->hal.hw, false); + af_ctrlr->fsm = ISP_FSM_ENABLE; return ESP_OK; } @@ -183,13 +250,17 @@ esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctr ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state"); #if CONFIG_ISP_ISR_IRAM_SAFE + if (cbs->on_env_statistics_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_env_statistics_done), ESP_ERR_INVALID_ARG, TAG, "on_env_statistics_done callback not in IRAM"); + } if (cbs->on_env_change) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_env_change), ESP_ERR_INVALID_ARG, TAG, "on_env_change callback not in IRAM"); } + if (user_data) { + ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); + } #endif - - ESP_RETURN_ON_ERROR(esp_isp_register_isr(af_ctrlr->isp_proc, ISP_SUBMODULE_AF), TAG, "fail to register ISR"); - + af_ctrlr->cbs.on_env_statistics_done = cbs->on_env_statistics_done; af_ctrlr->cbs.on_env_change = cbs->on_env_change; af_ctrlr->user_data = user_data; @@ -209,36 +280,47 @@ esp_err_t esp_isp_af_env_detector_set_threshold(isp_af_ctrlr_t af_ctrlr, int def /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ -static bool IRAM_ATTR s_af_env_isr(isp_af_ctrlr_t af_ctrlr) +static void IRAM_ATTR s_isp_af_default_isr(void *arg) { - bool need_yield = false; + isp_af_ctrlr_t af_ctrlr = (isp_af_ctrlr_t)arg; + isp_proc_handle_t proc = af_ctrlr->isp_proc; + + uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK); + bool need_yield = false; esp_isp_af_env_detector_evt_data_t edata = {}; - if (af_ctrlr->cbs.on_env_change(af_ctrlr, &edata, af_ctrlr->user_data)) { - need_yield |= true; - } - return need_yield; -} + if (af_events) { + // Get the statistics result + for (int i = 0; i < SOC_ISP_AF_WINDOW_NUMS; i++) { + edata.af_result.definition[i] = isp_ll_af_get_window_sum(proc->hal.hw, i); + edata.af_result.luminance[i] = isp_ll_af_get_window_lum(proc->hal.hw, i); + } + } -bool IRAM_ATTR esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events) -{ /** - * HW events are cleared in the ISP ISR dispatcher. - * We only deal with HW events + * Deal with the interrupts. + * Now only one detector. + * Should decide a detector instance according to the hw event. */ - - bool need_yield = false; - + if (af_events & ISP_LL_EVENT_AF_FDONE) { + BaseType_t high_task_awake = false; + // Send the event data to the queue, overwrite the legacy one if exist + xQueueOverwriteFromISR(af_ctrlr->evt_que, &edata.af_result, &high_task_awake); + // Invoke the callback if the callback is registered + need_yield |= high_task_awake == pdTRUE; + if (af_ctrlr->cbs.on_env_statistics_done) { + need_yield |= af_ctrlr->cbs.on_env_statistics_done(af_ctrlr, &edata, af_ctrlr->user_data); + } + } if (af_events & ISP_LL_EVENT_AF_ENV) { - /** - * Now only one detector. - * Should decide a detector instance according to the hw event. - */ - isp_af_ctrlr_t af_ctrlr = proc->af_ctlr[0]; - - need_yield |= s_af_env_isr(af_ctrlr); + // Invoke the callback if the callback is registered + if (af_ctrlr->cbs.on_env_change) { + need_yield |= af_ctrlr->cbs.on_env_change(af_ctrlr, &edata, af_ctrlr->user_data); + } } - return need_yield; + if (need_yield) { + portYIELD_FROM_ISR(); + } } diff --git a/components/esp_driver_isp/src/isp.c b/components/esp_driver_isp/src/isp_core.c similarity index 69% rename from components/esp_driver_isp/src/isp.c rename to components/esp_driver_isp/src/isp_core.c index c0d8a2699d0..0e18905b585 100644 --- a/components/esp_driver_isp/src/isp.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -12,29 +12,14 @@ #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "esp_clk_tree.h" -#include "driver/isp.h" +#include "driver/isp_core.h" #include "esp_private/periph_ctrl.h" #include "esp_private/mipi_csi_share_hw_ctrl.h" #include "hal/hal_utils.h" -#include "hal/isp_types.h" -#include "hal/isp_hal.h" -#include "hal/isp_ll.h" #include "soc/mipi_csi_bridge_struct.h" #include "soc/isp_periph.h" #include "isp_internal.h" -#if CONFIG_ISP_ISR_IRAM_SAFE -#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM) -#else -#define ISP_INTR_ALLOC_FLAGS 0 -#endif - -#if CONFIG_ISP_ISR_IRAM_SAFE -#define ISP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) -#else -#define ISP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#endif - typedef struct isp_platform_t { _lock_t mutex; isp_processor_t *processors[SOC_ISP_NUMS]; @@ -202,100 +187,3 @@ esp_err_t esp_isp_disable(isp_proc_handle_t proc) return ESP_OK; } - -/*--------------------------------------------------------------- - INTR ----------------------------------------------------------------*/ -static void IRAM_ATTR s_isp_isr_dispatcher(void *arg) -{ - isp_processor_t *proc = (isp_processor_t *)arg; - bool need_yield = false; - - //Check and clear hw events - uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK); - - bool do_dispatch = false; - //Deal with hw events - if (af_events) { - portENTER_CRITICAL_ISR(&proc->spinlock); - do_dispatch = proc->af_isr_added; - portEXIT_CRITICAL_ISR(&proc->spinlock); - - if (do_dispatch) { - need_yield |= esp_isp_af_isr(proc, af_events); - } - do_dispatch = false; - } - - if (need_yield) { - portYIELD_FROM_ISR(); - } -} - -esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule) -{ - esp_err_t ret = ESP_FAIL; - ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - - bool do_alloc = false; - portENTER_CRITICAL(&proc->spinlock); - proc->isr_ref_counts++; - if (proc->isr_ref_counts == 1) { - assert(!proc->intr_hdl); - do_alloc = true; - } - - switch (submodule) { - case ISP_SUBMODULE_AF: - proc->af_isr_added = true; - break; - default: - assert(false); - } - portEXIT_CRITICAL(&proc->spinlock); - - if (do_alloc) { - ret = esp_intr_alloc(isp_hw_info.instances[proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS, s_isp_isr_dispatcher, (void *)proc, &proc->intr_hdl); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "no intr source"); - return ret; - } - esp_intr_enable(proc->intr_hdl); - } - - return ESP_OK; -} - -esp_err_t esp_isp_deregister_isr(isp_proc_handle_t proc, isp_submodule_t submodule) -{ - esp_err_t ret = ESP_FAIL; - ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - - bool do_free = false; - portENTER_CRITICAL(&proc->spinlock); - proc->isr_ref_counts--; - assert(proc->isr_ref_counts >= 0); - if (proc->isr_ref_counts == 0) { - assert(proc->intr_hdl); - do_free = true; - } - - switch (submodule) { - case ISP_SUBMODULE_AF: - proc->af_isr_added = false; - break; - default: - assert(false); - } - portEXIT_CRITICAL(&proc->spinlock); - - if (do_free) { - esp_intr_disable(proc->intr_hdl); - ret = esp_intr_free(proc->intr_hdl); - if (ret != ESP_OK) { - return ret; - } - } - - return ESP_OK; -} diff --git a/components/esp_driver_isp/src/isp_internal.h b/components/esp_driver_isp/src/isp_internal.h index eab28412287..1ad011c409c 100644 --- a/components/esp_driver_isp/src/isp_internal.h +++ b/components/esp_driver_isp/src/isp_internal.h @@ -16,7 +16,11 @@ #include "esp_heap_caps.h" #include "esp_intr_alloc.h" #include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/idf_additions.h" +#include "driver/isp_types.h" #include "hal/isp_hal.h" +#include "hal/isp_ll.h" #include "hal/isp_types.h" #include "soc/isp_periph.h" #include "soc/soc_caps.h" @@ -25,32 +29,24 @@ extern "C" { #endif +#if CONFIG_ISP_ISR_IRAM_SAFE +#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM) +#define ISP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define ISP_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED) +#define ISP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif + typedef enum { ISP_FSM_INIT, ISP_FSM_ENABLE, + ISP_FSM_START, } isp_fsm_t; /*--------------------------------------------------------------- Driver Context ---------------------------------------------------------------*/ -typedef enum { - ISP_SUBMODULE_AF, -} isp_submodule_t; - -typedef struct isp_af_controller_t isp_af_controller_t; -typedef struct isp_processor_t isp_processor_t; - -struct isp_af_controller_t { - int id; - isp_fsm_t fsm; - portMUX_TYPE spinlock; - isp_processor_t *isp_proc; - esp_isp_af_env_config_t config; - esp_isp_af_env_detector_evt_cbs_t cbs; - void *user_data; -}; - -struct isp_processor_t { +typedef struct isp_processor_t { int proc_id; isp_hal_context_t hal; #if SOC_ISP_SHARE_CSI_BRG @@ -59,22 +55,10 @@ struct isp_processor_t { #endif isp_fsm_t isp_fsm; portMUX_TYPE spinlock; - intr_handle_t intr_hdl; /* sub module contexts */ - isp_af_controller_t *af_ctlr[SOC_ISP_AF_CTLR_NUMS]; - - /* should be accessed within isp_processor_t spinlock */ - int isr_ref_counts; - bool af_isr_added; -}; - -/*--------------------------------------------------------------- - INTR ----------------------------------------------------------------*/ -esp_err_t esp_isp_register_isr(isp_proc_handle_t proc, isp_submodule_t submodule); -esp_err_t esp_isp_deregister_isr(isp_proc_handle_t proc, isp_submodule_t submodule); -bool esp_isp_af_isr(isp_proc_handle_t proc, uint32_t af_events); + isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; +} isp_processor_t; #ifdef __cplusplus } diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index 2773b0b82ca..ee837995ec7 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -537,6 +537,7 @@ static inline void isp_ll_af_set_window_range(isp_dev_t *hw, uint32_t window_id, * * @return Window sum */ +__attribute__((always_inline)) static inline uint32_t isp_ll_af_get_window_sum(isp_dev_t *hw, uint32_t window_id) { switch (window_id) { @@ -560,6 +561,7 @@ static inline uint32_t isp_ll_af_get_window_sum(isp_dev_t *hw, uint32_t window_i * * @return Window lum */ +__attribute__((always_inline)) static inline uint32_t isp_ll_af_get_window_lum(isp_dev_t *hw, uint32_t window_id) { switch (window_id) { @@ -742,6 +744,18 @@ static inline uint32_t isp_ll_get_intr_status(isp_dev_t *hw) return hw->int_st.val; } +/** + * @brief Get interrupt status reg address + * + * @param[in] hw Hardware instance address + * + * @return Interrupt status reg address + */ +static inline uint32_t isp_ll_get_intr_status_reg_addr(isp_dev_t *hw) +{ + return (uint32_t)&(hw->int_st); +} + /** * @brief Get interrupt raw * diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index 80ea6db9de5..2a113ddb3fd 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -50,14 +50,6 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id); */ void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_af_window_t *window); -/** - * @brief Get AF oneshot result - * - * @param[in] hal Context of the HAL layer - * @param[out] out_res AF result - */ -void isp_hal_af_get_oneshot_result(const isp_hal_context_t *hal, isp_af_result_t *out_res); - /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index cbbb2fd00c7..8a2fb0fc76f 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,6 +48,12 @@ typedef enum { /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ +#if SOC_ISP_AF_WINDOW_NUMS +#define ISP_AF_WINDOW_NUM SOC_ISP_AF_WINDOW_NUMS // The AF window number for sampling +#else +#define ISP_AF_WINDOW_NUM 0 +#endif + /** * @brief ISP AF window */ @@ -62,10 +68,8 @@ typedef struct { * @brief ISP AF result */ typedef struct { -#if SOC_ISP_SUPPORTED - int definition[SOC_ISP_AF_WINDOW_NUMS]; ///< Definition, it refers how clear and sharp an image is - int luminance[SOC_ISP_AF_WINDOW_NUMS]; ///< Luminance, it refers how luminant an image is -#endif + int definition[ISP_AF_WINDOW_NUM]; ///< Definition, it refers how clear and sharp an image is + int luminance[ISP_AF_WINDOW_NUM]; ///< Luminance, it refers how luminant an image is } isp_af_result_t; #ifdef __cplusplus diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index 6fb72413a99..d897c07080a 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -31,22 +31,6 @@ void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_ll_af_set_window_range(hal->hw, window_id, window->top_left_x, window->top_left_y, window->bottom_right_x, window->bottom_right_y); } -void isp_hal_af_get_oneshot_result(const isp_hal_context_t *hal, isp_af_result_t *out_res) -{ - isp_ll_clear_intr(hal->hw, ISP_LL_EVENT_AF_FDONE); - isp_ll_af_manual_update(hal->hw); - - while (!(isp_ll_get_intr_raw(hal->hw) & ISP_LL_EVENT_AF_FDONE)) { - ; - } - - for (int i = 0; i < SOC_ISP_AF_WINDOW_NUMS; i++) { - out_res->definition[i] = isp_ll_af_get_window_sum(hal->hw, i); - out_res->luminance[i] = isp_ll_af_get_window_lum(hal->hw, i); - } -} - - /*--------------------------------------------------------------- INTR, put in iram ---------------------------------------------------------------*/ diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 4d05b9c74a4..1a2ff494d29 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -25,6 +25,7 @@ The ISP driver offers following services: - `Resource Allocation <#isp-resource-allocation>`__ - covers how to allocate ISP resources with properly set of configurations. It also covers how to recycle the resources when they finished working. - `Enable and disable ISP processor <#isp-enable-disable>`__ - covers how to enable and disable an ISP processor. - `Get AF oneshot result <#isp-af-get-oneshot-result>`__ - covers how to get AF oneshot result. +- `Start AF statistics continuously <#isp-af-start-conti-stat>`__ - covers how to start the continuous AF statistics. - `Register callback <#isp-callback>`__ - covers how to hook user specific code to ISP driver event callback function. - `Thread Safety <#isp-thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. - `Kconfig Options <#isp-kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver. @@ -114,7 +115,7 @@ Calling :cpp:func:`esp_isp_af_controller_disable` does the opposite, that is, pu Get Auto-Focus (AF) Oneshot Result ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Calling :cpp:func:`esp_isp_af_controller_get_oneshot_result` to get oneshot AF result. You can take following code as reference. +Calling :cpp:func:`esp_isp_af_controller_get_oneshot_statistics` to get oneshot AF statistics result. You can take following code as reference. .. code:: c @@ -123,8 +124,42 @@ Calling :cpp:func:`esp_isp_af_controller_get_oneshot_result` to get oneshot AF r }; isp_af_ctrlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); + ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); isp_af_result_t result = {}; - ESP_ERROR_CHECK(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result)); + /* Trigger the AF statistics and get its result for one time with timeout value 2000ms. */ + ESP_ERROR_CHECK(esp_isp_af_controller_get_oneshot_statistics(af_ctrlr, 2000, &result)); + +.. _isp-af-start-conti-stat: + +Start Auto-Focus (AF) Statistics Continuously +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Aside from the above oneshot API, the ISP AF driver also provides a way to start AF statistics continuously. Calling :cpp:func:`esp_isp_af_controller_start_continuous_statistics` to start the continuous statistics and :cpp:func:`esp_isp_af_controller_stop_continuous_statistics` to stop it. + +Note that if you want to use the continuous statistics, you need to register the :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_statistics_done` or :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_change` callback to get the statistics result. See how to register in `Register Event Callbacks <#isp-callback>`__ + +.. code:: c + + isp_af_ctrlr_t af_ctrlr = NULL; + esp_isp_af_config_t af_config = { + .edge_thresh = 128, + }; + isp_af_result_t stat_res = {}; + /* Create the af controller */ + ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); + /* Enabled the af controller */ + ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); + /* Start continuous AF statistics */ + ESP_ERROR_CHECK(esp_isp_af_controller_start_continuous_statistics(af_ctrlr)); + // You can do other stuffs here, the statistics result can be obtained in the callback + // ...... + // vTaskDelay(pdMS_TO_TICKS(1000)); + /* Stop continuous AF statistics */ + ESP_ERROR_CHECK(esp_isp_af_controller_stop_continuous_statistics(af_ctrlr)); + /* Disable the af controller */ + ESP_ERROR_CHECK(esp_isp_af_controller_disable(af_ctrlr)); + /* Delete the af controller and free the resources */ + ESP_ERROR_CHECK(esp_isp_del_af_controller(af_ctrlr)); Set Auto-Focus (AF) Environment Detector ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,6 +196,7 @@ Register Image Signal Processor (ISP) Auto-Focus (AF) Environment Detector Event After the ISP AF environment detector starts up, it can generate a specific event dynamically. If you have some functions that should be called when the event happens, please hook your function to the interrupt service routine by calling :cpp:func:`esp_isp_af_env_detector_register_event_callbacks`. All supported event callbacks are listed in :cpp:type:`esp_isp_af_env_detector_evt_cbs_t`: +- :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_statistics_done` sets a callback function for environment statistics done. As this function is called within the ISR context, you must ensure that the function does not attempt to block (e.g., by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function). The function prototype is declared in :cpp:type:`esp_isp_af_env_detector_callback_t`. - :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_change` sets a callback function for environment change. As this function is called within the ISR context, you must ensure that the function does not attempt to block (e.g., by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function). The function prototype is declared in :cpp:type:`esp_isp_af_env_detector_callback_t`. You can save your own context to :cpp:func:`esp_isp_af_env_detector_register_event_callbacks` as well, via the parameter ``user_data``. The user data will be directly passed to the callback function. From f1d1dfd1ef36d25a67dc441a4d98778c833cbbb4 Mon Sep 17 00:00:00 2001 From: "chaijie@espressif.com" Date: Tue, 7 May 2024 18:10:09 +0800 Subject: [PATCH 058/548] feat(esp32p4_eco1): modify cpll and spll config --- .../src/esp32p4/bootloader_esp32p4.c | 17 +++--- .../esp_hw_support/port/esp32p4/pmu_sleep.c | 8 ++- .../hal/esp32p4/include/hal/clk_tree_ll.h | 52 ++++++++++++++----- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c index 544fcd1ad43..c26c83381ee 100644 --- a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c +++ b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c @@ -91,13 +91,16 @@ static inline void bootloader_hardware_init(void) { // regi2c is enabled by default on ESP32P4, do nothing - // On ESP32P4 ECO0, the default (power on reset) CPLL and SPLL frequencies are very high, lower them to avoid bias may not be enough in bootloader - // And we are fixing SPLL to be 480MHz at all runtime - // Suppose to fix the issue on ECO1, will check when chip comes back - // TODO: IDF-8939 - REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M - REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M - esp_rom_delay_us(100); + unsigned chip_version = efuse_hal_chip_revision(); + if (chip_version == 0) { + // On ESP32P4 ECO0, the default (power on reset) CPLL and SPLL frequencies are very high, lower them to avoid bias may not be enough in bootloader + // And we are fixing SPLL to be 480MHz at all runtime + // Suppose to fix the issue on ECO1, will check when chip comes back + // TODO: IDF-8939 + REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M + REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M + esp_rom_delay_us(100); + } REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1, 10); REGI2C_WRITE_MASK(I2C_BIAS, I2C_BIAS_DREG_1P1_PVT, 10); } diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 919197fb481..391d80597d8 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -27,6 +27,7 @@ #include "pmu_param.h" #include "esp_rom_sys.h" #include "esp_rom_uart.h" +#include "hal/efuse_hal.h" #define HP(state) (PMU_MODE_HP_ ## state) #define LP(state) (PMU_MODE_LP_ ## state) @@ -317,8 +318,11 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(void) } pmu_sleep_shutdown_ldo(); - REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M - REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M + unsigned chip_version = efuse_hal_chip_revision(); + if (chip_version == 0) { + REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M + REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M + } return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index f504917fe7a..0e65f9e6b68 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -22,6 +22,7 @@ #include "hal/log.h" #include "esp32p4/rom/rtc.h" #include "hal/misc.h" +#include "hal/efuse_hal.h" #ifdef __cplusplus extern "C" { @@ -309,7 +310,13 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_cpll_get_freq_mhz(u { uint8_t div = REGI2C_READ_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0); uint8_t ref_div = REGI2C_READ_MASK(I2C_CPLL, I2C_CPLL_OC_REF_DIV); - return xtal_freq_mhz * (div + 4) / (ref_div + 1); +#if !ESP_CHIP_REV_ABOVE(ESP_HAL_CHIP_REV_MIN, 1) + unsigned chip_version = efuse_hal_chip_revision(); + if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { + return xtal_freq_mhz * (div + 4) / (ref_div + 1); + } else +#endif + return xtal_freq_mhz * div / (ref_div + 1); } /** @@ -336,22 +343,41 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_set_config(uint32_ uint8_t dchgp = 5; uint8_t dcur = 3; uint8_t oc_enb_fcal = 0; + unsigned chip_version = efuse_hal_chip_revision(); // Currently, only supporting 40MHz XTAL HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M); - switch (cpll_freq_mhz) { - case CLK_LL_PLL_400M_FREQ_MHZ: - /* Configure 400M CPLL */ - div7_0 = 6; - div_ref = 0; - break; - case CLK_LL_PLL_360M_FREQ_MHZ: - default: - /* Configure 360M CPLL */ - div7_0 = 5; - div_ref = 0; - break; + if (chip_version == 0) { + switch (cpll_freq_mhz) { + case CLK_LL_PLL_400M_FREQ_MHZ: + /* Configure 400M CPLL */ + div7_0 = 6; + div_ref = 0; + break; + case CLK_LL_PLL_360M_FREQ_MHZ: + default: + /* Configure 360M CPLL */ + div7_0 = 5; + div_ref = 0; + break; + } + } else { + /*div7_0 bit2 & bit3 will swap from ECO1*/ + switch (cpll_freq_mhz) { + case CLK_LL_PLL_400M_FREQ_MHZ: + /* Configure 400M CPLL */ + div7_0 = 10; + div_ref = 0; + break; + case CLK_LL_PLL_360M_FREQ_MHZ: + default: + /* Configure 360M CPLL */ + div7_0 = 9; + div_ref = 0; + break; + } } + uint8_t i2c_cpll_lref = (oc_enb_fcal << I2C_CPLL_OC_ENB_FCAL_LSB) | (dchgp << I2C_CPLL_OC_DCHGP_LSB) | (div_ref); uint8_t i2c_cpll_div_7_0 = div7_0; uint8_t i2c_cpll_dcur = (1 << I2C_CPLL_OC_DLREF_SEL_LSB ) | (3 << I2C_CPLL_OC_DHREF_SEL_LSB) | dcur; From cbcd3461712158a71accc3b98aa90a0c7e2bfb37 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Thu, 9 May 2024 17:04:45 +0800 Subject: [PATCH 059/548] feat(esp32p4): add eco1 revision config option --- .../src/esp32p4/bootloader_esp32p4.c | 12 +++++------- .../esp_hw_support/port/esp32p4/Kconfig.hw_support | 3 +++ components/esp_hw_support/port/esp32p4/pmu_sleep.c | 3 ++- components/hal/esp32p4/include/hal/clk_tree_ll.h | 11 ++++++----- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c index c26c83381ee..f04a9216986 100644 --- a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c +++ b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,6 +29,7 @@ #include "bootloader_flash_config.h" #include "bootloader_mem.h" #include "esp_private/regi2c_ctrl.h" +#include "soc/chip_revision.h" #include "soc/regi2c_lp_bias.h" #include "soc/regi2c_bias.h" #include "bootloader_console.h" @@ -90,13 +91,10 @@ static void bootloader_super_wdt_auto_feed(void) static inline void bootloader_hardware_init(void) { // regi2c is enabled by default on ESP32P4, do nothing - unsigned chip_version = efuse_hal_chip_revision(); - if (chip_version == 0) { + if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { // On ESP32P4 ECO0, the default (power on reset) CPLL and SPLL frequencies are very high, lower them to avoid bias may not be enough in bootloader - // And we are fixing SPLL to be 480MHz at all runtime - // Suppose to fix the issue on ECO1, will check when chip comes back - // TODO: IDF-8939 + // And we are fixing SPLL to be 480MHz after app is up REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M esp_rom_delay_us(100); @@ -173,7 +171,7 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM - // check whether a WDT reset happend + // check whether a WDT reset happened bootloader_check_wdt_reset(); // config WDT bootloader_config_wdt(); diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support index a7c2840267a..49b77c0ccf8 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support +++ b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support @@ -11,11 +11,14 @@ choice ESP32P4_REV_MIN config ESP32P4_REV_MIN_0 bool "Rev v0.0" + config ESP32P4_REV_MIN_1 + bool "Rev v0.1" endchoice config ESP32P4_REV_MIN_FULL int default 0 if ESP32P4_REV_MIN_0 + default 1 if ESP32P4_REV_MIN_1 config ESP_REV_MIN_FULL int diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 391d80597d8..ca93907ae5f 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -12,6 +12,7 @@ #include "esp_err.h" #include "esp_attr.h" #include "esp_private/regi2c_ctrl.h" +#include "soc/chip_revision.h" #include "soc/soc.h" #include "soc/regi2c_syspll.h" #include "soc/regi2c_cpll.h" @@ -319,7 +320,7 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(void) pmu_sleep_shutdown_ldo(); unsigned chip_version = efuse_hal_chip_revision(); - if (chip_version == 0) { + if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M REGI2C_WRITE_MASK(I2C_SYSPLL, I2C_SYSPLL_OC_DIV_7_0, 8); // lower default sys_pll freq to 480M } diff --git a/components/hal/esp32p4/include/hal/clk_tree_ll.h b/components/hal/esp32p4/include/hal/clk_tree_ll.h index 0e65f9e6b68..1dd5efd0212 100644 --- a/components/hal/esp32p4/include/hal/clk_tree_ll.h +++ b/components/hal/esp32p4/include/hal/clk_tree_ll.h @@ -9,6 +9,7 @@ #include #include "soc/clkout_channel.h" #include "soc/soc.h" +#include "soc/chip_revision.h" #include "soc/clk_tree_defs.h" #include "soc/hp_sys_clkrst_reg.h" #include "soc/hp_sys_clkrst_struct.h" @@ -24,6 +25,7 @@ #include "hal/misc.h" #include "hal/efuse_hal.h" + #ifdef __cplusplus extern "C" { #endif @@ -310,12 +312,10 @@ static inline __attribute__((always_inline)) uint32_t clk_ll_cpll_get_freq_mhz(u { uint8_t div = REGI2C_READ_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0); uint8_t ref_div = REGI2C_READ_MASK(I2C_CPLL, I2C_CPLL_OC_REF_DIV); -#if !ESP_CHIP_REV_ABOVE(ESP_HAL_CHIP_REV_MIN, 1) unsigned chip_version = efuse_hal_chip_revision(); if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { return xtal_freq_mhz * (div + 4) / (ref_div + 1); } else -#endif return xtal_freq_mhz * div / (ref_div + 1); } @@ -343,11 +343,12 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_set_config(uint32_ uint8_t dchgp = 5; uint8_t dcur = 3; uint8_t oc_enb_fcal = 0; - unsigned chip_version = efuse_hal_chip_revision(); // Currently, only supporting 40MHz XTAL HAL_ASSERT(xtal_freq_mhz == SOC_XTAL_FREQ_40M); - if (chip_version == 0) { + + unsigned chip_version = efuse_hal_chip_revision(); + if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { switch (cpll_freq_mhz) { case CLK_LL_PLL_400M_FREQ_MHZ: /* Configure 400M CPLL */ @@ -362,7 +363,7 @@ static inline __attribute__((always_inline)) void clk_ll_cpll_set_config(uint32_ break; } } else { - /*div7_0 bit2 & bit3 will swap from ECO1*/ + /*div7_0 bit2 & bit3 is swapped from ECO1*/ switch (cpll_freq_mhz) { case CLK_LL_PLL_400M_FREQ_MHZ: /* Configure 400M CPLL */ From 4dc565b7d08889f0fa5ab57bb85e4979dc7d3a47 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 13 May 2024 12:19:14 +0800 Subject: [PATCH 060/548] feature(usb_serial_jtag): add usb serial jtag support for esp32p4 --- .../src/usb_serial_jtag_connection_monitor.c | 8 +- .../test_apps/.build-test-rules.yml | 4 + .../test_apps/usb_serial_jtag/README.md | 4 +- .../pytest_esp_system_console_tests.py | 1 - .../esp32c3/include/hal/usb_serial_jtag_ll.h | 1 + .../esp32c6/include/hal/usb_serial_jtag_ll.h | 1 + .../esp32h2/include/hal/usb_serial_jtag_ll.h | 1 + .../esp32p4/include/hal/usb_serial_jtag_ll.h | 173 +++++++++++++++++- .../esp32s3/include/hal/usb_serial_jtag_ll.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32p4/include/soc/interrupts.h | 2 +- components/soc/esp32p4/include/soc/soc_caps.h | 3 +- components/soc/esp32p4/interrupts.c | 2 +- docs/docs_not_updated/esp32p4.txt | 1 - .../en/api-guides/usb-serial-jtag-console.rst | 4 +- .../establish-serial-connection.rst | 10 +- .../usb_serial_jtag_echo/README.md | 4 +- 17 files changed, 202 insertions(+), 22 deletions(-) diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_connection_monitor.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_connection_monitor.c index eb38a267e68..a730a636c0e 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_connection_monitor.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_connection_monitor.c @@ -52,7 +52,7 @@ static void IRAM_ATTR usb_serial_jtag_sof_tick_hook(void) #if CONFIG_USJ_NO_AUTO_LS_ON_CONNECTION esp_pm_lock_release(s_usb_serial_jtag_pm_lock); #endif -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-7496 SOC_USB_SERIAL_JTAG_PHY_ON_BBPLL +#if USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL rtc_clk_bbpll_remove_consumer(); #endif s_usb_serial_jtag_conn_status = false; @@ -62,7 +62,7 @@ static void IRAM_ATTR usb_serial_jtag_sof_tick_hook(void) #if CONFIG_USJ_NO_AUTO_LS_ON_CONNECTION esp_pm_lock_acquire(s_usb_serial_jtag_pm_lock); #endif -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-7496 SOC_USB_SERIAL_JTAG_PHY_ON_BBPLL +#if USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL rtc_clk_bbpll_add_consumer(); #endif s_usb_serial_jtag_conn_status = true; @@ -79,8 +79,8 @@ ESP_SYSTEM_INIT_FN(usb_serial_jtag_conn_status_init, SECONDARY, BIT(0), 230) // We always assume it is connected at first, so acquires the lock to avoid auto light sleep esp_pm_lock_acquire(s_usb_serial_jtag_pm_lock); #endif -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-7496 SOC_USB_SERIAL_JTAG_PHY_ON_BBPLL -// TODO: esp32p4 USJ rely on SPLL, if it will also be disabled during sleep, we need to call spll_add_consumer? +#if USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL +// TODO: esp32p4 USJ rely on SPLL, if it will also be disabled during sleep, we need to call spll_add_consumer? IDF-9947 rtc_clk_bbpll_add_consumer(); #endif s_usb_serial_jtag_conn_status = true; diff --git a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml index 5605004cfc9..18ab2db959d 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml +++ b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml @@ -3,6 +3,10 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag: disable: - if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET in ["esp32p4"] + temporary: true + reason: No runners. depends_components: - vfs - esp_driver_gpio diff --git a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md index f1988f4a402..ad95e411339 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md +++ b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_system/test_apps/console/pytest_esp_system_console_tests.py b/components/esp_system/test_apps/console/pytest_esp_system_console_tests.py index 730a390a475..06432a8158e 100644 --- a/components/esp_system/test_apps/console/pytest_esp_system_console_tests.py +++ b/components/esp_system/test_apps/console/pytest_esp_system_console_tests.py @@ -20,7 +20,6 @@ def not_expect(dut: Dut, output_regex: str) -> None: pytest.mark.esp32c3, pytest.mark.esp32c6, pytest.mark.esp32h2, - pytest.mark.esp32p4, ] diff --git a/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h index 11830296218..f57b378e7f4 100644 --- a/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32c3/include/hal/usb_serial_jtag_ll.h @@ -16,6 +16,7 @@ /* ----------------------------- Macros & Types ----------------------------- */ #define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask +#define USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL (1) // Define USB_SERIAL_JTAG interrupts // Note the hardware has more interrupts, but they're only useful for debugging diff --git a/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h index 56b44d0a1ac..d9aa7e58fa1 100644 --- a/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32c6/include/hal/usb_serial_jtag_ll.h @@ -16,6 +16,7 @@ /* ----------------------------- Macros & Types ----------------------------- */ #define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask +#define USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL (1) // Define USB_SERIAL_JTAG interrupts // Note the hardware has more interrupts, but they're only useful for debugging diff --git a/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h index bacbf3d3fbc..289f0adf18b 100644 --- a/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32h2/include/hal/usb_serial_jtag_ll.h @@ -16,6 +16,7 @@ /* ----------------------------- Macros & Types ----------------------------- */ #define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask +#define USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL (1) // Define USB_SERIAL_JTAG interrupts // Note the hardware has more interrupts, but they're only useful for debugging diff --git a/components/hal/esp32p4/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32p4/include/hal/usb_serial_jtag_ll.h index 029e3635261..f6b13b9a797 100644 --- a/components/hal/esp32p4/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32p4/include/hal/usb_serial_jtag_ll.h @@ -14,17 +14,188 @@ #include "soc/usb_serial_jtag_struct.h" #include "hal/usb_serial_jtag_types.h" -// This header is temporarily disabled until USJ is supported on the P4 (IDF-7496) #if SOC_USB_SERIAL_JTAG_SUPPORTED /* ----------------------------- Macros & Types ----------------------------- */ #define USB_SERIAL_JTAG_LL_SELECT_PHY_SUPPORTED 1 // Can route to an external FSLS PHY +#define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask + +// Define USB_SERIAL_JTAG interrupts +// Note the hardware has more interrupts, but they're only useful for debugging +// the hardware. +typedef enum { + USB_SERIAL_JTAG_INTR_SOF = (1 << 1), + USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT = (1 << 2), + USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY = (1 << 3), + USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1 = (1 << 8), + USB_SERIAL_JTAG_INTR_BUS_RESET = (1 << 9), + USB_SERIAL_JTAG_INTR_EP1_ZERO_PAYLOAD = (1 << 10), +} usb_serial_jtag_ll_intr_t; + #ifdef __cplusplus extern "C" { #endif +/* ----------------------------- USJ Peripheral ----------------------------- */ + +/** + * @brief Enable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_ena_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val |= mask; +} + +/** + * @brief Disable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_disable_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val &= (~mask); +} + +/** + * @brief Get the USB_SERIAL_JTAG interrupt status. + * + * @return The USB_SERIAL_JTAG interrupt status. + */ +static inline uint32_t usb_serial_jtag_ll_get_intsts_mask(void) +{ + return USB_SERIAL_JTAG.int_st.val; +} + +/** + * @brief Get the USB_SERIAL_JTAG raw interrupt status. + * + * @return The USB_SERIAL_JTAG raw interrupt status. + */ +static inline __attribute__((always_inline)) uint32_t usb_serial_jtag_ll_get_intraw_mask(void) +{ + return USB_SERIAL_JTAG.int_raw.val; +} + +/** + * @brief Clear the USB_SERIAL_JTAG interrupt status based on the given mask. + * + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline __attribute__((always_inline)) void usb_serial_jtag_ll_clr_intsts_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_clr.val = mask; +} + +/** + * @brief Get status of enabled interrupt. + * + * @return interrupt enable value + */ +static inline uint32_t usb_serial_jtag_ll_get_intr_ena_status(void) +{ + return USB_SERIAL_JTAG.int_ena.val; +} + +/** + * @brief Read the bytes from the USB_SERIAL_JTAG rxfifo. + * + * @param buf The data buffer. + * @param rd_len The data length needs to be read. + * + * @return amount of bytes read + */ +static inline int usb_serial_jtag_ll_read_rxfifo(uint8_t *buf, uint32_t rd_len) +{ + int i; + for (i = 0; i < (int)rd_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail) break; + buf[i] = USB_SERIAL_JTAG.ep1.rdwr_byte; + } + return i; +} + +/** + * @brief Write byte to the USB_SERIAL_JTAG txfifo. Only writes bytes as long / if there + * is room in the buffer. + * + * @param buf The data buffer. + * @param wr_len The data length needs to be written. + * + * @return Amount of bytes actually written. May be less than wr_len. + */ +static inline int usb_serial_jtag_ll_write_txfifo(const uint8_t *buf, uint32_t wr_len) +{ + int i; + for (i = 0; i < (int)wr_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free) break; + USB_SERIAL_JTAG.ep1.rdwr_byte = buf[i]; + } + return i; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG rxfifo has data available. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_rxfifo_data_available(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG txfifo has room. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_txfifo_writable(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free; +} + +/** + * @brief Flushes the TX buffer, that is, make it available for the + * host to pick up. + * + * @note When fifo is full (with 64 byte), HW will flush the buffer automatically, + * if this function is called directly after, this effectively turns into a + * no-op. Because a 64-byte packet will be interpreted as a not-complete USB + * transaction, you need to transfer either more data or a zero-length packet + * for the data to actually end up at the program listening to the CDC-ACM + * serial port. To send a zero-length packet, call + * usb_serial_jtag_ll_txfifo_flush() again when + * usb_serial_jtag_ll_txfifo_writable() returns true. + * + * @return na + */ +static inline void usb_serial_jtag_ll_txfifo_flush(void) +{ + USB_SERIAL_JTAG.ep1_conf.wr_done=1; +} + +/** + * @brief Enable USJ JTAG bridge + * + * If enabled, USJ is disconnected from internal JTAG interface. JTAG interface + * is routed through GPIO matrix instead. + * + * @param enable Enable USJ JTAG bridge + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_jtag_bridge(bool enable) +{ + USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable; +} + /* ---------------------------- USB PHY Control ---------------------------- */ /** diff --git a/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h b/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h index a3b8c90733a..8a1addeb11e 100644 --- a/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h +++ b/components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h @@ -18,6 +18,7 @@ #define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask #define USB_SERIAL_JTAG_LL_EXT_PHY_SUPPORTED 1 // Can route to an external FSLS PHY +#define USB_SERIAL_JTAG_LL_PHY_DEPENDS_ON_BBPLL (1) // Define USB_SERIAL_JTAG interrupts // Note the hardware has more interrupts, but they're only useful for debugging diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 3fb643d379f..b7f97803193 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -79,6 +79,10 @@ config SOC_WIRELESS_HOST_SUPPORTED bool default y +config SOC_USB_SERIAL_JTAG_SUPPORTED + bool + default y + config SOC_TEMP_SENSOR_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/interrupts.h b/components/soc/esp32p4/include/soc/interrupts.h index 76d65315f28..78bde5055e8 100644 --- a/components/soc/esp32p4/include/soc/interrupts.h +++ b/components/soc/esp32p4/include/soc/interrupts.h @@ -38,7 +38,7 @@ typedef enum { ETS_LP_SYSREG_INTR_SOURCE, ETS_LP_HUK_INTR_SOURCE, ETS_SYS_ICM_INTR_SOURCE, - ETS_USB_DEVICE_INTR_SOURCE, + ETS_USB_SERIAL_JTAG_INTR_SOURCE, ETS_SDIO_HOST_INTR_SOURCE, ETS_DW_GDMA_INTR_SOURCE, ETS_SPI2_INTR_SOURCE, diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index c2706a0ba1b..0ac8915371d 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -39,8 +39,7 @@ #define SOC_EMAC_SUPPORTED 1 #define SOC_USB_OTG_SUPPORTED 1 #define SOC_WIRELESS_HOST_SUPPORTED 1 -// disable usb serial jtag for esp32p4, current image does not support -// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 //TODO: IDF-7496 +#define SOC_USB_SERIAL_JTAG_SUPPORTED 1 #define SOC_TEMP_SENSOR_SUPPORTED 1 #define SOC_SUPPORTS_SECURE_DL_MODE 1 #define SOC_ULP_SUPPORTED 1 diff --git a/components/soc/esp32p4/interrupts.c b/components/soc/esp32p4/interrupts.c index 8ade2b23ecb..818367e9559 100644 --- a/components/soc/esp32p4/interrupts.c +++ b/components/soc/esp32p4/interrupts.c @@ -29,7 +29,7 @@ const char *const esp_isr_names[] = { [ETS_LP_SYSREG_INTR_SOURCE] = "LP_SYSREG", [ETS_LP_HUK_INTR_SOURCE] = "LP_HUK", [ETS_SYS_ICM_INTR_SOURCE] = "SYS_ICM", - [ETS_USB_DEVICE_INTR_SOURCE] = "USB_DEVICE", + [ETS_USB_SERIAL_JTAG_INTR_SOURCE] = "USB_SERIAL_JTAG", [ETS_SDIO_HOST_INTR_SOURCE] = "SDIO_HOST", [ETS_DW_GDMA_INTR_SOURCE] = "DW_GDMA", [ETS_SPI2_INTR_SOURCE] = "SPI2", diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index d622285560c..5d3535fdbe3 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -8,7 +8,6 @@ api-guides/RF_calibration.rst api-guides/deep-sleep-stub.rst api-guides/coexist.rst api-guides/flash_psram_config.rst -api-guides/usb-serial-jtag-console.rst api-guides/wifi.rst api-guides/usb-otg-console.rst api-guides/esp-wifi-mesh.rst diff --git a/docs/en/api-guides/usb-serial-jtag-console.rst b/docs/en/api-guides/usb-serial-jtag-console.rst index 23d57436a3e..4bde079df73 100644 --- a/docs/en/api-guides/usb-serial-jtag-console.rst +++ b/docs/en/api-guides/usb-serial-jtag-console.rst @@ -19,8 +19,8 @@ Generally, ESP chips implement a serial port using UART and can be connected to Hardware Requirements ===================== -{IDF_TARGET_USB_DP_GPIO:default="Not Updated!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27"} -{IDF_TARGET_USB_DM_GPIO:default="Not Updated!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26"} +{IDF_TARGET_USB_DP_GPIO:default="Not Updated!",esp32c3="19",esp32s3="20", esp32c6="13", esp32h2="27", esp32p4="25/27"} +{IDF_TARGET_USB_DM_GPIO:default="Not Updated!",esp32c3="18",esp32s3="19", esp32c6="12", esp32h2="26", esp32p4="24/26"} Connect {IDF_TARGET_NAME} to the USB port as follows: diff --git a/docs/en/get-started/establish-serial-connection.rst b/docs/en/get-started/establish-serial-connection.rst index 51d6ab56fe6..fff30cf6649 100644 --- a/docs/en/get-started/establish-serial-connection.rst +++ b/docs/en/get-started/establish-serial-connection.rst @@ -146,16 +146,16 @@ Sometimes the USB-to-UART bridge is external. This is often used in small develo The USB on the {IDF_TARGET_NAME} uses the **{IDF_TARGET_USB_PIN_DP}** for **D+** and **{IDF_TARGET_USB_PIN_DM}** for **D-**. - .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED and not esp32s3 + .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED - .. note:: The {IDF_TARGET_NAME} supports only *USB CDC and JTAG*. + .. only:: not SOC_USB_OTG_SUPPORTED - If you are flashing for the first time, you need to get the {IDF_TARGET_NAME} into the download mode manually. To do so, press and hold the ``BOOT`` button and then press the ``RESET`` button once. After that release the ``BOOT`` button. - - .. only:: esp32s3 + .. note:: The {IDF_TARGET_NAME} supports only *USB CDC and JTAG*. If you are flashing for the first time, you need to get the {IDF_TARGET_NAME} into the download mode manually. To do so, press and hold the ``BOOT`` button and then press the ``RESET`` button once. After that release the ``BOOT`` button. + For any usage for usb serial jtag, please refer to :doc:`USB_SERIAL_JTAG_CONSOLE <../api-guides/usb-serial-jtag-console>` for more information. + .. only:: esp32s2 After flashing the binaries, a manual reset is needed. diff --git a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md index 1b053da468f..ce33f425ea6 100644 --- a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md +++ b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # USB SERIAL JTAG Echo Example From b400a8cd727c9deb0b82152e57f1b5ec8ee2648b Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 6 May 2024 21:50:11 +0200 Subject: [PATCH 061/548] change(gdbinit): set remote timeout for the gdb connection --- tools/idf_py_actions/debug_ext.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/idf_py_actions/debug_ext.py b/tools/idf_py_actions/debug_ext.py index dd4cacc1b41..ed1eed2ae50 100644 --- a/tools/idf_py_actions/debug_ext.py +++ b/tools/idf_py_actions/debug_ext.py @@ -11,16 +11,26 @@ import time from textwrap import indent from threading import Thread -from typing import Any, Dict, List, Optional, Union +from typing import Any +from typing import Dict +from typing import List +from typing import Optional +from typing import Union from click import INT from click.core import Context from esp_coredump import CoreDump -from idf_py_actions.constants import OPENOCD_TAGET_CONFIG, OPENOCD_TAGET_CONFIG_DEFAULT +from idf_py_actions.constants import OPENOCD_TAGET_CONFIG +from idf_py_actions.constants import OPENOCD_TAGET_CONFIG_DEFAULT from idf_py_actions.errors import FatalError -from idf_py_actions.serial_ext import BAUD_RATE, PORT -from idf_py_actions.tools import (PropertyDict, ensure_build_directory, generate_hints, get_default_serial_port, - get_sdkconfig_value, yellow_print) +from idf_py_actions.serial_ext import BAUD_RATE +from idf_py_actions.serial_ext import PORT +from idf_py_actions.tools import ensure_build_directory +from idf_py_actions.tools import generate_hints +from idf_py_actions.tools import get_default_serial_port +from idf_py_actions.tools import get_sdkconfig_value +from idf_py_actions.tools import PropertyDict +from idf_py_actions.tools import yellow_print PYTHON = sys.executable ESP_ROM_INFO_FILE = 'roms.json' @@ -51,6 +61,7 @@ ''' GDBINIT_CONNECT = ''' # Connect to the default openocd-esp port and break on app_main() +set remotetimeout 10 target remote :3333 monitor reset halt maintenance flush register-cache From 199dc389cc640eebf05beee39a2a2dc6b5c82773 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Mon, 13 May 2024 10:13:54 +0200 Subject: [PATCH 062/548] fix(esp-tls): Fix compilation for linux target on macos This commit fixes compilation errors for the esp-tls component for the linux target on a MacOS system. --- components/esp-tls/esp_tls_platform_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp-tls/esp_tls_platform_port.c b/components/esp-tls/esp_tls_platform_port.c index 3067a0976ea..410f14cc56e 100644 --- a/components/esp-tls/esp_tls_platform_port.c +++ b/components/esp-tls/esp_tls_platform_port.c @@ -5,7 +5,7 @@ */ #include "sdkconfig.h" - +#include #if CONFIG_IDF_TARGET_LINUX #include #include From bfa95cdd75dc2ca26dd56fc9c388a183cb2ebac1 Mon Sep 17 00:00:00 2001 From: gongyantao Date: Tue, 14 May 2024 09:59:20 +0800 Subject: [PATCH 063/548] fix(bt/ble): fix some issues in bluetooth controller 1: fix assert 1024 issue when bt tx and wifi coexist on esp32 2: fix ble scan backoff 3: parse out the correct packet types from host parameters for hci command hci_enhanced_setup_synchronous_connection --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 43ecd22ec6b..45e32805359 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 43ecd22ec6b5b484709693ae8e86478a7f130f17 +Subproject commit 45e328053591081abcd387ec2eecc8add43f4b15 From d8bc05c5d005a1393166e3d3cbb5874782ac7e63 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Tue, 2 Apr 2024 09:18:18 +0800 Subject: [PATCH 064/548] fix(bt/controller): Parse out the correct packet types from Host parameters - For HCI command HCI_Enhanced_Setup_Synchronous_Connection --- components/esp_rom/esp32/ld/esp32.rom.ld | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/esp_rom/esp32/ld/esp32.rom.ld b/components/esp_rom/esp32/ld/esp32.rom.ld index 814eb8219bd..b47c3140b89 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.ld @@ -1474,7 +1474,7 @@ PROVIDE ( uart_tx_switch = 0x40009028 ); /* These functions are part of the ROM GPIO driver. We do not use them; the provided esp-idf functions -replace them and this way we can re-use the fixed RAM addresses these routines need. +replace them and this way we can reuse the fixed RAM addresses these routines need. */ /* <-- So you don't read over it: This comment disables the next lines. PROVIDE ( gpio_init = 0x40009c20 ); @@ -1623,6 +1623,7 @@ PROVIDE ( ld_acl_sniff_trans_sched = 0x40033734 ); PROVIDE ( lc_pwr_decr_ind_handler = 0x4002859c ); PROVIDE ( lc_pwr_incr_ind_handler = 0x400284a8 ); PROVIDE ( lc_pwr_max_ind_handler = 0x40028690 ); +PROVIDE ( lc_setup_sync_param_check = 0x4002354c ); PROVIDE ( lm_sync_conf = 0x3ffb8348 ); PROVIDE ( lm_nb_sync_active = 0x3ffb8346 ); From 24e5e3aef11517fb1b6600b418ba47dcaf4bceb7 Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Wed, 17 Apr 2024 11:21:34 +0530 Subject: [PATCH 065/548] feat: Enable app_update test app for ESP32P4 --- components/app_update/test_apps/.build-test-rules.yml | 4 ++-- components/app_update/test_apps/README.md | 4 ++-- components/app_update/test_apps/pytest_app_update_ut.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/app_update/test_apps/.build-test-rules.yml b/components/app_update/test_apps/.build-test-rules.yml index 37751ed08bf..8c365fcc5ee 100644 --- a/components/app_update/test_apps/.build-test-rules.yml +++ b/components/app_update/test_apps/.build-test-rules.yml @@ -2,6 +2,6 @@ components/app_update/test_apps: disable: - - if: IDF_TARGET in ["esp32c6", "esp32h2", "esp32p4", "esp32c5"] + - if: IDF_TARGET in ["esp32c6", "esp32h2", "esp32c5"] temporary: true - reason: target esp32c6, esp32h2, esp32p4, esp32c5 is not supported yet # TODO: IDF-8068, [ESP32C5] IDF-8638 + reason: target esp32c6, esp32h2 esp32c5 is not supported yet # TODO: [ESP32C5] IDF-8638 diff --git a/components/app_update/test_apps/README.md b/components/app_update/test_apps/README.md index b5be4985c57..ace56d6d199 100644 --- a/components/app_update/test_apps/README.md +++ b/components/app_update/test_apps/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/app_update/test_apps/pytest_app_update_ut.py b/components/app_update/test_apps/pytest_app_update_ut.py index 9ff51bb993b..594bdbf2f33 100644 --- a/components/app_update/test_apps/pytest_app_update_ut.py +++ b/components/app_update/test_apps/pytest_app_update_ut.py @@ -19,7 +19,7 @@ def run_multiple_stages(dut: Dut, test_case_num: int, stages: int) -> None: @pytest.mark.supported_targets -@pytest.mark.temp_skip_ci(targets=['esp32c6', 'esp32h2', 'esp32p4'], reason='c6/h2/p4 support TBD') # TODO: IDF-8959 +@pytest.mark.temp_skip_ci(targets=['esp32c6', 'esp32h2'], reason='c6/h2 support TBD') @pytest.mark.generic def test_app_update(dut: Dut) -> None: extra_data = dut.parse_test_menu() From 1a1a7086992746081e9ccd220f2dfc1811fc0a62 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 9 May 2024 17:45:01 +0800 Subject: [PATCH 066/548] fix(brownout): fixed brownout isr crashing if cache disabled If a brownout ISR was triggered while cache was disabled the system would panic. This was due to a print accessing a string stored in flash --- components/esp_system/port/brownout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_system/port/brownout.c b/components/esp_system/port/brownout.c index ef1a5ed67b5..271384ac64d 100644 --- a/components/esp_system/port/brownout.c +++ b/components/esp_system/port/brownout.c @@ -28,7 +28,7 @@ #define BROWNOUT_DET_LVL 0 #endif -static __attribute__((unused)) DRAM_ATTR const char *TAG = "BOD"; +static __attribute__((unused)) DRAM_ATTR const char TAG[] = "BOD"; #if CONFIG_ESP_SYSTEM_BROWNOUT_INTR IRAM_ATTR static void rtc_brownout_isr_handler(void *arg) From f324e75c64d1906a3e7aa348b4ebc8ad5a5a7b75 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 14 May 2024 10:56:22 +0800 Subject: [PATCH 067/548] fix(interrupt): fixed interrupt thresholds not working on C5 --- .../include/esp_private/interrupt_clic.h | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/components/riscv/include/esp_private/interrupt_clic.h b/components/riscv/include/esp_private/interrupt_clic.h index 8628e4761ad..4089ef8abc8 100644 --- a/components/riscv/include/esp_private/interrupt_clic.h +++ b/components/riscv/include/esp_private/interrupt_clic.h @@ -46,6 +46,27 @@ extern "C" { #define MTVT_CSR 0x307 +#if CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION + +/** + * The ESP32-P4 and the beta version of the ESP32-C5 implement a non-standard version of the CLIC: + * - The interrupt threshold is configured via a memory-mapped register instead of a CSR + * - The mintstatus CSR is at 0x346 instead of 0xFB1 as per the official specification + */ +#define INTTHRESH_STANDARD 0 +#define MINTSTATUS_CSR 0x346 + +#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 + +/* The ESP32-C5 (MP) and C61 use the standard CLIC specification, for example, it defines the mintthresh CSR */ +#define INTTHRESH_STANDARD 1 +#define MINTSTATUS_CSR 0xFB1 +#define MINTTHRESH_CSR 0x347 + +#else + #error "Check the implementation of the CLIC on this target." +#endif + /** * @brief Convert a priority level from 8-bit to NLBITS and NLBITS to 8-bit * @@ -59,11 +80,20 @@ extern "C" { #define NLBITS_TO_BYTE(level) (((level) << NLBITS_SHIFT) | ((1 << NLBITS_SHIFT) - 1)) +#if INTTHRESH_STANDARD +/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ +#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel)) + +/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ +#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel))) +#else +/* For the non-standard intthresh implementation the threshold is stored in the upper 8 bits of CLIC_CPU_INT_THRESH reg */ /* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ #define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel) << CLIC_CPU_INT_THRESH_S) /* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ #define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel >> CLIC_CPU_INT_THRESH_S) & CLIC_CPU_INT_THRESH_V)) +#endif //INTTHRESH_STANDARD /* Helper macro to set interrupt level RVHAL_EXCM_LEVEL. Used during critical sections */ #define RVHAL_EXCM_LEVEL_CLIC (CLIC_INT_THRESH(RVHAL_EXCM_LEVEL - 1)) @@ -72,26 +102,7 @@ extern "C" { #define RVHAL_INTR_ENABLE_THRESH_CLIC (CLIC_INT_THRESH(RVHAL_INTR_ENABLE_THRESH)) -#if CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - -/** - * The ESP32-P4 and the beta version of the ESP32-C5 implement a non-standard version of the CLIC: - * - The interrupt threshold is configured via a memory-mapped register instead of a CSR - * - The mintstatus CSR is at 0x346 instead of 0xFB1 as per the official specification - */ -#define INTTHRESH_STANDARD 0 -#define MINTSTATUS_CSR 0x346 - -#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 - -/* The ESP32-C5 (MP) and C61 use the standard CLIC specification, for example, it defines the mintthresh CSR */ -#define INTTHRESH_STANDARD 1 -#define MINTSTATUS_CSR 0xFB1 -#define MINTTHRESH_CSR 0x347 -#else - #error "Check the implementation of the CLIC on this target." -#endif FORCE_INLINE_ATTR void assert_valid_rv_int_num(int rv_int_num) From 2f6fb59b6b2acd7d923f1598055e843fc4dd8295 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Fri, 10 May 2024 09:48:14 +0530 Subject: [PATCH 068/548] docs(nimble): Added chip information in ble_enc_adv README file --- components/bt/host/nimble/Kconfig.in | 1 - examples/bluetooth/.build-test-rules.yml | 13 ++++--------- .../ble_enc_adv_data/enc_adv_data_cent/README.md | 4 ++-- .../ble_enc_adv_data/enc_adv_data_prph/README.md | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index 616dd20fc15..d02293a87a3 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -906,7 +906,6 @@ config BT_NIMBLE_OPTIMIZE_MULTI_CONN config BT_NIMBLE_ENC_ADV_DATA bool "Encrypted Advertising Data" - depends on SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV help This option is used to enable encrypted advertising data. diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index ab792435afd..16d87cc996b 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -131,17 +131,12 @@ examples/bluetooth/hci/controller_hci_uart_esp32c3_and_esp32s3: # config BT_NIMBLE_ENABLED does not depends on any soc cap -examples/bluetooth/nimble: - <<: *bt_default_depends - disable: - - if: SOC_BLE_SUPPORTED != 1 - depends_filepatterns: - - examples/bluetooth/nimble/common/**/* - examples/bluetooth/nimble/ble_enc_adv_data: <<: *bt_default_depends - disable: - - if: SOC_ESP_NIMBLE_CONTROLLER != 1 + enable: + - if: SOC_BLE_SUPPORTED == 1 and IDF_TARGET != "esp32" + temporary: true + reason: BLE5.0 not supported on esp32 depends_filepatterns: - examples/bluetooth/nimble/common/**/* diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md index 294852040c3..09290a2409c 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_cent/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C2 | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # BLE Encrypted Advertising Data Central Example diff --git a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md index 1402564ca28..ad4acd83fd9 100644 --- a/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md +++ b/examples/bluetooth/nimble/ble_enc_adv_data/enc_adv_data_prph/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C2 | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | -------- | # BLE Encrypted Advertising Data Peripheral Example From 84724677214ebb38d7dcce25f00c235b3b339681 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 15 May 2024 14:32:15 +0800 Subject: [PATCH 069/548] fix(isp): updated to only support input data type as raw8 --- components/esp_driver_isp/src/isp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_driver_isp/src/isp.c b/components/esp_driver_isp/src/isp.c index c0d8a2699d0..e4aacb90ab2 100644 --- a/components/esp_driver_isp/src/isp.c +++ b/components/esp_driver_isp/src/isp.c @@ -88,6 +88,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_CSI, ESP_ERR_NOT_SUPPORTED, TAG, "only support CSI as input source at this moment"); + ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == ISP_COLOR_RAW8, ESP_ERR_NOT_SUPPORTED, TAG, "input data type not supported"); isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(proc, ESP_ERR_NO_MEM, TAG, "no mem"); From 173bb82f45fa1ab45bfb9d1401e1d9da5540146b Mon Sep 17 00:00:00 2001 From: wangning Date: Sat, 11 May 2024 18:09:37 +0800 Subject: [PATCH 070/548] docs(esp32c3): Added missing USB functions to esp32-c3 devkit user guides --- .../_static/esp32-c3-devkitc-02-v1-pinout.png | Bin 279210 -> 279856 bytes .../esp32c3/user-guide-devkitc-02.rst | 9 +++------ .../esp32c3/user-guide-devkitc-02.rst | 8 +++----- .../esp32c3/user-guide-devkitm-1.rst | 4 ++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/_static/esp32-c3-devkitc-02-v1-pinout.png b/docs/_static/esp32-c3-devkitc-02-v1-pinout.png index ca1a40782f6dfcdd397022df552441187e6ea33d..19386275efe984acbf000b9339dea490c2e5ab30 100644 GIT binary patch delta 261653 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

@`7E$H2(5~=L$!?aM@p_|XT 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 z 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 z zMQ6B*)r4&}i7z2SCX<@#rnFI(FS^Xil_wV(2bS9}Qq%-EmPYi!&3NR)Uwj9lZ-v=g zQL6X?1yYCv(Q#8pPZn?B){e#Vz8MV**%)yocmf?yO;3S+`r1TmQ)#`|hSitG|Bc>< zH;|WY=V9yXX=?@vALgYG@wZN0q@XIJGp1?fJ~g+F^%fx-QGV`rk33k9^2mx5(~wQc zylKRsS0o*s{VN^NbYQ`$_cr1y+}uw_1ZCH zU`4uqjT!SC8AV4`WN~WVqXY(#l2Lc>Ga>XXr}1>xj*wLvc0i9o-DGC0h$stS^XmCy zyqO3ywfp$>F6$lr@(%?rVl^-FfVzkn*Sy~{x|D7D4y|I`q69+b)=|?sKrBIUe!2XV z0|}%`NMyvZ(}Z{mgX&{X;p^XJ_E@s6Qn20dwG^WB)+jyI&uzv&KB&bU&km7wJ4c3j z#kM6lj}bApHRv6%4=`?X@vSg_lV-QS5sa3kG?w+|s;Mee9>uHSb*O1M7!F-Imau&K zddgsi1*oZgQO&1ZSg8@m1@Ja!YE&N2HFt{sD1UI08rT{P!E$yXF#aB^*<%zuu6&|K zjk8aM>bn4$*rZZ}Q%697o6<#lz5L$SSy*hgxc^dxPz7^(fat-Pcq%YV#shKO@4G37 zl;9=lE3>e=>Tncua8zRE`LYzG3o;-o48s_2u%+|qp-)hJu;sU%fhsiQfK2HH%1oH` z{2KWvg@(k;q%283zwF<`5c%YR0>(G&Go^O+!1xDOok&C5ekT)Kno7;o-vaNHKb6p1 zWVyV){6UNl#U6foaPZ}gd*xgB+|JQ3$uJBr>1m&(&B`1_81^*p4^f`K(Blp*n!j(4D-?bFXUSPaogx8}zk^Wpe+tS?sp^BB~w%h%|z=oR;JoO;_Ym77_nSOpfbA z!AuS55t<>?kK}Rub)PNMqd$w9|5|4fPu?&%RI;o@<7E)vJWxVF^jbWBeZJ00K-eQE z(qnV_fbpJZw%PovWJV-$sX7B10}ZV2>#8yabmULH$&T!N6FPmWcOSGyn#ND<5>78| zXKnr{13jk;B?LFxXNWzg!CLpCubbTAi8XmtU8j9-&WfMFTM;}x-92-kwsC-vX1Qmo7>Yv#Paku_GW?CkKmV7r zCGkli-t?+iRmUT%ya~0zX-4>s^|ao&KIQcDo_d+2p78h@^V@PA zv$M%yndbbH+utEunc;ULCwl7sH1!s3G*!so9LRe9}L6a`( z!k=E<3_)wRw&nos>_D^(1fcFJT z@qX3G5o_9Ufm(PQd-6xziyuY|S9F+Hi#WSD5Y9aICa03~minBCrwDsA-MYF*T4$Xg zlJ0dOSU2MPSK9q*QO&od{+eIa&k4^eadJfd1^77z^8YfD)8M%V;?Di!W4@0+8&(iz zl!PxD-iJz7Uf(a(|1NtE`e`jvmT%4S7JJ&(&ex9FE#p&uvfN*D#FdNv*`O`j;bol3 z?f-&g@nR%&Xh%z)^&6rdgPZTcO?%f7VPUpJ0H1`jL&{Una4mfY zZzw2_*CZn_xwRYWYFi#8Tw!=L8dkOT3zAIJ^3lz@OtUn=n{7U@RH|DC6@r{oRQs>b4#xXEWkR19w>^{GeCmSNY>_a5tlX)!033(Pxo7+5Kk z+ee=L+wGD^wglI&0Z)R}kI0Jmzr%Q#@3=vv4r?p%?f5odbKuS&R+bMCAKpoY)Y_aF zLkN`tScza>aXjcUwrXd_^(@+n)a>FfwNN?foTQ82ux4ZkspjTc(*Za^0it5%@{Z$2 z92^|BMNv+d&`rnt==4uyz5SK7$0jo1Kjc4kE!g&vF5LlzmFdD$`GEq9{$Yo*V$)is zvokOx5M~o$2pMG<5H68CD3{eDoOhb`wMtH&|D`*L0Wk@X!s?B<+8$%@L~)`cl#;5q zs*Yq48mP!H>_QuctI-^(b4kSErC{Cb$ufNW;F*G#?C6s9hzwgP?D^5P zngGg65>Uku`XRu`v+I6DeCFwIG$q*xyAcARa>Oo<~QQ6%D9^PM= zI3w2@j}2(&RZJtdA8)TVessNRjv{%F=UU}|!La~CQb7o-<=^ZX_b-FZ3;16rCqs~Z zOwD3QQz^$qBI}}oTGBkJxpi!IpjH+DVuWY{4$%8o+!}(?{vIfqhI?kR_prxSJp1c; z@vf}kKg^upV!Uj_id(x#;wXkEyc%66z=idGqp=ZZQThU1CGMsk>+Ft)0RlO|CV?1A zLd%pe!MxUYJIVVsnxV=YfB4xr|HF+8IES??7isOLQv|Z!*f)~>tkgUL#(}?LkB0X4 zur@ESz1e&NS=En!<3rz=722H&44Jf_N~bNtK=Fi9uFBmVLWM!u@pM*QhV~4a3dz zK~?|hj83$#Y~=AXnGs4PAs`a+l>mE?cfZ15bt%=|CCj5DV_@dIZl$YMKYF(;g+&P0 zHrUte4&jLKA`ZL@L)wi)3m}@{4CvNp9%XjqP`Y&gf?@)sfo_xO$^*&sN0B<-V-iR9 z$#}_zt=gC4me+wUZdwuZ!Ewx+_sX2*>!=HCD+*924pV0CHP-%j(r72H-?X;%5y8w z_j1%=zIWXEyaXISs?wH3Bz-$wp<~tFPnVmw|G;18?oLE?>e_n2dYHn~q82$=o~hk> zF&#ifKW|k}6e0UW?>hr?0pIY7^zIv#M-X4Oz1j42hE6(%4{@VZ@m8t@uq`ml)&ZS~ zmuky2ePvST`-h@2UH7q^_*>{sd+1|YmWMKhPZg>9)H>k#RDBA+G-Hc)Z1IdRl2#tk zVv_}RGkj*8GzBBi$=!XKMyG9dI!ra`1Dt z7UOBA$SZ|9KAVY0RvaF3tDNx)yzc>NRe(e}$V!`5n*8QC{m4{wYp$ zH)>pa1Xl#_QQk_VIkYVxu9?@dkuotr-c5`;xV`^*Sc8ftY=+`ZvEsL_hpcz1fUUYC z9>H?v(|$HcUv?gBq)LOPF&0ROR?wq z*NCXiGCn#(T4i!pA@unS=DSbZz#l-{7_Xc#$tkByc>R`#%-?Bsa6%mFw-|^k|3e zJJcHHOjyaA`lLN+49vv6IjrS-v#GC4i<51iZZ&E8_#7*lg-YK1{NwV9vn+RdZ()Qg z$2`_+I$LI_b>UC~rH3zYZ?6N9H5P;CbCZTxQHweP= zJ1%!Zfl$O>Pfz1?Jip!F;Us$)NYs}Hd_~~bRybmp5N(|@BZiyw@1;Wg>n(aX;Y=#Q{C??xgONQoj+=j{|U{lxN!PkN-_Ssg{S zcqB-IXY!5@ky@>$s#Ck>xk%5^Wk``AwMb;Ik+D;A1ZL$i)_RfB?fXVWyY=<9w*BsQ zX{GN6fr?%91%O3K*C8--I$@<%TxaZcVEg`YNYA#xztW{@{D0@y(^{lR?(`cI#F9sG z-6@7w?jmq@h*`;tOG=D20HS0~OP)iSpAhfZ=L3_^bfgv+h$&Qt#ccI3X5ko%0i7 zZ4ul)^ry=%d%L(Z%3=GkOW%Pyy#}sh8X*?C{?osu;%GsY*X0IF2)Z|@P6H+BBN(Ok zYMnFp=`jR+t{Mqug`7<~AMeh_bAwavMT?NGc8smpoO}9%CEr633Qxs`jV~Is3bP(p8+y zGp0LsAqqWp@`z*Bm-cz*8a06Vuc7d^$LjgN-bMs_5{Nc*)^C3!G2U8xx?UaZ#?4y_ zI6cGhzw>aUQG!C>j0p}3GPO470n3^I9=m1Add;Zu=$^guBc2y}5+urPX?*3>i{$!t z8*D~`xTwIu)2HjY%uHxAX5>7IKX~7Qm{}Hozukiq{V7-`{YHpqqf-Me0%}8)ir6H3 z(fU{E_rJul{p*@@w6H`)i!G9%Sqv6doWw&!{IJ8q6Zt-W*ouFVm|WoWwbvb>{^Q-I z@bX^LSGcafq~o5cUNLNO@17`#j_t$vN}O+oujfC%X(X$zX4VariClTq4OX<9WZX{R*QEFsfGzPBktu_*fZx5g zYt}JD{9&!L`luaE>7GCW1J4NFMmf$|xvbma~! zaWM=ZaWNOGpf1NN4s#`p+||Jo8-nfOI@iZNHk-xW!a%zuIp)iG>jx~%d7lWvi<34Spoir9m9>j|yt^MK+B~Nry}T^w5DX!E z2wy?-tbJOHDroUwS&O9`(y}yZgjCMgrHkEFM&x;;ip=;``k5zbH2A4g6a8m&;jClN*t zot{4{N&vnmOiZ_URKc>n^DV0p%|)pKUe}rCuQbvPj}(2A8NN51_9WklgIKvx4L==7 zN5x(;;F&o$%t)_H)8_R1+nCdvQ}5!*;{ywnJ`ocFykKZl>s zP)?}BU&fwlpUW#&x!T~Ux4cEQ5Jn|6Wp`lS@EIG|m>$XB)2=mwrQ);kk0ODlvva4t z-VJ%KRGZfbO7uEodQM1QOVN25$gfYY4(=rdj1%UJn>gkHi`xsiLy}*T%|{l z{cwrz67HZP1OwM^uhuYYw}sv(Hr{_r*Ah`(ec&*xagjo7kP@n|Dftv%etUx%ra%a^ znO2Un8lrow36r9uNbvZdb1k(=Bkac?8e=raRAhYQFDlRT9)p19pkuQApBN5@FDuGs z_2(ZPsl}3!Un6~8?g!BJVd4E*7JJd8)|a;{P3oLotl|$hm+(cYEQA7J1fI82cVK16Fnw9=1g34F?LM*$T0N+7 zK6`TCQT&dVDjwClZO+cKa`LI;!KRTnR?!+FL8L7muAsEuc~J3-qQ;TQ;0t2Nb(F6{TfOhcmpX))n@9*X)JQxZk{08C{ng4tx-E4O3!`=_CW`X)) zgN|IP&F=S0bB<*XkNMZSr%N$!kqNh@5D(j0qWBlWdi-Egp{|JH)ea)h@^=`j92LY<Xb!X!;A(}U&Ky9~zq9sy|NcD} z_8V+<6{p7hVgr*^0y*Wi`w=CXIWd9nj8NX*36dp^y5EdheEnFDAB%FNsydGCWD3;M zKT$F=q9ts1YIJ&Yo7EzKK2pU>Azu+ALzo{Gn3nc|2~J#Rf_!+MbIqwN0GOM+ChyP~?K z$Um217j@FdyC$^HJ+Ivp(}_<-r9}V{MI0G9<5pQdFi3AukAM~EK1}Uuv9jgOt&bL| z>QpzdK@LM{X(ZTgViQ0tY5Q)tHBV)>8M!(1{OOq5X%dO^#L-RWiXN8?BbG?)R_7Yv zA`z55gYV?%G{laotVMyTIoH+J^zmVr)q|S|5d5B+pyu3c7*W8{Vim`r;;ax7D5LE9d zgNt;s5)#MS zmg~7$o%)gA7h?T7<*Ubw>o=0^&katxIkHQ+6r%s72^!C0c-g@PyiFKuqsBl3QBsey z2-n9>umX-m0j9++!3V}a`QGHP`hNW)r|52bEGLPC8Z5x_J^9aaSUjvv6IsF^K>2wR zYPMzhu+k3&36+;D$9*RL{uQY(^pD>NoS(c(z>=u1-R1hj9Ta9Q*1XvdiA#rtR7>=B zFf>?R;B`cVfRz=!uCZHMz6+*cG!F?^eXA{rg+*iHWn$-O!ml*>OiH%J)X89ZwIz+n zt0U<{41O3ER*ERtkpKanGq!+x!MgJoZQ94R5&MOu{WH&XnrUqbTW2G-=_PaGsjkzv zWh_;N(8gS^;&;v}*=m0CNvRgQNrq#j9zO3inkKBQvtFfNkMlC-U%gK!81b5p>xjgx zJCwUWB_;d{3c1Kk^a}nL%zFQCj_G_R%BLwG^%O1E^U>4-%-3!duUV815xUUd5r{h5 zBJLVdIA?o82khYmO&Wio<_&?Wb;99gsMK5M9-s!R?JW8M-i4SEghurPVcBm~r$3z%%d?Rvmudm7e0hirNL>&Rv>AKNI1)C%5a zSEmw3Y1yn`U{AA7CNX96ez+V}XR4lWhJ;AB#!b2`S3D&&Z{5ri<}!255<$wp(TJM` zk9YfL+dhw8-|8Oo&wA+6DVmT{Q>FzsEUfNu^@s~PL6ZGg>4<+T@x$O8q|=Px3c-G( z(g5sSLSgm_L&{EAZ&ruK)=3X|(7(2pK2iC37E>l1-amtAL6$G&j zn+JwOPQ3=;NyM6rKaXTtXwnYYjIwmv1t8tIlIsGq9|lJra20pwH=e-lTvz1zzE`!7c6Gb6OKy^%r9Lwr3?8#7TfS1R`Z_?tPU-IbV~n#h~zbar+nqqzT6sBJckem z|0=VQd$gjR`Xv||m;E0|?dPAXN`ZSuFgY84rzKX~;^Czrec+gUKzy&u&$O122DxbZ zB>C>{uug<=C07I3b{VV!8#~tsj=i0&++|+8C+kd(9<~83(+;q|u44&b3X3{pYGXf* z_nq2D?;GTBA0UWk#Di5|jp|a1a(jFCk@#7-1;Dr5Zf*_P?m1=oj=s`$`@;BGTi#(> zkumnlcgizqVUoh>ba^=37Vp+rT4>Ejbcc9I;}-Xo2@o6RbCOGqJipApW6V$!`+#;& zR%K+MK^)R>=xHqTGd9ego)y{{(Fn7z8^P79vtgZ_g@1oFMTWw zP90HuIx3-cKVciQcz~;mg@v-24WOUOZCCC=9SnuhmLqp{j}xYO7qkwa(7Y(yCVV9zRl}1_zmld>gYVj@v3>F$+TX$#=B5Vct0i zE{n^te%e{DvT`~r5@@;QP1O5Jq0qX){j1dV286(GgTkH=(l1Wh?uX^JZO7uI>=wXm z(|KdaG=k>%p(Vs}?;2XJaZy}xm%MeNtFHbzI0O`UYt%L}?b{x?`37P;Ej1UE@Jn1l z1i#O_WXF0@6v;fWD!(N)h{?Ih{q5DUg#CAD2u^Y$d+p--6~fKSx_MmdLC0A^p#+PA zeo#n8fuBB;hL`ebK^ODZL|}df_{!VA>64`labwj42v{J3wM7Vrd`s|~H~bzCjML%~ zN7Y%SMDz(v{pa4ZWbPF$23ClryJbXo!WG4u-zn%684JpI7pLBIuJDT=6!BUn(cEqb zdrQH ze2zuP>^urre*0IgJlp*#oXKa=SNjt3-&6FoKjeQ=tB1GX*kHgFmDd@rK>0?qJWWozo9&23xcavwB6#RsUv;=EXur?QR9H1(9c;G z4<3~&9;scOxhb*t;#ChA`xi(;mZJI<-~aKgS*Sd^;PTkoejrgi^U%=ssliron0ydZdmxH*gBR)HND*OHC`dF?odD#&zXR_P zX@ZMlXZ^G6w^#ci=vV%V2K4LRo9p_HvuqF_2SDe-l)VGvfs*yzb|5Qm-`y@=bVuVT zuOTDYN+Y}n)7D)gX1r;ZD6oh(VpS)mn0#1t)9}Rze8dLbLYhk)>j{Xg9-lkE?kv8E z=~N&Vjk}ju?AJ)w@6CT~Qk6%dxpJwwbqzj0Pcr+x5sb?Cv>YYrpJD;yfR1H~7AOA} zSS=d*eQwVB}`(A)2h{;PLFB1Qep+{^B6%!xPrHL6DtMf zK!Ib`;^VB&+0+|$e6Qb0QkI6m4Nua1^+kAbxF7eQPG0vht9$U^bh z|1myCgl}bUWxrq>BS;u4-X(;NB7WA;6Z_j>*j9}e{%G@(wGWRFaB7E|`8}C4t|6H} z3s=tGt|0rsd0Z%ovAV;l$TbeCryNJJRgB6ZYwFHu1un=6-?N}v%IS|b4cp|peiV(I z6}MRQN+F#RZu&ugQOWW@KZRHscwKG+}SQ#7dEO`E&l1zzd* z(p^(m54HcYVt` z-#th?kKH0&_H6qZ-7)arVKn~`!CG5 zq{X(5*Cqz>o`p^893guxW6{LZksM$>T{z{coi%T=GpVX#Pf9U+ zay#Rekky50XASMS2iL4+26oAEMgKQFD0z&HoswmEcQe9jX@u#PH+*-)8HqBKn|}L~ zmiX1-!x8(l6)=Nt`FtJ1k0y8>&yw*pT26Z7CL~P%PTbd{Ji^Lq_Y*HF?=ornj~5ZW zd>#kTwjKQKOYD#W|3c~aXBhg2tnAm=S#Ytww$2j32$nXQw$GY-?f=|TQ%{6qcSveLW8 z2Ze891^(Vn!w0$Abbg*%GKd0dB@VvLW&_MR9llV=Ew_e`ZKR)j2L>wVa}Ba2RQ(OV zPqPz8M?Y>Dc&pfO4JCdUOMAz2T)nQhj-_+JxaV6=nQhObI7^X2lw7VSQ&(Bgdh zE89CXT==_$cbLA^`R;CYL;mz27_>hKdq>rpfA!*b=I*{}N|7q=rA4GvE%C9JAI(YW zp1r2pFUH@uolfDS=NSTx3^;tmXf-(7h8`0O7aGrwM;`sypyZ* zo}td*!3*qH{ogRthIaHj{>~!+xV6DF2q+N=YaM$f+X}r8O~xfdVg(3Z%fE*;8(aSD z%4@4ihPCSCveC#7T>Vu(SPo21Q73#zv}PjbU#Xjt&~Qtp*HG33BE6HiU~RV{Xx=UI z#KnOyL?VEr4Ev|32Z(YI?&>sl)uU7OsQ-rG z2t_=MVp!4)zi&A?5C4$SfQN+_rVAS+?Dg1F&OinS_x5HhPi8tQys<|9*on2Ik9u%3 zLbj>ZuI8z0OlOW*4i})zv4l)P(}}0t!8@M{{UP}i+q-cPqP0l!YRK@+){e4wpv#<3 zjzZKdrrm37$G2}5&PYi~Vz~M_tCU)`%2*JzE9P`LBWrY=oFQW)D7icag%7=IDWBXp z-_(6G^Eh%qBV^)JJtwcNO3%b!?Wm;ZQ`fWaLW5CYc*y*XCjo3EHHkW2k*ZM9$K6`h z8)sJQmQ+%J7JfqWBTKv2XI>QFuUn88p!cYM5$)h7GwtG06Wi1NCOT96)mpH`LiZwN z%i&8V0KQBFBsR3ZRd(1)uM22GAEejTwdj$VXS5JWyiS$lLvKHu zHQxz!|B6`ywvw%KLCu1?y1En4sY0`N^=E#}#Du)M#^Lm0zFMv8rAdgCRGpivci!}^ zub~o1A}}#AFhh>zIX3q6^pr^DiUrB@AfnmY$;k-hI1i@r&adjFN}4^k$nG($z>^>= zXIF=noO+ATTnC0hlWX-dF{s{E;swPkW54WaKtAR-ub1^Agy=t}Y6O$6F!LLpgOiiV zX!u=4Wo2MU2pM}V8-)RqObbYJm^`v!XJ>D@-AYD&C%Nekk~Y9yMeFw|=vL=dS;_oj zaYiAP0wG~xx$p@st6oAqXwimwac2?=z$ZmQ|MxXEDtO$Ew7a{zFTIFrfG`Msa&2wR zCvUq;;V(G@LpaFUu)8@~MP@Su1v^Z}vynhc))Kl~C~J^Bi;VN*MRCu!jz{!AgLffy zoFo>Lj@IWVaZqCU^x{Gv43_P0uF)%}02@Z2 z;+-xF{^|L77I+DNy1QS7G=RFluTKZ0?0_~!XW&(y{lStREmmQcAeXc7C;xYI^h_17 zao|VV{Ctbt?N}btCLm4nt7hGXL$VOgk>Kps#gMXo+my>T$CgTT-4q)LWn6L15aPkL z5X>R|NOsKv^|Rht{?gT;&F6i4SFnQ)L%HgD0u{Pg!ET#G+uL4wG2Yzjr$G!4?tb=V z_s$<^e7#_2D`eK3oR&6Z8F+54>BJP0@0_bP1E=l=$o=V>olOMc>^0`Ivhz9`-^B_9 zwBL`ShVZlpy#Wn6zcy|anAhk@7b@tI&-H@oqL-Qo=F&g+AjbP zF_IeQ>C>qEp<;J+J4O@Z=14D1gZw-x?9SlsyZ!6?5?$N|`p?2|KZcc4paJwNK9a@3wxmU3}^)>_MyDdnmlhh%p6_ z2dQm#U`O%3x7~{su&VAm_k2<3wWR+Ed$YN^rOV$F9dAWKHJLd0?sifsAUL(JPl)i? z-M#sMf@$byP>ekm)!X6MNz0BlGGar2xaLdA`7*E-#C;~9a$#zza)ixF(53_={!MmP zv8PurTTUrNE_`k6co>?J|28rihzzU2hF;lN3+kIJnQ*c5B!c6dog&P!KEKKtRTuD7 zH2k?vkg8$rNYm`YR!~J{afoN-Mq-NQr%5e5*cc zJQ!EFNrTcK@D(?X^Jvmns^|4@q8+u+owV+TgEwvOSNPjhS5(^&objA<@gLK0m5h+} z{Qod!i$I6&ZOZQ@`Ti{}o+oN^D#DM7^w@mBci-s6Sn|BL@V`!ujom!q>x%tGg*S7E z&8|)$;%{gopL^t@7>1R64cssT2A`$=Xv7!<7D`Y#5a(bGvkeaqZ)_`Z`dc{R74l(a zzx}OAHK}1nxE?_A-vo%E*=FE>*`{7?9S@WJI;@{__t=NLsbxp;@>{%TG}+CSWf%4I z*n+Ay8;ge|Ebu1SkjW9Nv_^e(TKv8$SGf3ON1V0gncbcw3f!KT;7-((@sTiOIe$gX z>Puw%V5NI+;TdVkBII<)UUf-|57-)XK5dbRS?PA}2n3WhdGnsG~J*=*fFkz!&kr4$0s< zbg8&k%F(Kv0#b%Ux1I0!;zZoDr42-&M!Q=n&@@;_j_#SCSAt!|4?d}#WtFPI92qmG zwve*R^i&f;0%yk_-kg6}CUpN<)%2y2q0}LjXkp<@h70bhRwF*b!{?MnNWA*o;&b|y z+~o72n>1io%3eg4BhR~1!`$f7mZfS|DZAI&MpVo`4jd_nHRo3kmzuY3(~vRxPv;$d zyyAQW-5X`8#k)brkm@)HQVO zQfq9l8X6jpz=A5>UGvMVMqRmgtk|nRGhzy1+`m^5V`6qp6v%-_LS%GmHGlL!MW&@m zNl2im0X62UFMh(HG)T=pyZMY)eEg-6s-Pg$i;n`x(yKWyYrevVL3j1_Shlp1PD{&FssT?a>IaWH~Vxgc-p>K~Bx@ zE18Lvd>5RU%q|8oZ-jNwtmTGc6GAkP;*`zY5$}Dj^5#ED=yqtYnxrhsF@M~(+KFreP-PKhO<});*W*^ zHl0IG^-^ApDgp}pgZF70996*4q0ZJ}&lUPkywV}xLld&|eq{5)qb}}Rv<4wwDtcyN zTB`l;{=V?2l#ryJV;(@rH7>B#akAvbCwO|>3qyM%U&b9gU2A-WF|4et=4vd&LDyAK z+|6wVG((WF^%+j(Uf);a={pDY`c`Y^Eh`V%E#_iMHA>P&($dmu)-y6PYSxVim<>Z* zkLtH?F8)e`5{-q!BO}BaF?%J|Efs}hV1pKYEsFf#DFdv1x|YE9ER|AMnB4DZxmQO` zzl?*QsWm5s0~x)I1=BTHS(^8M*yQxr8yO0!l=lz(Nk>{rHJVCtnqZP@p|t0x&nd+` zDSvotUh@bQ>0~(wO0nrIdt|(Rs@X_kdc0p}$F4>)pG?EBTPiyEM8vnW@w{yEb!C>K zyV}(!st*X4Wa2O9)yWxVH5%(~t;NUZf^woL`}7UotFBn@;cYV>S~Qvm{(=DE^c@F* zhD-KrWhiJ4T*f zX{Ci0EI&NUuZ&q;6o|E0t&5qrI!)DI|0WlJSZ+gq6d+&5bJ6Sze@|p-NJQimW3*N6 zBp@#ou(z|!8t9oCJ<>>=vr^6-_S*s=v^}RO_nhi7K^FjH!s-)Slrkp)jKIKWzBkN$Jkdty^)CrPwCRh04S0!vK!-VFB>CI0(Ietkos$bCYgbABL)5^8)m?s?@cx_sf|)W~w>CA04EeM65gg88;83SLGh zj)#gRZ}>z4R+a>pXf`6a?yqa`v*TqvQ!evDk@!W7( zuxdW;&k+OH5jaOJ!2XUDtk+k;D`WG;-+l!;cNtVuAIaN~$X( z2zgcVPoa!4o>mhSZmg-9wK+UJ{z!dm=pWwuUe5{_o>VzWFeSqWer6?|!=`5h5g`un zqWn2A=~G-enVuv5Kzw7OPBZ4aspUyRslSYr{yVe=r)2Ev8LLO{I3bQ{($oHVsr+VoAFv_AV2*Cd{vw|ZgM$)VL#8##;RplgZaZ? z0@LU8z(A9~xu;+ZPvZq@JTn7N?usR_ zAT`4WRIf+|k6*!Y+l90S)-=rbS!Sc!3zAbR)KiJL#BufXR1|SNPdi$x64AZ~SlOEt zK&(o4;d|aa+_L7DgB^sL4Fmy2LHyP)?t{fRHyv=@Y8B)H#ZJsgJ9$D4nWgi}X1$ z+@nyxwFdu$fk{MsL-cID0sb(#xB&xD79l&@Y!L)b-h4Q4G0m}-ENy>tajlW2iiMP8 z<1|p`ByrhCB#l9SX*RoF94{|Bo&-{)QN}({+CJRasPTqZZfOE{SSH3|f^f#Xl_@Hryq83~_}oM`9x&|H~u z_5kfk5U2z}P9*f47@7!Jd8)s^t(IG4??d-EL55A|FJ#3=4MZ6sQEhto&jw0N#VM67 z>8QJJ-!6I~`oEU_!R2^htTxrJTmIWH)WJ|oTbl%xfQ|O=(`W|pS>Mnwjw`o%%Nv16 z8%zW7P~eF?E@VK%%!JEo;URd zFied#b76;CPae0(VM@P9@@~3gDjP*&OXMf3uu{n(#-moDI{QJU3GC zM3dadIn{WCa~mr9i)6FmweX!|CTfa1zXjjMXk1htwUhLkk<<3lg4nS2ceHJ}w!uc)HEgCVaTWdFbKhc3Vc1)a4ZX=76Hq3uae_SUvsA#A5 zMJAg`HZ0rp5H>wt%^S>tc8vaXYW;ER;1P_F?tX@Jy$tY^M+btcet(W6qWVR}#40TA z@9&k0&|dP|fH|`NviF#=UwZ7&YSr5l86MdBMi`?Ngs5DO++}4BV39Q(A%W)R%Bz9bp5migr$Vr0}6Q zqhD;m-aQ>RnOri7(f!8S|C)e+U;tG1-aPT_ip?NzNta_5dvqxZ71qPC?p=l9Orsg4 zZ(m1c{68!KE9<0V+t3gy0|Nu79$h%O3MwMifdw2S6qIbGGEE@16vnpZ*RQpaUpF^5 zrkDTK1(M1Bl`7P?P$J|~_qoDT^Oag}>Zs@VmN}qRYbtRxMw4zHpQB<^0{j7i0ydoB zp9>fA3m)R}bi4N}f9G0VXySOR8=+@Tx+NxUdnpNLDl~F>YL(9_hxr_f|3t}IJi29k z*WXCr@&>9GS=vH0krlwuaq}uMfpDniCKjTE!r4a2d@p#1K=0vl=V|KNG40T z+9NI4TeW5 zQ%8nGjrw3}i#`{{$JbBM)Ikwi;)xXLuq&61jOgulVkuP(^)oDK&`iutSBl&YFg(OcY-67go1^TQBXc(wn>(|5;H{lD)YluDwq2?>d^vu6=m zk-dqG%=+SvJa9-y*?)$p0adZo+2QxguSbe$@BAZ?;zQtW}fhGDlZ=sgc_PUC0hKC!)P?=Qm>Yjrp^3bp4Zs8qX z5PaGpbu9bbZTTm9ceIy#edeG?$}+HRJ=g@~rn~Tk%9B{Z2B^4)!1qC0 zh3FQYpMOVVVq+tPTyn~Hhb^&|aqys+`;ubMeequ;2OA|9jwI%+Y-41&N~0Tp@0;v9 zzDn$+4I}`~U-)pfC`criY*aw`I}dUcjwl|VB5GTfzE3}gwEt8S3keC9-+D#gQsvz@ z8no??oGO>SV2&9rc+G z&My0K;}H3lN~9|uSH5G%Gm}W7g$I^ikC~mwmzCA5LzTS>(b01E%Tnu|hgQ@{h_#6) za;$zEyQm8JDz^mhT>0Jh1u^h_m&Q7gZSmVD$3G&bqsF;uJaK#lzb1(&ic>t1DbDqE zdoli0?@q8&pJov^~1#q`QpsQrKFI{lq~iYTC2Uw}R$2{n>p~Ns)K(9xg;P ze0zYp@nonu$hQ@3`Z&n&h*0cLRNA55kEM$2&2r@yqSB+b9NcQbiC16GNZJ~a&NJq9 zuWRF;Czgp@Ytk2=dVOIUi!3Q+R*UE})Q~Or*QmBY<|4jXbTXkZ_B$!jHn#v}Mky*P zrpQPBf{3IR$Q;k8+#VgT@^D+P+FOZb*~%$-(fc0G|FEe#-;rQiAO&IE>)gS5&`?j= z;aM2=e{inJ=I>}s7s7aF)(d~sHRtw~oF)HgTWZ}(&lc<6(t)B`lccHHX$zz#s6*uC zR=(&fOGoG8k(3D}KE*EAavRM)uEHsFcAK3Whm76!Va}3FYCe(U78aV~rgva;cVT={ zZK+EYZt-$1rO=l_y%BzDw{t!sa`TyV-1;I5Af0S<-;>^oc|B3|YxiO{nsj_*=iBMs zU1=%aGL52~UL5uXL1ImN|8|7GWjra+>Z4u))E`)nJB8Zgy92QJzwWLJG$}O8DJNzis~^i?zxs?1u5mi9UF zNnlT#C`2#lebls!*m*%kQ_1t1bD;4Vhw4ek;;{9rN=`8BF?A#TBfAaeL^IRVrOACC zBHHII2DD0pPmZNI$_}JXg?OjF6rz!7*jlEhw|xnyjkf07K{x#x0=0&748W6&hK6Q#VIh3c1D&PS zm#IP68+idgI3!^CF?62_6{V%2QR=}VArcU7eu0ptujY93a_W;<7Qvk;^ziB72h4W6 zO2(`f#v_S26YUnGsGCa68wZ?kki{5{oE~l;VBulCNA9WTn!9Ec*RecOIp9&q=&gD` z%Mo|Fr*>kY5cnOC=Lmb#J=;kELy88u+$;Usx#_a;j~;bhAfR}tudg4u^?j#+VswT$ zTY@`nIoda%`IJlWyeUreiw+FaU~JdtZo*%IT0rR^!%sOiH6irjxKpI%|#0)xdgF9-knWsfxWk8y1b9Z~jQOoSQRs zbg*zFp4HLHZIKhqV@LQ zqu`M;{Ws{+_{4mNGNCM`7^lqVlOZynk}!Lrc33A;bYI%OXkM#UGa#Qt#mq*kU;I{m zOaS95hvLamhId`JSG)=7ORCAsx>vGT?QGQ4LTJP6ggat8!`}&(>)1u!-MH@&xWAbC zW5-3ZL77|rp4Nm9<1&@%=ss6+k!V8b63Pne*wP|`rMLt|i`~m`@bBW6L%#fj4gBub zw;ew36s=YAj3hWFPuGkTQhNb4vwKX2||0HwVNRP4<+_gFrWC+s9NvL<)>OTC%aS~bN9NL zB&~b3X>pfWl1+`XzxSb#8^JenEvD&lHP3q{6^+mNZ2Y@GE#Cd_$NJq?Jd0CcN^55G z-CteG>C5Q8%eP+-dp1WeB1LQz3l=4Z>L=`GHf?+QS)(7%53*Y+%h^wJ+_p|`vE-o` zyR#zrVV`!b*M#hK?lbM>IoWi}d^V(?cpt}A-BPb0Xfz(_F0nO$_Q(%SnM^Fp91|0> z|F@2i`Oclvt8^FXIxqvC$KBW4VPP9J2Q!*yQ*aofAaZ>!fW11eC>BhY0V6#IKhGi( zo4_9J&U$T~OUbI#AC{Tb9uX)xpVWRZdEqrBCh-q9w|M=(H`UdqWdCZch`Oo42x-k0 zys#XY5TKxJeL+c0d%3;#?=bm@6|XUGbhoxKjO{lz=r}m8CR-HNf4KVV0eE@(efaR} zIaha;hf5TXWh0xj>PR>keigXyEDaMJyzbJD$9)33?%yH| zzxBUqt6%Fcv9sekG34ync%%lVa=)9K>BJ0Zo|8^18*-3i4hk@8l8?IY5BByrpTB(h z3C@0hMoQShoX!Mn5FyUTH-t$MZD0TI>rNY)rLCg=z00>R@4L9TMDbd;fV|K`h?q{2 zgaRLTX&_foUw>ms0e~zKu%Ht@+3tlgZ$9F>F|GaaUv||)U6$v#80ZS>rj=1>zG4KO zK7f&apYxrEezFiLYq->x4*%y%NQg?tyl;aM9T@UKN|qhq0O`yB1=O-U`v0R%80tO@ zAZ6X3@}Ax-Y~CA8gJQ+Kfd(Gj)}OL~Y5l05NTc z$$2Ui@6dSPBMqoC{`UZ`hLipO52^()CrFYN6mnV1T2*?>p9()RhiMx*Sj4_`a$*Eq zSFjt40mKlC0}#Z+?L~B#J5CGZ-uqyI_&S0C;0}H|5(mA24|SVLvB} zqH&wOhCGQEZI>Vvk%S8%;{J>4aFQnh9bgnXl+yC@gd&KpjRtZJT<>pw8cxEqOmW+q zPfAY4SlfSPH|PLcaZbuWfVprC3=EW&mC3=}52lEfM{5-Xh~g(&u?_%VFqjNv$V@_l z3GO6R8NcA82ogJuXbxdQ9A*Ofemrl!?i=(k>6MO+{Xbv^nvpBX#MFY0hQP2Wf+;-- zS9CiVO+w}nyCGL(1dk;t-{?ymurcO^8!gFWZ_R3~JnUd=0p}_?`C}WHAijI|+{|oi zrJxfV{Z_ifW=ylpo)IkmAXXSqI@Dl+86jK<2tGN7&)La30zQFnIE@>-py(fWUuM<0 zH=yT24f!3FU~?%cCB+5QrNh1TPQYLnds7KdPfsCp`AWf18^D02Q}3xbC-sa0OAA-$on%ZE`s~@W8$!+>p-sa$@xt*%My63J(^B!fe8#3+ zZa0#W$~-)US(`Go1=WRNu;TQXpP!GqLEYORWoZq)n2ok|6XsUaCHNnF@F0bzp<&_; zg(xn~xnm2VILc=z`{qa}LuNO&+mw`7d8oFLswE>O;g3dd-}6mm#o=6KB9uVLx+*YnW1aIQ7Hz!O?V zf|&&S{lCxj!4A-O&yqKqdVC@5cYAvvEOR1a;`fI;#YN_2kLzc(Q}SEdDI~`O-@b@8B3csm>;g_-o)1ojfpuP@>s8O z>1HgzfMIg4z8B+Q4z>Ds836(@w~_(jzHC^t1)PhCr&(GB zyjT-hb>Ef>4B6~*#BC=<5ai4Y4sFlWVT9l@=Ds6t#>cRertzksYT-s`_Z2He=Wn40R@72hWMH!RPlPK>pNto=L{weaLJHrmw$!qH+r`AewD<2hq?0j1{xgy${@aC~=mBc7p`?UK*2NQti7WFlB2W88heh+V)z>NvSNvxaPH! zRu;<(KCPn5D=h?MHI&CfdWmesLpQZIXqgBp9g!o|z(GzeG8BAN^uLFO+_@{tTFA3^IC<+ahAPm_-`ru|F3|nUD3o%D6Oj88e(ofc0J=Cp-y_GSd%0nxOYc1 z-hJ5pv@Ng>OR+kQ%5m-IvCw-p*Mao8u4Sj(iqs#FnX5KB9$P%~ge|A^0F8Y2ZelB6 zP1D&Rz$^Cfa`(I!EgF&e$wu>$sgZEUTHIU5)knF_K}%h61FFZ|it$T`03IuNgR`jPijwn*`NaYTHh8ncWS= zkg47`cSMZwgpsZG_oIdLvBoEX%MiBMIw9pol%K=LpruCa-`v&DWbgidfYqb z0nF50JHn~MNt)xk#Zcdf_lp)9J_TjQ?^b@V>vVf|NtW4c^7OhdNS>f@7Gw%7~7UY?$q(+A1uUw zBu6-3A0K-X&=lsl?ty-l6DlZdY;0N9Xf-|hqx!80ouH{H^)i$Ghu98(x`YF-RT1&u zm}?F&D5PUKU6HZiS)$8h%n|F;X4jCl#?EOF6tYQE&QMVMdQtUGf1&_Vwm(HY-5=~t z$49g@MnJ~oqHI6o-znIE4ymyh_NrNpLNZ_DcDLl}qLH=V99aEpZ{rVH&v5nbkw)!98t1)53@ z0nH6(&j^izHn=z2=UN z+gx1A>thvU0m=M!Yinyy!rAm%>UA_Vp}r>IHUh=wQ=M!WL~ zbTkzPa|KRHjIdiU0O3F=t%JK=8tON4=!73UcmQWRbTe;&^7HUH@#mrKa1z&kS$xi)S*=cAT%N(n}&`7Gn znfBw-u!m4}%LhM2SF;5#)OLp0hiDy9qmmkIIU2DW?r(B;MSZ1u*=J3q?nkQr@Lw%h zTu7w-lW-1s%stUjIcOG%=V+^%QG*rOn0{6m+b|-;1PYIdp-)s{M3-{|lx4#Xv@&dL zMc$5juIEv&Pzy&bY>R^9QKU99R|r!gtFCOG1OWZuEpinlKjeRj zTsh2=AWKtTUp>Vd8Q43!>meb|9JNbjb+n*nge(0f(|!2U5udG^>90qb-xFVqBmCn# z*>~?oIyh(^{+4ud9m_4|Js8qD=9p90*`zNu=ED`#A4}`@lG-Dnqj_v_>)Ngj3w~&;KbP7S9{BtRV4C7 zsB|M%epRp&J)Us6`L`nT7W;tb8q-NtbdU9lrjSd2i;Ii@>RtfCTZkq#)c1EtUd!lD zqRJ8Y$Ld*)O5wIs4aK>2J>d}Ob_aVC)BRT7XD2RDhx-9*`{3Z9Es7@qt`y7%^6()x z^r-YABC$|`UW4{uN(vV~?MVznYat$i?mwosRvhEO4vlvG-Q3Dw;FMom_@ejDy?Y1) zG}sUpKtLhwu3jb5*_zSE{>*$+J6rg zrhK`65<4*sthV7`S|)CKWRSeztzIfRM8n)`QmijEc5JzK^Ev?ArgEXt_-r3-x!+&~ zW`&3)_7GnGn)mhN@$>~eg4<^jn!mK~m0$G{%-L~Ujp{F+ZCV_4Ev{#yXBiXx($L@h zCe_0;v;16Gi^8{1tZY`y(4so2y||N&-As&T>G;)Z&4-HS=oe$vNFJk@^X;rD@y&^1 z2SvxT_yBG;7jpdf{$XAdEL>2d!*YTL3tJ{QHuj1*41sWP@$-(m|zIFW3bUCf4;Knqy(6LDYTs!=Y_;ShPQDd*_~8yy?kZU%eZ{`a_h&Cu&_rK z78dE8Q3yb25c86Fe9|f!iUr8mZPoQLOt+FF|9_LB^B20`vyc+BceXq~V;Ac(86B&q z9aI>Ni!~Vr%;wa#n^MQ#c&JduV&K-Y>|+eCb-9GS26yETUriUxO^xz3_qVc#mO4ue zP}v98jWFuNqA&buXxOQ^B@>AJU>oYm)3LpMPd_&{Mi1p^n7NyUIKA&7y^K@|NuMlK zOx)G&9Q{^lBXSg>j7zh6=+DKnoGW=2qx;ixglTE}c$RyBoPzWa8J$?9uHbv@9Df+H z7%gSt^B~Y>Au?`)*@tFFYVz6U)MHt4#Zw;1ARA{|l?u-!6k6J=Df|dA)tu>1gT2@V zXCn%@vJu7K#imkAu)3J@#B%iuD4E{)UsJffvGrw-|7*D~++?M8FJieiggtg{9mZ?f zTkfTcwZ!nb84b>KIMr@`7-vrorETCbeqx+`^t5N7)>0FRzwtfPzDHZb<|N9(p37qG zhTW-R3|X0*;l0ZUAwtJ3?afG9L=V9WX=&3(3(%tircvzc*5k>QC#XHGpqwKS(OZX^twUk~q4W~=h zFy^roGZ#JGeEg#xo87j>P zY0~ac2M|^@PfOTtnx0*8#9JY(9eJkW*qlthZnc%QX?F=_i1d)A*ixn!;PoioSzFyl zq9{j}>_WNzil@5tRb>j92ks!zM#%hDmEv*){_@8H_-OvBpNWx(Tb|LBl8^nq+xA`Y zueqmgRskdIx0wT0<3eRzQS$vD3$;`sI(^nf3i~l~g04cYb*)Emu~=Wa6wvSsrvJ$* z%F5<&7eQu7IQE~>GH%O(oCYg4|?w}({@6w+&f$TF>(5ACI?Ok!?O<9V+ z_H5DLkUTTs8d{Cq4f3*)^Y-EK&#$gmre_?9%PyNx(;azv55-(|>7K~pt1;)6$49c~ zap~`PYnsjtHD7_6#IQGVOi(;tc2~#RIx2~1Qp1jJp~c>TIZ3)A^aB;1-6gHkmvqp? z&SaO2PeWGoB=k8stDjf6DDQhwb3|t*SwjDG+qEDyP}FnJCG+XYVw z*2WBy^W9m_|e$)H_y3k1hp%xMPynPKvef zxE>;ydGku%?dR1Z96DyR@wiz9N>PW}%V(O7bOptu&*42fF+cX;z8<~r_@k<^2ATQ# z0+r2rOtcrU`i^(QiWcvjI?Ertw{PDLe*G8_5J1n^aJVH3o3l-R`JM(D8QJUC9VeE` z06R4W(Uz=+XHj9J&q*64@Q_W-%+yuwjb}ppWMzB;dy%A3yKuW7Vn?jGW#Nv5w4MBs z@#f~{(@U5NB$O_w0$w0j!^H+N?%RlL0Qz ziqM4qJSs=|K{33^+40!>YePXQz5$o3(CdRmeLNjDYkk(^Q4x7aUPL>C^o?mgyG>P~b_Xr^t@^v6m zd5Q4b-K$qrWAd@#Jyy!Dl~}}R>GxV#_Vd5l5n^$9qvR*|08XSJ(Zf4COZ|0Lyx}av zo}4epL*G#i+$XD!6GrTK0ZYsusO&(x zeov=Ze!^>Sti_OHa%Kic+}m4JE}X63j7h$Ok(2WaD4-rnNMK=32u@BDBp%>$eG>vu z<{?*qvHdscNFdHVykg#CcC+bJyDs=bQ|3yq%v;CBN3pkA?>po92|aIfZ`hIe5ptd6 z+ZI<3mJ%+G{;QoCwFVyzk z1*#S4*l;&CHj1c!3G}z^Ii$x^WaQ;_5m`z20Y zvIWXD=IPff!O^s)V#pOkE+Lv9{mw$@75RHuIZk8QLy;W=H2Pn)V@vYVW^o^H1X8@= zx;~{+eO&s~EmUU!5&gzQxQC1|Y6V9j?+1#-G*_cZl8ygz9ef?pKPG0Kw6f7buU5&* zj(S$^y}~TTbvdVxt>`h|R$4AWlT9$g%oLKm|LE@X)Jc|?hA_8tZ zVkuV>EDp}^oE3ye8?YNomFcA4C<>JgSJu^RCYO7qV`<;hgVam}w5lJto(rv@nIkow z?jTvUo%^tx1L>@XI_fua@3md$^^kd8Yh-V**<*Dt^08L8lc{=;TZZe`-=AiAJXKie z3=G)?Qnq>e>y(0h@<_FoS51*c25CDnf`x-X#xwQN_Ac0Mg%G;n;ZYx8wDrSS_221UX%Vy=&K7_C;iP~XCseVx*G#HU+eM85SKq?iNXpZ)wt-3!` zGM&ua%OY7lPppsnBPA~`&i-k>HkeZ7;9*g@+;+JFokSzHqD%16N>T0pTGwsOrwP0sbXw;#W4PSCgoc+BAbd28h&fZ7YT zpNY-YIryqrS-2Z$Utyd7Gy66Xwct6Q`k0w}Lc989Ub0)Owb1 z2j*zy*lJG8m*Q&7I^+1h(#$?rE@Lrua%L$zZ6bcC%1YPpdQ8721W)mH8AILbskgUI z+W0yWZGLn8*iIr;dCi*>zrK6@qG18r9eHGDo^6Ix<&)DdP@^a$#V{9o?9E)IBUVScITovArBW$OEUC7xE9PG4fzke4v4|B7&Sq!%*gFs>O~=bl-$?W zzkO!;lvee2g0Em9x)bZ~_71&89|@|ER=B0Cvp8tNsqEED*mOOLG#73bI=Fb&W#s&M zUNXlJrdPu1#?!!O=KhX=UeNKPTd~#n*iNap%fQT`?s%kZ)96>?ro!Z(?!!HXUaddw zoU{~s?37jZsx>MP?kG6qHOCw9-NRV7|c z7@wP^7;@;V(Qi6-Dp~F<_-WpjJHH-XB|dskcdyo*uP)riyt*($vk;9`6rnFlcFpOOUJ-S3!8W)QfPTCEcg`r6Qaa=y*$fmP9YIy-8rB(=7_^`X2>`XlzBhYgX# zK%hOZ0=qNsdgzv^_rkYeq*^Z)`$#Z%LuE{=$90hkUn{nxKhzbDNiee}AWCot!16nl!k>Io*zOOc_S*3ZjyBeFE z3)(!4klWGj`tw>JtPXqie$MB=ufBfsCYEz$WTCi+QoJ|EjtTT95AW0cH*#mQcRPOr zWik4~c{AXwJ7`s*f1vt6t7;%lG;f-!*n5-K+tvQl;lxMIjI=JhUhn!CCMP?AOmC!I zf=Z+vWp%Pojjkk?*!)?waxx|NwXJN(ZEvb)h*0&eXoZNa#E_G}K$9l2Bv)%!x3KtZ zB9l3Gjj;{6?*D*-Gp#&KWn=ems+z;M&2Cm1WF2=N)MDOy4XRgOyKQ2@6bX552 zHX6Sn?V>kr^H|2U1O(;tJ5ywIJky$ROlCtp)0dt|6c)c3ZL0#TcBBm$&X3kK*b9f)SVgh|7CC{m( z$lKj!1e1oCE1in5f{*m$jE#cg<7t5~gfw+_2IU(!WlU=^z@#p0cQH>p`<~X1`k~*I zKnlR8;%zG%>+S8GJI++k?tu}E2|!&a(4Gmq{jeV}J9qQet%ndO%nj*?Hlq@P`n0Ndd`JhhG#`1?;>6;FRRo~~gJra3sGh^0%zHzmw#|z&R{9b2u+c6?r zf85^pbZXG!xn}3)^!y0oX7P7{Jj{P%)yCAbB3iGJxlqS#twd{f#6D(O9+%K`=c5xF z`zVplTyOQzMvQ2s64OAF$K8~oV&-I092abwTCZAzpIY2!uaqkg?SZYTf+U>q9oghZ zpO3un^oPZoO;5x-XShq#Nxso4VGX?^^pIja)kY+x@O`-Gn!NV|BsOkc2fGs66>ESc z`Bc$TPx!JmcGto2a+UTnwUfXXp;UsTdXc?l*4|Uz=bSXS++z~B8^^!Hc6d(}x)nL| z>sHy81Qg~-P-LqbGR*g_&&%) zNwRsihGU)gc&_Ii8`5<0a$8UT$ymZ(%-HYZB>uy9LG*n+QD^%3112@4M6?C$2PK3L zSBY=|>k8N6kBp488ZPvQK`{2G$mgD8%D_WR_DJ%>=d=) zJkFgK#VAf0#YO)2(iNs83A4k~MdvY(Lxs7hP=crv)YsaZ)O*`AEL&~N$bx%F_`6fS z@rF{SxNcm&qT1H@k9%ZSycujq6U1u#rr-5Mb7h%D7P#kC^SD=+C!A!@EycyR2>yPr zVqnk4{+(dG*j_C5@IwqRIC4+YENiI!$oip!{_1Vl5IYo1R*PE~_OG-`iT=!x2O8NNSbcrtwbaV;3!qR)?Hz z+DR$xuS`KzqzcLwbqxD#xZT~|P(U}89XB(@8|G_9@LESXjKNr4zYETI79JqC(S5`>b*~cwv!* z_m|1MFQP}5&ut!%BZ?|$q$xOqVb`Fv<{Xu z*G5UT(~Z`h!!z7djVm@hLkFjY#RW_COqIo}uSha;2WlD{8&3&@aV5WsIs+F{5DZ;_ zP>|Wfm|Od_(E|R&{mgp+eGjH7ccl`a2EqLIVPw1M!Xa?n)N^#x?=o}F8J!&NIIawS z0kRh0!4aZff4R)g*q0-FaQ5m^ZZ!yTiEYOfgnDevj`{T7UO z?*`P@OTtpl2%;6!e|iV~>({S^43a_&sEkr-AT!6HAG(!Bd($#kb-EGBiV>TVk$h7V zlp&YLQ{DF&g%2%7i#?mJm?_d4e7sEPJ zf1u4iA^XcW$tQdL=ALD?<^3X4poAxi>6gCTiP)H7*1@fB?d>QsRD+=#zW4RdE82dI(f!trsL^xjQyumLwCOqeJPRALm315y;2$+>U7W2S%7E5t(d z2Kl~J^R!?~-fEQMm#-A=<$+JZ<(}9pT>%uKUkI?OE^_z=+qO<2=8YZp3m2NKBmFrSJCKW>%CpmuM$~aZ|Ue4n8^Mhq`i=+%#Srp0E8uy+K z5D)DWv~>FA4_)RD)?W`($VlmGkoi12O2n{$wtcbQmT0x!_hw^9(A*7a>gLzP3PN$; zadYRR+5aZ0_|?F0GSS5P05R9nxi^1H`<%|krX#|g`K?P_HY$}tgw2TCtm8RE4p$!k zNYvU+4%cr1NU;+jfAsG!{!3ky>ed9t{qr2c^3D&j@h<*#GU&F-1{@$+t*xK}MOuO8j*h#Sm*HqBDsj(^|#zscGjrH|y_sQ{TvDkV=R-A>P zWa5dMGbtG2_d0Y8oUwYi;#_f(KRBo<co-DAfY0tH<`?nUnRJNa{EEejCfjEf z=XN#DFF6V|NDPt^;_xgi#q5qrK`V+Q%&#u;%xF7^eeQfX9*PL)6#F2U!mQp zKPhWAdh+2Ro3R909_ym4px>W*>1uB3}%P-G}IOE zd%feufvw1L>?Z2jO}r2?k0)~c|}IGlC`kvtsv%RN}bqC_)?dw ze`|8bGcf%^r0j;RC7sudO_xxs&Bwq%J&S^&LsY;k+^Y9H&zudfa4_)l?j|=9NWoh* z|1`_~0N(L5;q3aCm2!eZC$WY(TwqR+22!iwJT9?u0`6*UYop zi%BRK^K1=+G}Q6&F**Osn;3$vsAmL7Qs@{B^r{Y*GFOI+GJkcNK(%p0#62{SicfF= zB1<5g{?CuK+2#-+1s51M5nR81L(!gz0b%$I;}0l8^mf~S|E_(`RhAVH6vPBWSs<#% z&dxqZT_+;Ka9u=2$4w@{#LBcIX7PF|Y!^cg3hXwaNp2j^O@wc@j6#j{Wj!a zz#4%fC~BvV1Ot@i%MkwOa`rSAqQ}IA40F-LUewVRX;~Nigu)@SbU@#Ob+Yss?bWNb z7*W?AGUj4Q_3P0hDCHd&8|?B2%bo5DIj`L0;R(A$bo(!u78Jm(*+?L#+ADT;p!oXr z>%5UwVp7uS#YKN~R6_t+Zw-RLvC}EC@aN@(PIk_Aq zpuK$fqLBg93ed6f|8qu!S4&}NL=fkWMn@7IP#w5l^e})el`G_tGqbS#GUNavw<}$p zIVl@j>zc!S+cTi(fkyamc+GM0FRGb@7w*&kOsEKsXV`FMEG(wRJKKx^soPKa+jDyfTe11)md3Z zg-U?S?)xZmc5=LGi&(C3NKy}3@h)_}%nuDE2Ax0?+&LRNJB&AP`oLVR=*z8tMs`=* z{TUH?C?g}4=!@RsZtdqg-{+DNA$QDTb+FYF0d!G*BjSd7Q zU4h+<6xiKS31OyV4=;A(|Nh4Zg;y(3o_v&|M?o$8_Wk=FfIL8lAmpOoWug1f57)3{ zq`9-RX<#7y&4pyHuzznbjpqNJZ&VeqVc{b~X;!)OV0?Ul#u<1c>}o>w#~T8{Aat;| zN9;>Mz)B@_ilTVt87RSxQ2zsiLNsaHz!L(8oQz5U7QH3`r(^> zsDG)1&OIgUh!bf=;7#bEL6DMf)PM(&3070h)QD|OED+g$U>5#GB2;ppLv5muV9k>Jq>H$?|}V6XE1!q75DJ+)E!)_M6Tw-6w3)ORZt6c)*+tS|C0$*Xw_4 z{(k47c*lQgupucgFQ43e3$uDc_oQ9z|E-4U*Zc-}Cd@q18&krSadpgST0afhogVEb zzAgbug#qUwN9*uMkHxX#Xx0!~8@58`9xf39$DZ)2rsI6RFtcy$H z_-x0|e5j~6i&K8#xRRG{=Qq(r?~gikn(#P_!~2qSxb>f{gP;31kkffSN}rX+@KG)h zFo5?T6kKpq2)vv`nRS+b^&`Z?gCXgIj=7{H277z^m{w3L0tS!g6BBa-4mlK@Iv@lp z*G2Auf|h}aDO`WsN z%7GjZt#6*!88{cn%jNa!JGmp`zDr!c+^Q4l8PIRLcS18V> z$FvBF8+B~RPT2bT=(~~&H?ure@gI_or!CN=))tXK9K5$C?t~nJsO@KOFOkpjG2*$o zxfwGOs(cRjtFXssa3veEAcM0G^Q@rl1V*r5P*5sN(8|V)@+ar!)LyhT!1IJJV8>== zW>)d>{N(z2Q1_p-=UPfi;!mD@8gVeshWonFv_Q>im=5^->o^1IcOPRGDC&O)e;PYG ziVlUD%O5Nt@fsR>PHJVhN1ZETfi@Be@}|Z9ObwhgUmABmNd8#B%rWPdGIO2T2ygIz z-dP^N$usZ11!ce`@m&3?!AiG+5kqjcz#Oq>hXXZ(PzmrKeyIF7!`x$P-IK@NR<&`p zXwjC2CPr~Z&%^C(#M$$&Ud16{&Lvr}PD22!?U?&R7?e?eLj!rM4 z+vNz?e@&$3EycFxMFf;ux7fKmw@fydB(VRs0w0)br8RvSsf7?k0U?yiH>y}XUyZy9 zAH|9 zJ99Fom=9nDYVFSnK9SJqnkQBAUi?2q>4uC;LH93_@XDl|6;~#yIrj=fxoN!9q8+x_ zP#vyFC1#v6$|C(ozW7qi1D#0kqOIF}NwlNQGt)A13D#^k%VS;>)!XP;-TGq#QzIXZ zT-_A!8`~q57biD01Hk%q;mCb=$jr%ZQ4%Cp{Tc?@ zm;e?o*h4f>mQ{_zHII_;B~XK3tYn!&?3I6CSI>RbQMKzaf#(U@HNK9Ia?n(k&3qCH z?KYRRYzG>G6VQ?YuzCuG;a$EsbQIj?&g;l{HUb5QeRHUCN>gLw6X3gO>1T^$M5s># zq%8g&XTKT_hG=_H@9`;qfx~RZZN<2i;A2olp`ZrDc%p#uKqDTlMjZI8$zdn)0s#Ub z8A{;S%we30^u45GajmfvgiJRVs0asG4xSFLG;iRqJLGu3wwMP0y`f(qd-!u)t{MFf z*=%NFTj!>yPt2FNuJ$*7aKEX_!xFrXR(t;3UyD=USb6Ktdo6}B!`VEWFLZdrY2Ei8Se8^Ffeg^`7*Cq^Ika=dxx}V`xnZ})WWUZSBnPHrg8lO zfYA>~VQt>CI?TTXQFJ^?`qv!%X4?3X0wpS&z8ORUeX+g+aU$q1WCth2W-h*Wr_5wt z?)r`cYs$&n38bd^5*AlMFX-$R52r{Vb#U4*rC&Q)u!s%C{x#bKz_ITW`wgYFqd?#H`4fd?>R{g2H z++j^W-1ah3hKt|mN4ekf!LW%6Ql%Bc`+gQK=J8^XEN_6}C=I6J- zl^D9CEl70t=<2m8DR5d=M|qzfn28>(aEqQDJ7A=Ys5rNIit7F8%Z2E=SJX~!1%b&5 zt~6B%E#b=P*@$14=b>Y>;mGOmc9yLu)adO{-p95Ayk`d5IZP>q+01}HbvnI+-2buRl>l7nnB2`Bs;$+kS)^N7bn0zc z@#z>=9_gGBYfJKPeXfz)17Bs-A4EC0$)+B~4kYb4i{v08TR5mD?!CXGwguZqM7zvy zxVW-*?muMB7Kje_(Id0#C8Tyze~{r2y5G0Tvj zh{S=%dk*1EN*CMY%SyId!+-)WEGJ3_1%LjGss)1xN5D2o!~uu_Bq&D6^=+mc9L7wdg4Mob6*o<=LRXp*hPp?55Tv1M1iL|pbZ>nNE+b0ED zK}SE(AKp#uehgo4vFrPr5eEd@l$|}dxVD-{^TrQ^MJ zDUw5IlR*pY2b;5OY!|I#Yu72V2QpyS$yXQlVJTUVD8Y9GO>rqVRu7Qq4|i8vL0FRW zRF)?|dZq#{4|}347uA#S`%BbL8%*MF%|HBllfA=xgd}RNcd*sat9t9}Cn+!GTinR- zsjj`0y^|QW;zH52dAtm!9BW+s6IhC|h}ZvP>Mfw6>fSfdp&L|08Z1CUI;BBCKtUR5 zq(Qp#fT$=f-6`GOCDPqUcX#*PJ$}Fcz1Ov7Efy}vIcN6S`+cAH3E)uO-9Ii=fJuHZ z-G&_oL=g0UIiU->QIE77YuSCZAj$!z>d?eP>a!-OPE}`^(U)VX@Leeq&{;-9G3aC zh_yL==V}TY3(Gd?8GX*mbR?jhgNv0+zYhu|aM-+&m9^)WH1e0#pSA0GDMK&e;81Qq z4Is}`uvz8`sseiYH3;PkMmPpIo@^*ol}Q1=>^DKaMBs))cPamIYrx{MVfylBWiDi}X&F5@B<>eB)_#_A3OQGz)m)*whsLkwY zC5cFfx5W`At8CxMMUHyrA`Hpaw?X~`a}YL?lN_z3K?%0g|JrwXmjj0GooKj zB))R&{@`Cq+n>M(sBY;*BDTJ#*l+mk5&c@+|J^wGx0zvZ4I-jQ0iWwhgH>t~opRHk zcF{1T??FMU071zD+uzCdLUYnUl%sBg{{izce4MJ+7VWGIny=RGM{ z$z%$tsnDh1`-P$?)s6Anr^|1y@T;&w{jQo?#Ba4V!a@PFDZ}s4=*11UyU(;Iwk(ar z3@0l_ihRJ(3^emh66u#__=jp|opf%E(&=3*-DvGXi#Zw=7I~%I{0yL4M)ysf;mcEW zgD=r;Aqt{w^8a}gj3%N>xdwrq9%-<`LQSQN685;=0IXOpbJb+(=w_|gu2A+!#8ibDSBqRN{zRZP>uTN`#{f(J7TYMaV>=l({ zWkwB+$91VAGoK3yH8xUH5#wzj-w0T+l<`ryp#D949KQa|oxhO!eq$nUOl4%kZ`}SBiZ;W8=e-X;1VL2_ zAI|~TW3ft8x{6lK0uE$z>)Y>TEh5-cDz^Kshs%^_f~LWs{UbV*1MImgUWCL1jW{^U z+C*kMnfJN|ef1|K0WDnrgmKw+Q_XOhc>eg*z#ISX-)*=RSssy*b!RK2D+AS4&;t?B z*7VzU_kU(eH;zT1bxQQ^-#dM>kjBU2P*IaKP08sCrDj0lh;(r7B@; zsV(3`$wxH6p>{3sjpHy0KK^m>T8;e`X3=Ho3KyF3mX$to;K{i}Z^>!2P z*vDfvRsusR65wmIp`}x0rCs3O!)XMHCdb&-6X56E%>;$gGST$)#+K>4{sQiGD7!H5 znES|=QQ=kis)GTzxZL_+QrwDEM*cN=KqG&_!W{qDmak;o#3yzvsP34;XwH2vx<=cV zQaCGpy4P^FOX9}m2E|L@4r%ws9R!XFMg|{V-mU+QD}PY1n*bilkNqWEAc*tVjEmwi zA=a5W^uw>^E&RatleE_2%-%k!Skd5O|7yd!7Nhqm9<}UFC{6eDijj zW=ry4cEsqcsCU)8m*(`R;PwiHebVM|My`wG8#D$__LCM2>ik2c98drQdE7CmQ;)%J z`D#M=xR)a##L_be{gc=OMW!8IbqFgUT>6m{RpSNWV}OW(;0pexn_K9Xoc|ZP!j<4R zKR=%9Flz{P9zIjLm6+RQrN%U`e2QBqq!egE1sS1cUf2vp-AE*`OR9&$jI2~Z~*z=-i~!f z#7E%y!ra#%AS;d75?wu%l_NM5?7C=Zh`ND_-oGe>iyI8=R0PV70UG6Tdph9;j(8a0 z3;-vwG@0lQhYm250{R@g?Sd+XfHq`A0RdWrTxjE7UYB96o$*fuc1iI+1DMydo&@zy z8-q_yCk;Y2fy_x7DUgiIAMjQ30LTtX6NJFrf^!3m{ahEn5^FsmB|>Xi?xi@!~tJam$ii{o$mOz*|Qa#wI;mI&<|TV3iv3sH4L8_ri1NspiUOd%)m5RT?YbC#~|H%`&s5bqT;i*IdxR4xaH>i$T-vR|pZhb2U);so zETe2U7l>)GZXCSWAd2e3(KWt^h$c5R3vI};uD^%BRowbhVo!%VeDRYQl^(uv8z?n1q^|8fXC(WKt^- z_We6kD#rum)h8;pv0dOF|5!1U(v3jS8uHZ_>)Q!H5e51$h7KkMhL7OksXw1{zuNgL z1G#6_Yb|^K8&a~WNN*}4fHF*lcfdlk+4wOo1qXY32=xFkxlsn1U7)cCa=Hyley3va zQI3vf_mTnkE00Q$g2xvS9=d@Il6HG=aB!x}HGtK@_pJ-V#K!&zrZLRdQ=hnjJhp1V!s@-}o4p(J-PJ_D_T4JR(hPmrLr_b`o8ZHL0 zyehF>r+#+1C}(V(c`P~G_6so6hEW@0&F>qo-jPa?44qS;i=V=U`ntIehe|7%f-T-D z#Qrk<|BvyBD0G4qw>0z)FWY>ZX+$jai1m>Cy>3z!1;PTac zM>|}^s6%TF+BCkXlK6rjjM{M_&e%KRzjRGt_`j@Z*|L_3Yf%Xv|L*wtMXkHyX6c)f z?2BOy`LQg%@yLZzSu1cfAlgQ`q)|!xCfvKwW!v0=62U*Z-2?=1glM1--^h`|8xwurQ z1zbYGVy|KY3ade&6b6~?5ugvIqmx4X4S2ehNu0sXOV2D#L`}Uv{C;+RKAGE6Chj*i zuT6>;X#v2T6=ukv14$*Q9)7pBLck%x@oy2BRDn?un0@6bogE#=#Ke&2PDvwLbDICR z$c<3+^|AI2oubeI9uiSVuPqAlCVo`>$Yw%P%ooqos;%sK+F9h?z2})_;%>7N!2(9p zjB}e$iO9&d@*@d?pHJ=0_SHU!(*z79v^IGI-{o&co0(lu+9u8sV~X_zt{4gqD=B0D z*xHAngg52I$2O0@a-R!dRJ`?$@%9usq`ac`K8uJjxYDxl^mOdV%h@heYEK{9!P=3V z`1T4T_h?Qj=uhE}K&f4(SAok{MHx`T?`!KhJ!>Bu%}1f_`15C!=@?-#b<^^{8R>Vo zw2C?CS41tY3tr6okyf*q=be&zpT}S2A+=jMbjZ2e@02?m_znHS1JBOSXHu`Cqgiyl z6lg{EYPXrA+t-1CivTFqf=GU5=ae(at6F1Olpk9ZSjyyFd$00#OXz+uw_q??}AmeqAEOXUlO~I=o#mu0ijJ;HXrhl!%00-@m(; z-`wQw3g|3hV~9S@{6Fi1FZWL0Sa_mVE7Ff)#P}~uFCCEK-iLibp7WL>x~?_ouuZq( zI7k?;bwXQ?&jE$`5HK0aS7ih-)Hd{7ARtL)NTUcu7{Thry7m`17q)O9wg9PkHlC*h-QaTqzll)k6l6(?;Gk?MqLi30Yr{uJXmpUXkDyHMF zrW6X7PC@X;jd(yCI}r)`YuFkNsr9oGBx$EQ&wv&^bubaJuPs4A_=d+Z{;z4^gcY3P z>q$lO`@3-%bwdvUBq#o#wg}-iS2gDr0J=~vCsPpFg^h{10FJ3Ayu2|fDUZSG`~X09 zM%8@N1AB{td1aY`j-P+}ksg^9Fj_qtg5lTa5PDy;tnkI>0y!f$in`04EMf_#N&asQ zKVilOlVTHK3RHhOt_edJ+B|{8zuhbnJ_gvk4LzD8K(QnPGZ&e3>L>r&kYpE=mYP!S zHNm~W@rS_mfyELB_;8>#+W(xWYteu)Y2PCE0S_n$qeAR;A|wzDhc_~-lx##xq#*nxlk&sq1%CJUMMIlqc(#AWAA1T z>@Jb;yYr?Xip2jeK@K;F()-_!_f8i>a{z6cY z66Br0=G^xMsk|=q!O8(U-lr8X@B;VZwf%pYSinY90hA5^ZU8jzP!X_fjLT{ech{+o zGQMx^hQX`!?xWI`AUJHw#}SZiMsM$1uz8a5+UObh{g-|g$4Bo&^Y2}ACFqGDOb4Vh zvw|`*{vMfZjQjtcgoh#WH@+KN?rIoe%NmEOI*jU>?YP9fLZhGR+;7O-P9Ni6up%hd zMXwdiUV{!UjbYb=@V_4t6Q!V(`nPkqWsFbp7XCJus037|v*QnQ!zmWe#LT%oMO|&i zSNd|zjJ>}97&@zM|3%>(nT(u-D&Vb^F{)K?s_95sCnR{iQ>NuOrUKdvgQ{s)fQa*g z2?ZE`Z}b|M^}LM%YYnl&FRriao{Ip+0aP-*eKVlTi5%b84xF4~fvp}e7!$L22T&u; z%1>rHgUl~7lr8ig4c<3*6nud??47=@tENU}LvbNt@zSvaaU+NF{{>jQE-N=HDZQ{* z`^K=Af~n#yaIPtsi|NFo+B6m5QhI*s7I~d$b%@lHt_Q&|t(=kzYqwb^q4idG>Y6-X z`!>Jstj=EDAfcJ87G0!wnd-q}XbxY!YeP;Bw%+E?|H)R%B5|n?{t?=QT#^yh;KLKC zcnMs~wjLS@UIYJ4a{e#0Ccr=q5F3VT>OC&)=3JJ8Bm=Yc1uj>@ncoe9(Vi<&+&) zk;y-;6;3RTt5)N2(R>3XRrfB%Zl7Igd`wXe6PcZTRNsi=J|Kx(6729W8{U!_{=Up4 zb$)5pWe5&yj1`61^v;&>ZVYK(tFbdt#5R(d`G&vPvTycWhI7sBj40p zT2&Dfi2{bQs z%4hPDY*ZPn+DoU$mBcwqo2exj(=tn%sfd};;c$5bbF8B#fnc-g!^`!8EgpAG_by*^z4 z+4n+G?dJ{9)rDI3(Ej|<>Tskm)0YO2Y)`5gA#htsZQ73Epy)hkG1;I zkl?p;5PnA2{IXd_k8^=Qz`-jSr@N=@d+ah{^-bw>(7UN@$NW;}$m8)l>MOO?S~Ms(@!YteDtXG1UEY!Y|(8;KqW257$Ts*juuB zcW_(#B#%$yWrh%)SJp@f%j;?NaiUK;h8&2uzquFQ+tS#2~6uEP?D^Anj zMLgyf<4E<$ZbRk^*Q;k0#Kxh?HPJg9^V>UrsOcNw`reoB!YcD;)uQ`I%Vi*I4wh6W zdDu+Sv3)t;G9RVt#gXBTTJMp#bY#jJf&H@Sp3n^%6&z9w-=bZ-w}n%pL{x=~KF_{7 zz;UG4<#e%r9w*)vnRx3qs;!$o|KZ`oKU%xASSjyu0}|R-g3oh7a~=~k_i(Bp0W?f| zWx|KICC(>>5qPk2f{iX+bg%b&$G|my&1H?Mk?-i6Trc06%k&dpm*Rcos`;vrv%U#( z!l+l_)R6w1Wpz!560W5u7t$Il4D?IIdn+G>{+`PNWsg?yIcrSp14kC6bgIX{vruG6 z!APW(%a(?E-#rerRN7|*JN-rt)QV-!jcM~mJFRw?S`q%RLjI;00)ey&W<^ly?6liH z+r`gN&L6+}Z1iCI%lhH(1Z@CzeG-#(DUO853whhXJV&50h3-1|lI#7KcRgU(r0u3p z0Se~(>1Mnj6Q$LZ^Hucrrg4d>o=%d}$Njk;BS9q#hlG%f?}xr&q=JvXstE-w#h>2C z`pr#2>+3TWBVJq zvcI1Y#z`Ytvb5`hz&0e7!%BOz-aI(i}`fm`i|jq0QDPJ#hSO2UuWE zmGwOSJ^UMtn8C-?|IXRhC_n!@ewG)q7)Gs@gb0c-nM7|HX9k4rYL6`WekwK1Wy=b$ zY|Ohc6tLW?L!@ton6JqNZVs_GeyEAae||NSdFDx(f)q$Q-#swmmU|Qs)BPivZlc!n z3r#k4_d<1vZUUxlhjN=c`g__A!eaDr`LEYk~E8Lz%l1?J23Z-G%jEK+npzKlLKdXE3O)yKkivjvO&Wt*Klbj}=eQk@vWV3yb zHv$))pS$ntW!}thF0FSjBw{u#!bb|@MooLpE2_thz&AEZXxD6WB*}KyN|DE7LNaS5 z@%P80R9Up-{fzsBvE!Gbrz`T|r{ljOLBq{B!!ua6;wgc4x>|Fe5tFs9aYC;MGt)7t z^`O(j#R1yol}nQEN4l}>{D@u^w^Q2mccU+KT&afh<5Pkns{Xstd96zKij`!M3c|Ge?v`=_?An#U1*c{%vFYx#XbYez%iye>P|Z8F%NTuMa5~@!L3RH&JK}Hu z=5Czis)XUV3wBlP=QAvZ$#)uz;Y~-DY>#9+AH$HR=0vuBqOBx3-URItjYfBhCes@^ zQ0Ro(N1Pb!n^~;s1g^dJXf1m0RZvuTFvD%Zo`az~-mTY8cZ0nO)Vr`I)$oIpO_7#M zx;qwBi!~v;eybNy)tv`>tE09)dXCiGZ@qH8v;AQC0JaxKf3n(MOyR*5C^ZGulapK6 zNy~1D^U*`>d`G`#VF@+mJ-;kDekgE|v-bW0?mjY()%!1(qR}=k%aUz@RTN#%GZv2P zWW%V2e zz~ri&4T9Y`8IzLBLj}%>w^*>UA+g?2mV~YlAQArHw&94|-C3axf6EW2`l6w6T=gWN z+C)Ma@-Gi!7QIdE3i*>@AW);vo^$zQX6Tv}LAIgwrBidNFVjN)Q$_hQeNW{jep3!( zBD+%eX@*XdhVgVB?}Nu}*V>_|owFk$WAv8_y&Z~w#3!iN4kzMm^Wx37fP)_xn%Xdf zT*i37Y2pE$0m5XKnL`BO;Hj#rN+Sh*Z|Ba1uv@PZ@{W0BTAuMxEJbUJt`L*t38k2k z;jjW-A7YN)YuwR#-^|Rc9*{*r{01R_o)CVWcsw)SAtCY^SWOm%HQ%JeX%7L3K&4!^ zMo}H8G!Q}>P-t?104d-_j)v$FfCN*Bm+!rv|jMhZ}XMyCYkrWqGxzR<2te2@7W;kH)M6e zZp3=|5yIM%vKhTi;J;vj>Bh^qya}&Jf?Kc_Q1?HV^m?Lo=}-G)wxr&L!*JCis?XMA zZRA?CgOxW9S?%nb=(_dfqrZ#(z``OS(e7)2 zLzx^uxY*m^Cy5XZv2;#H=1pj%T<7C7e>*LFe{p$(J}JgNP)e1cLt|ybtYmNWqfm^C zw_Z_{1Lj5>*uMVSY{?=wXz&^!CSJ?2!CBYQ)b7cQ{Bu~|qLD0V)~r5HLh`cPneIUu z$~-B@mu;RvZfNB60Y3pn%zIHL=U##1?7pGu?}6#|Ro}4Oxso{M?O2)k0|7bOn%G2# z`(Ofs1LzPA%+sGL1K5$+K^H3^AY)ezX2;>EZwQ@tW4^eNGY%Gog7fjxN&J}cYeob+ z%nOEKYH?g1!vEIoAH2xh@mYrE`8OLx#a_{zFg$+zSR&&^_KTE-Erzs@){J@ETk<7! zg&(!ax&QcUzos7+^%-=R#zcK1=4KsU(^DJfjGpi}*#X@8^@LHG_*SXKHRdc81neXHBM8#U$IUnP;uq-{0 zb-z0E`}CQbOUC|z^xf?ZItq?ZDoQq%SH!Aidi}x4+Q|7qP|N(*DNI@A(R+<`D@aPF zbUd^II!B|NTP8)jM**dG&k5J9aaGw~ew1=7z@xaS$CEusZ@1=uOhZ2PE!M(UYi5iB zMmmx1H1nHs5>+_=<=p0pqKB-&)2+(WfNE4-XZ!w>U-bp*7{cZ&5gBaut8I99T82@- z6yN`RR~*d;oIvu~_#c;YpI;GR%$1`G!(*#tQNh2{o`Fu0NFH1`N>waR^!-V;lexre=(S7t^Y=VvV)K<#S$9UZ7w3<2O0)eaa$$=od=WWYia41l^9Ujrova1IFq zMivjicmR=X1^jvA%d-I!KN7&tN=nZRf$_6BD6mX)zx+cmA+rYv>9OtE;ADmgy9??P z(IA$u31*8eq?U9?3Bj^+J2Nl-?898poW$wvWpFKXQ=Z!s!Kj3Ws@XNARhw;U^n(cf~j zf*L^RLdavRtgH~43J<_5d8ae-84U*^>dJ*+0A0eHgdY7%W#kQ)hJoCyKObK5-no5V zE~>&pS5{dGtF=nwCheoA#vOCMK-tJ;FXu+S7iLpsKD+w!6^FS~Usco7blfBt)hznl zMar3gjpOy)^zEXN_EOI1`lON6+w7cy!;Ar(Ok z7UyX=GD)ryA3Yk2mSwX4R?XL9bKUU5G}oHT4{MBhcdl3mxT{d~^QlCWDQoQt$NP5P z%=#!UW*7Sme;5-kQudW`+lsq>Oo+vt;RL`PSnw5hSb z*0uOPE*cN~-Vjwl7iGXX;cUiC2%WCG>l&U`hbwk#Pu!rCaRp1F3sW4PWSj3jbgCEB z7G94v1~)ceM_ZF;;}4dJY;%Hk62LNWzfFx=1Jj3>)nr5WScv!5au=6ZulVG%fYW5p za%m}hcTeAb2qMD(REm|`!od0g7&e(qG`b!e&$+HsA~5Wk*;!Wzj0*X@W@=JAwEzCC zNG1hh)i_SSf0&zW7z_bq+4q+O@oX*iMn2CAkEk zf31^$m`b^)47R)j9BNU+`6`vITC6Nf@;5C*`<+wQ34NF5p9TAi=T6h|y1@g-FTHQv zU0Tb*B?SE`Tws8)J*fzhe;6B*Tr3k1Hkj+AWpz5+(3n&y8b-^&wr0`$RS)Yt!20Au zWPr6Fr>Qg3QesQZqx{%53!?Hb7%usG`8q7ZMAQ7)pDnnW?dgDBu^O+n&JmsE%~T29 zwfx*HcR1sNJwwBphY$Trb~Asfd41-a-bTM@UJ!-QZAO1&e1$DGU!S6K4Qi}2WSpTS zvOIo?WY3$wGcD7owCkDEGAd8m^8`35*?XlNoLM(0R{-A+vB+y{ha zr~g_VEVM9bsm~kJ*k;ndaJp@3s27XptB8-+WV3NQR^|@k85CqGI=h|h=LmN%r3!#!a6)9qPV;!d^Kr zI@0rMcWAA`^$^O^3#hw z6pv~O_1PaOMU;#l&8SCZF0*JszhF1dn4QM9?fpvxM)c#DP0(KJ8o3tG{Ds~VYQFc+ z)HdRaJ@w-xyp9`iwpFv?@gCa3pRInsL8)}@A?{cZB1~Xb2-xjBnHU%DvCjTq=1g>U z63B^0{J72OSCdqny4J#voz(7~3yu@?ozEzB#@VkDg`m%e99e5E~k~u>H@AWc<63 z#19seu@&DW{DhX;76Xu~Us&a~!rr_$G0rL&XW=&gNq5eCV0XG~%Zu-=Wqj&VJzkrX z#$1WuYyV8{OSH%tZ-C%$n!9Rwy5?F7laJpL-`7{eUr*5UOjS*|ROIk@!R**N(BW8D ze3m(R<35grgrr$9PCPyVf14VCjaFJ^IsNUw+#tk|6j;6XOHq6N0j?~l&A`jm*52O2 zroX;k0B8lefG!ZpUL*r+`y*)MqXuvRI~+}}#RToY{6(eCK^tNO^plVs5n0G>%)w(IUexITVDk(88@-ESS7Ok97;V@wF{_o+)NoEG| zeDvyJWiL@wxtbT1DE@#+u3>a53iPh3dFyc1k$@qi76ofe-uV^zjg6tR9gLJu2hZ6- zQ972K-03Uli~{DOoeFJRoMnO5t9Adr!o+=tA&qrdCcyWjm60fufcgz| z&(d;MGt(zvnxAATKb6(e$L9WEf_rw7I_|FG%r~j(E z7j1TUa3_aeb+6CMKX|sQQ=4AAM{R%mlyi~U4!;piq&--wLieJrdtuKnOPBvu;NP4h z0!Y%e#mQ3p*)O5Jxu37k+|`g=t{j_LJgQgKTZXK)kFGwVdu6_L^#2rXTrf=MBy2hI z=pGl9JeS0jCk`M+1`zol1c;r z^K_W8SGucxuIo&-j?INcTO5iFC-FDh$;3jWNNLJaA=JGRD~O5h(a~j+$%$pdT^`J8 z;|$7m-oAemdluf$GVpXT&-JoD{g&U(tZtLxNp(m@f&9fAtIf;L8lF3v4J;<u@n2Uvu5scdI(r#x`$t&onbRVWY zZ?9+~a`vqmuY=N`ZbVANTtyt^&H5M*YV51Y?4rCv(T-3QuNWVvtGbK5s^MGDWv5@e zCF>Brb4uYGQSXHdep^z!~^BaKTH_+IdlkG0$z&*)4tsC*yl);6qGD)uOoL*tnZB< z>cFN>ygo!47L6FyXue>Xl-R1xbLdTBiHtXSVMQhSg?0vO?39{pX^m7Ydo1yS%bx>M z3or4^l-+_ZDof=zl~sOPsPVM6(vcA)o7Od=6I_b~x6Fp5OmVeuQo61Dw@JUJ6SDb|j)pz)2p7+=)BzSSHh>WkzrbnwU>=ilToCbQNN*r8H5!EGr zL@#Jpe>$radl)<6@(zMu^mI+D_N#$8C9yhnOw&G*#`PatmD7QDMdPg-V{S3WYB6$Y zLAsim4z81#1)7s+4mfq*%Muuq(Pj6;3qOw6O4svxu(2T}n(h(;{D!)MG(4dyasBRw zy!J{;|MDkG_0vVUS6@$_jq-;GncL z56@eX0T!b=Tj&!K@1B;dCN*3n%lz!hh|3~r7sL0$L0`*0`q>xLZ>?sH^@olaR55Pe zl3Ej0;Ytf#$JEYFv%fXkHJbxK_ldwa5D5{$?tXE7y#quG^@7*TFKK6>M*s_;8?+1C zRHg3w06AmSu5*Ga%ov%O*XH4ORbF6N29xn-i7Wpnq5l5pDH7rblc4+0%55hmwtkj= zo;|j3Vvbm~F1bVzGU#ZXTA)h7-MfRKO3Eu5)vO6gkjnBNSkO_%*eOzll`c&6Ar5s!$KxiQC&;0iKtAE<_?N%w=1G1}AyU_wT`WkmN zNWQiR=6)~GQ2xp@V*FqS`NAR5SP|NwOg}i~B<9qG-T>$Dl?kPU(}u`{cWG-|UW3AN zLktisP{rms1~=sp(-f8~O>oCJ1JVc~jEsuMG|E(k{9@R2ZptlL$JIe-d1^kh_8b25 z&O9Qc_K(3tl!j8{=Bm`!s#%Zr&{9$a{36HZ=T~kD=qD<7U#v@g=60u}bIb`tj zrlU_*yT8^GNb{QqCb6nuLOjWfndN+kXKE@VT`*wT}1~J-$1?zJm5Ql z#sx95ALD0-Ap+(Oj*rvRehWD+E6EE=fZZl3X^rwTU^LR8gMlG#<8q?7xR%B=gA*q4O`b_;%kJG?!Qu5pzv z%OcLHkfKZT?Aio8xKst78Eu^N;A@|U?VLdsrC#?k@U%{hjc+3^I@|zIqt&ZiHitPH zG2QSoAY}|a;)U9eQo&rSPn+eN$254B3;(NmA3f$rctj^S*2<5=C)sq3$QGoV%Q7ZV z)@mu(P?~J6o;q1|cTmjp7G&&;y-{SXnXYilvpl|bZhc9|ih)HYN9NV8_&3E`bl`HR z*0Ia*b~3w2CH5O!Jn>2LSLM^TY^8gcIS@kz!~SFV^$j}2nTUU@>C)d&~=QU?PRC85($AIlG zcwuYwP`EJAd^4k*q`(m*hVd8U+uRlUOD1Lhyv_6G@rGm$#1Th{Njk@Jh!>*%OZ(|2 zH_oz?RMaSH8^X{&CMBr z&Jwuqqk4l0*a0934FaC0+evo8-(%n}g@{}P$y+ZiA+TpZqoMhV2q^^K2F(d^Ccr$d z+;Tb!7z1ct-GQuIEzi?2u$_<9?IGm2O;}ds@G2+Q3Je6QmF zs}FV5cmMmr&t>|fm97dw_Cxt?WxY59upWy6>DVGTG|paoRC zOm73|;)H~Rtsqks5v~C!V2nV3W_-BRmbH2V7+Y0;7j4+-rhT6L(H#Rb1UcYy1Jt+8 zv$JRNV}NIhf-u(ryq0Q^Ia#w7XMxazX?)DdiX5+ny)fN$L_BO_2|-#Vk*fcG{Qig- zFrgF`A0TpRAi$djqOu`?l0@l5-TN&K{ve_~!0-N29v>V$1_2zPrwFFt6O)$4va&J} zHmiudLD7Ep)J2*V*y$JA5{}g)CPl@=#eSCcC zfl~!8Df<_&6|e#iK`(HyM(M;M7S$JCUunGmd~Iy|Co3$70Xh98kawqp+YRh|s!qbb z++)5+Oe_U<9gr*J0WdAF@b425jScr8xQAe~<^7BFAN{Kz3mBM#&`+4Ku&~?N4kWFr z`Ut$8r7Vjq=Hf3f`Ug~M@}=eF!=s}mFiWN3j5_(csOXd zb^UwqC0x3Hg`ybeTfq$!qq&z2f!|b!Qs)ak?PUKvj%+G<5TaC)mf1c1)npOLBc7ex zoPBefc3V-c5M*~k#4e9E@Sh_SSQHRcA5rv00$Ll8u!BrhCf&w_uQHulM@}va z{{P6xNU+xKgDaJgKqKd|GMuY-)pA{p3?yMg24*K<%S0%pH60pca`bweh*{9sy`w9} z=c}&-v@`RvOU3HR`1|=kAB__)44)&b*_@}?L6?TwqY)+WS7P7uChWNngP*~%SSwCm zfhGRE><2310LEO5sVyL|A=v2g{vM?hY#$*x>joQjPSF)_N>^I(`)h zLd{2YQ{kyVSp$Y86BX*pdl$%I2+5*k?%#pr2wJn>Jq)P$;T)xtzJ1#!Xh2A1Ib{bkgCb#(M zOM<6#A2H8S%hMxURGRd;x+C}5nD71K3Rk!hGH<;4bl|b7RMom{<`Cp>SSNb;h!yp2 z34FM({5DA~&Bw~6=kQ>TUm4K|!<>Z8|Lsj%yk|%o=OJDgNGi zd8jwGBwp`IeSggtKh=fpRo;|rg_TDxHcTUaW17F!>jWX(@XZsQ2{jo<6sue>b5vSo z;bhcmBouzLtyuAo|`OKimvAXzlvned0YBsX~iXX!LktFiP zT9Y%bJngwEa(gLp=#n3UajH)-LSc3b%n%0HEgk3j=T=>t?5Mg zSe^XQZ7F4D1hGw>%7{b3sbt1zL-Wm6<#mK2wdw8#w3V~CSXi?j_Z-*)@uJh6b96uz zK0=8{HEUr8O!A-lAfesY(y`My+S&Jh(=YpF+OPk5e&dlaO-eLd8$m^hO~UcQ7bWLT z;8v6vKZ`5JP*G_XC#v~0USnG~LUG&srwED755-(}14UGZ2(rnqt4S@@9cWHQ>b=jG zQ0f-9?~6E@k!`m5sVAS|NV`rm8T1E0)iM1~ZY|f?;uyLZ1l#-bxeOzz%78;neZ-k) z6dt3@2Q<;OeF!Z*hx^6$>RM0s#rEc3^BC+i{H$N4-nTVB+`1O!E!XmUS{K@aW=-h5 zDL>?$UX|-ooNbeFhXyPcs{QoZMe6$z_AHhxgOyltfU83*^`eWETNbu?johzTAU zIJHsga+iy&(}oXMty849Xtc|K;2ljOX@^=l5E? zk1EmjVAcdiHRnXGPqq|9u6w(U3C$*jJge#oKpdg{`u|Y=CtqUS1~EpNdXB%0`^(mj z&%;|3{F^*eF3rU)<3lh!xWsK;6PJkY`>+-g2X1G?Bx6oMDLKWpbrW@NGemTx=Y6!* zUcs3&n0Ipt4wmDMawo7>rRK5jW~QK9tAHm%gf7`|KZfR!JIN6X7wC;q6xC{FTZ5y% z1pZ=U$=m%)v4)mt?GM{Aryb7|m7*lep$@m}wP=&gmHOQj1);q=0jHK|+&~JG32U(q zcXh87S)D1~Apcx;+3V)c9+#WXMTbu3WoGfAHUwqk?+iWTERk$@tRu2`l40u;RZbY0 zFw0!(B2fJ)++JwvLBfMr$IPJt-t**a*5UMM@^iKEsh*|r0v(-qv9G^G+V4Z|3T6?3 z#bV{Z@}#Ji8|kIrQO&beexHDs1l8S*_@&d4c^*~|MJPULJ{^+}YG#CKYy&>@b@Q{B zd6PXfV_tsi3DREd`adsM`i07B*cX{2O5w8(_5&uDr-K;vQ2pT}7`jBT$;Yf~%6=10 zm4n?owb-)T`qkJev}I-RPM>Gi+N{AZlrv9p9gXKTjdF7_k;=V z`BdVp-U|L?MfAcw7XqbP0bK8CA?FIAUE=uWYOzB-__<1=Bh1FtkAHN_U|xuGO=`Xh z{gjau$Ds@oYFv-rA6;YVjmML^F^HG#=_F>qs;(w);-Ue9`{krjuo0Xp5KsiSG2qCLYd&eM^2Tc z&9%N~D8g+Mvv-&c3Wk|Kd%IZ%-pWWE^O)yDAC(eSt@EqKdNC02&CYjaqY=7_vox#TaXI92V0>*M>ww6Y>{ zHTiRN8rfz%CR~fyQkMmz7NpD6obV1ZL2ypL3t&Fr{8UR7vF09v#L?`FKIpqkmg{{9ZX zxt_yt?UFk0&hk@U>Ad}1{8k+!`&dDP&Z|whPwEgMlW0u-ut9y0M{8~IZ;FI! zR=2ciu3c)EVZCM=GhS%K+1lVP(1NKYq*Ld1ga7oAn_P8pX!RK^CNPqBs(FKwg$t8dYZMU?f62TCPKVMFb~_j%aEPNd3BH_;cxw`!Krl~C@r?Ga4pu@ z6TAMH=eW9#<+EB;^N^P5JegHPvD3_nJSTNg0piXSV7bT#tmUOB|8*x3H%?B~k0$wd1Xf|H)Y!~jR_K%%8;96WVxX8jdECVnPz_T%8CTc>k?UZmCL~`Y)6}(Mm0Dj=k(dP0>I#y&r^)CTlzP z3BzCwnFR@0TFB5l7gQXpG{-m3zB{fe!5=Q<8u}9ue7w4(jxD?LtmNLy#agx;m+CrN zcb)Syw3F>H*`*{U9roW>XK;di0@DJeNW}o39vIY1U$SG*z&E&Gf2W{EJEI~P@}sH} z`W^+?FZCuK`N(fe^0J{zIv)mDu;K2Cb!>z|)PGGdQ z?;aa1#gyfIfeACVPD(9MV!JEYHedj_FpR%!{9q%_w)R&k%v;l~F$D|{NWLxw&lP2B z4!du}RaBe>(KK_Ew@gg3{o*cIQ*+ma2Ir|g2w}c)FcRl1>M}KuE3xo)qZih&d@I_In@yexs2+8gU4imwJFybm$ z!B)6L@%+D~s_?8mM~Cva1vN`?uD-1V^>N`nZ_iEEeS&FQd)1ayregyF9+LTKuNfag zb+mWALRu(Yu@%c(nG<$lx+NxcwU&aK+Hc;9(7}$ny(Ty0`bh;XY((h29rB*Eip1Wa%=`6y2{Dt=LUq54}f8!BpQ&nI2FL zVR1H|`;w<}aZy;|d<%~{x-U%OG4kLB_9DMi-)RX~XV#%ZdYwIvK|MyG<4B-0uYyBX zgx;6N6#3vT*zaWvfw!xBQe{0sJBCxb_#5h;66Z?6?0u~%-KMf#pK!^t(w^WC!6D}E z;km9XIA{LvVPt)42~eL<3{Dr1rmMp4l|2ESt;05Y{PM1!POo;4^VYY|q)3)&Od+lO z=cY~v>CF4yk0tL69<9S0&fvRO1eEhGw(RJuE9(dhWQj%c?g-KBzYe-8nw#S!k#to0 zautgcit_(Zbrw)jg=@Gb1e8`v+M+|c%RmGqq#Fe3W`LnLf=YwZ4T1yG-3PVP@}t|M7nB_q-lu_i4_{PYk8PeocsvRQw#t$j^Rn%$1p)O+L#F zX`xOyPu*`{EdLn~5B!^)IZ%P?u3C9MY`sa!*MD#pwkWQx6#O?z&*N9q`K!7~4Ii2} z${3mmsU$7+_PP4#c5MaL3gLP-7>3bg9QS)CT+Y)xp5YO+fCGg>kzOX*3K9JMVr&)7 zj_LMyh)7Q~XZH~zf&7n__5JEF&OI6f=$~h91jX|cRbv+88-VVSdwDCrFWHN083|bbjBuz1Nb~8ibV7*9-dbiKq@Ar*l?b(yX^Ha!t>{QyMo`({H=Y^B654g? z2*buY99|Qi7F|b>l!jajm)R-re#fg70wujwRV!8IH>ySjMKDz?4mAUEtno%Mh z;Z*yl>Vg^UmVZfOXuel%+hLtdc-R@-y45q&=>10)b&Yr`#MVqQ$LCfJDdc?MVCo;M$=3(F8n7({ z#3&7*FTXVq3VxX9uH$75)k*d!Y)!VNY2GS={SB4Q4JFD=-lW~~7J+VwamT0n(djgP zuLE(6Z}FA+1Hy8+ff?#%WdF}*`E|?0ow$bFkRANf5Fav#cl7jbX|uIGE%1JyfUe%j4yEF%OiOPnNW>9eq3+S@l7^sq6a$}Y1xrR zU$EAw#fqH`L_7A%z8gFm%W736KqVc9ZINZ;pcu)YFMLzlcxf?YE;%|{ke|&w8I=CX ztJhP3@+tIZ)(N($;1`^smi3aAyM zuqn68Ry`@|(vkKkCD&MZTa_@(%i0HI*>xRuZ=hVnmh;I#Rj>3hAs=$%Lk|FYgbR%akqL)NV>n;hRk^1N?g znmxgcpKrAv^~PnFB!TbN|Ls924Sn_LIlFdx**BLQT9Q1b&bKWs?J>JMRWtLH7svXn zBTxuyG&|TST+#h={(UCIyZnITQ726_hqwPD@RI#2p}xxvv!qP)N*A7@Mh(j+e~I?P z(vt#D9Rv2i8&d)~2^2V;RHx=Xf!PyPJ~{Ar4a@i& zVf!m1?uqrUN{h2kFb!?tP|c#4nl%(f51SPaz3m1k&m%KlVg-KN{N0nv=}I4m7)11V zL7DTzxIv^Vf#gH4({5hm1^`Fwrsl{F8bw9bJYxwASx_47SzlcAu*>JHk^C$`7NuHw zGYgZBlU>c;9eB`& zPUsWL%i6sRz;Tw+(~A~sSJG)RZ&o~sWRAQu9bH^G&m&FnTTNX0m&+=S6$`L5J7TZ5 z=R8%CT_sH?g z)+2C>{I&jbJOvZ1ZToZrzP^Stwb{#S;tB$OamrcQ{bkIad>+~Cdl$dsZy86O7Ena< z29*;ojkxpS!Hf2FRKb?d(i5`MY_#7<2QE)pqt~D-TChS3zSLo6-Z?@u1uyF+|B7d3 zg)5~CvMKAiVkQj6?48f7mO3$KfBi|8Nk}$E;tiZg<)#xEkrnx;-}MsFyrtFm3shsc ziiXgSY`HPvzF3#A2TYu#T!^j~iEDGEtI7S5faBVQz0^96yyG^^i&}IMm1`FffyBuR z=jDz@6H`cj2Gkl}bPWxO=eT-3YdNQ&?3HnvPsH>+Tt1G}DSZIhw{v-N#1UiqZgOE$ zOIO@`8IOjJ#)sak5`KcoXDE;1`bnu1phNf>7S3bgPAFEt7{+kCM=sP5f33QAbMRKq z4}utk>I95cdv-6&UrdiDSA{2yTOyB`K6Nc|(BJi@h~D=mtQmtUpQI_JpUZ!c?$q&; zaih$W!%L#!*p>KeMjS|3aMxq%nr+vXH&>ZGBkHFBZ$X*18z4S@(M4%Y(B2)WDIOUx zG1WFXxqW+#Py4AsiX(j?DhG{=haQS zBec>~M>TzfB@A83(B<*$26K|L2v%P4V@^57^iWw>pUxlL)>;a-7vGBHtJR(0q9m-; zWxC17ZXBp+WF=S(g`SsTw?8i>F_WvL718!&W!o#>wI&6#QLYL)+>p#+Yv<3n zUD@;45wrTM#UNZIVtT-eqkxx6aTS%<*1cUX5ym5?7tT z7eQg#0b8A;Of)kxLhZ8Y7se#Bg%etGahLFMsxA@5%e)h8=x+1$P;HCN@MhnD_0==2 zvfVopo1fWB<=2{BN9BiT^+exMYubAC<+8F_+iln9X=&TUGWK+tpSAKS*~^o5>3MWN z7+7;1o<-TivFzd9_1d0V#r<*!*GDR_ptv)e0jLw8B9zEfH1q1IPzw$b$#Xd+R_HBf zQMny|!xqGG`=MSOT})GbQp~n`p^Pao;cH{UDAS63PMzxhbd+7CkmOJk(cZwsgnf#< zdac;7$WBOBpzDxjdtC*#Qhf9T6Pw8GXtnivD^u>`(lztbfQ1h? z+jU*VLlg~Mx3Cd0`{+@^4QgqyVOhCa$G)EY0fm9xEk>&B8VU{dk>I_@s{>4>;w6}n zl$8V-ibLlhIP~FkP1R`;Jf%-1LQQ^*oOOwO8-7^ER{8JHwnOw~b}7?t@1ne=>M(i| zEZA0>n^4G@5r&&oDS=gu9E~qceQ869qpA-lY46KX+n7$DaD*n?>B^Bme!bYOzu^c; zr(!OXx)nRVa)D(O;=AaWdZr3p50@PuS@T_g=JPCB@%4#6^%?VKujO*USgjzJ^)_YP z`MNUN>c1C~sr**lL&UIRN=fNJz*-oQX*O!w7caco`XH$}q5EiCn$ZA%TxW-I7 zX=XPfHSMHM;BO5c*yPpv8O#QFSi}_FH z7PEsGOVpz8UR-cG-(2yM*HjF9(P9!*TzZk1COtAgR>IHM`CSdy|IoA9r`>xW=nvm? zZ`-)YS;or@#I)-#{EeSqr?{<#&oFN`(x3n}wQ_Gpiqah>`QDkyJ-+V$KdZ@I<3^&N zwBExk`z!gW_cliHP&byE3Q3*DuSKb?V7w( zzH#FU>pPt}-G2C&+s|JStKu&I%lBEr1)k$S=0jilE1L{QtL08j1Q0`r9G)ys~swxgLirgOhNw5qhRLn= zAG$(bvAR?B9r?RAm2&ou-cndzKTz7B-GZ**R#wp~a`XwEHc9)@c_5uluhyBzyn;CN z=H`$op-fd(tq`2s$1jfC@elFwW1TBn(pItpHqRV88EZJf>5%-Saj{1pQq|OIz9JtL zNW87C!YS1^dm7Zu;^ij#X{C-6$?#ic{BQl2``QchR|Q*N*s>)bb=%4&)c5hs3#ax( zScglS`Kx+7MO{~!86DRD2IDr*{b%75Kld2Cky&b&kOxLTrvF4<>2^8KB<79@Z_(pSl-Um4veRH0@6b0d;YH}EgSzZa`9UuRS#@p$=|79Lc4gE_!bs znVQ0l8{=2w;rlhZ+xY2O;d11%XBNA%nM+5!$+LF8$t8;)lJspZ^|XKj+q`sI1)VGE zs>F@{tWu}FOun@`tLbGG#g_0k^`|?t2Qpg8O>C)&Ti@y`dda|;s(Zsq-MQP|Ho-gz zp&7&vze=5dcWD!azx#K3kZ*0|(kZ5h$nLcGR(F>92afs`Je210XcG^UyB5vIY&uIA z-L^i4Jcw^I^-t{AuL3nSjPd*Hw2xj)*q*}T0^P(j#f@X<~@o8fYW)@>NAaq3kT@;7epou#B$8bya|3d z|F?2A*_{TI{cCpXyFi?xZZYZOUK3!!b676qaf5fmvpL*81PEJJeBs<36;R^dLQiuQ z6wCk=IH#Z(_PYLYUPgo)gvwj>UFMUQge{mU4EP9FQzfcp9TR@+1X496bmF0jyb8Ft z_BpIZ+;y2jK&vtZ)Okh|-ww?2kEKre<7~E*>`K^3bQAM_1Rp_{5z4J@;o_6sHymd0iUPxH&ag9VXkCc#)uu)qdmcK4#e z4ryk_^S6fF-=SdhnJ1J-#CDu3L8_-{5l!JXtQfJIoe@#$56^(PTIis40Z4IGx2VrHb>%J6ut)5>8a^}wW*f% z!>TIxexV;hL29FwE-Txkn*Z+K4 z(C0$LtlX<<_s5Y_SQ}!6d2#m9W2oIP8*X){(HrDO1fPnl#Z+D%5C*#Q@^B5DFe$;_ z%S_I0PpB+cMMhFBSM?|yCR*onjSguQsL9k}NB`X773U{uELC9t%}%bMW=zWtBdZ`uK4g8Cq9}lmxiKsgSn?6CD3sD zw#vZ-DF#wGwt4*HVf-e4-Jk~m8N8bfc0Zp#oIpEXjS+ath?n7LK;YKf6agLUctxaA3&jCm!`w^I6E@!M+^O}@Mkx-kYJTeC{aH#}L%c^cK{_v$uOSofdN zG*j)JVXgGVtv9l1ZIWbedplEWiLidLzwvA*>mdXc71`|HrEngbKI9qqJGTwVJ(S(`v~gwqvZcpHP7(nKGC{a zx!C=#eUo0~mi@~3EwU980Oy7jV!eNF6u^29?oZs!&AEBd^Rq|Qo%X$qD9&$`%d!#G z%!5SFi=z*7jh~i)khQY%RVh$4M{S@6ZVOU7Oo&iGG6Vr|PSJ7h|Gg4;u3a9?YdIn? zTv1vYSy%|IkXVy0=n#QCG5`~h00u=s^E zG;`BKQ&STe^~Gl$M9O9en)LvX4T7EReLw-Ycv%w@dJGH9EqT%b~h69pIhni?{S5HPcqW# zy1cq71*p0JeZ~I=WY&RZ7YrOy6uYZ4d*En8MGi-hNtCO#JW99S%Q-{l_$!nCM~npL8?RJODmSME?Er=PgK`MaH3J z<>r1INRzZ0Fa81!$=?Cl4SdYEz*)Dx&KBOOe|O*=@GyQjS{neJca$nBDvC-RjtfOu70?ca2YhYluj)8myd~4Xi>gVF(GDa*Y?sX*qSc;&jrx@56 zNp+G4n^i$TS*Rc6hXwL|tk)6${)<0%;?}>MYTy{m12~KOq@-UP8pOeqjpXav)}OaI zc!17kq*)d?I+0Fr9~P3AJWCk~Hcv!Er~vhEYHI3iRs0r!_PAy}4)KumA29TRefhnb zS{oAPZQJv0NScZFK_&4Y6tQ6~D8+1^?%!Cs%kp3MhX95%Gw&G6;-`G?l#)e$xFPl1jnV0O2}rxo*% z>D}Gl4gqf;1=t3cR#$7TsJ?&y4vdlSwX`-4s#>c$Mn}mYz`(-ALGrXS!UjOjN=xRAlu1iguQz#-! zzRReg`1%gwm$#1!k;Nm&mlW&9;T_%Q*Y~+Po<08g4!cs^vS_5cZgt0f=NlS)wuHZY zqPL5jSfi9)uc=Qka2KL2V7Z<@*Qu-&2ROkI7Bj@(Do3I(em8laG_{ zSKPtO-)2nlH9v@xQDBKaG9&ZLXKpw3v)1|K|R27n)Em1T;aiGhn?pg9NSg z0smo(*49>xpjHrKU<{1rtAen_@5%8NICyy1*O|PQ+1DkN%#ljBcV==7)J6JLEp^i| z>4@kV7eA4*64ZW%=HIBV-pES~tlb&zxX5QCD)pI5SJLLep#IM^3JOkk$@PzI7D02*_?0vb2~N05X59PoWe)ZfpH zj0dEoCi-*-zlju3<~BFGV11%UuId#|zFL ze9th_!rHq)FyV^h?92ed&aYLH`e68^JdsLAt4!%v+LhD?r3d9(TMkBYatVfZaID7o z_&{FK>H5C4-7wPzuh{060YSl~?Xed(H`gcE)=eyA~jOUNQNX}zBLlxB84AKyhu6mSMVK}>5PE=wd6_U}(N(wqBX~2CO`Y}*L zNWvr^4`w5Pe~<+RX4Jd5xW7Mg*>8<;x=ZJL{`~o{ElXC;_t0gpP2j>&n(gMj2HgtU z(-f#6^y5Ibi3av2?|lb`Iq2lrZH_$^s}O?&4bF^6&e~xnRA%42awnw|kH2(IL)emu zyqozMPb828i;d6>B?BGqIwb25p-6C zF@%uTN1J}x!P0FAZK%l`(+chK0#e;QNFrYF`%-NLNhl{Xk#77EU2_c^#)!yC@_5>V zVuA)9mn@+|6Q3K>#=b`3xOwke z$67Bk^;+LomeiNIjQo`PA~>&-GwdS;ke)z_|7C3me7dhUM5uT*v)e{#e$j*#HPb09 zXrCspU#%j^uHg*^2FlOwWVzKBx_GM|8N_^au&y9^!^y5vm$;JOrmJpIrc6UID7ip3wqxFmJ$|v{DQa-e7 zbr5uQL@Zrhu%O&TFc1MQ*vXO~8$-KS@G0+T|5ev>>IFx?NlT&jwlvFxcQp0uiXq{& z2)U}0hw8fV3z33Mh_g9g0vBLO&NLhRc@MB=n+%z%<0ebZm5~{{whh;BY;4$Z$k?BO zo+q$p1Kk{70GJq{6p<|%fToA+_b4%uRN!Kuqx+ti7(5aWqBfC;d5~MtnV8c&JRAkG ztdOC7-yXjL8+yw8{QP6*8=UuG>0Fy_5C`pP>9(^_{T&Pp-Z33CboBGH#V~R~hi727 zhvY+_cp`rn6H@^ADaZsdFa(1K%yOS;P468rE}dt&TSQ(l=Ba1$+z6J>FkgkBXe9x# zm}Onj-}*uL;I4A^#-^r7b1Y0X$i8+8DtmR%V#u-%5zkMDez(4HozajX_s8DpgSJpD z%_#fpvXvWuz3Z;FKu`=^*tj3GXju#xfMHrIxCSTLy1#BWHQd9%nZD|`f$$PnbE|7g z?r}NK9zI!WzxgXJ&C8Igs55lHx3hJk^qDM}H+v(7fF;_+fIlU8-BiJg(H9kr2V7Hi z&sgq3f!g_1=2kA#pGC(*a1CK-b5{QO`+$*;Z7Fko=Z7x0@iZHM$6xnV{iGIezHD*N zI`unMB86exlYP3({Q5l%xxuJ6?`uUF?dE&d=83#@;7+=@xrN7SDBUc9%~5QR z2_V_8j}<)yDJ;Rk;Rh_Br3v&LAy{SdbezYHMUMX}PXUxBh?7eMyDb<sWpwE?!Ue>+9eas35b2l zZhj+f=!CEnYnHk2Y)tDBv7d*FP~EDLiX{IAoIZa!IfZ?GqM+_!S$9}W#Z+^ZnjQ-4 z*dgxe^;D24Ur0$zrvqoDy=P6@<-(z}NaL6-`goF3G4sNYWA*i-S&WUV<}@Wx-=9`c zv4c>!4kF^J<|#z4Ea9G)+44es*1{;Cc0Rn@yvbq6Y#)vYsT)3N=7QLn32iZIRGC-H?N(VX(la&*7R3fh^gaqHSbA|tB ztNDu#y)@6NftM+uc6+kxn(3XaGRg?I=^wqaPO%x=h2P<0G&E;=fV}9rZ*hN=&)Uv< zG~XgR_A7AC+TkJ>B%tLX>ZH+Yi9 z!P)zSRm#X-tSNB%2BR~2a&>#V2jtCHT^)37I?0DP(lG32%}1$aDR!~;6dcCDpkwBz2NCpOqyIfR`YRwT*7Xt?xXi*%X|mXTQNQYb zce(jg2GS-JOVREGUa)!SHx(Kq^z_x6ZXDv}6lsjyX0{jB7jPQuxwT`@CpqvlrHqEu z9N6M=1b^STjy!TAPqys&k}lprMYkkg z!sn`p(Q(0FORH@K3^5koxjrggmF|uktrPF>fGLiA)#p$MmHfche!!YjjkO z_;;ln!rv&x^)d>e)kAFV*`1pkp+Z;7c<0R~1d(k?*uKRBt)X=RyTgMY<|+#DryH^< zle??Qv=!zlC5Qs9MTNra5&{b%Jxv^Q*bQ=;`aK(V^xtt)*VyTN5lj;T5Fnk=QD2tN z?2GGfv`h=Mu@E+1Q08+T|Gr;o7b{*serkRi<~`y<=M=C`+vh=ew@$h=PF`47$-aiWYA3p}5oGL!?oIsZpeLX@2vtqcPLft+S zDZWPPK_WxGHnAk*C0Io4JuD>-Vf4rFQ+J3zu@x|F8~G)pRuP9ww|o?S7;4#@pLPVd zrPe4TSMTN*3I8lwgQ9WT3H?o8mNkPPm+|ZlDOA+fisvWmeTHYbJpSlx=p$5puAUT= z+_}5kt%iabfukQO%-T{TeK%&BQ@0@L_%qtr=^}sjY-zit2Rp(HTBsdI$}eOD z(ntmnC@ttA!q#eDzgc*osl+Y1H{-6lQf!>~P@KlIoKDTn&sQkjuRu#O*y=pw`gpg_{gj@A<6CC3TXrwSk5h2ZW#}q_3I$$ZHGt%TygqZT zI1uj&l~inD69bu`)$j$=m-g{`{#I;kY(|Kc^|t{>Bn!W4Z2@cgz?vdyHob_bC}`^U zDA@=EF%y|H4<2FqHvPzKFE;Lq6@<})&S*L|wh$)ej4`4|Vq#)I^DQ=P4Ro*%eq)rB zCy^bryZX)BXV6yF>&1&_dj%W66=mqm^7IAUcQR$`X52zKC%vfxDSr5=FJFBDHM^UK zt@xQ_bk#LHRpBi0LhMhZdxU%Vv2F`=aQV|2UeL$|?Adf#>n4}jihpyUi7K%^UcEc*6GVDHdK+DdB(s=ckm=XjXkSm#P0or{gZ8Qh*PfHL;q4O`Z{_F) zPX1`5yVKSLt;#++X24~d^b{H1p(4ailYCUU&YpjB%DTPr-s{Wci6m{I=KvP|>aJ6l zO8jwc8lQ5u%FwUmlhJjCunGN4s!%%nUHy|&a2nhyIL*`g+A-X7BUZdha`r{aP@u0t z5-C16{4ed~FRHc)eHC=|;wD*?I9bqlpdD-X$18hlZ56gI_?E^MM6W=9J){uSwz~ZN zyodkJl-}RWDcj~d-8IhhuhaY$JWhO0~|V1f&387rribvjE#?>PW#tZF!^p4mhsV|znf(wc>P+Ih`%pV zwXUNB6GG7|9|qajzyTCDgqr%0!G67l`JK1O*daB|)_Q;VXKq($-vhpuNu~JmRN)>K((Y$Mwq*vK zud)VR_++JBi+wF2$l#cpoB3+K*y@4}f3h9gL!8u{U}pBoAq7Z{w;-Yg%t~n|ozrhS zG>Sh5)5%hmvqS_$H(aHO6tGq|tcaR@6GcUnWD(iA_l?r#(P@}ChYN|SLdW?wKP$p! za6%?8lq0%&K=Y(7ue;}fevf6(=$O6W1K=`ONXx&iglf(_mEyIHTP&YdMRO88c<}b^ zuiCIr<5ni%d}K9N_=B|XF2(=M1kKlgj^F{d&rxk>fF5Bf(!Q~G06tMNMF`s_Aa!Kw z+7nO)hBJY9u4MpfSOIeoZ>Tmog824oRXo6-F$-lBoaI5Na2vqkQO6Ift2#mA=pg^s zP1>87AzWs%y6hueBPjO>IIbxoI6-g`P#ItsQ-Q-RrzOsCm@sCo`j=Op-jMRq9na^8 z$U$SS?=o2{68l^M&jMw1le&f*CndP-vcv6B9*W+T=VlOlurZG2ouOy#FE{;0%j-#z z`J_E>e2@A9$SqjN9bb`{*5$~qp{ z)?TdUT_pb+Rq=LzuODI*=iX8Faa{fDvt^p+9BPUx#X4yXX>aCCo$74RlD>uwOWmGD zJ*6DYBAWDCJxih7YNwhh{QB8*;ImVpgTPLwdD!NsFcBOHwLx>zcT`YXxY6l1s+yR* z!`T&Df}6~VQ4cXDgj@6(zoj{3?Eq_^F8GL%S+3d9$9&rreygy&+3ih zzo~}ve=Aq`*GT3N7S?CBtMY+FkFwuo{YcdJYI4{hX1{+wHlB|T09UszWnvo87#W=o z2Z?Dyn?^^WjA^oI9+@LX>zd}zvF z!8y~saNL};%R}4}P7oFm6jnuk9$1&UdhnReEd#8OF)@ChE4WH zZH>HQzPmD?_#o#V7YZg{!*_jo)(_YF&o!Vc9IZ3wmBkP4%ppbK$YP~%756gX%kRYW zXDe#9%koM)_DVgO_Z$h@KiVPG*A&a?bBlLRVU{md_Qbb#Pm{)#^3Gbl#LB-pwKw!X zPVRv^*t(yT%;C}!Oy{AnmU|fXT~W+3g%hHv+tOazk4tA#FMOnHo7As4kG!g*Jzpf# z(&a=+@A$%}j+fD+>dPykw52Cjd%|Vh(ZeJpHm_23=dHQe=rff61;GV2gK|ztf!ifQ-o_i?s zE%EKqql<6PBsR3)zWpP3`sM3aJ;zm&)svQt!b5`WCkb*z8(~`4qS1N-ocTW2MzVD` zKlm7!El-tn3q9HyNIg$(E~4%m#SR{8`n{Q7g|Wh(3qKeoOuDixi=b^)qdiZ#KCX-D zeh;oUsvU3jp<>u+WJ1v|+qM~Q2(o*!DIxi|x2tvTt16j;&?-k&^t+v!kNFlmllQ#w z7#iq#P2oJ>FbUPNHP6A?oLw87R?mAru8AMuyO%$`y;vVF^xo5cRl~_)mDCF1pu)aG z1NNb4*cLKk{|T-}0zMbnD7VVrWyZ3#`jGCI`WvB##NN^?)FXv1Z6oBELh+jMwkBxXJ$?dRVlYf%gB+*ZvH5A z3VCiE)GkcbYf&~8vOF*+jfdYft?sw>eNU9PFOc&$ZY(j?pG8Ev$y+87q(*Ms!4;}` zj;EpDv|n~Gn%|JtupySYdWIi{Vkf(r3Azou@DaPs8opi-rSUY$G1qlM2*aPcpX292 z*ItTW%F%YTrd3z956`X|yWAuW1DL0BczZmB_t*C{oLG&Xf0)VJb7qne)3!RVEj#q` zqiy7N^GdDu)04CJxnuBpvu2Gqvo2!y^mh$%;`GVFgi zYABV{R!@aEe#HIV9LaK<^nt5>sE_*$A|EGfst&@eq~BcGy9+Ybxz4FK zzRk9cGBqIb(W=Pgn0+_+NmK(Tu(QvJ8bp$l(PdaI9a-ap_>2F$*hULkdg?TV z4^CQD(eWz;%f$;k6F)fJUL4~cHM7hz8Efr^uD`gR+W1+o2a&3}%tWf|(|I$?ZQ#eMPg`1A;V18{4EG5clnvLqR*mf4@aK)y*7&?Ud)7aZS8%{q(QNlZFiECaZ4y-rRpPW7z)+ zkZ3GdT^dK9?HC*9XX?sURn_Nb5IAk$2#rDgDLygxu-xkLWoAmh8VgGHnpbVh^p&!5 z#@s|k$hGH4XB0^?q)bNY;Lu6j+nwMCgzLEnq+fYia1QmM?`0lUuO65P|879Jb)8vP z*SqzaplV(xhG!`Fr@soyJ)~9a+`pqRb5mTV98L>BNAvNPy`DoG$ao)k+($K4Kvd!c z3AwNxeXv))Jl!pLZ)Lw9C*~={ZtR9lBK!8O0RUX_LZR1tEd=SE;-&Z!9v&hf*i|yb z2%Re6bRjvWntS_e%hB$4pC-j)tZi=CJCE{WLH&ZDU#d!_k+vV(r{IV`oxmH}BZTV=54F(Lrd@;6PpHm`04DRJZ7 zxLH(4;9K>v&JWZxu^rKJI^rltrOu+5FRfbPebSwxz37|y{V`v0pD|a8-`G56ZVzv2 zDz$byT#s7PhA~-od{RHIUc~9L#^TVXRzGE(IQ6mFn3j*jW&asR@02)-exG& z507^QP|cJ^bNk`{YQFNor6)oKJ}bU!zXdXyb&i`sO54$%%Oe(k+k!a|I`ibN)j-Bn z{f7URE5_oi{>Gkbjf>knHPu(BB--UdeH;E=LF2P%=)iE^)(&lQz{l~SviK}embHiW z|HbuzMV9Ebxu-*cl9AP3oe%wl;bYTjA%~GX-$NdGwuCz!lSRI@)WXcdzhBIZfeXGZDQynQieMtoS6XUM8As@7-BUJteS?bPSGLr9cq}%yPhNa*lY>f{Pkgwmo zQLApq0H^y+*7C|T@Xus!R3&KA_VUl4KQMX;Y}sR#Um;68{K@BqL^ooj)$q5O0s5%y z8L-jJF3yBNw==4v^!|;=-%>@pj2r8JY0PjuaCoppdUtM>EOkpTDOLOT1zHws12PWR zd&Oza&uSMJ2jTbCTS*=lWlbVCzzA{1zCkl*`aC1k!E*>g-I5+xfe?ZyxdK-&BsufO zT=rH2s(-G(5el1A;5LZN$t2U2lKZ*&D?s(a@B|;9&Z7G#bB}0k7vgiw2Cq_Fow(Pl zjd@>H3Y>o9zpv5a%YNG~oiWqG*muP09kT>_O|UB^g{xlFATKlLzf>x4l_MNS++<6Y zJcA__?uX^}7C|I=ce2>H3-5bPqCO=xOIqw63u!GHN~RLtcD?!Z(*MnK(XKDYlRlJN zS6Y@iN*iKx41t}J1Z-u(Brc`R=t&>fm8?~N7wPgw`bD-w$Is`&LV($q&ch`M2pzoP+QgBh;x!3~L9QUL4XpIazvNEn1Yn<;U zM*po3K=v=$-;Y2hX(303q`Bvvha`C_>gd5r{it_URoCh=ym9yBzR;WOl}eQ1ERwza zfS)M+HIIp76EBb8?;IC6vNcszR}Yq$D!hF8(my1`7}$oKyyWwawE&Wb`1l>Oo*E4E zVO|*&S^(Igys*l$$>|Nw?Oq~wFK`Hij5P0#~`z{t(feI;Bx60QX-Xn_uvtP{D6c`k7PEdC3+|%{Fwn&j0)uTw0z|H zz(es~#{TyD6b9^MgP<;_=f2H*IR*kjX5d;?v~1kw-KTC2UU_`*jv4ZyO!L z)u#JWg;I8BbqnAXv@Ogl2 zz_}s=8o}_YAZ1R>69IG&j}wI!a_xHce|LaF{J%#Wf1K!Hi)Elnbtj8Xez*iGK;>@z z<=)8&P|GR3f&cD%T%6|SQhV8`o-C*yg6QO^P=HOO1~!GLP{A0Jo_N*j2H?j6sipIP zKp7@}18JngRGzWqY{)I=aGw~eUX`hW+(nBJ@e~l3Ktw_!>EI3SzJ= zJb<3+()&9Eq^zT3;y&Wxi3It#-@CiJDN-_d$jHcmO4|y`Lb0Omd}=u)=>u==?5?BQ zK?^DRhF3?xzwz`-`M)I%Lb6gQFu6G_DCj8zgCBIYNSmuu^?*@^nMzpg@}?EMQDfi@ zHOmvUo0}qO12e}uAVh}rDQjAR{3Q@;x;~KZr%dz+s5A)hSCztj>CgSlq|=v9!0?BS zgTo>xK`iWg@C;b}^t!$fZOrlfI_No{OHIrvu(1-2n%QmEkh*-Z3n>b0|3ljS*uVzAuuhL z0QUfU!_~oI=ya)hgmND>Ep1p%4vQAQhqm9+(#OHU!9>!&mKNW|_An#9gmr*!2C6%{ z0ia$+(PJWw{f|F0Zr1h){O6@vF0jA7b9CeZ=Dz1LIZjo2N(# z6I_Ren~NOilj&6DGLSGG*9T>6vnQ?i>dzK%x=moBy}A2ZKs=L{j;iqU4+ucIbdPz` zaZ-SWZet_qng8_36SILd45TYRM%P&rz3(0JNqVVc_7USh(?+F1>+j!$L`3M`N`c6D z8dP*lJCK?PqPH4BMfxG|j{=t^G!G0cdIiQ(=$|jI` zE7vm;EU0FI{+pVbihX*1d3o53^E@>&4LB6>FF_8MJeXWKAL1^bgwTk_gI{C771z0) z!0`bMXn2iClOJ@8-M6{8*n;!CR&mji>me?1MG_Jc8r;@GkxJn8-hdSC{*Z#WH2RSR zSdGA_2I72?BvfiMO#!@*z=Sy2 zSW;sLK)J={L-as|X5K1N(uWDebap=4o*Z?#P=l`zegOqA-Xk7%0bo>p!VED7f=^N8 zvcK>(`Cr%Q=SuJY`%4M|pfLbEXrN|sv@whWB5HvL#CjGwT6+&1yFp4aZfYvZdU`bA zO5ury;KWDX%ZUTA-$MvlGVnj80VlLyYY_w*H$5Ur{5LdSAOBBKV`nrT!xQxmg(zNn zGfzvG`^=-f&X9-@*(+8pF-;(G=(c-C6x}m?5f=aM`lZ73sj$VjlZW6CfAk^U|o9s)2U7J&osMh!xPgWw@5i@~y-trrF4Tgx>jv_0U`8cLTUa64N2q!b9i)3@7d zLyQP5vp`44Y#)0~eaC?sSVXtzjC z_39QnSObu0gTQ^825M8sBCq!0-y$MFq5P^5OnWa(OjZQjzkL3T3@*v9zp!|h@%4Il z0hFx(+gHlB_s3&K1SWb4N^kEQRsN?jh{y{<7w~2`ma6_eDt~dLz5nC?73lCn_=wC= z{iR?2r%yecpOEJWKY6#&^{Wji2w;@w^o=VL-qC{v zMp{7u-f8~pM&{c}BiN}JYi&O5jRmtBz^ZswozcW0-9ewtP-ym220I8E0*K7X$TFEP z7r71ZP^jcMZJN=NNnKV7pzT!WG@s@1TNQ@wSM3O0I-lB1n-zHo>N>#IBjaVrO5(~n zIhPl3eJyDq)s3%0)mLuATp}?FDKl+L^X)l_S15On*yb)?WS(t}=Q&!s?>vwwi;9cu z0O(_-?IkI5&^TcT>>#RchWb2ucy&H2fGC~&{s3tNSuE)jTMQH5$WQv_mk>2d6Fje9 z(WWMNjyktvVI@mPGyOHdEHJ;|PH;IYlstD9gdB4yP;;)B7I3YV!hlxgBV z-AXrYFQsVbc*sNWF8HZvS5%p{Z<0Wb+v#J2JC%SRtO=m_pe}@u4kmxI@nSkQ?edQY zOC3569dxgy$W##);A=NGHz!5FOHU6T#S*B201vP1l*|DRudpS+$NxXXy>(Po?bj~6 zXhCUEBn71mx?4dIl$H<)B?M^%X;^@TARtI6NQsEjh;(;IH_`&qCEefL`aHk${`H>o zopZ)GdkhoUYp;9V_l#>^*PLAaE}vm6!&X1PdE4!H?>$T{q4zOruV-65OGw~98s za{9a4otjarV&O(~E;-3{DR{eKV z8E!W_|2kYFP~ws<40%%6rs( z;R+s)_kk-EADf`k>8`c@`;QHy4L{&k!t9z4TNe$qCi;?3UPVbIpI(uS^_y&H8Yv_< z7%vQ9_UdG*ZX4Czh~cS97tWnUY0p8>7{rvxO-4_eMxqFBTy!uB6dLr0vW{w;g9oJ76m%4`ozHc zJ5XNq>pKP=>O*<81VY;DxAOLh2g0}Lnqs4(ew$34;LXJXvHG7U=JpH54kot?#3^tpkOzW(vhpTZa_ zz0P~{A;zHC0YX9Kg0ea#IkOuO0T1^st{+;1nyH*>;8)L^oMznCKBTIxQ-6C~qqvER;#%#&Zu9!@?@L2OlaouWtxINE;ni7wzjcu3 z8p_r-Zo$H9Hlm_i{i!{LCu7qB*BACnO5nbLBagW+$z<)F6YB4PmeF^|I;~g9+B#hm z#yH+K5sXT-Bs@bZJd;6Ybpm)3TmA6J4$uQn1athM+j{fi%YcAXo;Fw@SMV-a(0jl1 z_-LP|J(DIqv!^GF@d}8y1OqTh#);0?|700*42}BvuNEUN)-Qc(oY!GXl&CcES*bTs&|pE%j}!`!g` z3oqN(C*G$YQuj%|X_~?r_OH8t(w z7za*x-BUu!6DLn5p*mTHFp?lo-l4kYrcywxlvlAl@8823cHytU%`$5^*3L?a$gKbL zl+BpRFX1sV0WUGNatW<^`0G)dIEe@WIdRThL3Oh;cMg3`q#}s3LJw5}?(Ef@8NeL^ zW&!hqbW&zGVTyEKH(9(9%S2!!ZAVR*ka` zis^P)llcyl@;=dKrhjkWKfLm9RLOc5@6yHSmbboE3wQd z|CBXOT~~6So;o{-77KT9<^8S4dC)7;53VggbGjYGu|2ROl6`qp>un0l`hdkc@?%1j*} zDa@Cw`~((eVIFrXt=ab`X2(IkeO^ViSpsPoBeoFV`$>0I){(KKPE_(l`Rs$$qW z|MMiXrQO>61N{+k!v6UU9MKmBIY)~Dn=aMqv@H$^(~CPW z@jP}Tp)sLBh@ zz0?MKQr*J2o2ZvdQy97eE>j?18Xap^( zfZ!^l&i(qXZP7E~G0!)U=#C|ls%e#%W4QT1-bfShRf!ejg|W{VJ*%oW2I8~%As}hh zciD%2e0|;^@=usn6ZUVImYmo6smFv!`%5nA+gjDwRIjWG!=lGa0VwAMToW1O87Mt$ z2CvNz*;%c(#Uh_Sv@vd#v=k@!e4L5PjrxY&2-G+tRVz`qFj+~DuBlFiwW43Nw=~P>5$jD<6?0#1GW;A_-wk6ax%N>nddv;Ts z$A2%|*^1|`GXYP6IiI9>GUZ~t(Zf6G>H23>SlzPk>yQm?;q|!VDV~2MYLD1|Z)_X~ zlQjdsvbucXmiI-sr>CZP+~wE;mB z=>s&Q9hwh$^cGB%zK~QtIG3KOqS?Cktdg#hau1t3kpmXZzk>abUkCNC+{m}1c)TB+ zuG%#!=dw~8Qs>9srmC?Gd|=+C+p%ZdF?!WRs*V-_K417V;1c~FvHv`XCX-2b2_UW#13deWJB&V7IT8_!4lTZsI+tjCVi9(P#7 zob0(?sXHPP?`P*N$fTQdZBJY;Wiw;Bi3=N2BaCtp_6|82nG8V73us@43FL~zl6fbU zV4}$`Mmy~4Dgq)~o7p-24$#=b`Qr!OE@r3+v1IJYHUOb%MC{K&ETDV&G@yg7Fzt@c zU2pT6l_cF;;)L)=1eRX~*eE|Yr3N`&*<8VFB!|$~e@hv13|486A1DWV5O=jnD^Yoj z`=SJ^o0}Mv88bBoLaWgD__2=e;)KG&LLL})1!)|_Nk1Y#^gx zy`-=Z)u)=lm`I2X9(%`CBmsKaa})bxW`)W;6avSe1EmdU(xQ&P1_}U8?fG8x=Y-VO z$p-BG73Q8agt;hSuAuDhmA3HFSA)pNXiQ9!Kn9NG`~f|x1C14`O;h)0+UNJII>*K; zR3^`?Z*4t*Tx9bR7c=^2eb)Z9Q$PJ?055FSzCC{gA@l?^A-HbU3V0Sq4X|)<0Cj}I zqN3hAO;?zh;@ykf427ClShFotHfGFuXfS06Ny##m_B;KA0ed%m{uUV?9H(QZjq2;` zH$s*O`QKx2?>`}&!`f>wj(_m4pMFtsalrt1BTSyFSeOVF5G>uxk?t|F0BLbI4kY&~ zgiWucOG%9Z1G4vyb@J`ldhW>3(5q17sH&<$Zp8=%nSGB8jf&ElnK}I@Ej)APKQ$9W z5aMGX)Y;CO@{DpFZfHKxduI_w1bu8XMgs$H0-Um_ycnC|w*Ctj7q>@o@oTzvTFv(D zHKIRkm=nyYvJ`)_?Vou(A&hh7E6E-T9$ zg&&p$ugieu?lBU#Cohg818j~QZ>CToiVfr6HndR7CuXO!RiSv~? zbZ+hxgIGAs!_tJ@9YZNyItYRp77QKV@Lznw8Wa@aQnWI7Gx_He(lY$BrXue&QmI$T zc!(_2M`~gPURd8FwomC3>pja$C!Ral;;~ZJpWsLX)0#lm#>~oE$GHXqrLz*Q*_y^L zD?(uQGxYDN`aS(UmI77ftb=|)x+{{#`F3N5S&A+7*Er1(LmW1oDixx;8PohqUvA%{ zUJdTsb7612`X_lERV4h=1?L1i^!XxM#QW4O(-e|h>dPzhL1SKsy`DN^6^4$%R@-{M zn1`uzd2NsAm><%&DKrxs3_yWu`dhgGlwurbv(BUQ!5Z@#0ot|_uhzqu)He2$#VSm& zeHANVbO^h-4*#D+rf>gmP2&wmvLW_^z9}{H_GBtb9wW}_%sktHX>ygmayKE_y$hW= zW~Z^F@Mwsk(_lY`2EV?DXLF1oicjg)n58m9efDe<1WK;3!+B#`1p_AL=1|OkSp4|L zre!B*()n8PLNXO*PXUe~1Y1AN;r-F!KELg-2zy()vGT!5njh?;aj{*5zrQ!MP7f=$ z=RPtJiCAo_H&EU&^Po)6FFqjGgOY}UZ${73aW{3ZJ~8$%zJR7uP>0^#_tLC?c31Iv z!oRbm*wvJR&`-C2pNF81kdn=Q&@Ac;^gL*Jz>jJ8FjirN!Uv_7bno$A9Itx9&`j?I z=F9rWx2B_VIBd6K#i)ItL&a%s!&6iv78Q`HG5iVzaQr1D`wd`sfHen=5cP`tUCul` zE3eujppfX_5_)h;tai1W@bksd?N=w-lF++Dx8%1&%xf~wK@f%`>h^eBbpkR#KA35S znbQt|Lh55{@CY!L>b!(RY48K~BQEI5;0lP#oo^Q87>a)$1s}{AgJuH`t%ChM6Q=@S zEi<*3^)pq~wCdHJZ*j5+txGU$8s@7GoROMuoX|9UEY{%un=bh%MCu+|iNIdG3Z)W^ z`GSTaAW_PNJOt`y*S)>V4=bS)3BJqrhwHQu(qOa;n89S*s&NwU;6q}sE|;vNLYeZR z58QNDnTN~1szyw!ys_~Il^Zw4F%Dz6h%%-X-(GN)epQaaumTemKJEU;FMNm$*FfdR zBXYCc7IPY00dCb=YyJGSW~Sv`%^OvzFGlWjtVl12T8=ie&_RM*??pmE7yLRV=A;a0 zI2ZS!TY{yk4@ikc>2)IOj3?k{?n4Izzz=ABuFH)5FmkBjr5S(bvHi%cKe|A$Xuga8 zsRVt^VJ>%KrG^Xj{TM;3dK7@A_J0WNP?U@a-iC%e02P1;nJlSO*L*$o)*RiG2KM(| z+MoP_v_Tlj^TtAd2b)*8k2la%Q{X@~tq%w@+oR?RaMfes9^AT3H`me}EM)-tN_)Vv5IhT<&H| zT#jx|I2gsp4Fs~U3XRaV*ah)X(q3}BzOKjh?) z!xlx?g`OWzkfP8P?8FL9S})P|7%$@UovY*&Kv=BEy^-R_qYGTcvn;z?1r?H)>DvjW zr>A$|2R-NF17mI~f4cu@DVe2RKFOXAF zJsq+wAr3slT@SOn2m|ZB-jZ_yH4|_7n4)7{^bZpyZ`YQ%!JruK%*x}^SY9mkpj#>3 z6MiSTDvM^~0-;X}Y}th5WIP)i8!~e6eau2ar$JXNr=mh45REq3bj~OiV`Z8$GQ=bj zh9t381*g1vb?N{Z>k68hl#t;;Zyev?V3LiEjdRfB1^xwKRQ-qRfnACmc10rIp8m);$y-dAT7jHX^b9q4ioZZi&gi6@27F|^IIp+kAv>E1FMAo?&0qNwfjH`vd}9~hVj(D$60?POJBNk> zp}Io>?2`?Wt~sYd=o5sg+Xsog>$Iqa+MeVmiU$~_?a`$4kt~)BDCmwhQly(edzaX0 zu?j$XGoZm*4i0OyJbxC1J+$eNnxBP*<-;5^A%Y1t)(-Gd=+y?rv0qo4ND+>U7pq~; zCYpjFvs9#c=jG)g`hoiG66-C6&bSa-OB`-=1H0t>;ecJy^l9iEgkAa2B+fqIZOrJi zxBk9Kq^Djp5BRb=hIk1#IsMdJiD&a!;fjWgU-6ace5WN9 zKF|bX97=i{j2Krzz$%SY+7?Wrut#MfiX&lSG!$!rLdQNyEPAwCxLmwYPuð(BHl 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 z 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 >qO@cjD^4XkhixQQmL<@OOh_t2QJwPyWg6% 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 Uar=)?=$}WvpmsjvtjWFq13|pxU;qFB diff --git a/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst b/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst index 61cd114383a..857ae0bd6cc 100644 --- a/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst +++ b/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst @@ -70,7 +70,6 @@ The key components of the board are described in a counter-clockwise direction. * - RGB LED - Addressable RGB LED, driven by GPIO8. - Start Application Development ----------------------------- @@ -105,7 +104,6 @@ If you order a few samples, each ESP32-C3-DevKitC-02 comes in an individual pack For retail orders, please go to https://www.espressif.com/en/contact-us/get-samples. - Wholesale Orders ^^^^^^^^^^^^^^^^ @@ -192,8 +190,8 @@ No. Name Type [1]_ Function 9 RX I/O/T GPIO20, U0RXD 10 TX I/O/T GPIO21, U0TXD 11 G G Ground -12 18 I/O/T GPIO18 -13 19 I/O/T GPIO19 +12 18 I/O/T GPIO18, USB_D- +13 19 I/O/T GPIO19, USB_D+ 14 G G Ground 15 G G Ground === ==== ========== ==================================== @@ -207,7 +205,7 @@ Pin Layout .. figure:: ../../../_static/esp32-c3-devkitc-02-v1-pinout.png :align: center - :scale: 50% + :scale: 45% :alt: ESP32-C3-DevKitC-02 (click to enlarge) :figclass: align-center @@ -233,7 +231,6 @@ Related Documents For further design documentation for the board, please contact us at `sales@espressif.com `_. - .. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf .. _ESP32-C3-WROOM-02 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3-wroom-02_datasheet_en.pdf .. _ESP32-C3-DevKitC-02 Schematic: https://dl.espressif.com/dl/schematics/SCH_ESP32-C3-DEVKITC-02_V1_1_20210126A.pdf diff --git a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst index e23aa28b1c2..c3388cb74b8 100644 --- a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst +++ b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst @@ -192,23 +192,21 @@ J3 9 RX I/O/T GPIO20, U0RXD 10 TX I/O/T GPIO21, U0TXD 11 G G 接地 -12 18 I/O/T GPIO18 -13 19 I/O/T GPIO19 +12 18 I/O/T GPIO18, USB_D- +13 19 I/O/T GPIO19, USB_D+ 14 G G 接地 15 G G 接地 ==== ==== ========== ================================ - .. [1] P:电源;I:输入;O:输出;T:可设置为高阻。 .. [2] GPIO2、GPIO8、GPIO9 为 ESP32-C3 芯片的 Strapping 管脚。在芯片上电和系统复位过程中,Strapping 管脚根据管脚的二进制电压值控制芯片功能。Strapping 管脚的具体描述和应用,请参考 `ESP32-C3 技术规格书`_ 的 Strapping 管脚章节。 - 管脚布局 ^^^^^^^^ .. figure:: ../../../_static/esp32-c3-devkitc-02-v1-pinout.png :align: center - :scale: 50% + :scale: 45% :alt: ESP32-C3-DevKitC-02 管脚布局(点击放大) :figclass: align-center diff --git a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst index bf521bbf019..76f4c71f152 100644 --- a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst +++ b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst @@ -193,8 +193,8 @@ J3 10 IO5 I/O/T GPIO5, ADC2_CH0, FSPIWP, MTDI 11 IO4 I/O/T GPIO4, ADC1_CH4, FSPIHD, MTMS 12 GND G 接地 -13 IO18 I/O/T GPIO18 -14 IO19 I/O/T GPIO19 +13 IO18 I/O/T GPIO18, USB_D- +14 IO19 I/O/T GPIO19, USB_D+ 15 GND G 接地 ==== ==== ========== ================================ From 2cad39aee5c0065cafd5e4f0e3f5fe968311847c Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 16 May 2024 14:54:27 +0800 Subject: [PATCH 071/548] feat(gpio): add gpio support on ESP32C5 MP version --- .../test_apps/.build-test-rules.yml | 4 - .../esp_driver_gpio/test_apps/gpio/README.md | 4 +- .../test_apps/gpio/main/test_gpio.c | 4 + components/esp_pm/Kconfig | 3 +- components/hal/esp32c5/include/hal/gpio_ll.h | 223 +- components/hal/esp32p4/include/hal/gpio_ll.h | 60 +- .../esp32c5/beta3/include/soc/io_mux_struct.h | 22 +- .../esp32c5/beta3/ld/esp32c5.peripherals.ld | 2 +- .../mp/include/soc/Kconfig.soc_caps.in | 28 +- .../soc/esp32c5/mp/include/soc/io_mux_reg.h | 4272 +---------------- .../esp32c5/mp/include/soc/io_mux_struct.h | 2 +- .../soc/esp32c5/mp/include/soc/soc_caps.h | 20 +- .../soc/esp32c5/mp/ld/esp32c5.peripherals.ld | 2 +- .../soc/esp32p4/include/soc/io_mux_struct.h | 26 +- examples/peripherals/.build-test-rules.yml | 4 - .../peripherals/gpio/generic_gpio/README.md | 4 +- examples/storage/.build-test-rules.yml | 4 - examples/storage/nvs_rw_blob/README.md | 4 +- examples/system/.build-test-rules.yml | 4 - 19 files changed, 314 insertions(+), 4378 deletions(-) diff --git a/components/esp_driver_gpio/test_apps/.build-test-rules.yml b/components/esp_driver_gpio/test_apps/.build-test-rules.yml index 68cfc3a41d3..f0eb84e6e24 100644 --- a/components/esp_driver_gpio/test_apps/.build-test-rules.yml +++ b/components/esp_driver_gpio/test_apps/.build-test-rules.yml @@ -1,10 +1,6 @@ # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps components/esp_driver_gpio/test_apps: - disable: - - if: IDF_TARGET == "esp32c5" - temporary: true - reason: not support yet # TODO: [ESP32C5] IDF-8717 disable_test: - if: IDF_TARGET == "esp32p4" temporary: true diff --git a/components/esp_driver_gpio/test_apps/gpio/README.md b/components/esp_driver_gpio/test_apps/gpio/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/esp_driver_gpio/test_apps/gpio/README.md +++ b/components/esp_driver_gpio/test_apps/gpio/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c index 177c65862fc..d1811d2a068 100644 --- a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c +++ b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c @@ -535,6 +535,8 @@ TEST_CASE("GPIO_set_output_level_get_input_level_test", "[gpio]") TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "get level error! the level should be high!"); } +#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C5) +// C5 on FPGA do not support GPIO pull down // This test routes constant-high/low signal to pins, another way is to directly connect TEST_GPIO_EXT_IN_IO to // 3.3v or GND pin TEST_CASE("GPIO_get_level_from_fixed_voltage_test", "[gpio]") @@ -662,6 +664,8 @@ TEST_CASE("GPIO_mode_test", "[gpio]") TEST_ASSERT_EQUAL_INT_MESSAGE(!level, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT set error, it gives incorrect output"); } +#endif + static void prompt_to_continue(const char *str) { printf("%s , please press \"Enter\" to go on!\n", str); diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 3058381fbd0..718379486df 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -2,7 +2,8 @@ menu "Power Management" config PM_ENABLE bool "Support for power management" # SMP FreeRTOS currently does not support power management IDF-4997 - depends on !FREERTOS_SMP || __DOXYGEN__ + # Power Management is not supported on ESP32C5 MP IDF-8643 + depends on (!FREERTOS_SMP || __DOXYGEN__) && !IDF_TARGET_ESP32C5 default n help If enabled, application is compiled with support for power management. diff --git a/components/hal/esp32c5/include/hal/gpio_ll.h b/components/hal/esp32c5/include/hal/gpio_ll.h index 57df8172cd5..75d809bc73b 100644 --- a/components/hal/esp32c5/include/hal/gpio_ll.h +++ b/components/hal/esp32c5/include/hal/gpio_ll.h @@ -22,23 +22,17 @@ #include "soc/gpio_struct.h" #include "soc/lp_aon_struct.h" #include "soc/pmu_struct.h" -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION -#include "soc/lp_io_struct.h" -#include "soc/pcr_struct.h" +#include "soc/io_mux_struct.h" #include "soc/clk_tree_defs.h" +#include "soc/pcr_struct.h" #include "soc/usb_serial_jtag_struct.h" -#include "soc/io_mux_struct.h" #include "hal/gpio_types.h" +#include "hal/assert.h" +#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION +#include "soc/lp_io_struct.h" #elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION #include "soc/lp_gpio_struct.h" -#include "soc/usb_serial_jtag_reg.h" -#include "soc/pcr_struct.h" -#include "soc/clk_tree_defs.h" -#include "soc/io_mux_struct.h" -#include "hal/gpio_types.h" -#include "hal/misc.h" #endif -#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -69,15 +63,15 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, bool *pu, bool *pd, bool *ie, bool *oe, bool *od, uint32_t *drv, uint32_t *fun_sel, uint32_t *sig_out, bool *slp_sel) { - *pu = IOMUX.gpio[gpio_num].fun_wpu; - *pd = IOMUX.gpio[gpio_num].fun_wpd; - *ie = IOMUX.gpio[gpio_num].fun_ie; + *pu = IO_MUX.gpio[gpio_num].fun_wpu; + *pd = IO_MUX.gpio[gpio_num].fun_wpd; + *ie = IO_MUX.gpio[gpio_num].fun_ie; *oe = (hw->enable.val & (1 << gpio_num)) >> gpio_num; *od = hw->pin[gpio_num].pad_driver; - *drv = IOMUX.gpio[gpio_num].fun_drv; - *fun_sel = IOMUX.gpio[gpio_num].mcu_sel; + *drv = IO_MUX.gpio[gpio_num].fun_drv; + *fun_sel = IO_MUX.gpio[gpio_num].mcu_sel; *sig_out = hw->func_out_sel_cfg[gpio_num].out_sel; - *slp_sel = IOMUX.gpio[gpio_num].slp_sel; + *slp_sel = IO_MUX.gpio[gpio_num].slp_sel; } /** @@ -88,12 +82,7 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, */ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_wpu = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // REG_SET_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_wpu = 1; } /** @@ -105,12 +94,7 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_wpu = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_wpu = 0; } /** @@ -121,12 +105,7 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_wpd = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // REG_SET_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_wpd = 1; } /** @@ -143,20 +122,11 @@ static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) // Note that esp32C5 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. // TODO: read the specific efuse with efuse_ll.h -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { USB_SERIAL_JTAG.conf0.pad_pull_override = 1; USB_SERIAL_JTAG.conf0.dp_pullup = 0; } - IOMUX.gpio[gpio_num].fun_wpd = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { - // SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); - // CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); - // } - // REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_wpd = 0; } /** @@ -182,11 +152,7 @@ __attribute__((always_inline)) static inline void gpio_ll_get_intr_status(gpio_dev_t *hw, uint32_t core_id, uint32_t *status) { (void)core_id; -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION *status = hw->pcpu_int.procpu_int; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - abort(); -#endif } /** @@ -261,12 +227,7 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_ie = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_ie = 0; } /** @@ -277,12 +238,7 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_ie = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_ie = 1; } /** @@ -293,12 +249,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].filter_en = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_FILTER_EN(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].filter_en = 1; } /** @@ -309,15 +260,9 @@ static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].filter_en = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - PIN_FILTER_DIS(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].filter_en = 0; } -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION /** * @brief Enable GPIO hysteresis * @@ -330,8 +275,8 @@ static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t // We are not going to use the hardware control in IDF for C5. // Therefore, we need to always switch to use software control first. // i.e. Swt hys_sel to 1, so that hys_en determines whether hysteresis is enabled or not - IOMUX.gpio[gpio_num].hys_sel = 1; - IOMUX.gpio[gpio_num].hys_en = 1; + IO_MUX.gpio[gpio_num].hys_sel = 1; + IO_MUX.gpio[gpio_num].hys_en = 1; } /** @@ -342,10 +287,9 @@ static inline void gpio_ll_pin_input_hysteresis_enable(gpio_dev_t *hw, uint32_t */ static inline void gpio_ll_pin_input_hysteresis_disable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].hys_sel = 1; - IOMUX.gpio[gpio_num].hys_en = 0; + IO_MUX.gpio[gpio_num].hys_sel = 1; + IO_MUX.gpio[gpio_num].hys_en = 0; } -#endif /** * @brief Disable output mode on GPIO. @@ -461,12 +405,7 @@ static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, uint32_t gpio_num, gpio_drive_cap_t strength) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].fun_drv = strength; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // SET_PERI_REG_BITS(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, strength, FUN_DRV_S); - abort(); -#endif + IO_MUX.gpio[gpio_num].fun_drv = strength; } /** @@ -478,12 +417,7 @@ static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu */ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_num, gpio_drive_cap_t *strength) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - *strength = (gpio_drive_cap_t)(IOMUX.gpio[gpio_num].fun_drv); -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // *strength = (gpio_drive_cap_t)GET_PERI_REG_BITS2(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_DRV_V, FUN_DRV_S); - abort(); -#endif + *strength = (gpio_drive_cap_t)(IO_MUX.gpio[gpio_num].fun_drv); } /** @@ -527,7 +461,7 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) } /** - * @brief Set pad input to a peripheral signal through the IOMUX. + * @brief Set pad input to a peripheral signal through the IO_MUX. * * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number of the pad. @@ -537,7 +471,7 @@ __attribute__((always_inline)) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) { hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; - IOMUX.gpio[gpio].fun_ie = 1; + IO_MUX.gpio[gpio].fun_ie = 1; } /** @@ -554,11 +488,10 @@ static inline void gpio_ll_iomux_func_sel(uint32_t pin_name, uint32_t func) USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; } #elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // // Disable USB Serial JTAG if pins 12 or pins 13 needs to select an IOMUX function - // if (pin_name == IO_MUX_GPIO12_REG || pin_name == IO_MUX_GPIO13_REG) { - // CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); - // } - abort(); + // Disable USB Serial JTAG if pins 13 or pins 14 needs to select an IOMUX function + if (pin_name == IO_MUX_GPIO13_REG || pin_name == IO_MUX_GPIO14_REG) { + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + } #endif PIN_FUNC_SELECT(pin_name, func); } @@ -590,19 +523,18 @@ static inline void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t f if (gpio_num == USB_INT_PHY0_DM_GPIO_NUM || gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; } - IOMUX.gpio[gpio_num].mcu_sel = func; + IO_MUX.gpio[gpio_num].mcu_sel = func; #elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // // Disable USB Serial JTAG if pins 12 or pins 13 needs to select an IOMUX function - // if (gpio_num == USB_INT_PHY0_DM_GPIO_NUM || gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { - // CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); - // } - // PIN_FUNC_SELECT(IO_MUX_GPIO0_REG + (gpio_num * 4), func); - abort(); + // Disable USB Serial JTAG if pins 13 or pins 14 needs to select an IOMUX function + if (gpio_num == USB_INT_PHY0_DM_GPIO_NUM || gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + USB_SERIAL_JTAG.conf0.usb_pad_enable = 0; + } + IO_MUX.gpio[gpio_num].mcu_sel = func; #endif } /** - * @brief Set peripheral output to an GPIO pad through the IOMUX. + * @brief Set peripheral output to an GPIO pad through the IO_MUX. * * @param hw Peripheral GPIO hardware instance address. * @param gpio_num gpio_num GPIO number of the pad. @@ -625,7 +557,6 @@ static inline void gpio_ll_iomux_out(gpio_dev_t *hw, uint8_t gpio_num, int func, static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) { switch (src) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION case SOC_MOD_CLK_XTAL: PCR.iomux_clk_conf.iomux_func_clk_sel = 0; break; @@ -635,14 +566,6 @@ static inline void gpio_ll_iomux_set_clk_src(soc_module_clk_t src) case SOC_MOD_CLK_PLL_F80M: PCR.iomux_clk_conf.iomux_func_clk_sel = 2; break; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - case SOC_MOD_CLK_XTAL: - PCR.iomux_clk_conf.iomux_func_clk_sel = 3; - break; - case SOC_MOD_CLK_PLL_F80M: - PCR.iomux_clk_conf.iomux_func_clk_sel = 1; - break; -#endif default: // Unsupported IO_MUX clock source HAL_ASSERT(false); @@ -694,12 +617,7 @@ static inline void gpio_ll_force_unhold_all(void) */ static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].slp_sel = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_SEL_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].slp_sel = 1; } /** @@ -711,12 +629,7 @@ static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].slp_sel = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_SEL_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].slp_sel = 0; } /** @@ -727,12 +640,7 @@ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_wpu = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_PULLUP_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_wpu = 0; } /** @@ -743,12 +651,7 @@ static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_wpu = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_PULLUP_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_wpu = 1; } /** @@ -759,12 +662,7 @@ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_wpd = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_PULLDOWN_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_wpd = 1; } /** @@ -775,12 +673,7 @@ static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_wpd = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_PULLDOWN_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_wpd = 0; } /** @@ -791,12 +684,7 @@ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_ie = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_INPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_ie = 0; } /** @@ -807,12 +695,7 @@ static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, uint32_t gpio_num */ static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_ie = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_INPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_ie = 1; } /** @@ -823,12 +706,7 @@ static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_oe = 0; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_OUTPUT_DISABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_oe = 0; } /** @@ -839,12 +717,7 @@ static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, uint32_t gpio_nu */ static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, uint32_t gpio_num) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - IOMUX.gpio[gpio_num].mcu_oe = 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // PIN_SLP_OUTPUT_ENABLE(IO_MUX_GPIO0_REG + (gpio_num * 4)); - abort(); -#endif + IO_MUX.gpio[gpio_num].mcu_oe = 1; } #ifdef __cplusplus diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index 94a4df39183..ff3e0ea90e7 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -64,15 +64,15 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, { uint32_t bit_shift = (gpio_num < 32) ? gpio_num : (gpio_num - 32); uint32_t bit_mask = 1 << bit_shift; - *pu = IOMUX.gpio[gpio_num].fun_wpu; - *pd = IOMUX.gpio[gpio_num].fun_wpd; - *ie = IOMUX.gpio[gpio_num].fun_ie; + *pu = IO_MUX.gpio[gpio_num].fun_wpu; + *pd = IO_MUX.gpio[gpio_num].fun_wpd; + *ie = IO_MUX.gpio[gpio_num].fun_ie; *oe = (((gpio_num < 32) ? hw->enable.val : hw->enable1.val) & bit_mask) >> bit_shift; *od = hw->pin[gpio_num].pad_driver; - *drv = IOMUX.gpio[gpio_num].fun_drv; - *fun_sel = IOMUX.gpio[gpio_num].mcu_sel; + *drv = IO_MUX.gpio[gpio_num].fun_drv; + *fun_sel = IO_MUX.gpio[gpio_num].mcu_sel; *sig_out = hw->func_out_sel_cfg[gpio_num].out_sel; - *slp_sel = IOMUX.gpio[gpio_num].slp_sel; + *slp_sel = IO_MUX.gpio[gpio_num].slp_sel; } /** @@ -83,7 +83,7 @@ static inline void gpio_ll_get_io_config(gpio_dev_t *hw, uint32_t gpio_num, */ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].fun_wpu = 1; + IO_MUX.gpio[gpio_num].fun_wpu = 1; } /** @@ -95,7 +95,7 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].fun_wpu = 0; + IO_MUX.gpio[gpio_num].fun_wpu = 0; } /** @@ -106,7 +106,7 @@ static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].fun_wpd = 1; + IO_MUX.gpio[gpio_num].fun_wpd = 1; } /** @@ -133,7 +133,7 @@ static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) USB_WRAP.otg_conf.pad_pull_override = 1; USB_WRAP.otg_conf.dp_pullup = 0; } - IOMUX.gpio[gpio_num].fun_wpd = 0; + IO_MUX.gpio[gpio_num].fun_wpd = 0; } /** @@ -235,7 +235,7 @@ static inline void gpio_ll_intr_disable(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].fun_ie = 0; + IO_MUX.gpio[gpio_num].fun_ie = 0; } /** @@ -246,7 +246,7 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].fun_ie = 1; + IO_MUX.gpio[gpio_num].fun_ie = 1; } /** @@ -257,7 +257,7 @@ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].filter_en = 1; + IO_MUX.gpio[gpio_num].filter_en = 1; } /** @@ -268,7 +268,7 @@ static inline void gpio_ll_pin_filter_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_pin_filter_disable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].filter_en = 0; + IO_MUX.gpio[gpio_num].filter_en = 0; } /** @@ -451,7 +451,7 @@ static inline void gpio_ll_wakeup_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, uint32_t gpio_num, gpio_drive_cap_t strength) { - IOMUX.gpio[gpio_num].fun_drv = strength; + IO_MUX.gpio[gpio_num].fun_drv = strength; } /** @@ -463,7 +463,7 @@ static inline void gpio_ll_set_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu */ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_num, gpio_drive_cap_t *strength) { - *strength = (gpio_drive_cap_t)(IOMUX.gpio[gpio_num].fun_drv); + *strength = (gpio_drive_cap_t)(IO_MUX.gpio[gpio_num].fun_drv); } /** @@ -547,7 +547,7 @@ static inline bool gpio_ll_is_digital_io_hold(gpio_dev_t *hw, uint32_t gpio_num) } /** - * @brief Set pad input to a peripheral signal through the IOMUX. + * @brief Set pad input to a peripheral signal through the IO_MUX. * * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number of the pad. @@ -557,7 +557,7 @@ __attribute__((always_inline)) static inline void gpio_ll_iomux_in(gpio_dev_t *hw, uint32_t gpio, uint32_t signal_idx) { hw->func_in_sel_cfg[signal_idx].sig_in_sel = 0; - IOMUX.gpio[gpio].fun_ie = 1; + IO_MUX.gpio[gpio].fun_ie = 1; } /** @@ -597,11 +597,11 @@ static inline void gpio_ll_func_sel(gpio_dev_t *hw, uint8_t gpio_num, uint32_t f } else if (gpio_num == USB_OTG_INT_PHY_DM_GPIO_NUM || gpio_num == USB_OTG_INT_PHY_DP_GPIO_NUM) { USB_WRAP.otg_conf.usb_pad_enable = 0; } - IOMUX.gpio[gpio_num].mcu_sel = func; + IO_MUX.gpio[gpio_num].mcu_sel = func; } /** - * @brief Set peripheral output to an GPIO pad through the IOMUX. + * @brief Set peripheral output to an GPIO pad through the IO_MUX. * * @param hw Peripheral GPIO hardware instance address. * @param gpio_num gpio_num GPIO number of the pad. @@ -685,7 +685,7 @@ static inline void gpio_ll_force_unhold_all(void) */ static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].slp_sel = 1; + IO_MUX.gpio[gpio_num].slp_sel = 1; } /** @@ -697,7 +697,7 @@ static inline void gpio_ll_sleep_sel_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].slp_sel = 0; + IO_MUX.gpio[gpio_num].slp_sel = 0; } /** @@ -708,7 +708,7 @@ static inline void gpio_ll_sleep_sel_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_wpu = 0; + IO_MUX.gpio[gpio_num].mcu_wpu = 0; } /** @@ -719,7 +719,7 @@ static inline void gpio_ll_sleep_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_wpu = 1; + IO_MUX.gpio[gpio_num].mcu_wpu = 1; } /** @@ -730,7 +730,7 @@ static inline void gpio_ll_sleep_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_wpd = 1; + IO_MUX.gpio[gpio_num].mcu_wpd = 1; } /** @@ -741,7 +741,7 @@ static inline void gpio_ll_sleep_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_wpd = 0; + IO_MUX.gpio[gpio_num].mcu_wpd = 0; } /** @@ -752,7 +752,7 @@ static inline void gpio_ll_sleep_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_ie = 0; + IO_MUX.gpio[gpio_num].mcu_ie = 0; } /** @@ -763,7 +763,7 @@ static inline void gpio_ll_sleep_input_disable(gpio_dev_t *hw, uint32_t gpio_num */ static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_ie = 1; + IO_MUX.gpio[gpio_num].mcu_ie = 1; } /** @@ -774,7 +774,7 @@ static inline void gpio_ll_sleep_input_enable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_oe = 0; + IO_MUX.gpio[gpio_num].mcu_oe = 0; } /** @@ -785,7 +785,7 @@ static inline void gpio_ll_sleep_output_disable(gpio_dev_t *hw, uint32_t gpio_nu */ static inline void gpio_ll_sleep_output_enable(gpio_dev_t *hw, uint32_t gpio_num) { - IOMUX.gpio[gpio_num].mcu_oe = 1; + IO_MUX.gpio[gpio_num].mcu_oe = 1; } #ifdef __cplusplus diff --git a/components/soc/esp32c5/beta3/include/soc/io_mux_struct.h b/components/soc/esp32c5/beta3/include/soc/io_mux_struct.h index ace0a983de2..fdab268dfe1 100644 --- a/components/soc/esp32c5/beta3/include/soc/io_mux_struct.h +++ b/components/soc/esp32c5/beta3/include/soc/io_mux_struct.h @@ -34,7 +34,7 @@ typedef union { uint32_t reserved_15:17; }; uint32_t val; -} iomux_pin_ctrl_reg_t; +} io_mux_pin_ctrl_reg_t; /** Type of gpio register * IO MUX Configure Register for pad XTAL_32K_P @@ -102,13 +102,13 @@ typedef union { uint32_t hys_en:1; /** hys_sel : R/W; bitpos: [17]; default: 0; * Select enabling signals of the pad from software and efuse hardware. 1: Select - * enabling siganl from slftware. 0: Select enabling signal from efuse hardware. + * enabling signal from slftware. 0: Select enabling signal from efuse hardware. */ uint32_t hys_sel:1; uint32_t reserved_18:14; }; uint32_t val; -} iomux_gpio_reg_t; +} io_mux_gpio_reg_t; /** Type of date register * IO MUX Version Control Register @@ -122,20 +122,20 @@ typedef union { uint32_t reserved_28:4; }; uint32_t val; -} iomux_date_reg_t; +} io_mux_date_reg_t; -typedef struct iomux_dev_t { - volatile iomux_pin_ctrl_reg_t pin_ctrl; - volatile iomux_gpio_reg_t gpio[27]; +typedef struct io_mux_dev_t { + volatile io_mux_pin_ctrl_reg_t pin_ctrl; + volatile io_mux_gpio_reg_t gpio[27]; uint32_t reserved_070[35]; - volatile iomux_date_reg_t date; -} iomux_dev_t; + volatile io_mux_date_reg_t date; +} io_mux_dev_t; -extern iomux_dev_t IOMUX; +extern io_mux_dev_t IO_MUX; #ifndef __cplusplus -_Static_assert(sizeof(iomux_dev_t) == 0x100, "Invalid size of iomux_dev_t structure"); +_Static_assert(sizeof(io_mux_dev_t) == 0x100, "Invalid size of io_mux_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32c5/beta3/ld/esp32c5.peripherals.ld b/components/soc/esp32c5/beta3/ld/esp32c5.peripherals.ld index 14d416ccc3e..54c687aff33 100644 --- a/components/soc/esp32c5/beta3/ld/esp32c5.peripherals.ld +++ b/components/soc/esp32c5/beta3/ld/esp32c5.peripherals.ld @@ -41,7 +41,7 @@ PROVIDE ( DS = 0x6008C000 ); PROVIDE ( HMAC = 0x6008D000 ); PROVIDE ( ECDSA = 0x6008E000 ); -PROVIDE ( IOMUX = 0x60090000 ); +PROVIDE ( IO_MUX = 0x60090000 ); PROVIDE ( GPIO = 0x60091000 ); PROVIDE ( GPIO_EXT = 0x60091f00 ); PROVIDE ( SDM = 0x60091f00 ); diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index 347785282fd..cb12a7c2fd5 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -111,17 +111,41 @@ config SOC_CPU_IDRAM_SPLIT_USING_PMP bool default y +config SOC_GPIO_PORT + int + default 1 + config SOC_GPIO_PIN_COUNT int default 29 +config SOC_GPIO_SUPPORT_PIN_HYS_FILTER + bool + default y + +config SOC_GPIO_SUPPORT_RTC_INDEPENDENT + bool + default y + config SOC_GPIO_IN_RANGE_MAX int - default 30 + default 28 config SOC_GPIO_OUT_RANGE_MAX int - default 30 + default 28 + +config SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK + int + default 0 + +config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK + hex + default 0x0000000001FFFF00 + +config SOC_GPIO_SUPPORT_FORCE_HOLD + bool + default y config SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP bool diff --git a/components/soc/esp32c5/mp/include/soc/io_mux_reg.h b/components/soc/esp32c5/mp/include/soc/io_mux_reg.h index c8bec06285e..1a9dec1b88a 100644 --- a/components/soc/esp32c5/mp/include/soc/io_mux_reg.h +++ b/components/soc/esp32c5/mp/include/soc/io_mux_reg.h @@ -95,6 +95,36 @@ extern "C" { #define PIN_FILTER_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FILTER_EN) #define PIN_FILTER_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FILTER_EN) +#define IO_MUX_GPIO0_REG PERIPHS_IO_MUX_U_PAD_XTAL_32K_P +#define IO_MUX_GPIO1_REG PERIPHS_IO_MUX_U_PAD_XTAL_32K_N +#define IO_MUX_GPIO2_REG PERIPHS_IO_MUX_U_PAD_MTMS +#define IO_MUX_GPIO3_REG PERIPHS_IO_MUX_U_PAD_MTDI +#define IO_MUX_GPIO4_REG PERIPHS_IO_MUX_U_PAD_MTCK +#define IO_MUX_GPIO5_REG PERIPHS_IO_MUX_U_PAD_MTDO +#define IO_MUX_GPIO6_REG PERIPHS_IO_MUX_U_PAD_GPIO6 +#define IO_MUX_GPIO7_REG PERIPHS_IO_MUX_U_PAD_GPIO7 +#define IO_MUX_GPIO8_REG PERIPHS_IO_MUX_U_PAD_GPIO8 +#define IO_MUX_GPIO9_REG PERIPHS_IO_MUX_U_PAD_GPIO9 +#define IO_MUX_GPIO10_REG PERIPHS_IO_MUX_U_PAD_GPIO10 +#define IO_MUX_GPIO11_REG PERIPHS_IO_MUX_U_PAD_U0TXD +#define IO_MUX_GPIO12_REG PERIPHS_IO_MUX_U_PAD_U0RXD +#define IO_MUX_GPIO13_REG PERIPHS_IO_MUX_U_PAD_GPIO13 +#define IO_MUX_GPIO14_REG PERIPHS_IO_MUX_U_PAD_GPIO14 +#define IO_MUX_GPIO15_REG PERIPHS_IO_MUX_U_PAD_SPICS1 +#define IO_MUX_GPIO16_REG PERIPHS_IO_MUX_U_PAD_SPICS0 +#define IO_MUX_GPIO17_REG PERIPHS_IO_MUX_U_PAD_SPIQ +#define IO_MUX_GPIO18_REG PERIPHS_IO_MUX_U_PAD_SPIWP +#define IO_MUX_GPIO19_REG PERIPHS_IO_MUX_U_PAD_VDD_SPI +#define IO_MUX_GPIO20_REG PERIPHS_IO_MUX_U_PAD_SPIHD +#define IO_MUX_GPIO21_REG PERIPHS_IO_MUX_U_PAD_SPICLK +#define IO_MUX_GPIO22_REG PERIPHS_IO_MUX_U_PAD_SPID +#define IO_MUX_GPIO23_REG PERIPHS_IO_MUX_U_PAD_GPIO23 +#define IO_MUX_GPIO24_REG PERIPHS_IO_MUX_U_PAD_GPIO24 +#define IO_MUX_GPIO25_REG PERIPHS_IO_MUX_U_PAD_GPIO25 +#define IO_MUX_GPIO26_REG PERIPHS_IO_MUX_U_PAD_GPIO26 +#define IO_MUX_GPIO27_REG PERIPHS_IO_MUX_U_PAD_GPIO27 +#define IO_MUX_GPIO28_REG PERIPHS_IO_MUX_U_PAD_GPIO28 + #define PIN_FUNC_GPIO 1 #define GPIO_PAD_PULLUP(num) do{PIN_PULLDWN_DIS(IOMUX_REG_GPIO##num);PIN_PULLUP_EN(IOMUX_REG_GPIO##num);}while(0) @@ -102,21 +132,21 @@ extern "C" { #define GPIO_PAD_SET_DRV(num, drv) PIN_SET_DRV(IOMUX_REG_GPIO##num, drv) // TODO: [ESP32C5] IDF-8698 need check -#define SPI_HD_GPIO_NUM 22 -#define SPI_WP_GPIO_NUM 20 -#define SPI_CS0_GPIO_NUM 18 -#define SPI_CLK_GPIO_NUM 23 -#define SPI_D_GPIO_NUM 24 -#define SPI_Q_GPIO_NUM 19 +#define SPI_HD_GPIO_NUM 20 +#define SPI_WP_GPIO_NUM 18 +#define SPI_CS0_GPIO_NUM 16 +#define SPI_CLK_GPIO_NUM 21 +#define SPI_D_GPIO_NUM 22 +#define SPI_Q_GPIO_NUM 17 -#define USB_INT_PHY0_DM_GPIO_NUM 25 -#define USB_INT_PHY0_DP_GPIO_NUM 26 +#define USB_INT_PHY0_DM_GPIO_NUM 13 +#define USB_INT_PHY0_DP_GPIO_NUM 14 #define EXT_OSC_SLOW_GPIO_NUM 0 #define MAX_RTC_GPIO_NUM 8 -#define MAX_PAD_GPIO_NUM 26 -#define MAX_GPIO_NUM 30 +#define MAX_PAD_GPIO_NUM 28 +#define MAX_GPIO_NUM 32 #define DIG_IO_HOLD_BIT_SHIFT 32 #define REG_IO_MUX_BASE DR_REG_IO_MUX_BASE @@ -137,4107 +167,127 @@ extern "C" { // definitions above are inherited from previous version of code, should double check // definitions below are generated from pin_txt.csv -#define PERIPHS_IO_MUX_XTAL_32K_P_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_XTAL_32K_P_GPIO0_0 0 -#define FUNC_XTAL_32K_P_GPIO0 1 - -#define PERIPHS_IO_MUX_XTAL_32K_N_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_XTAL_32K_N_GPIO1_0 0 -#define FUNC_XTAL_32K_N_GPIO1 1 - -// Strapping: Boot Mode select -#define PERIPHS_IO_MUX_MTMS_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_MTMS_MTMS 0 -#define FUNC_MTMS_GPIO2 1 -#define FUNC_MTMS_FSPIQ 2 - -// Strapping: Boot Mode select -#define PERIPHS_IO_MUX_MTDI_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_MTDI_MTDI 0 -#define FUNC_MTDI_GPIO3 1 - -#define PERIPHS_IO_MUX_MTCK_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_MTCK_MTCK 0 -#define FUNC_MTCK_GPIO4 1 -#define FUNC_MTCK_FSPIHD 2 - -#define PERIPHS_IO_MUX_MTDO_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_MTDO_MTDO 0 -#define FUNC_MTDO_GPIO5 1 -#define FUNC_MTDO_FSPIWP 2 - -#define PERIPHS_IO_MUX_GPIO6_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO6_GPIO6_0 0 -#define FUNC_GPIO6_GPIO6 1 -#define FUNC_GPIO6_FSPICLK 2 - -// Strapping: JTAG sel -#define PERIPHS_IO_MUX_GPIO7_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO7_GPIO7_0 0 -#define FUNC_GPIO7_GPIO7 1 -#define FUNC_GPIO7_FSPID 2 - -#define PERIPHS_IO_MUX_GPIO8_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO8_GPIO8_0 0 -#define FUNC_GPIO8_GPIO8 1 - -#define PERIPHS_IO_MUX_GPIO9_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO9_GPIO9_0 0 -#define FUNC_GPIO9_GPIO9 1 - -#define PERIPHS_IO_MUX_GPIO10_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO10_GPIO10_0 0 -#define FUNC_GPIO10_GPIO10 1 -#define FUNC_GPIO10_FSPICS0 2 - -#define PERIPHS_IO_MUX_U0TXD_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_U0TXD_U0TXD 0 -#define FUNC_U0TXD_GPIO11 1 - -#define PERIPHS_IO_MUX_U0RXD_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_U0RXD_U0RXD 0 -#define FUNC_U0RXD_GPIO12 1 - -#define PERIPHS_IO_MUX_GPIO13_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO13_GPIO13_0 0 -#define FUNC_GPIO13_GPIO13 1 - -#define PERIPHS_IO_MUX_GPIO14_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO14_GPIO14_0 0 -#define FUNC_GPIO14_GPIO14 1 - -#define PERIPHS_IO_MUX_SPICS1_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPICS1_SPICS1 0 -#define FUNC_SPICS1_GPIO15 1 - -#define PERIPHS_IO_MUX_SPICS0_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPICS0_SPICS0 0 -#define FUNC_SPICS0_GPIO16 1 - -#define PERIPHS_IO_MUX_SPIQ_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPIQ_SPIQ 0 -#define FUNC_SPIQ_GPIO17 1 - -#define PERIPHS_IO_MUX_SPIWP_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPIWP_SPIWP 0 -#define FUNC_SPIWP_GPIO18 1 - -#define PERIPHS_IO_MUX_VDD_SPI_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_VDD_SPI_GPIO19_0 0 -#define FUNC_VDD_SPI_GPIO19 1 - -#define PERIPHS_IO_MUX_SPIHD_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPIHD_SPIHD 0 -#define FUNC_SPIHD_GPIO20 1 - -#define PERIPHS_IO_MUX_SPICLK_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPICLK_SPICLK 0 -#define FUNC_SPICLK_GPIO21 1 - -#define PERIPHS_IO_MUX_SPID_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_SPID_SPID 0 -#define FUNC_SPID_GPIO22 1 - -#define PERIPHS_IO_MUX_GPIO23_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO23_GPIO23_0 0 -#define FUNC_GPIO23_GPIO23 1 - -#define PERIPHS_IO_MUX_GPIO24_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO24_GPIO24_0 0 -#define FUNC_GPIO24_GPIO24 1 - -#define PERIPHS_IO_MUX_GPIO25_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO25_GPIO25_0 0 -#define FUNC_GPIO25_GPIO25 1 - -// Strapping: Boot Mode select (analog mode) -#define PERIPHS_IO_MUX_GPIO26_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO26_GPIO26_0 0 -#define FUNC_GPIO26_GPIO26 1 - -// Strapping: Boot Mode select -#define PERIPHS_IO_MUX_GPIO27_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO27_GPIO27_0 0 -#define FUNC_GPIO27_GPIO27 1 - -// Strapping: Boot Mode select -#define PERIPHS_IO_MUX_GPIO28_U (REG_IO_MUX_BASE + 0x0) -#define FUNC_GPIO28_GPIO28_0 0 -#define FUNC_GPIO28_GPIO28 1 - - -/** IO_MUX_GPIO0_REG register - * IO MUX configuration register for GPIO0 - */ -#define IO_MUX_GPIO0_REG (DR_REG_IO_MUX_BASE + 0x0) -/** IO_MUX_GPIO0_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO0 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_MCU_OE (BIT(0)) -#define IO_MUX_GPIO0_MCU_OE_M (IO_MUX_GPIO0_MCU_OE_V << IO_MUX_GPIO0_MCU_OE_S) -#define IO_MUX_GPIO0_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO0_MCU_OE_S 0 -/** IO_MUX_GPIO0_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO0.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO0_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO0_SLP_SEL_M (IO_MUX_GPIO0_SLP_SEL_V << IO_MUX_GPIO0_SLP_SEL_S) -#define IO_MUX_GPIO0_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO0_SLP_SEL_S 1 -/** IO_MUX_GPIO0_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO0 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO0_MCU_WPD_M (IO_MUX_GPIO0_MCU_WPD_V << IO_MUX_GPIO0_MCU_WPD_S) -#define IO_MUX_GPIO0_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO0_MCU_WPD_S 2 -/** IO_MUX_GPIO0_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO0 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO0_MCU_WPU_M (IO_MUX_GPIO0_MCU_WPU_V << IO_MUX_GPIO0_MCU_WPU_S) -#define IO_MUX_GPIO0_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO0_MCU_WPU_S 3 -/** IO_MUX_GPIO0_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO0 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_MCU_IE (BIT(4)) -#define IO_MUX_GPIO0_MCU_IE_M (IO_MUX_GPIO0_MCU_IE_V << IO_MUX_GPIO0_MCU_IE_S) -#define IO_MUX_GPIO0_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO0_MCU_IE_S 4 -/** IO_MUX_GPIO0_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO0 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO0_MCU_DRV 0x00000003U -#define IO_MUX_GPIO0_MCU_DRV_M (IO_MUX_GPIO0_MCU_DRV_V << IO_MUX_GPIO0_MCU_DRV_S) -#define IO_MUX_GPIO0_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO0_MCU_DRV_S 5 -/** IO_MUX_GPIO0_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO0.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO0_FUN_WPD_M (IO_MUX_GPIO0_FUN_WPD_V << IO_MUX_GPIO0_FUN_WPD_S) -#define IO_MUX_GPIO0_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO0_FUN_WPD_S 7 -/** IO_MUX_GPIO0_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO0.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO0_FUN_WPU_M (IO_MUX_GPIO0_FUN_WPU_V << IO_MUX_GPIO0_FUN_WPU_S) -#define IO_MUX_GPIO0_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO0_FUN_WPU_S 8 -/** IO_MUX_GPIO0_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO0.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_FUN_IE (BIT(9)) -#define IO_MUX_GPIO0_FUN_IE_M (IO_MUX_GPIO0_FUN_IE_V << IO_MUX_GPIO0_FUN_IE_S) -#define IO_MUX_GPIO0_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO0_FUN_IE_S 9 -/** IO_MUX_GPIO0_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO0. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO0_FUN_DRV 0x00000003U -#define IO_MUX_GPIO0_FUN_DRV_M (IO_MUX_GPIO0_FUN_DRV_V << IO_MUX_GPIO0_FUN_DRV_S) -#define IO_MUX_GPIO0_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO0_FUN_DRV_S 10 -/** IO_MUX_GPIO0_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO0_MCU_SEL 0x00000007U -#define IO_MUX_GPIO0_MCU_SEL_M (IO_MUX_GPIO0_MCU_SEL_V << IO_MUX_GPIO0_MCU_SEL_S) -#define IO_MUX_GPIO0_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO0_MCU_SEL_S 12 -/** IO_MUX_GPIO0_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO0_FILTER_EN_M (IO_MUX_GPIO0_FILTER_EN_V << IO_MUX_GPIO0_FILTER_EN_S) -#define IO_MUX_GPIO0_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO0_FILTER_EN_S 15 -/** IO_MUX_GPIO0_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO0_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO0_HYS_EN (BIT(16)) -#define IO_MUX_GPIO0_HYS_EN_M (IO_MUX_GPIO0_HYS_EN_V << IO_MUX_GPIO0_HYS_EN_S) -#define IO_MUX_GPIO0_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO0_HYS_EN_S 16 -/** IO_MUX_GPIO0_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO0. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO0_HYS_EN\\ - */ -#define IO_MUX_GPIO0_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO0_HYS_SEL_M (IO_MUX_GPIO0_HYS_SEL_V << IO_MUX_GPIO0_HYS_SEL_S) -#define IO_MUX_GPIO0_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO0_HYS_SEL_S 17 - -/** IO_MUX_GPIO1_REG register - * IO MUX configuration register for GPIO1 - */ -#define IO_MUX_GPIO1_REG (DR_REG_IO_MUX_BASE + 0x4) -/** IO_MUX_GPIO1_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO1 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_MCU_OE (BIT(0)) -#define IO_MUX_GPIO1_MCU_OE_M (IO_MUX_GPIO1_MCU_OE_V << IO_MUX_GPIO1_MCU_OE_S) -#define IO_MUX_GPIO1_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO1_MCU_OE_S 0 -/** IO_MUX_GPIO1_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO1.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO1_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO1_SLP_SEL_M (IO_MUX_GPIO1_SLP_SEL_V << IO_MUX_GPIO1_SLP_SEL_S) -#define IO_MUX_GPIO1_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO1_SLP_SEL_S 1 -/** IO_MUX_GPIO1_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO1 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO1_MCU_WPD_M (IO_MUX_GPIO1_MCU_WPD_V << IO_MUX_GPIO1_MCU_WPD_S) -#define IO_MUX_GPIO1_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO1_MCU_WPD_S 2 -/** IO_MUX_GPIO1_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO1 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO1_MCU_WPU_M (IO_MUX_GPIO1_MCU_WPU_V << IO_MUX_GPIO1_MCU_WPU_S) -#define IO_MUX_GPIO1_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO1_MCU_WPU_S 3 -/** IO_MUX_GPIO1_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO1 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_MCU_IE (BIT(4)) -#define IO_MUX_GPIO1_MCU_IE_M (IO_MUX_GPIO1_MCU_IE_V << IO_MUX_GPIO1_MCU_IE_S) -#define IO_MUX_GPIO1_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO1_MCU_IE_S 4 -/** IO_MUX_GPIO1_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO1 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO1_MCU_DRV 0x00000003U -#define IO_MUX_GPIO1_MCU_DRV_M (IO_MUX_GPIO1_MCU_DRV_V << IO_MUX_GPIO1_MCU_DRV_S) -#define IO_MUX_GPIO1_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO1_MCU_DRV_S 5 -/** IO_MUX_GPIO1_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO1_FUN_WPD_M (IO_MUX_GPIO1_FUN_WPD_V << IO_MUX_GPIO1_FUN_WPD_S) -#define IO_MUX_GPIO1_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO1_FUN_WPD_S 7 -/** IO_MUX_GPIO1_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO1_FUN_WPU_M (IO_MUX_GPIO1_FUN_WPU_V << IO_MUX_GPIO1_FUN_WPU_S) -#define IO_MUX_GPIO1_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO1_FUN_WPU_S 8 -/** IO_MUX_GPIO1_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_FUN_IE (BIT(9)) -#define IO_MUX_GPIO1_FUN_IE_M (IO_MUX_GPIO1_FUN_IE_V << IO_MUX_GPIO1_FUN_IE_S) -#define IO_MUX_GPIO1_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO1_FUN_IE_S 9 -/** IO_MUX_GPIO1_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO1. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO1_FUN_DRV 0x00000003U -#define IO_MUX_GPIO1_FUN_DRV_M (IO_MUX_GPIO1_FUN_DRV_V << IO_MUX_GPIO1_FUN_DRV_S) -#define IO_MUX_GPIO1_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO1_FUN_DRV_S 10 -/** IO_MUX_GPIO1_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO1_MCU_SEL 0x00000007U -#define IO_MUX_GPIO1_MCU_SEL_M (IO_MUX_GPIO1_MCU_SEL_V << IO_MUX_GPIO1_MCU_SEL_S) -#define IO_MUX_GPIO1_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO1_MCU_SEL_S 12 -/** IO_MUX_GPIO1_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO1_FILTER_EN_M (IO_MUX_GPIO1_FILTER_EN_V << IO_MUX_GPIO1_FILTER_EN_S) -#define IO_MUX_GPIO1_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO1_FILTER_EN_S 15 -/** IO_MUX_GPIO1_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO1_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO1_HYS_EN (BIT(16)) -#define IO_MUX_GPIO1_HYS_EN_M (IO_MUX_GPIO1_HYS_EN_V << IO_MUX_GPIO1_HYS_EN_S) -#define IO_MUX_GPIO1_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO1_HYS_EN_S 16 -/** IO_MUX_GPIO1_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO1. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO1_HYS_EN\\ - */ -#define IO_MUX_GPIO1_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO1_HYS_SEL_M (IO_MUX_GPIO1_HYS_SEL_V << IO_MUX_GPIO1_HYS_SEL_S) -#define IO_MUX_GPIO1_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO1_HYS_SEL_S 17 - -/** IO_MUX_GPIO2_REG register - * IO MUX configuration register for GPIO2 - */ -#define IO_MUX_GPIO2_REG (DR_REG_IO_MUX_BASE + 0x8) -/** IO_MUX_GPIO2_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO2 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_MCU_OE (BIT(0)) -#define IO_MUX_GPIO2_MCU_OE_M (IO_MUX_GPIO2_MCU_OE_V << IO_MUX_GPIO2_MCU_OE_S) -#define IO_MUX_GPIO2_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO2_MCU_OE_S 0 -/** IO_MUX_GPIO2_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO2.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO2_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO2_SLP_SEL_M (IO_MUX_GPIO2_SLP_SEL_V << IO_MUX_GPIO2_SLP_SEL_S) -#define IO_MUX_GPIO2_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO2_SLP_SEL_S 1 -/** IO_MUX_GPIO2_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO2 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO2_MCU_WPD_M (IO_MUX_GPIO2_MCU_WPD_V << IO_MUX_GPIO2_MCU_WPD_S) -#define IO_MUX_GPIO2_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO2_MCU_WPD_S 2 -/** IO_MUX_GPIO2_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO2 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO2_MCU_WPU_M (IO_MUX_GPIO2_MCU_WPU_V << IO_MUX_GPIO2_MCU_WPU_S) -#define IO_MUX_GPIO2_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO2_MCU_WPU_S 3 -/** IO_MUX_GPIO2_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO2 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_MCU_IE (BIT(4)) -#define IO_MUX_GPIO2_MCU_IE_M (IO_MUX_GPIO2_MCU_IE_V << IO_MUX_GPIO2_MCU_IE_S) -#define IO_MUX_GPIO2_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO2_MCU_IE_S 4 -/** IO_MUX_GPIO2_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO2 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO2_MCU_DRV 0x00000003U -#define IO_MUX_GPIO2_MCU_DRV_M (IO_MUX_GPIO2_MCU_DRV_V << IO_MUX_GPIO2_MCU_DRV_S) -#define IO_MUX_GPIO2_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO2_MCU_DRV_S 5 -/** IO_MUX_GPIO2_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO2.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO2_FUN_WPD_M (IO_MUX_GPIO2_FUN_WPD_V << IO_MUX_GPIO2_FUN_WPD_S) -#define IO_MUX_GPIO2_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO2_FUN_WPD_S 7 -/** IO_MUX_GPIO2_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO2.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO2_FUN_WPU_M (IO_MUX_GPIO2_FUN_WPU_V << IO_MUX_GPIO2_FUN_WPU_S) -#define IO_MUX_GPIO2_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO2_FUN_WPU_S 8 -/** IO_MUX_GPIO2_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO2.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_FUN_IE (BIT(9)) -#define IO_MUX_GPIO2_FUN_IE_M (IO_MUX_GPIO2_FUN_IE_V << IO_MUX_GPIO2_FUN_IE_S) -#define IO_MUX_GPIO2_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO2_FUN_IE_S 9 -/** IO_MUX_GPIO2_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO2. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO2_FUN_DRV 0x00000003U -#define IO_MUX_GPIO2_FUN_DRV_M (IO_MUX_GPIO2_FUN_DRV_V << IO_MUX_GPIO2_FUN_DRV_S) -#define IO_MUX_GPIO2_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO2_FUN_DRV_S 10 -/** IO_MUX_GPIO2_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO2_MCU_SEL 0x00000007U -#define IO_MUX_GPIO2_MCU_SEL_M (IO_MUX_GPIO2_MCU_SEL_V << IO_MUX_GPIO2_MCU_SEL_S) -#define IO_MUX_GPIO2_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO2_MCU_SEL_S 12 -/** IO_MUX_GPIO2_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO2_FILTER_EN_M (IO_MUX_GPIO2_FILTER_EN_V << IO_MUX_GPIO2_FILTER_EN_S) -#define IO_MUX_GPIO2_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO2_FILTER_EN_S 15 -/** IO_MUX_GPIO2_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO2_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO2_HYS_EN (BIT(16)) -#define IO_MUX_GPIO2_HYS_EN_M (IO_MUX_GPIO2_HYS_EN_V << IO_MUX_GPIO2_HYS_EN_S) -#define IO_MUX_GPIO2_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO2_HYS_EN_S 16 -/** IO_MUX_GPIO2_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO2. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO2_HYS_EN\\ - */ -#define IO_MUX_GPIO2_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO2_HYS_SEL_M (IO_MUX_GPIO2_HYS_SEL_V << IO_MUX_GPIO2_HYS_SEL_S) -#define IO_MUX_GPIO2_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO2_HYS_SEL_S 17 - -/** IO_MUX_GPIO3_REG register - * IO MUX configuration register for GPIO3 - */ -#define IO_MUX_GPIO3_REG (DR_REG_IO_MUX_BASE + 0xc) -/** IO_MUX_GPIO3_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO3 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_MCU_OE (BIT(0)) -#define IO_MUX_GPIO3_MCU_OE_M (IO_MUX_GPIO3_MCU_OE_V << IO_MUX_GPIO3_MCU_OE_S) -#define IO_MUX_GPIO3_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO3_MCU_OE_S 0 -/** IO_MUX_GPIO3_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO3.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO3_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO3_SLP_SEL_M (IO_MUX_GPIO3_SLP_SEL_V << IO_MUX_GPIO3_SLP_SEL_S) -#define IO_MUX_GPIO3_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO3_SLP_SEL_S 1 -/** IO_MUX_GPIO3_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO3 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO3_MCU_WPD_M (IO_MUX_GPIO3_MCU_WPD_V << IO_MUX_GPIO3_MCU_WPD_S) -#define IO_MUX_GPIO3_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO3_MCU_WPD_S 2 -/** IO_MUX_GPIO3_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO3 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO3_MCU_WPU_M (IO_MUX_GPIO3_MCU_WPU_V << IO_MUX_GPIO3_MCU_WPU_S) -#define IO_MUX_GPIO3_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO3_MCU_WPU_S 3 -/** IO_MUX_GPIO3_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO3 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_MCU_IE (BIT(4)) -#define IO_MUX_GPIO3_MCU_IE_M (IO_MUX_GPIO3_MCU_IE_V << IO_MUX_GPIO3_MCU_IE_S) -#define IO_MUX_GPIO3_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO3_MCU_IE_S 4 -/** IO_MUX_GPIO3_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO3 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO3_MCU_DRV 0x00000003U -#define IO_MUX_GPIO3_MCU_DRV_M (IO_MUX_GPIO3_MCU_DRV_V << IO_MUX_GPIO3_MCU_DRV_S) -#define IO_MUX_GPIO3_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO3_MCU_DRV_S 5 -/** IO_MUX_GPIO3_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO3.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO3_FUN_WPD_M (IO_MUX_GPIO3_FUN_WPD_V << IO_MUX_GPIO3_FUN_WPD_S) -#define IO_MUX_GPIO3_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO3_FUN_WPD_S 7 -/** IO_MUX_GPIO3_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO3.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO3_FUN_WPU_M (IO_MUX_GPIO3_FUN_WPU_V << IO_MUX_GPIO3_FUN_WPU_S) -#define IO_MUX_GPIO3_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO3_FUN_WPU_S 8 -/** IO_MUX_GPIO3_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO3.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_FUN_IE (BIT(9)) -#define IO_MUX_GPIO3_FUN_IE_M (IO_MUX_GPIO3_FUN_IE_V << IO_MUX_GPIO3_FUN_IE_S) -#define IO_MUX_GPIO3_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO3_FUN_IE_S 9 -/** IO_MUX_GPIO3_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO3. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO3_FUN_DRV 0x00000003U -#define IO_MUX_GPIO3_FUN_DRV_M (IO_MUX_GPIO3_FUN_DRV_V << IO_MUX_GPIO3_FUN_DRV_S) -#define IO_MUX_GPIO3_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO3_FUN_DRV_S 10 -/** IO_MUX_GPIO3_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO3_MCU_SEL 0x00000007U -#define IO_MUX_GPIO3_MCU_SEL_M (IO_MUX_GPIO3_MCU_SEL_V << IO_MUX_GPIO3_MCU_SEL_S) -#define IO_MUX_GPIO3_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO3_MCU_SEL_S 12 -/** IO_MUX_GPIO3_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO3_FILTER_EN_M (IO_MUX_GPIO3_FILTER_EN_V << IO_MUX_GPIO3_FILTER_EN_S) -#define IO_MUX_GPIO3_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO3_FILTER_EN_S 15 -/** IO_MUX_GPIO3_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO3_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO3_HYS_EN (BIT(16)) -#define IO_MUX_GPIO3_HYS_EN_M (IO_MUX_GPIO3_HYS_EN_V << IO_MUX_GPIO3_HYS_EN_S) -#define IO_MUX_GPIO3_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO3_HYS_EN_S 16 -/** IO_MUX_GPIO3_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO3. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO3_HYS_EN\\ - */ -#define IO_MUX_GPIO3_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO3_HYS_SEL_M (IO_MUX_GPIO3_HYS_SEL_V << IO_MUX_GPIO3_HYS_SEL_S) -#define IO_MUX_GPIO3_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO3_HYS_SEL_S 17 - -/** IO_MUX_GPIO4_REG register - * IO MUX configuration register for GPIO4 - */ -#define IO_MUX_GPIO4_REG (DR_REG_IO_MUX_BASE + 0x10) -/** IO_MUX_GPIO4_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO4 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_MCU_OE (BIT(0)) -#define IO_MUX_GPIO4_MCU_OE_M (IO_MUX_GPIO4_MCU_OE_V << IO_MUX_GPIO4_MCU_OE_S) -#define IO_MUX_GPIO4_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO4_MCU_OE_S 0 -/** IO_MUX_GPIO4_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO4.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO4_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO4_SLP_SEL_M (IO_MUX_GPIO4_SLP_SEL_V << IO_MUX_GPIO4_SLP_SEL_S) -#define IO_MUX_GPIO4_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO4_SLP_SEL_S 1 -/** IO_MUX_GPIO4_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO4 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO4_MCU_WPD_M (IO_MUX_GPIO4_MCU_WPD_V << IO_MUX_GPIO4_MCU_WPD_S) -#define IO_MUX_GPIO4_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO4_MCU_WPD_S 2 -/** IO_MUX_GPIO4_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO4 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO4_MCU_WPU_M (IO_MUX_GPIO4_MCU_WPU_V << IO_MUX_GPIO4_MCU_WPU_S) -#define IO_MUX_GPIO4_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO4_MCU_WPU_S 3 -/** IO_MUX_GPIO4_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO4 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_MCU_IE (BIT(4)) -#define IO_MUX_GPIO4_MCU_IE_M (IO_MUX_GPIO4_MCU_IE_V << IO_MUX_GPIO4_MCU_IE_S) -#define IO_MUX_GPIO4_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO4_MCU_IE_S 4 -/** IO_MUX_GPIO4_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO4 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO4_MCU_DRV 0x00000003U -#define IO_MUX_GPIO4_MCU_DRV_M (IO_MUX_GPIO4_MCU_DRV_V << IO_MUX_GPIO4_MCU_DRV_S) -#define IO_MUX_GPIO4_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO4_MCU_DRV_S 5 -/** IO_MUX_GPIO4_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO4.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO4_FUN_WPD_M (IO_MUX_GPIO4_FUN_WPD_V << IO_MUX_GPIO4_FUN_WPD_S) -#define IO_MUX_GPIO4_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO4_FUN_WPD_S 7 -/** IO_MUX_GPIO4_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO4.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO4_FUN_WPU_M (IO_MUX_GPIO4_FUN_WPU_V << IO_MUX_GPIO4_FUN_WPU_S) -#define IO_MUX_GPIO4_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO4_FUN_WPU_S 8 -/** IO_MUX_GPIO4_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO4.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_FUN_IE (BIT(9)) -#define IO_MUX_GPIO4_FUN_IE_M (IO_MUX_GPIO4_FUN_IE_V << IO_MUX_GPIO4_FUN_IE_S) -#define IO_MUX_GPIO4_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO4_FUN_IE_S 9 -/** IO_MUX_GPIO4_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO4. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO4_FUN_DRV 0x00000003U -#define IO_MUX_GPIO4_FUN_DRV_M (IO_MUX_GPIO4_FUN_DRV_V << IO_MUX_GPIO4_FUN_DRV_S) -#define IO_MUX_GPIO4_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO4_FUN_DRV_S 10 -/** IO_MUX_GPIO4_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO4_MCU_SEL 0x00000007U -#define IO_MUX_GPIO4_MCU_SEL_M (IO_MUX_GPIO4_MCU_SEL_V << IO_MUX_GPIO4_MCU_SEL_S) -#define IO_MUX_GPIO4_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO4_MCU_SEL_S 12 -/** IO_MUX_GPIO4_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO4_FILTER_EN_M (IO_MUX_GPIO4_FILTER_EN_V << IO_MUX_GPIO4_FILTER_EN_S) -#define IO_MUX_GPIO4_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO4_FILTER_EN_S 15 -/** IO_MUX_GPIO4_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO4_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO4_HYS_EN (BIT(16)) -#define IO_MUX_GPIO4_HYS_EN_M (IO_MUX_GPIO4_HYS_EN_V << IO_MUX_GPIO4_HYS_EN_S) -#define IO_MUX_GPIO4_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO4_HYS_EN_S 16 -/** IO_MUX_GPIO4_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO4. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO4_HYS_EN\\ - */ -#define IO_MUX_GPIO4_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO4_HYS_SEL_M (IO_MUX_GPIO4_HYS_SEL_V << IO_MUX_GPIO4_HYS_SEL_S) -#define IO_MUX_GPIO4_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO4_HYS_SEL_S 17 - -/** IO_MUX_GPIO5_REG register - * IO MUX configuration register for GPIO5 - */ -#define IO_MUX_GPIO5_REG (DR_REG_IO_MUX_BASE + 0x14) -/** IO_MUX_GPIO5_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO5 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_MCU_OE (BIT(0)) -#define IO_MUX_GPIO5_MCU_OE_M (IO_MUX_GPIO5_MCU_OE_V << IO_MUX_GPIO5_MCU_OE_S) -#define IO_MUX_GPIO5_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO5_MCU_OE_S 0 -/** IO_MUX_GPIO5_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO5.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO5_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO5_SLP_SEL_M (IO_MUX_GPIO5_SLP_SEL_V << IO_MUX_GPIO5_SLP_SEL_S) -#define IO_MUX_GPIO5_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO5_SLP_SEL_S 1 -/** IO_MUX_GPIO5_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO5 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO5_MCU_WPD_M (IO_MUX_GPIO5_MCU_WPD_V << IO_MUX_GPIO5_MCU_WPD_S) -#define IO_MUX_GPIO5_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO5_MCU_WPD_S 2 -/** IO_MUX_GPIO5_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO5 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO5_MCU_WPU_M (IO_MUX_GPIO5_MCU_WPU_V << IO_MUX_GPIO5_MCU_WPU_S) -#define IO_MUX_GPIO5_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO5_MCU_WPU_S 3 -/** IO_MUX_GPIO5_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO5 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_MCU_IE (BIT(4)) -#define IO_MUX_GPIO5_MCU_IE_M (IO_MUX_GPIO5_MCU_IE_V << IO_MUX_GPIO5_MCU_IE_S) -#define IO_MUX_GPIO5_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO5_MCU_IE_S 4 -/** IO_MUX_GPIO5_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO5 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO5_MCU_DRV 0x00000003U -#define IO_MUX_GPIO5_MCU_DRV_M (IO_MUX_GPIO5_MCU_DRV_V << IO_MUX_GPIO5_MCU_DRV_S) -#define IO_MUX_GPIO5_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO5_MCU_DRV_S 5 -/** IO_MUX_GPIO5_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO5.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO5_FUN_WPD_M (IO_MUX_GPIO5_FUN_WPD_V << IO_MUX_GPIO5_FUN_WPD_S) -#define IO_MUX_GPIO5_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO5_FUN_WPD_S 7 -/** IO_MUX_GPIO5_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO5.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO5_FUN_WPU_M (IO_MUX_GPIO5_FUN_WPU_V << IO_MUX_GPIO5_FUN_WPU_S) -#define IO_MUX_GPIO5_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO5_FUN_WPU_S 8 -/** IO_MUX_GPIO5_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO5.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_FUN_IE (BIT(9)) -#define IO_MUX_GPIO5_FUN_IE_M (IO_MUX_GPIO5_FUN_IE_V << IO_MUX_GPIO5_FUN_IE_S) -#define IO_MUX_GPIO5_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO5_FUN_IE_S 9 -/** IO_MUX_GPIO5_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO5. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO5_FUN_DRV 0x00000003U -#define IO_MUX_GPIO5_FUN_DRV_M (IO_MUX_GPIO5_FUN_DRV_V << IO_MUX_GPIO5_FUN_DRV_S) -#define IO_MUX_GPIO5_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO5_FUN_DRV_S 10 -/** IO_MUX_GPIO5_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO5_MCU_SEL 0x00000007U -#define IO_MUX_GPIO5_MCU_SEL_M (IO_MUX_GPIO5_MCU_SEL_V << IO_MUX_GPIO5_MCU_SEL_S) -#define IO_MUX_GPIO5_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO5_MCU_SEL_S 12 -/** IO_MUX_GPIO5_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO5_FILTER_EN_M (IO_MUX_GPIO5_FILTER_EN_V << IO_MUX_GPIO5_FILTER_EN_S) -#define IO_MUX_GPIO5_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO5_FILTER_EN_S 15 -/** IO_MUX_GPIO5_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO5_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO5_HYS_EN (BIT(16)) -#define IO_MUX_GPIO5_HYS_EN_M (IO_MUX_GPIO5_HYS_EN_V << IO_MUX_GPIO5_HYS_EN_S) -#define IO_MUX_GPIO5_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO5_HYS_EN_S 16 -/** IO_MUX_GPIO5_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO5. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO5_HYS_EN\\ - */ -#define IO_MUX_GPIO5_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO5_HYS_SEL_M (IO_MUX_GPIO5_HYS_SEL_V << IO_MUX_GPIO5_HYS_SEL_S) -#define IO_MUX_GPIO5_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO5_HYS_SEL_S 17 - -/** IO_MUX_GPIO6_REG register - * IO MUX configuration register for GPIO6 - */ -#define IO_MUX_GPIO6_REG (DR_REG_IO_MUX_BASE + 0x18) -/** IO_MUX_GPIO6_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO6 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_MCU_OE (BIT(0)) -#define IO_MUX_GPIO6_MCU_OE_M (IO_MUX_GPIO6_MCU_OE_V << IO_MUX_GPIO6_MCU_OE_S) -#define IO_MUX_GPIO6_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO6_MCU_OE_S 0 -/** IO_MUX_GPIO6_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO6.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO6_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO6_SLP_SEL_M (IO_MUX_GPIO6_SLP_SEL_V << IO_MUX_GPIO6_SLP_SEL_S) -#define IO_MUX_GPIO6_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO6_SLP_SEL_S 1 -/** IO_MUX_GPIO6_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO6 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO6_MCU_WPD_M (IO_MUX_GPIO6_MCU_WPD_V << IO_MUX_GPIO6_MCU_WPD_S) -#define IO_MUX_GPIO6_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO6_MCU_WPD_S 2 -/** IO_MUX_GPIO6_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO6 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO6_MCU_WPU_M (IO_MUX_GPIO6_MCU_WPU_V << IO_MUX_GPIO6_MCU_WPU_S) -#define IO_MUX_GPIO6_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO6_MCU_WPU_S 3 -/** IO_MUX_GPIO6_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO6 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_MCU_IE (BIT(4)) -#define IO_MUX_GPIO6_MCU_IE_M (IO_MUX_GPIO6_MCU_IE_V << IO_MUX_GPIO6_MCU_IE_S) -#define IO_MUX_GPIO6_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO6_MCU_IE_S 4 -/** IO_MUX_GPIO6_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO6 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO6_MCU_DRV 0x00000003U -#define IO_MUX_GPIO6_MCU_DRV_M (IO_MUX_GPIO6_MCU_DRV_V << IO_MUX_GPIO6_MCU_DRV_S) -#define IO_MUX_GPIO6_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO6_MCU_DRV_S 5 -/** IO_MUX_GPIO6_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO6.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO6_FUN_WPD_M (IO_MUX_GPIO6_FUN_WPD_V << IO_MUX_GPIO6_FUN_WPD_S) -#define IO_MUX_GPIO6_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO6_FUN_WPD_S 7 -/** IO_MUX_GPIO6_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO6.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO6_FUN_WPU_M (IO_MUX_GPIO6_FUN_WPU_V << IO_MUX_GPIO6_FUN_WPU_S) -#define IO_MUX_GPIO6_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO6_FUN_WPU_S 8 -/** IO_MUX_GPIO6_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO6.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_FUN_IE (BIT(9)) -#define IO_MUX_GPIO6_FUN_IE_M (IO_MUX_GPIO6_FUN_IE_V << IO_MUX_GPIO6_FUN_IE_S) -#define IO_MUX_GPIO6_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO6_FUN_IE_S 9 -/** IO_MUX_GPIO6_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO6. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO6_FUN_DRV 0x00000003U -#define IO_MUX_GPIO6_FUN_DRV_M (IO_MUX_GPIO6_FUN_DRV_V << IO_MUX_GPIO6_FUN_DRV_S) -#define IO_MUX_GPIO6_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO6_FUN_DRV_S 10 -/** IO_MUX_GPIO6_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO6_MCU_SEL 0x00000007U -#define IO_MUX_GPIO6_MCU_SEL_M (IO_MUX_GPIO6_MCU_SEL_V << IO_MUX_GPIO6_MCU_SEL_S) -#define IO_MUX_GPIO6_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO6_MCU_SEL_S 12 -/** IO_MUX_GPIO6_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO6_FILTER_EN_M (IO_MUX_GPIO6_FILTER_EN_V << IO_MUX_GPIO6_FILTER_EN_S) -#define IO_MUX_GPIO6_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO6_FILTER_EN_S 15 -/** IO_MUX_GPIO6_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO6_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO6_HYS_EN (BIT(16)) -#define IO_MUX_GPIO6_HYS_EN_M (IO_MUX_GPIO6_HYS_EN_V << IO_MUX_GPIO6_HYS_EN_S) -#define IO_MUX_GPIO6_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO6_HYS_EN_S 16 -/** IO_MUX_GPIO6_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO6. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO6_HYS_EN\\ - */ -#define IO_MUX_GPIO6_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO6_HYS_SEL_M (IO_MUX_GPIO6_HYS_SEL_V << IO_MUX_GPIO6_HYS_SEL_S) -#define IO_MUX_GPIO6_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO6_HYS_SEL_S 17 - -/** IO_MUX_GPIO7_REG register - * IO MUX configuration register for GPIO7 - */ -#define IO_MUX_GPIO7_REG (DR_REG_IO_MUX_BASE + 0x1c) -/** IO_MUX_GPIO7_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO7 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_MCU_OE (BIT(0)) -#define IO_MUX_GPIO7_MCU_OE_M (IO_MUX_GPIO7_MCU_OE_V << IO_MUX_GPIO7_MCU_OE_S) -#define IO_MUX_GPIO7_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO7_MCU_OE_S 0 -/** IO_MUX_GPIO7_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO7.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO7_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO7_SLP_SEL_M (IO_MUX_GPIO7_SLP_SEL_V << IO_MUX_GPIO7_SLP_SEL_S) -#define IO_MUX_GPIO7_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO7_SLP_SEL_S 1 -/** IO_MUX_GPIO7_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO7 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO7_MCU_WPD_M (IO_MUX_GPIO7_MCU_WPD_V << IO_MUX_GPIO7_MCU_WPD_S) -#define IO_MUX_GPIO7_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO7_MCU_WPD_S 2 -/** IO_MUX_GPIO7_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO7 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO7_MCU_WPU_M (IO_MUX_GPIO7_MCU_WPU_V << IO_MUX_GPIO7_MCU_WPU_S) -#define IO_MUX_GPIO7_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO7_MCU_WPU_S 3 -/** IO_MUX_GPIO7_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO7 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_MCU_IE (BIT(4)) -#define IO_MUX_GPIO7_MCU_IE_M (IO_MUX_GPIO7_MCU_IE_V << IO_MUX_GPIO7_MCU_IE_S) -#define IO_MUX_GPIO7_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO7_MCU_IE_S 4 -/** IO_MUX_GPIO7_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO7 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO7_MCU_DRV 0x00000003U -#define IO_MUX_GPIO7_MCU_DRV_M (IO_MUX_GPIO7_MCU_DRV_V << IO_MUX_GPIO7_MCU_DRV_S) -#define IO_MUX_GPIO7_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO7_MCU_DRV_S 5 -/** IO_MUX_GPIO7_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO7.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO7_FUN_WPD_M (IO_MUX_GPIO7_FUN_WPD_V << IO_MUX_GPIO7_FUN_WPD_S) -#define IO_MUX_GPIO7_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO7_FUN_WPD_S 7 -/** IO_MUX_GPIO7_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO7.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO7_FUN_WPU_M (IO_MUX_GPIO7_FUN_WPU_V << IO_MUX_GPIO7_FUN_WPU_S) -#define IO_MUX_GPIO7_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO7_FUN_WPU_S 8 -/** IO_MUX_GPIO7_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO7.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_FUN_IE (BIT(9)) -#define IO_MUX_GPIO7_FUN_IE_M (IO_MUX_GPIO7_FUN_IE_V << IO_MUX_GPIO7_FUN_IE_S) -#define IO_MUX_GPIO7_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO7_FUN_IE_S 9 -/** IO_MUX_GPIO7_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO7. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO7_FUN_DRV 0x00000003U -#define IO_MUX_GPIO7_FUN_DRV_M (IO_MUX_GPIO7_FUN_DRV_V << IO_MUX_GPIO7_FUN_DRV_S) -#define IO_MUX_GPIO7_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO7_FUN_DRV_S 10 -/** IO_MUX_GPIO7_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO7_MCU_SEL 0x00000007U -#define IO_MUX_GPIO7_MCU_SEL_M (IO_MUX_GPIO7_MCU_SEL_V << IO_MUX_GPIO7_MCU_SEL_S) -#define IO_MUX_GPIO7_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO7_MCU_SEL_S 12 -/** IO_MUX_GPIO7_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO7_FILTER_EN_M (IO_MUX_GPIO7_FILTER_EN_V << IO_MUX_GPIO7_FILTER_EN_S) -#define IO_MUX_GPIO7_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO7_FILTER_EN_S 15 -/** IO_MUX_GPIO7_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO7_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO7_HYS_EN (BIT(16)) -#define IO_MUX_GPIO7_HYS_EN_M (IO_MUX_GPIO7_HYS_EN_V << IO_MUX_GPIO7_HYS_EN_S) -#define IO_MUX_GPIO7_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO7_HYS_EN_S 16 -/** IO_MUX_GPIO7_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO7. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO7_HYS_EN\\ - */ -#define IO_MUX_GPIO7_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO7_HYS_SEL_M (IO_MUX_GPIO7_HYS_SEL_V << IO_MUX_GPIO7_HYS_SEL_S) -#define IO_MUX_GPIO7_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO7_HYS_SEL_S 17 - -/** IO_MUX_GPIO8_REG register - * IO MUX configuration register for GPIO8 - */ -#define IO_MUX_GPIO8_REG (DR_REG_IO_MUX_BASE + 0x20) -/** IO_MUX_GPIO8_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO8 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_MCU_OE (BIT(0)) -#define IO_MUX_GPIO8_MCU_OE_M (IO_MUX_GPIO8_MCU_OE_V << IO_MUX_GPIO8_MCU_OE_S) -#define IO_MUX_GPIO8_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO8_MCU_OE_S 0 -/** IO_MUX_GPIO8_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO8.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO8_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO8_SLP_SEL_M (IO_MUX_GPIO8_SLP_SEL_V << IO_MUX_GPIO8_SLP_SEL_S) -#define IO_MUX_GPIO8_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO8_SLP_SEL_S 1 -/** IO_MUX_GPIO8_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO8 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO8_MCU_WPD_M (IO_MUX_GPIO8_MCU_WPD_V << IO_MUX_GPIO8_MCU_WPD_S) -#define IO_MUX_GPIO8_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO8_MCU_WPD_S 2 -/** IO_MUX_GPIO8_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO8 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO8_MCU_WPU_M (IO_MUX_GPIO8_MCU_WPU_V << IO_MUX_GPIO8_MCU_WPU_S) -#define IO_MUX_GPIO8_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO8_MCU_WPU_S 3 -/** IO_MUX_GPIO8_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO8 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_MCU_IE (BIT(4)) -#define IO_MUX_GPIO8_MCU_IE_M (IO_MUX_GPIO8_MCU_IE_V << IO_MUX_GPIO8_MCU_IE_S) -#define IO_MUX_GPIO8_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO8_MCU_IE_S 4 -/** IO_MUX_GPIO8_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO8 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO8_MCU_DRV 0x00000003U -#define IO_MUX_GPIO8_MCU_DRV_M (IO_MUX_GPIO8_MCU_DRV_V << IO_MUX_GPIO8_MCU_DRV_S) -#define IO_MUX_GPIO8_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO8_MCU_DRV_S 5 -/** IO_MUX_GPIO8_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO8.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO8_FUN_WPD_M (IO_MUX_GPIO8_FUN_WPD_V << IO_MUX_GPIO8_FUN_WPD_S) -#define IO_MUX_GPIO8_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO8_FUN_WPD_S 7 -/** IO_MUX_GPIO8_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO8.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO8_FUN_WPU_M (IO_MUX_GPIO8_FUN_WPU_V << IO_MUX_GPIO8_FUN_WPU_S) -#define IO_MUX_GPIO8_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO8_FUN_WPU_S 8 -/** IO_MUX_GPIO8_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO8.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_FUN_IE (BIT(9)) -#define IO_MUX_GPIO8_FUN_IE_M (IO_MUX_GPIO8_FUN_IE_V << IO_MUX_GPIO8_FUN_IE_S) -#define IO_MUX_GPIO8_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO8_FUN_IE_S 9 -/** IO_MUX_GPIO8_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO8. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO8_FUN_DRV 0x00000003U -#define IO_MUX_GPIO8_FUN_DRV_M (IO_MUX_GPIO8_FUN_DRV_V << IO_MUX_GPIO8_FUN_DRV_S) -#define IO_MUX_GPIO8_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO8_FUN_DRV_S 10 -/** IO_MUX_GPIO8_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO8_MCU_SEL 0x00000007U -#define IO_MUX_GPIO8_MCU_SEL_M (IO_MUX_GPIO8_MCU_SEL_V << IO_MUX_GPIO8_MCU_SEL_S) -#define IO_MUX_GPIO8_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO8_MCU_SEL_S 12 -/** IO_MUX_GPIO8_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO8_FILTER_EN_M (IO_MUX_GPIO8_FILTER_EN_V << IO_MUX_GPIO8_FILTER_EN_S) -#define IO_MUX_GPIO8_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO8_FILTER_EN_S 15 -/** IO_MUX_GPIO8_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO8_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO8_HYS_EN (BIT(16)) -#define IO_MUX_GPIO8_HYS_EN_M (IO_MUX_GPIO8_HYS_EN_V << IO_MUX_GPIO8_HYS_EN_S) -#define IO_MUX_GPIO8_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO8_HYS_EN_S 16 -/** IO_MUX_GPIO8_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO8. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO8_HYS_EN\\ - */ -#define IO_MUX_GPIO8_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO8_HYS_SEL_M (IO_MUX_GPIO8_HYS_SEL_V << IO_MUX_GPIO8_HYS_SEL_S) -#define IO_MUX_GPIO8_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO8_HYS_SEL_S 17 - -/** IO_MUX_GPIO9_REG register - * IO MUX configuration register for GPIO9 - */ -#define IO_MUX_GPIO9_REG (DR_REG_IO_MUX_BASE + 0x24) -/** IO_MUX_GPIO9_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO9 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_MCU_OE (BIT(0)) -#define IO_MUX_GPIO9_MCU_OE_M (IO_MUX_GPIO9_MCU_OE_V << IO_MUX_GPIO9_MCU_OE_S) -#define IO_MUX_GPIO9_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO9_MCU_OE_S 0 -/** IO_MUX_GPIO9_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO9.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO9_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO9_SLP_SEL_M (IO_MUX_GPIO9_SLP_SEL_V << IO_MUX_GPIO9_SLP_SEL_S) -#define IO_MUX_GPIO9_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO9_SLP_SEL_S 1 -/** IO_MUX_GPIO9_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO9 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO9_MCU_WPD_M (IO_MUX_GPIO9_MCU_WPD_V << IO_MUX_GPIO9_MCU_WPD_S) -#define IO_MUX_GPIO9_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO9_MCU_WPD_S 2 -/** IO_MUX_GPIO9_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO9 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO9_MCU_WPU_M (IO_MUX_GPIO9_MCU_WPU_V << IO_MUX_GPIO9_MCU_WPU_S) -#define IO_MUX_GPIO9_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO9_MCU_WPU_S 3 -/** IO_MUX_GPIO9_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO9 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_MCU_IE (BIT(4)) -#define IO_MUX_GPIO9_MCU_IE_M (IO_MUX_GPIO9_MCU_IE_V << IO_MUX_GPIO9_MCU_IE_S) -#define IO_MUX_GPIO9_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO9_MCU_IE_S 4 -/** IO_MUX_GPIO9_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO9 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO9_MCU_DRV 0x00000003U -#define IO_MUX_GPIO9_MCU_DRV_M (IO_MUX_GPIO9_MCU_DRV_V << IO_MUX_GPIO9_MCU_DRV_S) -#define IO_MUX_GPIO9_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO9_MCU_DRV_S 5 -/** IO_MUX_GPIO9_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO9.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO9_FUN_WPD_M (IO_MUX_GPIO9_FUN_WPD_V << IO_MUX_GPIO9_FUN_WPD_S) -#define IO_MUX_GPIO9_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO9_FUN_WPD_S 7 -/** IO_MUX_GPIO9_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO9.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO9_FUN_WPU_M (IO_MUX_GPIO9_FUN_WPU_V << IO_MUX_GPIO9_FUN_WPU_S) -#define IO_MUX_GPIO9_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO9_FUN_WPU_S 8 -/** IO_MUX_GPIO9_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO9.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_FUN_IE (BIT(9)) -#define IO_MUX_GPIO9_FUN_IE_M (IO_MUX_GPIO9_FUN_IE_V << IO_MUX_GPIO9_FUN_IE_S) -#define IO_MUX_GPIO9_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO9_FUN_IE_S 9 -/** IO_MUX_GPIO9_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO9. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO9_FUN_DRV 0x00000003U -#define IO_MUX_GPIO9_FUN_DRV_M (IO_MUX_GPIO9_FUN_DRV_V << IO_MUX_GPIO9_FUN_DRV_S) -#define IO_MUX_GPIO9_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO9_FUN_DRV_S 10 -/** IO_MUX_GPIO9_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO9_MCU_SEL 0x00000007U -#define IO_MUX_GPIO9_MCU_SEL_M (IO_MUX_GPIO9_MCU_SEL_V << IO_MUX_GPIO9_MCU_SEL_S) -#define IO_MUX_GPIO9_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO9_MCU_SEL_S 12 -/** IO_MUX_GPIO9_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO9_FILTER_EN_M (IO_MUX_GPIO9_FILTER_EN_V << IO_MUX_GPIO9_FILTER_EN_S) -#define IO_MUX_GPIO9_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO9_FILTER_EN_S 15 -/** IO_MUX_GPIO9_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO9_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO9_HYS_EN (BIT(16)) -#define IO_MUX_GPIO9_HYS_EN_M (IO_MUX_GPIO9_HYS_EN_V << IO_MUX_GPIO9_HYS_EN_S) -#define IO_MUX_GPIO9_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO9_HYS_EN_S 16 -/** IO_MUX_GPIO9_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO9. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO9_HYS_EN\\ - */ -#define IO_MUX_GPIO9_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO9_HYS_SEL_M (IO_MUX_GPIO9_HYS_SEL_V << IO_MUX_GPIO9_HYS_SEL_S) -#define IO_MUX_GPIO9_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO9_HYS_SEL_S 17 - -/** IO_MUX_GPIO10_REG register - * IO MUX configuration register for GPIO10 - */ -#define IO_MUX_GPIO10_REG (DR_REG_IO_MUX_BASE + 0x28) -/** IO_MUX_GPIO10_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO10 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_MCU_OE (BIT(0)) -#define IO_MUX_GPIO10_MCU_OE_M (IO_MUX_GPIO10_MCU_OE_V << IO_MUX_GPIO10_MCU_OE_S) -#define IO_MUX_GPIO10_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO10_MCU_OE_S 0 -/** IO_MUX_GPIO10_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO10.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO10_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO10_SLP_SEL_M (IO_MUX_GPIO10_SLP_SEL_V << IO_MUX_GPIO10_SLP_SEL_S) -#define IO_MUX_GPIO10_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO10_SLP_SEL_S 1 -/** IO_MUX_GPIO10_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO10 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO10_MCU_WPD_M (IO_MUX_GPIO10_MCU_WPD_V << IO_MUX_GPIO10_MCU_WPD_S) -#define IO_MUX_GPIO10_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO10_MCU_WPD_S 2 -/** IO_MUX_GPIO10_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO10 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO10_MCU_WPU_M (IO_MUX_GPIO10_MCU_WPU_V << IO_MUX_GPIO10_MCU_WPU_S) -#define IO_MUX_GPIO10_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO10_MCU_WPU_S 3 -/** IO_MUX_GPIO10_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO10 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_MCU_IE (BIT(4)) -#define IO_MUX_GPIO10_MCU_IE_M (IO_MUX_GPIO10_MCU_IE_V << IO_MUX_GPIO10_MCU_IE_S) -#define IO_MUX_GPIO10_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO10_MCU_IE_S 4 -/** IO_MUX_GPIO10_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO10 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO10_MCU_DRV 0x00000003U -#define IO_MUX_GPIO10_MCU_DRV_M (IO_MUX_GPIO10_MCU_DRV_V << IO_MUX_GPIO10_MCU_DRV_S) -#define IO_MUX_GPIO10_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO10_MCU_DRV_S 5 -/** IO_MUX_GPIO10_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO10.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO10_FUN_WPD_M (IO_MUX_GPIO10_FUN_WPD_V << IO_MUX_GPIO10_FUN_WPD_S) -#define IO_MUX_GPIO10_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO10_FUN_WPD_S 7 -/** IO_MUX_GPIO10_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO10.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO10_FUN_WPU_M (IO_MUX_GPIO10_FUN_WPU_V << IO_MUX_GPIO10_FUN_WPU_S) -#define IO_MUX_GPIO10_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO10_FUN_WPU_S 8 -/** IO_MUX_GPIO10_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO10.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_FUN_IE (BIT(9)) -#define IO_MUX_GPIO10_FUN_IE_M (IO_MUX_GPIO10_FUN_IE_V << IO_MUX_GPIO10_FUN_IE_S) -#define IO_MUX_GPIO10_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO10_FUN_IE_S 9 -/** IO_MUX_GPIO10_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO10. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO10_FUN_DRV 0x00000003U -#define IO_MUX_GPIO10_FUN_DRV_M (IO_MUX_GPIO10_FUN_DRV_V << IO_MUX_GPIO10_FUN_DRV_S) -#define IO_MUX_GPIO10_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO10_FUN_DRV_S 10 -/** IO_MUX_GPIO10_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO10_MCU_SEL 0x00000007U -#define IO_MUX_GPIO10_MCU_SEL_M (IO_MUX_GPIO10_MCU_SEL_V << IO_MUX_GPIO10_MCU_SEL_S) -#define IO_MUX_GPIO10_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO10_MCU_SEL_S 12 -/** IO_MUX_GPIO10_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO10_FILTER_EN_M (IO_MUX_GPIO10_FILTER_EN_V << IO_MUX_GPIO10_FILTER_EN_S) -#define IO_MUX_GPIO10_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO10_FILTER_EN_S 15 -/** IO_MUX_GPIO10_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO10_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO10_HYS_EN (BIT(16)) -#define IO_MUX_GPIO10_HYS_EN_M (IO_MUX_GPIO10_HYS_EN_V << IO_MUX_GPIO10_HYS_EN_S) -#define IO_MUX_GPIO10_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO10_HYS_EN_S 16 -/** IO_MUX_GPIO10_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO10. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO10_HYS_EN\\ - */ -#define IO_MUX_GPIO10_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO10_HYS_SEL_M (IO_MUX_GPIO10_HYS_SEL_V << IO_MUX_GPIO10_HYS_SEL_S) -#define IO_MUX_GPIO10_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO10_HYS_SEL_S 17 - -/** IO_MUX_GPIO11_REG register - * IO MUX configuration register for GPIO11 - */ -#define IO_MUX_GPIO11_REG (DR_REG_IO_MUX_BASE + 0x2c) -/** IO_MUX_GPIO11_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO11 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_MCU_OE (BIT(0)) -#define IO_MUX_GPIO11_MCU_OE_M (IO_MUX_GPIO11_MCU_OE_V << IO_MUX_GPIO11_MCU_OE_S) -#define IO_MUX_GPIO11_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO11_MCU_OE_S 0 -/** IO_MUX_GPIO11_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO11.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO11_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO11_SLP_SEL_M (IO_MUX_GPIO11_SLP_SEL_V << IO_MUX_GPIO11_SLP_SEL_S) -#define IO_MUX_GPIO11_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO11_SLP_SEL_S 1 -/** IO_MUX_GPIO11_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO11 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO11_MCU_WPD_M (IO_MUX_GPIO11_MCU_WPD_V << IO_MUX_GPIO11_MCU_WPD_S) -#define IO_MUX_GPIO11_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO11_MCU_WPD_S 2 -/** IO_MUX_GPIO11_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO11 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO11_MCU_WPU_M (IO_MUX_GPIO11_MCU_WPU_V << IO_MUX_GPIO11_MCU_WPU_S) -#define IO_MUX_GPIO11_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO11_MCU_WPU_S 3 -/** IO_MUX_GPIO11_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO11 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_MCU_IE (BIT(4)) -#define IO_MUX_GPIO11_MCU_IE_M (IO_MUX_GPIO11_MCU_IE_V << IO_MUX_GPIO11_MCU_IE_S) -#define IO_MUX_GPIO11_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO11_MCU_IE_S 4 -/** IO_MUX_GPIO11_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO11 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO11_MCU_DRV 0x00000003U -#define IO_MUX_GPIO11_MCU_DRV_M (IO_MUX_GPIO11_MCU_DRV_V << IO_MUX_GPIO11_MCU_DRV_S) -#define IO_MUX_GPIO11_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO11_MCU_DRV_S 5 -/** IO_MUX_GPIO11_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO11.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO11_FUN_WPD_M (IO_MUX_GPIO11_FUN_WPD_V << IO_MUX_GPIO11_FUN_WPD_S) -#define IO_MUX_GPIO11_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO11_FUN_WPD_S 7 -/** IO_MUX_GPIO11_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO11.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO11_FUN_WPU_M (IO_MUX_GPIO11_FUN_WPU_V << IO_MUX_GPIO11_FUN_WPU_S) -#define IO_MUX_GPIO11_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO11_FUN_WPU_S 8 -/** IO_MUX_GPIO11_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO11.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_FUN_IE (BIT(9)) -#define IO_MUX_GPIO11_FUN_IE_M (IO_MUX_GPIO11_FUN_IE_V << IO_MUX_GPIO11_FUN_IE_S) -#define IO_MUX_GPIO11_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO11_FUN_IE_S 9 -/** IO_MUX_GPIO11_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO11. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO11_FUN_DRV 0x00000003U -#define IO_MUX_GPIO11_FUN_DRV_M (IO_MUX_GPIO11_FUN_DRV_V << IO_MUX_GPIO11_FUN_DRV_S) -#define IO_MUX_GPIO11_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO11_FUN_DRV_S 10 -/** IO_MUX_GPIO11_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO11_MCU_SEL 0x00000007U -#define IO_MUX_GPIO11_MCU_SEL_M (IO_MUX_GPIO11_MCU_SEL_V << IO_MUX_GPIO11_MCU_SEL_S) -#define IO_MUX_GPIO11_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO11_MCU_SEL_S 12 -/** IO_MUX_GPIO11_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO11_FILTER_EN_M (IO_MUX_GPIO11_FILTER_EN_V << IO_MUX_GPIO11_FILTER_EN_S) -#define IO_MUX_GPIO11_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO11_FILTER_EN_S 15 -/** IO_MUX_GPIO11_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO11_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO11_HYS_EN (BIT(16)) -#define IO_MUX_GPIO11_HYS_EN_M (IO_MUX_GPIO11_HYS_EN_V << IO_MUX_GPIO11_HYS_EN_S) -#define IO_MUX_GPIO11_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO11_HYS_EN_S 16 -/** IO_MUX_GPIO11_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO11. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO11_HYS_EN\\ - */ -#define IO_MUX_GPIO11_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO11_HYS_SEL_M (IO_MUX_GPIO11_HYS_SEL_V << IO_MUX_GPIO11_HYS_SEL_S) -#define IO_MUX_GPIO11_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO11_HYS_SEL_S 17 - -/** IO_MUX_GPIO12_REG register - * IO MUX configuration register for GPIO12 - */ -#define IO_MUX_GPIO12_REG (DR_REG_IO_MUX_BASE + 0x30) -/** IO_MUX_GPIO12_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO12 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_MCU_OE (BIT(0)) -#define IO_MUX_GPIO12_MCU_OE_M (IO_MUX_GPIO12_MCU_OE_V << IO_MUX_GPIO12_MCU_OE_S) -#define IO_MUX_GPIO12_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO12_MCU_OE_S 0 -/** IO_MUX_GPIO12_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO12.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO12_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO12_SLP_SEL_M (IO_MUX_GPIO12_SLP_SEL_V << IO_MUX_GPIO12_SLP_SEL_S) -#define IO_MUX_GPIO12_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO12_SLP_SEL_S 1 -/** IO_MUX_GPIO12_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO12 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO12_MCU_WPD_M (IO_MUX_GPIO12_MCU_WPD_V << IO_MUX_GPIO12_MCU_WPD_S) -#define IO_MUX_GPIO12_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO12_MCU_WPD_S 2 -/** IO_MUX_GPIO12_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO12 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO12_MCU_WPU_M (IO_MUX_GPIO12_MCU_WPU_V << IO_MUX_GPIO12_MCU_WPU_S) -#define IO_MUX_GPIO12_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO12_MCU_WPU_S 3 -/** IO_MUX_GPIO12_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO12 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_MCU_IE (BIT(4)) -#define IO_MUX_GPIO12_MCU_IE_M (IO_MUX_GPIO12_MCU_IE_V << IO_MUX_GPIO12_MCU_IE_S) -#define IO_MUX_GPIO12_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO12_MCU_IE_S 4 -/** IO_MUX_GPIO12_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO12 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO12_MCU_DRV 0x00000003U -#define IO_MUX_GPIO12_MCU_DRV_M (IO_MUX_GPIO12_MCU_DRV_V << IO_MUX_GPIO12_MCU_DRV_S) -#define IO_MUX_GPIO12_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO12_MCU_DRV_S 5 -/** IO_MUX_GPIO12_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO12.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO12_FUN_WPD_M (IO_MUX_GPIO12_FUN_WPD_V << IO_MUX_GPIO12_FUN_WPD_S) -#define IO_MUX_GPIO12_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO12_FUN_WPD_S 7 -/** IO_MUX_GPIO12_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO12.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO12_FUN_WPU_M (IO_MUX_GPIO12_FUN_WPU_V << IO_MUX_GPIO12_FUN_WPU_S) -#define IO_MUX_GPIO12_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO12_FUN_WPU_S 8 -/** IO_MUX_GPIO12_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO12.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_FUN_IE (BIT(9)) -#define IO_MUX_GPIO12_FUN_IE_M (IO_MUX_GPIO12_FUN_IE_V << IO_MUX_GPIO12_FUN_IE_S) -#define IO_MUX_GPIO12_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO12_FUN_IE_S 9 -/** IO_MUX_GPIO12_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO12. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO12_FUN_DRV 0x00000003U -#define IO_MUX_GPIO12_FUN_DRV_M (IO_MUX_GPIO12_FUN_DRV_V << IO_MUX_GPIO12_FUN_DRV_S) -#define IO_MUX_GPIO12_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO12_FUN_DRV_S 10 -/** IO_MUX_GPIO12_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO12_MCU_SEL 0x00000007U -#define IO_MUX_GPIO12_MCU_SEL_M (IO_MUX_GPIO12_MCU_SEL_V << IO_MUX_GPIO12_MCU_SEL_S) -#define IO_MUX_GPIO12_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO12_MCU_SEL_S 12 -/** IO_MUX_GPIO12_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO12_FILTER_EN_M (IO_MUX_GPIO12_FILTER_EN_V << IO_MUX_GPIO12_FILTER_EN_S) -#define IO_MUX_GPIO12_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO12_FILTER_EN_S 15 -/** IO_MUX_GPIO12_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO12_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO12_HYS_EN (BIT(16)) -#define IO_MUX_GPIO12_HYS_EN_M (IO_MUX_GPIO12_HYS_EN_V << IO_MUX_GPIO12_HYS_EN_S) -#define IO_MUX_GPIO12_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO12_HYS_EN_S 16 -/** IO_MUX_GPIO12_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO12. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO12_HYS_EN\\ - */ -#define IO_MUX_GPIO12_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO12_HYS_SEL_M (IO_MUX_GPIO12_HYS_SEL_V << IO_MUX_GPIO12_HYS_SEL_S) -#define IO_MUX_GPIO12_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO12_HYS_SEL_S 17 - -/** IO_MUX_GPIO13_REG register - * IO MUX configuration register for GPIO13 - */ -#define IO_MUX_GPIO13_REG (DR_REG_IO_MUX_BASE + 0x34) -/** IO_MUX_GPIO13_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO13 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_MCU_OE (BIT(0)) -#define IO_MUX_GPIO13_MCU_OE_M (IO_MUX_GPIO13_MCU_OE_V << IO_MUX_GPIO13_MCU_OE_S) -#define IO_MUX_GPIO13_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO13_MCU_OE_S 0 -/** IO_MUX_GPIO13_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO13.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO13_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO13_SLP_SEL_M (IO_MUX_GPIO13_SLP_SEL_V << IO_MUX_GPIO13_SLP_SEL_S) -#define IO_MUX_GPIO13_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO13_SLP_SEL_S 1 -/** IO_MUX_GPIO13_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO13 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO13_MCU_WPD_M (IO_MUX_GPIO13_MCU_WPD_V << IO_MUX_GPIO13_MCU_WPD_S) -#define IO_MUX_GPIO13_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO13_MCU_WPD_S 2 -/** IO_MUX_GPIO13_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO13 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO13_MCU_WPU_M (IO_MUX_GPIO13_MCU_WPU_V << IO_MUX_GPIO13_MCU_WPU_S) -#define IO_MUX_GPIO13_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO13_MCU_WPU_S 3 -/** IO_MUX_GPIO13_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO13 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_MCU_IE (BIT(4)) -#define IO_MUX_GPIO13_MCU_IE_M (IO_MUX_GPIO13_MCU_IE_V << IO_MUX_GPIO13_MCU_IE_S) -#define IO_MUX_GPIO13_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO13_MCU_IE_S 4 -/** IO_MUX_GPIO13_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO13 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO13_MCU_DRV 0x00000003U -#define IO_MUX_GPIO13_MCU_DRV_M (IO_MUX_GPIO13_MCU_DRV_V << IO_MUX_GPIO13_MCU_DRV_S) -#define IO_MUX_GPIO13_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO13_MCU_DRV_S 5 -/** IO_MUX_GPIO13_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO13.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO13_FUN_WPD_M (IO_MUX_GPIO13_FUN_WPD_V << IO_MUX_GPIO13_FUN_WPD_S) -#define IO_MUX_GPIO13_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO13_FUN_WPD_S 7 -/** IO_MUX_GPIO13_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO13.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO13_FUN_WPU_M (IO_MUX_GPIO13_FUN_WPU_V << IO_MUX_GPIO13_FUN_WPU_S) -#define IO_MUX_GPIO13_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO13_FUN_WPU_S 8 -/** IO_MUX_GPIO13_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO13.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_FUN_IE (BIT(9)) -#define IO_MUX_GPIO13_FUN_IE_M (IO_MUX_GPIO13_FUN_IE_V << IO_MUX_GPIO13_FUN_IE_S) -#define IO_MUX_GPIO13_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO13_FUN_IE_S 9 -/** IO_MUX_GPIO13_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO13. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO13_FUN_DRV 0x00000003U -#define IO_MUX_GPIO13_FUN_DRV_M (IO_MUX_GPIO13_FUN_DRV_V << IO_MUX_GPIO13_FUN_DRV_S) -#define IO_MUX_GPIO13_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO13_FUN_DRV_S 10 -/** IO_MUX_GPIO13_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO13_MCU_SEL 0x00000007U -#define IO_MUX_GPIO13_MCU_SEL_M (IO_MUX_GPIO13_MCU_SEL_V << IO_MUX_GPIO13_MCU_SEL_S) -#define IO_MUX_GPIO13_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO13_MCU_SEL_S 12 -/** IO_MUX_GPIO13_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO13_FILTER_EN_M (IO_MUX_GPIO13_FILTER_EN_V << IO_MUX_GPIO13_FILTER_EN_S) -#define IO_MUX_GPIO13_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO13_FILTER_EN_S 15 -/** IO_MUX_GPIO13_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO13_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO13_HYS_EN (BIT(16)) -#define IO_MUX_GPIO13_HYS_EN_M (IO_MUX_GPIO13_HYS_EN_V << IO_MUX_GPIO13_HYS_EN_S) -#define IO_MUX_GPIO13_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO13_HYS_EN_S 16 -/** IO_MUX_GPIO13_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO13. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO13_HYS_EN\\ - */ -#define IO_MUX_GPIO13_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO13_HYS_SEL_M (IO_MUX_GPIO13_HYS_SEL_V << IO_MUX_GPIO13_HYS_SEL_S) -#define IO_MUX_GPIO13_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO13_HYS_SEL_S 17 - -/** IO_MUX_GPIO14_REG register - * IO MUX configuration register for GPIO14 - */ -#define IO_MUX_GPIO14_REG (DR_REG_IO_MUX_BASE + 0x38) -/** IO_MUX_GPIO14_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO14 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_MCU_OE (BIT(0)) -#define IO_MUX_GPIO14_MCU_OE_M (IO_MUX_GPIO14_MCU_OE_V << IO_MUX_GPIO14_MCU_OE_S) -#define IO_MUX_GPIO14_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO14_MCU_OE_S 0 -/** IO_MUX_GPIO14_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO14.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO14_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO14_SLP_SEL_M (IO_MUX_GPIO14_SLP_SEL_V << IO_MUX_GPIO14_SLP_SEL_S) -#define IO_MUX_GPIO14_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO14_SLP_SEL_S 1 -/** IO_MUX_GPIO14_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO14 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO14_MCU_WPD_M (IO_MUX_GPIO14_MCU_WPD_V << IO_MUX_GPIO14_MCU_WPD_S) -#define IO_MUX_GPIO14_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO14_MCU_WPD_S 2 -/** IO_MUX_GPIO14_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO14 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO14_MCU_WPU_M (IO_MUX_GPIO14_MCU_WPU_V << IO_MUX_GPIO14_MCU_WPU_S) -#define IO_MUX_GPIO14_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO14_MCU_WPU_S 3 -/** IO_MUX_GPIO14_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO14 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_MCU_IE (BIT(4)) -#define IO_MUX_GPIO14_MCU_IE_M (IO_MUX_GPIO14_MCU_IE_V << IO_MUX_GPIO14_MCU_IE_S) -#define IO_MUX_GPIO14_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO14_MCU_IE_S 4 -/** IO_MUX_GPIO14_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO14 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO14_MCU_DRV 0x00000003U -#define IO_MUX_GPIO14_MCU_DRV_M (IO_MUX_GPIO14_MCU_DRV_V << IO_MUX_GPIO14_MCU_DRV_S) -#define IO_MUX_GPIO14_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO14_MCU_DRV_S 5 -/** IO_MUX_GPIO14_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO14.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO14_FUN_WPD_M (IO_MUX_GPIO14_FUN_WPD_V << IO_MUX_GPIO14_FUN_WPD_S) -#define IO_MUX_GPIO14_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO14_FUN_WPD_S 7 -/** IO_MUX_GPIO14_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO14.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO14_FUN_WPU_M (IO_MUX_GPIO14_FUN_WPU_V << IO_MUX_GPIO14_FUN_WPU_S) -#define IO_MUX_GPIO14_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO14_FUN_WPU_S 8 -/** IO_MUX_GPIO14_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO14.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_FUN_IE (BIT(9)) -#define IO_MUX_GPIO14_FUN_IE_M (IO_MUX_GPIO14_FUN_IE_V << IO_MUX_GPIO14_FUN_IE_S) -#define IO_MUX_GPIO14_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO14_FUN_IE_S 9 -/** IO_MUX_GPIO14_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO14. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO14_FUN_DRV 0x00000003U -#define IO_MUX_GPIO14_FUN_DRV_M (IO_MUX_GPIO14_FUN_DRV_V << IO_MUX_GPIO14_FUN_DRV_S) -#define IO_MUX_GPIO14_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO14_FUN_DRV_S 10 -/** IO_MUX_GPIO14_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO14_MCU_SEL 0x00000007U -#define IO_MUX_GPIO14_MCU_SEL_M (IO_MUX_GPIO14_MCU_SEL_V << IO_MUX_GPIO14_MCU_SEL_S) -#define IO_MUX_GPIO14_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO14_MCU_SEL_S 12 -/** IO_MUX_GPIO14_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO14_FILTER_EN_M (IO_MUX_GPIO14_FILTER_EN_V << IO_MUX_GPIO14_FILTER_EN_S) -#define IO_MUX_GPIO14_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO14_FILTER_EN_S 15 -/** IO_MUX_GPIO14_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO14_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO14_HYS_EN (BIT(16)) -#define IO_MUX_GPIO14_HYS_EN_M (IO_MUX_GPIO14_HYS_EN_V << IO_MUX_GPIO14_HYS_EN_S) -#define IO_MUX_GPIO14_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO14_HYS_EN_S 16 -/** IO_MUX_GPIO14_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO14. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO14_HYS_EN\\ - */ -#define IO_MUX_GPIO14_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO14_HYS_SEL_M (IO_MUX_GPIO14_HYS_SEL_V << IO_MUX_GPIO14_HYS_SEL_S) -#define IO_MUX_GPIO14_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO14_HYS_SEL_S 17 - -/** IO_MUX_GPIO15_REG register - * IO MUX configuration register for GPIO15 - */ -#define IO_MUX_GPIO15_REG (DR_REG_IO_MUX_BASE + 0x3c) -/** IO_MUX_GPIO15_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO15 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_MCU_OE (BIT(0)) -#define IO_MUX_GPIO15_MCU_OE_M (IO_MUX_GPIO15_MCU_OE_V << IO_MUX_GPIO15_MCU_OE_S) -#define IO_MUX_GPIO15_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO15_MCU_OE_S 0 -/** IO_MUX_GPIO15_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO15.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO15_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO15_SLP_SEL_M (IO_MUX_GPIO15_SLP_SEL_V << IO_MUX_GPIO15_SLP_SEL_S) -#define IO_MUX_GPIO15_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO15_SLP_SEL_S 1 -/** IO_MUX_GPIO15_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO15 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO15_MCU_WPD_M (IO_MUX_GPIO15_MCU_WPD_V << IO_MUX_GPIO15_MCU_WPD_S) -#define IO_MUX_GPIO15_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO15_MCU_WPD_S 2 -/** IO_MUX_GPIO15_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO15 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO15_MCU_WPU_M (IO_MUX_GPIO15_MCU_WPU_V << IO_MUX_GPIO15_MCU_WPU_S) -#define IO_MUX_GPIO15_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO15_MCU_WPU_S 3 -/** IO_MUX_GPIO15_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO15 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_MCU_IE (BIT(4)) -#define IO_MUX_GPIO15_MCU_IE_M (IO_MUX_GPIO15_MCU_IE_V << IO_MUX_GPIO15_MCU_IE_S) -#define IO_MUX_GPIO15_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO15_MCU_IE_S 4 -/** IO_MUX_GPIO15_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO15 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO15_MCU_DRV 0x00000003U -#define IO_MUX_GPIO15_MCU_DRV_M (IO_MUX_GPIO15_MCU_DRV_V << IO_MUX_GPIO15_MCU_DRV_S) -#define IO_MUX_GPIO15_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO15_MCU_DRV_S 5 -/** IO_MUX_GPIO15_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO15.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO15_FUN_WPD_M (IO_MUX_GPIO15_FUN_WPD_V << IO_MUX_GPIO15_FUN_WPD_S) -#define IO_MUX_GPIO15_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO15_FUN_WPD_S 7 -/** IO_MUX_GPIO15_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO15.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO15_FUN_WPU_M (IO_MUX_GPIO15_FUN_WPU_V << IO_MUX_GPIO15_FUN_WPU_S) -#define IO_MUX_GPIO15_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO15_FUN_WPU_S 8 -/** IO_MUX_GPIO15_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO15.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_FUN_IE (BIT(9)) -#define IO_MUX_GPIO15_FUN_IE_M (IO_MUX_GPIO15_FUN_IE_V << IO_MUX_GPIO15_FUN_IE_S) -#define IO_MUX_GPIO15_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO15_FUN_IE_S 9 -/** IO_MUX_GPIO15_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO15. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO15_FUN_DRV 0x00000003U -#define IO_MUX_GPIO15_FUN_DRV_M (IO_MUX_GPIO15_FUN_DRV_V << IO_MUX_GPIO15_FUN_DRV_S) -#define IO_MUX_GPIO15_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO15_FUN_DRV_S 10 -/** IO_MUX_GPIO15_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO15_MCU_SEL 0x00000007U -#define IO_MUX_GPIO15_MCU_SEL_M (IO_MUX_GPIO15_MCU_SEL_V << IO_MUX_GPIO15_MCU_SEL_S) -#define IO_MUX_GPIO15_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO15_MCU_SEL_S 12 -/** IO_MUX_GPIO15_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO15_FILTER_EN_M (IO_MUX_GPIO15_FILTER_EN_V << IO_MUX_GPIO15_FILTER_EN_S) -#define IO_MUX_GPIO15_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO15_FILTER_EN_S 15 -/** IO_MUX_GPIO15_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO15_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO15_HYS_EN (BIT(16)) -#define IO_MUX_GPIO15_HYS_EN_M (IO_MUX_GPIO15_HYS_EN_V << IO_MUX_GPIO15_HYS_EN_S) -#define IO_MUX_GPIO15_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO15_HYS_EN_S 16 -/** IO_MUX_GPIO15_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO15. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO15_HYS_EN\\ - */ -#define IO_MUX_GPIO15_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO15_HYS_SEL_M (IO_MUX_GPIO15_HYS_SEL_V << IO_MUX_GPIO15_HYS_SEL_S) -#define IO_MUX_GPIO15_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO15_HYS_SEL_S 17 - -/** IO_MUX_GPIO16_REG register - * IO MUX configuration register for GPIO16 - */ -#define IO_MUX_GPIO16_REG (DR_REG_IO_MUX_BASE + 0x40) -/** IO_MUX_GPIO16_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO16 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_MCU_OE (BIT(0)) -#define IO_MUX_GPIO16_MCU_OE_M (IO_MUX_GPIO16_MCU_OE_V << IO_MUX_GPIO16_MCU_OE_S) -#define IO_MUX_GPIO16_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO16_MCU_OE_S 0 -/** IO_MUX_GPIO16_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO16.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO16_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO16_SLP_SEL_M (IO_MUX_GPIO16_SLP_SEL_V << IO_MUX_GPIO16_SLP_SEL_S) -#define IO_MUX_GPIO16_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO16_SLP_SEL_S 1 -/** IO_MUX_GPIO16_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO16 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO16_MCU_WPD_M (IO_MUX_GPIO16_MCU_WPD_V << IO_MUX_GPIO16_MCU_WPD_S) -#define IO_MUX_GPIO16_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO16_MCU_WPD_S 2 -/** IO_MUX_GPIO16_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO16 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO16_MCU_WPU_M (IO_MUX_GPIO16_MCU_WPU_V << IO_MUX_GPIO16_MCU_WPU_S) -#define IO_MUX_GPIO16_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO16_MCU_WPU_S 3 -/** IO_MUX_GPIO16_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO16 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_MCU_IE (BIT(4)) -#define IO_MUX_GPIO16_MCU_IE_M (IO_MUX_GPIO16_MCU_IE_V << IO_MUX_GPIO16_MCU_IE_S) -#define IO_MUX_GPIO16_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO16_MCU_IE_S 4 -/** IO_MUX_GPIO16_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO16 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO16_MCU_DRV 0x00000003U -#define IO_MUX_GPIO16_MCU_DRV_M (IO_MUX_GPIO16_MCU_DRV_V << IO_MUX_GPIO16_MCU_DRV_S) -#define IO_MUX_GPIO16_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO16_MCU_DRV_S 5 -/** IO_MUX_GPIO16_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO16.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO16_FUN_WPD_M (IO_MUX_GPIO16_FUN_WPD_V << IO_MUX_GPIO16_FUN_WPD_S) -#define IO_MUX_GPIO16_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO16_FUN_WPD_S 7 -/** IO_MUX_GPIO16_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO16.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO16_FUN_WPU_M (IO_MUX_GPIO16_FUN_WPU_V << IO_MUX_GPIO16_FUN_WPU_S) -#define IO_MUX_GPIO16_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO16_FUN_WPU_S 8 -/** IO_MUX_GPIO16_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO16.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_FUN_IE (BIT(9)) -#define IO_MUX_GPIO16_FUN_IE_M (IO_MUX_GPIO16_FUN_IE_V << IO_MUX_GPIO16_FUN_IE_S) -#define IO_MUX_GPIO16_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO16_FUN_IE_S 9 -/** IO_MUX_GPIO16_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO16. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO16_FUN_DRV 0x00000003U -#define IO_MUX_GPIO16_FUN_DRV_M (IO_MUX_GPIO16_FUN_DRV_V << IO_MUX_GPIO16_FUN_DRV_S) -#define IO_MUX_GPIO16_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO16_FUN_DRV_S 10 -/** IO_MUX_GPIO16_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO16_MCU_SEL 0x00000007U -#define IO_MUX_GPIO16_MCU_SEL_M (IO_MUX_GPIO16_MCU_SEL_V << IO_MUX_GPIO16_MCU_SEL_S) -#define IO_MUX_GPIO16_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO16_MCU_SEL_S 12 -/** IO_MUX_GPIO16_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO16_FILTER_EN_M (IO_MUX_GPIO16_FILTER_EN_V << IO_MUX_GPIO16_FILTER_EN_S) -#define IO_MUX_GPIO16_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO16_FILTER_EN_S 15 -/** IO_MUX_GPIO16_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO16_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO16_HYS_EN (BIT(16)) -#define IO_MUX_GPIO16_HYS_EN_M (IO_MUX_GPIO16_HYS_EN_V << IO_MUX_GPIO16_HYS_EN_S) -#define IO_MUX_GPIO16_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO16_HYS_EN_S 16 -/** IO_MUX_GPIO16_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO16. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO16_HYS_EN\\ - */ -#define IO_MUX_GPIO16_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO16_HYS_SEL_M (IO_MUX_GPIO16_HYS_SEL_V << IO_MUX_GPIO16_HYS_SEL_S) -#define IO_MUX_GPIO16_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO16_HYS_SEL_S 17 - -/** IO_MUX_GPIO17_REG register - * IO MUX configuration register for GPIO17 - */ -#define IO_MUX_GPIO17_REG (DR_REG_IO_MUX_BASE + 0x44) -/** IO_MUX_GPIO17_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO17 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_MCU_OE (BIT(0)) -#define IO_MUX_GPIO17_MCU_OE_M (IO_MUX_GPIO17_MCU_OE_V << IO_MUX_GPIO17_MCU_OE_S) -#define IO_MUX_GPIO17_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO17_MCU_OE_S 0 -/** IO_MUX_GPIO17_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO17.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO17_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO17_SLP_SEL_M (IO_MUX_GPIO17_SLP_SEL_V << IO_MUX_GPIO17_SLP_SEL_S) -#define IO_MUX_GPIO17_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO17_SLP_SEL_S 1 -/** IO_MUX_GPIO17_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO17 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO17_MCU_WPD_M (IO_MUX_GPIO17_MCU_WPD_V << IO_MUX_GPIO17_MCU_WPD_S) -#define IO_MUX_GPIO17_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO17_MCU_WPD_S 2 -/** IO_MUX_GPIO17_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO17 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO17_MCU_WPU_M (IO_MUX_GPIO17_MCU_WPU_V << IO_MUX_GPIO17_MCU_WPU_S) -#define IO_MUX_GPIO17_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO17_MCU_WPU_S 3 -/** IO_MUX_GPIO17_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO17 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_MCU_IE (BIT(4)) -#define IO_MUX_GPIO17_MCU_IE_M (IO_MUX_GPIO17_MCU_IE_V << IO_MUX_GPIO17_MCU_IE_S) -#define IO_MUX_GPIO17_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO17_MCU_IE_S 4 -/** IO_MUX_GPIO17_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO17 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO17_MCU_DRV 0x00000003U -#define IO_MUX_GPIO17_MCU_DRV_M (IO_MUX_GPIO17_MCU_DRV_V << IO_MUX_GPIO17_MCU_DRV_S) -#define IO_MUX_GPIO17_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO17_MCU_DRV_S 5 -/** IO_MUX_GPIO17_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO17.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO17_FUN_WPD_M (IO_MUX_GPIO17_FUN_WPD_V << IO_MUX_GPIO17_FUN_WPD_S) -#define IO_MUX_GPIO17_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO17_FUN_WPD_S 7 -/** IO_MUX_GPIO17_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO17.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO17_FUN_WPU_M (IO_MUX_GPIO17_FUN_WPU_V << IO_MUX_GPIO17_FUN_WPU_S) -#define IO_MUX_GPIO17_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO17_FUN_WPU_S 8 -/** IO_MUX_GPIO17_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO17.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_FUN_IE (BIT(9)) -#define IO_MUX_GPIO17_FUN_IE_M (IO_MUX_GPIO17_FUN_IE_V << IO_MUX_GPIO17_FUN_IE_S) -#define IO_MUX_GPIO17_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO17_FUN_IE_S 9 -/** IO_MUX_GPIO17_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO17. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO17_FUN_DRV 0x00000003U -#define IO_MUX_GPIO17_FUN_DRV_M (IO_MUX_GPIO17_FUN_DRV_V << IO_MUX_GPIO17_FUN_DRV_S) -#define IO_MUX_GPIO17_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO17_FUN_DRV_S 10 -/** IO_MUX_GPIO17_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO17_MCU_SEL 0x00000007U -#define IO_MUX_GPIO17_MCU_SEL_M (IO_MUX_GPIO17_MCU_SEL_V << IO_MUX_GPIO17_MCU_SEL_S) -#define IO_MUX_GPIO17_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO17_MCU_SEL_S 12 -/** IO_MUX_GPIO17_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO17_FILTER_EN_M (IO_MUX_GPIO17_FILTER_EN_V << IO_MUX_GPIO17_FILTER_EN_S) -#define IO_MUX_GPIO17_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO17_FILTER_EN_S 15 -/** IO_MUX_GPIO17_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO17_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO17_HYS_EN (BIT(16)) -#define IO_MUX_GPIO17_HYS_EN_M (IO_MUX_GPIO17_HYS_EN_V << IO_MUX_GPIO17_HYS_EN_S) -#define IO_MUX_GPIO17_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO17_HYS_EN_S 16 -/** IO_MUX_GPIO17_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO17. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO17_HYS_EN\\ - */ -#define IO_MUX_GPIO17_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO17_HYS_SEL_M (IO_MUX_GPIO17_HYS_SEL_V << IO_MUX_GPIO17_HYS_SEL_S) -#define IO_MUX_GPIO17_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO17_HYS_SEL_S 17 - -/** IO_MUX_GPIO18_REG register - * IO MUX configuration register for GPIO18 - */ -#define IO_MUX_GPIO18_REG (DR_REG_IO_MUX_BASE + 0x48) -/** IO_MUX_GPIO18_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO18 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_MCU_OE (BIT(0)) -#define IO_MUX_GPIO18_MCU_OE_M (IO_MUX_GPIO18_MCU_OE_V << IO_MUX_GPIO18_MCU_OE_S) -#define IO_MUX_GPIO18_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO18_MCU_OE_S 0 -/** IO_MUX_GPIO18_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO18.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO18_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO18_SLP_SEL_M (IO_MUX_GPIO18_SLP_SEL_V << IO_MUX_GPIO18_SLP_SEL_S) -#define IO_MUX_GPIO18_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO18_SLP_SEL_S 1 -/** IO_MUX_GPIO18_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO18 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO18_MCU_WPD_M (IO_MUX_GPIO18_MCU_WPD_V << IO_MUX_GPIO18_MCU_WPD_S) -#define IO_MUX_GPIO18_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO18_MCU_WPD_S 2 -/** IO_MUX_GPIO18_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO18 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO18_MCU_WPU_M (IO_MUX_GPIO18_MCU_WPU_V << IO_MUX_GPIO18_MCU_WPU_S) -#define IO_MUX_GPIO18_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO18_MCU_WPU_S 3 -/** IO_MUX_GPIO18_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO18 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_MCU_IE (BIT(4)) -#define IO_MUX_GPIO18_MCU_IE_M (IO_MUX_GPIO18_MCU_IE_V << IO_MUX_GPIO18_MCU_IE_S) -#define IO_MUX_GPIO18_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO18_MCU_IE_S 4 -/** IO_MUX_GPIO18_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO18 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO18_MCU_DRV 0x00000003U -#define IO_MUX_GPIO18_MCU_DRV_M (IO_MUX_GPIO18_MCU_DRV_V << IO_MUX_GPIO18_MCU_DRV_S) -#define IO_MUX_GPIO18_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO18_MCU_DRV_S 5 -/** IO_MUX_GPIO18_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO18.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO18_FUN_WPD_M (IO_MUX_GPIO18_FUN_WPD_V << IO_MUX_GPIO18_FUN_WPD_S) -#define IO_MUX_GPIO18_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO18_FUN_WPD_S 7 -/** IO_MUX_GPIO18_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO18.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO18_FUN_WPU_M (IO_MUX_GPIO18_FUN_WPU_V << IO_MUX_GPIO18_FUN_WPU_S) -#define IO_MUX_GPIO18_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO18_FUN_WPU_S 8 -/** IO_MUX_GPIO18_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO18.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_FUN_IE (BIT(9)) -#define IO_MUX_GPIO18_FUN_IE_M (IO_MUX_GPIO18_FUN_IE_V << IO_MUX_GPIO18_FUN_IE_S) -#define IO_MUX_GPIO18_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO18_FUN_IE_S 9 -/** IO_MUX_GPIO18_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO18. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO18_FUN_DRV 0x00000003U -#define IO_MUX_GPIO18_FUN_DRV_M (IO_MUX_GPIO18_FUN_DRV_V << IO_MUX_GPIO18_FUN_DRV_S) -#define IO_MUX_GPIO18_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO18_FUN_DRV_S 10 -/** IO_MUX_GPIO18_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO18_MCU_SEL 0x00000007U -#define IO_MUX_GPIO18_MCU_SEL_M (IO_MUX_GPIO18_MCU_SEL_V << IO_MUX_GPIO18_MCU_SEL_S) -#define IO_MUX_GPIO18_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO18_MCU_SEL_S 12 -/** IO_MUX_GPIO18_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO18_FILTER_EN_M (IO_MUX_GPIO18_FILTER_EN_V << IO_MUX_GPIO18_FILTER_EN_S) -#define IO_MUX_GPIO18_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO18_FILTER_EN_S 15 -/** IO_MUX_GPIO18_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO18_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO18_HYS_EN (BIT(16)) -#define IO_MUX_GPIO18_HYS_EN_M (IO_MUX_GPIO18_HYS_EN_V << IO_MUX_GPIO18_HYS_EN_S) -#define IO_MUX_GPIO18_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO18_HYS_EN_S 16 -/** IO_MUX_GPIO18_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO18. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO18_HYS_EN\\ - */ -#define IO_MUX_GPIO18_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO18_HYS_SEL_M (IO_MUX_GPIO18_HYS_SEL_V << IO_MUX_GPIO18_HYS_SEL_S) -#define IO_MUX_GPIO18_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO18_HYS_SEL_S 17 - -/** IO_MUX_GPIO19_REG register - * IO MUX configuration register for GPIO19 - */ -#define IO_MUX_GPIO19_REG (DR_REG_IO_MUX_BASE + 0x4c) -/** IO_MUX_GPIO19_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO19 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_MCU_OE (BIT(0)) -#define IO_MUX_GPIO19_MCU_OE_M (IO_MUX_GPIO19_MCU_OE_V << IO_MUX_GPIO19_MCU_OE_S) -#define IO_MUX_GPIO19_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO19_MCU_OE_S 0 -/** IO_MUX_GPIO19_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO19.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO19_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO19_SLP_SEL_M (IO_MUX_GPIO19_SLP_SEL_V << IO_MUX_GPIO19_SLP_SEL_S) -#define IO_MUX_GPIO19_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO19_SLP_SEL_S 1 -/** IO_MUX_GPIO19_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO19 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO19_MCU_WPD_M (IO_MUX_GPIO19_MCU_WPD_V << IO_MUX_GPIO19_MCU_WPD_S) -#define IO_MUX_GPIO19_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO19_MCU_WPD_S 2 -/** IO_MUX_GPIO19_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO19 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO19_MCU_WPU_M (IO_MUX_GPIO19_MCU_WPU_V << IO_MUX_GPIO19_MCU_WPU_S) -#define IO_MUX_GPIO19_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO19_MCU_WPU_S 3 -/** IO_MUX_GPIO19_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO19 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_MCU_IE (BIT(4)) -#define IO_MUX_GPIO19_MCU_IE_M (IO_MUX_GPIO19_MCU_IE_V << IO_MUX_GPIO19_MCU_IE_S) -#define IO_MUX_GPIO19_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO19_MCU_IE_S 4 -/** IO_MUX_GPIO19_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO19 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO19_MCU_DRV 0x00000003U -#define IO_MUX_GPIO19_MCU_DRV_M (IO_MUX_GPIO19_MCU_DRV_V << IO_MUX_GPIO19_MCU_DRV_S) -#define IO_MUX_GPIO19_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO19_MCU_DRV_S 5 -/** IO_MUX_GPIO19_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO19.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO19_FUN_WPD_M (IO_MUX_GPIO19_FUN_WPD_V << IO_MUX_GPIO19_FUN_WPD_S) -#define IO_MUX_GPIO19_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO19_FUN_WPD_S 7 -/** IO_MUX_GPIO19_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO19.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO19_FUN_WPU_M (IO_MUX_GPIO19_FUN_WPU_V << IO_MUX_GPIO19_FUN_WPU_S) -#define IO_MUX_GPIO19_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO19_FUN_WPU_S 8 -/** IO_MUX_GPIO19_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO19.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_FUN_IE (BIT(9)) -#define IO_MUX_GPIO19_FUN_IE_M (IO_MUX_GPIO19_FUN_IE_V << IO_MUX_GPIO19_FUN_IE_S) -#define IO_MUX_GPIO19_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO19_FUN_IE_S 9 -/** IO_MUX_GPIO19_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO19. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO19_FUN_DRV 0x00000003U -#define IO_MUX_GPIO19_FUN_DRV_M (IO_MUX_GPIO19_FUN_DRV_V << IO_MUX_GPIO19_FUN_DRV_S) -#define IO_MUX_GPIO19_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO19_FUN_DRV_S 10 -/** IO_MUX_GPIO19_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO19_MCU_SEL 0x00000007U -#define IO_MUX_GPIO19_MCU_SEL_M (IO_MUX_GPIO19_MCU_SEL_V << IO_MUX_GPIO19_MCU_SEL_S) -#define IO_MUX_GPIO19_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO19_MCU_SEL_S 12 -/** IO_MUX_GPIO19_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO19_FILTER_EN_M (IO_MUX_GPIO19_FILTER_EN_V << IO_MUX_GPIO19_FILTER_EN_S) -#define IO_MUX_GPIO19_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO19_FILTER_EN_S 15 -/** IO_MUX_GPIO19_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO19_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO19_HYS_EN (BIT(16)) -#define IO_MUX_GPIO19_HYS_EN_M (IO_MUX_GPIO19_HYS_EN_V << IO_MUX_GPIO19_HYS_EN_S) -#define IO_MUX_GPIO19_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO19_HYS_EN_S 16 -/** IO_MUX_GPIO19_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO19. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO19_HYS_EN\\ - */ -#define IO_MUX_GPIO19_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO19_HYS_SEL_M (IO_MUX_GPIO19_HYS_SEL_V << IO_MUX_GPIO19_HYS_SEL_S) -#define IO_MUX_GPIO19_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO19_HYS_SEL_S 17 - -/** IO_MUX_GPIO20_REG register - * IO MUX configuration register for GPIO20 - */ -#define IO_MUX_GPIO20_REG (DR_REG_IO_MUX_BASE + 0x50) -/** IO_MUX_GPIO20_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO20 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_MCU_OE (BIT(0)) -#define IO_MUX_GPIO20_MCU_OE_M (IO_MUX_GPIO20_MCU_OE_V << IO_MUX_GPIO20_MCU_OE_S) -#define IO_MUX_GPIO20_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO20_MCU_OE_S 0 -/** IO_MUX_GPIO20_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO20.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO20_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO20_SLP_SEL_M (IO_MUX_GPIO20_SLP_SEL_V << IO_MUX_GPIO20_SLP_SEL_S) -#define IO_MUX_GPIO20_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO20_SLP_SEL_S 1 -/** IO_MUX_GPIO20_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO20 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO20_MCU_WPD_M (IO_MUX_GPIO20_MCU_WPD_V << IO_MUX_GPIO20_MCU_WPD_S) -#define IO_MUX_GPIO20_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO20_MCU_WPD_S 2 -/** IO_MUX_GPIO20_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO20 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO20_MCU_WPU_M (IO_MUX_GPIO20_MCU_WPU_V << IO_MUX_GPIO20_MCU_WPU_S) -#define IO_MUX_GPIO20_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO20_MCU_WPU_S 3 -/** IO_MUX_GPIO20_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO20 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_MCU_IE (BIT(4)) -#define IO_MUX_GPIO20_MCU_IE_M (IO_MUX_GPIO20_MCU_IE_V << IO_MUX_GPIO20_MCU_IE_S) -#define IO_MUX_GPIO20_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO20_MCU_IE_S 4 -/** IO_MUX_GPIO20_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO20 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO20_MCU_DRV 0x00000003U -#define IO_MUX_GPIO20_MCU_DRV_M (IO_MUX_GPIO20_MCU_DRV_V << IO_MUX_GPIO20_MCU_DRV_S) -#define IO_MUX_GPIO20_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO20_MCU_DRV_S 5 -/** IO_MUX_GPIO20_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO20.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO20_FUN_WPD_M (IO_MUX_GPIO20_FUN_WPD_V << IO_MUX_GPIO20_FUN_WPD_S) -#define IO_MUX_GPIO20_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO20_FUN_WPD_S 7 -/** IO_MUX_GPIO20_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO20.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO20_FUN_WPU_M (IO_MUX_GPIO20_FUN_WPU_V << IO_MUX_GPIO20_FUN_WPU_S) -#define IO_MUX_GPIO20_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO20_FUN_WPU_S 8 -/** IO_MUX_GPIO20_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO20.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_FUN_IE (BIT(9)) -#define IO_MUX_GPIO20_FUN_IE_M (IO_MUX_GPIO20_FUN_IE_V << IO_MUX_GPIO20_FUN_IE_S) -#define IO_MUX_GPIO20_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO20_FUN_IE_S 9 -/** IO_MUX_GPIO20_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO20. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO20_FUN_DRV 0x00000003U -#define IO_MUX_GPIO20_FUN_DRV_M (IO_MUX_GPIO20_FUN_DRV_V << IO_MUX_GPIO20_FUN_DRV_S) -#define IO_MUX_GPIO20_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO20_FUN_DRV_S 10 -/** IO_MUX_GPIO20_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO20_MCU_SEL 0x00000007U -#define IO_MUX_GPIO20_MCU_SEL_M (IO_MUX_GPIO20_MCU_SEL_V << IO_MUX_GPIO20_MCU_SEL_S) -#define IO_MUX_GPIO20_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO20_MCU_SEL_S 12 -/** IO_MUX_GPIO20_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO20_FILTER_EN_M (IO_MUX_GPIO20_FILTER_EN_V << IO_MUX_GPIO20_FILTER_EN_S) -#define IO_MUX_GPIO20_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO20_FILTER_EN_S 15 -/** IO_MUX_GPIO20_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO20_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO20_HYS_EN (BIT(16)) -#define IO_MUX_GPIO20_HYS_EN_M (IO_MUX_GPIO20_HYS_EN_V << IO_MUX_GPIO20_HYS_EN_S) -#define IO_MUX_GPIO20_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO20_HYS_EN_S 16 -/** IO_MUX_GPIO20_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO20. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO20_HYS_EN\\ - */ -#define IO_MUX_GPIO20_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO20_HYS_SEL_M (IO_MUX_GPIO20_HYS_SEL_V << IO_MUX_GPIO20_HYS_SEL_S) -#define IO_MUX_GPIO20_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO20_HYS_SEL_S 17 - -/** IO_MUX_GPIO21_REG register - * IO MUX configuration register for GPIO21 - */ -#define IO_MUX_GPIO21_REG (DR_REG_IO_MUX_BASE + 0x54) -/** IO_MUX_GPIO21_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO21 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_MCU_OE (BIT(0)) -#define IO_MUX_GPIO21_MCU_OE_M (IO_MUX_GPIO21_MCU_OE_V << IO_MUX_GPIO21_MCU_OE_S) -#define IO_MUX_GPIO21_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO21_MCU_OE_S 0 -/** IO_MUX_GPIO21_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO21.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO21_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO21_SLP_SEL_M (IO_MUX_GPIO21_SLP_SEL_V << IO_MUX_GPIO21_SLP_SEL_S) -#define IO_MUX_GPIO21_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO21_SLP_SEL_S 1 -/** IO_MUX_GPIO21_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO21 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO21_MCU_WPD_M (IO_MUX_GPIO21_MCU_WPD_V << IO_MUX_GPIO21_MCU_WPD_S) -#define IO_MUX_GPIO21_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO21_MCU_WPD_S 2 -/** IO_MUX_GPIO21_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO21 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO21_MCU_WPU_M (IO_MUX_GPIO21_MCU_WPU_V << IO_MUX_GPIO21_MCU_WPU_S) -#define IO_MUX_GPIO21_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO21_MCU_WPU_S 3 -/** IO_MUX_GPIO21_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO21 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_MCU_IE (BIT(4)) -#define IO_MUX_GPIO21_MCU_IE_M (IO_MUX_GPIO21_MCU_IE_V << IO_MUX_GPIO21_MCU_IE_S) -#define IO_MUX_GPIO21_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO21_MCU_IE_S 4 -/** IO_MUX_GPIO21_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO21 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO21_MCU_DRV 0x00000003U -#define IO_MUX_GPIO21_MCU_DRV_M (IO_MUX_GPIO21_MCU_DRV_V << IO_MUX_GPIO21_MCU_DRV_S) -#define IO_MUX_GPIO21_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO21_MCU_DRV_S 5 -/** IO_MUX_GPIO21_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO21.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO21_FUN_WPD_M (IO_MUX_GPIO21_FUN_WPD_V << IO_MUX_GPIO21_FUN_WPD_S) -#define IO_MUX_GPIO21_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO21_FUN_WPD_S 7 -/** IO_MUX_GPIO21_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO21.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO21_FUN_WPU_M (IO_MUX_GPIO21_FUN_WPU_V << IO_MUX_GPIO21_FUN_WPU_S) -#define IO_MUX_GPIO21_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO21_FUN_WPU_S 8 -/** IO_MUX_GPIO21_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO21.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_FUN_IE (BIT(9)) -#define IO_MUX_GPIO21_FUN_IE_M (IO_MUX_GPIO21_FUN_IE_V << IO_MUX_GPIO21_FUN_IE_S) -#define IO_MUX_GPIO21_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO21_FUN_IE_S 9 -/** IO_MUX_GPIO21_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO21. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO21_FUN_DRV 0x00000003U -#define IO_MUX_GPIO21_FUN_DRV_M (IO_MUX_GPIO21_FUN_DRV_V << IO_MUX_GPIO21_FUN_DRV_S) -#define IO_MUX_GPIO21_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO21_FUN_DRV_S 10 -/** IO_MUX_GPIO21_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO21_MCU_SEL 0x00000007U -#define IO_MUX_GPIO21_MCU_SEL_M (IO_MUX_GPIO21_MCU_SEL_V << IO_MUX_GPIO21_MCU_SEL_S) -#define IO_MUX_GPIO21_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO21_MCU_SEL_S 12 -/** IO_MUX_GPIO21_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO21_FILTER_EN_M (IO_MUX_GPIO21_FILTER_EN_V << IO_MUX_GPIO21_FILTER_EN_S) -#define IO_MUX_GPIO21_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO21_FILTER_EN_S 15 -/** IO_MUX_GPIO21_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO21_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO21_HYS_EN (BIT(16)) -#define IO_MUX_GPIO21_HYS_EN_M (IO_MUX_GPIO21_HYS_EN_V << IO_MUX_GPIO21_HYS_EN_S) -#define IO_MUX_GPIO21_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO21_HYS_EN_S 16 -/** IO_MUX_GPIO21_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO21. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO21_HYS_EN\\ - */ -#define IO_MUX_GPIO21_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO21_HYS_SEL_M (IO_MUX_GPIO21_HYS_SEL_V << IO_MUX_GPIO21_HYS_SEL_S) -#define IO_MUX_GPIO21_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO21_HYS_SEL_S 17 - -/** IO_MUX_GPIO22_REG register - * IO MUX configuration register for GPIO22 - */ -#define IO_MUX_GPIO22_REG (DR_REG_IO_MUX_BASE + 0x58) -/** IO_MUX_GPIO22_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO22 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_MCU_OE (BIT(0)) -#define IO_MUX_GPIO22_MCU_OE_M (IO_MUX_GPIO22_MCU_OE_V << IO_MUX_GPIO22_MCU_OE_S) -#define IO_MUX_GPIO22_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO22_MCU_OE_S 0 -/** IO_MUX_GPIO22_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO22.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO22_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO22_SLP_SEL_M (IO_MUX_GPIO22_SLP_SEL_V << IO_MUX_GPIO22_SLP_SEL_S) -#define IO_MUX_GPIO22_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO22_SLP_SEL_S 1 -/** IO_MUX_GPIO22_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO22 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO22_MCU_WPD_M (IO_MUX_GPIO22_MCU_WPD_V << IO_MUX_GPIO22_MCU_WPD_S) -#define IO_MUX_GPIO22_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO22_MCU_WPD_S 2 -/** IO_MUX_GPIO22_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO22 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO22_MCU_WPU_M (IO_MUX_GPIO22_MCU_WPU_V << IO_MUX_GPIO22_MCU_WPU_S) -#define IO_MUX_GPIO22_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO22_MCU_WPU_S 3 -/** IO_MUX_GPIO22_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO22 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_MCU_IE (BIT(4)) -#define IO_MUX_GPIO22_MCU_IE_M (IO_MUX_GPIO22_MCU_IE_V << IO_MUX_GPIO22_MCU_IE_S) -#define IO_MUX_GPIO22_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO22_MCU_IE_S 4 -/** IO_MUX_GPIO22_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO22 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO22_MCU_DRV 0x00000003U -#define IO_MUX_GPIO22_MCU_DRV_M (IO_MUX_GPIO22_MCU_DRV_V << IO_MUX_GPIO22_MCU_DRV_S) -#define IO_MUX_GPIO22_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO22_MCU_DRV_S 5 -/** IO_MUX_GPIO22_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO22.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO22_FUN_WPD_M (IO_MUX_GPIO22_FUN_WPD_V << IO_MUX_GPIO22_FUN_WPD_S) -#define IO_MUX_GPIO22_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO22_FUN_WPD_S 7 -/** IO_MUX_GPIO22_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO22.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO22_FUN_WPU_M (IO_MUX_GPIO22_FUN_WPU_V << IO_MUX_GPIO22_FUN_WPU_S) -#define IO_MUX_GPIO22_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO22_FUN_WPU_S 8 -/** IO_MUX_GPIO22_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO22.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_FUN_IE (BIT(9)) -#define IO_MUX_GPIO22_FUN_IE_M (IO_MUX_GPIO22_FUN_IE_V << IO_MUX_GPIO22_FUN_IE_S) -#define IO_MUX_GPIO22_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO22_FUN_IE_S 9 -/** IO_MUX_GPIO22_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO22. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO22_FUN_DRV 0x00000003U -#define IO_MUX_GPIO22_FUN_DRV_M (IO_MUX_GPIO22_FUN_DRV_V << IO_MUX_GPIO22_FUN_DRV_S) -#define IO_MUX_GPIO22_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO22_FUN_DRV_S 10 -/** IO_MUX_GPIO22_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO22_MCU_SEL 0x00000007U -#define IO_MUX_GPIO22_MCU_SEL_M (IO_MUX_GPIO22_MCU_SEL_V << IO_MUX_GPIO22_MCU_SEL_S) -#define IO_MUX_GPIO22_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO22_MCU_SEL_S 12 -/** IO_MUX_GPIO22_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO22_FILTER_EN_M (IO_MUX_GPIO22_FILTER_EN_V << IO_MUX_GPIO22_FILTER_EN_S) -#define IO_MUX_GPIO22_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO22_FILTER_EN_S 15 -/** IO_MUX_GPIO22_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO22_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO22_HYS_EN (BIT(16)) -#define IO_MUX_GPIO22_HYS_EN_M (IO_MUX_GPIO22_HYS_EN_V << IO_MUX_GPIO22_HYS_EN_S) -#define IO_MUX_GPIO22_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO22_HYS_EN_S 16 -/** IO_MUX_GPIO22_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO22. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO22_HYS_EN\\ - */ -#define IO_MUX_GPIO22_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO22_HYS_SEL_M (IO_MUX_GPIO22_HYS_SEL_V << IO_MUX_GPIO22_HYS_SEL_S) -#define IO_MUX_GPIO22_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO22_HYS_SEL_S 17 - -/** IO_MUX_GPIO23_REG register - * IO MUX configuration register for GPIO23 - */ -#define IO_MUX_GPIO23_REG (DR_REG_IO_MUX_BASE + 0x5c) -/** IO_MUX_GPIO23_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO23 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_MCU_OE (BIT(0)) -#define IO_MUX_GPIO23_MCU_OE_M (IO_MUX_GPIO23_MCU_OE_V << IO_MUX_GPIO23_MCU_OE_S) -#define IO_MUX_GPIO23_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO23_MCU_OE_S 0 -/** IO_MUX_GPIO23_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO23.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO23_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO23_SLP_SEL_M (IO_MUX_GPIO23_SLP_SEL_V << IO_MUX_GPIO23_SLP_SEL_S) -#define IO_MUX_GPIO23_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO23_SLP_SEL_S 1 -/** IO_MUX_GPIO23_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO23 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO23_MCU_WPD_M (IO_MUX_GPIO23_MCU_WPD_V << IO_MUX_GPIO23_MCU_WPD_S) -#define IO_MUX_GPIO23_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO23_MCU_WPD_S 2 -/** IO_MUX_GPIO23_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO23 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO23_MCU_WPU_M (IO_MUX_GPIO23_MCU_WPU_V << IO_MUX_GPIO23_MCU_WPU_S) -#define IO_MUX_GPIO23_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO23_MCU_WPU_S 3 -/** IO_MUX_GPIO23_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO23 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_MCU_IE (BIT(4)) -#define IO_MUX_GPIO23_MCU_IE_M (IO_MUX_GPIO23_MCU_IE_V << IO_MUX_GPIO23_MCU_IE_S) -#define IO_MUX_GPIO23_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO23_MCU_IE_S 4 -/** IO_MUX_GPIO23_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO23 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO23_MCU_DRV 0x00000003U -#define IO_MUX_GPIO23_MCU_DRV_M (IO_MUX_GPIO23_MCU_DRV_V << IO_MUX_GPIO23_MCU_DRV_S) -#define IO_MUX_GPIO23_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO23_MCU_DRV_S 5 -/** IO_MUX_GPIO23_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO23.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO23_FUN_WPD_M (IO_MUX_GPIO23_FUN_WPD_V << IO_MUX_GPIO23_FUN_WPD_S) -#define IO_MUX_GPIO23_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO23_FUN_WPD_S 7 -/** IO_MUX_GPIO23_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO23.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO23_FUN_WPU_M (IO_MUX_GPIO23_FUN_WPU_V << IO_MUX_GPIO23_FUN_WPU_S) -#define IO_MUX_GPIO23_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO23_FUN_WPU_S 8 -/** IO_MUX_GPIO23_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO23.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_FUN_IE (BIT(9)) -#define IO_MUX_GPIO23_FUN_IE_M (IO_MUX_GPIO23_FUN_IE_V << IO_MUX_GPIO23_FUN_IE_S) -#define IO_MUX_GPIO23_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO23_FUN_IE_S 9 -/** IO_MUX_GPIO23_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO23. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO23_FUN_DRV 0x00000003U -#define IO_MUX_GPIO23_FUN_DRV_M (IO_MUX_GPIO23_FUN_DRV_V << IO_MUX_GPIO23_FUN_DRV_S) -#define IO_MUX_GPIO23_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO23_FUN_DRV_S 10 -/** IO_MUX_GPIO23_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO23_MCU_SEL 0x00000007U -#define IO_MUX_GPIO23_MCU_SEL_M (IO_MUX_GPIO23_MCU_SEL_V << IO_MUX_GPIO23_MCU_SEL_S) -#define IO_MUX_GPIO23_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO23_MCU_SEL_S 12 -/** IO_MUX_GPIO23_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO23_FILTER_EN_M (IO_MUX_GPIO23_FILTER_EN_V << IO_MUX_GPIO23_FILTER_EN_S) -#define IO_MUX_GPIO23_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO23_FILTER_EN_S 15 -/** IO_MUX_GPIO23_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO23_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO23_HYS_EN (BIT(16)) -#define IO_MUX_GPIO23_HYS_EN_M (IO_MUX_GPIO23_HYS_EN_V << IO_MUX_GPIO23_HYS_EN_S) -#define IO_MUX_GPIO23_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO23_HYS_EN_S 16 -/** IO_MUX_GPIO23_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO23. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO23_HYS_EN\\ - */ -#define IO_MUX_GPIO23_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO23_HYS_SEL_M (IO_MUX_GPIO23_HYS_SEL_V << IO_MUX_GPIO23_HYS_SEL_S) -#define IO_MUX_GPIO23_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO23_HYS_SEL_S 17 - -/** IO_MUX_GPIO24_REG register - * IO MUX configuration register for GPIO24 - */ -#define IO_MUX_GPIO24_REG (DR_REG_IO_MUX_BASE + 0x60) -/** IO_MUX_GPIO24_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO24 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_MCU_OE (BIT(0)) -#define IO_MUX_GPIO24_MCU_OE_M (IO_MUX_GPIO24_MCU_OE_V << IO_MUX_GPIO24_MCU_OE_S) -#define IO_MUX_GPIO24_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO24_MCU_OE_S 0 -/** IO_MUX_GPIO24_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO24.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO24_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO24_SLP_SEL_M (IO_MUX_GPIO24_SLP_SEL_V << IO_MUX_GPIO24_SLP_SEL_S) -#define IO_MUX_GPIO24_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO24_SLP_SEL_S 1 -/** IO_MUX_GPIO24_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO24 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO24_MCU_WPD_M (IO_MUX_GPIO24_MCU_WPD_V << IO_MUX_GPIO24_MCU_WPD_S) -#define IO_MUX_GPIO24_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO24_MCU_WPD_S 2 -/** IO_MUX_GPIO24_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO24 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO24_MCU_WPU_M (IO_MUX_GPIO24_MCU_WPU_V << IO_MUX_GPIO24_MCU_WPU_S) -#define IO_MUX_GPIO24_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO24_MCU_WPU_S 3 -/** IO_MUX_GPIO24_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO24 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_MCU_IE (BIT(4)) -#define IO_MUX_GPIO24_MCU_IE_M (IO_MUX_GPIO24_MCU_IE_V << IO_MUX_GPIO24_MCU_IE_S) -#define IO_MUX_GPIO24_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO24_MCU_IE_S 4 -/** IO_MUX_GPIO24_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO24 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO24_MCU_DRV 0x00000003U -#define IO_MUX_GPIO24_MCU_DRV_M (IO_MUX_GPIO24_MCU_DRV_V << IO_MUX_GPIO24_MCU_DRV_S) -#define IO_MUX_GPIO24_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO24_MCU_DRV_S 5 -/** IO_MUX_GPIO24_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO24.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO24_FUN_WPD_M (IO_MUX_GPIO24_FUN_WPD_V << IO_MUX_GPIO24_FUN_WPD_S) -#define IO_MUX_GPIO24_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO24_FUN_WPD_S 7 -/** IO_MUX_GPIO24_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO24.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO24_FUN_WPU_M (IO_MUX_GPIO24_FUN_WPU_V << IO_MUX_GPIO24_FUN_WPU_S) -#define IO_MUX_GPIO24_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO24_FUN_WPU_S 8 -/** IO_MUX_GPIO24_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO24.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_FUN_IE (BIT(9)) -#define IO_MUX_GPIO24_FUN_IE_M (IO_MUX_GPIO24_FUN_IE_V << IO_MUX_GPIO24_FUN_IE_S) -#define IO_MUX_GPIO24_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO24_FUN_IE_S 9 -/** IO_MUX_GPIO24_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO24. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO24_FUN_DRV 0x00000003U -#define IO_MUX_GPIO24_FUN_DRV_M (IO_MUX_GPIO24_FUN_DRV_V << IO_MUX_GPIO24_FUN_DRV_S) -#define IO_MUX_GPIO24_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO24_FUN_DRV_S 10 -/** IO_MUX_GPIO24_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO24_MCU_SEL 0x00000007U -#define IO_MUX_GPIO24_MCU_SEL_M (IO_MUX_GPIO24_MCU_SEL_V << IO_MUX_GPIO24_MCU_SEL_S) -#define IO_MUX_GPIO24_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO24_MCU_SEL_S 12 -/** IO_MUX_GPIO24_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO24_FILTER_EN_M (IO_MUX_GPIO24_FILTER_EN_V << IO_MUX_GPIO24_FILTER_EN_S) -#define IO_MUX_GPIO24_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO24_FILTER_EN_S 15 -/** IO_MUX_GPIO24_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO24_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO24_HYS_EN (BIT(16)) -#define IO_MUX_GPIO24_HYS_EN_M (IO_MUX_GPIO24_HYS_EN_V << IO_MUX_GPIO24_HYS_EN_S) -#define IO_MUX_GPIO24_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO24_HYS_EN_S 16 -/** IO_MUX_GPIO24_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO24. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO24_HYS_EN\\ - */ -#define IO_MUX_GPIO24_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO24_HYS_SEL_M (IO_MUX_GPIO24_HYS_SEL_V << IO_MUX_GPIO24_HYS_SEL_S) -#define IO_MUX_GPIO24_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO24_HYS_SEL_S 17 - -/** IO_MUX_GPIO25_REG register - * IO MUX configuration register for GPIO25 - */ -#define IO_MUX_GPIO25_REG (DR_REG_IO_MUX_BASE + 0x64) -/** IO_MUX_GPIO25_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO25 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_MCU_OE (BIT(0)) -#define IO_MUX_GPIO25_MCU_OE_M (IO_MUX_GPIO25_MCU_OE_V << IO_MUX_GPIO25_MCU_OE_S) -#define IO_MUX_GPIO25_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO25_MCU_OE_S 0 -/** IO_MUX_GPIO25_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO25.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO25_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO25_SLP_SEL_M (IO_MUX_GPIO25_SLP_SEL_V << IO_MUX_GPIO25_SLP_SEL_S) -#define IO_MUX_GPIO25_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO25_SLP_SEL_S 1 -/** IO_MUX_GPIO25_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO25 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO25_MCU_WPD_M (IO_MUX_GPIO25_MCU_WPD_V << IO_MUX_GPIO25_MCU_WPD_S) -#define IO_MUX_GPIO25_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO25_MCU_WPD_S 2 -/** IO_MUX_GPIO25_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO25 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO25_MCU_WPU_M (IO_MUX_GPIO25_MCU_WPU_V << IO_MUX_GPIO25_MCU_WPU_S) -#define IO_MUX_GPIO25_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO25_MCU_WPU_S 3 -/** IO_MUX_GPIO25_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO25 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_MCU_IE (BIT(4)) -#define IO_MUX_GPIO25_MCU_IE_M (IO_MUX_GPIO25_MCU_IE_V << IO_MUX_GPIO25_MCU_IE_S) -#define IO_MUX_GPIO25_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO25_MCU_IE_S 4 -/** IO_MUX_GPIO25_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO25 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO25_MCU_DRV 0x00000003U -#define IO_MUX_GPIO25_MCU_DRV_M (IO_MUX_GPIO25_MCU_DRV_V << IO_MUX_GPIO25_MCU_DRV_S) -#define IO_MUX_GPIO25_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO25_MCU_DRV_S 5 -/** IO_MUX_GPIO25_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO25.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO25_FUN_WPD_M (IO_MUX_GPIO25_FUN_WPD_V << IO_MUX_GPIO25_FUN_WPD_S) -#define IO_MUX_GPIO25_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO25_FUN_WPD_S 7 -/** IO_MUX_GPIO25_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO25.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO25_FUN_WPU_M (IO_MUX_GPIO25_FUN_WPU_V << IO_MUX_GPIO25_FUN_WPU_S) -#define IO_MUX_GPIO25_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO25_FUN_WPU_S 8 -/** IO_MUX_GPIO25_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO25.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_FUN_IE (BIT(9)) -#define IO_MUX_GPIO25_FUN_IE_M (IO_MUX_GPIO25_FUN_IE_V << IO_MUX_GPIO25_FUN_IE_S) -#define IO_MUX_GPIO25_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO25_FUN_IE_S 9 -/** IO_MUX_GPIO25_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO25. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO25_FUN_DRV 0x00000003U -#define IO_MUX_GPIO25_FUN_DRV_M (IO_MUX_GPIO25_FUN_DRV_V << IO_MUX_GPIO25_FUN_DRV_S) -#define IO_MUX_GPIO25_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO25_FUN_DRV_S 10 -/** IO_MUX_GPIO25_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO25_MCU_SEL 0x00000007U -#define IO_MUX_GPIO25_MCU_SEL_M (IO_MUX_GPIO25_MCU_SEL_V << IO_MUX_GPIO25_MCU_SEL_S) -#define IO_MUX_GPIO25_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO25_MCU_SEL_S 12 -/** IO_MUX_GPIO25_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO25_FILTER_EN_M (IO_MUX_GPIO25_FILTER_EN_V << IO_MUX_GPIO25_FILTER_EN_S) -#define IO_MUX_GPIO25_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO25_FILTER_EN_S 15 -/** IO_MUX_GPIO25_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO25_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO25_HYS_EN (BIT(16)) -#define IO_MUX_GPIO25_HYS_EN_M (IO_MUX_GPIO25_HYS_EN_V << IO_MUX_GPIO25_HYS_EN_S) -#define IO_MUX_GPIO25_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO25_HYS_EN_S 16 -/** IO_MUX_GPIO25_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO25. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO25_HYS_EN\\ - */ -#define IO_MUX_GPIO25_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO25_HYS_SEL_M (IO_MUX_GPIO25_HYS_SEL_V << IO_MUX_GPIO25_HYS_SEL_S) -#define IO_MUX_GPIO25_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO25_HYS_SEL_S 17 - -/** IO_MUX_GPIO26_REG register - * IO MUX configuration register for GPIO26 - */ -#define IO_MUX_GPIO26_REG (DR_REG_IO_MUX_BASE + 0x68) -/** IO_MUX_GPIO26_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO26 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_MCU_OE (BIT(0)) -#define IO_MUX_GPIO26_MCU_OE_M (IO_MUX_GPIO26_MCU_OE_V << IO_MUX_GPIO26_MCU_OE_S) -#define IO_MUX_GPIO26_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO26_MCU_OE_S 0 -/** IO_MUX_GPIO26_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO26.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO26_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO26_SLP_SEL_M (IO_MUX_GPIO26_SLP_SEL_V << IO_MUX_GPIO26_SLP_SEL_S) -#define IO_MUX_GPIO26_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO26_SLP_SEL_S 1 -/** IO_MUX_GPIO26_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO26 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO26_MCU_WPD_M (IO_MUX_GPIO26_MCU_WPD_V << IO_MUX_GPIO26_MCU_WPD_S) -#define IO_MUX_GPIO26_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO26_MCU_WPD_S 2 -/** IO_MUX_GPIO26_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO26 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO26_MCU_WPU_M (IO_MUX_GPIO26_MCU_WPU_V << IO_MUX_GPIO26_MCU_WPU_S) -#define IO_MUX_GPIO26_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO26_MCU_WPU_S 3 -/** IO_MUX_GPIO26_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO26 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_MCU_IE (BIT(4)) -#define IO_MUX_GPIO26_MCU_IE_M (IO_MUX_GPIO26_MCU_IE_V << IO_MUX_GPIO26_MCU_IE_S) -#define IO_MUX_GPIO26_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO26_MCU_IE_S 4 -/** IO_MUX_GPIO26_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO26 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO26_MCU_DRV 0x00000003U -#define IO_MUX_GPIO26_MCU_DRV_M (IO_MUX_GPIO26_MCU_DRV_V << IO_MUX_GPIO26_MCU_DRV_S) -#define IO_MUX_GPIO26_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO26_MCU_DRV_S 5 -/** IO_MUX_GPIO26_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO26.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO26_FUN_WPD_M (IO_MUX_GPIO26_FUN_WPD_V << IO_MUX_GPIO26_FUN_WPD_S) -#define IO_MUX_GPIO26_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO26_FUN_WPD_S 7 -/** IO_MUX_GPIO26_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO26.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO26_FUN_WPU_M (IO_MUX_GPIO26_FUN_WPU_V << IO_MUX_GPIO26_FUN_WPU_S) -#define IO_MUX_GPIO26_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO26_FUN_WPU_S 8 -/** IO_MUX_GPIO26_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO26.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_FUN_IE (BIT(9)) -#define IO_MUX_GPIO26_FUN_IE_M (IO_MUX_GPIO26_FUN_IE_V << IO_MUX_GPIO26_FUN_IE_S) -#define IO_MUX_GPIO26_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO26_FUN_IE_S 9 -/** IO_MUX_GPIO26_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO26. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO26_FUN_DRV 0x00000003U -#define IO_MUX_GPIO26_FUN_DRV_M (IO_MUX_GPIO26_FUN_DRV_V << IO_MUX_GPIO26_FUN_DRV_S) -#define IO_MUX_GPIO26_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO26_FUN_DRV_S 10 -/** IO_MUX_GPIO26_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO26_MCU_SEL 0x00000007U -#define IO_MUX_GPIO26_MCU_SEL_M (IO_MUX_GPIO26_MCU_SEL_V << IO_MUX_GPIO26_MCU_SEL_S) -#define IO_MUX_GPIO26_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO26_MCU_SEL_S 12 -/** IO_MUX_GPIO26_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO26_FILTER_EN_M (IO_MUX_GPIO26_FILTER_EN_V << IO_MUX_GPIO26_FILTER_EN_S) -#define IO_MUX_GPIO26_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO26_FILTER_EN_S 15 -/** IO_MUX_GPIO26_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO26_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO26_HYS_EN (BIT(16)) -#define IO_MUX_GPIO26_HYS_EN_M (IO_MUX_GPIO26_HYS_EN_V << IO_MUX_GPIO26_HYS_EN_S) -#define IO_MUX_GPIO26_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO26_HYS_EN_S 16 -/** IO_MUX_GPIO26_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO26. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO26_HYS_EN\\ - */ -#define IO_MUX_GPIO26_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO26_HYS_SEL_M (IO_MUX_GPIO26_HYS_SEL_V << IO_MUX_GPIO26_HYS_SEL_S) -#define IO_MUX_GPIO26_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO26_HYS_SEL_S 17 - -/** IO_MUX_GPIO27_REG register - * IO MUX configuration register for GPIO27 - */ -#define IO_MUX_GPIO27_REG (DR_REG_IO_MUX_BASE + 0x6c) -/** IO_MUX_GPIO27_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO27 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_MCU_OE (BIT(0)) -#define IO_MUX_GPIO27_MCU_OE_M (IO_MUX_GPIO27_MCU_OE_V << IO_MUX_GPIO27_MCU_OE_S) -#define IO_MUX_GPIO27_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO27_MCU_OE_S 0 -/** IO_MUX_GPIO27_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO27.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO27_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO27_SLP_SEL_M (IO_MUX_GPIO27_SLP_SEL_V << IO_MUX_GPIO27_SLP_SEL_S) -#define IO_MUX_GPIO27_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO27_SLP_SEL_S 1 -/** IO_MUX_GPIO27_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO27 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO27_MCU_WPD_M (IO_MUX_GPIO27_MCU_WPD_V << IO_MUX_GPIO27_MCU_WPD_S) -#define IO_MUX_GPIO27_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO27_MCU_WPD_S 2 -/** IO_MUX_GPIO27_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO27 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO27_MCU_WPU_M (IO_MUX_GPIO27_MCU_WPU_V << IO_MUX_GPIO27_MCU_WPU_S) -#define IO_MUX_GPIO27_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO27_MCU_WPU_S 3 -/** IO_MUX_GPIO27_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO27 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_MCU_IE (BIT(4)) -#define IO_MUX_GPIO27_MCU_IE_M (IO_MUX_GPIO27_MCU_IE_V << IO_MUX_GPIO27_MCU_IE_S) -#define IO_MUX_GPIO27_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO27_MCU_IE_S 4 -/** IO_MUX_GPIO27_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO27 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO27_MCU_DRV 0x00000003U -#define IO_MUX_GPIO27_MCU_DRV_M (IO_MUX_GPIO27_MCU_DRV_V << IO_MUX_GPIO27_MCU_DRV_S) -#define IO_MUX_GPIO27_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO27_MCU_DRV_S 5 -/** IO_MUX_GPIO27_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO27.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO27_FUN_WPD_M (IO_MUX_GPIO27_FUN_WPD_V << IO_MUX_GPIO27_FUN_WPD_S) -#define IO_MUX_GPIO27_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO27_FUN_WPD_S 7 -/** IO_MUX_GPIO27_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO27.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO27_FUN_WPU_M (IO_MUX_GPIO27_FUN_WPU_V << IO_MUX_GPIO27_FUN_WPU_S) -#define IO_MUX_GPIO27_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO27_FUN_WPU_S 8 -/** IO_MUX_GPIO27_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO27.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_FUN_IE (BIT(9)) -#define IO_MUX_GPIO27_FUN_IE_M (IO_MUX_GPIO27_FUN_IE_V << IO_MUX_GPIO27_FUN_IE_S) -#define IO_MUX_GPIO27_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO27_FUN_IE_S 9 -/** IO_MUX_GPIO27_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO27. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO27_FUN_DRV 0x00000003U -#define IO_MUX_GPIO27_FUN_DRV_M (IO_MUX_GPIO27_FUN_DRV_V << IO_MUX_GPIO27_FUN_DRV_S) -#define IO_MUX_GPIO27_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO27_FUN_DRV_S 10 -/** IO_MUX_GPIO27_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO27_MCU_SEL 0x00000007U -#define IO_MUX_GPIO27_MCU_SEL_M (IO_MUX_GPIO27_MCU_SEL_V << IO_MUX_GPIO27_MCU_SEL_S) -#define IO_MUX_GPIO27_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO27_MCU_SEL_S 12 -/** IO_MUX_GPIO27_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO27_FILTER_EN_M (IO_MUX_GPIO27_FILTER_EN_V << IO_MUX_GPIO27_FILTER_EN_S) -#define IO_MUX_GPIO27_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO27_FILTER_EN_S 15 -/** IO_MUX_GPIO27_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO27_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO27_HYS_EN (BIT(16)) -#define IO_MUX_GPIO27_HYS_EN_M (IO_MUX_GPIO27_HYS_EN_V << IO_MUX_GPIO27_HYS_EN_S) -#define IO_MUX_GPIO27_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO27_HYS_EN_S 16 -/** IO_MUX_GPIO27_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO27. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO27_HYS_EN\\ - */ -#define IO_MUX_GPIO27_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO27_HYS_SEL_M (IO_MUX_GPIO27_HYS_SEL_V << IO_MUX_GPIO27_HYS_SEL_S) -#define IO_MUX_GPIO27_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO27_HYS_SEL_S 17 - -/** IO_MUX_GPIO28_REG register - * IO MUX configuration register for GPIO28 - */ -#define IO_MUX_GPIO28_REG (DR_REG_IO_MUX_BASE + 0x70) -/** IO_MUX_GPIO28_MCU_OE : R/W; bitpos: [0]; default: 0; - * Configures whether or not to enable the output of GPIO28 in sleep mode. - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_MCU_OE (BIT(0)) -#define IO_MUX_GPIO28_MCU_OE_M (IO_MUX_GPIO28_MCU_OE_V << IO_MUX_GPIO28_MCU_OE_S) -#define IO_MUX_GPIO28_MCU_OE_V 0x00000001U -#define IO_MUX_GPIO28_MCU_OE_S 0 -/** IO_MUX_GPIO28_SLP_SEL : R/W; bitpos: [1]; default: 0; - * Configures whether or not to enter sleep mode for GPIO28.\\ - * 0: Not enter\\ - * 1: Enter\\ - */ -#define IO_MUX_GPIO28_SLP_SEL (BIT(1)) -#define IO_MUX_GPIO28_SLP_SEL_M (IO_MUX_GPIO28_SLP_SEL_V << IO_MUX_GPIO28_SLP_SEL_S) -#define IO_MUX_GPIO28_SLP_SEL_V 0x00000001U -#define IO_MUX_GPIO28_SLP_SEL_S 1 -/** IO_MUX_GPIO28_MCU_WPD : R/W; bitpos: [2]; default: 0; - * Configure whether or not to enable pull-down resistor of GPIO28 in sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_MCU_WPD (BIT(2)) -#define IO_MUX_GPIO28_MCU_WPD_M (IO_MUX_GPIO28_MCU_WPD_V << IO_MUX_GPIO28_MCU_WPD_S) -#define IO_MUX_GPIO28_MCU_WPD_V 0x00000001U -#define IO_MUX_GPIO28_MCU_WPD_S 2 -/** IO_MUX_GPIO28_MCU_WPU : R/W; bitpos: [3]; default: 0; - * Configures whether or not to enable pull-up resistor of GPIO28 during sleep mode. \\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_MCU_WPU (BIT(3)) -#define IO_MUX_GPIO28_MCU_WPU_M (IO_MUX_GPIO28_MCU_WPU_V << IO_MUX_GPIO28_MCU_WPU_S) -#define IO_MUX_GPIO28_MCU_WPU_V 0x00000001U -#define IO_MUX_GPIO28_MCU_WPU_S 3 -/** IO_MUX_GPIO28_MCU_IE : R/W; bitpos: [4]; default: 0; - * Configures whether or not to enable the input of GPIO28 during sleep mode.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_MCU_IE (BIT(4)) -#define IO_MUX_GPIO28_MCU_IE_M (IO_MUX_GPIO28_MCU_IE_V << IO_MUX_GPIO28_MCU_IE_S) -#define IO_MUX_GPIO28_MCU_IE_V 0x00000001U -#define IO_MUX_GPIO28_MCU_IE_S 4 -/** IO_MUX_GPIO28_MCU_DRV : R/W; bitpos: [6:5]; default: 0; - * Configures the drive strength of GPIO28 during sleep mode. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO28_MCU_DRV 0x00000003U -#define IO_MUX_GPIO28_MCU_DRV_M (IO_MUX_GPIO28_MCU_DRV_V << IO_MUX_GPIO28_MCU_DRV_S) -#define IO_MUX_GPIO28_MCU_DRV_V 0x00000003U -#define IO_MUX_GPIO28_MCU_DRV_S 5 -/** IO_MUX_GPIO28_FUN_WPD : R/W; bitpos: [7]; default: 0; - * Configures whether or not to enable pull-down resistor of GPIO28.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_FUN_WPD (BIT(7)) -#define IO_MUX_GPIO28_FUN_WPD_M (IO_MUX_GPIO28_FUN_WPD_V << IO_MUX_GPIO28_FUN_WPD_S) -#define IO_MUX_GPIO28_FUN_WPD_V 0x00000001U -#define IO_MUX_GPIO28_FUN_WPD_S 7 -/** IO_MUX_GPIO28_FUN_WPU : R/W; bitpos: [8]; default: 0; - * Configures whether or not enable pull-up resistor of GPIO28.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_FUN_WPU (BIT(8)) -#define IO_MUX_GPIO28_FUN_WPU_M (IO_MUX_GPIO28_FUN_WPU_V << IO_MUX_GPIO28_FUN_WPU_S) -#define IO_MUX_GPIO28_FUN_WPU_V 0x00000001U -#define IO_MUX_GPIO28_FUN_WPU_S 8 -/** IO_MUX_GPIO28_FUN_IE : R/W; bitpos: [9]; default: 0; - * Configures whether or not to enable input of GPIO28.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_FUN_IE (BIT(9)) -#define IO_MUX_GPIO28_FUN_IE_M (IO_MUX_GPIO28_FUN_IE_V << IO_MUX_GPIO28_FUN_IE_S) -#define IO_MUX_GPIO28_FUN_IE_V 0x00000001U -#define IO_MUX_GPIO28_FUN_IE_S 9 -/** IO_MUX_GPIO28_FUN_DRV : R/W; bitpos: [11:10]; default: 2; - * Configures the drive strength of GPIO28. \\ - * 0: ~5 mA\\ - * 1: ~10 mA\\ - * 2: ~20 mA\\ - * 3: ~40 mA\\ - */ -#define IO_MUX_GPIO28_FUN_DRV 0x00000003U -#define IO_MUX_GPIO28_FUN_DRV_M (IO_MUX_GPIO28_FUN_DRV_V << IO_MUX_GPIO28_FUN_DRV_S) -#define IO_MUX_GPIO28_FUN_DRV_V 0x00000003U -#define IO_MUX_GPIO28_FUN_DRV_S 10 -/** IO_MUX_GPIO28_MCU_SEL : R/W; bitpos: [14:12]; default: 1; - * Configures to select IO MUX function for this signal. \\ - * 0: Select Function 0\\ - * 1: Select Function 1\\ - * ......\\ - */ -#define IO_MUX_GPIO28_MCU_SEL 0x00000007U -#define IO_MUX_GPIO28_MCU_SEL_M (IO_MUX_GPIO28_MCU_SEL_V << IO_MUX_GPIO28_MCU_SEL_S) -#define IO_MUX_GPIO28_MCU_SEL_V 0x00000007U -#define IO_MUX_GPIO28_MCU_SEL_S 12 -/** IO_MUX_GPIO28_FILTER_EN : R/W; bitpos: [15]; default: 0; - * Configures whether or not to enable filter for pin input signals.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_FILTER_EN (BIT(15)) -#define IO_MUX_GPIO28_FILTER_EN_M (IO_MUX_GPIO28_FILTER_EN_V << IO_MUX_GPIO28_FILTER_EN_S) -#define IO_MUX_GPIO28_FILTER_EN_V 0x00000001U -#define IO_MUX_GPIO28_FILTER_EN_S 15 -/** IO_MUX_GPIO28_HYS_EN : R/W; bitpos: [16]; default: 0; - * Configures whether or not to enable the hysteresis function of the pin when - * IO_MUX_GPIO28_HYS_SEL is set to 1.\\ - * 0: Disable\\ - * 1: Enable\\ - */ -#define IO_MUX_GPIO28_HYS_EN (BIT(16)) -#define IO_MUX_GPIO28_HYS_EN_M (IO_MUX_GPIO28_HYS_EN_V << IO_MUX_GPIO28_HYS_EN_S) -#define IO_MUX_GPIO28_HYS_EN_V 0x00000001U -#define IO_MUX_GPIO28_HYS_EN_S 16 -/** IO_MUX_GPIO28_HYS_SEL : R/W; bitpos: [17]; default: 0; - * Configures to choose the signal for enabling the hysteresis function for GPIO28. \\ - * 0: Choose the output enable signal of eFuse\\ - * 1: Choose the output enable signal of IO_MUX_GPIO28_HYS_EN\\ - */ -#define IO_MUX_GPIO28_HYS_SEL (BIT(17)) -#define IO_MUX_GPIO28_HYS_SEL_M (IO_MUX_GPIO28_HYS_SEL_V << IO_MUX_GPIO28_HYS_SEL_S) -#define IO_MUX_GPIO28_HYS_SEL_V 0x00000001U -#define IO_MUX_GPIO28_HYS_SEL_S 17 +#define PERIPHS_IO_MUX_U_PAD_XTAL_32K_P (REG_IO_MUX_BASE + 0x0) +#define FUNC_XTAL_32K_P_GPIO0 1 +#define FUNC_XTAL_32K_P_GPIO0_0 0 + +#define PERIPHS_IO_MUX_U_PAD_XTAL_32K_N (REG_IO_MUX_BASE + 0x4) +#define FUNC_XTAL_32K_N_GPIO1 1 +#define FUNC_XTAL_32K_N_GPIO1_0 0 + +#define PERIPHS_IO_MUX_U_PAD_MTMS (REG_IO_MUX_BASE + 0x8) +#define FUNC_MTMS_FSPIQ 2 +#define FUNC_MTMS_GPIO2 1 +#define FUNC_MTMS_MTMS 0 + +#define PERIPHS_IO_MUX_U_PAD_MTDI (REG_IO_MUX_BASE + 0xC) +#define FUNC_MTDI_GPIO3 1 +#define FUNC_MTDI_MTDI 0 + +#define PERIPHS_IO_MUX_U_PAD_MTCK (REG_IO_MUX_BASE + 0x10) +#define FUNC_MTCK_FSPIHD 2 +#define FUNC_MTCK_GPIO4 1 +#define FUNC_MTCK_MTCK 0 + +#define PERIPHS_IO_MUX_U_PAD_MTDO (REG_IO_MUX_BASE + 0x14) +#define FUNC_MTDO_FSPIWP 2 +#define FUNC_MTDO_GPIO5 1 +#define FUNC_MTDO_MTDO 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO6 (REG_IO_MUX_BASE + 0x18) +#define FUNC_GPIO6_FSPICLK 2 +#define FUNC_GPIO6_GPIO6 1 +#define FUNC_GPIO6_GPIO6_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO7 (REG_IO_MUX_BASE + 0x1C) +#define FUNC_GPIO7_FSPID 2 +#define FUNC_GPIO7_GPIO7 1 +#define FUNC_GPIO7_GPIO7_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO8 (REG_IO_MUX_BASE + 0x20) +#define FUNC_GPIO8_GPIO8 1 +#define FUNC_GPIO8_GPIO8_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO9 (REG_IO_MUX_BASE + 0x24) +#define FUNC_GPIO9_GPIO9 1 +#define FUNC_GPIO9_GPIO9_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO10 (REG_IO_MUX_BASE + 0x28) +#define FUNC_GPIO10_FSPICS0 2 +#define FUNC_GPIO10_GPIO10 1 +#define FUNC_GPIO10_GPIO10_0 0 + +#define PERIPHS_IO_MUX_U_PAD_U0TXD (REG_IO_MUX_BASE + 0x2C) +#define FUNC_U0TXD_GPIO11 1 +#define FUNC_U0TXD_U0TXD 0 + +#define PERIPHS_IO_MUX_U_PAD_U0RXD (REG_IO_MUX_BASE + 0x30) +#define FUNC_U0RXD_GPIO12 1 +#define FUNC_U0RXD_U0RXD 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO13 (REG_IO_MUX_BASE + 0x34) +#define FUNC_GPIO13_GPIO13 1 +#define FUNC_GPIO13_GPIO13_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO14 (REG_IO_MUX_BASE + 0x38) +#define FUNC_GPIO14_GPIO14 1 +#define FUNC_GPIO14_GPIO14_0 0 + +#define PERIPHS_IO_MUX_U_PAD_SPICS1 (REG_IO_MUX_BASE + 0x3C) +#define FUNC_SPICS1_GPIO15 1 +#define FUNC_SPICS1_SPICS1 0 + +#define PERIPHS_IO_MUX_U_PAD_SPICS0 (REG_IO_MUX_BASE + 0x40) +#define FUNC_SPICS0_GPIO16 1 +#define FUNC_SPICS0_SPICS0 0 + +#define PERIPHS_IO_MUX_U_PAD_SPIQ (REG_IO_MUX_BASE + 0x44) +#define FUNC_SPIQ_GPIO17 1 +#define FUNC_SPIQ_SPIQ 0 + +#define PERIPHS_IO_MUX_U_PAD_SPIWP (REG_IO_MUX_BASE + 0x48) +#define FUNC_SPIWP_GPIO18 1 +#define FUNC_SPIWP_SPIWP 0 + +#define PERIPHS_IO_MUX_U_PAD_VDD_SPI (REG_IO_MUX_BASE + 0x4C) +#define FUNC_VDD_SPI_GPIO19 1 +#define FUNC_VDD_SPI_GPIO19_0 0 + +#define PERIPHS_IO_MUX_U_PAD_SPIHD (REG_IO_MUX_BASE + 0x50) +#define FUNC_SPIHD_GPIO20 1 +#define FUNC_SPIHD_SPIHD 0 + +#define PERIPHS_IO_MUX_U_PAD_SPICLK (REG_IO_MUX_BASE + 0x54) +#define FUNC_SPICLK_GPIO21 1 +#define FUNC_SPICLK_SPICLK 0 + +#define PERIPHS_IO_MUX_U_PAD_SPID (REG_IO_MUX_BASE + 0x58) +#define FUNC_SPID_GPIO22 1 +#define FUNC_SPID_SPID 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO23 (REG_IO_MUX_BASE + 0x5C) +#define FUNC_GPIO23_GPIO23 1 +#define FUNC_GPIO23_GPIO23_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO24 (REG_IO_MUX_BASE + 0x60) +#define FUNC_GPIO24_GPIO24 1 +#define FUNC_GPIO24_GPIO24_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO25 (REG_IO_MUX_BASE + 0x64) +#define FUNC_GPIO25_GPIO25 1 +#define FUNC_GPIO25_GPIO25_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO26 (REG_IO_MUX_BASE + 0x68) +#define FUNC_GPIO26_GPIO26 1 +#define FUNC_GPIO26_GPIO26_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO27 (REG_IO_MUX_BASE + 0x6C) +#define FUNC_GPIO27_GPIO27 1 +#define FUNC_GPIO27_GPIO27_0 0 + +#define PERIPHS_IO_MUX_U_PAD_GPIO28 (REG_IO_MUX_BASE + 0x70) +#define FUNC_GPIO28_GPIO28 1 +#define FUNC_GPIO28_GPIO28_0 0 /** IO_MUX_DATE_REG register * Version control register diff --git a/components/soc/esp32c5/mp/include/soc/io_mux_struct.h b/components/soc/esp32c5/mp/include/soc/io_mux_struct.h index bc32968ea04..2acfae5d3fd 100644 --- a/components/soc/esp32c5/mp/include/soc/io_mux_struct.h +++ b/components/soc/esp32c5/mp/include/soc/io_mux_struct.h @@ -134,7 +134,7 @@ typedef struct { volatile io_mux_date_reg_t date; } io_mux_dev_t; -extern io_mux_dev_t IOMUX; +extern io_mux_dev_t IO_MUX; #ifndef __cplusplus _Static_assert(sizeof(io_mux_dev_t) == 0x200, "Invalid size of io_mux_dev_t structure"); diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index b635b7f2399..f20d1b4a315 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -174,35 +174,35 @@ // #define SOC_ETM_CHANNELS_PER_GROUP 50 // Number of ETM channels in the group /*-------------------------- GPIO CAPS ---------------------------------------*/ -// TODO: [ESP32C5] IDF-8717 // ESP32-C5 has 1 GPIO peripheral -// #define SOC_GPIO_PORT 1U +#define SOC_GPIO_PORT 1U #define SOC_GPIO_PIN_COUNT 29 // #define SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER 1 // #define SOC_GPIO_FLEX_GLITCH_FILTER_NUM 8 +#define SOC_GPIO_SUPPORT_PIN_HYS_FILTER 1 // GPIO peripheral has the ETM extension // #define SOC_GPIO_SUPPORT_ETM 1 // Target has the full LP IO subsystem // On ESP32-C5, Digital IOs have their own registers to control pullup/down capability, independent of LP registers. -// #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) +#define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) // GPIO0~7 on ESP32C5 can support chip deep sleep wakeup -// #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP (1) +// #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP (1) // TODO: [ESP32C5] IDF-8719 #define SOC_GPIO_VALID_GPIO_MASK ((1U< Date: Thu, 25 Apr 2024 10:52:32 +0800 Subject: [PATCH 072/548] feat(coredump): replace fun sel function --- .../test_apps/gpio/main/test_gpio.c | 4 ---- components/espcoredump/src/core_dump_uart.c | 15 +++++++-------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c index d1811d2a068..177c65862fc 100644 --- a/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c +++ b/components/esp_driver_gpio/test_apps/gpio/main/test_gpio.c @@ -535,8 +535,6 @@ TEST_CASE("GPIO_set_output_level_get_input_level_test", "[gpio]") TEST_ASSERT_EQUAL_INT_MESSAGE(1, gpio_get_level(TEST_GPIO_EXT_IN_IO), "get level error! the level should be high!"); } -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C5) -// C5 on FPGA do not support GPIO pull down // This test routes constant-high/low signal to pins, another way is to directly connect TEST_GPIO_EXT_IN_IO to // 3.3v or GND pin TEST_CASE("GPIO_get_level_from_fixed_voltage_test", "[gpio]") @@ -664,8 +662,6 @@ TEST_CASE("GPIO_mode_test", "[gpio]") TEST_ASSERT_EQUAL_INT_MESSAGE(!level, gpio_get_level(TEST_GPIO_EXT_IN_IO), "direction GPIO_MODE_INPUT_OUTPUT set error, it gives incorrect output"); } -#endif - static void prompt_to_continue(const char *str) { printf("%s , please press \"Enter\" to go on!\n", str); diff --git a/components/espcoredump/src/core_dump_uart.c b/components/espcoredump/src/core_dump_uart.c index b859c4ea0d6..00414aaa7bf 100644 --- a/components/espcoredump/src/core_dump_uart.c +++ b/components/espcoredump/src/core_dump_uart.c @@ -6,6 +6,7 @@ #include #include "soc/uart_reg.h" #include "soc/gpio_periph.h" +#include "soc/uart_pins.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" #include "esp_core_dump_types.h" @@ -147,17 +148,15 @@ static esp_err_t esp_core_dump_uart_hw_init(void) uint32_t tm_cur = 0; int ch = 0; - // TODO: move chip dependent code to portable part + gpio_hal_context_t gpio_hal = { + .dev = GPIO_HAL_GET_HW(GPIO_PORT_0) + }; + //Make sure txd/rxd are enabled // use direct reg access instead of gpio_pullup_dis which can cause exception when flash cache is disabled REG_CLR_BIT(GPIO_PIN_REG_1, FUN_PU); -#if CONFIG_IDF_TARGET_ESP32P4 - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U_PAD_GPIO38, FUNC_GPIO38_UART0_RXD_PAD); - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U_PAD_GPIO37, FUNC_GPIO37_UART0_TXD_PAD); -#else - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD); - gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD); -#endif + gpio_hal_func_sel(&gpio_hal, U0RXD_GPIO_NUM, U0RXD_MUX_FUNC); + gpio_hal_func_sel(&gpio_hal, U0TXD_GPIO_NUM, U0TXD_MUX_FUNC); ESP_COREDUMP_LOGI("Press Enter to print core dump to UART..."); const int cpu_ticks_per_ms = esp_clk_cpu_freq() / 1000; tm_end = esp_cpu_get_cycle_count() / cpu_ticks_per_ms + CONFIG_ESP_COREDUMP_UART_DELAY; From a621402e1ffdb05f5347ca432410268378e9dbd1 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Fri, 10 May 2024 15:20:47 +0800 Subject: [PATCH 073/548] feat(pm): add SOC_PM_SUPPORTED in soc caps --- components/esp_pm/Kconfig | 3 +-- components/soc/esp32/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32/include/soc/soc_caps.h | 1 + components/soc/esp32c2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c2/include/soc/soc_caps.h | 1 + components/soc/esp32c3/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c3/include/soc/soc_caps.h | 1 + components/soc/esp32c5/beta3/include/soc/soc_caps.h | 1 + components/soc/esp32c5/mp/include/soc/soc_caps.h | 1 + components/soc/esp32c6/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c6/include/soc/soc_caps.h | 1 + components/soc/esp32c61/include/soc/soc_caps.h | 1 + components/soc/esp32h2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32h2/include/soc/soc_caps.h | 1 + components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + components/soc/esp32s2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32s2/include/soc/soc_caps.h | 1 + components/soc/esp32s3/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32s3/include/soc/soc_caps.h | 1 + 20 files changed, 44 insertions(+), 2 deletions(-) diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 718379486df..c458c2c3b8b 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -2,8 +2,7 @@ menu "Power Management" config PM_ENABLE bool "Support for power management" # SMP FreeRTOS currently does not support power management IDF-4997 - # Power Management is not supported on ESP32C5 MP IDF-8643 - depends on (!FREERTOS_SMP || __DOXYGEN__) && !IDF_TARGET_ESP32C5 + depends on (!FREERTOS_SMP && SOC_PM_SUPPORTED) || __DOXYGEN__ default n help If enabled, application is compiled with support for power management. diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 3723989bc71..a4c8168e8aa 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -187,6 +187,10 @@ config SOC_LP_PERIPH_SHARE_INTERRUPT bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL int default 5 diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index b1c18246f4e..97b1c6e9301 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -104,6 +104,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_LP_PERIPH_SHARE_INTERRUPT 1 // LP peripherals sharing the same interrupt source +#define SOC_PM_SUPPORTED 1 #if SOC_CAPS_ECO_VER < 200 #define SOC_DPORT_WORKAROUND 1 diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index 285d91d2922..c8fd88516dd 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -131,6 +131,10 @@ config SOC_LP_PERIPH_SHARE_INTERRUPT bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_26M bool default y diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 46e90f108b1..545f4e5cdbc 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -49,6 +49,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_LP_PERIPH_SHARE_INTERRUPT 1 // LP peripherals sharing the same interrupt source +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_26M 1 diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 80a7732c89b..a31c20b6418 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -183,6 +183,10 @@ config SOC_LP_PERIPH_SHARE_INTERRUPT bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index de6c54a6ba2..6a4c6548633 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -65,6 +65,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_LP_PERIPH_SHARE_INTERRUPT 1 // LP peripherals sharing the same interrupt source +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index 8862d8cee76..e14d4e9b05c 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -81,6 +81,7 @@ #define SOC_MODEM_CLOCK_SUPPORTED 1 // TODO: [ESP32C5] IDF-8845 need check, it is opened because pll has been used on beta3 #define SOC_BT_SUPPORTED 1 #define SOC_PHY_SUPPORTED 1 +// #define SOC_PM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8643 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index f20d1b4a315..cd358d4b902 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -72,6 +72,7 @@ // #define SOC_KEY_MANAGER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8621 // #define SOC_HUK_SUPPORTED 1 // TODO: [ESP32C5] IDF-8617 // #define SOC_MODEM_CLOCK_SUPPORTED 1 // TODO: [ESP32C5] IDF-8845 +// #define SOC_PM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8643 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 8b522a023ee..4f8185e74c3 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -239,6 +239,10 @@ config SOC_MODEM_CLOCK_SUPPORTED bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index d9fdc588ce0..efdd5bb6b0d 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -76,6 +76,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_MODEM_CLOCK_SUPPORTED 1 +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index f7462c9a6c6..9ed294cbea2 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -75,6 +75,7 @@ // #define SOC_PAU_SUPPORTED 0 // #define SOC_LP_I2C_SUPPORTED 0 //TODO: [ESP32C61] IDF-9330, IDF-9337 // #define SOC_ULP_LP_UART_SUPPORTED 0 //TODO: [ESP32C61] IDF-9329, IDF-9341 +// #define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 9606984626f..b129f22fa4c 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -227,6 +227,10 @@ config SOC_MODEM_CLOCK_SUPPORTED bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_32M bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 2181547f95b..763f154c3c2 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -73,6 +73,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_MODEM_CLOCK_SUPPORTED 1 +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_32M 1 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 3fb643d379f..5e3f06bcbe7 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -263,6 +263,10 @@ config SOC_DEEP_SLEEP_SUPPORTED bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index c2706a0ba1b..7e48a2b2ee0 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -92,6 +92,7 @@ // #define SOC_PPA_SUPPORTED 1 //TODO: IDF-6878 #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index dc17829d64d..790fc583032 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -211,6 +211,10 @@ config SOC_LP_PERIPH_SHARE_INTERRUPT bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index a3405cddbcf..154af5960e8 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -89,6 +89,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_LP_PERIPH_SHARE_INTERRUPT 1 // LP peripherals sharing the same interrupt source +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index c736f416198..cacd5d6b7f6 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -251,6 +251,10 @@ config SOC_LP_PERIPH_SHARE_INTERRUPT bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 536560d2d12..bd62a94337c 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -79,6 +79,7 @@ #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_LP_PERIPH_SHARE_INTERRUPT 1 // LP peripherals sharing the same interrupt source +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 From f27e117b5b8889b7f8c4388c909037471d7c87c7 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 16 May 2024 15:02:55 +0800 Subject: [PATCH 074/548] feat(gpio): update gpio docs on ESP32C5 MP version --- components/espcoredump/src/core_dump_uart.c | 2 +- .../beta3/include/soc/Kconfig.soc_caps.in | 4 ++ .../soc/esp32c5/beta3/include/soc/soc_caps.h | 2 +- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 2 +- docs/docs_not_updated/esp32c5.txt | 1 - docs/en/api-reference/peripherals/gpio.rst | 4 +- .../peripherals/gpio/esp32c5.inc | 40 +++++++++++-------- docs/zh_CN/api-reference/peripherals/gpio.rst | 4 +- .../peripherals/gpio/esp32c5.inc | 40 +++++++++++-------- 9 files changed, 61 insertions(+), 38 deletions(-) diff --git a/components/espcoredump/src/core_dump_uart.c b/components/espcoredump/src/core_dump_uart.c index 00414aaa7bf..69ab1c28054 100644 --- a/components/espcoredump/src/core_dump_uart.c +++ b/components/espcoredump/src/core_dump_uart.c @@ -154,7 +154,7 @@ static esp_err_t esp_core_dump_uart_hw_init(void) //Make sure txd/rxd are enabled // use direct reg access instead of gpio_pullup_dis which can cause exception when flash cache is disabled - REG_CLR_BIT(GPIO_PIN_REG_1, FUN_PU); + REG_CLR_BIT(GPIO_PIN_REG_1, FUN_PU); //TODO: IDF-9948 gpio_hal_func_sel(&gpio_hal, U0RXD_GPIO_NUM, U0RXD_MUX_FUNC); gpio_hal_func_sel(&gpio_hal, U0TXD_GPIO_NUM, U0TXD_MUX_FUNC); ESP_COREDUMP_LOGI("Press Enter to print core dump to UART..."); diff --git a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in index d4ab7aaa2ce..fec9d4ad5db 100644 --- a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in @@ -143,6 +143,10 @@ config SOC_BT_SUPPORTED bool default y +config SOC_PM_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index e14d4e9b05c..fa64ffd022f 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -81,7 +81,7 @@ #define SOC_MODEM_CLOCK_SUPPORTED 1 // TODO: [ESP32C5] IDF-8845 need check, it is opened because pll has been used on beta3 #define SOC_BT_SUPPORTED 1 #define SOC_PHY_SUPPORTED 1 -// #define SOC_PM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8643 +#define SOC_PM_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index c706f5da5d1..f7a76b644df 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -61,7 +61,7 @@ PROVIDE ( GPIO_EXT = 0x500E0F00 ); PROVIDE ( SDM = 0x500E0F00 ); PROVIDE ( GLITCH_FILTER = 0x500E0F30 ); PROVIDE ( GPIO_ETM = 0x500E0F60 ); -PROVIDE ( IOMUX = 0x500E1000 ); +PROVIDE ( IO_MUX = 0x500E1000 ); PROVIDE ( MSPI_IOMUX = 0x500E1200 ); PROVIDE ( HP_SYSTEM = 0x500E5000 ); diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 326cbc716c5..116da84970d 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -113,7 +113,6 @@ api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst api-reference/peripherals/usb_host/usb_host_notes_design.rst api-reference/peripherals/hmac.rst api-reference/peripherals/usb_device.rst -api-reference/peripherals/gpio.rst api-reference/peripherals/sdspi_host.rst api-reference/peripherals/spi_slave.rst api-reference/peripherals/etm.rst diff --git a/docs/en/api-reference/peripherals/gpio.rst b/docs/en/api-reference/peripherals/gpio.rst index 617d43fd1a1..3efd331f076 100644 --- a/docs/en/api-reference/peripherals/gpio.rst +++ b/docs/en/api-reference/peripherals/gpio.rst @@ -73,7 +73,9 @@ In addition, if you would like to dump the configurations of all IOs, you can us If an IO pin is routed to a peripheral signal through the GPIO matrix, the signal ID printed in the dump information is defined in the :component_file:`soc/{IDF_TARGET_PATH_NAME}/include/soc/gpio_sig_map.h` header file. The word ``**RESERVED**`` indicates the IO is occupied by either SPI flash or PSRAM. It is strongly not recommended to reconfigure them for other application purposes. -.. only:: esp32c3 or esp32c6 or esp32h2 or esp32p4 or esp32s2 or esp32s3 +Do not rely on the default configurations values in the Technical Reference Manual, because it may be changed in the bootloader or application startup code before app_main. + +.. only:: esp32c3 or esp32c6 or esp32h2 or esp32p4 or esp32s2 or esp32s3 or esp32c5 Configure USB PHY Pins to GPIO ------------------------------- diff --git a/docs/en/api-reference/peripherals/gpio/esp32c5.inc b/docs/en/api-reference/peripherals/gpio/esp32c5.inc index 9a16e59dae6..e62afa2ffd3 100644 --- a/docs/en/api-reference/peripherals/gpio/esp32c5.inc +++ b/docs/en/api-reference/peripherals/gpio/esp32c5.inc @@ -9,9 +9,7 @@ .. gpio-summary -Current GPIOs are for {IDF_TARGET_NAME} beta3 version. {IDF_TARGET_NAME} MP version would have 2 more available IOs, and some pin functions are changed. The {IDF_TARGET_NAME} MP version will be updated later. - -The {IDF_TARGET_NAME} chip features 27 physical GPIO pins (GPIO0 ~ GPIO26). Each pin can be used as a general-purpose I/O, or to be connected to an internal peripheral signal. Through GPIO matrix and IO MUX, peripheral input signals can be from any IO pins, and peripheral output signals can be routed to any IO pins. Together these modules provide highly configurable I/O. For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__]. +The {IDF_TARGET_NAME} chip features 29 physical GPIO pins (GPIO0 ~ GPIO28). Each pin can be used as a general-purpose I/O, or to be connected to an internal peripheral signal. Through GPIO matrix and IO MUX, peripheral input signals can be from any IO pins, and peripheral output signals can be routed to any IO pins. Together these modules provide highly configurable I/O. For more details, see *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__]. The table below provides more information on pin usage, and please note the comments in the table for GPIOs with restrictions. @@ -42,7 +40,7 @@ The table below provides more information on pin usage, and please note the comm * - GPIO3 - ADC1_CH2 - LP_GPIO3 - - Strapping pin + - * - GPIO4 - ADC1_CH3 @@ -57,7 +55,7 @@ The table below provides more information on pin usage, and please note the comm * - GPIO6 - ADC1_CH5 - LP_GPIO6 - - Strapping pin + - * - GPIO7 - @@ -92,12 +90,12 @@ The table below provides more information on pin usage, and please note the comm * - GPIO13 - - - - + - USB-JTAG * - GPIO14 - - - - + - USB-JTAG * - GPIO15 - @@ -107,12 +105,12 @@ The table below provides more information on pin usage, and please note the comm * - GPIO16 - - - - + - SPI0/1 * - GPIO17 - - - - + - SPI0/1 * - GPIO18 - @@ -142,27 +140,37 @@ The table below provides more information on pin usage, and please note the comm * - GPIO23 - - - - SPI0/1 + - * - GPIO24 - - - - SPI0/1 + - * - GPIO25 - - - - USB-JTAG + - * - GPIO26 - - - - USB-JTAG + - + + * - GPIO27 + - + - + - Strapping pin + + * - GPIO28 + - + - + - Strapping pin .. note:: - - Strapping pin: GPIO2, GPIO3, GPIO6, and GPIO7 are strapping pins. For more information, please refer to `datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__. - - SPI0/1: GPIO18 ~ GPIO24 are usually used for SPI flash and not recommended for other uses. - - USB-JTAG: GPIO25 and GPIO26 are used by USB-JTAG by default. If they are reconfigured to operate as normal GPIOs, USB-JTAG functionality will be disabled. + - Strapping pin: GPIO2, GPIO7, GPIO27, and GPIO28 are strapping pins. For more information, please refer to `datasheet <{IDF_TARGET_DATASHEET_EN_URL}>`__. + - SPI0/1: GPIO16 ~ GPIO22 are usually used for SPI flash and not recommended for other uses. + - USB-JTAG: GPIO13 and GPIO14 are used by USB-JTAG by default. If they are reconfigured to operate as normal GPIOs, USB-JTAG functionality will be disabled. --- diff --git a/docs/zh_CN/api-reference/peripherals/gpio.rst b/docs/zh_CN/api-reference/peripherals/gpio.rst index e071fc93195..99d6fcac03e 100644 --- a/docs/zh_CN/api-reference/peripherals/gpio.rst +++ b/docs/zh_CN/api-reference/peripherals/gpio.rst @@ -73,7 +73,9 @@ GPIO 驱动提供了一个函数 :cpp:func:`gpio_dump_io_configuration` 用来 如果 IO 管脚通过 GPIO 交换矩阵连接到内部外设信号,输出信息打印中的外设信号 ID 定义可以在 :component_file:`soc/{IDF_TARGET_PATH_NAME}/include/soc/gpio_sig_map.h` 头文件中查看。``**RESERVED**`` 字样则表示此 IO 用于连接 SPI flash 或 PSRAM,强烈建议不要重新配置这些管脚用于其他功能。 -.. only:: esp32c3 or esp32c6 or esp32h2 or esp32p4 or esp32s2 or esp32s3 +请不要依赖技术参考手册中记录的 GPIO 默认配置状态,因为特殊用途的 GPIO 可能会在 app_main 之前被引导程序或应用程序启动阶段的代码更改。 + +.. only:: esp32c3 or esp32c6 or esp32h2 or esp32p4 or esp32s2 or esp32s3 or esp32c5 配置 USB PHY 管脚 为普通 GPIO 管脚 --------------------------------------- diff --git a/docs/zh_CN/api-reference/peripherals/gpio/esp32c5.inc b/docs/zh_CN/api-reference/peripherals/gpio/esp32c5.inc index 78f87a207f4..a3b31437188 100644 --- a/docs/zh_CN/api-reference/peripherals/gpio/esp32c5.inc +++ b/docs/zh_CN/api-reference/peripherals/gpio/esp32c5.inc @@ -9,9 +9,7 @@ .. gpio-summary -当前的 GPIO 适用于 {IDF_TARGET_NAME} beta3 版本。{IDF_TARGET_NAME} MP 版本将会增加 2 个可用的 IO,并且一些引脚功能将会改变。{IDF_TARGET_NAME} MP 版本将会在以后更新。 - -{IDF_TARGET_NAME} 芯片具有 27 个物理 GPIO 管脚(GPIO0 ~ GPIO26)。每个管脚都可用作一个通用 IO,或连接一个内部的外设信号。通过 GPIO 交换矩阵和 IO MUX,可配置外设模块的输入信号来源于任何的 IO 管脚,并且外设模块的输出信号也可连接到任意 IO 管脚。这些模块共同组成了芯片的 IO 控制。更多详细信息,请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *IO MUX 和 GPIO 矩阵(GPIO、IO_MUX)* [`PDF <{IDF_TARGET_TRM_CN_URL}#iomuxgpio>`__]。 +{IDF_TARGET_NAME} 芯片具有 29 个物理 GPIO 管脚(GPIO0 ~ GPIO28)。每个管脚都可用作一个通用 IO,或连接一个内部的外设信号。通过 GPIO 交换矩阵和 IO MUX,可配置外设模块的输入信号来源于任何的 IO 管脚,并且外设模块的输出信号也可连接到任意 IO 管脚。这些模块共同组成了芯片的 IO 控制。更多详细信息,请参阅 *{IDF_TARGET_NAME} 技术参考手册* > *IO MUX 和 GPIO 矩阵(GPIO、IO_MUX)* [`PDF <{IDF_TARGET_TRM_CN_URL}#iomuxgpio>`__]。 下表提供了各管脚的详细信息,部分 GPIO 具有特殊的使用限制,具体可参考表中的注释列。 @@ -42,7 +40,7 @@ * - GPIO3 - ADC1_CH2 - LP_GPIO3 - - Strapping 管脚 + - * - GPIO4 - ADC1_CH3 @@ -57,7 +55,7 @@ * - GPIO6 - ADC1_CH5 - LP_GPIO6 - - Strapping 管脚 + - * - GPIO7 - @@ -92,12 +90,12 @@ * - GPIO13 - - - - + - USB-JTAG * - GPIO14 - - - - + - USB-JTAG * - GPIO15 - @@ -107,12 +105,12 @@ * - GPIO16 - - - - + - SPI0/1 * - GPIO17 - - - - + - SPI0/1 * - GPIO18 - @@ -142,27 +140,37 @@ * - GPIO23 - - - - SPI0/1 + - * - GPIO24 - - - - SPI0/1 + - * - GPIO25 - - - - USB-JTAG + - * - GPIO26 - - - - USB-JTAG + - + + * - GPIO27 + - + - + - Strapping 管脚 + + * - GPIO28 + - + - + - Strapping 管脚 .. note:: - - Strapping 管脚:GPIO2、GPIO3、GPIO6 和 GPIO7 是 Strapping 管脚。更多信息请参考 `ESP32-C5 技术规格书 <{IDF_TARGET_DATASHEET_CN_URL}>`_。 - - SPI0/1:GPIO18 ~ GPIO24 通常用于 SPI flash,不推荐用于其他用途。 - - USB-JTAG:GPIO25 和 GPIO26 默认用于 USB-JTAG。如果将它们配置为普通 GPIO,驱动程序将禁用 USB-JTAG 功能。 + - Strapping 管脚:GPIO2、GPIO7、GPIO27 和 GPIO28 是 Strapping 管脚。更多信息请参考 `ESP32-C5 技术规格书 <{IDF_TARGET_DATASHEET_CN_URL}>`_。 + - SPI0/1:GPIO16 ~ GPIO22 通常用于 SPI flash,不推荐用于其他用途。 + - USB-JTAG:GPIO13 和 GPIO14 默认用于 USB-JTAG。如果将它们配置为普通 GPIO,驱动程序将禁用 USB-JTAG 功能。 --- From 7403b8d68d1df4e6e872137bd2678af1e8b28a5c Mon Sep 17 00:00:00 2001 From: gaoxu Date: Fri, 26 Apr 2024 10:57:51 +0800 Subject: [PATCH 075/548] feat(rom): update c5 mp verison rom ld file --- .../esp32c5/mp/esp32c5/ld/esp32c5.rom.heap.ld | 1 + .../esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- .../esp32c5/mp/esp32c5/ld/esp32c5.rom.rvfp.ld | 133 +++++++++++++----- 3 files changed, 100 insertions(+), 36 deletions(-) diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.heap.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.heap.ld index 2a100bd3630..90acc2b6ce0 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.heap.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.heap.ld @@ -76,5 +76,6 @@ PROVIDE (multi_heap_aligned_alloc = multi_heap_aligned_alloc_impl); PROVIDE (multi_heap_aligned_free = multi_heap_aligned_free_impl); PROVIDE (multi_heap_check = multi_heap_check); PROVIDE (multi_heap_set_lock = multi_heap_set_lock); +PROVIDE (multi_heap_os_funcs_init = multi_heap_mutex_init); PROVIDE (multi_heap_internal_lock = multi_heap_internal_lock); PROVIDE (multi_heap_internal_unlock = multi_heap_internal_unlock); diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld index 1a8175af900..8b1bbe312db 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld @@ -62,7 +62,7 @@ ic_get_he_rts_threshold_bytes = 0x40000c88; lmacAdjustTimestamp = 0x40000c8c; lmacDiscardAgedMSDU = 0x40000c90; lmacDiscardMSDU = 0x40000c94; -/*lmacEndFrameExchangeSequence = 0x40000c98;*/ +lmacEndFrameExchangeSequence = 0x40000c98; lmacIsIdle = 0x40000c9c; lmacIsLongFrame = 0x40000ca0; lmacMSDUAged = 0x40000ca4; diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.rvfp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.rvfp.ld index 53fe001c90c..b6853454f5a 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.rvfp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.rvfp.ld @@ -18,23 +18,23 @@ ***************************************/ /* Functions */ -_rvfp__addsf3 = 0x40000a2c; -_rvfp__eqsf2 = 0x40000a30; -_rvfp__extendsfdf2 = 0x40000a34; -_rvfp__fixsfsi = 0x40000a38; -_rvfp__fixunssfsi = 0x40000a3c; -_rvfp__floatdisf = 0x40000a40; -_rvfp__floatsisf = 0x40000a44; -_rvfp__floatundisf = 0x40000a48; -_rvfp__floatunsisf = 0x40000a4c; -_rvfp__gesf2 = 0x40000a50; -_rvfp__gtsf2 = 0x40000a54; -_rvfp__lesf2 = 0x40000a58; -_rvfp__ltsf2 = 0x40000a5c; -_rvfp__mulsf3 = 0x40000a60; -_rvfp__nesf2 = 0x40000a64; -_rvfp__subsf3 = 0x40000a68; -_rvfp__truncdfsf2 = 0x40000a6c; +__addsf3 = 0x40000a2c; +__eqsf2 = 0x40000a30; +__extendsfdf2 = 0x40000a34; +__fixsfsi = 0x40000a38; +__fixunssfsi = 0x40000a3c; +__floatdisf = 0x40000a40; +__floatsisf = 0x40000a44; +__floatundisf = 0x40000a48; +__floatunsisf = 0x40000a4c; +__gesf2 = 0x40000a50; +__gtsf2 = 0x40000a54; +__lesf2 = 0x40000a58; +__ltsf2 = 0x40000a5c; +__mulsf3 = 0x40000a60; +__nesf2 = 0x40000a64; +__subsf3 = 0x40000a68; +__truncdfsf2 = 0x40000a6c; /*************************************** @@ -42,21 +42,84 @@ _rvfp__truncdfsf2 = 0x40000a6c; ***************************************/ /* Functions */ -_rvfp__adddf3 = 0x40000a70; -_rvfp__eqdf2 = 0x40000a74; -_rvfp__fixdfdi = 0x40000a78; -_rvfp__fixdfsi = 0x40000a7c; -_rvfp__fixsfdi = 0x40000a80; -_rvfp__fixunsdfsi = 0x40000a84; -_rvfp__fixunssfdi = 0x40000a88; -_rvfp__floatdidf = 0x40000a8c; -_rvfp__floatsidf = 0x40000a90; -_rvfp__floatundidf = 0x40000a94; -_rvfp__floatunsidf = 0x40000a98; -_rvfp__gedf2 = 0x40000a9c; -_rvfp__gtdf2 = 0x40000aa0; -_rvfp__ledf2 = 0x40000aa4; -_rvfp__ltdf2 = 0x40000aa8; -_rvfp__muldf3 = 0x40000aac; -_rvfp__nedf2 = 0x40000ab0; -_rvfp__subdf3 = 0x40000ab4; +__adddf3 = 0x40000a70; +__eqdf2 = 0x40000a74; +__fixdfdi = 0x40000a78; +__fixdfsi = 0x40000a7c; +__fixsfdi = 0x40000a80; +__fixunsdfsi = 0x40000a84; +__fixunssfdi = 0x40000a88; +__floatdidf = 0x40000a8c; +__floatsidf = 0x40000a90; +__floatundidf = 0x40000a94; +__floatunsidf = 0x40000a98; +__gedf2 = 0x40000a9c; +__gtdf2 = 0x40000aa0; +__ledf2 = 0x40000aa4; +__ltdf2 = 0x40000aa8; +__muldf3 = 0x40000aac; +__nedf2 = 0x40000ab0; +__subdf3 = 0x40000ab4; + +/*************************************** + Group libgcc +***************************************/ + +/* Functions */ +__divsf3 = 0x400008c0; +__negsf2 = 0x400008e8; +__powisf2 = 0x400008f0; +__unordsf2 = 0x400008fc; +__absvdi2 = 0x40000900; +__absvsi2 = 0x40000904; +__addvdi3 = 0x4000090c; +__addvsi3 = 0x40000910; +__ashldi3 = 0x40000914; +__ashrdi3 = 0x40000918; +__bswapdi2 = 0x4000091c; +__bswapsi2 = 0x40000920; +__clear_cache = 0x40000924; +__clrsbdi2 = 0x40000928; +__clrsbsi2 = 0x4000092c; +__clzdi2 = 0x40000930; +__clzsi2 = 0x40000934; +__cmpdi2 = 0x40000938; +__ctzdi2 = 0x4000093c; +__ctzsi2 = 0x40000940; +__divdc3 = 0x40000944; +__divdf3 = 0x40000948; +__divdi3 = 0x4000094c; +__divsc3 = 0x40000950; +__divsi3 = 0x40000954; +__ffsdi2 = 0x40000960; +__ffssi2 = 0x40000964; +__gcc_bcmp = 0x40000998; +__lshrdi3 = 0x400009a8; +__moddi3 = 0x400009b0; +__modsi3 = 0x400009b4; +__muldc3 = 0x400009b8; +__muldi3 = 0x400009c0; +__mulsc3 = 0x400009c4; +__mulsi3 = 0x400009c8; +__mulvdi3 = 0x400009cc; +__mulvsi3 = 0x400009d0; +__negdf2 = 0x400009d8; +__negdi2 = 0x400009dc; +__negvdi2 = 0x400009e0; +__negvsi2 = 0x400009e4; +__paritysi2 = 0x400009e8; +__popcountdi2 = 0x400009ec; +__popcountsi2 = 0x400009f0; +__powidf2 = 0x400009f4; +__subvdi3 = 0x400009fc; +__subvsi3 = 0x40000a00; +__ucmpdi2 = 0x40000a04; +__udivdi3 = 0x40000a08; +__udivmoddi4 = 0x40000a0c; +__udivsi3 = 0x40000a10; +__udiv_w_sdiv = 0x40000a14; +__umoddi3 = 0x40000a18; +__umodsi3 = 0x40000a1c; +__unorddf2 = 0x40000a20; +__extenddftf2 = 0x40000a24; +__trunctfdf2 = 0x40000a28; From 352ee6fc260bdf3e21b53e89b67216a3fde71b08 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 16 May 2024 17:28:58 +0800 Subject: [PATCH 076/548] ble: fixed some issues on ESP32C6 and ESP32H2 --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index 0af472c6f95..66633625971 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit 0af472c6f95858e638565dad19a79fe47de1fff2 +Subproject commit 6663362597110007a901eed9c87fa1cff6ac25fe diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 70612d08d1f..9bf31906cdb 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 70612d08d1ff94dfb5da99d6a68aa4032cd63276 +Subproject commit 9bf31906cdbef6ac3d271117f1cd439bd411eef5 From bd8d7ea76a3e05feb62445fee881b9ff25efdc61 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Wed, 24 Apr 2024 06:04:55 +0300 Subject: [PATCH 077/548] fix(coredump): increase sanity check before get summary Closes https://github.com/espressif/esp-idf/issues/13594 --- components/espcoredump/src/core_dump_elf.c | 36 ++++++-------------- components/espcoredump/src/core_dump_flash.c | 6 ++-- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index f83b49f16e3..97779136edb 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -762,39 +762,23 @@ typedef struct { void *n_ptr; } elf_note_content_t; +esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size); + /* Below are the helper function to parse the core dump ELF stored in flash */ static esp_err_t elf_core_dump_image_mmap(esp_partition_mmap_handle_t* core_data_handle, const void **map_addr) { - size_t out_size; + const esp_partition_t *core_part = NULL; + uint32_t out_size; assert(core_data_handle); assert(map_addr); - /* Find the partition that could potentially contain a (previous) core dump. */ - const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, - ESP_PARTITION_SUBTYPE_DATA_COREDUMP, - NULL); - if (!core_part) { - ESP_COREDUMP_LOGE("Core dump partition not found!"); - return ESP_ERR_NOT_FOUND; - } - if (core_part->size < sizeof(uint32_t)) { - ESP_COREDUMP_LOGE("Core dump partition too small!"); - return ESP_ERR_INVALID_SIZE; - } - /* Data read from the mmapped core dump partition will be garbage if flash - * encryption is enabled in hardware and core dump partition is not encrypted - */ - if (esp_flash_encryption_enabled() && !core_part->encrypted) { - ESP_COREDUMP_LOGE("Flash encryption enabled in hardware and core dump partition is not encrypted!"); - return ESP_ERR_NOT_SUPPORTED; - } - /* Read the size of the core dump file from the partition */ - esp_err_t ret = esp_partition_read(core_part, 0, &out_size, sizeof(uint32_t)); - if (ret != ESP_OK) { - ESP_COREDUMP_LOGE("Failed to read core dump data size"); - return ret; + /* Retrieve the partition and size. */ + esp_err_t err = esp_core_dump_partition_and_size_get(&core_part, &out_size); + if (err != ESP_OK) { + return err; } - /* map the full core dump parition, including the checksum. */ + + /* map the full core dump partition, including the checksum. */ return esp_partition_mmap(core_part, 0, out_size, ESP_PARTITION_MMAP_DATA, map_addr, core_data_handle); } diff --git a/components/espcoredump/src/core_dump_flash.c b/components/espcoredump/src/core_dump_flash.c index 7cd6382fd98..2790a8b1494 100644 --- a/components/espcoredump/src/core_dump_flash.c +++ b/components/espcoredump/src/core_dump_flash.c @@ -55,7 +55,7 @@ esp_err_t esp_core_dump_write_data(core_dump_write_data_t *wr_data, void *data, #define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_) esp_err_t esp_core_dump_image_check(void); -static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size); +esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size); static void esp_core_dump_flash_print_write_start(void) { @@ -258,7 +258,7 @@ static esp_err_t esp_core_dump_flash_write_prepare(core_dump_write_data_t *wr_da padding = COREDUMP_CACHE_SIZE - modulo; } - /* Now we can check whether we have enough space in our core dump parition + /* Now we can check whether we have enough space in our core dump partition * or not. */ if ((*data_len + padding + cs_len) > s_core_flash_config.partition.size) { ESP_COREDUMP_LOGE("Not enough space to save core dump!"); @@ -488,7 +488,7 @@ esp_err_t esp_core_dump_image_erase(void) return err; } -static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size) +esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size) { uint32_t core_size = 0; const esp_partition_t *core_part = NULL; From 5e817df25fd8421d9b610b8a0cb6c58688a38d74 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 6 May 2024 15:39:02 +0200 Subject: [PATCH 078/548] fix(coredump): don't allow mapping of non-encrypted coredump partition --- components/espcoredump/src/core_dump_elf.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 97779136edb..74a1ac5a8d2 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -778,6 +778,14 @@ static esp_err_t elf_core_dump_image_mmap(esp_partition_mmap_handle_t* core_data return err; } + /* Data read from the mmapped core dump partition will be garbage if flash + * encryption is enabled in hardware and core dump partition is not encrypted + */ + if (esp_flash_encryption_enabled() && !core_part->encrypted) { + ESP_COREDUMP_LOGE("Flash encryption enabled in hardware and core dump partition is not encrypted!"); + return ESP_ERR_NOT_SUPPORTED; + } + /* map the full core dump partition, including the checksum. */ return esp_partition_mmap(core_part, 0, out_size, ESP_PARTITION_MMAP_DATA, map_addr, core_data_handle); From a9383cb4330467b5896d4dd5c2658b31e3435cdb Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 22 Apr 2024 17:20:53 +0800 Subject: [PATCH 079/548] example(camera): added new camera dsi example --- examples/peripherals/.build-test-rules.yml | 7 + .../camera/camera_dsi/CMakeLists.txt | 6 + .../peripherals/camera/camera_dsi/README.md | 139 +++++++++++ .../camera/camera_dsi/main/CMakeLists.txt | 4 + .../camera/camera_dsi/main/Kconfig.projbuild | 25 ++ .../camera/camera_dsi/main/camera_dsi_main.c | 221 ++++++++++++++++++ .../camera/camera_dsi/main/example_config.h | 36 +++ .../camera/camera_dsi/main/example_dsi_init.c | 79 +++++++ .../camera/camera_dsi/main/example_dsi_init.h | 38 +++ .../camera/camera_dsi/main/idf_component.yml | 5 + .../camera/camera_dsi/pytest_camera_dsi.py | 10 + .../camera/camera_dsi/sdkconfig.defaults | 4 + .../isp_af_schemes/src/isp_af_scheme_sa.c | 2 +- 13 files changed, 575 insertions(+), 1 deletion(-) create mode 100644 examples/peripherals/camera/camera_dsi/CMakeLists.txt create mode 100644 examples/peripherals/camera/camera_dsi/README.md create mode 100644 examples/peripherals/camera/camera_dsi/main/CMakeLists.txt create mode 100644 examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild create mode 100644 examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c create mode 100644 examples/peripherals/camera/camera_dsi/main/example_config.h create mode 100644 examples/peripherals/camera/camera_dsi/main/example_dsi_init.c create mode 100644 examples/peripherals/camera/camera_dsi/main/example_dsi_init.h create mode 100644 examples/peripherals/camera/camera_dsi/main/idf_component.yml create mode 100644 examples/peripherals/camera/camera_dsi/pytest_camera_dsi.py create mode 100644 examples/peripherals/camera/camera_dsi/sdkconfig.defaults diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 174a6caafd4..d5df6075196 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -24,6 +24,13 @@ examples/peripherals/analog_comparator: - esp_driver_gpio - esp_driver_ana_cmpr +examples/peripherals/camera/camera_dsi: + disable: + - if: SOC_MIPI_CSI_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 + depends_components: + - esp_lcd + - esp_driver_cam + examples/peripherals/dac: disable: - if: SOC_DAC_SUPPORTED != 1 diff --git a/examples/peripherals/camera/camera_dsi/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/CMakeLists.txt new file mode 100644 index 00000000000..69a158b554a --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(camera_dsi) diff --git a/examples/peripherals/camera/camera_dsi/README.md b/examples/peripherals/camera/camera_dsi/README.md new file mode 100644 index 00000000000..76081356bdd --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/README.md @@ -0,0 +1,139 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + + +# Camera display via DSI example + +## Overview + +This example demonstrates how to use the esp_driver_cam component to capture camera sensor signals and display it via DSI interface. + +## Usage + +The subsections below give only absolutely necessary information. For full steps to configure ESP-IDF and use it to build and run projects, see [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started). + + +### Hardware Required + +This example requires: + +- OV5647 camera sensor with VCM (Voice Coil Motor). The VCM used in this example is DW9714. +- ILI9881C LCD screen +- ESP32P4 devkit + + + GND GND + ┌────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ ┌───────────────┴─────────────┴──────────────────┐ │ + │ │ │ ┌──────────┴───────────┐ + │ │ │ DSI DATA 1P │ │ + │ │ ├───────────────────────────┤ │ + ┌───────────┴─────────┐ CSI DATA 1P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 1N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 1N │ ESP32-P4 │ │ │ + │ OV5647 ├──────────────────────┤ │ DSI CLK N │ ILI9881C │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI CLK N │ │ │ │ + │ ├──────────────────────┤ │ DSI CLK P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI CLK P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 0P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 0N │ │ │ │ + │ ├──────────────────────┤ │ └──────────────────────┘ + │ │ │ │ + └───────┬──┬──────────┘ │ │ + │ │ I2C SCL │ │ + │ └─────────────────────────────────┤ │ + │ I2C SDA │ │ + └────────────────────────────────────┤ │ + └────────────────────────────────────────────────┘ + + +### Set Chip Target + +First of all, your target must be supported by both: + +- **By your ESP-IDF version**: For the full list of supported targets, run: + ``` + idf.py --list-targets + ``` +- **By this example**: For the full list of supported targets, refer to the supported targets table at the top of this README. + +After you make sure that your target is supported, go to your example project directory and [set the chip target](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-py.html#select-the-target-chip-set-target): + +``` +idf.py set-target +``` + +For example, to set esp32-P4 as the chip target, run: + +``` +idf.py set-target esp32p4 +``` + + +### Configure the Project + +For information about Kconfig options, see [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) > _Name of relevant section(s)_. + +To conveniently check or modify Kconfig options for this example in a project configuration menu, run: + +``` +idf.py menuconfig +``` + +``` +Set CONFIG_CAMERA_OV5647 to y +``` + + +### Build and Flash + +Execute the following command to build the project, flash it to your development board, and run the monitor tool to view the serial output: + +``` +idf.py build flash monitor +``` + +This command can be reduced to `idf.py flash monitor`. + +If the above command fails, check the log on the serial monitor which usually provides information on the possible cause of the issue. + +To exit the serial monitor, use `Ctrl` + `]`. + + +## Example Output + +If you see the following console output, your example should be running correctly: + +``` +I (1085) main_task: Calling app_main() +I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c +I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0 +I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps +I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps +I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps +I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps +``` + + +## Reference + +- Link to the ESP-IDF feature's API reference, for example [ESP-IDF: Camera Controller Driver](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/camera_driver.html) +- [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started) +- [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) (Kconfig Options) diff --git a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt new file mode 100644 index 00000000000..92fcf227473 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "camera_dsi_main.c" "example_dsi_init.c" + INCLUDE_DIRS "." + REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd + ) diff --git a/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild b/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild new file mode 100644 index 00000000000..fdc04994528 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild @@ -0,0 +1,25 @@ +menu "Example Configuration" + config EXAMPLE_USED_LDO_CHAN_ID + int "example used LDO channel ID" + default 3 + help + Example used LDO channel ID, you may check datasheet to know more details. + + config EXAMPLE_USED_LDO_VOLTAGE_MV + int "example used LDO voltage in mV" + default 2500 + range 0 3300 + help + Example used LDO voltage, in mV + + choice EXAMPLE_MIPI_CSI_VRES + bool "Set MIPI CSI verticol resolution" + default EXAMPLE_MIPI_CSI_VRES_640 + + config EXAMPLE_MIPI_CSI_VRES_640 + bool "640" + config EXAMPLE_MIPI_CSI_VRES_1280 + bool "1280" + endchoice + +endmenu diff --git a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c new file mode 100644 index 00000000000..dc9b3e8de25 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c @@ -0,0 +1,221 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "esp_attr.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_ili9881c.h" +#include "esp_ldo_regulator.h" +#include "esp_cache.h" +#include "driver/i2c_master.h" +#include "driver/isp.h" +#include "esp_cam_ctlr_csi.h" +#include "esp_cam_ctlr.h" +#include "esp_sccb_intf.h" +#include "esp_sccb_i2c.h" +#include "esp_cam_sensor.h" +#include "ov5647.h" +#include "example_dsi_init.h" +#include "example_config.h" + +static const char *TAG = "cam_dsi"; + +static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); +static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); + +void app_main(void) +{ + esp_err_t ret = ESP_FAIL; + esp_lcd_panel_handle_t ili9881c_ctrl_panel = NULL; + esp_lcd_panel_handle_t mipi_dpi_panel = NULL; + void *frame_buffer = NULL; + size_t frame_buffer_size = 0; + + //mipi ldo + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = CONFIG_EXAMPLE_USED_LDO_CHAN_ID, + .voltage_mv = CONFIG_EXAMPLE_USED_LDO_VOLTAGE_MV, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + /** + * @background + * Sensor use RAW8 + * ISP convert to RGB565 + */ + //---------------DSI Init------------------// + example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); + + //---------------Necessary variable config------------------// + frame_buffer_size = EXAMPLE_MIPI_CSI_DISP_HSIZE * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + + ESP_LOGD(TAG, "EXAMPLE_MIPI_CSI_DISP_HSIZE: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", EXAMPLE_MIPI_CSI_DISP_HSIZE, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); + ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); + ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); + + esp_cam_ctlr_trans_t new_trans = { + .buffer = frame_buffer, + .buflen = frame_buffer_size, + }; + + //---------------I2C Init------------------// + i2c_master_bus_config_t i2c_bus_conf = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .sda_io_num = EXAMPLE_MIPI_SCCB_SDA_IO, + .scl_io_num = EXAMPLE_MIPI_SCCB_SCL_IO, + .i2c_port = I2C_NUM_0, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle = NULL; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_conf, &bus_handle)); + + //---------------SCCB Init------------------// + esp_sccb_io_handle_t ov5647_io_handle = NULL; + sccb_i2c_config_t i2c_config = { + .scl_speed_hz = EXAMPLE_MIPI_SCCB_FREQ, + .device_address = EXAMPLE_OV5647_DEV_ADDR, + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + }; + ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &ov5647_io_handle)); + + //---------------CSI Init------------------// + esp_cam_ctlr_csi_config_t csi_config = { + .ctlr_id = 0, + .h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, +#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 + .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P, +#else + .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P, +#endif + .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, + .input_data_color_type = MIPI_CSI_COLOR_RAW8, + .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .data_lane_num = 2, + .byte_swap_en = false, + .queue_items = 1, + }; + esp_cam_ctlr_handle_t cam_handle = NULL; + ret = esp_cam_new_csi_ctlr(&csi_config, &cam_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "csi init fail[%d]", ret); + return; + } + + esp_cam_ctlr_evt_cbs_t cbs = { + .on_get_new_trans = s_camera_get_new_vb, + .on_trans_finished = s_camera_get_finished_trans, + }; + if (esp_cam_ctlr_register_event_callbacks(cam_handle, &cbs, &new_trans) != ESP_OK) { + ESP_LOGE(TAG, "ops register fail"); + return; + } + + ESP_ERROR_CHECK(esp_cam_ctlr_enable(cam_handle)); + + //---------------ISP Init------------------// + isp_proc_handle_t isp_proc = NULL; + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 80 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_CSI, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + .has_line_start_packet = false, + .has_line_end_packet = false, + .h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, +#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 + .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P, +#else + .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P, +#endif + }; + ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); + ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); + + //---------------DSI Panel Init------------------// + example_dsi_ili9881c_panel_init(ili9881c_ctrl_panel); + + //init to all white + memset(frame_buffer, 0xFF, frame_buffer_size); + esp_cache_msync((void *)frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + if (esp_cam_ctlr_start(cam_handle) != ESP_OK) { + ESP_LOGE(TAG, "Driver start fail"); + return; + } + + esp_cam_sensor_config_t cam_config = { + .sccb_handle = ov5647_io_handle, + .reset_pin = -1, + .pwdn_pin = -1, + .xclk_pin = -1, + .sensor_port = ESP_CAM_SENSOR_MIPI_CSI, + }; + + esp_cam_sensor_device_t *cam = ov5647_detect(&cam_config); + if (!cam) { + ESP_LOGE(TAG, "failed to detect 5647"); + return; + } + + esp_cam_sensor_format_array_t cam_fmt_array = {0}; + esp_cam_sensor_query_format(cam, &cam_fmt_array); + const esp_cam_sensor_format_t *parray = cam_fmt_array.format_array; + for (int i = 0; i < cam_fmt_array.count; i++) { + ESP_LOGI(TAG, "fmt[%d].name:%s", i, parray[i].name); + } + + esp_cam_sensor_format_t *cam_cur_fmt = NULL; + for (int i = 0; i < cam_fmt_array.count; i++) { + +#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 + if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) { + cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); + } +#else + if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x1280_50fps")) { + cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); + } +#endif + } + + ret = esp_cam_sensor_set_format(cam, (const esp_cam_sensor_format_t *) cam_cur_fmt); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Format set fail"); + } else { + ESP_LOGI(TAG, "Format in use:%s", cam_cur_fmt->name); + } + int enable_flag = 1; + // Set sensor output stream + ret = esp_cam_sensor_ioctl(cam, ESP_CAM_SENSOR_IOC_S_STREAM, &enable_flag); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Start stream fail"); + } + + example_dpi_panel_init(mipi_dpi_panel); + + while (1) { + ESP_ERROR_CHECK(esp_cam_ctlr_receive(cam_handle, &new_trans, ESP_CAM_CTLR_MAX_DELAY)); + } +} + +static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + esp_cam_ctlr_trans_t new_trans = *(esp_cam_ctlr_trans_t *)user_data; + trans->buffer = new_trans.buffer; + trans->buflen = new_trans.buflen; + + return false; +} + +static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + return false; +} diff --git a/examples/peripherals/camera/camera_dsi/main/example_config.h b/examples/peripherals/camera/camera_dsi/main/example_config.h new file mode 100644 index 00000000000..fe6bbac88a8 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/example_config.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_MIPI_SCCB_FREQ (100000) +#define EXAMPLE_MIPI_SCCB_SCL_IO (34) +#define EXAMPLE_MIPI_SCCB_SDA_IO (31) +#define EXAMPLE_MIPI_CSI_DISP_HSIZE 800 +#define EXAMPLE_MIPI_CSI_DISP_VSIZE_640P 640 +#define EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P 1280 +#define EXAMPLE_MIPI_CSI_640P 1 +#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000) +#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 + +#define EXAMPLE_MIPI_DSI_IMAGE_HSIZE 800 +#define EXAMPLE_MIPI_DSI_IMAGE_VSIZE 1280 +#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 +#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 +#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40 +#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4 +#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 +#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 + +#define EXAMPLE_OV5647_DEV_ADDR 0x36 +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.c b/examples/peripherals/camera/camera_dsi/main/example_dsi_init.c new file mode 100644 index 00000000000..5291024f331 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/example_dsi_init.c @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_ili9881c.h" +#include "esp_ldo_regulator.h" +#include "esp_cache.h" +#include "example_dsi_init.h" +#include "example_config.h" + +void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer) +{ + esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; + esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; + + //---------------DSI resource allocation------------------// + esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = 2, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = 1000, // 1000 Mbps + }; + ESP_ERROR_CHECK(esp_lcd_new_dsi_bus(&bus_config, &mipi_dsi_bus)); + + esp_lcd_dbi_io_config_t dbi_config = { + .virtual_channel = 0, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(mipi_dsi_bus, &dbi_config, &mipi_dbi_io)); + + esp_lcd_panel_dev_config_t lcd_dev_config = { + .bits_per_pixel = 16, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .reset_gpio_num = -1, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_ili9881c(mipi_dbi_io, &lcd_dev_config, ili9881c_ctrl_panel)); + + esp_lcd_dpi_panel_config_t dpi_config = { + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = 80, + .virtual_channel = 0, + .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, + .video_timing = { + .h_size = EXAMPLE_MIPI_DSI_IMAGE_HSIZE, + .v_size = EXAMPLE_MIPI_DSI_IMAGE_VSIZE, + .hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP, + .hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC, + .hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP, + .vsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_VBP, + .vsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_VSYNC, + .vsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_VFP, + }, + }; + ESP_ERROR_CHECK(esp_lcd_new_panel_dpi(mipi_dsi_bus, &dpi_config, mipi_dpi_panel)); + ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, frame_buffer)); +} + +void example_dsi_ili9881c_panel_init(esp_lcd_panel_handle_t ili9881c_ctrl_panel) +{ + //---------------DSI Panel Init------------------// + ESP_ERROR_CHECK(esp_lcd_panel_reset(ili9881c_ctrl_panel)); + ESP_ERROR_CHECK(esp_lcd_panel_init(ili9881c_ctrl_panel)); + // turn on display + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(ili9881c_ctrl_panel, true)); +} + +void example_dpi_panel_init(esp_lcd_panel_handle_t mipi_dpi_panel) +{ + //---------------DPI Panel Init------------------// + ESP_ERROR_CHECK(esp_lcd_panel_init(mipi_dpi_panel)); +} diff --git a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.h b/examples/peripherals/camera/camera_dsi/main/example_dsi_init.h new file mode 100644 index 00000000000..f2f4c1c5970 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/example_dsi_init.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief DSI init function + * + * @param[out] ili9881c_ctrl_panel ILI9881C panel handle + * @param[out] mipi_dpi_panel MIPI DPI panel handle + * @param[out] frame_buffer frame buffer + */ +void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer); + +/** + * @brief DSI ILI9881C panel init function + * + * @param[in] ili9881c_ctrl_panel ILI9881C panel handle + */ +void example_dsi_ili9881c_panel_init(esp_lcd_panel_handle_t ili9881c_ctrl_panel); + +/** + * @brief DPI panel init function + * + * @param[in] mipi_dpi_panel MIPI DPI panel handle + */ +void example_dpi_panel_init(esp_lcd_panel_handle_t mipi_dpi_panel); + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/camera/camera_dsi/main/idf_component.yml b/examples/peripherals/camera/camera_dsi/main/idf_component.yml new file mode 100644 index 00000000000..16bbe273836 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/main/idf_component.yml @@ -0,0 +1,5 @@ +dependencies: + espressif/esp_cam_sensor: "^0.2.2" + espressif/esp_lcd_ili9881c: "*" + idf: + version: ">=5.3.0" diff --git a/examples/peripherals/camera/camera_dsi/pytest_camera_dsi.py b/examples/peripherals/camera/camera_dsi/pytest_camera_dsi.py new file mode 100644 index 00000000000..9c234e62174 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/pytest_camera_dsi.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_camera_dsi(dut: Dut) -> None: + dut.expect_exact('Calling app_main()') diff --git a/examples/peripherals/camera/camera_dsi/sdkconfig.defaults b/examples/peripherals/camera/camera_dsi/sdkconfig.defaults new file mode 100644 index 00000000000..7c4a6989325 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_CAMERA_OV5647=y diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c index 516782695db..094ae4df468 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c @@ -136,7 +136,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu af_current_best = af_current; } - ESP_LOGV(TAG, "af_sum: %"PRId32", af_current: %"PRId32".%"PRId32, af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000)); + ESP_LOGV(TAG, "af_sum: %d, af_current: %d.%d", af_sum, (int)af_current, (int)((int)(af_current * 1000) % 1000)); } // second search From 2ed780b686a10f70e7a483e6949016dfaf1dc47d Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 22 Apr 2024 17:21:31 +0800 Subject: [PATCH 080/548] fix(isp): fixed af environment detector lack of configuration issue --- components/esp_driver_isp/CMakeLists.txt | 1 + components/esp_driver_isp/src/isp_af.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index b75c9bfc4a8..7551a2a5a50 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -9,4 +9,5 @@ endif() idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${public_include} + PRIV_REQUIRES esp_driver_gpio ) diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index f2e0087a3d6..5e7bb86bdb3 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -174,6 +174,10 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, 0); isp_ll_clear_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV); + isp_ll_af_env_monitor_set_mode(af_ctrlr->isp_proc->hal.hw, ISP_LL_AF_ENV_MONITOR_MODE_ABS); + isp_ll_af_env_monitor_set_period(af_ctrlr->isp_proc->hal.hw, af_ctrlr->config.interval); + isp_ll_enable_intr(af_ctrlr->isp_proc->hal.hw, ISP_LL_EVENT_AF_ENV, true); + return ESP_OK; } @@ -196,7 +200,7 @@ esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctr return ESP_OK; } -esp_err_t esp_isp_af_env_detector_set_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh) +esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state"); From e4f1c0119743ccf42a66d64c1076976e59934c5c Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 22 Apr 2024 17:15:15 +0800 Subject: [PATCH 081/548] fix(csi): fixed wrong assert when there's new transaction --- components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 1136273da0d..6c297f1b9c5 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -300,6 +300,7 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ bool need_yield = false; BaseType_t high_task_woken = pdFALSE; csi_controller_t *ctlr = (csi_controller_t *)user_data; + bool has_new_trans = false; bool use_backup = false; dw_gdma_block_transfer_config_t csi_dma_transfer_config = {}; @@ -328,12 +329,14 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ use_backup = true; } else { csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; } } else if (xQueueReceiveFromISR(ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) { if (!(new_trans.buffer) || new_trans.buflen < ctlr->fb_size_in_bytes) { use_backup = true; } else { csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; } } else if (!ctlr->bk_buffer_dis) { use_backup = true; @@ -344,7 +347,9 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ new_trans.buflen = ctlr->fb_size_in_bytes; ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer"); csi_dma_transfer_config.dst.addr = (uint32_t)ctlr->backup_buffer; - } else { + } + + if (!has_new_trans) { assert(false && "no new buffer, and no driver internal buffer"); } From 5f07f64802e280a65a63bf2a15945615a84f2c3d Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 24 Apr 2024 16:59:20 +0800 Subject: [PATCH 082/548] example(isp): added isp af example --- examples/peripherals/.build-test-rules.yml | 6 +- .../peripherals/camera/camera_dsi/README.md | 2 +- .../camera/camera_dsi/main/CMakeLists.txt | 4 +- .../camera/camera_dsi/main/Kconfig.projbuild | 20 +- .../camera/camera_dsi/main/camera_dsi_main.c | 21 +- .../camera/camera_dsi/main/example_config.h | 17 +- .../camera/camera_dsi/main/idf_component.yml | 2 + .../camera/components/dsi_init/CMakeLists.txt | 4 + .../dsi_init}/example_dsi_init.c | 4 - .../dsi_init}/example_dsi_init.h | 9 + .../components/dsi_init/idf_component.yml | 4 + .../peripherals/isp/auto_focus/CMakeLists.txt | 6 + examples/peripherals/isp/auto_focus/README.md | 141 +++++++ .../isp_af_schemes/include/isp_af_scheme.h | 2 +- .../isp_af_schemes/include/isp_af_scheme_sa.h | 8 +- .../isp_af_schemes/src/isp_af_scheme_sa.c | 14 +- .../isp/auto_focus/main/CMakeLists.txt | 4 + .../isp/auto_focus/main/Kconfig.projbuild | 41 ++ .../isp/auto_focus/main/example_config.h | 24 ++ .../isp/auto_focus/main/idf_component.yml | 9 + .../isp/auto_focus/main/isp_af_dsi_main.c | 357 ++++++++++++++++++ .../isp/auto_focus/sdkconfig.defaults | 4 + 22 files changed, 651 insertions(+), 52 deletions(-) create mode 100644 examples/peripherals/camera/components/dsi_init/CMakeLists.txt rename examples/peripherals/camera/{camera_dsi/main => components/dsi_init}/example_dsi_init.c (96%) rename examples/peripherals/camera/{camera_dsi/main => components/dsi_init}/example_dsi_init.h (68%) create mode 100644 examples/peripherals/camera/components/dsi_init/idf_component.yml create mode 100644 examples/peripherals/isp/auto_focus/CMakeLists.txt create mode 100644 examples/peripherals/isp/auto_focus/README.md create mode 100644 examples/peripherals/isp/auto_focus/main/CMakeLists.txt create mode 100644 examples/peripherals/isp/auto_focus/main/Kconfig.projbuild create mode 100644 examples/peripherals/isp/auto_focus/main/example_config.h create mode 100644 examples/peripherals/isp/auto_focus/main/idf_component.yml create mode 100644 examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c create mode 100644 examples/peripherals/isp/auto_focus/sdkconfig.defaults diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index d5df6075196..0217624acc7 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -125,11 +125,11 @@ examples/peripherals/i2s/i2s_recorder: examples/peripherals/isp/auto_focus: disable: - - if: INCLUDE_DEFAULT == 1 - temporary: true - reason: disable build temporarily # TODO: IDF-8895 + - if: SOC_MIPI_CSI_SUPPORTED != 1 or SOC_MIPI_DSI_SUPPORTED != 1 or SOC_ISP_SUPPORTED != 1 depends_components: - esp_driver_isp + - esp_driver_cam + - esp_lcd examples/peripherals/jpeg/jpeg_decode: disable: diff --git a/examples/peripherals/camera/camera_dsi/README.md b/examples/peripherals/camera/camera_dsi/README.md index 76081356bdd..c078a675f31 100644 --- a/examples/peripherals/camera/camera_dsi/README.md +++ b/examples/peripherals/camera/camera_dsi/README.md @@ -17,7 +17,7 @@ The subsections below give only absolutely necessary information. For full steps This example requires: -- OV5647 camera sensor with VCM (Voice Coil Motor). The VCM used in this example is DW9714. +- OV5647 camera sensor - ILI9881C LCD screen - ESP32P4 devkit diff --git a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt index 92fcf227473..8910b7da400 100644 --- a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt +++ b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "camera_dsi_main.c" "example_dsi_init.c" +idf_component_register(SRCS "camera_dsi_main.c" INCLUDE_DIRS "." - REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd + REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd dsi_init ) diff --git a/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild b/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild index fdc04994528..8117f6ef7ba 100644 --- a/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild +++ b/examples/peripherals/camera/camera_dsi/main/Kconfig.projbuild @@ -12,8 +12,20 @@ menu "Example Configuration" help Example used LDO voltage, in mV - choice EXAMPLE_MIPI_CSI_VRES - bool "Set MIPI CSI verticol resolution" + choice EXAMPLE_MIPI_CSI_DISP_HRES + bool "Set MIPI CSI horizontal resolution" + default EXAMPLE_MIPI_CSI_HRES_800 + + config EXAMPLE_MIPI_CSI_HRES_800 + bool "800" + endchoice + + config EXAMPLE_MIPI_CSI_DISP_HRES + int + default 800 if EXAMPLE_MIPI_CSI_HRES_800 + + choice EXAMPLE_MIPI_CSI_DISP_VRES + bool "Set MIPI CSI vertical resolution" default EXAMPLE_MIPI_CSI_VRES_640 config EXAMPLE_MIPI_CSI_VRES_640 @@ -22,4 +34,8 @@ menu "Example Configuration" bool "1280" endchoice + config EXAMPLE_MIPI_CSI_DISP_VRES + int + default 640 if EXAMPLE_MIPI_CSI_VRES_640 + default 1280 if EXAMPLE_MIPI_CSI_VRES_1280 endmenu diff --git a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c index dc9b3e8de25..9087aa28fb5 100644 --- a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c +++ b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c @@ -55,9 +55,9 @@ void app_main(void) example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); //---------------Necessary variable config------------------// - frame_buffer_size = EXAMPLE_MIPI_CSI_DISP_HSIZE * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - ESP_LOGD(TAG, "EXAMPLE_MIPI_CSI_DISP_HSIZE: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", EXAMPLE_MIPI_CSI_DISP_HSIZE, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); + ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); @@ -89,12 +89,8 @@ void app_main(void) //---------------CSI Init------------------// esp_cam_ctlr_csi_config_t csi_config = { .ctlr_id = 0, - .h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, -#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 - .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P, -#else - .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P, -#endif + .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, + .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, .input_data_color_type = MIPI_CSI_COLOR_RAW8, .output_data_color_type = MIPI_CSI_COLOR_RGB565, @@ -129,12 +125,8 @@ void app_main(void) .output_data_color_type = ISP_COLOR_RGB565, .has_line_start_packet = false, .has_line_end_packet = false, - .h_res = EXAMPLE_MIPI_CSI_DISP_HSIZE, -#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 - .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_640P, -#else - .v_res = EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P, -#endif + .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, + .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, }; ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); @@ -174,7 +166,6 @@ void app_main(void) esp_cam_sensor_format_t *cam_cur_fmt = NULL; for (int i = 0; i < cam_fmt_array.count; i++) { - #if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) { cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); diff --git a/examples/peripherals/camera/camera_dsi/main/example_config.h b/examples/peripherals/camera/camera_dsi/main/example_config.h index fe6bbac88a8..c72a6b02ea0 100644 --- a/examples/peripherals/camera/camera_dsi/main/example_config.h +++ b/examples/peripherals/camera/camera_dsi/main/example_config.h @@ -12,24 +12,11 @@ extern "C" { #define EXAMPLE_RGB565_BITS_PER_PIXEL 16 #define EXAMPLE_MIPI_SCCB_FREQ (100000) -#define EXAMPLE_MIPI_SCCB_SCL_IO (34) -#define EXAMPLE_MIPI_SCCB_SDA_IO (31) -#define EXAMPLE_MIPI_CSI_DISP_HSIZE 800 -#define EXAMPLE_MIPI_CSI_DISP_VSIZE_640P 640 -#define EXAMPLE_MIPI_CSI_DISP_VSIZE_1280P 1280 -#define EXAMPLE_MIPI_CSI_640P 1 +#define EXAMPLE_MIPI_SCCB_SCL_IO (8) +#define EXAMPLE_MIPI_SCCB_SDA_IO (7) #define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000) #define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 -#define EXAMPLE_MIPI_DSI_IMAGE_HSIZE 800 -#define EXAMPLE_MIPI_DSI_IMAGE_VSIZE 1280 -#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 -#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 -#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40 -#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4 -#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 -#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 - #define EXAMPLE_OV5647_DEV_ADDR 0x36 #ifdef __cplusplus } diff --git a/examples/peripherals/camera/camera_dsi/main/idf_component.yml b/examples/peripherals/camera/camera_dsi/main/idf_component.yml index 16bbe273836..f7121dc8c58 100644 --- a/examples/peripherals/camera/camera_dsi/main/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/main/idf_component.yml @@ -3,3 +3,5 @@ dependencies: espressif/esp_lcd_ili9881c: "*" idf: version: ">=5.3.0" + dsi_init: + path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init diff --git a/examples/peripherals/camera/components/dsi_init/CMakeLists.txt b/examples/peripherals/camera/components/dsi_init/CMakeLists.txt new file mode 100644 index 00000000000..348bb317260 --- /dev/null +++ b/examples/peripherals/camera/components/dsi_init/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "example_dsi_init.c" + INCLUDE_DIRS "." + REQUIRES esp_lcd + ) diff --git a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.c b/examples/peripherals/camera/components/dsi_init/example_dsi_init.c similarity index 96% rename from examples/peripherals/camera/camera_dsi/main/example_dsi_init.c rename to examples/peripherals/camera/components/dsi_init/example_dsi_init.c index 5291024f331..1cf9f3768a2 100644 --- a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.c +++ b/examples/peripherals/camera/components/dsi_init/example_dsi_init.c @@ -6,14 +6,10 @@ #include #include #include "esp_log.h" -#include "esp_heap_caps.h" #include "esp_lcd_mipi_dsi.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_ili9881c.h" -#include "esp_ldo_regulator.h" -#include "esp_cache.h" #include "example_dsi_init.h" -#include "example_config.h" void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer) { diff --git a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.h b/examples/peripherals/camera/components/dsi_init/example_dsi_init.h similarity index 68% rename from examples/peripherals/camera/camera_dsi/main/example_dsi_init.h rename to examples/peripherals/camera/components/dsi_init/example_dsi_init.h index f2f4c1c5970..5cffbc3cdfa 100644 --- a/examples/peripherals/camera/camera_dsi/main/example_dsi_init.h +++ b/examples/peripherals/camera/components/dsi_init/example_dsi_init.h @@ -10,6 +10,15 @@ extern "C" { #endif +#define EXAMPLE_MIPI_DSI_IMAGE_HSIZE 800 +#define EXAMPLE_MIPI_DSI_IMAGE_VSIZE 1280 +#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 +#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 +#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40 +#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4 +#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 +#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 + /** * @brief DSI init function * diff --git a/examples/peripherals/camera/components/dsi_init/idf_component.yml b/examples/peripherals/camera/components/dsi_init/idf_component.yml new file mode 100644 index 00000000000..6e0028e6a5e --- /dev/null +++ b/examples/peripherals/camera/components/dsi_init/idf_component.yml @@ -0,0 +1,4 @@ +dependencies: + espressif/esp_lcd_ili9881c: "^0.2.0" + idf: + version: ">=5.3.0" diff --git a/examples/peripherals/isp/auto_focus/CMakeLists.txt b/examples/peripherals/isp/auto_focus/CMakeLists.txt new file mode 100644 index 00000000000..dd9fec70ab3 --- /dev/null +++ b/examples/peripherals/isp/auto_focus/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(isp_af_dsi) diff --git a/examples/peripherals/isp/auto_focus/README.md b/examples/peripherals/isp/auto_focus/README.md new file mode 100644 index 00000000000..a38446fd9ec --- /dev/null +++ b/examples/peripherals/isp/auto_focus/README.md @@ -0,0 +1,141 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + + +# Camera display via DSI example + +## Overview + +This example demonstrates how to use the ISP (image signal processor) to work with esp_driver_cam component. This example will capture camera sensor signals via CSI interface and display it via DSI interface. This example also enables the ISP AF (auto-focus) feature. + +## Usage + +The subsections below give only absolutely necessary information. For full steps to configure ESP-IDF and use it to build and run projects, see [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started). + + +### Hardware Required + +This example requires: + +- OV5647 camera sensor with VCM (Voice Coil Motor). The VCM used in this example is DW9714. +- ILI9881C LCD screen +- ESP32P4 devkit + + + GND GND + ┌────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────┐ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ ┌───────────────┴─────────────┴──────────────────┐ │ + │ │ │ ┌──────────┴───────────┐ + │ │ │ DSI DATA 1P │ │ + │ │ ├───────────────────────────┤ │ + ┌───────────┴─────────┐ CSI DATA 1P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 1N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 1N │ ESP32-P4 │ │ │ + │ OV5647 ├──────────────────────┤ │ DSI CLK N │ ILI9881C │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI CLK N │ │ │ │ + │ ├──────────────────────┤ │ DSI CLK P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI CLK P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0P │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 0P │ │ │ │ + │ ├──────────────────────┤ │ DSI DATA 0N │ │ + │ │ │ ├───────────────────────────┤ │ + │ │ CSI DATA 0N │ │ │ │ + │ ├──────────────────────┤ │ └──────────────────────┘ + │ │ │ │ + └───────┬──┬──────────┘ │ │ + │ │ I2C SCL │ │ + │ └─────────────────────────────────┤ │ + │ I2C SDA │ │ + └────────────────────────────────────┤ │ + └────────────────────────────────────────────────┘ + + +### Set Chip Target + +First of all, your target must be supported by both: + +- **By your ESP-IDF version**: For the full list of supported targets, run: + ``` + idf.py --list-targets + ``` +- **By this example**: For the full list of supported targets, refer to the supported targets table at the top of this README. + +After you make sure that your target is supported, go to your example project directory and [set the chip target](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/tools/idf-py.html#select-the-target-chip-set-target): + +``` +idf.py set-target +``` + +For example, to set esp32-P4 as the chip target, run: + +``` +idf.py set-target esp32p4 +``` + + +### Configure the Project + +For information about Kconfig options, see [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) > _Name of relevant section(s)_. + +To conveniently check or modify Kconfig options for this example in a project configuration menu, run: + +``` +idf.py menuconfig +``` + +``` +Set CONFIG_CAMERA_OV5647 to y +``` + + +### Build and Flash + +Execute the following command to build the project, flash it to your development board, and run the monitor tool to view the serial output: + +``` +idf.py build flash monitor +``` + +This command can be reduced to `idf.py flash monitor`. + +If the above command fails, check the log on the serial monitor which usually provides information on the possible cause of the issue. + +To exit the serial monitor, use `Ctrl` + `]`. + + +## Example Output + +If you see the following console output, your example should be running correctly: + +``` +I (1085) main_task: Calling app_main() +I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c +I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 +I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0 +I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps +I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps +I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps +I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps +``` + +You will also see the screen auto-focus when the screen image changes. + +## Reference + +- Link to the ESP-IDF camera controller driver API reference, [ESP-IDF: Camera Controller Driver](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/camera_driver.html) +- Link to the ESP-IDF ISP driver API reference, [ESP-IDF: Image Signal Processor](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/api-reference/peripherals/isp.html) +- [ESP-IDF Getting Started](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#get-started) +- [Project Configuration](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/kconfig.html) (Kconfig Options) diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme.h b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme.h index 1926c484fd2..95164fce3a2 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme.h +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h index 44e6a57decb..dd70f17d0ce 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,8 +33,9 @@ typedef struct { * @brief Sensor driver API to set sensor focus value * * @param[in] focus_val Camera sensor focus value + * @param[in] arg User arg */ - esp_err_t (*af_sensor_set_focus)(int focus_val); + esp_err_t (*af_sensor_set_focus)(int focus_val, void *arg); } isp_af_sa_scheme_sensor_drv_t; @@ -72,13 +73,14 @@ esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme); * @param[in] scheme AF scheme handle * @param[in] sensor_drv Sensor driver, see `isp_af_sa_scheme_sensor_drv_t` * @param[in] info Sensor info + * @param[in] arg User arg * * @return * - ESP_OK On success * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid * - ESP_ERR_INVALID_STATE Invalid state */ -esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info); +esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info, void *arg); #ifdef __cplusplus } diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c index 094ae4df468..b7b5502d520 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,6 +29,7 @@ typedef struct { isp_af_sa_scheme_sensor_info_t sensor_info; isp_af_sa_scheme_sensor_drv_t sensor_drv; + void *arg; } af_scheme_context_t; /* ------------------------ Interface Functions --------------------------- */ @@ -78,7 +79,7 @@ esp_err_t isp_af_delete_sa_scheme(isp_af_scheme_handle_t scheme) return ESP_OK; } -esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info) +esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, const isp_af_sa_scheme_sensor_drv_t *sensor_drv, const isp_af_sa_scheme_sensor_info_t *info, void *arg) { ESP_RETURN_ON_FALSE(scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); ESP_RETURN_ON_FALSE(scheme->ctx, ESP_ERR_INVALID_STATE, TAG, "no scheme created yet"); @@ -86,6 +87,7 @@ esp_err_t isp_af_sa_scheme_register_sensor_driver(isp_af_scheme_handle_t scheme, af_scheme_context_t *ctx = scheme->ctx; ctx->sensor_drv.af_sensor_set_focus = sensor_drv->af_sensor_set_focus; ctx->sensor_info.focus_val_max = info->focus_val_max; + ctx->arg = arg; return ESP_OK; } @@ -117,7 +119,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu isp_af_result_t result = {}; - ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(0), TAG, "sensor set focus val fail"); + ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(0, ctx->arg), TAG, "sensor set focus val fail"); ESP_LOGV(TAG, "//----------- af start ----------//"); @@ -128,7 +130,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu for (int x = 0; x <= ctx->first_approx_cycles; x++) { af_current = af_current_base + x * ctx->first_step_val; - ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail"); + ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current, ctx->arg), TAG, "sensor set focus val fail"); ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail"); af_sum = result.definition[0] + result.definition[1] + result.definition[2]; if (af_sum > af_sum_max) { @@ -154,7 +156,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu af_current = 0; } - ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current), TAG, "sensor set focus val fail"); + ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current, ctx->arg), TAG, "sensor set focus val fail"); ESP_RETURN_ON_ERROR(esp_isp_af_controller_get_oneshot_result(ctx->af_ctlr, &result), TAG, "get AF result fail"); af_sum = result.definition[0] + result.definition[1] + result.definition[2]; if (af_sum > af_sum_max) { @@ -167,7 +169,7 @@ static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_lu // af done ESP_LOGV(TAG, "//----------- af done ----------//"); ESP_LOGV(TAG, "af_sum_max: %d, af_current_best: %d.%d", af_sum_max, (int)af_current_best, (int)((int)(af_current_best * 1000) % 1000)); - ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current_best), TAG, "sensor set focus val fail"); + ESP_RETURN_ON_ERROR(ctx->sensor_drv.af_sensor_set_focus(af_current_best, ctx->arg), TAG, "sensor set focus val fail"); // update env threshold ESP_LOGV(TAG, "//------- update env threshold -------//"); diff --git a/examples/peripherals/isp/auto_focus/main/CMakeLists.txt b/examples/peripherals/isp/auto_focus/main/CMakeLists.txt new file mode 100644 index 00000000000..60d0b9d6057 --- /dev/null +++ b/examples/peripherals/isp/auto_focus/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "isp_af_dsi_main.c" + INCLUDE_DIRS "." + REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd dsi_init + ) diff --git a/examples/peripherals/isp/auto_focus/main/Kconfig.projbuild b/examples/peripherals/isp/auto_focus/main/Kconfig.projbuild new file mode 100644 index 00000000000..8117f6ef7ba --- /dev/null +++ b/examples/peripherals/isp/auto_focus/main/Kconfig.projbuild @@ -0,0 +1,41 @@ +menu "Example Configuration" + config EXAMPLE_USED_LDO_CHAN_ID + int "example used LDO channel ID" + default 3 + help + Example used LDO channel ID, you may check datasheet to know more details. + + config EXAMPLE_USED_LDO_VOLTAGE_MV + int "example used LDO voltage in mV" + default 2500 + range 0 3300 + help + Example used LDO voltage, in mV + + choice EXAMPLE_MIPI_CSI_DISP_HRES + bool "Set MIPI CSI horizontal resolution" + default EXAMPLE_MIPI_CSI_HRES_800 + + config EXAMPLE_MIPI_CSI_HRES_800 + bool "800" + endchoice + + config EXAMPLE_MIPI_CSI_DISP_HRES + int + default 800 if EXAMPLE_MIPI_CSI_HRES_800 + + choice EXAMPLE_MIPI_CSI_DISP_VRES + bool "Set MIPI CSI vertical resolution" + default EXAMPLE_MIPI_CSI_VRES_640 + + config EXAMPLE_MIPI_CSI_VRES_640 + bool "640" + config EXAMPLE_MIPI_CSI_VRES_1280 + bool "1280" + endchoice + + config EXAMPLE_MIPI_CSI_DISP_VRES + int + default 640 if EXAMPLE_MIPI_CSI_VRES_640 + default 1280 if EXAMPLE_MIPI_CSI_VRES_1280 +endmenu diff --git a/examples/peripherals/isp/auto_focus/main/example_config.h b/examples/peripherals/isp/auto_focus/main/example_config.h new file mode 100644 index 00000000000..628a441f56f --- /dev/null +++ b/examples/peripherals/isp/auto_focus/main/example_config.h @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_MIPI_SCCB_FREQ (100000) +#define EXAMPLE_MIPI_SCCB_SCL_IO (8) +#define EXAMPLE_MIPI_SCCB_SDA_IO (7) +#define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000) +#define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 + +#define EXAMPLE_OV5647_DEV_ADDR 0x36 +#define EXAMPLE_DW9714_DEV_ADDR 0xC +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/isp/auto_focus/main/idf_component.yml b/examples/peripherals/isp/auto_focus/main/idf_component.yml new file mode 100644 index 00000000000..803bff156a7 --- /dev/null +++ b/examples/peripherals/isp/auto_focus/main/idf_component.yml @@ -0,0 +1,9 @@ +dependencies: + espressif/esp_cam_sensor: "^0.2.2" + espressif/esp_lcd_ili9881c: "*" + idf: + version: ">=5.3.0" + isp_af_schemes: + path: ${IDF_PATH}/examples/peripherals/isp/auto_focus/components/isp_af_schemes + dsi_init: + path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c new file mode 100644 index 00000000000..6cca1612bc7 --- /dev/null +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -0,0 +1,357 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_ili9881c.h" +#include "esp_ldo_regulator.h" +#include "esp_cache.h" +#include "driver/i2c_master.h" +#include "driver/isp.h" +#include "isp_af_scheme_sa.h" +#include "esp_cam_ctlr_csi.h" +#include "esp_cam_ctlr.h" +#include "esp_sccb_intf.h" +#include "esp_sccb_i2c.h" +#include "esp_cam_sensor.h" +#include "ov5647.h" +#include "example_dsi_init.h" +#include "example_config.h" + +static const char *TAG = "isp_dsi"; + +static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); +static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); + +typedef union { + struct { + uint16_t s : 4; + uint16_t d : 10; + uint16_t flag : 1; + uint16_t pd : 1; + }; + struct { + uint16_t byte2 : 8; + uint16_t byte1 : 8; + }; + uint16_t val; +} dw9714_reg_t; + +static bool IRAM_ATTR s_env_change_cb(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data) +{ + BaseType_t mustYield = pdFALSE; + TaskHandle_t task_handle = (TaskHandle_t)user_data; + vTaskNotifyGiveFromISR(task_handle, &mustYield); + + return (mustYield == pdTRUE); +} + +static esp_err_t s_sensor_set_focus_val(int focus_val, void *arg) +{ + esp_sccb_io_handle_t dw9714_io_handle = arg; + + dw9714_reg_t reg = {0}; + reg.d = (uint16_t)((focus_val / 120.0) * 1023.0); + + uint8_t data[2] = {0}; + data[0] = reg.byte1; + data[1] = reg.byte2; + + uint16_t reg_addr = (data[0] << 8) + (data[1]); + uint8_t reg_val = 0; + + esp_err_t ret = esp_sccb_transmit_reg_a16v8(dw9714_io_handle, reg_addr, reg_val); + if (ret != ESP_OK) { + printf("dw9714 esp_sccb_transmit_reg_a16v8 failed\n"); + return ret; + } + + return ESP_OK; +} + +static void af_task(void *arg) +{ + TaskHandle_t task_handle = xTaskGetCurrentTaskHandle(); + + typedef struct af_task_param_t { + isp_proc_handle_t isp_proc; + esp_sccb_io_handle_t dw9714_io_handle; + } af_task_param_t; + + af_task_param_t af_task_param = *(af_task_param_t *)arg; + + /** + * AF window, windows for ISP hardware to record the + * - lunimance + * - definition + * of the current windows + */ + esp_isp_af_config_t af_config = { + .window = { + [0] = { + .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, + [1] = { + .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, + [2] = { + .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, + }, + .edge_thresh = 128, + }; + + isp_af_ctrlr_t af_ctrlr = NULL; + ESP_ERROR_CHECK(esp_isp_new_af_controller(af_task_param.isp_proc, &af_config, &af_ctrlr)); + + esp_isp_af_env_config_t env_config = { + .interval = 10, + }; + ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config)); + + esp_isp_af_env_detector_evt_cbs_t cbs = { + .on_env_change = s_env_change_cb, + }; + ESP_ERROR_CHECK(esp_isp_af_env_detector_register_event_callbacks(af_ctrlr, &cbs, task_handle)); + + isp_af_sa_scheme_config_t af_scheme_config = { + .first_step_val = 12, + .first_approx_cycles = 10, + .second_step_val = 2, + .second_approx_cycles = 10, + }; + isp_af_scheme_handle_t af_scheme = NULL; + ESP_ERROR_CHECK(isp_af_create_sa_scheme(af_ctrlr, &af_scheme_config, &af_scheme)); + + isp_af_sa_scheme_sensor_drv_t sensor_driver = { + .af_sensor_set_focus = s_sensor_set_focus_val, + }; + isp_af_sa_scheme_sensor_info_t sensor_info = { + .focus_val_max = 120, + }; + ESP_ERROR_CHECK(isp_af_sa_scheme_register_sensor_driver(af_scheme, &sensor_driver, &sensor_info, af_task_param.dw9714_io_handle)); + + int definition_thresh = 0; + int luminance_thresh = 0; + ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); + + while (1) { + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ESP_ERROR_CHECK(isp_af_process(af_scheme, &definition_thresh, &luminance_thresh)); + ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector_threshold(af_ctrlr, definition_thresh, luminance_thresh)); + } +} + +void app_main(void) +{ + esp_err_t ret = ESP_FAIL; + esp_lcd_panel_handle_t ili9881c_ctrl_panel = NULL; + esp_lcd_panel_handle_t mipi_dpi_panel = NULL; + void *frame_buffer = NULL; + size_t frame_buffer_size = 0; + + //mipi ldo + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = CONFIG_EXAMPLE_USED_LDO_CHAN_ID, + .voltage_mv = CONFIG_EXAMPLE_USED_LDO_VOLTAGE_MV, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + /** + * @background + * Sensor use RAW8 + * ISP convert to RGB565 + */ + //---------------DSI Init------------------// + example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); + + //---------------Necessary variable config------------------// + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + + ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); + ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); + ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); + + esp_cam_ctlr_trans_t new_trans = { + .buffer = frame_buffer, + .buflen = frame_buffer_size, + }; + + //---------------I2C Init------------------// + i2c_master_bus_config_t i2c_bus_conf = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .sda_io_num = EXAMPLE_MIPI_SCCB_SDA_IO, + .scl_io_num = EXAMPLE_MIPI_SCCB_SCL_IO, + .i2c_port = I2C_NUM_0, + .flags.enable_internal_pullup = true, + }; + i2c_master_bus_handle_t bus_handle = NULL; + ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_bus_conf, &bus_handle)); + + //---------------SCCB Init------------------// + esp_sccb_io_handle_t ov5647_io_handle = NULL; + sccb_i2c_config_t i2c_config = { + .scl_speed_hz = EXAMPLE_MIPI_SCCB_FREQ, + .device_address = EXAMPLE_OV5647_DEV_ADDR, + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + }; + ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &ov5647_io_handle)); + + esp_sccb_io_handle_t dw9714_io_handle = NULL; + i2c_config.device_address = EXAMPLE_DW9714_DEV_ADDR; + ESP_ERROR_CHECK(sccb_new_i2c_io(bus_handle, &i2c_config, &dw9714_io_handle)); + + //---------------CSI Init------------------// + esp_cam_ctlr_csi_config_t csi_config = { + .ctlr_id = 0, + .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, + .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, + .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, + .input_data_color_type = MIPI_CSI_COLOR_RAW8, + .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .data_lane_num = 2, + .byte_swap_en = false, + .queue_items = 1, + }; + esp_cam_ctlr_handle_t handle = NULL; + ret = esp_cam_new_csi_ctlr(&csi_config, &handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "csi init fail[%d]", ret); + return; + } + + esp_cam_ctlr_evt_cbs_t cbs = { + .on_get_new_trans = s_camera_get_new_vb, + .on_trans_finished = s_camera_get_finished_trans, + }; + if (esp_cam_ctlr_register_event_callbacks(handle, &cbs, &new_trans) != ESP_OK) { + ESP_LOGE(TAG, "ops register fail"); + return; + } + + ESP_ERROR_CHECK(esp_cam_ctlr_enable(handle)); + //---------------ISP Init------------------// + isp_proc_handle_t isp_proc = NULL; + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 80 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_CSI, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + .has_line_start_packet = false, + .has_line_end_packet = false, + .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, + .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, + }; + ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); + ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); + + typedef struct af_task_param_t { + isp_proc_handle_t isp_proc; + esp_sccb_io_handle_t dw9714_io_handle; + } af_task_param_t; + + af_task_param_t af_task_param = { + .isp_proc = isp_proc, + .dw9714_io_handle = dw9714_io_handle, + }; + xTaskCreatePinnedToCore(af_task, "af_task", 8192, &af_task_param, 5, NULL, 0); + + //---------------DSI Panel Init------------------// + example_dsi_ili9881c_panel_init(ili9881c_ctrl_panel); + + //init to all white + memset(frame_buffer, 0xFF, frame_buffer_size); + esp_cache_msync((void *)frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + if (esp_cam_ctlr_start(handle) != ESP_OK) { + ESP_LOGE(TAG, "Driver start fail"); + return; + } + + esp_cam_sensor_config_t cam_config = { + .sccb_handle = ov5647_io_handle, + .reset_pin = -1, + .pwdn_pin = -1, + .xclk_pin = -1, + .sensor_port = ESP_CAM_SENSOR_MIPI_CSI, + }; + + esp_cam_sensor_device_t *cam = ov5647_detect(&cam_config); + if (!cam) { + ESP_LOGE(TAG, "failed to detect 5647"); + return; + } + + esp_cam_sensor_format_array_t cam_fmt_array = {0}; + esp_cam_sensor_query_format(cam, &cam_fmt_array); + const esp_cam_sensor_format_t *parray = cam_fmt_array.format_array; + for (int i = 0; i < cam_fmt_array.count; i++) { + ESP_LOGI(TAG, "fmt[%d].name:%s", i, parray[i].name); + } + + esp_cam_sensor_format_t *cam_cur_fmt = NULL; + for (int i = 0; i < cam_fmt_array.count; i++) { +#if CONFIG_EXAMPLE_MIPI_CSI_VRES_640 + if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x640_50fps")) { + cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); + break; + } +#else + if (!strcmp(parray[i].name, "MIPI_2lane_24Minput_RAW8_800x1280_50fps")) { + cam_cur_fmt = (esp_cam_sensor_format_t *) & (parray[i].name); + break; + } +#endif + } + + ret = esp_cam_sensor_set_format(cam, (const esp_cam_sensor_format_t *) cam_cur_fmt); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Format set fail"); + } else { + ESP_LOGI(TAG, "Format in use:%s", cam_cur_fmt->name); + } + int enable_flag = 1; + // Set sensor output stream + ret = esp_cam_sensor_ioctl(cam, ESP_CAM_SENSOR_IOC_S_STREAM, &enable_flag); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Start stream fail"); + } + + example_dpi_panel_init(mipi_dpi_panel); + + while (1) { + ESP_ERROR_CHECK(esp_cam_ctlr_receive(handle, &new_trans, ESP_CAM_CTLR_MAX_DELAY)); + } +} + +static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + esp_cam_ctlr_trans_t new_trans = *(esp_cam_ctlr_trans_t *)user_data; + trans->buffer = new_trans.buffer; + trans->buflen = new_trans.buflen; + + return false; +} + +bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) +{ + return false; +} diff --git a/examples/peripherals/isp/auto_focus/sdkconfig.defaults b/examples/peripherals/isp/auto_focus/sdkconfig.defaults new file mode 100644 index 00000000000..7c4a6989325 --- /dev/null +++ b/examples/peripherals/isp/auto_focus/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_CAMERA_OV5647=y From 0dc29caf4a48a1e0106cd54832e8b33e89922c47 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 14 May 2024 22:32:25 +0800 Subject: [PATCH 083/548] fix(freertos/idf): Add missing critical sections to vTaskSuspendAll() vTaskSuspendAll() requires critical sections when building for SMP. Otherwise, it is possible for a task to switch cores in between getting the core ID and before incremented uxSchedulerSuspended. --- components/freertos/FreeRTOS-Kernel/tasks.c | 29 +++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 5341549b83a..d9f10e69045 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -2462,22 +2462,29 @@ void vTaskEndScheduler( void ) void vTaskSuspendAll( void ) { - /* A critical section is not required as the variable is of type + /* For SMP, we need to take the kernel lock here as we are about to access + * kernel data structures. + * + * For single-core, a critical section is not required as the variable is of type * BaseType_t. Please read Richard Barry's reply in the following link to a * post in the FreeRTOS support forum before reporting this as a bug! - * https://goo.gl/wu4acr */ + prvENTER_CRITICAL_SMP_ONLY( &xKernelLock ); + { + /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that + * do not otherwise exhibit real time behaviour. */ + portSOFTWARE_BARRIER(); - /* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that - * do not otherwise exhibit real time behaviour. */ - portSOFTWARE_BARRIER(); - - /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment - * is used to allow calls to vTaskSuspendAll() to nest. */ - ++uxSchedulerSuspended[ portGET_CORE_ID() ]; + /* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment + * is used to allow calls to vTaskSuspendAll() to nest. */ + ++uxSchedulerSuspended[ portGET_CORE_ID() ]; - /* Enforces ordering for ports and optimised compilers that may otherwise place - * the above increment elsewhere. */ - portMEMORY_BARRIER(); + /* Enforces ordering for ports and optimised compilers that may otherwise place + * the above increment elsewhere. */ + portMEMORY_BARRIER(); + } + /* Release the previously taken kernel lock. */ + prvEXIT_CRITICAL_SMP_ONLY( &xKernelLock ); } /*----------------------------------------------------------*/ From cbb43bb4c4d7a05a219af4e40d4d67999eba6857 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 14 May 2024 23:01:50 +0800 Subject: [PATCH 084/548] refactor(freertos/idf): Add critical section requirements to function description This commit adds a note regarding the critical section calling requires of some internal functions. --- components/freertos/FreeRTOS-Kernel/tasks.c | 31 +++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index d9f10e69045..2482826674e 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -141,6 +141,11 @@ * - If a yield is required on the current core, this macro return pdTRUE * - if a yield is required on the other core, this macro will internally * trigger it. + * + * - In SMP, these macros must be called from a critical section (where the + * kernel locks are taken). + * - In single-core, these macros must be called from a critical section or when + * the scheduler is suspended. */ #if ( configNUMBER_OF_CORES > 1 ) #define taskIS_YIELD_REQUIRED( pxTCB, xYieldEqualPriority ) prvIsYieldRequiredSMP( ( pxTCB ), ( pxTCB )->uxPriority, xYieldEqualPriority ) @@ -177,7 +182,12 @@ #endif /* configNUMBER_OF_CORES > 1 */ /*-----------------------------------------------------------*/ -/* Macros to check if a particular task is a currently running. */ +/* Macros to check if a particular task is a currently running. + * + * - In SMP, these macros must be called from a critical section (where the + * kernel lock is taken). + * - In single-core, these macros must be called from a critical section or when + * the scheduler is suspended */ #if ( configNUMBER_OF_CORES > 1 ) #define taskIS_CURRENTLY_RUNNING( pxTCB ) ( ( ( ( pxTCB ) == pxCurrentTCBs[ 0 ] ) || ( ( pxTCB ) == pxCurrentTCBs[ 1 ] ) ) ? pdTRUE : pdFALSE ) #define taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCoreID ) ( ( ( pxTCB ) == pxCurrentTCBs[ ( xCoreID ) ] ) ? pdTRUE : pdFALSE ) @@ -193,7 +203,12 @@ /*-----------------------------------------------------------*/ /* Macro to check if a particular task can currently be scheduled (i.e., is - * the scheduler suspended). */ + * the scheduler suspended). + * + * - In SMP, these macros must be called from a critical section (where the + * kernel lock is taken). + * - In single-core, these macros must be called from a critical section or when + * the scheduler is suspended */ #if ( configNUMBER_OF_CORES > 1 ) #define taskCAN_BE_SCHEDULED( pxTCB ) prvCheckTaskCanBeScheduledSMP( pxTCB ) #else @@ -569,6 +584,9 @@ static BaseType_t prvCreateIdleTasks( void ); * Exit: * - Returns pdTRUE if the current core requires yielding * - The other core will be triggered to yield if required + * + * @note This function must be called from a critical section where the kernel + * lock is taken). */ #if ( configNUMBER_OF_CORES > 1 ) @@ -589,6 +607,9 @@ static BaseType_t prvCreateIdleTasks( void ); * - If a task is unpinned, check the scheduler suspension state on both cores. * The task can be scheduled if the scheduler is not suspended on either of * the cores. + * + * @note This function must be called from a critical section (where the kernel + * lock is taken). */ #if ( configNUMBER_OF_CORES > 1 ) @@ -772,6 +793,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; UBaseType_t uxTaskPriority, BaseType_t xYieldEqualPriority ) { + /* This function must be called from a critical section (where the kernel + * lock is taken). */ + configASSERT( uxTaskPriority < configMAX_PRIORITIES ); /* Save core ID as we can no longer be preempted. */ @@ -825,6 +849,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; static BaseType_t prvCheckTaskCanBeScheduledSMP( TCB_t * pxTCB ) { + /* This function must be called from a critical section (where the kernel + * lock is taken). */ + BaseType_t xReturn; if( pxTCB->xCoreID == tskNO_AFFINITY ) From 3640c1ecba76752ab51977e99ca7b2fb71be0885 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 19 Apr 2024 13:25:53 +0530 Subject: [PATCH 085/548] fix(bootloader_support): Fix flash encryption for esp32p4 --- .../src/flash_encryption/flash_encrypt.c | 15 ++++++++------- .../esp32p4/include/hal/mspi_timing_tuning_ll.h | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/components/bootloader_support/src/flash_encryption/flash_encrypt.c b/components/bootloader_support/src/flash_encryption/flash_encrypt.c index c1f6352311b..a0a48312e0b 100644 --- a/components/bootloader_support/src/flash_encryption/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encryption/flash_encrypt.c @@ -18,6 +18,7 @@ #if SOC_KEY_MANAGER_SUPPORTED #include "hal/key_mgr_hal.h" +#include "hal/mspi_timing_tuning_ll.h" #include "soc/keymng_reg.h" #endif @@ -217,8 +218,15 @@ static esp_err_t check_and_generate_encryption_keys(void) } #if SOC_KEY_MANAGER_SUPPORTED +#if CONFIG_IDF_TARGET_ESP32C5 && SOC_KEY_MANAGER_SUPPORTED + // TODO: [ESP32C5] IDF-8622 find a more proper place for these codes + REG_SET_BIT(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY_FLASH); + REG_SET_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); + REG_CLR_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); +#endif // Force Key Manager to use eFuse key for XTS-AES operation key_mgr_hal_set_key_usage(ESP_KEY_MGR_XTS_AES_128_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); + _mspi_timing_ll_reset_mspi(); #endif return ESP_OK; @@ -263,13 +271,6 @@ esp_err_t esp_flash_encrypt_contents(void) esp_partition_info_t partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES]; int num_partitions; -#if CONFIG_IDF_TARGET_ESP32C5 && SOC_KEY_MANAGER_SUPPORTED - // TODO: [ESP32C5] IDF-8622 find a more proper place for these codes - REG_SET_BIT(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY_FLASH); - REG_SET_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); - REG_CLR_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); -#endif - #ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK REG_WRITE(SENSITIVE_XTS_AES_KEY_UPDATE_REG, 1); #endif diff --git a/components/hal/esp32p4/include/hal/mspi_timing_tuning_ll.h b/components/hal/esp32p4/include/hal/mspi_timing_tuning_ll.h index 9f2e152698d..6b84ef3c263 100644 --- a/components/hal/esp32p4/include/hal/mspi_timing_tuning_ll.h +++ b/components/hal/esp32p4/include/hal/mspi_timing_tuning_ll.h @@ -18,6 +18,7 @@ #include "soc/soc.h" #include "soc/iomux_mspi_pin_reg.h" #include "soc/iomux_mspi_pin_struct.h" +#include "soc/hp_sys_clkrst_reg.h" #ifdef __cplusplus extern "C" { @@ -71,6 +72,20 @@ typedef enum { MSPI_LL_PIN_MAX, } mspi_ll_pin_t; +/** + * Reset the MSPI clock + */ +__attribute__((always_inline)) +static inline void _mspi_timing_ll_reset_mspi(void) +{ + REG_SET_BIT(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_MSPI_AXI); + REG_CLR_BIT(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_MSPI_AXI); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance +#define mspi_timing_ll_reset_mspi(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; _mspi_timing_ll_reset_mspi(__VA_ARGS__) + /** * Set all MSPI DQS phase * From 8639f69ed7a5ff41f81024e83123a3453be49aa8 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Fri, 10 May 2024 16:28:52 +0800 Subject: [PATCH 086/548] fix(wifi): fix the tx issue when mesh packet lifetime remain equal to zero --- components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld | 2 +- components/esp_wifi/lib | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld index 1a8175af900..d5d68d5d49d 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld @@ -74,7 +74,7 @@ lmacReachLongLimit = 0x40000cb8; lmacReachShortLimit = 0x40000cbc; lmacRecycleMPDU = 0x40000cc0; lmacRxDone = 0x40000cc4; -lmacSetTxFrame = 0x40000cc8; +/*lmacSetTxFrame = 0x40000cc8;*/ lmacTxDone = 0x40000ccc; lmacTxFrame = 0x40000cd0; lmacDisableTransmit = 0x40000cd4; diff --git a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld index b69157baaed..a3f9c9586d5 100644 --- a/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld +++ b/components/esp_rom/esp32c61/ld/esp32c61.rom.pp.ld @@ -48,7 +48,7 @@ lmacReachLongLimit = 0x40000b60; lmacReachShortLimit = 0x40000b64; lmacRecycleMPDU = 0x40000b68; lmacRxDone = 0x40000b6c; -lmacSetTxFrame = 0x40000b70; +/*lmacSetTxFrame = 0x40000b70;*/ lmacTxDone = 0x40000b74; lmacTxFrame = 0x40000b78; mac_tx_set_duration = 0x40000b7c; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 97373dacc24..ddb736ba7a6 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 97373dacc24433574f1b13ab6f7f564d50a7c78a +Subproject commit ddb736ba7a670e9500a8df863978319ab55af454 From 02c2356cb11dab0a1052f563c4a72fb66d09e73c Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Tue, 7 May 2024 22:51:22 +0530 Subject: [PATCH 087/548] fix(esp_wifi): Fix issue in selecting FTM compensation with external AP --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index ddb736ba7a6..bcb739c215e 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit ddb736ba7a670e9500a8df863978319ab55af454 +Subproject commit bcb739c215e8c06c42b11a19918414deebcea7e3 From 3dbba47d8c26a8cd984ecf40948bb1cd22013178 Mon Sep 17 00:00:00 2001 From: Shyamal Khachane Date: Tue, 14 May 2024 11:24:43 +0530 Subject: [PATCH 088/548] fix(esp_wifi): Fix issues in NAN datapath establishment 1. Resolve indefinite waiting while stopping NAN 2. Increase NDP response timeout to 8 DW's 3. Set NAN discovery beacon interval to 100 TU's as per Section 9.2 of Wi-Fi Aware Specification v4.0 --- components/esp_wifi/lib | 2 +- components/esp_wifi/wifi_apps/nan_app/src/nan_app.c | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index bcb739c215e..8fd22ddcaf3 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit bcb739c215e8c06c42b11a19918414deebcea7e3 +Subproject commit 8fd22ddcaf33a066d6f87375530475293a4b2630 diff --git a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c index 64b2c5bbf0a..783ce7fbfb8 100644 --- a/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c +++ b/components/esp_wifi/wifi_apps/nan_app/src/nan_app.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,12 +28,13 @@ #define NDP_REJECTED BIT5 /* Macros */ -#define MACADDR_LEN 6 +#define MACADDR_LEN 6 #define MACADDR_EQUAL(a1, a2) (memcmp(a1, a2, MACADDR_LEN)) #define MACADDR_COPY(dst, src) (memcpy(dst, src, MACADDR_LEN)) -#define NAN_DW_INTVL_MS 524 /* NAN DW interval (512 TU's ~= 524 mSec) */ -#define NAN_NDP_RESP_TIMEOUT_DW 4 +#define NAN_DW_INTVL_MS 524 /* NAN DW interval (512 TU's ~= 524 mSec) */ +#define NAN_NDP_RESP_TIMEOUT_DW 8 #define NAN_NDP_RESP_TIMEOUT NAN_NDP_RESP_TIMEOUT_DW*NAN_DW_INTVL_MS +#define NAN_NDP_TERM_TIMEOUT 2*NAN_DW_INTVL_MS /* NDP Termination Timeout - 2 DW*/ /* Global Variables */ static const char *TAG = "nan_app"; @@ -800,7 +801,7 @@ esp_err_t esp_wifi_nan_stop(void) NAN_DATA_UNLOCK(); os_event_group_clear_bits(nan_event_group, NDP_TERMINATED); - os_event_group_wait_bits(nan_event_group, NDP_TERMINATED, pdFALSE, pdFALSE, portMAX_DELAY); + os_event_group_wait_bits(nan_event_group, NDP_TERMINATED, pdFALSE, pdFALSE, pdMS_TO_TICKS(NAN_NDP_TERM_TIMEOUT)); os_event_group_clear_bits(nan_event_group, NDP_TERMINATED); /* Wait for 1 NAN DW interval (512 TU's ~= 524 mSec) for successful termination */ g_wifi_osi_funcs._task_delay(NAN_DW_INTVL_MS/portTICK_PERIOD_MS); From 4cf29dfceffb8c3bb5d494ba442974df1cb7d671 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 25 Apr 2024 19:14:47 +0800 Subject: [PATCH 089/548] fix(wifi): fixed sniffer and espnow issue 1. fix(wifi): fixed sniffer dump fcs error packets fail Closes https://github.com/espressif/esp-idf/issues/10777 2. fix(wifi): fixed the espnow priv parameter get error Closes https://github.com/espressif/esp-idf/issues/13693 --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld | 2 +- components/esp_wifi/lib | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 7f6b0ad0483..c5397d877e6 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -1655,7 +1655,7 @@ hal_sniffer_enable = 0x40001eec; hal_sniffer_disable = 0x40001ef0; /*hal_sniffer_rx_set_promis = 0x40001ef4;*/ hal_sniffer_rx_clr_statistics = 0x40001ef8; -hal_sniffer_set_promis_misc_pkt = 0x40001efc; +/*hal_sniffer_set_promis_misc_pkt = 0x40001efc;*/ tsf_hal_set_tsf_enable = 0x40001f00; tsf_hal_set_tsf_disable = 0x40001f04; tsf_hal_is_tsf_enabled = 0x40001f08; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld index 748ce1d1f7a..7a3eabdb20c 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld @@ -31,7 +31,7 @@ rcUpdateTxDone = 0x4000177c; wDevCheckBlockError = 0x400017b4; /* wDev_IndicateFrame = 0x400017c8;*/ wDev_ProcessFiq = 0x400017f0; -wDev_ProcessRxSucData = 0x400017f4; +/*wDev_ProcessRxSucData = 0x400017f4;*/ /*ppProcTxDone = 0x40001804;*/ pm_tx_data_done_process = 0x40001808; ppMapWaitTxq = 0x40001810; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 8fd22ddcaf3..11a226dcb42 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 8fd22ddcaf33a066d6f87375530475293a4b2630 +Subproject commit 11a226dcb42c092d8b85542ecd0d663dafedac6d From d2551d6e4b158b8030f858a0ac33d6a1f9421fac Mon Sep 17 00:00:00 2001 From: liuning Date: Thu, 16 May 2024 10:39:26 +0800 Subject: [PATCH 090/548] fix(wifi): fix esp32 unrecoverable m f issue --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 11a226dcb42..4816d356ad5 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 11a226dcb42c092d8b85542ecd0d663dafedac6d +Subproject commit 4816d356ad5335c4477426713d820a11687ca4ae From 6da7a46bfaa8edb4ef9730ad1b7414c2e05ea5e8 Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Thu, 16 May 2024 14:45:06 +0800 Subject: [PATCH 091/548] fix(bss_color):fix bss color issues --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 4816d356ad5..c230df3c50e 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 4816d356ad5335c4477426713d820a11687ca4ae +Subproject commit c230df3c50ea1cbbf8104eb8c46c99672ae25e1b From beebbada649d8fec3519fe42e4fe893f1002226f Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Thu, 16 May 2024 19:20:59 +0800 Subject: [PATCH 092/548] fix(wifi):esp32c6 wifi rx statistics is always zero --- components/esp_wifi/lib | 2 +- examples/wifi/iperf/main/iperf_example_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index c230df3c50e..6aa93ec85df 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit c230df3c50ea1cbbf8104eb8c46c99672ae25e1b +Subproject commit 6aa93ec85df32b54dc91c44bb0ef2d5319f757cb diff --git a/examples/wifi/iperf/main/iperf_example_main.c b/examples/wifi/iperf/main/iperf_example_main.c index 83df4b0d232..a856e20ebc0 100644 --- a/examples/wifi/iperf/main/iperf_example_main.c +++ b/examples/wifi/iperf/main/iperf_example_main.c @@ -58,7 +58,7 @@ void iperf_hook_show_wifi_stats(iperf_traffic_type_t type, iperf_status_t status } #endif #if CONFIG_ESP_WIFI_ENABLE_WIFI_RX_STATS - if (type != IPERF_UDP_SERVER) { + if (type != IPERF_UDP_CLIENT) { wifi_cmd_get_rx_statistics(0, NULL); } #endif From e11f0304275be77fb0fa19d05893e2121e71a3b2 Mon Sep 17 00:00:00 2001 From: xuxiao Date: Tue, 7 May 2024 19:07:24 +0800 Subject: [PATCH 093/548] feat(wifi): add itwt teardown status --- components/esp_wifi/include/esp_wifi_he_types.h | 9 +++++++++ components/esp_wifi/lib | 2 +- examples/wifi/itwt/main/itwt_main.c | 8 ++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_he_types.h b/components/esp_wifi/include/esp_wifi_he_types.h index 0baf7a66d15..a6ba90d591d 100644 --- a/components/esp_wifi/include/esp_wifi_he_types.h +++ b/components/esp_wifi/include/esp_wifi_he_types.h @@ -302,9 +302,18 @@ typedef struct { uint64_t target_wake_time; /**< TWT SP start time */ } wifi_event_sta_itwt_setup_t; +/** + * @brief iTWT teardown status + */ +typedef enum { + ITWT_TEARDOWN_FAIL, /**< station sends teardown frame fail */ + ITWT_TEARDOWN_SUCCESS, /**< 1) station successfully sends teardown frame to AP; 2) station receives teardown frame from AP */ +} wifi_itwt_teardown_status_t; + /** Argument structure for WIFI_EVENT_TWT_TEARDOWN event */ typedef struct { uint8_t flow_id; /**< flow id */ + wifi_itwt_teardown_status_t status; /**< itwt teardown status */ } wifi_event_sta_itwt_teardown_t; /** diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 6aa93ec85df..321823002fd 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 6aa93ec85df32b54dc91c44bb0ef2d5319f757cb +Subproject commit 321823002fd7aa2d76b9996b95336495011525db diff --git a/examples/wifi/itwt/main/itwt_main.c b/examples/wifi/itwt/main/itwt_main.c index 1e4e1af461a..cdc87359b09 100644 --- a/examples/wifi/itwt/main/itwt_main.c +++ b/examples/wifi/itwt/main/itwt_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -183,7 +183,11 @@ static void itwt_teardown_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { wifi_event_sta_itwt_teardown_t *teardown = (wifi_event_sta_itwt_teardown_t *) event_data; - ESP_LOGI(TAG, "flow_id %d%s", teardown->flow_id, (teardown->flow_id == 8) ? "(all twt)" : ""); + if (teardown->status == ITWT_TEARDOWN_FAIL) { + ESP_LOGE(TAG, "flow_id %d%s, twt teardown frame tx failed", teardown->flow_id, (teardown->flow_id == 8) ? "(all twt)" : ""); + } else { + ESP_LOGI(TAG, "flow_id %d%s", teardown->flow_id, (teardown->flow_id == 8) ? "(all twt)" : ""); + } } static void itwt_suspend_handler(void *arg, esp_event_base_t event_base, From fdb4197d02a7d3176cfc56cb332290a5d9e98833 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Sat, 18 May 2024 18:34:51 +0530 Subject: [PATCH 094/548] fix(esp_wifi): Add some bugfixes and cleanup in softAP 1. Fix wrong reason code in 'WIFI_EVENT_AP_STADISCONNECTED' event 2. cleanup in softAP for disconnecting connected station 3. Update examples to display reason while processing WIFI_EVENT_AP_STADISCONNECTED event --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 +- components/esp_wifi/include/esp_wifi_types_generic.h | 2 +- components/esp_wifi/lib | 2 +- examples/bluetooth/blufi/main/blufi_example_main.c | 2 +- examples/protocols/http_server/captive_portal/main/main.c | 4 ++-- .../wifi/getting_started/softAP/main/softap_example_main.c | 4 ++-- examples/wifi/softap_sta/main/softap_sta.c | 6 +++--- examples/wifi/wps_softap_registrar/main/wps.c | 6 +++--- tools/test_apps/peripherals/i2c_wifi/main/i2c_wifi_main.c | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index c5397d877e6..5276d60ac0d 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -1849,7 +1849,7 @@ ieee80211_alloc_tx_buf = 0x40002108; /* ieee80211_send_nulldata = 0x40002110; */ /* ieee80211_setup_robust_mgmtframe = 0x40002114; */ ieee80211_encap_null_data = 0x4000211c; -ieee80211_send_deauth = 0x40002120; +ieee80211_send_deauth_no_bss = 0x40002120; ieee80211_alloc_deauth = 0x40002124; ieee80211_send_proberesp = 0x40002128; ieee80211_getcapinfo = 0x40002130; diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 754672d84e2..0cea6304580 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -903,7 +903,7 @@ typedef struct { uint8_t mac[6]; /**< MAC address of the station disconnects to soft-AP */ uint8_t aid; /**< the aid that soft-AP gave to the station disconnects to */ bool is_mesh_child; /**< flag to identify mesh child */ - uint8_t reason; /**< reason of disconnection */ + uint16_t reason; /**< reason of disconnection */ } wifi_event_ap_stadisconnected_t; /** Argument structure for WIFI_EVENT_AP_PROBEREQRECVED event */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 321823002fd..482ab97ae35 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 321823002fd7aa2d76b9996b95336495011525db +Subproject commit 482ab97ae352dfdbaed028338a9ee45d7f2e6127 diff --git a/examples/bluetooth/blufi/main/blufi_example_main.c b/examples/bluetooth/blufi/main/blufi_example_main.c index 301a9ea72b0..3e009078303 100644 --- a/examples/bluetooth/blufi/main/blufi_example_main.c +++ b/examples/bluetooth/blufi/main/blufi_example_main.c @@ -246,7 +246,7 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base, } case WIFI_EVENT_AP_STADISCONNECTED: { wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; - BLUFI_INFO("station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid); + BLUFI_INFO("station "MACSTR" leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason); break; } diff --git a/examples/protocols/http_server/captive_portal/main/main.c b/examples/protocols/http_server/captive_portal/main/main.c index 6111a5b37a8..8dee238e86b 100644 --- a/examples/protocols/http_server/captive_portal/main/main.c +++ b/examples/protocols/http_server/captive_portal/main/main.c @@ -39,8 +39,8 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, MAC2STR(event->mac), event->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data; - ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d", - MAC2STR(event->mac), event->aid); + ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d, reason=%d", + MAC2STR(event->mac), event->aid, event->reason); } } diff --git a/examples/wifi/getting_started/softAP/main/softap_example_main.c b/examples/wifi/getting_started/softAP/main/softap_example_main.c index 4eba17b50b9..485d74e90b3 100644 --- a/examples/wifi/getting_started/softAP/main/softap_example_main.c +++ b/examples/wifi/getting_started/softAP/main/softap_example_main.c @@ -39,8 +39,8 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base, MAC2STR(event->mac), event->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", - MAC2STR(event->mac), event->aid); + ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d", + MAC2STR(event->mac), event->aid, event->reason); } } diff --git a/examples/wifi/softap_sta/main/softap_sta.c b/examples/wifi/softap_sta/main/softap_sta.c index 863bb963a49..e10b21ec8ad 100644 --- a/examples/wifi/softap_sta/main/softap_sta.c +++ b/examples/wifi/softap_sta/main/softap_sta.c @@ -90,8 +90,8 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, MAC2STR(event->mac), event->aid); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data; - ESP_LOGI(TAG_AP, "Station "MACSTR" left, AID=%d", - MAC2STR(event->mac), event->aid); + ESP_LOGI(TAG_AP, "Station "MACSTR" left, AID=%d, reason:%d", + MAC2STR(event->mac), event->aid, event->reason); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { esp_wifi_connect(); ESP_LOGI(TAG_STA, "Station started"); @@ -145,7 +145,7 @@ esp_netif_t *wifi_init_sta(void) .password = EXAMPLE_ESP_WIFI_STA_PASSWD, .scan_method = WIFI_ALL_CHANNEL_SCAN, .failure_retry_cnt = EXAMPLE_ESP_MAXIMUM_RETRY, - /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8). + /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (password len => 8). * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards. diff --git a/examples/wifi/wps_softap_registrar/main/wps.c b/examples/wifi/wps_softap_registrar/main/wps.c index b7f5ef8d0d2..31ea2308586 100644 --- a/examples/wifi/wps_softap_registrar/main/wps.c +++ b/examples/wifi/wps_softap_registrar/main/wps.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -62,8 +62,8 @@ static void wifi_event_handler(void* arg, esp_event_base_t event_base, { ESP_LOGI(TAG, "WIFI_EVENT_AP_STADISCONNECTED"); wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; - ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", - MAC2STR(event->mac), event->aid); + ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d", + MAC2STR(event->mac), event->aid, event->reason); } break; case WIFI_EVENT_AP_STACONNECTED: diff --git a/tools/test_apps/peripherals/i2c_wifi/main/i2c_wifi_main.c b/tools/test_apps/peripherals/i2c_wifi/main/i2c_wifi_main.c index 4f0cdcd7dce..fcf1770a243 100644 --- a/tools/test_apps/peripherals/i2c_wifi/main/i2c_wifi_main.c +++ b/tools/test_apps/peripherals/i2c_wifi/main/i2c_wifi_main.c @@ -56,7 +56,7 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid); } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *) event_data; - ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid); + ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d, reason=%d", MAC2STR(event->mac), event->aid, event->reason); } } From c046d87561416b79b9e64ca10bc12b90bd4d0cf2 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Mon, 15 Apr 2024 17:27:01 +0800 Subject: [PATCH 095/548] docs(wifi): update the docmentation for mesh API --- components/esp_wifi/include/esp_mesh.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/components/esp_wifi/include/esp_mesh.h b/components/esp_wifi/include/esp_mesh.h index 44936538298..18e55c2dfdb 100644 --- a/components/esp_wifi/include/esp_mesh.h +++ b/components/esp_wifi/include/esp_mesh.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -141,7 +141,7 @@ extern "C" { #define MESH_ASSOC_FLAG_STA_VOTED (0x04) /**< station vote done, set when connect to router */ #define MESH_ASSOC_FLAG_NETWORK_FREE (0x08) /**< no root in current network */ #define MESH_ASSOC_FLAG_STA_VOTE_EXPIRE (0x10) /**< the voted address is expired, means the voted device lose the chance to be root */ -#define MESH_ASSOC_FLAG_ROOTS_FOUND (0x20) /**< roots conflict is found, means that thre are at least two roots in the mesh network */ +#define MESH_ASSOC_FLAG_ROOTS_FOUND (0x20) /**< roots conflict is found, means that there are at least two roots in the mesh network */ #define MESH_ASSOC_FLAG_ROOT_FIXED (0x40) /**< the root is fixed in the mesh network */ /** @@ -216,7 +216,7 @@ typedef enum { MESH_ROOT, /**< the only sink of the mesh network. Has the ability to access external IP network */ MESH_NODE, /**< intermediate device. Has the ability to forward packets over the mesh network */ MESH_LEAF, /**< has no forwarding ability */ - MESH_STA, /**< connect to router with a standlone Wi-Fi station mode, no network expansion capability */ + MESH_STA, /**< connect to router with a standalone Wi-Fi station mode, no network expansion capability */ } mesh_type_t; /** @@ -642,14 +642,16 @@ esp_err_t esp_mesh_stop(void); * - Field size should not exceed MESH_MPS. Note that the size of one mesh packet should not exceed MESH_MTU. * - Field proto should be set to data protocol in use (default is MESH_PROTO_BIN for binary). * - Field tos should be set to transmission tos (type of service) in use (default is MESH_TOS_P2P for point-to-point reliable). + * - If the packet is to the root, MESH_TOS_P2P must be set to ensure reliable transmission. + * - As long as the MESH_TOS_P2P is set, the API is blocking, even if the flag is set with MESH_DATA_NONBLOCK. + * - As long as the MESH_TOS_DEF is set, the API is non-blocking. * @param[in] flag bitmap for data sent + * - Flag is at least one of the three MESH_DATA_P2P/MESH_DATA_FROMDS/MESH_DATA_TODS, which represents the direction of packet sending. * - Speed up the route search - * - If the packet is to the root and "to" parameter is NULL, set this parameter to 0. * - If the packet is to an internal device, MESH_DATA_P2P should be set. * - If the packet is to the root ("to" parameter isn't NULL) or to external IP network, MESH_DATA_TODS should be set. * - If the packet is from the root to an internal device, MESH_DATA_FROMDS should be set. - * - Specify whether this API is block or non-block, block by default - * - If needs non-blocking, MESH_DATA_NONBLOCK should be set. Otherwise, may use esp_mesh_send_block_time() to specify a blocking time. + * - Specify whether this API is blocking or non-blocking, blocking by default. * - In the situation of the root change, MESH_DATA_DROP identifies this packet can be dropped by the new root * for upstream data to external IP network, we try our best to avoid data loss caused by the root change, but * there is a risk that the new root is running out of memory because most of memory is occupied by the pending data which @@ -684,6 +686,7 @@ esp_err_t esp_mesh_send(const mesh_addr_t *to, const mesh_data_t *data, int flag, const mesh_opt_t opt[], int opt_count); /** * @brief Set blocking time of esp_mesh_send() + * - Suggest to set the blocking time to at least 5s when the environment is poor. Otherwise, esp_mesh_send() may timeout frequently. * * @attention This API shall be called before mesh is started. * @@ -1202,6 +1205,7 @@ int esp_mesh_get_xon_qsize(void); /** * @brief Set whether allow more than one root existing in one network + * - The default value is true, that is, multiple roots are allowed. * * @param[in] allowed allow or not * From 686878497e70251e6419aa408e2d2012b7cfd9bb Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Fri, 10 May 2024 12:12:38 +0800 Subject: [PATCH 096/548] docs: update wifi iperf README --- examples/wifi/iperf/README.md | 91 ++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/examples/wifi/iperf/README.md b/examples/wifi/iperf/README.md index b6ed09ea29c..b42b7c44405 100644 --- a/examples/wifi/iperf/README.md +++ b/examples/wifi/iperf/README.md @@ -4,61 +4,74 @@ # Iperf Example ## Note about iperf version -The iperf example doesn't support all features in standard iperf. It's compitable with iperf version 2.x. +The iperf example doesn't support all features in standard iperf. It's compatible with iperf version 2.x. -## Note about 80MHz flash frequency +- Refer to the components registry iperf-cmd page for more information: https://components.espressif.com/components/espressif/iperf-cmd + +## Note about 80MHz flash frequency (ESP32) The iperf can get better throughput if the SPI flash frequency is set to 80MHz, but the system may crash in 80MHz mode for ESP-WROVER-KIT. Removing R140~R145 from the board can fix this issue. Currently the default SPI frequency is set to 40MHz, if you want to change the SPI flash frequency to 80MHz, please make sure R140~R145 are removed from ESP-WROVER-KIT or use ESP32 DevKitC. ## Introduction This example implements the protocol used by the common performance measurement tool [iPerf](https://iperf.fr/). -Performance can be measured between two ESP32s running this example, or between a single ESP32 and a computer running the iPerf tool +Performance can be measured between two ESP targets running this example, or between a single ESP target and a computer running the iPerf tool Demo steps to test station TCP Tx performance: -1. Configure in `menuconfig` which serial output you are using. Execute `idf.py menuconfig` and go to `Component config/ESP System Settings/Channel for console output`, then select the appropiate interface. By default the UART0 interface is used, this means that for example in the ESP32-S3-DevKitC-1 or ESP32-C6-DevKitC-1 you should connect to the micro-usb connector labeled as UART and not to the one labeled as USB. To use the one labeled as USB you should change the aforementioned setting to `USB Serial/JTAG Controller`. -2. Build the iperf example with sdkconfig.defaults, which contains performance test specific configurations +- Configure in `menuconfig` which serial output you are using. Execute `idf.py menuconfig` and go to `Component config/ESP System Settings/Channel for console output`, then select the appropriate interface. By default the UART0 interface is used, this means that for example in the ESP32-S3-DevKitC-1 or ESP32-C6-DevKitC-1 you should connect to the micro-usb connector labeled as UART and not to the one labeled as USB. To use the one labeled as USB you should change the aforementioned setting to `USB Serial/JTAG Controller`. -3. Run the demo as station mode and join the target AP - sta ssid password +- Build and flash the iperf example with `sdkconfig.defaults`, which contains performance test specific configurations + - Use `help` for detailed command usage information. -4. Run iperf as server on AP side - iperf -s -i 3 +- Run the demo as station mode and join the target AP + - `sta_connect ` + - NOTE: the dut is started in station mode by default. If you want to use the dut as softap, please set wifi mode first: + - `wifi_mode ap` + - `ap_set ` -5. Run iperf as client on ESP32 side - iperf -c 192.168.10.42 -i 3 -t 60 +- Run iperf as server on AP side + - `iperf -s -i 3` -The console output, which is printed by station TCP RX throughput test, looks like: +- Run iperf as client on ESP side + - `iperf -c 192.168.10.42 -i 3 -t 60` ->iperf> sta aptest -> ->I (5325) iperf: sta connecting to 'aptest' -> ->iperf> I (6017) event: ip: 192.168.10.248, mask: 255.255.255.0, gw: 192.168.10.1 -> ->iperf> iperf -s -i 3 -t 1000 -> ->I (14958) iperf: mode=tcp-server sip=192.168.10.248:5001, dip=0.0.0.0:5001, interval=3, time=1000 -> ->Interval Bandwidth -> ->iperf> accept: 192.168.10.42,62958 -> ->0- 3 sec 8.43 Mbits/sec -> ->3- 6 sec 36.16 Mbits/sec -> ->6- 9 sec 36.22 Mbits/sec -> ->9- 12 sec 36.44 Mbits/sec -> ->12- 15 sec 36.25 Mbits/sec -> ->15- 18 sec 24.36 Mbits/sec -> ->18- 21 sec 27.79 Mbits/sec +The console output, which is printed by station TCP RX throughput test, looks like: + ``` + iperf> sta_connect testap-11 ******** + I (36836) WIFI: Connecting to testap-11... + I (36839) WIFI: DONE.WIFI_CONNECT_START,OK. + iperf> I (39248) WIFI: WIFI_EVENT_STA_DISCONNECTED! reason: 201 + I (39249) WIFI: trying to reconnect... + I (41811) wifi:new:<11,2>, old:<1,0>, ap:<255,255>, sta:<11,2>, prof:1, snd_ch_cfg:0x0 + I (41813) wifi:state: init -> auth (0xb0) + I (41816) wifi:state: auth -> assoc (0x0) + I (41840) wifi:state: assoc -> run (0x10) + I (41847) wifi:idx:0 (ifx:0, 30:5a:3a:74:90:f0), tid:0, ssn:0, winSize:64 + I (41914) wifi:connected with testap-11, aid = 1, channel 11, 40D, bssid = 30:5a:3a:74:90:f0 + I (41915) wifi:security: WPA2-PSK, phy: bgn, rssi: -34 + I (41926) wifi:pm start, type: 0 + + I (41927) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us + I (41929) WIFI: WIFI_EVENT_STA_CONNECTED! + I (41983) wifi:AP's beacon interval = 102400 us, DTIM period = 3 + I (42929) esp_netif_handlers: sta ip: 192.168.1.79, mask: 255.255.255.0, gw: 192.168.1.1 + I (42930) WIFI: IP_EVENT_STA_GOT_IP: Interface "sta" address: 192.168.1.79 + I (42942) WIFI: - IPv4 address: 192.168.1.79, + iperf> + iperf> iperf -s -i 2 + I (84810) IPERF: mode=tcp-server sip=0.0.0.0:5001, dip=0.0.0.0:5001, interval=2, time=30 + I (84812) iperf: Socket created + iperf> I (87967) iperf: accept: 192.168.1.2,43726 + + Interval Bandwidth + 0.0- 2.0 sec 24.36 Mbits/sec + 2.0- 4.0 sec 23.38 Mbits/sec + 4.0- 6.0 sec 24.02 Mbits/sec + 6.0- 8.0 sec 25.27 Mbits/sec + 8.0-10.0 sec 23.84 Mbits/sec + ``` Steps to test station/soft-AP TCP/UDP RX/TX throughput are similar as test steps in station TCP TX. From 68be49d2cf1ade352c4d74e244ce27ddf162b01e Mon Sep 17 00:00:00 2001 From: muhaidong Date: Sun, 28 Apr 2024 20:00:37 +0800 Subject: [PATCH 097/548] fix(wifi): fixed scan get ap number issue --- examples/wifi/scan/main/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wifi/scan/main/scan.c b/examples/wifi/scan/main/scan.c index 19e2c41555c..2876fb95a50 100644 --- a/examples/wifi/scan/main/scan.c +++ b/examples/wifi/scan/main/scan.c @@ -185,8 +185,8 @@ static void wifi_scan(void) #endif /*USE_CHANNEL_BTIMAP*/ ESP_LOGI(TAG, "Max AP number ap_info can hold = %u", number); - ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count)); + ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); ESP_LOGI(TAG, "Total APs scanned = %u, actual AP number ap_info holds = %u", ap_count, number); for (int i = 0; i < number; i++) { ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid); From e53ca8e018dc0dd76f7d602ffb305a2de1af56af Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Wed, 15 May 2024 10:50:23 +0800 Subject: [PATCH 098/548] fix(lp_core_test): fixed race-condition in lp core tests --- .../test_apps/lp_core/main/lp_core/test_main.c | 2 -- .../ulp/test_apps/lp_core/main/test_lp_core.c | 16 ++++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main.c index beff51564c4..b9adad2670f 100644 --- a/components/ulp/test_apps/lp_core/main/lp_core/test_main.c +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_main.c @@ -71,11 +71,9 @@ void handle_commands(lp_core_test_commands_t cmd) break; case LP_CORE_NO_COMMAND: - main_cpu_reply = LP_CORE_COMMAND_NOK; break; default: - main_cpu_reply = LP_CORE_COMMAND_NOK; break; } } diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core.c b/components/ulp/test_apps/lp_core/main/test_lp_core.c index e27febe2e60..c1ebaaaf0e0 100644 --- a/components/ulp/test_apps/lp_core/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/main/test_lp_core.c @@ -47,6 +47,12 @@ static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_ } +static void clear_test_cmds(void) +{ + ulp_main_cpu_command = LP_CORE_NO_COMMAND; + ulp_command_resp = LP_CORE_NO_COMMAND; +} + TEST_CASE("LP core and main CPU are able to exchange data", "[lp_core]") { const uint32_t test_data = 0x12345678; @@ -76,9 +82,7 @@ TEST_CASE("LP core and main CPU are able to exchange data", "[lp_core]") printf("data out: 0x%" PRIx32 ", expected: 0x%" PRIx32 " \n", ulp_test_data_out, test_data); TEST_ASSERT(test_data == ulp_test_data_out); - /* Clear test data */ - ulp_main_cpu_command = LP_CORE_NO_COMMAND; - ulp_command_resp = LP_CORE_NO_COMMAND; + clear_test_cmds(); } TEST_CASE("Test LP core delay", "[lp_core]") @@ -113,9 +117,7 @@ TEST_CASE("Test LP core delay", "[lp_core]") printf("Waited for %" PRIi64 "us, expected: %" PRIi32 "us\n", diff, delay_period_us); TEST_ASSERT_INT_WITHIN(delta_us, delay_period_us, diff); - /* Clear test data */ - ulp_main_cpu_command = LP_CORE_NO_COMMAND; - ulp_command_resp = LP_CORE_NO_COMMAND; + clear_test_cmds(); } #define LP_TIMER_TEST_DURATION_S (5) @@ -210,6 +212,8 @@ static void check_reset_reason_and_sleep_duration(void) printf("CPU slept for %"PRIi64" ms, expected it to sleep approx %"PRIi64" ms\n", sleep_duration, expected_sleep_duration_ms); /* Rough estimate, as CPU spends quite some time waking up, but will test if lp core is waking up way too often etc */ TEST_ASSERT_INT_WITHIN_MESSAGE(1000, expected_sleep_duration_ms, sleep_duration, "LP Core did not wake up the expected number of times"); + + clear_test_cmds(); } TEST_CASE_MULTIPLE_STAGES("LP Timer can wakeup lp core periodically during deep sleep", "[ulp]", From f3a73cbce34c578daefc4f28e49750421d15bb22 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Mon, 13 May 2024 14:47:24 +0800 Subject: [PATCH 099/548] docs(sys-time): update link to hw design guidelines --- docs/en/api-reference/system/system_time.rst | 3 +-- docs/zh_CN/api-reference/system/system_time.rst | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/en/api-reference/system/system_time.rst b/docs/en/api-reference/system/system_time.rst index f959f1c42c5..e3b1581253f 100644 --- a/docs/en/api-reference/system/system_time.rst +++ b/docs/en/api-reference/system/system_time.rst @@ -8,7 +8,6 @@ System Time {IDF_TARGET_INT_OSC_FRE_DIVIDED:default="Not updated", esp32="about 33 kHz", esp32s2="about 33 kHz", esp32s3="about 68 kHz", esp32c3="about 68 kHz", esp32c2="about 68 kHz"} {IDF_TARGET_EXT_CRYSTAL_PIN:default="Not updated", esp32="32K_XP and 32K_XN", esp32s2="XTAL_32K_P and XTAL_32K_N", esp32s3="XTAL_32K_P and XTAL_32K_N", esp32c3="XTAL_32K_P and XTAL_32K_N", esp32c6="XTAL_32K_P and XTAL_32K_N", esp32h2="XTAL_32K_P and XTAL_32K_N", esp32p4="XTAL_32K_P and XTAL_32K_N"} {IDF_TARGET_EXT_OSC_PIN:default="Not updated", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} -{IDF_TARGET_HARDWARE_DESIGN_URL:default="Not updated",esp32="`ESP32 Hardware Design Guidelines `_", esp32s2="`ESP32-S2 Hardware Design Guidelines `_", esp32s3="`ESP32-S3 Hardware Design Guidelines `_", esp32c3="`ESP32-C3 Hardware Design Guidelines `_", esp32c6="`ESP32-C6 Hardware Design Guidelines `_", esp32c2="`ESP8684 Hardware Design Guidelines `_", esp32h2="`ESP32-H2 Hardware Design Guidelines `_", esp32p4="`ESP32-P4 Hardware Design Guidelines `_"} Overview @@ -51,7 +50,7 @@ The RTC timer has the following clock sources: The choice depends on your requirements for system time accuracy and power consumption in sleep modes. To modify the RTC clock source, set :ref:`CONFIG_RTC_CLK_SRC` in project configuration. -More details about the wiring requirements for the external crystal or external oscillator, please refer to {IDF_TARGET_HARDWARE_DESIGN_URL}. +More details about the wiring requirements for the external crystal or external oscillator, please refer to the `Hardware Design Guidelines `_. Get Current Time ---------------- diff --git a/docs/zh_CN/api-reference/system/system_time.rst b/docs/zh_CN/api-reference/system/system_time.rst index f14dc188615..48f9d678e0e 100644 --- a/docs/zh_CN/api-reference/system/system_time.rst +++ b/docs/zh_CN/api-reference/system/system_time.rst @@ -8,7 +8,6 @@ {IDF_TARGET_INT_OSC_FRE_DIVIDED:default="未更新", esp32="约 33 kHz", esp32s2="约 33 kHz", esp32s3="约 68 kHz", esp32c3="约 68 kHz", esp32c2="约 68 kHz"} {IDF_TARGET_EXT_CRYSTAL_PIN:default="未更新", esp32="32K_XP 和 32K_XN", esp32s2="XTAL_32K_P 和 XTAL_32K_N", esp32s3="XTAL_32K_P 和 XTAL_32K_N", esp32c3="XTAL_32K_P 和 XTAL_32K_N", esp32c6="XTAL_32K_P 和 XTAL_32K_N", esp32h2="XTAL_32K_P 和 XTAL_32K_N", esp32p4="XTAL_32K_P 和 XTAL_32K_N"} {IDF_TARGET_EXT_OSC_PIN:default="未更新", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} -{IDF_TARGET_HARDWARE_DESIGN_URL:default="未更新", esp32="`ESP32 硬件设计指南 `_", esp32s2="`ESP32-S2 硬件设计指南 `_", esp32s3="`ESP32-S3 硬件设计指南 `_", esp32c3="`ESP32-C3 硬件设计指南 `_", esp32c2="`ESP8684 硬件设计指南 `_", esp32c6="`ESP32-C6 硬件设计指南 `_", esp32h2="`ESP32-H2 硬件设计指南 `_", esp32p4="`ESP32-P4 硬件设计指南 `_"} 概述 @@ -51,7 +50,7 @@ RTC 定时器有以下时钟源: 时钟源的选择取决于系统时间精度要求和睡眠模式下的功耗要求。要修改 RTC 时钟源,请在项目配置中设置 :ref:`CONFIG_RTC_CLK_SRC`。 -想要了解外置晶振或外置振荡器的更多布线要求,请参考 {IDF_TARGET_HARDWARE_DESIGN_URL}。 +想要了解外置晶振或外置振荡器的更多布线要求,请参考 `硬件设计指南 `_。 获取当前时间 -------------- From 856a299ba873269c4ca3c258c5bd4e0fd90500ab Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Mon, 22 Apr 2024 18:44:28 +0530 Subject: [PATCH 100/548] fix: reset redirect counter for using same handler Closes https://github.com/espressif/esp-idf/issues/13633 --- components/esp_http_client/esp_http_client.c | 12 +++++++++- .../esp_http_client/include/esp_http_client.h | 24 ++++++++++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 372d86e900f..36ed29f2e1f 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -957,9 +957,19 @@ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client) return err; } +esp_err_t esp_http_client_reset_redirect_counter(esp_http_client_handle_t client) +{ + if (client == NULL) { + return ESP_ERR_INVALID_ARG; + } + client->redirect_counter = 0; + return ESP_OK; +} + static esp_err_t esp_http_check_response(esp_http_client_handle_t client) { if (client->response->status_code >= HttpStatus_Ok && client->response->status_code < HttpStatus_MultipleChoices) { + client->redirect_counter = 0; return ESP_OK; } if (client->redirect_counter >= client->max_redirection_count) { diff --git a/components/esp_http_client/include/esp_http_client.h b/components/esp_http_client/include/esp_http_client.h index 1c50a1fa5ae..bb9319e42d1 100644 --- a/components/esp_http_client/include/esp_http_client.h +++ b/components/esp_http_client/include/esp_http_client.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -36,7 +36,7 @@ typedef enum { HTTP_EVENT_ERROR = 0, /*!< This event occurs when there are any errors during execution */ HTTP_EVENT_ON_CONNECTED, /*!< Once the HTTP has been connected to the server, no data exchange has been performed */ HTTP_EVENT_HEADERS_SENT, /*!< After sending all the headers to the server */ - HTTP_EVENT_HEADER_SENT = HTTP_EVENT_HEADERS_SENT, /*!< This header has been kept for backward compatability + HTTP_EVENT_HEADER_SENT = HTTP_EVENT_HEADERS_SENT, /*!< This header has been kept for backward compatibility and will be deprecated in future versions esp-idf */ HTTP_EVENT_ON_HEADER, /*!< Occurs when receiving each header sent from the server */ HTTP_EVENT_ON_DATA, /*!< Occurs when receiving data from the server, possibly multiple portions of the packet */ @@ -125,7 +125,7 @@ typedef enum { typedef enum { HTTP_AUTH_TYPE_NONE = 0, /*!< No authention */ HTTP_AUTH_TYPE_BASIC, /*!< HTTP Basic authentication */ - HTTP_AUTH_TYPE_DIGEST, /*!< HTTP Disgest authentication */ + HTTP_AUTH_TYPE_DIGEST, /*!< HTTP Digest authentication */ } esp_http_client_auth_type_t; /** @@ -249,7 +249,7 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co * must be set while making a call to esp_http_client_init() API. * You can do any amount of calls to esp_http_client_perform while using the same esp_http_client_handle_t. The underlying connection may be kept open if the server allows it. * If you intend to transfer more than one file, you are even encouraged to do so. - * esp_http_client will then attempt to re-use the same connection for the following transfers, thus making the operations faster, less CPU intense and using less network resources. + * esp_http_client will then attempt to reuse the same connection for the following transfers, thus making the operations faster, less CPU intense and using less network resources. * Just note that you will have to use `esp_http_client_set_**` between the invokes to set options for the following esp_http_client_perform. * * @note You must never call this function simultaneously from two places using the same client handle. @@ -612,7 +612,7 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h * @brief Set redirection URL. * When received the 30x code from the server, the client stores the redirect URL provided by the server. * This function will set the current URL to redirect to enable client to execute the redirection request. - * When `disable_auto_redirect` is set, the client will not call this function but the event `HTTP_EVENT_REDIRECT` will be dispatched giving the user contol over the redirection event. + * When `disable_auto_redirect` is set, the client will not call this function but the event `HTTP_EVENT_REDIRECT` will be dispatched giving the user control over the redirection event. * * @param[in] client The esp_http_client handle * @@ -622,6 +622,18 @@ esp_http_client_transport_t esp_http_client_get_transport_type(esp_http_client_h */ esp_err_t esp_http_client_set_redirection(esp_http_client_handle_t client); +/** + * @brief Reset the redirection counter. + * This is useful to reset redirect counter in cases where the same handle is used for multiple requests. + * + * @param[in] client The esp_http_client handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG + */ +esp_err_t esp_http_client_reset_redirect_counter(esp_http_client_handle_t client); + /** * @brief On receiving a custom authentication header, this API can be invoked to set the * authentication information from the header. This API can be called from the event @@ -676,7 +688,7 @@ int esp_http_client_read_response(esp_http_client_handle_t client, char *buffer, /** * @brief Process all remaining response data * This uses an internal buffer to repeatedly receive, parse, and discard response data until complete data is processed. - * As no additional user-supplied buffer is required, this may be preferrable to `esp_http_client_read_response` in situations where the content of the response may be ignored. + * As no additional user-supplied buffer is required, this may be preferable to `esp_http_client_read_response` in situations where the content of the response may be ignored. * * @param[in] client The esp_http_client handle * @param len Length of data discarded From eb8dad2fa668ef8b676afcf2636fc80c9bb351dc Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Mon, 6 May 2024 14:17:36 +0530 Subject: [PATCH 101/548] fix: Add warning to enable LWIP_NETIF_LOOPBACK to use control socket API Closes https://github.com/espressif/esp-idf/issues/13659 --- components/esp_http_server/src/util/ctrl_sock.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/components/esp_http_server/src/util/ctrl_sock.c b/components/esp_http_server/src/util/ctrl_sock.c index 65d6e7f972d..36eb5b055bb 100644 --- a/components/esp_http_server/src/util/ctrl_sock.c +++ b/components/esp_http_server/src/util/ctrl_sock.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,7 +11,7 @@ #include #include #include "sdkconfig.h" - +#include "esp_log.h" #include "ctrl_sock.h" #if CONFIG_IDF_TARGET_LINUX @@ -22,11 +22,20 @@ #define IPV6_ENABLED CONFIG_LWIP_IPV6 #endif // !CONFIG_IDF_TARGET_LINUX +#if !CONFIG_LWIP_NETIF_LOOPBACK +static const char *TAG = "esp_http_server"; +#endif + /* Control socket, because in some network stacks select can't be woken up any * other way */ int cs_create_ctrl_sock(int port) { +#if !CONFIG_LWIP_NETIF_LOOPBACK + ESP_LOGE(TAG, "Please enable LWIP_NETIF_LOOPBACK for %s API", __func__); + return -1; +#endif + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { return -1; From 5899701b683e8856fe56f018fba06917ca4fa908 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 19 Apr 2024 12:12:53 +0800 Subject: [PATCH 102/548] feat(esp_pm): fix esp32p4 cpu powerdown kconfig dependency error --- .../include/esp_private/sleep_cpu.h | 13 ++++++------ components/esp_hw_support/include/esp_sleep.h | 8 +++++--- .../esp_hw_support/lowpower/CMakeLists.txt | 3 ++- .../cpu_retention/port/esp32c3/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32c5/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32c6/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32h2/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32p4/sleep_cpu.c | 20 +++++++++---------- .../cpu_retention/port/esp32s3/sleep_cpu.c | 2 +- components/esp_hw_support/sleep_modes.c | 16 +++++++-------- components/esp_pm/Kconfig | 5 +++-- components/esp_pm/linker.lf | 2 +- components/esp_pm/pm_impl.c | 2 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + 15 files changed, 46 insertions(+), 38 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/sleep_cpu.h b/components/esp_hw_support/include/esp_private/sleep_cpu.h index 136c0341031..cc2dd35980b 100644 --- a/components/esp_hw_support/include/esp_private/sleep_cpu.h +++ b/components/esp_hw_support/include/esp_private/sleep_cpu.h @@ -9,6 +9,7 @@ #include #include "sdkconfig.h" #include "esp_err.h" +#include "esp_sleep.h" #include "soc/soc_caps.h" #ifdef __cplusplus @@ -21,7 +22,7 @@ extern "C" { * This file contains declarations of cpu retention related functions in light sleep mode. */ -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP || SOC_PM_SUPPORT_CPU_PD +#if ESP_SLEEP_POWER_DOWN_CPU || SOC_PM_SUPPORT_CPU_PD /** * @brief Whether to allow the cpu power domain to be powered off. * @@ -31,7 +32,7 @@ extern "C" { bool cpu_domain_pd_allowed(void); #endif -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU /** * @brief Configure the parameters of the CPU domain during the sleep process * @@ -64,9 +65,9 @@ void sleep_disable_cpu_retention(void); esp_err_t esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp); #endif // SOC_PM_CPU_RETENTION_BY_SW -#endif // CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#endif // ESP_SLEEP_POWER_DOWN_CPU -#if !CONFIG_FREERTOS_UNICORE && CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU /** * Do sleep prepare for other smp cores */ @@ -77,13 +78,11 @@ void sleep_smp_cpu_sleep_prepare(void); */ void sleep_smp_cpu_wakeup_prepare(void); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP /** * Notify the other core that this sleep does not require retention. */ void esp_sleep_cpu_skip_retention(void); -#endif // CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP -#endif // !CONFIG_FREERTOS_UNICORE && CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#endif // !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU #ifdef __cplusplus } diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 018820e364c..61579a8e4a5 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -133,6 +133,8 @@ enum { ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION = ESP_ERR_INVALID_ARG, }; +#define ESP_SLEEP_POWER_DOWN_CPU (CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP || (SOC_CPU_IN_TOP_DOMAIN && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)) + /** * @brief Disable wakeup source * @@ -713,7 +715,7 @@ void esp_default_wake_deep_sleep(void); */ void esp_deep_sleep_disable_rom_logging(void); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU #if SOC_PM_CPU_RETENTION_BY_RTCCNTL /** @@ -752,7 +754,7 @@ esp_err_t esp_sleep_cpu_retention_init(void); * Release system retention memory. */ esp_err_t esp_sleep_cpu_retention_deinit(void); -#endif // CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#endif // ESP_SLEEP_POWER_DOWN_CPU /** * @brief Configure to isolate all GPIO pins in sleep state diff --git a/components/esp_hw_support/lowpower/CMakeLists.txt b/components/esp_hw_support/lowpower/CMakeLists.txt index 6727506080c..3ba4d4d6a8b 100644 --- a/components/esp_hw_support/lowpower/CMakeLists.txt +++ b/components/esp_hw_support/lowpower/CMakeLists.txt @@ -4,7 +4,8 @@ endif() set(srcs) -if(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP) +if(CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP OR + (CONFIG_SOC_CPU_IN_TOP_DOMAIN AND CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)) list(APPEND srcs "cpu_retention/port/${target}/sleep_cpu.c") if(CONFIG_SOC_PM_CPU_RETENTION_BY_SW) list(APPEND srcs "cpu_retention/port/${target}/sleep_cpu_asm.S") diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c index 4547bd1f9e0..9fdd1d3a768 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c @@ -102,7 +102,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c index d12d2d47f80..fbb67fd0895 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c @@ -489,7 +489,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c index 87642de1d70..e97de1c0ebe 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c @@ -532,7 +532,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c index 3734807b885..b30913b2331 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c @@ -532,7 +532,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index f27af1d5dc4..cefc1f70cb8 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -41,7 +41,7 @@ #endif -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE #include #include "soc/hp_system_reg.h" typedef enum { @@ -162,7 +162,7 @@ static esp_err_t esp_sleep_cpu_retention_init_impl(void) s_cpu_retention.retent.clic_frame[core_id] = (cpu_domain_dev_sleep_frame_t *)frame; } } -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE for (uint8_t core_id = 0; core_id < portNUM_PROCESSORS; ++core_id) { atomic_init(&s_smp_retention_state[core_id], SMP_IDLE); } @@ -414,7 +414,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_DONE); while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_BACKUP_DONE) { ; @@ -438,7 +438,7 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0); uint32_t mstatus = save_mstatus_and_disable_global_int(); uint8_t core_id = esp_cpu_get_core_id(); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_START); #endif cpu_domain_dev_regs_save(s_cpu_retention.retent.clic_frame[core_id]); @@ -457,7 +457,7 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin validate_retention_frame_crc((uint32_t*)frame, sizeof(RvCoreNonCriticalSleepFrame) - sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE // Start core1 if (core_id == 0) { REG_SET_BIT(HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, HP_SYS_CLKRST_REG_CORE1_CPU_CLK_EN); @@ -472,7 +472,7 @@ esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uin cpu_domain_dev_regs_restore(s_cpu_retention.retent.clic_frame[core_id]); restore_mstatus(mstatus); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE atomic_store(&s_smp_retention_state[core_id], SMP_RESTORE_DONE); #endif return err; @@ -504,7 +504,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { @@ -515,7 +515,7 @@ esp_err_t sleep_cpu_configure(bool light_sleep_enable) } #if !CONFIG_FREERTOS_UNICORE -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU static TCM_IRAM_ATTR void smp_core_do_retention(void) { uint8_t core_id = esp_cpu_get_core_id(); @@ -579,7 +579,7 @@ IRAM_ATTR void esp_sleep_cpu_skip_retention(void) { void sleep_smp_cpu_sleep_prepare(void) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU while (atomic_load(&s_smp_retention_state[!esp_cpu_get_core_id()]) != SMP_IDLE) { ; } @@ -591,7 +591,7 @@ void sleep_smp_cpu_sleep_prepare(void) void sleep_smp_cpu_wakeup_prepare(void) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU uint8_t core_id = esp_cpu_get_core_id(); if (atomic_load(&s_smp_retention_state[core_id]) == SMP_RESTORE_DONE) { while (atomic_load(&s_smp_retention_state[!core_id]) != SMP_RESTORE_DONE) { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c index cc0f11b3789..2e16de3c677 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c @@ -232,7 +232,7 @@ bool cpu_domain_pd_allowed(void) esp_err_t sleep_cpu_configure(bool light_sleep_enable) { -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU if (light_sleep_enable) { ESP_RETURN_ON_ERROR(esp_sleep_cpu_retention_init(), TAG, "Failed to enable CPU power down during light sleep."); } else { diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index c049ae73acc..59d6cb22a82 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -878,7 +878,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m if (should_skip_sleep) { result = ESP_ERR_SLEEP_REJECT; -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && !CONFIG_FREERTOS_UNICORE && SOC_PM_CPU_RETENTION_BY_SW +#if ESP_SLEEP_POWER_DOWN_CPU && !CONFIG_FREERTOS_UNICORE && SOC_PM_CPU_RETENTION_BY_SW esp_sleep_cpu_skip_retention(); #endif } else { @@ -942,14 +942,14 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif #if SOC_PMU_SUPPORTED -#if SOC_PM_CPU_RETENTION_BY_SW && CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0); if (pd_flags & (PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_TOP)) { result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep); } else #endif { -#if !CONFIG_FREERTOS_UNICORE && CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_SW +#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW // Skip smp retention if CPU power domain power-down is not allowed esp_sleep_cpu_skip_retention(); #endif @@ -1256,7 +1256,7 @@ esp_err_t esp_light_sleep_start(void) #endif #if !CONFIG_FREERTOS_UNICORE -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_SW +#if ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW sleep_smp_cpu_sleep_prepare(); #else esp_ipc_isr_stall_other_cpu(); @@ -1374,7 +1374,7 @@ esp_err_t esp_light_sleep_start(void) // Enter sleep, then wait for flash to be ready on wakeup err = esp_light_sleep_inner(pd_flags, flash_enable_time_us); } -#if !CONFIG_FREERTOS_UNICORE && CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_SW +#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW if (err != ESP_OK) { esp_sleep_cpu_skip_retention(); } @@ -1412,7 +1412,7 @@ esp_err_t esp_light_sleep_start(void) #if !CONFIG_FREERTOS_UNICORE esp_ipc_isr_stall_resume(); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_SW +#if ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW sleep_smp_cpu_wakeup_prepare(); #else esp_ipc_isr_release_other_cpu(); @@ -2063,7 +2063,7 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, esp_sleep_pd_option_ #if SOC_PM_SUPPORT_TOP_PD FORCE_INLINE_ATTR bool top_domain_pd_allowed(void) { bool top_pd_allowed = true; -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU top_pd_allowed &= cpu_domain_pd_allowed(); #else top_pd_allowed = false; @@ -2179,7 +2179,7 @@ static uint32_t get_power_down_flags(void) } #endif -#if SOC_PM_SUPPORT_CPU_PD +#if SOC_PM_SUPPORT_CPU_PD && ESP_SLEEP_POWER_DOWN_CPU if ((s_config.domain[ESP_PD_DOMAIN_CPU].pd_option != ESP_PD_OPTION_ON) && cpu_domain_pd_allowed()) { pd_flags |= RTC_SLEEP_PD_CPU; } diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 3058381fbd0..ab24e4b5bd0 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -84,7 +84,8 @@ menu "Power Management" config PM_CHECK_SLEEP_RETENTION_FRAME bool - depends on PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP + depends on (PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP || \ + (SOC_CPU_IN_TOP_DOMAIN && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP)) default y if IDF_CI_BUILD default n help @@ -142,7 +143,7 @@ menu "Power Management" config PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP bool "Power down Digital Peripheral in light sleep (EXPERIMENTAL)" depends on SOC_PM_SUPPORT_TOP_PD - select PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP + select PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP if !SOC_CPU_IN_TOP_DOMAIN default n #TODO: enable by default if periph init/deinit management supported (WIFI-5252) help If enabled, digital peripherals will be powered down in light sleep, it will reduce sleep diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index d4be371ce40..8216d8a8607 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -29,7 +29,7 @@ entries: sleep_gpio:gpio_sleep_mode_config_apply (noflash) if SOC_PM_CPU_RETENTION_BY_RTCCNTL = y && (PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || SOC_PM_SUPPORT_TAGMEM_PD = y): sleep_cpu:sleep_enable_cpu_retention (noflash) - if PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y: + if PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || (SOC_CPU_IN_TOP_DOMAIN = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP = y): sleep_cpu:cpu_domain_pd_allowed (noflash) if SOC_PM_SUPPORT_TOP_PD = y: sleep_clock:clock_domain_pd_allowed (noflash) diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 3159ba3703c..37d76df5d10 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -372,7 +372,7 @@ static esp_err_t esp_pm_sleep_configure(const void *vconfig) esp_err_t err = ESP_OK; const esp_pm_config_t* config = (const esp_pm_config_t*) vconfig; -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP +#if ESP_SLEEP_POWER_DOWN_CPU err = sleep_cpu_configure(config->light_sleep_enable); if (err != ESP_OK) { return err; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b7f97803193..c8822246f20 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1495,6 +1495,10 @@ config SOC_PAU_IN_TOP_DOMAIN bool default y +config SOC_CPU_IN_TOP_DOMAIN + bool + default y + config SOC_PSRAM_VDD_POWER_MPLL bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 0ac8915371d..8d3fece9edd 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -603,6 +603,7 @@ #define SOC_PM_PAU_LINK_NUM (4) #define SOC_PAU_IN_TOP_DOMAIN (1) +#define SOC_CPU_IN_TOP_DOMAIN (1) /*-------------------------- PSRAM CAPS ----------------------------*/ #define SOC_PSRAM_VDD_POWER_MPLL (1) From c97ab134ef568440e9cf98a0db7243e8e1b31ea5 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 19 Apr 2024 13:13:44 +0800 Subject: [PATCH 103/548] ci(esp_pm): add pd_top auto lightsleep test case for esp_pm --- .../cpu_retention/port/esp32p4/sleep_cpu.c | 4 ++-- .../esp_pm/test_apps/.build-test-rules.yml | 1 + .../esp_pm/test_apps/esp_pm/pytest_esp_pm.py | 17 ++++++++++++++++- .../esp_pm/sdkconfig.ci.pm_pd_top_sleep | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 components/esp_pm/test_apps/esp_pm/sdkconfig.ci.pm_pd_top_sleep diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index cefc1f70cb8..097e6b9b50e 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -410,7 +410,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_END, (void *)0); #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME /* Minus 2 * sizeof(long) is for bypass `pmufunc` and `frame_crc` field */ - update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + update_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); #endif REG_WRITE(RTC_SLEEP_WAKE_STUB_ADDR_REG, (uint32_t)rv_core_critical_regs_restore); @@ -425,7 +425,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME else { - validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_FRMSZ - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); + validate_retention_frame_crc((uint32_t*)frame, RV_SLEEP_CTX_SZ1 - 2 * sizeof(long), (uint32_t *)(&frame->frame_crc)); } #endif diff --git a/components/esp_pm/test_apps/.build-test-rules.yml b/components/esp_pm/test_apps/.build-test-rules.yml index 8aece557bd3..67cf500b6ce 100644 --- a/components/esp_pm/test_apps/.build-test-rules.yml +++ b/components/esp_pm/test_apps/.build-test-rules.yml @@ -4,6 +4,7 @@ components/esp_pm/test_apps: enable: - if: INCLUDE_DEFAULT == 1 disable: + - if: CONFIG_NAME == "pm_pd_top_sleep" and IDF_TARGET not in ["esp32c6", "esp32h2", "esp32p4"] - if: IDF_TARGET == "esp32c5" temporary: true reason: not support yet # TODO: [ESP32C5] IDF-8643 diff --git a/components/esp_pm/test_apps/esp_pm/pytest_esp_pm.py b/components/esp_pm/test_apps/esp_pm/pytest_esp_pm.py index 9d7ff9eaffb..a2c2fc0f765 100644 --- a/components/esp_pm/test_apps/esp_pm/pytest_esp_pm.py +++ b/components/esp_pm/test_apps/esp_pm/pytest_esp_pm.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import pytest from pytest_embedded import Dut @@ -42,3 +42,18 @@ def test_esp_attr_xip_psram_esp32s2(dut: Dut) -> None: ) def test_esp_attr_xip_psram_esp32s3(dut: Dut) -> None: dut.run_all_single_board_cases() + + +# power down CPU and TOP domain in auto-lightsleep +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 +@pytest.mark.esp32p4 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'pm_pd_top_sleep' + ], +) +def test_esp_pd_top_and_cpu_sleep(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_pm/test_apps/esp_pm/sdkconfig.ci.pm_pd_top_sleep b/components/esp_pm/test_apps/esp_pm/sdkconfig.ci.pm_pd_top_sleep new file mode 100644 index 00000000000..5658858b850 --- /dev/null +++ b/components/esp_pm/test_apps/esp_pm/sdkconfig.ci.pm_pd_top_sleep @@ -0,0 +1 @@ +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y From 157c5b52e31f9bf7661db064d74e50c1ea02caaf Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 23 Apr 2024 11:10:40 +0800 Subject: [PATCH 104/548] change(esp_hw_support): put more code into TCM to speed up the sleep and wake-up process --- .../cpu_retention/port/esp32p4/sleep_cpu.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index 097e6b9b50e..e7ea617a9da 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -81,7 +81,7 @@ typedef struct { } retent; } sleep_cpu_retention_t; -static DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention; +static TCM_DRAM_ATTR __attribute__((unused)) sleep_cpu_retention_t s_cpu_retention; extern RvCoreCriticalSleepFrame *rv_core_critical_regs_frame[portNUM_PROCESSORS]; @@ -209,7 +209,7 @@ FORCE_INLINE_ATTR void restore_mstatus(uint32_t mstatus_val) RV_WRITE_CSR(mstatus, mstatus_val); } -static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) +static TCM_IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(void) { RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[esp_cpu_get_core_id()]; @@ -277,7 +277,7 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi return frame; } -static IRAM_ATTR void rv_core_noncritical_regs_restore(void) +static TCM_IRAM_ATTR void rv_core_noncritical_regs_restore(void) { RvCoreNonCriticalSleepFrame *frame = s_cpu_retention.retent.non_critical_frame[esp_cpu_get_core_id()]; @@ -343,7 +343,7 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(void) RV_WRITE_CSR(mcycle, frame->mcycle); } -static IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *frame) +static TCM_IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *frame) { assert(frame); cpu_domain_dev_regs_region_t *region = frame->region; @@ -357,7 +357,7 @@ static IRAM_ATTR void cpu_domain_dev_regs_save(cpu_domain_dev_sleep_frame_t *fra } } -static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *frame) +static TCM_IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t *frame) { assert(frame); cpu_domain_dev_regs_region_t *region = frame->region; @@ -372,12 +372,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * } #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME -static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) +static TCM_IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); } -static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) +static TCM_IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts @@ -399,7 +399,7 @@ extern RvCoreCriticalSleepFrame * rv_core_critical_regs_save(void); extern RvCoreCriticalSleepFrame * rv_core_critical_regs_restore(void); typedef uint32_t (* sleep_cpu_entry_cb_t)(uint32_t, uint32_t, uint32_t, bool); -static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, +static TCM_IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) { uint8_t core_id = esp_cpu_get_core_id(); @@ -432,7 +432,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, return pmu_sleep_finish(); } -esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), +esp_err_t TCM_IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) { esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_CPU_TO_MEM_START, (void *)0); @@ -572,7 +572,7 @@ static TCM_IRAM_ATTR void smp_core_do_retention(void) } -IRAM_ATTR void esp_sleep_cpu_skip_retention(void) { +TCM_IRAM_ATTR void esp_sleep_cpu_skip_retention(void) { atomic_store(&s_smp_retention_state[esp_cpu_get_core_id()], SMP_SKIP_RETENTION); } #endif From 64c062047fcc031584cd1f807210fa93e80d4693 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 23 Apr 2024 11:19:43 +0800 Subject: [PATCH 105/548] fix(esp_hw_support): invalidate L1DCache before enter hardware sleep --- .../port/esp32p4/sleep_cpu_asm.S | 22 ------------------- .../esp_hw_support/port/esp32p4/pmu_sleep.c | 9 ++++++++ 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S index ed46453f319..046ef617776 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S @@ -117,28 +117,6 @@ rv_core_critical_regs_save: mv t3, t0 csrr t0, mscratch sw t0, RV_SLP_CTX_T0(t3) - - /* writeback dcache is required here!!! */ - la t0, CACHE_SYNC_MAP_REG - li t1, 0x10 /* map l1 dcache */ - sw t1, 0x0(t0) /* set EXTMEM_CACHE_SYNC_MAP_REG bit 4 */ - la t2, CACHE_SYNC_ADDR_REG - sw zero, 0x0(t2) /* clear EXTMEM_CACHE_SYNC_ADDR_REG */ - la t0, CACHE_SYNC_SIZE_REG - sw zero, 0x0(t0) /* clear EXTMEM_CACHE_SYNC_SIZE_REG */ - - la t1, CACHE_SYNC_CTRL_REG - lw t2, 0x0(t1) - ori t2, t2, 0x4 - sw t2, 0x0(t1) - - li t0, 0x10 /* SYNC_DONE bit */ -wait_sync_done: - lw t2, 0x0(t1) - and t2, t0, t2 - beqz t2, wait_sync_done - - lw t0, RV_SLP_CTX_T0(t3) lw t1, RV_SLP_CTX_T1(t3) lw t2, RV_SLP_CTX_T2(t3) lw t3, RV_SLP_CTX_T3(t3) diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index ca93907ae5f..a2a55cf83be 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -12,11 +12,13 @@ #include "esp_err.h" #include "esp_attr.h" #include "esp_private/regi2c_ctrl.h" +#include "esp32p4/rom/cache.h" #include "soc/chip_revision.h" #include "soc/soc.h" #include "soc/regi2c_syspll.h" #include "soc/regi2c_cpll.h" #include "soc/rtc.h" +#include "soc/cache_reg.h" #include "soc/pau_reg.h" #include "soc/pmu_reg.h" #include "soc/pmu_struct.h" @@ -285,6 +287,11 @@ void pmu_sleep_shutdown_ldo(void) { CLEAR_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_XPD); } +FORCE_INLINE_ATTR void sleep_writeback_l1_dcache(void) { + Cache_WriteBack_All(CACHE_MAP_L1_DCACHE); + while (!REG_GET_BIT(CACHE_SYNC_CTRL_REG, CACHE_SYNC_DONE)); +} + TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) { lp_aon_hal_inform_wakeup_type(dslp); @@ -297,6 +304,8 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev); pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev); + sleep_writeback_l1_dcache(); + /* Start entry into sleep mode */ pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev); From bef1fba3bc4a27d765e94c456df3b4d22e98cbe7 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 26 Apr 2024 13:42:08 +0530 Subject: [PATCH 106/548] fix(mbedtls/crypto_shared_gdma): Enable AXI-DMA enable external memory AES-ECC access - When external memory encryption is enabled, set the aes_ecc bit of AXI-DMA to enable memory access --- .../hal/esp32p4/include/hal/axi_dma_ll.h | 16 +++ .../hal/test_apps/crypto/main/CMakeLists.txt | 2 +- components/mbedtls/CMakeLists.txt | 3 + .../mbedtls/port/aes/dma/esp_aes_dma_core.c | 97 +++++++++++++------ .../esp_crypto_shared_gdma.c | 41 +++++++- components/mbedtls/port/sha/dma/sha.c | 87 ++++++++++++++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + 8 files changed, 220 insertions(+), 31 deletions(-) diff --git a/components/hal/esp32p4/include/hal/axi_dma_ll.h b/components/hal/esp32p4/include/hal/axi_dma_ll.h index 5cd68088720..ddc1f5c3fba 100644 --- a/components/hal/esp32p4/include/hal/axi_dma_ll.h +++ b/components/hal/esp32p4/include/hal/axi_dma_ll.h @@ -273,6 +273,14 @@ static inline void axi_dma_ll_rx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch dev->in[channel].conf.in_conf0.in_etm_en_chn = enable; } +/** + * @brief Whether to enable the mean access ecc or aes domain + */ +static inline void axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->in[channel].conf.in_conf0.in_ecc_aec_en_chn = enable; +} + ///////////////////////////////////// TX ///////////////////////////////////////// /** * @brief Get DMA TX channel interrupt status word @@ -471,6 +479,14 @@ static inline void axi_dma_ll_tx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch dev->out[channel].conf.out_conf0.out_etm_en_chn = enable; } +/** + * @brief Whether to enable the mean access ecc or aes domain + */ +static inline void axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->out[channel].conf.out_conf0.out_ecc_aec_en_chn = enable; +} + ///////////////////////////////////// CRC-TX ///////////////////////////////////////// /** diff --git a/components/hal/test_apps/crypto/main/CMakeLists.txt b/components/hal/test_apps/crypto/main/CMakeLists.txt index 6c1febef204..3f7585a3aaf 100644 --- a/components/hal/test_apps/crypto/main/CMakeLists.txt +++ b/components/hal/test_apps/crypto/main/CMakeLists.txt @@ -68,7 +68,7 @@ if(CONFIG_SOC_SHA_SUPPORTED) endif() idf_component_register(SRCS ${srcs} - PRIV_REQUIRES efuse mbedtls esp_mm + PRIV_REQUIRES efuse mbedtls esp_mm bootloader_support REQUIRES test_utils unity WHOLE_ARCHIVE PRIV_INCLUDE_DIRS "${priv_include_dirs}" diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index 86d49803fdf..8f4e118f6b3 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -201,6 +201,9 @@ if(SHA_PERIPHERAL_TYPE STREQUAL "dma" OR AES_PERIPHERAL_TYPE STREQUAL "dma") target_link_libraries(mbedcrypto PRIVATE idf::esp_mm) if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA) target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/crypto_shared_gdma/esp_crypto_shared_gdma.c") + if(CONFIG_SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT) + target_link_libraries(mbedcrypto PRIVATE idf::spi_flash idf::bootloader_support) + endif() endif() endif() diff --git a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c index bcf18069b4f..5788b0c2f8e 100644 --- a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c +++ b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c @@ -16,6 +16,8 @@ #include "esp_memory_utils.h" #include "esp_private/esp_cache_private.h" #include "esp_private/periph_ctrl.h" +#include "soc/soc_caps.h" +#include "sdkconfig.h" #if CONFIG_PM_ENABLE #include "esp_pm.h" @@ -36,10 +38,19 @@ #include "aes/esp_aes_gcm.h" #endif +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT +#include "esp_flash_encrypt.h" +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + /* Max size of each chunk to process when output buffer is in unaligned external ram must be a multiple of block size */ +#if (CONFIG_IDF_TARGET_ESP32P4 && CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE) +/* As P4 has larger memory than other targets, thus we can support a larger chunk write size */ +#define AES_MAX_CHUNK_WRITE_SIZE 8*1024 +#else #define AES_MAX_CHUNK_WRITE_SIZE 1600 +#endif /* Input over this length will yield and wait for interrupt instead of busy-waiting, 30000 bytes is approx 0.5 ms */ @@ -163,6 +174,26 @@ static int esp_aes_dma_wait_complete(bool use_intr, crypto_dma_desc_t *output_de return 0; } +static inline size_t get_cache_line_size(const void *addr) +{ + esp_err_t ret = ESP_FAIL; + size_t cache_line_size = 0; + +#if (CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE) + if (esp_ptr_external_ram(addr)) { + ret = esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &cache_line_size); + } else +#endif + { + ret = esp_cache_get_alignment(MALLOC_CAP_DMA, &cache_line_size); + } + + if (ret != ESP_OK) { + return 0; + } + + return cache_line_size; +} /* Output buffers in external ram needs to be 16-byte aligned and DMA can't access input in the iCache mem range, reallocate them into internal memory and encrypt in chunks to avoid @@ -176,14 +207,32 @@ static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char size_t chunk_len; int ret = 0; int offset = 0; + uint32_t input_heap_caps = MALLOC_CAP_DMA; + uint32_t output_heap_caps = MALLOC_CAP_DMA; unsigned char *input_buf = NULL; unsigned char *output_buf = NULL; const unsigned char *dma_input; chunk_len = MIN(AES_MAX_CHUNK_WRITE_SIZE, len); - if (realloc_input) { - input_buf = heap_caps_malloc(chunk_len, MALLOC_CAP_DMA); + size_t input_alignment = 1; + size_t output_alignment = 1; +/* When AES-DMA operations are carried out using external memory with external memory encryption enabled, + we need to make sure that the addresses and the sizes of the buffers on which the DMA operates are 16 byte-aligned. */ +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT + if (esp_flash_encryption_enabled()) { + if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) { + input_alignment = MAX(get_cache_line_size(input), SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT); + output_alignment = MAX(get_cache_line_size(output), SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT); + + input_heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(input) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + output_heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(output) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + } + } +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + + if (realloc_input) { + input_buf = heap_caps_aligned_alloc(input_alignment, chunk_len, input_heap_caps); if (input_buf == NULL) { mbedtls_platform_zeroize(output, len); ESP_LOGE(TAG, "Failed to allocate memory"); @@ -192,8 +241,7 @@ static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char } if (realloc_output) { - output_buf = heap_caps_malloc(chunk_len, MALLOC_CAP_DMA); - + output_buf = heap_caps_aligned_alloc(output_alignment, chunk_len, output_heap_caps); if (output_buf == NULL) { mbedtls_platform_zeroize(output, len); ESP_LOGE(TAG, "Failed to allocate memory"); @@ -284,27 +332,6 @@ static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_ return ptr; } -static inline size_t get_cache_line_size(const void *addr) -{ - esp_err_t ret = ESP_FAIL; - size_t cache_line_size = 0; - -#if (CONFIG_SPIRAM && SOC_PSRAM_DMA_CAPABLE) - if (esp_ptr_external_ram(addr)) { - ret = esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &cache_line_size); - } else -#endif - { - ret = esp_cache_get_alignment(MALLOC_CAP_DMA, &cache_line_size); - } - - if (ret != ESP_OK) { - return 0; - } - - return cache_line_size; -} - static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_dma_desc_num, size_t cache_line_size) { esp_err_t ret = ESP_OK; @@ -404,7 +431,7 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le dma_descs_needed = (unaligned_start_bytes ? 1 : 0) + dma_desc_get_required_num(aligned_block_bytes, max_desc_size) + (unaligned_end_bytes ? 1 : 0); /* Allocate memory for DMA descriptors of total size aligned up to a multiple of cache line size */ - dma_descriptors = (crypto_dma_desc_t *) aes_dma_calloc(dma_descs_needed, sizeof(crypto_dma_desc_t), MALLOC_CAP_DMA, NULL); + dma_descriptors = (crypto_dma_desc_t *) aes_dma_calloc(dma_descs_needed, sizeof(crypto_dma_desc_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, NULL); if (dma_descriptors == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for the array of DMA descriptors"); return ESP_FAIL; @@ -413,7 +440,7 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le size_t populated_dma_descs = 0; if (unaligned_start_bytes) { - start_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS, NULL); + start_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS | (esp_ptr_external_ram(buffer) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL) , NULL); if (start_alignment_stream_buffer == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for start alignment buffer"); return ESP_FAIL; @@ -435,7 +462,7 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le } if (unaligned_end_bytes) { - end_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS, NULL); + end_alignment_stream_buffer = aes_dma_calloc(alignment_buffer_size, sizeof(uint8_t), AES_DMA_ALLOC_CAPS | (esp_ptr_external_ram(buffer) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_INTERNAL), NULL); if (end_alignment_stream_buffer == NULL) { ESP_LOGE(TAG, "Failed to allocate memory for end alignment buffer"); return ESP_FAIL; @@ -499,6 +526,20 @@ int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsign return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; } +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT + if (esp_flash_encryption_enabled()) { + if (esp_ptr_external_ram(input) || esp_ptr_external_ram(output) || esp_ptr_in_drom(input) || esp_ptr_in_drom(output)) { + if (((intptr_t)(input) & (SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) { + input_needs_realloc = true; + } + + if (((intptr_t)(output) & (SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) { + output_needs_realloc = true; + } + } + } +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + /* DMA cannot access memory in the iCache range, copy input to internal ram */ if (!s_check_dma_capable(input)) { input_needs_realloc = true; diff --git a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c index 059ebb738a5..9f202249e99 100644 --- a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c +++ b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,13 @@ #include "esp_cache.h" #include "esp_crypto_dma.h" #include "esp_crypto_lock.h" +#include "esp_memory_utils.h" #include "soc/soc_caps.h" +#include "sdkconfig.h" + +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT +#include "esp_flash_encrypt.h" +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ #if SOC_AHB_GDMA_VERSION == 1 #include "hal/gdma_ll.h" @@ -140,6 +146,22 @@ esp_err_t esp_crypto_shared_gdma_start(const lldesc_t *input, const lldesc_t *ou return ESP_OK; } +/* The external memory ecc-aes access must be enabled when there exists + at least one buffer in the DMA descriptors that resides in external memory. */ +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT +static bool check_dma_descs_need_ext_mem_ecc_aes_access(const crypto_dma_desc_t *dmadesc) +{ + crypto_dma_desc_t* desc = (crypto_dma_desc_t*) dmadesc; + while (desc) { + if (esp_ptr_in_drom(desc->buffer) || esp_ptr_external_ram(desc->buffer)) { + return true; + } + desc = desc->next; + } + return false; +} +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, const crypto_dma_desc_t *output, gdma_trigger_peripheral_t peripheral) { int rx_ch_id = 0; @@ -173,6 +195,23 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c axi_dma_ll_rx_reset_channel(&AXI_DMA, rx_ch_id); #endif /* SOC_AHB_GDMA_VERSION */ +/* When GDMA operations are carried out using external memory with external memory encryption enabled, + we need to enable AXI-DMA's AES-ECC mean access bit. */ +#if (SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT) + if (esp_flash_encryption_enabled()) { + int tx_ch_id = 0; + gdma_get_channel_id(tx_channel, &tx_ch_id); + + if (check_dma_descs_need_ext_mem_ecc_aes_access(input) || check_dma_descs_need_ext_mem_ecc_aes_access(output)) { + axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(&AXI_DMA, rx_ch_id, true); + axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(&AXI_DMA, tx_ch_id, true); + } else { + axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(&AXI_DMA, rx_ch_id, false); + axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(&AXI_DMA, tx_ch_id, false); + } + } +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + gdma_start(tx_channel, (intptr_t)input); gdma_start(rx_channel, (intptr_t)output); diff --git a/components/mbedtls/port/sha/dma/sha.c b/components/mbedtls/port/sha/dma/sha.c index 38775dfbfb6..7963818d496 100644 --- a/components/mbedtls/port/sha/dma/sha.c +++ b/components/mbedtls/port/sha/dma/sha.c @@ -53,6 +53,11 @@ #include "hal/sha_ll.h" #include "soc/soc_caps.h" #include "esp_sha_dma_priv.h" +#include "sdkconfig.h" + +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT +#include "esp_flash_encrypt.h" +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ #if SOC_SHA_GDMA #define SHA_LOCK() esp_crypto_sha_aes_lock_acquire() @@ -168,6 +173,63 @@ static void esp_sha_block_mode(esp_sha_type sha_type, const uint8_t *input, uint static DRAM_ATTR crypto_dma_desc_t s_dma_descr_input; static DRAM_ATTR crypto_dma_desc_t s_dma_descr_buf; +static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen, + const void *buf, uint32_t buf_len, bool is_first_block); + +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT +static esp_err_t esp_sha_dma_process_ext(esp_sha_type sha_type, const void *input, uint32_t ilen, + const void *buf, uint32_t buf_len, bool is_first_block, + bool realloc_input, bool realloc_buf) +{ + int ret = ESP_FAIL; + void *input_copy = NULL; + void *buf_copy = NULL; + + const void *dma_input = NULL; + const void *dma_buf = NULL; + + uint32_t heap_caps = 0; + + if (realloc_input) { + heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(input) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + input_copy = heap_caps_aligned_alloc(SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT, ilen, heap_caps); + if (input_copy == NULL) { + ESP_LOGE(TAG, "Failed to allocate aligned SPIRAM memory"); + return ret; + } + memcpy(input_copy, input, ilen); + dma_input = input_copy; + } else { + dma_input = input; + } + + if (realloc_buf) { + heap_caps = MALLOC_CAP_8BIT | (esp_ptr_external_ram(buf) ? MALLOC_CAP_SPIRAM : MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + buf_copy = heap_caps_aligned_alloc(SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT, buf_len, heap_caps); + if (buf_copy == NULL) { + ESP_LOGE(TAG, "Failed to allocate aligned internal memory"); + return ret; + } + memcpy(buf_copy, buf, buf_len); + dma_buf = buf_copy; + } else { + dma_buf = buf; + } + + ret = esp_sha_dma_process(sha_type, dma_input, ilen, dma_buf, buf_len, is_first_block); + + if (realloc_input) { + free(input_copy); + } + + if (realloc_buf) { + free(buf_copy); + } + + return ret; +} +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + /* Performs SHA on multiple blocks at a time */ static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, uint32_t ilen, const void *buf, uint32_t buf_len, bool is_first_block) @@ -179,6 +241,29 @@ static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, u memset(&s_dma_descr_input, 0, sizeof(crypto_dma_desc_t)); memset(&s_dma_descr_buf, 0, sizeof(crypto_dma_desc_t)); +/* When SHA-DMA operations are carried out using external memory with external memory encryption enabled, + we need to make sure that the addresses and the sizes of the buffers on which the DMA operates are 16 byte-aligned. */ +#ifdef SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT + if (esp_flash_encryption_enabled()) { + if (esp_ptr_external_ram(input) || esp_ptr_external_ram(buf) || esp_ptr_in_drom(input) || esp_ptr_in_drom(buf)) { + bool input_needs_realloc = false; + bool buf_needs_realloc = false; + + if (ilen && ((intptr_t)(input) & (SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) { + input_needs_realloc = true; + } + + if (buf_len && ((intptr_t)(buf) & (SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT - 1)) != 0) { + buf_needs_realloc = true; + } + + if (input_needs_realloc || buf_needs_realloc) { + return esp_sha_dma_process_ext(sha_type, input, ilen, buf, buf_len, is_first_block, input_needs_realloc, buf_needs_realloc); + } + } + } +#endif /* SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT */ + /* DMA descriptor for Memory to DMA-SHA transfer */ if (ilen) { s_dma_descr_input.dw0.length = ilen; @@ -188,7 +273,7 @@ static esp_err_t esp_sha_dma_process(esp_sha_type sha_type, const void *input, u s_dma_descr_input.buffer = (void *) input; dma_descr_head = &s_dma_descr_input; } - /* Check after input to overide head if there is any buf*/ + /* Check after input to override head if there is any buf*/ if (buf_len) { s_dma_descr_buf.dw0.length = buf_len; s_dma_descr_buf.dw0.size = buf_len; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b7f97803193..4715b3fc574 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -483,6 +483,10 @@ config SOC_GDMA_SUPPORT_ETM bool default y +config SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT + int + default 16 + config SOC_DMA2D_GROUPS int default 1 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 0ac8915371d..49fb33703ac 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -192,6 +192,7 @@ #define SOC_AXI_GDMA_SUPPORT_PSRAM 1 #define SOC_GDMA_SUPPORT_ETM 1 // #define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1 +#define SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT (16) /*-------------------------- 2D-DMA CAPS -------------------------------------*/ #define SOC_DMA2D_GROUPS (1U) // Number of 2D-DMA groups From 0c5bce6918641289ed2adcaf7e7382b34df53764 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Tue, 14 May 2024 11:21:21 +0530 Subject: [PATCH 107/548] fix(bootloader_support): Make esp_flash_encrypt.h independent of spi_flash_mmap.h header --- components/app_update/esp_ota_ops.c | 1 + .../bootloader_flash/src/bootloader_flash.c | 3 +++ components/bootloader_support/include/esp_flash_encrypt.h | 3 --- components/bootloader_support/src/bootloader_init.c | 1 - components/bootloader_support/src/bootloader_utility.c | 3 +++ components/esp_partition/partition.c | 1 + components/esp_system/port/cpu_start.c | 2 +- components/espcoredump/src/core_dump_flash.c | 3 ++- components/mbedtls/CMakeLists.txt | 4 ++-- components/nvs_flash/test_apps/main/test_nvs.c | 1 + 10 files changed, 14 insertions(+), 8 deletions(-) diff --git a/components/app_update/esp_ota_ops.c b/components/app_update/esp_ota_ops.c index 52bba6c4987..9c03ccf16fe 100644 --- a/components/app_update/esp_ota_ops.c +++ b/components/app_update/esp_ota_ops.c @@ -17,6 +17,7 @@ #include "esp_image_format.h" #include "esp_secure_boot.h" #include "esp_flash_encrypt.h" +#include "spi_flash_mmap.h" #include "sdkconfig.h" #include "esp_ota_ops.h" diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index b725995b1c9..22bcf0fb69c 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -13,6 +13,9 @@ #include "hal/efuse_ll.h" #include "hal/efuse_hal.h" +#ifndef BOOTLOADER_BUILD +#include "spi_flash_mmap.h" +#endif #include "hal/spi_flash_ll.h" #include "rom/spi_flash.h" #if CONFIG_IDF_TARGET_ESP32 diff --git a/components/bootloader_support/include/esp_flash_encrypt.h b/components/bootloader_support/include/esp_flash_encrypt.h index 7c09593ecc9..6e495dbce06 100644 --- a/components/bootloader_support/include/esp_flash_encrypt.h +++ b/components/bootloader_support/include/esp_flash_encrypt.h @@ -9,9 +9,6 @@ #include "esp_attr.h" #include "esp_err.h" #include "soc/soc_caps.h" -#ifndef BOOTLOADER_BUILD -#include "spi_flash_mmap.h" -#endif #include "hal/efuse_ll.h" #include "sdkconfig.h" diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 49a096e66c6..6289936986c 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -14,7 +14,6 @@ #include "bootloader_random.h" #include "bootloader_clock.h" #include "bootloader_common.h" -#include "esp_flash_encrypt.h" #include "esp_cpu.h" #include "soc/rtc.h" #include "hal/wdt_hal.h" diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index 7aad0fa5b5a..8694e369be5 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -34,6 +34,9 @@ #include "esp_app_desc.h" #include "esp_secure_boot.h" #include "esp_flash_encrypt.h" +#ifndef BOOTLOADER_BUILD +#include "spi_flash_mmap.h" +#endif #include "esp_flash_partitions.h" #include "bootloader_flash_priv.h" #include "bootloader_random.h" diff --git a/components/esp_partition/partition.c b/components/esp_partition/partition.c index 174d1c1f0d0..d32ff0ff1ec 100644 --- a/components/esp_partition/partition.c +++ b/components/esp_partition/partition.c @@ -27,6 +27,7 @@ #if !CONFIG_IDF_TARGET_LINUX #include "esp_flash.h" #include "esp_flash_encrypt.h" +#include "spi_flash_mmap.h" #endif #include "esp_log.h" #include "esp_rom_md5.h" diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 73255e14646..8d356d02c37 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -93,7 +93,6 @@ #include "bootloader_flash_config.h" #include "bootloader_flash.h" #include "esp_private/crosscore_int.h" -#include "esp_flash_encrypt.h" #include "esp_private/sleep_gpio.h" #include "hal/wdt_hal.h" @@ -114,6 +113,7 @@ #include "esp_rom_spiflash.h" #include "bootloader_init.h" #include "esp_private/bootloader_flash_internal.h" +#include "spi_flash_mmap.h" #endif // CONFIG_APP_BUILD_TYPE_RAM //This dependency will be removed in the future diff --git a/components/espcoredump/src/core_dump_flash.c b/components/espcoredump/src/core_dump_flash.c index 7cd6382fd98..0efda911595 100644 --- a/components/espcoredump/src/core_dump_flash.c +++ b/components/espcoredump/src/core_dump_flash.c @@ -12,6 +12,7 @@ #include "esp_flash_encrypt.h" #include "esp_rom_crc.h" #include "esp_private/spi_flash_os.h" +#include "spi_flash_mmap.h" #define BLANK_COREDUMP_SIZE 0xFFFFFFFF @@ -258,7 +259,7 @@ static esp_err_t esp_core_dump_flash_write_prepare(core_dump_write_data_t *wr_da padding = COREDUMP_CACHE_SIZE - modulo; } - /* Now we can check whether we have enough space in our core dump parition + /* Now we can check whether we have enough space in our core dump partition * or not. */ if ((*data_len + padding + cs_len) > s_core_flash_config.partition.size) { ESP_COREDUMP_LOGE("Not enough space to save core dump!"); diff --git a/components/mbedtls/CMakeLists.txt b/components/mbedtls/CMakeLists.txt index 8f4e118f6b3..ad0ca7151da 100644 --- a/components/mbedtls/CMakeLists.txt +++ b/components/mbedtls/CMakeLists.txt @@ -200,10 +200,10 @@ endif() if(SHA_PERIPHERAL_TYPE STREQUAL "dma" OR AES_PERIPHERAL_TYPE STREQUAL "dma") target_link_libraries(mbedcrypto PRIVATE idf::esp_mm) if(CONFIG_SOC_SHA_GDMA OR CONFIG_SOC_AES_GDMA) - target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/crypto_shared_gdma/esp_crypto_shared_gdma.c") if(CONFIG_SOC_AXI_DMA_EXT_MEM_ENC_ALIGNMENT) - target_link_libraries(mbedcrypto PRIVATE idf::spi_flash idf::bootloader_support) + target_link_libraries(mbedcrypto PRIVATE idf::bootloader_support) endif() + target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/crypto_shared_gdma/esp_crypto_shared_gdma.c") endif() endif() diff --git a/components/nvs_flash/test_apps/main/test_nvs.c b/components/nvs_flash/test_apps/main/test_nvs.c index b0687b608f7..688722fe9ff 100644 --- a/components/nvs_flash/test_apps/main/test_nvs.c +++ b/components/nvs_flash/test_apps/main/test_nvs.c @@ -17,6 +17,7 @@ #include "esp_log.h" #include "esp_partition.h" #include "esp_system.h" +#include "spi_flash_mmap.h" #include "nvs.h" #include "nvs_flash.h" From 7b10c2421fe8644ef52a90c41f4f2c54c672158f Mon Sep 17 00:00:00 2001 From: Lou Tianhao Date: Mon, 20 May 2024 14:49:49 +0800 Subject: [PATCH 108/548] fix(esp_system): fix core1 access cache when core0 close cache during sleep --- components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c index 62877ae7d90..564690a4475 100644 --- a/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c +++ b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c @@ -5,8 +5,9 @@ */ #include "stdint.h" +#include "esp_attr.h" -void esp_ipc_isr_waiting_for_finish_cmd(void* ipc_isr_finish_cmd) +void IRAM_ATTR esp_ipc_isr_waiting_for_finish_cmd(void* ipc_isr_finish_cmd) { while (*(volatile uint32_t *)ipc_isr_finish_cmd == 0) { }; } From 9ebc8f02a9770e749c11208fa0f598e67fd940ed Mon Sep 17 00:00:00 2001 From: Xiaoyu Liu Date: Wed, 15 May 2024 15:52:53 +0800 Subject: [PATCH 109/548] feat(system/console): Added argtable3 SBOM manifest file in console component for SPDX file generation --- components/console/argtable3/sbom.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 components/console/argtable3/sbom.yml diff --git a/components/console/argtable3/sbom.yml b/components/console/argtable3/sbom.yml new file mode 100644 index 00000000000..1e40eb87dca --- /dev/null +++ b/components/console/argtable3/sbom.yml @@ -0,0 +1,5 @@ +name: 'argtable3' +version: '3.2.2' +supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' +originator: 'Organization: Argtable.org and individual contributors' +description: An open source ANSI C library that parses GNU-style command-line options. From 9e74564ba5ff57c54ac1adac8dc83c8be7599abd Mon Sep 17 00:00:00 2001 From: shenmengjing Date: Tue, 7 May 2024 17:56:56 +0800 Subject: [PATCH 110/548] docs: Update the CN Translation for ram-usage and speed --- docs/en/api-guides/performance/speed.rst | 4 +- .../api-guides/performance/ram-usage.rst | 17 ++++ docs/zh_CN/api-guides/performance/speed.rst | 85 ++++++++++++++----- 3 files changed, 84 insertions(+), 22 deletions(-) diff --git a/docs/en/api-guides/performance/speed.rst b/docs/en/api-guides/performance/speed.rst index 9f59ad065ee..8e6760466e6 100644 --- a/docs/en/api-guides/performance/speed.rst +++ b/docs/en/api-guides/performance/speed.rst @@ -165,8 +165,8 @@ In addition to the overall performance improvements shown above, the following o :SOC_RTC_FAST_MEM_SUPPORTED: - If using Deep-sleep mode, setting :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` allows a faster wake from sleep. Note that if using Secure Boot, this represents a security compromise, as Secure Boot validation are not be performed on wake. - Setting :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON` skips verifying the binary on every boot from the power-on reset. How much time this saves depends on the binary size and the flash settings. Note that this setting carries some risk if the flash becomes corrupt unexpectedly. Read the help text of the :ref:`config item ` for an explanation and recommendations if using this option. - It is possible to save a small amount of time during boot by disabling RTC slow clock calibration. To do so, set :ref:`CONFIG_RTC_CLK_CAL_CYCLES` to 0. Any part of the firmware that uses RTC slow clock as a timing source will be less accurate as a result. - :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling memory test on the external memory (:ref:`CONFIG_SPIRAM_MEMTEST`) can have a large impact on startup time (approximately 1 second per 4MiB of memory tested). Disabling the memory tests will reduce startup time at the expense of testing the external memory. - :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling comprehensive poisoning will increase the startup time (approximately 300 milliseconds per 4MiB of memory set) since all the memory used as heap (including the external memory) will be set to a default value. + :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling memory test on the external memory (:ref:`CONFIG_SPIRAM_MEMTEST`) can have a large impact on startup time (approximately 1 second per 4 MB of memory tested). Disabling the memory tests will reduce startup time at the expense of testing the external memory. + :SOC_SPIRAM_SUPPORTED: - When external memory is used (:ref:`CONFIG_SPIRAM` enabled), enabling comprehensive poisoning will increase the startup time (approximately 300 milliseconds per 4 MiB of memory set) since all the memory used as heap (including the external memory) will be set to a default value. The example project :example:`system/startup_time` is pre-configured to optimize startup time. The file :example_file:`system/startup_time/sdkconfig.defaults` contain all of these settings. You can append these to the end of your project's own ``sdkconfig`` file to merge the settings, but please read the documentation for each setting first. diff --git a/docs/zh_CN/api-guides/performance/ram-usage.rst b/docs/zh_CN/api-guides/performance/ram-usage.rst index 1c912bac76a..f8ea43f8dcd 100644 --- a/docs/zh_CN/api-guides/performance/ram-usage.rst +++ b/docs/zh_CN/api-guides/performance/ram-usage.rst @@ -183,6 +183,7 @@ IRAM 优化 任何最终未用于静态 IRAM 的内存都将添加到堆内存中。 + .. only:: esp32c3 flash 暂停特性 @@ -233,3 +234,19 @@ IRAM 优化 .. note:: 部分配置选项可以将一些功能移动到 IRAM 中,从而提高性能,但这类选项默认不进行配置,因此未在此列出。了解启用上述选项对 IRAM 大小造成的影响,请参阅配置项的帮助文本。 + + +.. only:: esp32s2 or esp32s3 or esp32p4 + + 改变 cache 大小 + ^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} RAM 内存可用大小取决于 cache 的大小。在下面列出的 Kconfig 选项中减少 cache 大小将会增加可用的 RAM。 + + .. list:: + + :esp32s2: - :ref:`CONFIG_ESP32S2_INSTRUCTION_CACHE_SIZE` + :esp32s2: - :ref:`CONFIG_ESP32S2_DATA_CACHE_SIZE` + :esp32s3: - :ref:`CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE` + :esp32s3: - :ref:`CONFIG_ESP32S3_DATA_CACHE_SIZE` + :esp32p4: - :ref:`CONFIG_CACHE_L2_CACHE_SIZE` diff --git a/docs/zh_CN/api-guides/performance/speed.rst b/docs/zh_CN/api-guides/performance/speed.rst index 678abf9e6d0..e5be50dd983 100644 --- a/docs/zh_CN/api-guides/performance/speed.rst +++ b/docs/zh_CN/api-guides/performance/speed.rst @@ -4,7 +4,7 @@ :link_to_translation:`en:[English]` {IDF_TARGET_CONTROLLER_CORE_CONFIG:default="CONFIG_BT_CTRL_PINNED_TO_CORE", esp32="CONFIG_BTDM_CTRL_PINNED_TO_CORE_CHOICE", esp32s3="CONFIG_BT_CTRL_PINNED_TO_CORE_CHOICE"} -{IDF_TARGET_RF_TYPE:default="Wi-Fi/蓝牙", esp32s2="Wi-Fi", esp32c6="Wi-Fi/蓝牙/802.15.4", esp32h2="蓝牙/802.15.4"} +{IDF_TARGET_RF_TYPE:default="Wi-Fi/蓝牙", esp32s2="Wi-Fi", esp32c6="Wi-Fi/蓝牙/802.15.4", esp32h2="蓝牙/802.15.4, esp32c5="Wi-Fi/蓝牙/802.15.4"} 概述 ----------- @@ -56,7 +56,7 @@ .. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES - CPU 周期是各核心独立计数的,因此本方法仅适用于测量中断处理程序或固定在单个核心上的任务。 + CPU 周期是各内核独立计数的,因此本方法仅适用于测量中断处理程序或固定在单个核上的任务。 - 在执行“微基准测试”时(即仅对运行时间不到 1-2 ms 的小代码段进行基准测试),二进制文件会影响 flash 缓存的性能,进而可能会导致计时测量出现较大差异。这是因为二进制布局可能会导致在特定的执行顺序中产生不同模式的缓存缺失。执行较大测试代码通常可以抵消这种影响。在基准测试时多次执行一个小函数可以减少 flash 缓存缺失的影响。另外,将该代码移到 IRAM 中(参见 :ref:`speed-targeted-optimizations` )也可以解决这个问题。 @@ -88,6 +88,36 @@ :not SOC_CPU_HAS_FPU: - 避免使用浮点运算 ``float``。{IDF_TARGET_NAME} 通过软件模拟进行浮点运算,因此速度非常慢。可以考虑使用不同的整数表示方法进行运算,如定点表示法,或者将部分计算用整数运算后再切换为浮点运算。 - 避免使用双精度浮点运算 ``double``。{IDF_TARGET_NAME} 通过软件模拟进行双精度浮点运算,因此速度非常慢。可以考虑使用基于整数的表示方法或单精度浮点数。 + +.. only:: esp32s2 or esp32s3 or esp32p4 + + 更改 cache 大小 + ^^^^^^^^^^^^^^^ + + 在 {IDF_TARGET_NAME} 上,通过下面列出的 Kconfig 选项增加 cache 的大小,“cache 缺失”的频率可能会降低,从而在一定程度上提高整体速度。 + + .. list:: + + :esp32s2: - :ref:`CONFIG_ESP32S2_INSTRUCTION_CACHE_SIZE`. + :esp32s2: - :ref:`CONFIG_ESP32S2_DATA_CACHE_SIZE`. + :esp32s3: - :ref:`CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE`. + :esp32s3: - :ref:`CONFIG_ESP32S3_DATA_CACHE_SIZE`. + :esp32p4: - :ref:`CONFIG_CACHE_L2_CACHE_SIZE`. + + + .. note:: + + 增加 cache 大小也将导致可用 RAM 的减少。 + + +.. only:: SOC_CACHE_L2_CACHE_SIZE_CONFIGURABLE + + .. note:: + + 在 {IDF_TARGET_NAME} 上,可以通过 Kconfig 选项 :ref:`CONFIG_CACHE_L2_CACHE_SIZE` 来配置 L2 cache 大小。 + 将 L2 cache 大小设为最小,则可用 RAM 大小达到最大,但也可能提高“cache 缺失”的频率。 + 将 L2 cache 大小设为最大,则“cache 缺失”的频率可能降低,但可用 RAM 大小也随之减少。 + 减少日志开销 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,6 +140,7 @@ .. _speed-targeted-optimizations: + 针对性优化 --------------------------- @@ -134,6 +165,8 @@ :SOC_RTC_FAST_MEM_SUPPORTED: - 如果使用 Deep-sleep 模式,启用 :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP` 可以加快从睡眠中唤醒的速度。请注意,启用该选项后在唤醒时将不会执行安全启动验证,需要考量安全风险。 - 设置 :ref:`CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON` 可以在每次上电复位启动时跳过二进制文件验证,节省的时间取决于二进制文件大小和 flash 设置。请注意,如果 flash 意外损坏,此设置将有一定风险。更多关于使用该选项的解释和建议,参见 :ref:`项目配置 ` 。 - 禁用 RTC 慢速时钟校准可以节省一小部分启动时间。设置 :ref:`CONFIG_RTC_CLK_CAL_CYCLES` 为 0 可以实现该操作。设置后,以 RTC 慢速时钟为时钟源的固件部分精确度将降低。 + :SOC_SPIRAM_SUPPORTED: - 使用外部内存(启用 :ref:`CONFIG_SPIRAM`)时,启用外部内存 (:ref:`CONFIG_SPIRAM_MEMTEST`) 测试可能会大大增加启动时间(每测试 4 MB 的内存大约增加 1 秒)。禁用内存测试将减少启动时间,但将无法对外部存储器进行测试。 + :SOC_SPIRAM_SUPPORTED: - 使用外部内存(启用 :ref:`CONFIG_SPIRAM`)时,所有用作堆的内存(包括外部内存)都将被设为默认值,所以启用全面的 poisoning 将增加启动时间(每设置 4 MiB 的内存大约增加 300 毫秒)。 示例项目 :example:`system/startup_time` 预配了优化启动时间的设置,文件 :example_file:`system/startup_time/sdkconfig.defaults` 包含了所有相关设置。可以将这些设置追加到项目中 ``sdkconfig`` 文件的末尾并合并,但请事先阅读每个设置的相关说明。 @@ -180,24 +213,24 @@ ESP-IDF 启动的系统任务预设了固定优先级。启动时,一些任务 .. list:: - - :ref:`app-main-task` 中执行 app_main 函数的主任务优先级最低 (1) 且默认固定在核心 0 上执行( :ref:`可配置 ` )。 - - 系统任务 :doc:`/api-reference/system/esp_timer` 用于管理定时器事件并执行回调函数,优先级较高 (22, ``ESP_TASK_TIMER_PRIO``) 且固定在核心 0 上执行。 - - FreeRTOS 初始化调度器时会创建定时器任务,用于处理 FreeRTOS 定时器的回调函数,优先级最低(1, :ref:`可配置 ` )且固定在核心 0 上执行。 - - 系统任务 :doc:`/api-reference/system/esp_event` 用于管理默认的系统事件循环并执行回调函数,优先级较高 (20, ``ESP_TASK_EVENT_PRIO``) 且固定在核心 0 上执行。此配置仅在应用程序调用 :cpp:func:`esp_event_loop_create_default` 时使用。可以调用 :cpp:func:`esp_event_loop_create` 添加自定义任务配置。 - - :doc:`/api-guides/lwip` TCP/IP 任务优先级较高 (18, ``ESP_TASK_TCPIP_PRIO``) 且并未固定在特定核心上执行( :ref:`可配置 ` )。 - :SOC_WIFI_SUPPORTED: - :doc:`/api-guides/wifi` 任务优先级较高 (23) 且默认固定在核心 0 上执行( :ref:`可配置 ` )。 - :SOC_WIFI_SUPPORTED: - 使用 Wi-Fi Protected Setup (WPS)、WPA2 EAP-TLS、Device Provisioning Protocol (DPP) 或 BSS Transition Management (BTM) 等功能时,Wi-Fi wpa_supplicant 组件可能会创建优先级较低的专用任务 (2),这些任务并未固定在特定核心上执行。 - :SOC_BT_SUPPORTED: - :doc:`/api-reference/bluetooth/controller_vhci` 任务优先级较高 (23, ``ESP_TASK_BT_CONTROLLER_PRIO``) 且默认固定在核心 0 上执行( :ref:`可配置 <{IDF_TARGET_CONTROLLER_CORE_CONFIG}>` )。蓝牙控制器需要以低延迟响应请求,因此其任务应始终为最高优先级的任务之一并分配给单个 CPU 执行。 - :SOC_BT_SUPPORTED: - :doc:`/api-reference/bluetooth/nimble/index` 任务优先级较高 (21) 且默认固定在核心 0 上执行( :ref:`可配置 ` ). + - :ref:`app-main-task` 中执行 app_main 函数的主任务优先级最低 (1) 且默认固定在核 0 上执行( :ref:`可配置 ` )。 + - 系统任务 :doc:`/api-reference/system/esp_timer` 用于管理定时器事件并执行回调函数,优先级较高 (22, ``ESP_TASK_TIMER_PRIO``) 且固定在核 0 上执行。 + - FreeRTOS 初始化调度器时会创建定时器任务,用于处理 FreeRTOS 定时器的回调函数,优先级最低(1, :ref:`可配置 ` )且固定在核 0 上执行。 + - 系统任务 :doc:`/api-reference/system/esp_event` 用于管理默认的系统事件循环并执行回调函数,优先级较高 (20, ``ESP_TASK_EVENT_PRIO``) 且固定在核 0 上执行。此配置仅在应用程序调用 :cpp:func:`esp_event_loop_create_default` 时使用。可以调用 :cpp:func:`esp_event_loop_create` 添加自定义任务配置。 + - :doc:`/api-guides/lwip` TCP/IP 任务优先级较高 (18, ``ESP_TASK_TCPIP_PRIO``) 且并未固定在特定内核上执行( :ref:`可配置 ` )。 + :SOC_WIFI_SUPPORTED: - :doc:`/api-guides/wifi` 任务优先级较高 (23) 且默认固定在核 0 上执行( :ref:`可配置 ` )。 + :SOC_WIFI_SUPPORTED: - 使用 Wi-Fi Protected Setup (WPS)、WPA2 EAP-TLS、Device Provisioning Protocol (DPP) 或 BSS Transition Management (BTM) 等功能时,Wi-Fi wpa_supplicant 组件可能会创建优先级较低的专用任务 (2),这些任务并未固定在特定内核上执行。 + :SOC_BT_SUPPORTED: - :doc:`/api-reference/bluetooth/controller_vhci` 任务优先级较高 (23, ``ESP_TASK_BT_CONTROLLER_PRIO``) 且默认固定在核 0 上执行( :ref:`可配置 <{IDF_TARGET_CONTROLLER_CORE_CONFIG}>` )。蓝牙控制器需要以低延迟响应请求,因此其任务应始终为最高优先级的任务之一并分配给单个 CPU 执行。 + :SOC_BT_SUPPORTED: - :doc:`/api-reference/bluetooth/nimble/index` 任务优先级较高 (21) 且默认固定在核 0 上执行( :ref:`可配置 ` ). :esp32: - 使用 :doc:`/api-reference/bluetooth/index` 时会创建多个任务: - 堆栈事件回调任务 ("BTC") 优先级较高 (19)。 - 堆栈 BTU 层任务优先级较高 (20)。 - Host HCI 主任务优先级较高 (22)。 - 所有 Bluedroid 任务默认固定在同一个核心上执行,即核心 0( :ref:`可配置 ` )。 + 所有 Bluedroid 任务默认固定在同一个核心上执行,即核 0( :ref:`可配置 ` )。 - - 以太网驱动程序会创建一个 MAC 任务,用于接收以太网帧。如果使用默认配置 ``ETH_MAC_DEFAULT_CONFIG`` ,则该任务为中高优先级 (15) 且并未固定在特定核心上执行。可以在以太网 MAC 初始化时输入自定义 :cpp:class:`eth_mac_config_t` 结构体来更改此设置。 - - 如果使用 :doc:`/api-reference/protocols/mqtt` 组件,它会创建优先级默认为 5 的任务( :ref:`可配置 ` ,也可通过 :ref:`CONFIG_MQTT_USE_CUSTOM_CONFIG` 调整)。该任务未固定在特定核心上执行( :ref:`可配置 ` )。 + - 以太网驱动程序会创建一个 MAC 任务,用于接收以太网帧。如果使用默认配置 ``ETH_MAC_DEFAULT_CONFIG`` ,则该任务为中高优先级 (15) 且并未固定在特定内核上执行。可以在以太网 MAC 初始化时输入自定义 :cpp:class:`eth_mac_config_t` 结构体来更改此设置。 + - 如果使用 :doc:`/api-reference/protocols/mqtt` 组件,它会创建优先级默认为 5 的任务( :ref:`可配置 ` ,也可通过 :ref:`CONFIG_MQTT_USE_CUSTOM_CONFIG` 调整)。该任务未固定在特定内核上执行( :ref:`可配置 ` )。 - 关于 ``mDNS`` 服务的任务优先级,参见 `性能优化 `__ 。 @@ -206,17 +239,29 @@ ESP-IDF 启动的系统任务预设了固定优先级。启动时,一些任务 .. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES - 由于 {IDF_TARGET_RF_TYPE} 操作饥饿可能导致系统不稳定,通常不建议让特定任务的优先级高于 {IDF_TARGET_RF_TYPE} 操作的内置优先级。对于非常短且无需网络的实时操作,可以使用中断服务程序或极受限的任务(仅运行极短时间)并设置为最高优先级 (24)。将特定任务优先级设为 19 不会妨碍较低层级的 {IDF_TARGET_RF_TYPE} 功能无延迟运行,但仍然会抢占 lwIP TCP/IP 堆栈以及其他非实时内部功能,这对于不执行网络操作的实时任务而言是最佳选项。lwIP TCP/IP 任务优先级 (18) 应高于所有执行 TCP/IP 网络操作的任务,以保证任务正常执行。 + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED -.. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES + 一般情况下,不建议将任务优先级设置得比内置的 {IDF_TARGET_RF_TYPE} 操作更高,因为这样可能会使 CPU 被长时间占用,导致系统不稳定。 + + 对于非常短、对时序要求严格且不涉及网络的操作,可以使用中断服务程序或是限制运行时间的最高优先级 (24) 任务。 + + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED + + 将特定任务优先级设为 19,则较低层级的 {IDF_TARGET_RF_TYPE} 功能可以无延迟运行,且仍然会抢占 lwIP TCP/IP 堆栈以及其他非实时内部功能,这对于不执行网络操作的实时任务而言是最佳选项。 + + lwIP TCP/IP 任务优先级 (18) 应高于所有执行 TCP/IP 网络操作的任务,从而避免优先级反转的问题。 + +.. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES + + 默认配置下,除了个别例外,尤其是 lwIP TCP/IP 任务,大多数内置任务都固定在核 0 上执行。因此,应用程序可以方便地将高优先级任务放置在核 1 上执行。优先级大于等于 19 的应用程序任务在核 1 上运行时可以确保不会被任何内置任务抢占。为了进一步隔离各个 CPU 上运行的任务,配置 :ref:`lwIP 任务 ` ,可以使 lwIP 任务仅在核 0 上运行,而非其他内核,这可能会根据其他任务的运行情况减少总 TCP/IP 吞吐量。 - 默认配置下,除了个别例外,尤其是 lwIP TCP/IP 任务,大多数内置任务都固定在核心 0 上执行。因此,应用程序可以方便地将高优先级任务放置在核心 1 上执行。优先级大于等于 19 的应用程序任务在核心 1 上运行时可以确保不会被任何内置任务抢占。为了进一步隔离各个 CPU 上运行的任务,配置 :ref:`lwIP 任务 ` ,可以使 lwIP 任务仅在核心 0 上运行,而非上述任一核心,这可能会根据其他任务的运行情况减少总 TCP/IP 吞吐量。 + .. only:: SOC_WIFI_SUPPORTED or SOC_BT_SUPPORTED or SOC_IEEE802154_SUPPORTED - 由于 {IDF_TARGET_RF_TYPE} 操作饥饿可能导致系统不稳定,通常不建议让核心 0 上特定任务的优先级高于 {IDF_TARGET_RF_TYPE} 操作的内置优先级。将特定任务优先级设置为 19 并在核心 0 上运行,不会妨碍较低层级的 {IDF_TARGET_RF_TYPE} 功能无延迟运行,但仍然会抢占 lwIP TCP/IP 堆栈以及其他非实时内部功能,该选项适用于不执行网络操作的实时任务。lwIP TCP/IP 任务优先级 (18) 应高于所有执行 TCP/IP 网络操作的任务,以保证任务正常执行。 + 一般情况下,不建议将核 0 上的任务优先级设置得比内置的 {IDF_TARGET_RF_TYPE} 操作更高,因为这样可能会使 CPU 被长时间占用,导致系统不稳定。选择优先级为 19 并在核 0 上运行可以使底层 {IDF_TARGET_RF_TYPE} 功能运行无延迟,但仍会抢占 lwIP TCP/IP 栈和其他不太关键的内部功能。这对于无需执行网络操作且时序要求高的任务来说是一个选择。执行 TCP/IP 网络操作的任何任务都应该以低于 lwIP TCP/IP 任务 (18) 的优先级运行,以避免优先级反转问题。 .. note:: - 如果要让特定任务始终先于 ESP-IDF 内置任务运行,并不需要将其固定在核心 1 上。将该任务优先级设置为小于等于 17,则无需与核心绑定,那么核心 0 上没有执行较高优先级的内置任务时,该任务也可以选择在核心 0 上执行。使用未固定的任务可以提高整体 CPU 利用率,但这会增加任务调度的复杂性。 + 如果要让特定任务始终先于 ESP-IDF 内置任务运行,并不需要将其固定在核 1 上。将该任务优先级设置为小于等于 17,则无需与内核绑定,那么核 0 上没有执行较高优先级的内置任务时,该任务也可以选择在核 0 上执行。使用未固定的任务可以提高整体 CPU 利用率,但这会增加任务调度的复杂性。 .. note:: @@ -234,7 +279,7 @@ ESP-IDF 支持动态 :doc:`/api-reference/system/intr_alloc` 和中断抢占。 .. list:: - 调用 :cpp:func:`esp_intr_alloc` 时使用 ``ESP_INTR_FLAG_LEVEL2`` 或 ``ESP_INTR_FLAG_LEVEL3`` 等标志,可以为更重要的中断设定更高优先级。 - :SOC_HP_CPU_HAS_MULTIPLE_CORES: - 将中断分配到不运行内置 {IDF_TARGET_RF_TYPE} 任务的 CPU 上执行,即默认情况下,将中断分配到核心 1 上执行,参见 :ref:`built-in-task-priorities` 。调用 :cpp:func:`esp_intr_alloc` 函数即可将中断分配到函数所在 CPU。 + :SOC_HP_CPU_HAS_MULTIPLE_CORES: - 将中断分配到不运行内置 {IDF_TARGET_RF_TYPE} 任务的 CPU 上执行,即默认情况下,将中断分配到核 1 上执行,参见 :ref:`built-in-task-priorities` 。调用 :cpp:func:`esp_intr_alloc` 函数即可将中断分配到函数所在 CPU。 - 如果确定整个中断处理程序可以在 IRAM 中运行(参见 :ref:`iram-safe-interrupt-handlers` ),那么在调用 :cpp:func:`esp_intr_alloc` 分配中断时,请设置 ``ESP_INTR_FLAG_IRAM`` 标志,这样可以防止在应用程序固件写入内置 SPI flash 时临时禁用中断。 - 即使是非 IRAM 安全的中断处理程序,如果需要频繁执行,可以考虑将处理程序的函数移到 IRAM 中,从而尽可能规避执行中断代码时发生 flash 缓存缺失的可能性(参见 :ref:`speed-targeted-optimizations` )。如果可以确保只有部分处理程序位于 IRAM 中,则无需添加 ``ESP_INTR_FLAG_IRAM`` 标志将程序标记为 IRAM 安全。 From 89218b35e46075363488c622c19f2313edc121af Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Fri, 26 Apr 2024 16:37:32 +0400 Subject: [PATCH 111/548] fix(system): place idf's stray sections while linking --- Kconfig | 21 +++++ .../subproject/main/ld/esp32/bootloader.ld | 51 ++++++++++- .../subproject/main/ld/esp32c2/bootloader.ld | 55 +++++++++++- .../subproject/main/ld/esp32c3/bootloader.ld | 56 +++++++++++- .../main/ld/esp32c5/beta3/bootloader.ld | 54 ++++++++++++ .../main/ld/esp32c5/mp/bootloader.ld | 54 ++++++++++++ .../subproject/main/ld/esp32c6/bootloader.ld | 56 +++++++++++- .../subproject/main/ld/esp32c61/bootloader.ld | 54 ++++++++++++ .../subproject/main/ld/esp32h2/bootloader.ld | 57 +++++++++++- .../subproject/main/ld/esp32p4/bootloader.ld | 63 +++++++++++++- .../subproject/main/ld/esp32s2/bootloader.ld | 48 +++++++++- .../subproject/main/ld/esp32s3/bootloader.ld | 48 +++++++++- components/esp_system/ld/elf_misc.ld.in | 87 +++++++++++++++++++ components/esp_system/ld/esp32/sections.ld.in | 29 +------ .../esp_system/ld/esp32c2/sections.ld.in | 15 +--- .../esp_system/ld/esp32c3/sections.ld.in | 15 +--- .../ld/esp32c5/beta3/sections.ld.in | 15 +--- .../esp_system/ld/esp32c5/mp/sections.ld.in | 15 +--- .../esp_system/ld/esp32c6/sections.ld.in | 15 +--- .../esp_system/ld/esp32c61/sections.ld.in | 15 +--- .../esp_system/ld/esp32h2/sections.ld.in | 15 +--- .../esp_system/ld/esp32p4/sections.ld.in | 15 +--- .../esp_system/ld/esp32s2/sections.ld.in | 29 +------ .../esp_system/ld/esp32s3/sections.ld.in | 31 +------ tools/cmake/project.cmake | 8 +- tools/idf_py_actions/hints.yml | 4 + 26 files changed, 717 insertions(+), 208 deletions(-) create mode 100644 components/esp_system/ld/elf_misc.ld.in diff --git a/Kconfig b/Kconfig index 4330006c897..eff82a46915 100644 --- a/Kconfig +++ b/Kconfig @@ -607,6 +607,27 @@ mainmenu "Espressif IoT Development Framework Configuration" default "gcc" if COMPILER_RT_LIB_GCCLIB default "" if COMPILER_RT_LIB_HOST + choice COMPILER_ORPHAN_SECTIONS + prompt "Orphan sections handling" + default COMPILER_ORPHAN_SECTIONS_PLACE + depends on !IDF_TARGET_LINUX + help + If the linker finds orphan sections, it attempts to place orphan sections after sections of the same + attribute such as code vs data, loadable vs non-loadable, etc. + That means that orphan sections could placed between sections defined in IDF linker scripts. + This could lead to corruption of the binary image. Configure the linker action here. + + config COMPILER_ORPHAN_SECTIONS_WARNING + bool "Place with warning" + help + Places orphan sections without a warning message. + + config COMPILER_ORPHAN_SECTIONS_PLACE + bool "Place silently" + help + Places orphan sections without a warning/error message. + endchoice + endmenu # Compiler Options menu "Component config" diff --git a/components/bootloader/subproject/main/ld/esp32/bootloader.ld b/components/bootloader/subproject/main/ld/esp32/bootloader.ld index 5814b3e3cb6..d5fb575ddd5 100644 --- a/components/bootloader/subproject/main/ld/esp32/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -119,6 +119,7 @@ SECTIONS .dram0.data : ALIGN(0x10) { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -144,6 +145,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -208,12 +210,55 @@ SECTIONS */ .xt.prop 0 : { - KEEP (*(.xt.prop .gnu.linkonce.prop.*)) + KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) } .xt.lit 0 : { - KEEP (*(.xt.lit .gnu.linkonce.p.*)) + KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) } + .xtensa.info 0: { *(.xtensa.info) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } } diff --git a/components/bootloader/subproject/main/ld/esp32c2/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c2/bootloader.ld index a7cd5406965..f80441cebbe 100644 --- a/components/bootloader/subproject/main/ld/esp32c2/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c2/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -140,6 +140,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -165,6 +166,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -218,6 +220,57 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } } /** diff --git a/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld index a444e680a79..21f19c14fe8 100644 --- a/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -140,6 +140,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -165,6 +166,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -218,6 +220,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32c5/beta3/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c5/beta3/bootloader.ld index 00888b788fb..a2c0ef52ed8 100644 --- a/components/bootloader/subproject/main/ld/esp32c5/beta3/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c5/beta3/bootloader.ld @@ -139,6 +139,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -164,6 +165,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -217,6 +219,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32c5/mp/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c5/mp/bootloader.ld index 5b9af6783e5..e389464825c 100644 --- a/components/bootloader/subproject/main/ld/esp32c5/mp/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c5/mp/bootloader.ld @@ -138,6 +138,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -163,6 +164,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -216,6 +218,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32c6/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c6/bootloader.ld index 3fc5861d850..a9eb54247ce 100644 --- a/components/bootloader/subproject/main/ld/esp32c6/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c6/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -138,6 +138,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -163,6 +164,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -216,6 +218,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32c61/bootloader.ld b/components/bootloader/subproject/main/ld/esp32c61/bootloader.ld index 08e3d45c4ad..61bdd1bc2be 100644 --- a/components/bootloader/subproject/main/ld/esp32c61/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32c61/bootloader.ld @@ -138,6 +138,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -163,6 +164,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -216,6 +218,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32h2/bootloader.ld b/components/bootloader/subproject/main/ld/esp32h2/bootloader.ld index 2c40fece3d1..9ae2a74d8c2 100644 --- a/components/bootloader/subproject/main/ld/esp32h2/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32h2/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -138,7 +138,7 @@ SECTIONS .dram0.data : { - _data_start = ABSOLUTE(.); + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -164,6 +164,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -217,6 +218,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } /** diff --git a/components/bootloader/subproject/main/ld/esp32p4/bootloader.ld b/components/bootloader/subproject/main/ld/esp32p4/bootloader.ld index 348feb2a96a..b73ae430f40 100644 --- a/components/bootloader/subproject/main/ld/esp32p4/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32p4/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -131,9 +131,15 @@ SECTIONS _bss_end = ABSOLUTE(.); } > dram_seg - .dram0.data : + .dram0.bootdesc : ALIGN(0x10) { _data_start = ABSOLUTE(.); + *(.data_bootloader_desc .data_bootloader_desc.*) /* Should be the first. Bootloader version info. DO NOT PUT ANYTHING BEFORE IT! */ + } > dram_seg + + .dram0.data : + { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -159,6 +165,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -212,6 +219,58 @@ SECTIONS _etext = .; } > iram_seg + .riscv.attributes 0: { *(.riscv.attributes) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + /DISCARD/ : { *(.rela.*) } + } diff --git a/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld b/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld index 394f1a3e51b..f2c4ede304d 100644 --- a/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32s2/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -108,6 +108,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -133,6 +134,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -205,4 +207,48 @@ SECTIONS KEEP (*(.xt.lit .gnu.linkonce.p.*)) } + .xtensa.info 0: { *(.xtensa.info) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + } diff --git a/components/bootloader/subproject/main/ld/esp32s3/bootloader.ld b/components/bootloader/subproject/main/ld/esp32s3/bootloader.ld index bdebbaf9819..c0f4702a018 100644 --- a/components/bootloader/subproject/main/ld/esp32s3/bootloader.ld +++ b/components/bootloader/subproject/main/ld/esp32s3/bootloader.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -142,6 +142,7 @@ SECTIONS .dram0.data : { + *(.dram1 .dram1.*) /* catch stray DRAM_ATTR */ *(.data) *(.data.*) *(.gnu.linkonce.d.*) @@ -167,6 +168,7 @@ SECTIONS *(.gcc_except_table) *(.gnu.linkonce.e.*) *(.gnu.version_r) + *(.eh_frame_hdr) *(.eh_frame) . = (. + 3) & ~ 3; /* C++ constructor and destructor tables, properly ordered: */ @@ -239,6 +241,50 @@ SECTIONS KEEP (*(.xt.lit .gnu.linkonce.p.*)) } + .xtensa.info 0: { *(.xtensa.info) } + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + } /** diff --git a/components/esp_system/ld/elf_misc.ld.in b/components/esp_system/ld/elf_misc.ld.in new file mode 100644 index 00000000000..f1e9d5a8001 --- /dev/null +++ b/components/esp_system/ld/elf_misc.ld.in @@ -0,0 +1,87 @@ +#include "sdkconfig.h" + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + .debug_pubtypes 0 : { *(.debug_pubtypes) } + /* DWARF 3 */ + .debug_ranges 0 : { *(.debug_ranges) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* GNU DWARF 2 extensions */ + .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } + .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } + /* DWARF 4 */ + .debug_types 0 : { *(.debug_types) } + /* DWARF 5 */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + + .comment 0 : { *(.comment) } + .note.GNU-stack 0: { *(.note.GNU-stack) } + +#if CONFIG_IDF_TARGET_ARCH_RISCV + .riscv.attributes 0: { *(.riscv.attributes) } + + /DISCARD/ : + { + /** + * Discarding .rela.* sections results in the following mapping: + * .rela.text.* -> .text.* + * .rela.data.* -> .data.* + * And so forth... + */ + *(.rela.*) +#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + *(.eh_frame_hdr) + *(.eh_frame) +#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) + } +#elif CONFIG_IDF_TARGET_ARCH_XTENSA +/** + * .xt.prop and .xt.lit sections will be used by the debugger and disassembler + * to get more information about raw data present in the code. + * Indeed, it may be required to add some padding at some points in the code + * in order to align a branch/jump destination on a particular bound. + * Padding these instructions will generate null bytes that shall be + * interpreted as data, and not code by the debugger or disassembler. + * This section will only be present in the ELF file, not in the final binary + * For more details, check GCC-212 + */ + .xtensa.info 0: { *(.xtensa.info) } + .xt.prop 0 : { *(.xt.prop .xt.prop.* .gnu.linkonce.prop.*) } + .xt.lit 0 : { *(.xt.lit .xt.lit.* .gnu.linkonce.p.*) } + + /DISCARD/ : + { + *(.fini) + *(.eh_frame_hdr) +#if !CONFIG_COMPILER_CXX_EXCEPTIONS + *(.eh_frame) +#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS + } +#else + #error "Target architecture is not supported!" +#endif diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index b67d6af10d5..066994b743e 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -218,6 +218,7 @@ SECTIONS *(.UserEnter.literal); *(.UserEnter.text); . = ALIGN (16); + *(.entry.literal) *(.entry.text) *(.init.literal) *(.init) @@ -490,33 +491,7 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg - /** - * This section will be used by the debugger and disassembler to get more - * information about raw data present in the code. - * Indeed, it may be required to add some padding at some points in the code - * in order to align a branch/jump destination on a particular bound. - * Padding these instructions will generate null bytes that shall be - * interpreted as data, and not code by the debugger or disassembler. - * This section will only be present in the ELF file, not in the final binary - * For more details, check GCC-212 - */ - .xt.prop 0 : - { - KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) - } - - .xt.lit 0 : - { - KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) - } - - /DISCARD/ : - { - *(.eh_frame_hdr) -#if !CONFIG_COMPILER_CXX_EXCEPTIONS - *(.eh_frame) -#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index 43255d8d933..d6cd3757832 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -345,20 +345,7 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index c8c29d8cd54..1077f6966dd 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -457,20 +457,7 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c5/beta3/sections.ld.in b/components/esp_system/ld/esp32c5/beta3/sections.ld.in index 16533c7af6d..e2db66dab41 100644 --- a/components/esp_system/ld/esp32c5/beta3/sections.ld.in +++ b/components/esp_system/ld/esp32c5/beta3/sections.ld.in @@ -448,20 +448,7 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > dram0_0_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32c5/mp/sections.ld.in b/components/esp_system/ld/esp32c5/mp/sections.ld.in index 91013909f6d..54673f7a822 100644 --- a/components/esp_system/ld/esp32c5/mp/sections.ld.in +++ b/components/esp_system/ld/esp32c5/mp/sections.ld.in @@ -448,20 +448,7 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index cfd95dd74d9..ff44c831b6e 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -438,18 +438,5 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } diff --git a/components/esp_system/ld/esp32c61/sections.ld.in b/components/esp_system/ld/esp32c61/sections.ld.in index 91013909f6d..54673f7a822 100644 --- a/components/esp_system/ld/esp32c61/sections.ld.in +++ b/components/esp_system/ld/esp32c61/sections.ld.in @@ -448,20 +448,7 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(sram_seg)) <= LENGTH(sram_seg)), diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index cfd95dd74d9..ff44c831b6e 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -438,18 +438,5 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start) } > sram_seg - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index 9b5667b18ef..38d844c4bd1 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -514,18 +514,5 @@ SECTIONS ALIGNED_SYMBOL(16, _heap_start_high) } > sram_high - /DISCARD/ : - { - /** - * Discarding .rela.* sections results in the following mapping: - * .rela.text.* -> .text.* - * .rela.data.* -> .data.* - * And so forth... - */ - *(.rela.*) -#if !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - *(.eh_frame_hdr) - *(.eh_frame) -#endif // !(CONFIG_COMPILER_CXX_EXCEPTIONS || CONFIG_ESP_SYSTEM_USE_EH_FRAME) - } +#include "elf_misc.ld.in" } diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index a6a5e4c806e..65935dcf976 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -204,6 +204,7 @@ SECTIONS *(.UserEnter.literal); *(.UserEnter.text); . = ALIGN (16); + *(.entry.literal) *(.entry.text) *(.init.literal) *(.init) @@ -454,33 +455,7 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg - /** - * This section will be used by the debugger and disassembler to get more - * information about raw data present in the code. - * Indeed, it may be required to add some padding at some points in the code - * in order to align a branch/jump destination on a particular bound. - * Padding these instructions will generate null bytes that shall be - * interpreted as data, and not code by the debugger or disassembler. - * This section will only be present in the ELF file, not in the final binary - * For more details, check GCC-212 - */ - .xt.prop 0 : - { - KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) - } - - .xt.lit 0 : - { - KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) - } - - /DISCARD/ : - { - *(.eh_frame_hdr) -#if !CONFIG_COMPILER_CXX_EXCEPTIONS - *(.eh_frame) -#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS - } +#include "elf_misc.ld.in" } ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index 6eabbd5026b..48173b87572 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -20,7 +20,7 @@ SECTIONS ALIGNED_SYMBOL(4, _rtc_fast_start) ALIGNED_SYMBOL(4, _rtc_text_start) - *(.rtc.entry.text) + *(.rtc.entry.literal .rtc.entry.text) mapping[rtc_text] @@ -187,6 +187,7 @@ SECTIONS *(.UserEnter.literal); *(.UserEnter.text); . = ALIGN (16); + *(.entry.literal) *(.entry.text) *(.init.literal) *(.init) @@ -487,33 +488,7 @@ SECTIONS ALIGNED_SYMBOL(8, _heap_low_start) } > dram0_0_seg - /** - * This section will be used by the debugger and disassembler to get more - * information about raw data present in the code. - * Indeed, it may be required to add some padding at some points in the code - * in order to align a branch/jump destination on a particular bound. - * Padding these instructions will generate null bytes that shall be - * interpreted as data, and not code by the debugger or disassembler. - * This section will only be present in the ELF file, not in the final binary - * For more details, check GCC-212 - */ - .xt.prop 0 : - { - KEEP (*(.xt.prop .xt.prop.* .gnu.linkonce.prop.*)) - } - - .xt.lit 0 : - { - KEEP (*(.xt.lit .xt.lit.* .gnu.linkonce.p.*)) - } - - /DISCARD/ : - { - *(.eh_frame_hdr) -#if !CONFIG_COMPILER_CXX_EXCEPTIONS - *(.eh_frame) -#endif // !CONFIG_COMPILER_CXX_EXCEPTIONS - } +#include "elf_misc.ld.in" } ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)), diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index e92e5855d5a..c253a7008d5 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -67,7 +67,7 @@ idf_build_set_property(__COMPONENT_MANAGER_INTERFACE_VERSION 2) # Parse and store the VERSION argument provided to the project() command. # function(__parse_and_store_version_arg) - # The project_name is the fisrt argument that was passed to the project() command + # The project_name is the first argument that was passed to the project() command set(project_name ${ARGV0}) # Parse other arguments passed to the project() call @@ -663,7 +663,7 @@ macro(project project_name) # 3. git describe if the project is in a git repository # 4. Default to 1 if none of the above conditions are true # - # PS: PROJECT_VER will get overidden later if CONFIG_APP_PROJECT_VER_FROM_CONFIG is defined. + # PS: PROJECT_VER will get overridden later if CONFIG_APP_PROJECT_VER_FROM_CONFIG is defined. # See components/esp_app_format/CMakeLists.txt. if(NOT DEFINED PROJECT_VER) # Read the version information from the version.txt file if it is present @@ -825,6 +825,10 @@ macro(project project_name) # Do not print RWX segment warnings target_link_options(${project_elf} PRIVATE "-Wl,--no-warn-rwx-segments") endif() + if(CONFIG_ESP_ORPHAN_SECTION_WARNING) + # Print warnings if orphan sections are found + target_link_options(${project_elf} PRIVATE "-Wl,--orphan-handling=warn") + endif() unset(idf_target) endif() diff --git a/tools/idf_py_actions/hints.yml b/tools/idf_py_actions/hints.yml index c47560a2be0..f3bd56bf21d 100644 --- a/tools/idf_py_actions/hints.yml +++ b/tools/idf_py_actions/hints.yml @@ -426,3 +426,7 @@ - re: "implicit declaration of function '(opendir|readdir|telldir|seekdir|rewinddir|closedir|readdir_r|scandir|alphasort)'" hint: "Please include (not )" + +- + re: "unplaced orphan section" + hint: "Avoid creating custom sections. Please refer to the 'Linker Script Generation' article in the IDF documentation to address this. Or set option CONFIG_COMPILER_ORPHAN_SECTIONS_PLACE (not recommended)." From 021dc8747c5ea2dca9ab3e1e34fef4ed6e3769ef Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Mon, 22 Apr 2024 08:34:44 -0500 Subject: [PATCH 112/548] fix(ws_transport): fixed `server-key` corruption When first fragment is sent over HTTP during websocket connection, defer buffering of fragment until after the websocket server-key is validated. This order is required because the first fragment buffering overwrites the memory holding the server-key headers. Fixes 2267d4b Fixes https://github.com/espressif/esp-protocols/issues/396 PR https://github.com/espressif/esp-idf/pull/13724 --- components/tcp_transport/transport_ws.c | 30 +++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index 75cea861041..aaf0ce42c15 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -307,20 +307,6 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int return -1; } - if (delim_ptr != NULL) { - size_t delim_pos = delim_ptr - ws->buffer + sizeof(delimiter) - 1; - size_t remaining_len = ws->buffer_len - delim_pos; - if (remaining_len > 0) { - memmove(ws->buffer, ws->buffer + delim_pos, remaining_len); - ws->buffer_len = remaining_len; - } else { -#ifdef CONFIG_WS_DYNAMIC_BUFFER - free(ws->buffer); - ws->buffer = NULL; -#endif - ws->buffer_len = 0; - } - } // See esp_crypto_sha1() arg size unsigned char expected_server_sha1[20]; // Size of base64 coded string see above @@ -340,6 +326,22 @@ static int ws_connect(esp_transport_handle_t t, const char *host, int port, int ESP_LOGE(TAG, "Invalid websocket key"); return -1; } + + if (delim_ptr != NULL) { + size_t delim_pos = delim_ptr - ws->buffer + sizeof(delimiter) - 1; + size_t remaining_len = ws->buffer_len - delim_pos; + if (remaining_len > 0) { + memmove(ws->buffer, ws->buffer + delim_pos, remaining_len); + ws->buffer_len = remaining_len; + } else { +#ifdef CONFIG_WS_DYNAMIC_BUFFER + free(ws->buffer); + ws->buffer = NULL; +#endif + ws->buffer_len = 0; + } + } + return 0; } From a3d77114b67ba3850950483694cbe8c42c7fa428 Mon Sep 17 00:00:00 2001 From: Suren Gabrielyan Date: Thu, 16 May 2024 15:51:46 +0400 Subject: [PATCH 113/548] fix(ws_transport): utility functions minor improvments --- components/tcp_transport/transport_ws.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/tcp_transport/transport_ws.c b/components/tcp_transport/transport_ws.c index aaf0ce42c15..529494ca09d 100644 --- a/components/tcp_transport/transport_ws.c +++ b/components/tcp_transport/transport_ws.c @@ -131,7 +131,7 @@ static int esp_transport_read_internal(transport_ws_t *ws, char *buffer, int len return to_read; } -static char *trimwhitespace(const char *str) +static char *trimwhitespace(char *str) { char *end; @@ -141,19 +141,19 @@ static char *trimwhitespace(const char *str) } if (*str == 0) { - return (char *)str; + return str; } // Trim trailing space - end = (char *)(str + strlen(str) - 1); + end = str + strlen(str) - 1; while (end > str && isspace((unsigned char)*end)) { end--; } // Write new null terminator - *(end + 1) = 0; + *(end + 1) = '\0'; - return (char *)str; + return str; } static int get_http_status_code(const char *buffer) @@ -162,11 +162,11 @@ static int get_http_status_code(const char *buffer) const char *found = strcasestr(buffer, http); char status_code[4]; if (found) { - found += sizeof(http)/sizeof(http[0]) - 1; + found += sizeof(http) - 1; found = strchr(found, ' '); if (found) { found++; - strncpy(status_code, found, 4); + strncpy(status_code, found, 3); status_code[3] = '\0'; int code = atoi(status_code); ESP_LOGD(TAG, "HTTP status code is %d", code); @@ -176,14 +176,14 @@ static int get_http_status_code(const char *buffer) return -1; } -static char *get_http_header(const char *buffer, const char *key) +static char *get_http_header(char *buffer, const char *key) { char *found = strcasestr(buffer, key); if (found) { found += strlen(key); char *found_end = strstr(found, "\r\n"); if (found_end) { - found_end[0] = 0;//terminal string + *found_end = '\0'; // terminal string return trimwhitespace(found); } From 7c49b1da557b6f09cb48b2a9946257ad58e81b2d Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Tue, 21 May 2024 13:54:43 +0800 Subject: [PATCH 114/548] ci: add 5.3 known failed cases filename --- .gitlab/ci/common.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/common.yml b/.gitlab/ci/common.yml index b811b9c8e4e..687d8516406 100644 --- a/.gitlab/ci/common.yml +++ b/.gitlab/ci/common.yml @@ -84,7 +84,7 @@ variables: CI_PYTHON_TOOL_BRANCH: "" # Set this variable to specify the file name for the known failure cases. - KNOWN_FAILURE_CASES_FILE_NAME: "master.txt" + KNOWN_FAILURE_CASES_FILE_NAME: "5.3.txt" IDF_CI_BUILD: 1 From 5ec85c0bfd1e938b7d8d1318d6e26f5d0ceb7829 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 16 May 2024 15:29:27 +0800 Subject: [PATCH 115/548] feat(axi_icm): AXI interconnect QoS configuration functions --- .../hal/esp32p4/include/hal/axi_icm_ll.h | 180 ++++++++++++++++++ .../soc/esp32p4/include/soc/icm_sys_qos_reg.h | 10 +- .../esp32p4/include/soc/icm_sys_qos_struct.h | 10 +- .../soc/esp32p4/include/soc/icm_sys_reg.h | 42 ++-- .../soc/esp32p4/include/soc/icm_sys_struct.h | 9 +- components/soc/esp32p4/include/soc/reg_base.h | 1 + .../soc/esp32p4/ld/esp32p4.peripherals.ld | 2 + 7 files changed, 220 insertions(+), 34 deletions(-) create mode 100644 components/hal/esp32p4/include/hal/axi_icm_ll.h diff --git a/components/hal/esp32p4/include/hal/axi_icm_ll.h b/components/hal/esp32p4/include/hal/axi_icm_ll.h new file mode 100644 index 00000000000..eff188d4cdf --- /dev/null +++ b/components/hal/esp32p4/include/hal/axi_icm_ll.h @@ -0,0 +1,180 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include +#include "hal/assert.h" +#include "soc/icm_sys_qos_struct.h" +#include "soc/icm_sys_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + AXI_ICM_MASTER_CPU = 0, // An aggregate master port for other users, like HP CPU, LP CPU, USB, EMAC, SDMMC, AHB-GDMA, etc + AXI_ICM_MASTER_CACHE = 1, // Cache master port + AXI_ICM_MASTER_DW_GDMA_M0 = 5, // DW-GDMA master port 0 + AXI_ICM_MASTER_DW_GDMA_M1 = 6, // DW-GDMA master port 1 + AXI_ICM_MASTER_GDMA = 8, // AXI-GDMA + AXI_ICM_MASTER_DMA2D = 10, // DMA2D + AXI_ICM_MASTER_H264_M0 = 11, // H264 master port 0 + AXI_ICM_MASTER_H264_M1 = 12, // H264 master port 1 +} axi_icm_ll_master_id_t; + +/** + * @brief Set QoS burstiness for a master port, also enable the regulator + * + * @param mid Master port ID + * @param burstiness Burstiness value. It represents the depth of the token bucket. + */ +static inline void axi_icm_ll_set_qos_burstiness(axi_icm_ll_master_id_t mid, uint32_t burstiness) +{ + HAL_ASSERT(burstiness >= 1 && burstiness <= 256); + // wait for the previous command to finish + while (AXI_ICM_QOS.cmd.reg_axi_cmd_en); + // write data register + // data[23:16] - burstiness, data[0] - enable regulator + AXI_ICM_QOS.data.val = (burstiness - 1) << 16 | 0x1; + // command write operation + AXI_ICM_QOS.cmd.reg_axi_rd_wr_cmd = 1; + // write addr channel + AXI_ICM_QOS.cmd.reg_rd_wr_chan = 1; + // select master port + AXI_ICM_QOS.cmd.reg_axi_master_port = mid; + // set command type: burstiness regulator + AXI_ICM_QOS.cmd.reg_axi_cmd = 0; + // command enable bit + AXI_ICM_QOS.cmd.reg_axi_cmd_en = 1; + // wait for the data to be synced to internal register + while (AXI_ICM_QOS.cmd.reg_axi_cmd_en); +} + +/** + * @brief Set QoS peak and transaction rate for a master port + * + * @note Relationship between "level" and fractional rate: + * level = 0: 1/2 + * level = 1: 1/4 + * ... + * level = 11: 1/4096 + * + * @note if the transaction rate is set to 1/N, every N cycles, the master port can accept one transfer request (offer a token). + * + * @param mid Master port ID + * @param peak_level Peak level, lower value means higher rate + * @param transaction_level Transaction level, lower value means higher rate + */ +static inline void axi_icm_ll_set_qos_peak_transaction_rate(axi_icm_ll_master_id_t mid, uint32_t peak_level, uint32_t transaction_level) +{ + HAL_ASSERT(peak_level < transaction_level && transaction_level <= 11); + while (AXI_ICM_QOS.cmd.reg_axi_cmd_en); + // program data register + // data[31:20] - peak_rate, data[15:4] - transaction_rate + AXI_ICM_QOS.data.val = (0x80000000 >> peak_level) + (0x8000 >> transaction_level); + // command write operation + AXI_ICM_QOS.cmd.reg_axi_rd_wr_cmd = 1; + // write addr channel + AXI_ICM_QOS.cmd.reg_rd_wr_chan = 1; + // select master port + AXI_ICM_QOS.cmd.reg_axi_master_port = mid; + // set command type: peak rate xct rate + AXI_ICM_QOS.cmd.reg_axi_cmd = 1; + // command enable bit + AXI_ICM_QOS.cmd.reg_axi_cmd_en = 1; + // wait for the data to be synced to internal register + while (AXI_ICM_QOS.cmd.reg_axi_cmd_en); +} + +/** + * @brief Set QoS priority for DMA2D master port + * + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_dma2d_qos_arbiter_prio(uint32_t write_prio, uint32_t read_prio) +{ + AXI_ICM.mst_awqos_reg0.reg_dma2d_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_dma2d_arqos = read_prio; +} + +/** + * @brief Set QoS priority for AXI-GDMA master port + * + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_gdma_qos_arbiter_prio(uint32_t write_prio, uint32_t read_prio) +{ + AXI_ICM.mst_awqos_reg0.reg_pdma_int_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_axi_pdma_int_arqos = read_prio; +} + +/** + * @brief Set QoS priority for DW_GDMA master port + * + * @param master_port DW_GDMA master port ID + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_dw_gdma_qos_arbiter_prio(uint32_t master_port, uint32_t write_prio, uint32_t read_prio) +{ + if (master_port == 0) { + AXI_ICM.mst_awqos_reg0.reg_gdma_mst1_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_gdma_mst1_arqos = read_prio; + } else { + AXI_ICM.mst_awqos_reg0.reg_gdma_mst2_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_gdma_mst2_arqos = read_prio; + } +} + +/** + * @brief Set QoS priority for H264 master port + * + * @param master_port H264 master port ID + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_h264_dma_qos_arbiter_prio(uint32_t master_port, uint32_t write_prio, uint32_t read_prio) +{ + if (master_port == 0) { + AXI_ICM.mst_awqos_reg0.reg_h264_dma2d_m1_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_h264_dma2d_m1_arqos = read_prio; + } else { + AXI_ICM.mst_awqos_reg0.reg_h264_dma2d_m2_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_h264_dma2d_m2_arqos = read_prio; + } +} + +/** + * @brief Set QoS priority for Cache master port + * + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_cache_qos_arbiter_prio(uint32_t write_prio, uint32_t read_prio) +{ + AXI_ICM.mst_awqos_reg0.reg_cache_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_cache_arqos = read_prio; +} + +/** + * @brief Set QoS priority for CPU master port + * + * @param write_prio Write priority + * @param read_prio Read priority + */ +static inline void axi_icm_ll_set_cpu_qos_arbiter_prio(uint32_t write_prio, uint32_t read_prio) +{ + AXI_ICM.mst_awqos_reg0.reg_cpu_awqos = write_prio; + AXI_ICM.mst_arqos_reg0.reg_cpu_arqos = read_prio; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/icm_sys_qos_reg.h b/components/soc/esp32p4/include/soc/icm_sys_qos_reg.h index 9b428ae8605..09bf4eb269f 100644 --- a/components/soc/esp32p4/include/soc/icm_sys_qos_reg.h +++ b/components/soc/esp32p4/include/soc/icm_sys_qos_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ extern "C" { /** ICM_VERID_FILEDS_REG register * NA */ -#define ICM_VERID_FILEDS_REG (DR_REG_ICM_BASE + 0x0) +#define ICM_VERID_FILEDS_REG (DR_REG_AXI_ICM_QOS_BASE + 0x0) /** ICM_REG_VERID : RO; bitpos: [31:0]; default: 875574314; * NA */ @@ -26,7 +26,7 @@ extern "C" { /** ICM_HW_CFG_REG_REG register * NA */ -#define ICM_HW_CFG_REG_REG (DR_REG_ICM_BASE + 0x4) +#define ICM_HW_CFG_REG_REG (DR_REG_AXI_ICM_QOS_BASE + 0x4) /** ICM_REG_AXI_HWCFG_QOS_SUPPORT : RO; bitpos: [0]; default: 1; * NA */ @@ -108,7 +108,7 @@ extern "C" { /** ICM_CMD_REG register * NA */ -#define ICM_CMD_REG (DR_REG_ICM_BASE + 0x8) +#define ICM_CMD_REG (DR_REG_AXI_ICM_QOS_BASE + 0x8) /** ICM_REG_AXI_CMD : R/W; bitpos: [2:0]; default: 0; * NA */ @@ -162,7 +162,7 @@ extern "C" { /** ICM_DATA_REG register * NA */ -#define ICM_DATA_REG (DR_REG_ICM_BASE + 0xc) +#define ICM_DATA_REG (DR_REG_AXI_ICM_QOS_BASE + 0xc) /** ICM_REG_DATA : R/W; bitpos: [31:0]; default: 0; * NA */ diff --git a/components/soc/esp32p4/include/soc/icm_sys_qos_struct.h b/components/soc/esp32p4/include/soc/icm_sys_qos_struct.h index dbfb2098c7f..0752139bae1 100644 --- a/components/soc/esp32p4/include/soc/icm_sys_qos_struct.h +++ b/components/soc/esp32p4/include/soc/icm_sys_qos_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,7 +10,7 @@ extern "C" { #endif -/** Group: ICM AXI VERID FILEDS REG */ +/** Group: ICM AXI VERID FIELDS REG */ /** Type of verid_fileds register * NA */ @@ -144,11 +144,13 @@ typedef struct { volatile icm_hw_cfg_reg_reg_t hw_cfg_reg; volatile icm_cmd_reg_t cmd; volatile icm_data_reg_t data; -} icm_dev_t; +} axi_icm_qos_dev_t; + +extern axi_icm_qos_dev_t AXI_ICM_QOS; #ifndef __cplusplus -_Static_assert(sizeof(icm_dev_t) == 0x10, "Invalid size of icm_dev_t structure"); +_Static_assert(sizeof(axi_icm_qos_dev_t) == 0x10, "Invalid size of axi_icm_qos_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/icm_sys_reg.h b/components/soc/esp32p4/include/soc/icm_sys_reg.h index 8a06b1f0feb..f347868df90 100644 --- a/components/soc/esp32p4/include/soc/icm_sys_reg.h +++ b/components/soc/esp32p4/include/soc/icm_sys_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,7 @@ extern "C" { /** ICM_VER_DATE_REG register * NA */ -#define ICM_VER_DATE_REG (DR_REG_ICM_BASE + 0x0) +#define ICM_VER_DATE_REG (DR_REG_AXI_ICM_BASE + 0x0) /** ICM_REG_VER_DATE : R/W; bitpos: [31:0]; default: 539165204; * NA */ @@ -26,7 +26,7 @@ extern "C" { /** ICM_CLK_EN_REG register * NA */ -#define ICM_CLK_EN_REG (DR_REG_ICM_BASE + 0x4) +#define ICM_CLK_EN_REG (DR_REG_AXI_ICM_BASE + 0x4) /** ICM_REG_CLK_EN : R/W; bitpos: [0]; default: 0; * NA */ @@ -38,7 +38,7 @@ extern "C" { /** ICM_DLOCK_STATUS_REG register * NA */ -#define ICM_DLOCK_STATUS_REG (DR_REG_ICM_BASE + 0x8) +#define ICM_DLOCK_STATUS_REG (DR_REG_AXI_ICM_BASE + 0x8) /** ICM_REG_DLOCK_MST : RO; bitpos: [3:0]; default: 0; * Lowest numbered deadlocked master */ @@ -71,7 +71,7 @@ extern "C" { /** ICM_INT_RAW_REG register * NA */ -#define ICM_INT_RAW_REG (DR_REG_ICM_BASE + 0xc) +#define ICM_INT_RAW_REG (DR_REG_AXI_ICM_BASE + 0xc) /** ICM_REG_DLOCK_INT_RAW : R/WTC/SS; bitpos: [0]; default: 0; * NA */ @@ -97,7 +97,7 @@ extern "C" { /** ICM_INT_ST_REG register * NA */ -#define ICM_INT_ST_REG (DR_REG_ICM_BASE + 0x10) +#define ICM_INT_ST_REG (DR_REG_AXI_ICM_BASE + 0x10) /** ICM_REG_DLOCK_INT_ST : RO; bitpos: [0]; default: 0; * NA */ @@ -123,7 +123,7 @@ extern "C" { /** ICM_INT_ENA_REG register * NA */ -#define ICM_INT_ENA_REG (DR_REG_ICM_BASE + 0x14) +#define ICM_INT_ENA_REG (DR_REG_AXI_ICM_BASE + 0x14) /** ICM_REG_DLOCK_INT_ENA : R/W; bitpos: [0]; default: 1; * NA */ @@ -149,7 +149,7 @@ extern "C" { /** ICM_INT_CLR_REG register * NA */ -#define ICM_INT_CLR_REG (DR_REG_ICM_BASE + 0x18) +#define ICM_INT_CLR_REG (DR_REG_AXI_ICM_BASE + 0x18) /** ICM_REG_DLOCK_INT_CLR : WT; bitpos: [0]; default: 0; * NA */ @@ -175,7 +175,7 @@ extern "C" { /** ICM_MST_ARB_PRIORITY_REG0_REG register * NA */ -#define ICM_MST_ARB_PRIORITY_REG0_REG (DR_REG_ICM_BASE + 0x1c) +#define ICM_MST_ARB_PRIORITY_REG0_REG (DR_REG_AXI_ICM_BASE + 0x1c) /** ICM_REG_CPU_PRIORITY : R/W; bitpos: [3:0]; default: 0; * CPU arbitration priority for command channels between masters connected to sys_icm */ @@ -241,7 +241,7 @@ extern "C" { /** ICM_SLV_ARB_PRIORITY_REG register * NA */ -#define ICM_SLV_ARB_PRIORITY_REG (DR_REG_ICM_BASE + 0x24) +#define ICM_SLV_ARB_PRIORITY_REG (DR_REG_AXI_ICM_BASE + 0x24) /** ICM_REG_L2MEM_PRIORITY : R/W; bitpos: [5:3]; default: 0; * L2MEM arbitration priority for response channels between slaves connected to sys_icm */ @@ -285,7 +285,7 @@ extern "C" { /** ICM_MST_ARQOS_REG0_REG register * NA */ -#define ICM_MST_ARQOS_REG0_REG (DR_REG_ICM_BASE + 0x28) +#define ICM_MST_ARQOS_REG0_REG (DR_REG_AXI_ICM_BASE + 0x28) /** ICM_REG_CPU_ARQOS : R/W; bitpos: [3:0]; default: 0; * NA */ @@ -346,7 +346,7 @@ extern "C" { /** ICM_MST_AWQOS_REG0_REG register * NA */ -#define ICM_MST_AWQOS_REG0_REG (DR_REG_ICM_BASE + 0x30) +#define ICM_MST_AWQOS_REG0_REG (DR_REG_AXI_ICM_BASE + 0x30) /** ICM_REG_CPU_AWQOS : R/W; bitpos: [3:0]; default: 0; * NA */ @@ -407,7 +407,7 @@ extern "C" { /** ICM_SYS_ADDRHOLE_ADDR_REG register * icm sys addr hole address registers */ -#define ICM_SYS_ADDRHOLE_ADDR_REG (DR_REG_ICM_BASE + 0x38) +#define ICM_SYS_ADDRHOLE_ADDR_REG (DR_REG_AXI_ICM_BASE + 0x38) /** ICM_REG_ICM_SYS_ADDRHOLE_ADDR : RO; bitpos: [31:0]; default: 0; * NA */ @@ -419,9 +419,9 @@ extern "C" { /** ICM_SYS_ADDRHOLE_INFO_REG register * NA */ -#define ICM_SYS_ADDRHOLE_INFO_REG (DR_REG_ICM_BASE + 0x3c) +#define ICM_SYS_ADDRHOLE_INFO_REG (DR_REG_AXI_ICM_BASE + 0x3c) /** ICM_REG_ICM_SYS_ADDRHOLE_ID : RO; bitpos: [7:0]; default: 0; - * master id = 4-bit CID + 4-bit UID(refer to related IP) . CID is used to verfiy + * master id = 4-bit CID + 4-bit UID(refer to related IP) . CID is used to verify * master in icm. CID: 4'h1: cache, 4'h5 gdma mst1, 4'h6: gdma mst2, 4'h8: axi pdma, * 4'ha: dma2d, 4'hb: h264 mst1, 4'hc: h264 mst2. */ @@ -448,7 +448,7 @@ extern "C" { /** ICM_CPU_ADDRHOLE_ADDR_REG register * icm cpu addr hole address registers */ -#define ICM_CPU_ADDRHOLE_ADDR_REG (DR_REG_ICM_BASE + 0x40) +#define ICM_CPU_ADDRHOLE_ADDR_REG (DR_REG_AXI_ICM_BASE + 0x40) /** ICM_REG_ICM_CPU_ADDRHOLE_ADDR : RO; bitpos: [31:0]; default: 0; * It is illegall access address if reg_icm_cpu_addrhole_secure is 1. Otherwise, it * the address without permission to access. @@ -461,7 +461,7 @@ extern "C" { /** ICM_CPU_ADDRHOLE_INFO_REG register * NA */ -#define ICM_CPU_ADDRHOLE_INFO_REG (DR_REG_ICM_BASE + 0x44) +#define ICM_CPU_ADDRHOLE_INFO_REG (DR_REG_AXI_ICM_BASE + 0x44) /** ICM_REG_ICM_CPU_ADDRHOLE_ID : RO; bitpos: [4:0]; default: 0; * master id: 5'h0: hp core0, 5'h1:hp core1, 5'h2:lp core, 5'h3:usb otg11, 5'h4: * regdma, 5'h5: gmac, 5'h5 sdmmc, 5'h7: usbotg20, 5'h8: trace0, 5'h9: trace1, 5'ha @@ -489,7 +489,7 @@ extern "C" { /** ICM_DLOCK_TIMEOUT_REG register * NA */ -#define ICM_DLOCK_TIMEOUT_REG (DR_REG_ICM_BASE + 0x48) +#define ICM_DLOCK_TIMEOUT_REG (DR_REG_AXI_ICM_BASE + 0x48) /** ICM_REG_DLOCK_TIMEOUT : R/W; bitpos: [12:0]; default: 2048; * if no response until reg_dlock_timeout bus clock cycle, deadlock will happen */ @@ -501,7 +501,7 @@ extern "C" { /** ICM_RDN_ECO_CS_REG register * NA */ -#define ICM_RDN_ECO_CS_REG (DR_REG_ICM_BASE + 0x50) +#define ICM_RDN_ECO_CS_REG (DR_REG_AXI_ICM_BASE + 0x50) /** ICM_REG_RDN_ECO_EN : R/W; bitpos: [0]; default: 0; * NA */ @@ -520,7 +520,7 @@ extern "C" { /** ICM_RDN_ECO_LOW_REG register * NA */ -#define ICM_RDN_ECO_LOW_REG (DR_REG_ICM_BASE + 0x54) +#define ICM_RDN_ECO_LOW_REG (DR_REG_AXI_ICM_BASE + 0x54) /** ICM_RDN_ECO_LOW : R/W; bitpos: [31:0]; default: 0; * NA */ @@ -532,7 +532,7 @@ extern "C" { /** ICM_RDN_ECO_HIGH_REG register * NA */ -#define ICM_RDN_ECO_HIGH_REG (DR_REG_ICM_BASE + 0x58) +#define ICM_RDN_ECO_HIGH_REG (DR_REG_AXI_ICM_BASE + 0x58) /** ICM_RDN_ECO_HIGH : R/W; bitpos: [31:0]; default: 4294967295; * NA */ diff --git a/components/soc/esp32p4/include/soc/icm_sys_struct.h b/components/soc/esp32p4/include/soc/icm_sys_struct.h index 77b80c57b6d..887ae885aac 100644 --- a/components/soc/esp32p4/include/soc/icm_sys_struct.h +++ b/components/soc/esp32p4/include/soc/icm_sys_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -373,7 +373,7 @@ typedef union { typedef union { struct { /** reg_icm_sys_addrhole_id : RO; bitpos: [7:0]; default: 0; - * master id = 4-bit CID + 4-bit UID(refer to related IP) . CID is used to verfiy + * master id = 4-bit CID + 4-bit UID(refer to related IP) . CID is used to verify * master in icm. CID: 4'h1: cache, 4'h5 gdma mst1, 4'h6: gdma mst2, 4'h8: axi pdma, * 4'ha: dma2d, 4'hb: h264 mst1, 4'hc: h264 mst2. */ @@ -508,11 +508,12 @@ typedef struct { volatile icm_rdn_eco_cs_reg_t rdn_eco_cs; volatile icm_rdn_eco_low_reg_t rdn_eco_low; volatile icm_rdn_eco_high_reg_t rdn_eco_high; -} icm_dev_t; +} axi_icm_dev_t; +extern axi_icm_dev_t AXI_ICM; #ifndef __cplusplus -_Static_assert(sizeof(icm_dev_t) == 0x5c, "Invalid size of icm_dev_t structure"); +_Static_assert(sizeof(axi_icm_dev_t) == 0x5c, "Invalid size of axi_icm_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/reg_base.h b/components/soc/esp32p4/include/soc/reg_base.h index ca035cf30eb..f6a845a421a 100644 --- a/components/soc/esp32p4/include/soc/reg_base.h +++ b/components/soc/esp32p4/include/soc/reg_base.h @@ -64,6 +64,7 @@ #define DR_REG_RMT_BASE (DR_REG_HPPERIPH0_BASE + 0xA2000) #define DR_REG_BITSCRAM_BASE (DR_REG_HPPERIPH0_BASE + 0xA3000) #define DR_REG_AXI_ICM_BASE (DR_REG_HPPERIPH0_BASE + 0xA4000) +#define DR_REG_AXI_ICM_QOS_BASE (DR_REG_AXI_ICM_BASE + 0x400) #define DR_REG_HP_PERI_PMS_BASE (DR_REG_HPPERIPH0_BASE + 0xA5000) #define DR_REG_LP2HP_PERI_PMS_BASE (DR_REG_HPPERIPH0_BASE + 0xA5800) #define DR_REG_DMA_PMS_BASE (DR_REG_HPPERIPH0_BASE + 0xA6000) diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index c706f5da5d1..3b52e6ca7a5 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -19,6 +19,8 @@ PROVIDE ( I2C1 = 0x500C5000 ); PROVIDE ( UHCI0 = 0x500DF000 ); PROVIDE ( RMT = 0x500A2000 ); PROVIDE ( RMTMEM = 0x500A2800 ); +PROVIDE ( AXI_ICM = 0x500A4000 ); +PROVIDE ( AXI_ICM_QOS = 0x500A4400 ); PROVIDE ( HP_PERI_PMS = 0x500A5000 ); PROVIDE ( LP2HP_PERI_PMS = 0x500A5800 ); PROVIDE ( DMA_PMS = 0x500A6000 ); From ce7ceb8d9df5fa82a7a5b95650142ea560ab6aa5 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Tue, 21 May 2024 15:36:34 +0800 Subject: [PATCH 116/548] feat(csi): add verify to no backup buffer usage --- .../esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 6c297f1b9c5..e43474fd082 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -301,7 +301,6 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ BaseType_t high_task_woken = pdFALSE; csi_controller_t *ctlr = (csi_controller_t *)user_data; bool has_new_trans = false; - bool use_backup = false; dw_gdma_block_transfer_config_t csi_dma_transfer_config = {}; csi_dma_transfer_config = (dw_gdma_block_transfer_config_t) { @@ -325,32 +324,26 @@ static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_ if (ctlr->cbs.on_get_new_trans) { need_yield = ctlr->cbs.on_get_new_trans(&(ctlr->base), &new_trans, ctlr->cbs_user_data); - if (!(new_trans.buffer) || new_trans.buflen < ctlr->fb_size_in_bytes) { - use_backup = true; - } else { + if (new_trans.buffer && new_trans.buflen >= ctlr->fb_size_in_bytes) { csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); has_new_trans = true; } } else if (xQueueReceiveFromISR(ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) { - if (!(new_trans.buffer) || new_trans.buflen < ctlr->fb_size_in_bytes) { - use_backup = true; - } else { + if (new_trans.buffer && new_trans.buflen >= ctlr->fb_size_in_bytes) { csi_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); has_new_trans = true; } - } else if (!ctlr->bk_buffer_dis) { - use_backup = true; - } - - if (use_backup) { - new_trans.buffer = ctlr->backup_buffer; - new_trans.buflen = ctlr->fb_size_in_bytes; - ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer"); - csi_dma_transfer_config.dst.addr = (uint32_t)ctlr->backup_buffer; } if (!has_new_trans) { - assert(false && "no new buffer, and no driver internal buffer"); + if (!ctlr->bk_buffer_dis) { + new_trans.buffer = ctlr->backup_buffer; + new_trans.buflen = ctlr->fb_size_in_bytes; + ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer"); + csi_dma_transfer_config.dst.addr = (uint32_t)ctlr->backup_buffer; + } else { + assert(false && "no new buffer, and no driver internal buffer"); + } } ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); @@ -431,14 +424,22 @@ esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle) ESP_RETURN_ON_FALSE(ctlr->cbs.on_trans_finished, ESP_ERR_INVALID_STATE, TAG, "no on_trans_finished callback registered"); esp_cam_ctlr_trans_t trans = {}; + bool has_new_trans = false; + if (ctlr->cbs.on_get_new_trans) { ctlr->cbs.on_get_new_trans(handle, &trans, ctlr->cbs_user_data); - ESP_RETURN_ON_FALSE(trans.buffer, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, cannot start"); - } else if (!ctlr->bk_buffer_dis) { - trans.buffer = ctlr->backup_buffer; - trans.buflen = ctlr->fb_size_in_bytes; - } else { - ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, and no backup buffer"); + if (trans.buffer) { + has_new_trans = true; + } + } + + if (!has_new_trans) { + if (!ctlr->bk_buffer_dis) { + trans.buffer = ctlr->backup_buffer; + trans.buflen = ctlr->fb_size_in_bytes; + } else { + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, and no backup buffer"); + } } ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); From 2396dc5ff70ae1ab25ee9f6608fddd0fbb0a7a0b Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Thu, 16 May 2024 11:32:32 +0800 Subject: [PATCH 117/548] fix(wifi): fix the issue where deinit ble in a coexist scenario causes the wifi mac tsf counter to stop --- components/esp_hw_support/modem_clock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index ec89c4bcf20..e4b1a292192 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -454,7 +454,7 @@ void modem_clock_deselect_lp_clock_source(periph_module_t module) pmu_sleep_enable_hp_sleep_sysclk(false); } modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, false); - modem_clock_domain_clk_gate_enable(MODEM_CLOCK_DOMAIN_WIFI, PMU_HP_ICG_MODEM_CODE_SLEEP); + modem_clock_domain_clk_gate_enable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP); } #endif break; From d91dfe3510447492b269b9e27f980d875d97dcff Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 5 Dec 2023 13:38:47 +0800 Subject: [PATCH 118/548] change(esp_hw_support/sleep): improve esp32c3 systimer stall bug workaround --- components/esp_hw_support/Kconfig | 12 ------- .../port/esp32c3/include/soc/rtc.h | 12 ------- .../esp_hw_support/port/esp32c3/rtc_sleep.c | 13 +------- components/esp_hw_support/sleep_modes.c | 31 ++++++++++++------- .../esp_timer/src/esp_timer_impl_systimer.c | 4 +++ .../esp32c3/include/soc/Kconfig.soc_caps.in | 4 +++ components/soc/esp32c3/include/soc/soc_caps.h | 1 + 7 files changed, 29 insertions(+), 48 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index e1924af8c9b..b6b44bac402 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -214,18 +214,6 @@ menu "Hardware Settings" callback and hence it is highly recommended to keep them as short as possible. endmenu - menu "ESP_SLEEP_WORKAROUND" - # No visible menu/configs for workaround - visible if 0 - config ESP_SLEEP_SYSTIMER_STALL_WORKAROUND - bool "ESP32C3 SYSTIMER Stall Issue Workaround" - depends on IDF_TARGET_ESP32C3 - help - Its not able to stall ESP32C3 systimer in sleep. - To fix related RTOS TICK issue, select it to disable related systimer during sleep. - TODO: IDF-7036 - endmenu - menu "RTC Clock Config" orsource "./port/$IDF_TARGET/Kconfig.rtc" endmenu diff --git a/components/esp_hw_support/port/esp32c3/include/soc/rtc.h b/components/esp_hw_support/port/esp32c3/include/soc/rtc.h index 70c8a91ce3b..260df129305 100644 --- a/components/esp_hw_support/port/esp32c3/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32c3/include/soc/rtc.h @@ -646,18 +646,6 @@ void rtc_sleep_init(rtc_sleep_config_t cfg); */ void rtc_sleep_low_init(uint32_t slowclk_period); -#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND -/** - * @brief Configure systimer for esp32c3 systimer stall issue workaround - * - * This function configures related systimer for esp32c3 systimer stall issue. - * Only apply workaround when xtal powered up. - * - * @param en enable systimer or not - */ -void rtc_sleep_systimer_enable(bool en); -#endif - #define RTC_GPIO_TRIG_EN BIT(2) //!< GPIO wakeup #define RTC_TIMER_TRIG_EN BIT(3) //!< Timer wakeup #define RTC_WIFI_TRIG_EN BIT(5) //!< WIFI wakeup (light sleep only) diff --git a/components/esp_hw_support/port/esp32c3/rtc_sleep.c b/components/esp_hw_support/port/esp32c3/rtc_sleep.c index ac771a47af1..3c246f86901 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32c3/rtc_sleep.c @@ -24,7 +24,7 @@ #include "soc/regi2c_dig_reg.h" #include "soc/regi2c_lp_bias.h" #include "hal/efuse_hal.h" -#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND #include "soc/systimer_reg.h" #endif @@ -252,17 +252,6 @@ void rtc_sleep_low_init(uint32_t slowclk_period) REG_SET_FIELD(RTC_CNTL_TIMER1_REG, RTC_CNTL_CK8M_WAIT, RTC_CNTL_CK8M_WAIT_SLP_CYCLES); } -#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND -void rtc_sleep_systimer_enable(bool en) -{ - if (en) { - REG_SET_BIT(SYSTIMER_CONF_REG, SYSTIMER_TIMER_UNIT1_WORK_EN); - } else { - REG_CLR_BIT(SYSTIMER_CONF_REG, SYSTIMER_TIMER_UNIT1_WORK_EN); - } -} -#endif - static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu); uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 59d6cb22a82..e0cf2026a85 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -30,6 +30,10 @@ #include "hal/rtc_io_hal.h" #include "hal/clk_tree_hal.h" +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND +#include "hal/systimer_ll.h" +#endif + #if SOC_PM_SUPPORT_PMU_MODEM_STATE #include "esp_private/pm_impl.h" #endif @@ -870,11 +874,6 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m } } -#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND - if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { - rtc_sleep_systimer_enable(false); - } -#endif if (should_skip_sleep) { result = ESP_ERR_SLEEP_REJECT; @@ -883,9 +882,9 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif } else { #if CONFIG_ESP_SLEEP_DEBUG - if (s_sleep_ctx != NULL) { - s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers; - } + if (s_sleep_ctx != NULL) { + s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers; + } #endif if (deep_sleep) { #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP @@ -913,6 +912,13 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); #endif } else { +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND + if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { + for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { + systimer_ll_enable_counter(&SYSTIMER, counter_id, false); + } + } +#endif /* Cache Suspend 1: will wait cache idle in cache suspend */ suspend_cache(); /* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode. @@ -977,13 +983,14 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif /* Cache Resume 1: Resume cache for continue running*/ resume_cache(); - } - -#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { - rtc_sleep_systimer_enable(true); + for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { + systimer_ll_enable_counter(&SYSTIMER, counter_id, true); + } } #endif + } } #if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION if (pd_flags & RTC_SLEEP_PD_VDDSDIO) { diff --git a/components/esp_timer/src/esp_timer_impl_systimer.c b/components/esp_timer/src/esp_timer_impl_systimer.c index 1f2161fa996..549316a6dac 100644 --- a/components/esp_timer/src/esp_timer_impl_systimer.c +++ b/components/esp_timer/src/esp_timer_impl_systimer.c @@ -180,6 +180,10 @@ esp_err_t esp_timer_impl_early_init(void) systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_ALARM_ESPTIMER, SYSTIMER_ALARM_MODE_ONESHOT); systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_ALARM_ESPTIMER, SYSTIMER_COUNTER_ESPTIMER); + for (unsigned cpuid = 0; cpuid < SOC_CPU_CORES_NUM; ++cpuid) { + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_COUNTER_ESPTIMER, cpuid, (cpuid < portNUM_PROCESSORS) ? true : false); + } + return ESP_OK; } diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 80a7732c89b..1956fe2a8a1 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -619,6 +619,10 @@ config SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM int default 108 +config SOC_SLEEP_SYSTIMER_STALL_WORKAROUND + bool + default y + config SOC_RTCIO_PIN_COUNT int default 0 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index de6c54a6ba2..80ddbcc239c 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -257,6 +257,7 @@ #define SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE (SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM * (SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)) +#define SOC_SLEEP_SYSTIMER_STALL_WORKAROUND 1 /*-------------------------- RTCIO CAPS --------------------------------------*/ /* No dedicated RTCIO subsystem on ESP32-C3. RTC functions are still supported * for hold, wake & 32kHz crystal functions - via rtc_cntl_reg */ From 8b369072f953c9fba463dba17791a9085bab4f3d Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 26 Dec 2023 20:50:52 +0800 Subject: [PATCH 119/548] fix(esp_hw_support/sleep): stop TG0/TG1 watchdog if XTAL not power down in lightsleep --- components/esp_hw_support/sleep_modes.c | 67 +++++++++++++++---- .../esp32c3/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32c3/include/soc/soc_caps.h | 2 + 3 files changed, 59 insertions(+), 14 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index e0cf2026a85..4be257586c3 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -34,6 +34,11 @@ #include "hal/systimer_ll.h" #endif +#if SOC_SLEEP_TGWDT_STOP_WORKAROUND +#include "hal/mwdt_ll.h" +#include "hal/timer_ll.h" +#endif + #if SOC_PM_SUPPORT_PMU_MODEM_STATE #include "esp_private/pm_impl.h" #endif @@ -493,6 +498,52 @@ static void IRAM_ATTR resume_cache(void) { } } +#if SOC_SLEEP_TGWDT_STOP_WORKAROUND +static uint32_t s_stopped_tgwdt_bmap = 0; +#endif + +// Must be called from critical sections. +static void IRAM_ATTR suspend_timers(uint32_t pd_flags) { + if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { +#if SOC_SLEEP_TGWDT_STOP_WORKAROUND + /* If timegroup implemented task watchdog or interrupt watchdog is running, we have to stop it. */ + for (uint32_t tg_num = 0; tg_num < SOC_TIMER_GROUPS; ++tg_num) { + if (mwdt_ll_check_if_enabled(TIMER_LL_GET_HW(tg_num))) { + mwdt_ll_write_protect_disable(TIMER_LL_GET_HW(tg_num)); + mwdt_ll_disable(TIMER_LL_GET_HW(tg_num)); + mwdt_ll_write_protect_enable(TIMER_LL_GET_HW(tg_num)); + s_stopped_tgwdt_bmap |= BIT(tg_num); + } + } +#endif +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND + for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { + systimer_ll_enable_counter(&SYSTIMER, counter_id, false); + } +#endif + } +} + +// Must be called from critical sections. +static void IRAM_ATTR resume_timers(uint32_t pd_flags) { + if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { +#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND + for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { + systimer_ll_enable_counter(&SYSTIMER, counter_id, true); + } +#endif +#if SOC_SLEEP_TGWDT_STOP_WORKAROUND + for (uint32_t tg_num = 0; tg_num < SOC_TIMER_GROUPS; ++tg_num) { + if (s_stopped_tgwdt_bmap & BIT(tg_num)) { + mwdt_ll_write_protect_disable(TIMER_LL_GET_HW(tg_num)); + mwdt_ll_enable(TIMER_LL_GET_HW(tg_num)); + mwdt_ll_write_protect_enable(TIMER_LL_GET_HW(tg_num)); + } + } +#endif + } +} + // [refactor-todo] provide target logic for body of uart functions below static void IRAM_ATTR flush_uarts(void) { @@ -912,13 +963,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); #endif } else { -#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND - if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { - for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { - systimer_ll_enable_counter(&SYSTIMER, counter_id, false); - } - } -#endif + suspend_timers(pd_flags); /* Cache Suspend 1: will wait cache idle in cache suspend */ suspend_cache(); /* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode. @@ -983,13 +1028,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif /* Cache Resume 1: Resume cache for continue running*/ resume_cache(); -#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND - if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { - for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) { - systimer_ll_enable_counter(&SYSTIMER, counter_id, true); - } - } -#endif + resume_timers(pd_flags); } } #if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 1956fe2a8a1..e68c0211ebf 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -623,6 +623,10 @@ config SOC_SLEEP_SYSTIMER_STALL_WORKAROUND bool default y +config SOC_SLEEP_TGWDT_STOP_WORKAROUND + bool + default y + config SOC_RTCIO_PIN_COUNT int default 0 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 80ddbcc239c..03e25c655c2 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -258,6 +258,8 @@ #define SOC_RTC_CNTL_CPU_PD_RETENTION_MEM_SIZE (SOC_RTC_CNTL_CPU_PD_REG_FILE_NUM * (SOC_RTC_CNTL_CPU_PD_DMA_BUS_WIDTH >> 3)) #define SOC_SLEEP_SYSTIMER_STALL_WORKAROUND 1 +#define SOC_SLEEP_TGWDT_STOP_WORKAROUND 1 + /*-------------------------- RTCIO CAPS --------------------------------------*/ /* No dedicated RTCIO subsystem on ESP32-C3. RTC functions are still supported * for hold, wake & 32kHz crystal functions - via rtc_cntl_reg */ From bb466097e5bff68a0170741831cb83990aacc5f3 Mon Sep 17 00:00:00 2001 From: "wangtao@espressif.com" Date: Wed, 20 Mar 2024 13:48:36 +0800 Subject: [PATCH 120/548] feat(wifi): add softap csa&dtim&wait_bcast_data setting and ignore err nodata --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 +- components/esp_wifi/Kconfig | 21 +++++++++++++++---- .../esp_wifi/include/esp_private/wifi.h | 17 ++++++++++++--- components/esp_wifi/include/esp_wifi.h | 4 ++-- .../esp_wifi/include/esp_wifi_types_generic.h | 2 ++ components/esp_wifi/lib | 2 +- components/esp_wifi/src/wifi_init.c | 10 ++++++--- 7 files changed, 44 insertions(+), 14 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 5276d60ac0d..bd04e6157c2 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -1853,7 +1853,7 @@ ieee80211_send_deauth_no_bss = 0x40002120; ieee80211_alloc_deauth = 0x40002124; ieee80211_send_proberesp = 0x40002128; ieee80211_getcapinfo = 0x40002130; -sta_rx_csa = 0x40002134; +/* sta_rx_csa = 0x40002134; */ /* sta_recv_sa_query_resp = 0x40002144; */ ieee80211_set_max_rate = 0x4000214c; ic_set_sta = 0x40002150; diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index b83613ec240..1a69b8d6bd9 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -348,17 +348,30 @@ menu "Wi-Fi" int "Minimum active time" range 8 60 default 50 - depends on ESP_WIFI_SLP_IRAM_OPT help - The minimum timeout for waiting to receive data, unit: milliseconds. + Only for station in WIFI_PS_MIN_MODEM or WIFI_PS_MAX_MODEM. When the station enters the active state, + it will work for at least ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME. If a data packet is received or sent + during this period, the time will be refreshed. If the time is up, but the station still has packets + to receive or send, the time will also be refreshed. unit: milliseconds. config ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME int "Maximum keep alive time" range 10 60 default 10 - depends on ESP_WIFI_SLP_IRAM_OPT help - The maximum time that wifi keep alive, unit: seconds. + Only for station in WIFI_PS_MIN_MODEM or WIFI_PS_MAX_MODEM. If no packet has been + sent within ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME, a null data packet will be sent + to maintain the connection with the AP. unit: seconds. + + config ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME + int "Minimum wait broadcast data time" + range 10 30 + default 15 + help + Only for station in WIFI_PS_MIN_MODEM or WIFI_PS_MAX_MODEM. When the station knows through the beacon + that AP will send broadcast packet, it will wait for ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME + before entering the sleep process. If a broadcast packet is received with more data bits, the time + will refreshed. unit: milliseconds. config ESP_WIFI_FTM_ENABLE bool "WiFi FTM" diff --git a/components/esp_wifi/include/esp_private/wifi.h b/components/esp_wifi/include/esp_private/wifi.h index 880dd83076f..59ea571db8e 100644 --- a/components/esp_wifi/include/esp_private/wifi.h +++ b/components/esp_wifi/include/esp_private/wifi.h @@ -614,13 +614,13 @@ esp_err_t esp_wifi_internal_set_spp_amsdu(wifi_interface_t ifidx, bool spp_cap, void esp_wifi_internal_update_light_sleep_default_params(int min_freq_mhz, int max_freq_mhz); /** - * @brief Set the delay time for wifi to enter the sleep state when light sleep + * @brief Set the min active time for wifi to enter the sleep state when light sleep * - * @param return_to_sleep_delay: minimum timeout time for waiting to receive + * @param min_active_time: minimum timeout time for waiting to receive * data, when no data is received during the timeout period, * the wifi enters the sleep process. */ -void esp_wifi_set_sleep_delay_time(uint32_t return_to_sleep_delay); +void esp_wifi_set_sleep_min_active_time(uint32_t min_active_time); /** * @brief Set wifi keep alive time @@ -629,6 +629,17 @@ void esp_wifi_set_sleep_delay_time(uint32_t return_to_sleep_delay); */ void esp_wifi_set_keep_alive_time(uint32_t keep_alive_time); +/** + * @brief Set the min broadcast data wait time for wifi to enter the sleep state + * + * @attention Default sleep wait broadcast data time is 15000, Uint µs. + * + * @param time: When the station knows through the beacon that the AP + * will send broadcast packet, it will wait for a minimum of + * wait_broadcast_data_time before entering the sleep process. + */ +void esp_wifi_set_sleep_wait_broadcast_data_time(uint32_t time); + /** * @brief Configure wifi beacon montior default parameters * diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 6e49fc282df..0ce1a2f7d18 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -365,7 +365,7 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); * @return * - ESP_OK: succeed * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init - * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_INVALID_ARG: It doesn't normally happen, the function called inside the API was passed invalid argument, user should check if the wifi related config is correct * - ESP_ERR_NO_MEM: out of memory * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong * - ESP_FAIL: other WiFi internal errors @@ -598,7 +598,7 @@ esp_err_t esp_wifi_scan_get_ap_record(wifi_ap_record_t *ap_record); * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start * - ESP_ERR_WIFI_MODE: WiFi mode is wrong - * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_INVALID_ARG: It doesn't normally happen, the function called inside the API was passed invalid argument, user should check if the wifi related config is correct */ esp_err_t esp_wifi_clear_ap_list(void); diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 0cea6304580..fdad2e1cbd1 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -338,6 +338,8 @@ typedef struct { uint8_t ssid_hidden; /**< Broadcast SSID or not, default 0, broadcast the SSID */ uint8_t max_connection; /**< Max number of stations allowed to connect in */ uint16_t beacon_interval; /**< Beacon interval which should be multiples of 100. Unit: TU(time unit, 1 TU = 1024 us). Range: 100 ~ 60000. Default value: 100 */ + uint8_t csa_count; /**< Channel Switch Announcement Count. Notify the station that the channel will switch after the csa_count beacon intervals. Default value: 3 */ + uint8_t dtim_period; /**< Dtim period of soft-AP. Default value: 2 */ wifi_cipher_type_t pairwise_cipher; /**< Pairwise cipher of SoftAP, group cipher will be derived using this. Cipher values are valid starting from WIFI_CIPHER_TYPE_TKIP, enum values before that will be considered as invalid and default cipher suites(TKIP+CCMP) will be used. Valid cipher suites in softAP mode are WIFI_CIPHER_TYPE_TKIP, WIFI_CIPHER_TYPE_CCMP and WIFI_CIPHER_TYPE_TKIP_CCMP. */ bool ftm_responder; /**< Enable FTM Responder mode */ wifi_pmf_config_t pmf_cfg; /**< Configuration for Protected Management Frame */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 482ab97ae35..ab8a1f6d515 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 482ab97ae352dfdbaed028338a9ee45d7f2e6127 +Subproject commit ab8a1f6d515d4f5d033ec43ce5cff10260c8590c diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index c0dc4023e1b..29543b50366 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -328,12 +328,16 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) esp_pm_register_light_sleep_default_params_config_callback(esp_wifi_internal_update_light_sleep_default_params); - uint32_t sleep_delay_us = CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME * 1000; - esp_wifi_set_sleep_delay_time(sleep_delay_us); +#endif + + uint32_t min_active_time_us = CONFIG_ESP_WIFI_SLP_DEFAULT_MIN_ACTIVE_TIME * 1000; + esp_wifi_set_sleep_min_active_time(min_active_time_us); uint32_t keep_alive_time_us = CONFIG_ESP_WIFI_SLP_DEFAULT_MAX_ACTIVE_TIME * 1000 * 1000; esp_wifi_set_keep_alive_time(keep_alive_time_us); -#endif + + uint32_t wait_broadcast_data_time_us = CONFIG_ESP_WIFI_SLP_DEFAULT_WAIT_BROADCAST_DATA_TIME * 1000; + esp_wifi_set_sleep_wait_broadcast_data_time(wait_broadcast_data_time_us); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE #if SOC_PM_MODEM_RETENTION_BY_REGDMA From 1bf9c822f96160ccc2e94261f8690305f91b6856 Mon Sep 17 00:00:00 2001 From: liuning Date: Wed, 17 Apr 2024 17:40:46 +0800 Subject: [PATCH 121/548] feat(wifi): support coex pwr --- components/esp_coex/Kconfig | 7 +++++ .../include/private/esp_coexist_internal.h | 23 ++++++++++++-- components/esp_coex/lib | 2 +- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 6 ++-- .../esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld | 4 +-- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 +- .../esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld | 14 ++++----- .../esp_rom/esp32c6/ld/esp32c6.rom.pp.ld | 4 +-- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 +- components/esp_wifi/esp32/esp_adapter.c | 20 +++++++++++++ components/esp_wifi/esp32c2/esp_adapter.c | 20 +++++++++++++ components/esp_wifi/esp32c3/esp_adapter.c | 20 +++++++++++++ components/esp_wifi/esp32c5/esp_adapter.c | 30 +++++++++++++++---- components/esp_wifi/esp32c6/esp_adapter.c | 20 +++++++++++++ components/esp_wifi/esp32p4/esp_adapter.c | 12 ++++++++ components/esp_wifi/esp32s2/esp_adapter.c | 21 ++++++++++++- components/esp_wifi/esp32s3/esp_adapter.c | 20 +++++++++++++ .../include/esp_private/wifi_os_adapter.h | 2 ++ components/esp_wifi/include/esp_wifi.h | 15 ++++++++++ components/esp_wifi/lib | 2 +- 20 files changed, 220 insertions(+), 26 deletions(-) diff --git a/components/esp_coex/Kconfig b/components/esp_coex/Kconfig index fb982aeb0e6..d35ee7be78f 100644 --- a/components/esp_coex/Kconfig +++ b/components/esp_coex/Kconfig @@ -32,5 +32,12 @@ menu "Wireless Coexistence" This function depends on BT-off because currently we do not support external coex and internal coex simultaneously. + config ESP_COEX_POWER_MANAGEMENT + bool "Support power management under coexistence" + default n + depends on (ESP_COEX_SW_COEXIST_ENABLE) + help + If enabled, coexist power management will be enabled. endif + endmenu # Wireless Coexistence diff --git a/components/esp_coex/include/private/esp_coexist_internal.h b/components/esp_coex/include/private/esp_coexist_internal.h index 7aee0c05333..20cea8a437b 100644 --- a/components/esp_coex/include/private/esp_coexist_internal.h +++ b/components/esp_coex/include/private/esp_coexist_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -313,7 +313,7 @@ esp_err_t esp_coex_adapter_register(coex_adapter_funcs_t *funcs); #if CONFIG_EXTERNAL_COEX_ENABLE /** - * @brief Set external coexistence advanced informations, like working mode. + * @brief Set external coexistence advanced information, like working mode. * * @param out_pti1 This parameter no longer works, will be deprecated and later removed in future releases. * @param out_pti2 This parameter no longer works, will be deprecated and later removed in future releases. @@ -365,6 +365,25 @@ void esp_coex_external_set_txline(bool en); #endif /*SOC_EXTERNAL_COEX_LEADER_TX_LINE*/ #endif /*External Coex*/ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT +/** + * @brief Set coexist scheme flexible period + * + * @param period flexible period + * + * @return + * - ESP_OK: succeed + */ +int coex_schm_flexible_period_set(uint8_t period); + +/** + * @brief Get coexist scheme flexible period + * + * @return Coexist scheme flexible period + */ +uint8_t coex_schm_flexible_period_get(void); +#endif + /** * @brief Check the MD5 values of the coexistence adapter header files in IDF and WiFi library * diff --git a/components/esp_coex/lib b/components/esp_coex/lib index 87eecbdf139..2363239dded 160000 --- a/components/esp_coex/lib +++ b/components/esp_coex/lib @@ -1 +1 @@ -Subproject commit 87eecbdf1392d5b4304c4c8e7a26056fa5df294f +Subproject commit 2363239ddeda69523a4ed79e55815be21115200f diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index bd04e6157c2..09fca95d4fa 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -1430,7 +1430,7 @@ mac_tx_set_plcp2 = 0x40001b68; /* pm_check_state = 0x40001b6c; */ pm_disable_dream_timer = 0x40001b70; pm_disable_sleep_delay_timer = 0x40001b74; -pm_dream = 0x40001b78; +/*pm_dream = 0x40001b78;*/ pm_mac_wakeup = 0x40001b7c; pm_mac_sleep = 0x40001b80; pm_enable_active_timer = 0x40001b84; @@ -1611,7 +1611,7 @@ hal_disable_sta_tbtt = 0x40001e3c; ppCalTxopDur = 0x40001e40; wDev_IndicateCtrlFrame = 0x40001e44; hal_enable_sta_tbtt = 0x40001e48; -hal_set_sta_tbtt = 0x40001e4c; +/*hal_set_sta_tbtt = 0x40001e4c;*/ /* pm_update_next_tbtt = 0x40001e50;*/ /* pm_set_sleep_type = 0x40001e54; */ wDev_Rxbuf_Init = 0x40001e58; @@ -1670,7 +1670,7 @@ tsf_hal_set_tbtt_intr_enable = 0x40001f28; tsf_hal_set_tbtt_intr_disable = 0x40001f2c; tsf_hal_set_tbtt_soc_wakeup_enable = 0x40001f30; tsf_hal_set_tbtt_soc_wakeup_disable = 0x40001f34; -tsf_hal_set_tbtt_start_time = 0x40001f38; +/*tsf_hal_set_tbtt_start_time = 0x40001f38;*/ tsf_hal_set_tbtt_early_time = 0x40001f3c; tsf_hal_set_tbtt_interval = 0x40001f40; tsf_hal_get_tbtt_interval = 0x40001f44; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld index 7a3eabdb20c..9b7a16d1982 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld @@ -15,7 +15,7 @@ lmacTxFrame = 0x40001630; mac_tx_set_htsig = 0x40001638; mac_tx_set_plcp1 = 0x40001640; pm_check_state = 0x40001648; -pm_on_beacon_rx = 0x4000167c; +/*pm_on_beacon_rx = 0x4000167c;*/ /*pm_parse_beacon = 0x40001688;*/ pm_process_tim = 0x4000168c; pm_rx_beacon_process = 0x40001690; @@ -33,7 +33,7 @@ wDevCheckBlockError = 0x400017b4; wDev_ProcessFiq = 0x400017f0; /*wDev_ProcessRxSucData = 0x400017f4;*/ /*ppProcTxDone = 0x40001804;*/ -pm_tx_data_done_process = 0x40001808; +/*pm_tx_data_done_process = 0x40001808;*/ ppMapWaitTxq = 0x40001810; /*ieee80211_encap_esfbuf = 0x4000185c;*/ /*sta_input = 0x40001870;*/ diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index a5731b2bb27..60c97f4923d 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -1538,7 +1538,7 @@ mac_tx_set_plcp2 = 0x40001644; /* pm_check_state = 0x40001648; */ pm_disable_dream_timer = 0x4000164c; pm_disable_sleep_delay_timer = 0x40001650; -pm_dream = 0x40001654; +/*pm_dream = 0x40001654;*/ pm_mac_wakeup = 0x40001658; pm_mac_sleep = 0x4000165c; pm_enable_active_timer = 0x40001660; diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld index d5d68d5d49d..f3d4fcc0426 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld @@ -109,7 +109,7 @@ mac_tx_set_pti = 0x40000d44; pm_check_state = 0x40000d48; pm_disable_dream_timer = 0x40000d4c; pm_disable_sleep_delay_timer = 0x40000d50; -pm_dream = 0x40000d54; +/*pm_dream = 0x40000d54;*/ pm_mac_wakeup = 0x40000d58; pm_mac_sleep = 0x40000d5c; pm_enable_active_timer = 0x40000d60; @@ -119,7 +119,7 @@ pm_set_beacon_filter = 0x40000d6c; pm_is_in_wifi_slice_threshold = 0x40000d70; pm_is_waked = 0x40000d74; pm_keep_alive = 0x40000d78; -pm_on_beacon_rx = 0x40000d7c; +/*pm_on_beacon_rx = 0x40000d7c;*/ pm_on_data_rx = 0x40000d80; pm_on_data_tx = 0x40000d84; pm_on_tbtt = 0x40000d88; @@ -133,13 +133,13 @@ pm_parse_beacon = 0x40000da4; pm_process_tim = 0x40000da8; pm_rx_beacon_process = 0x40000dac; pm_rx_data_process = 0x40000db0; -pm_sleep = 0x40000db4; +/*pm_sleep = 0x40000db4;*/ pm_sleep_for = 0x40000db8; -pm_tbtt_process = 0x40000dbc; -pm_tx_data_done_process = 0x40000dc0; +/*pm_tbtt_process = 0x40000dbc;*/ +/*pm_tx_data_done_process = 0x40000dc0;*/ pm_allow_tx = 0x40000dc4; pm_extend_tbtt_adaptive_servo = 0x40000dc8; -pm_scale_listen_interval = 0x40000dcc; +/*pm_scale_listen_interval = 0x40000dcc;*/ pm_parse_mbssid_element = 0x40000dd0; pm_disconnected_wake = 0x40000dd4; pm_tx_data_process = 0x40000dd8; @@ -153,7 +153,7 @@ pm_twt_set_target_tsf = 0x40000df4; pm_enable_twt_keep_alive_timer = 0x40000df8; pm_mac_try_enable_modem_state = 0x40000dfc; pm_beacon_monitor_tbtt_timeout_process = 0x40000e00; -pm_update_next_tbtt = 0x40000e04; +/*pm_update_next_tbtt = 0x40000e04;*/ pm_twt_disallow_tx = 0x40000e08; pm_clear_wakeup_signal = 0x40000e0c; pm_mac_disable_tsf_tbtt_soc_wakeup = 0x40000e10; diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld index 78014c5e593..ce7c53ed882 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld @@ -59,7 +59,7 @@ mac_tx_set_plcp2 = 0x40000c6c; /* pm_check_state = 0x40000c70; */ /* pm_disable_dream_timer = 0x40000c74; */ pm_disable_sleep_delay_timer = 0x40000c78; -pm_dream = 0x40000c7c; +/*pm_dream = 0x40000c7c;*/ pm_mac_wakeup = 0x40000c80; pm_mac_sleep = 0x40000c84; //pm_enable_active_timer = 0x40000c88; @@ -274,7 +274,7 @@ tsf_hal_set_tbtt_rf_ctrl_enable = 0x40000fc8; tsf_hal_set_tbtt_rf_ctrl_wait_cycles = 0x40000fcc; tsf_hal_set_tbtt_soc_wakeup_disable = 0x40000fd0; tsf_hal_set_tbtt_soc_wakeup_enable = 0x40000fd4; -tsf_hal_set_tbtt_start_time = 0x40000fd8; +/*tsf_hal_set_tbtt_start_time = 0x40000fd8;*/ tsf_hal_set_time = 0x40000fdc; tsf_hal_set_timer_disable = 0x40000fe0; tsf_hal_set_timer_enable = 0x40000fe4; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 6d964839b3e..9f23d00f6b9 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -1816,7 +1816,7 @@ mac_tx_set_plcp2 = 0x4000540c; /* pm_check_state = 0x40005418; */ pm_disable_dream_timer = 0x40005424; pm_disable_sleep_delay_timer = 0x40005430; -pm_dream = 0x4000543c; +/*pm_dream = 0x4000543c;*/ pm_mac_wakeup = 0x40005448; pm_mac_sleep = 0x40005454; pm_enable_active_timer = 0x40005460; diff --git a/components/esp_wifi/esp32/esp_adapter.c b/components/esp_wifi/esp32/esp_adapter.c index 4bc3a36706b..ce79917000c 100644 --- a/components/esp_wifi/esp32/esp_adapter.c +++ b/components/esp_wifi/esp32/esp_adapter.c @@ -578,6 +578,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -712,5 +730,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32c2/esp_adapter.c b/components/esp_wifi/esp32c2/esp_adapter.c index 6efcee96101..4c0b4212cc4 100644 --- a/components/esp_wifi/esp32c2/esp_adapter.c +++ b/components/esp_wifi/esp32c2/esp_adapter.c @@ -517,6 +517,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -650,5 +668,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32c3/esp_adapter.c b/components/esp_wifi/esp32c3/esp_adapter.c index 923c3fcefde..10ec230ee96 100644 --- a/components/esp_wifi/esp32c3/esp_adapter.c +++ b/components/esp_wifi/esp32c3/esp_adapter.c @@ -534,6 +534,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -667,5 +685,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32c5/esp_adapter.c b/components/esp_wifi/esp32c5/esp_adapter.c index bf123ecf84b..c0c735e01a7 100644 --- a/components/esp_wifi/esp32c5/esp_adapter.c +++ b/components/esp_wifi/esp32c5/esp_adapter.c @@ -61,17 +61,17 @@ extern void wifi_apb80m_request(void); extern void wifi_apb80m_release(void); #endif -IRAM_ATTR void *wifi_malloc( size_t size ) +IRAM_ATTR void *wifi_malloc(size_t size) { return malloc(size); } -IRAM_ATTR void *wifi_realloc( void *ptr, size_t size ) +IRAM_ATTR void *wifi_realloc(void *ptr, size_t size) { return realloc(ptr, size); } -IRAM_ATTR void *wifi_calloc( size_t n, size_t size ) +IRAM_ATTR void *wifi_calloc(size_t n, size_t size) { return calloc(n, size); } @@ -82,7 +82,7 @@ static void *IRAM_ATTR wifi_zalloc_wrapper(size_t size) return ptr; } -wifi_static_queue_t *wifi_create_queue( int queue_len, int item_size) +wifi_static_queue_t *wifi_create_queue(int queue_len, int item_size) { wifi_static_queue_t *queue = NULL; @@ -91,7 +91,7 @@ wifi_static_queue_t *wifi_create_queue( int queue_len, int item_size) return NULL; } - queue->handle = xQueueCreate( queue_len, item_size); + queue->handle = xQueueCreate(queue_len, item_size); return queue; } @@ -522,6 +522,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -664,5 +682,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { #endif ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32c6/esp_adapter.c b/components/esp_wifi/esp32c6/esp_adapter.c index b44e9860001..aec8785a10b 100644 --- a/components/esp_wifi/esp32c6/esp_adapter.c +++ b/components/esp_wifi/esp32c6/esp_adapter.c @@ -523,6 +523,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -672,5 +690,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { #endif ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32p4/esp_adapter.c b/components/esp_wifi/esp32p4/esp_adapter.c index e004f3c0d01..f78dc1972d6 100644 --- a/components/esp_wifi/esp32p4/esp_adapter.c +++ b/components/esp_wifi/esp32p4/esp_adapter.c @@ -496,6 +496,16 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) return 0; } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ + return 0; +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ + return 1; +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -750,5 +760,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32s2/esp_adapter.c b/components/esp_wifi/esp32s2/esp_adapter.c index 72d9fd4b54b..95f9f2dbb10 100644 --- a/components/esp_wifi/esp32s2/esp_adapter.c +++ b/components/esp_wifi/esp32s2/esp_adapter.c @@ -573,6 +573,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -706,6 +724,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, - + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/esp32s3/esp_adapter.c b/components/esp_wifi/esp32s3/esp_adapter.c index eaa13b29e98..ba3311a2400 100644 --- a/components/esp_wifi/esp32s3/esp_adapter.c +++ b/components/esp_wifi/esp32s3/esp_adapter.c @@ -590,6 +590,24 @@ static int coex_schm_register_cb_wrapper(int type, int(*cb)(int)) #endif } +static int coex_schm_flexible_period_set_wrapper(uint8_t period) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_set(period); +#else + return 0; +#endif +} + +static uint8_t coex_schm_flexible_period_get_wrapper(void) +{ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT + return coex_schm_flexible_period_get(); +#else + return 1; +#endif +} + static void IRAM_ATTR esp_empty_wrapper(void) { @@ -723,5 +741,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = { ._coex_register_start_cb = coex_register_start_cb_wrapper, ._coex_schm_process_restart = coex_schm_process_restart_wrapper, ._coex_schm_register_cb = coex_schm_register_cb_wrapper, + ._coex_schm_flexible_period_set = coex_schm_flexible_period_set_wrapper, + ._coex_schm_flexible_period_get = coex_schm_flexible_period_get_wrapper, ._magic = ESP_WIFI_OS_ADAPTER_MAGIC, }; diff --git a/components/esp_wifi/include/esp_private/wifi_os_adapter.h b/components/esp_wifi/include/esp_private/wifi_os_adapter.h index 4cf59977e67..ded8bc0c21a 100644 --- a/components/esp_wifi/include/esp_private/wifi_os_adapter.h +++ b/components/esp_wifi/include/esp_private/wifi_os_adapter.h @@ -153,6 +153,8 @@ typedef struct wifi_osi_funcs_t { void (* _regdma_link_set_write_wait_content)(void *, uint32_t, uint32_t); void * (* _sleep_retention_find_link_by_id)(int); #endif + int (*_coex_schm_flexible_period_set)(uint8_t); + uint8_t (*_coex_schm_flexible_period_get)(void); int32_t _magic; } wifi_osi_funcs_t; diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 0ce1a2f7d18..f56beb6c6e0 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -1596,6 +1596,21 @@ esp_err_t esp_wifi_set_band(wifi_band_t band); esp_err_t esp_wifi_get_band(wifi_band_t* band); #endif /* SOC_WIFI_HE_SUPPORT_5G */ +#if CONFIG_ESP_COEX_POWER_MANAGEMENT +/** + * @brief Enable Wi-Fi coexistence power management + * + * @attention This API should be called after esp_wifi_init(). + * + * @param enabled Wi-Fi coexistence power management is enabled or not. + * + * @return + * - ESP_OK: succeed + * - others: failed + */ +esp_err_t esp_wifi_coex_pwr_configure(bool enabled); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index ab8a1f6d515..71c676dbf64 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit ab8a1f6d515d4f5d033ec43ce5cff10260c8590c +Subproject commit 71c676dbf6455b0821533844cb23135004ad4fbc From e13bb3d734149059a3378eedcf7b948b92f8a7a6 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Tue, 21 May 2024 21:32:14 +0800 Subject: [PATCH 122/548] fix(esp32c6): fix the issue of except wifi state caused by the missing mac retention config --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 71c676dbf64..a89846e501c 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 71c676dbf6455b0821533844cb23135004ad4fbc +Subproject commit a89846e501cebcdce6be6d4ecbe34dcf1567bf70 From 52b9c5d666ab779a489854b2f2dc4d775bfb4805 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Mon, 13 May 2024 17:01:56 +0800 Subject: [PATCH 123/548] feat(bt/bluedroid): support BLE set privacy mode --- .../bt/host/bluedroid/api/esp_gap_ble_api.c | 19 ++++++++++++ .../api/include/api/esp_gap_ble_api.h | 27 +++++++++++++++++ .../bt/host/bluedroid/bta/dm/bta_dm_act.c | 7 +++++ .../bt/host/bluedroid/bta/dm/bta_dm_api.c | 15 ++++++++++ .../bt/host/bluedroid/bta/dm/bta_dm_main.c | 1 + .../bluedroid/bta/dm/include/bta_dm_int.h | 11 +++++++ .../host/bluedroid/bta/include/bta/bta_api.h | 4 +++ .../btc/profile/std/gap/btc_gap_ble.c | 30 +++++++++++++++++++ .../btc/profile/std/include/btc_gap_ble.h | 9 +++++- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 11 +++++++ .../bluedroid/stack/btm/btm_ble_privacy.c | 28 +++++++++++++++++ .../bluedroid/stack/btm/include/btm_ble_int.h | 1 + .../bluedroid/stack/btm/include/btm_int.h | 3 ++ .../bt/host/bluedroid/stack/btu/btu_hcif.c | 5 +++- .../bt/host/bluedroid/stack/hcic/hciblecmds.c | 24 +++++++++++++++ .../stack/include/stack/btm_ble_api.h | 24 ++++++++++++++- .../bluedroid/stack/include/stack/hcidefs.h | 10 +++---- .../bluedroid/stack/include/stack/hcimsgs.h | 3 ++ 18 files changed, 224 insertions(+), 8 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_gap_ble_api.c b/components/bt/host/bluedroid/api/esp_gap_ble_api.c index db513eb5515..1d2267e8bc7 100644 --- a/components/bt/host/bluedroid/api/esp_gap_ble_api.c +++ b/components/bt/host/bluedroid/api/esp_gap_ble_api.c @@ -1014,6 +1014,25 @@ esp_err_t esp_ble_dtm_stop(void) return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } +esp_err_t esp_ble_gap_set_privacy_mode(esp_ble_addr_type_t addr_type, esp_bd_addr_t addr, esp_ble_privacy_mode_t mode) +{ + btc_msg_t msg; + btc_ble_gap_args_t arg; + + ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_GAP_BLE; + msg.act = BTC_GAP_BLE_SET_PRIVACY_MODE; + + arg.set_privacy_mode.addr_type = addr_type; + memcpy(arg.set_privacy_mode.addr, addr, sizeof(esp_bd_addr_t)); + arg.set_privacy_mode.privacy_mode = mode; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gap_args_t), NULL, NULL) + == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + #if (BLE_50_FEATURE_SUPPORT == TRUE) esp_err_t esp_ble_gap_read_phy(esp_bd_addr_t bd_addr) diff --git a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h index 9e9a0e153d5..ea52baf00e5 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -228,6 +228,7 @@ typedef enum { ESP_GAP_BLE_SET_RPA_TIMEOUT_COMPLETE_EVT, /*!< When set the Resolvable Private Address (RPA) timeout completes, the event comes */ ESP_GAP_BLE_ADD_DEV_TO_RESOLVING_LIST_COMPLETE_EVT, /*!< when add a device to the resolving list completes, the event comes*/ ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT, /*!< When vendor hci command complete, the event comes */ + ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT, /*!< When set privacy mode complete, the event comes */ ESP_GAP_BLE_EVT_MAX, /*!< when maximum advertising event complete, the event comes */ } esp_gap_ble_cb_event_t; @@ -1030,6 +1031,11 @@ typedef struct { } esp_ble_gap_past_params_t; #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) +typedef enum{ + ESP_BLE_NETWORK_PRIVACY_MODE = 0X00, /*!< Network Privacy Mode for peer device (default) */ + ESP_BLE_DEVICE_PRIVACY_MODE = 0X01, /*!< Device Privacy Mode for peer device */ +} esp_ble_privacy_mode_t; + /** * @brief Gap callback parameters union */ @@ -1507,6 +1513,12 @@ typedef union { uint16_t param_len; /*!< The length of parameter buffer */ uint8_t *p_param_buf; /*!< The point of parameter buffer */ } vendor_cmd_cmpl; /*!< Event parameter of ESP_GAP_BLE_VENDOR_CMD_COMPLETE_EVT */ + /** + * @brief ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT + */ + struct ble_set_privacy_mode_cmpl_evt_param { + esp_bt_status_t status; /*!< Indicate privacy mode set operation success status */ + } set_privacy_mode_cmpl; /*!< Event parameter of ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT */ } esp_ble_gap_cb_param_t; /** @@ -2640,6 +2652,21 @@ esp_err_t esp_ble_gap_clear_advertising(void); */ esp_err_t esp_ble_gap_vendor_command_send(esp_ble_vendor_cmd_params_t *vendor_cmd_param); +/** + * @brief This function set the privacy mode of the device in resolving list. + * + * @note This feature is not supported on ESP32. + * + * @param[in] addr_type: The address type of the peer identity address (BLE_ADDR_TYPE_PUBLIC or BLE_ADDR_TYPE_RANDOM). + * @param[in] addr: The peer identity address of the device. + * @param[in] mode: The privacy mode of the device. + * + * @return + * - ESP_OK : success + * - other : failed + */ +esp_err_t esp_ble_gap_set_privacy_mode(esp_ble_addr_type_t addr_type, esp_bd_addr_t addr, esp_ble_privacy_mode_t mode); + #ifdef __cplusplus } #endif diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index d478d12e48c..ba5e8f02bca 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -5838,6 +5838,13 @@ void bta_dm_ble_gap_add_dev_to_resolving_list(tBTA_DM_MSG *p_data) p_data->add_dev_to_resolving_list.p_add_dev_to_resolving_list_callback); } +void bta_dm_ble_gap_set_privacy_mode(tBTA_DM_MSG *p_data) +{ + APPL_TRACE_API("%s, privacy_mode = %d", __func__, p_data->ble_set_privacy_mode.privacy_mode); + BTM_BleSetPrivacyMode(p_data->ble_set_privacy_mode.addr_type, p_data->ble_set_privacy_mode.addr, + p_data->ble_set_privacy_mode.privacy_mode, p_data->ble_set_privacy_mode.p_cback); +} + #if (BLE_50_FEATURE_SUPPORT == TRUE) void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data) { diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c index a965edf81ba..a2282cd9bc6 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_api.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_api.c @@ -2679,6 +2679,21 @@ void BTA_DmBleDtmStop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback) } } +void BTA_DmBleSetPrivacyMode(uint8_t addr_type, BD_ADDR addr, uint8_t privacy_mode, tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback) +{ + tBTA_DM_API_SET_PRIVACY_MODE *p_msg; + + if ((p_msg = (tBTA_DM_API_SET_PRIVACY_MODE *)osi_malloc(sizeof(tBTA_DM_API_SET_PRIVACY_MODE))) + != NULL) { + p_msg->hdr.event = BTA_DM_API_SET_PRIVACY_MODE_EVT; + p_msg->addr_type = addr_type; + memcpy(p_msg->addr, addr, sizeof(BD_ADDR)); + p_msg->privacy_mode = privacy_mode; + p_msg->p_cback = p_cback; + bta_sys_sendmsg(p_msg); + } +} + #endif /******************************************************************************* diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c index 6242593c735..99736d8ecec 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_main.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_main.c @@ -234,6 +234,7 @@ const tBTA_DM_ACTION bta_dm_action[BTA_DM_MAX_EVT] = { bta_dm_ble_gap_clear_adv, /* BTA_DM_API_BLE_CLEAR_ADV_EVT */ bta_dm_ble_gap_set_rpa_timeout, /* BTA_DM_API_SET_RPA_TIMEOUT_EVT */ bta_dm_ble_gap_add_dev_to_resolving_list, /* BTA_DM_API_ADD_DEV_TO_RESOLVING_LIST_EVT */ + bta_dm_ble_gap_set_privacy_mode, /* BTA_DM_API_SET_PRIVACY_MODE_EVT */ #endif }; diff --git a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index d756932a6ba..8adc430b185 100644 --- a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -225,6 +225,7 @@ enum { BTA_DM_API_BLE_CLEAR_ADV_EVT, BTA_DM_API_SET_RPA_TIMEOUT_EVT, BTA_DM_API_ADD_DEV_TO_RESOLVING_LIST_EVT, + BTA_DM_API_SET_PRIVACY_MODE_EVT, #endif BTA_DM_MAX_EVT }; @@ -950,6 +951,14 @@ typedef struct { tBTA_CLEAR_ADV_CMPL_CBACK *p_clear_adv_cback; } tBTA_DM_API_CLEAR_ADV; +typedef struct { + BT_HDR hdr; + tBLE_ADDR_TYPE addr_type; + BD_ADDR addr; + UINT8 privacy_mode; + tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback; +} tBTA_DM_API_SET_PRIVACY_MODE; + #endif /* BLE_INCLUDED */ /* data type for BTA_DM_API_REMOVE_ACL_EVT */ @@ -1355,6 +1364,7 @@ typedef union { tBTA_DM_API_BLE_DTM_RX_START dtm_rx_start; tBTA_DM_API_BLE_DTM_STOP dtm_stop; tBTA_DM_API_CLEAR_ADV ble_clear_adv; + tBTA_DM_API_SET_PRIVACY_MODE ble_set_privacy_mode; #endif tBTA_DM_API_REMOVE_ACL remove_acl; @@ -1802,6 +1812,7 @@ extern void bta_dm_ble_gap_dtm_stop(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_clear_adv(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_set_rpa_timeout(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_add_dev_to_resolving_list(tBTA_DM_MSG *p_data); +extern void bta_dm_ble_gap_set_privacy_mode(tBTA_DM_MSG *p_data); #if (BLE_50_FEATURE_SUPPORT == TRUE) extern void bta_dm_ble_gap_dtm_enhance_tx_start(tBTA_DM_MSG *p_data); extern void bta_dm_ble_gap_dtm_enhance_rx_start(tBTA_DM_MSG *p_data); diff --git a/components/bt/host/bluedroid/bta/include/bta/bta_api.h b/components/bt/host/bluedroid/bta/include/bta/bta_api.h index e2f4d374520..75a81994596 100644 --- a/components/bt/host/bluedroid/bta/include/bta/bta_api.h +++ b/components/bt/host/bluedroid/bta/include/bta/bta_api.h @@ -437,6 +437,8 @@ typedef tBTM_SET_RPA_TIMEOUT_CMPL_CBACK tBTA_SET_RPA_TIMEOUT_CMPL_CBACK; typedef tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK tBTA_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK; +typedef tBTM_SET_PRIVACY_MODE_CMPL_CBACK tBTA_SET_PRIVACY_MODE_CMPL_CBACK; + typedef tBTM_CMPL_CB tBTA_CMPL_CB; typedef tBTM_VSC_CMPL tBTA_VSC_CMPL; @@ -2893,6 +2895,8 @@ extern void BTA_DmBleDtmTxStart(uint8_t tx_channel, uint8_t len_of_data, uint8_t extern void BTA_DmBleDtmRxStart(uint8_t rx_channel, tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback); extern void BTA_DmBleDtmStop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback); +extern void BTA_DmBleSetPrivacyMode(uint8_t addr_type, BD_ADDR addr, uint8_t privacy_mode, tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback); + /******************************************************************************* ** ** Function BTA_DmBleSetStorageParams diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 3ef4bd79169..6356eb19229 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -1326,6 +1326,25 @@ static void btc_ble_vendor_hci_cmd_complete_callback(tBTA_VSC_CMPL *p_param) } } +static void btc_ble_set_privacy_mode_callback(UINT8 status) +{ + esp_ble_gap_cb_param_t param; + bt_status_t ret; + btc_msg_t msg = {0}; + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_GAP_BLE; + msg.act = ESP_GAP_BLE_SET_PRIVACY_MODE_COMPLETE_EVT; + + param.set_privacy_mode_cmpl.status = btc_btm_status_to_esp_status(status); + + ret = btc_transfer_context(&msg, ¶m, sizeof(esp_ble_gap_cb_param_t), NULL, NULL); + + if (ret != BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__); + } +} + void btc_get_whitelist_size(uint16_t *length) { BTM_BleGetWhiteListSize(length); @@ -1504,6 +1523,13 @@ static void btc_ble_dtm_stop(tBTA_DTM_CMD_CMPL_CBACK *p_dtm_cmpl_cback) BTA_DmBleDtmStop(p_dtm_cmpl_cback); } +static void btc_ble_set_privacy_mode(uint8_t addr_type, + BD_ADDR addr, + uint8_t privacy_mode, + tBTA_SET_PRIVACY_MODE_CMPL_CBACK *p_cback) +{ + BTA_DmBleSetPrivacyMode(addr_type, addr, privacy_mode, p_cback); +} void btc_gap_ble_cb_handler(btc_msg_t *msg) { @@ -2354,6 +2380,10 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) arg->vendor_cmd_send.p_param_buf, btc_ble_vendor_hci_cmd_complete_callback); break; + case BTC_GAP_BLE_SET_PRIVACY_MODE: + btc_ble_set_privacy_mode(arg->set_privacy_mode.addr_type, arg->set_privacy_mode.addr, + arg->set_privacy_mode.privacy_mode, btc_ble_set_privacy_mode_callback); + break; default: break; } diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h index d09d3c9fc59..e540116de19 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_gap_ble.h @@ -105,6 +105,7 @@ typedef enum { BTC_GAP_BLE_ACT_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, BTC_GAP_BLE_ACT_ADD_DEVICE_TO_RESOLVING_LIST, BTC_GAP_BLE_ACT_VENDOR_HCI_CMD_EVT, + BTC_GAP_BLE_SET_PRIVACY_MODE, } btc_gap_ble_act_t; /* btc_ble_gap_args_t */ @@ -267,9 +268,15 @@ typedef union { uint8_t param_len; uint8_t *p_param_buf; } vendor_cmd_send; + // BTC_GAP_BLE_SET_PRIVACY_MODE + struct set_privacy_mode { + esp_ble_addr_type_t addr_type; + esp_bd_addr_t addr; + uint8_t privacy_mode; + } set_privacy_mode; } btc_ble_gap_args_t; -#if (BLE_50_FEATURE_SUPPORT == TRUE) +#if (BLE_50_FEATURE_SUPPORT == TRUE) typedef union { struct read_phy_args { esp_bd_addr_t bd_addr; diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 3de3f7c1045..9a95d43dfb1 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -4727,6 +4727,17 @@ BOOLEAN BTM_BleAddDevToResolvingList(BD_ADDR addr, return TRUE; } +BOOLEAN BTM_BleSetPrivacyMode(UINT8 addr_type, BD_ADDR bd_addr, UINT8 privacy_mode, tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_callback) +{ + if (btsnd_hcic_ble_set_privacy_mode(addr_type, bd_addr, privacy_mode) != TRUE) { + BTM_TRACE_ERROR("LE SetPrivacyMode Mode=%d: error", privacy_mode); + return FALSE; + } + + btm_cb.devcb.p_set_privacy_mode_cmpl_cb = p_callback; + return TRUE; +} + bool btm_ble_adv_pkt_ready(void) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 4c8ff652070..be4b9d15411 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -454,6 +454,34 @@ void btm_ble_set_rpa_timeout_complete(UINT8 *p, UINT16 evt_len) } +/******************************************************************************* +** +** Function btm_ble_set_privacy_mode_complete +** +** Description This function is called when the LE Set Privacy Mode command completes. +** +** Parameters p: Pointer to the command complete event data. +** evt_len: Length of the event data. +** +** Returns void +** +*******************************************************************************/ +void btm_ble_set_privacy_mode_complete(UINT8 *p, UINT16 evt_len) +{ + UINT8 status; + + // Extract the status of the command completion from the event data + STREAM_TO_UINT8(status, p); + + BTM_TRACE_DEBUG("%s status = 0x%x", __func__, status); + + tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_cb = btm_cb.devcb.p_set_privacy_mode_cmpl_cb; + + if (p_cb) { + (*p_cb)(status); + } +} + /******************************************************************************* VSC that implement controller based privacy ********************************************************************************/ diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h index dd42cefcac0..0f8888fb1bd 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_ble_int.h @@ -497,6 +497,7 @@ void btm_ble_enable_resolving_list_for_platform (UINT8 rl_mask); void btm_ble_resolving_list_init(UINT8 max_irk_list_sz); void btm_ble_resolving_list_cleanup(void); void btm_ble_add_default_entry_to_resolving_list(void); +void btm_ble_set_privacy_mode_complete(UINT8 *p, UINT16 evt_len); #endif void btm_ble_multi_adv_configure_rpa (tBTM_BLE_MULTI_ADV_INST *p_inst); diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index f8ed2d86bec..0f836cff806 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -237,6 +237,9 @@ tBTM_SET_RPA_TIMEOUT_CMPL_CBACK *p_ble_set_rpa_timeout_cmpl_cb; /* Callback fun ble set rpa timeout is completed */ tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_cmpl_cb; + +tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_set_privacy_mode_cmpl_cb; + tBTM_CMPL_CB *p_le_test_cmd_cmpl_cb; /* Callback function to be called when LE test mode command has been sent successfully */ diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index e856594be4d..1fda46abfcb 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1100,6 +1100,10 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l case HCI_BLE_SET_RAND_PRIV_ADDR_TIMOUT: btm_ble_set_rpa_timeout_complete(p, evt_len); break; + case HCI_BLE_SET_PRIVACY_MODE: + btm_ble_set_privacy_mode_complete(p, evt_len); + break; +#endif // #if (defined BLE_PRIVACY_SPT && BLE_PRIVACY_SPT == TRUE) #if (BLE_50_FEATURE_SUPPORT == TRUE) case HCI_BLE_SET_EXT_ADV_PARAM: case HCI_BLE_SET_EXT_ADV_DATA: @@ -1139,7 +1143,6 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; } #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) -#endif #endif /* (BLE_INCLUDED == TRUE) */ default: { diff --git a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c index 0f6408f0826..52a2b2dc09e 100644 --- a/components/bt/host/bluedroid/stack/hcic/hciblecmds.c +++ b/components/bt/host/bluedroid/stack/hcic/hciblecmds.c @@ -1909,4 +1909,28 @@ UINT8 btsnd_hcic_ble_set_default_periodic_adv_sync_trans_params(UINT8 mode, UINT return btu_hcif_send_cmd_sync(LOCAL_BR_EDR_CONTROLLER_ID, p); } #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) + +UINT8 btsnd_hcic_ble_set_privacy_mode(UINT8 addr_type, BD_ADDR addr, UINT8 privacy_mode) +{ + BT_HDR *p; + UINT8 *pp; + + if ((p = HCI_GET_CMD_BUF (HCIC_PARAM_SIZE_SET_PRIVACY_MODE)) == NULL) { + return (FALSE); + } + + pp = (UINT8 *)(p + 1); + p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_SET_PRIVACY_MODE; + p->offset = 0; + + UINT16_TO_STREAM(pp, HCI_BLE_SET_PRIVACY_MODE); + UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_SET_PRIVACY_MODE); + + UINT8_TO_STREAM(pp, addr_type); + BDADDR_TO_STREAM(pp, addr); + UINT8_TO_STREAM(pp, privacy_mode); + + btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p); + return (TRUE); +} #endif diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h index bf431ce6cd2..e1081c989e0 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -1006,6 +1006,8 @@ typedef void (tBTM_START_STOP_ADV_CMPL_CBACK) (UINT8 status); typedef void (tBTM_UPDATE_DUPLICATE_EXCEPTIONAL_LIST_CMPL_CBACK) (tBTM_STATUS status, uint8_t subcode, uint32_t length, uint8_t *device_info); typedef void (tBTM_CLEAR_ADV_CMPL_CBACK) (UINT8 status); +typedef void (tBTM_SET_PRIVACY_MODE_CMPL_CBACK) (tBTM_STATUS status); + #if (BLE_50_FEATURE_SUPPORT == TRUE) #define BTM_BLE_5_GAP_READ_PHY_COMPLETE_EVT 1 #define BTM_BLE_5_GAP_SET_PREFERED_DEFAULT_PHY_COMPLETE_EVT 2 @@ -1048,7 +1050,8 @@ typedef void (tBTM_CLEAR_ADV_CMPL_CBACK) (UINT8 status); #define BTM_BLE_GAP_SET_PAST_PARAMS_COMPLETE_EVT 38 #define BTM_BLE_GAP_PERIODIC_ADV_SYNC_TRANS_RECV_EVT 39 #endif // #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) -#define BTM_BLE_5_GAP_UNKNOWN_EVT 40 +#define BTM_BLE_GAP_SET_PRIVACY_MODE_COMPLETE_EVT 40 +#define BTM_BLE_5_GAP_UNKNOWN_EVT 41 typedef UINT8 tBTM_BLE_5_GAP_EVENT; #define BTM_BLE_EXT_ADV_DATA_COMPLETE 0x00 @@ -2689,6 +2692,25 @@ BOOLEAN BTM_BleAddDevToResolvingList(BD_ADDR addr, uint8_t irk[], tBTM_ADD_DEV_TO_RESOLVING_LIST_CMPL_CBACK *p_add_dev_to_resolving_list_callback); +/******************************************************************************* +** +** Function BTM_BleSetPrivacyMode +** +** Description This function is called to set the privacy mode of device in resolving list +** +** Parameters addr_type - The address type of the device in resolving list (public or random). +** addr - The address of the device in resolving list. +** privacy_mode - The privacy mode (network or device) of the device. +** p_callback - Callback function to be called when the operation is completed. +** +** Returns TRUE if the operation was successful, otherwise FALSE. +** +*******************************************************************************/ +BOOLEAN BTM_BleSetPrivacyMode(UINT8 addr_type, + BD_ADDR bd_addr, + UINT8 privacy_mode, + tBTM_SET_PRIVACY_MODE_CMPL_CBACK *p_callback); + /* #ifdef __cplusplus } diff --git a/components/bt/host/bluedroid/stack/include/stack/hcidefs.h b/components/bt/host/bluedroid/stack/include/stack/hcidefs.h index 2f6ce5b767d..21b14881739 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcidefs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcidefs.h @@ -384,8 +384,8 @@ #define HCI_BLE_RD_TRANSMIT_POWER (0x004B | HCI_GRP_BLE_CMDS) #define HCI_BLE_RD_RF_PATH_COMPENSATION (0x004C | HCI_GRP_BLE_CMDS) #define HCI_BLE_WR_RF_PATH_COMPENSATION (0x004D | HCI_GRP_BLE_CMDS) -#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS) #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) +#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS) #if (BLE_FEAT_PERIODIC_ADV_SYNC_TRANSFER == TRUE) #define HCI_BLE_SET_PERIOD_ADV_RECV_ENABLE (0x0059 | HCI_GRP_BLE_CMDS) #define HCI_BLE_PERIOD_ADV_SYNC_TRANS (0x005A | HCI_GRP_BLE_CMDS) @@ -1134,18 +1134,18 @@ typedef UINT8 tHCI_STATUS; #define HCI_MIN_INQ_LAP 0x9E8B00 #define HCI_MAX_INQ_LAP 0x9E8B3F -/* HCI role defenitions */ +/* HCI role definitions */ #define HCI_ROLE_MASTER 0x00 #define HCI_ROLE_SLAVE 0x01 #define HCI_ROLE_UNKNOWN 0xff -/* HCI mode defenitions */ +/* HCI mode definitions */ #define HCI_MODE_ACTIVE 0x00 #define HCI_MODE_HOLD 0x01 #define HCI_MODE_SNIFF 0x02 #define HCI_MODE_PARK 0x03 -/* HCI Flow Control Mode defenitions */ +/* HCI Flow Control Mode definitions */ #define HCI_PACKET_BASED_FC_MODE 0x00 #define HCI_BLOCK_BASED_FC_MODE 0x01 @@ -1414,7 +1414,7 @@ typedef UINT8 tHCI_STATUS; /* Define an invalid value for a handle */ #define HCI_INVALID_HANDLE 0xFFFF -/* Define max ammount of data in the HCI command */ +/* Define max amount of data in the HCI command */ #define HCI_COMMAND_SIZE 255 /* Define the preamble length for all HCI Commands. diff --git a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h index b7d64edd991..951e5b703a7 100644 --- a/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h +++ b/components/bt/host/bluedroid/stack/include/stack/hcimsgs.h @@ -758,6 +758,7 @@ void btsnd_hcic_vendor_spec_cmd (BT_HDR *buffer, UINT16 opcode, #define HCIC_PARAM_SIZE_BLE_WRITE_EXTENDED_SCAN_PARAM 11 #define HCIC_PARAM_SIZE_BLE_UPDATE_ADV_FLOW_CONTROL 2 #define HCIC_PARAM_SIZE_BLE_CLEAR_ADV 0 +#define HCIC_PARAM_SIZE_SET_PRIVACY_MODE 8 #if (BLE_50_FEATURE_SUPPORT == TRUE) #define HCIC_PARAM_SIZE_BLE_READ_PHY 2 #define HCIC_PARAM_SIZE_BLE_SET_DEF_PHY 3 @@ -1041,6 +1042,8 @@ UINT8 btsnd_hcic_ble_write_rf_path_compensation(UINT16 rf_tx_path, UINT16 rf_rx_ #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) +UINT8 btsnd_hcic_ble_set_privacy_mode(UINT8 addr_type, BD_ADDR addr, UINT8 privacy_mode); + #define HCIC_PARAM_SIZE_WRITE_AUTHENT_PAYLOAD_TOUT 4 #define HCI__WRITE_AUTHENT_PAYLOAD_TOUT_HANDLE_OFF 0 From b8d9da5c03ff71b076912356aa05128a2ce54baf Mon Sep 17 00:00:00 2001 From: "chaijie@espressif.com" Date: Sat, 23 Dec 2023 17:10:56 +0800 Subject: [PATCH 124/548] feat(sleep): support 8m force pu in sleep for esp32c6/esp32h2 --- components/esp_hw_support/port/esp32c6/pmu_sleep.c | 4 ++++ .../esp_hw_support/port/esp32c6/private_include/pmu_param.h | 1 + components/esp_hw_support/port/esp32h2/pmu_sleep.c | 3 +++ 3 files changed, 8 insertions(+) diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index c85fd72c2c7..7396e41b8c2 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -236,6 +236,10 @@ const pmu_sleep_config_t* pmu_sleep_config_default( analog_default.lp_sys[LP(SLEEP)].analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; analog_default.lp_sys[LP(SLEEP)].analog.dbg_atten = PMU_DBG_ATTEN_ACTIVE_DEFAULT; analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); + } else if (!(pd_flags & PMU_SLEEP_PD_RC_FAST)) { + analog_default.hp_sys.analog.dbias = get_act_hp_dbias(); + analog_default.lp_sys[LP(SLEEP)].analog.dbg_atten = PMU_DBG_ATTEN_LIGHTSLEEP_NODROP; + analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); } config->analog = analog_default; diff --git a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h index 751076f7521..aad6f976ba4 100644 --- a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h @@ -35,6 +35,7 @@ extern "C" { #define PMU_LP_DRVB_LIGHTSLEEP 0 #define PMU_HP_XPD_LIGHTSLEEP 1 +#define PMU_DBG_ATTEN_LIGHTSLEEP_NODROP 0 #define PMU_DBG_ATTEN_LIGHTSLEEP_DEFAULT 0 #define PMU_HP_DBIAS_LIGHTSLEEP_0V6_DEFAULT 1 #define PMU_LP_DBIAS_LIGHTSLEEP_0V7_DEFAULT 12 diff --git a/components/esp_hw_support/port/esp32h2/pmu_sleep.c b/components/esp_hw_support/port/esp32h2/pmu_sleep.c index 5c2b902523e..a59e81f1ecc 100644 --- a/components/esp_hw_support/port/esp32h2/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h2/pmu_sleep.c @@ -164,6 +164,9 @@ const pmu_sleep_config_t* pmu_sleep_config_default( analog_default.lp_sys[LP(SLEEP)].analog.pd_cur = PMU_PD_CUR_SLEEP_ON; analog_default.lp_sys[LP(SLEEP)].analog.bias_sleep = PMU_BIASSLP_SLEEP_ON; analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); + } else if (!(pd_flags & PMU_SLEEP_PD_RC_FAST)) { + analog_default.hp_sys.analog.dbias = get_act_hp_dbias(); + analog_default.lp_sys[LP(SLEEP)].analog.dbias = get_act_lp_dbias(); } config->analog = analog_default; } From 9f04d1ac360e76c1f4b6febdb2eca1ba0ca5d398 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Tue, 23 Apr 2024 11:30:02 +0800 Subject: [PATCH 125/548] fix(bt): Update bt lib for ESP32-C3 and ESP32-S3(a771b7c) - Fixed assert when starting advertising due to preemption - Fixed RPA generation after each reboot - Fixed RPA renew timer start and stop --- components/bt/controller/lib_esp32c3_family | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index 76ed4114ee7..9780fd66d97 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit 76ed4114ee7d081435a3c65793b4c8eb1dfaf199 +Subproject commit 9780fd66d97866977d972fb63319830f47f12785 diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld index 9b7a16d1982..e45a80e496c 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld @@ -165,9 +165,7 @@ r_lld_cca_lbt_handle = 0x40001df8; r_lld_cca_scst_timeout_check = 0x40001dfc; r_lld_cca_chan_avl_timeout_check = 0x40001e00; -r_lld_scan_start_hook = 0x40001c74; r_lld_con_start_hook = 0x40001ca8; -r_lld_init_start_hook = 0x40001cb8; /* ble Functions eco */ r_bt_bb_isr = 0x40000b9c; @@ -215,6 +213,8 @@ r_llc_llcp_channel_map_ind_ack = 0x40001d68; r_rwble_isr = 0x40001464; r_lld_scan_start_eco = 0x40001d24; r_lld_scan_try_sched_eco = 0x40001dac; +r_lld_scan_start_hook = 0x40001c74; +r_lld_init_start_hook = 0x40001cb8; */ From 0c3a0d6c9ae97a1de87e1b9d7adc1a82949d792e Mon Sep 17 00:00:00 2001 From: baohongde Date: Thu, 25 Apr 2024 14:44:59 +0800 Subject: [PATCH 126/548] fix(coex): Fixed some coexist issues - Fixed crash issue in coexist callback - Fixed coexist scheme status update issue --- components/bt/controller/lib_esp32c3_family | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index 9780fd66d97..4b1338827fa 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit 9780fd66d97866977d972fb63319830f47f12785 +Subproject commit 4b1338827fa19fbacc02dd9e46e76be2b0dd17a9 From 617f5a705202d559f860ba8afce6e1d687510fd8 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 11 Mar 2024 21:19:17 +0100 Subject: [PATCH 127/548] feat(coredump): save .bss, .data and .heap sections to the elf file --- components/espcoredump/Kconfig | 15 +- .../include_core_dump/esp_core_dump_common.h | 22 ++- components/espcoredump/src/core_dump_common.c | 100 +++++++---- components/espcoredump/src/core_dump_elf.c | 160 ++++++++++++++++-- docs/en/api-guides/core_dump.rst | 19 ++- docs/zh_CN/api-guides/core_dump.rst | 20 ++- .../gdbstub_runtime/main/test_app_main.c | 2 +- .../system/gdbstub_runtime/pytest_runtime.py | 11 +- .../system/panic/main/include/test_panic.h | 2 + .../system/panic/main/test_app_main.c | 3 + .../test_apps/system/panic/main/test_panic.c | 27 +++ .../system/panic/partitions_capture_dram.csv | 6 + tools/test_apps/system/panic/pytest_panic.py | 28 ++- .../sdkconfig.ci.coredump_flash_capture_dram | 6 + .../system/panic/test_panic_util/panic_dut.py | 41 +++-- 15 files changed, 386 insertions(+), 76 deletions(-) create mode 100644 tools/test_apps/system/panic/partitions_capture_dram.csv create mode 100644 tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram diff --git a/components/espcoredump/Kconfig b/components/espcoredump/Kconfig index 8de6fdd26cb..d95090c7435 100644 --- a/components/espcoredump/Kconfig +++ b/components/espcoredump/Kconfig @@ -47,6 +47,18 @@ menu "Core dump" depends on ESP_COREDUMP_DATA_FORMAT_ELF endchoice + config ESP_COREDUMP_CAPTURE_DRAM + bool "Include whole .bss and .data sections and heap data into core dump file" + default n + #TODO: Heap walker api is not ready for the esp32c5 (IDF-9641) + depends on ESP_COREDUMP_DATA_FORMAT_ELF && !IDF_TARGET_ESP32C5 + help + Storing these sections can help with easier debugging and troubleshooting. + However, additional storage space will be required in the core dump partition. + At least 128KB should be reserved, but the actual amount required may vary based + on the application's DRAM usage. + Note that sections located in external RAM will not be stored. + config ESP_COREDUMP_CHECK_BOOT bool "Check core dump data integrity on boot" default y @@ -112,7 +124,8 @@ menu "Core dump" help Size of the memory to be reserved for core dump stack. If 0 core dump process will run on the stack of crashed task/ISR, otherwise special stack will be allocated. - To ensure that core dump itself will not overflow task/ISR stack set this to the value above 800. + To ensure that core dump itself will not overflow task/ISR stack set this to the value around 1300-1800 + depending on the chosen checksum calculation method. SHA256 method needs more stack space than CRC32. NOTE: It eats DRAM. config ESP_COREDUMP_SUMMARY_STACKDUMP_SIZE diff --git a/components/espcoredump/include_core_dump/esp_core_dump_common.h b/components/espcoredump/include_core_dump/esp_core_dump_common.h index f5a26749e73..9e9efb2ef1c 100644 --- a/components/espcoredump/include_core_dump/esp_core_dump_common.h +++ b/components/espcoredump/include_core_dump/esp_core_dump_common.h @@ -20,15 +20,25 @@ extern "C" { * One can use these definitions to retrieve the start address and/or the size * of a specific region using the functions below. */ + typedef enum { - COREDUMP_MEMORY_DRAM, COREDUMP_MEMORY_IRAM, +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + COREDUMP_MEMORY_DRAM_BSS, + COREDUMP_MEMORY_DRAM_DATA, +#if CONFIG_IDF_TARGET_ESP32P4 + COREDUMP_MEMORY_DRAM_BSS_HIGH, + COREDUMP_MEMORY_DRAM_DATA_HIGH, +#endif +#else + COREDUMP_MEMORY_DRAM, +#endif #if SOC_RTC_MEM_SUPPORTED COREDUMP_MEMORY_RTC, COREDUMP_MEMORY_RTC_FAST, #endif COREDUMP_MEMORY_MAX, - COREDUMP_MEMORY_START = COREDUMP_MEMORY_DRAM + COREDUMP_MEMORY_START = COREDUMP_MEMORY_IRAM } coredump_region_t; /** @@ -126,6 +136,12 @@ esp_err_t esp_core_dump_write_data(core_dump_write_data_t *wr_data, void *data, */ esp_err_t esp_core_dump_write_end(core_dump_write_data_t *wr_data); +/** + * @brief Retrieve the stack information which will be used from the coredump module itself. + * It will show the whole stack boundaries in case the stack is shared with the crashed task. + */ +void esp_core_dump_get_own_stack_info(uint32_t *addr, uint32_t *size); + /** * @brief Stores the core dump in either binary or ELF format. */ @@ -157,7 +173,7 @@ static inline core_dump_task_handle_t esp_core_dump_get_current_task_handle(void * @brief Get the length, in bytes, of a given memory location. Padding is * taken into account in this calculation. * - * @param start Start address of the momery location. + * @param start Start address of the memory location. * @param end End address of the memory location. * * @return Size of the memory location, multiple of sizeof(uint32_t). diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index afca899b605..d455bc9d3b3 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -25,6 +25,25 @@ const static char TAG[] __attribute__((unused)) = "esp_core_dump_common"; /** * @brief Memory regions to dump, defined at compile time. */ +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM +#if !CONFIG_IDF_TARGET_ESP32P4 +extern int _bss_start; +extern int _bss_end; +extern int _data_start; +extern int _data_end; +#else +extern int _bss_start_low; +extern int _bss_end_low; +extern int _data_start_low; +extern int _data_end_low; +extern int _bss_start_high; +extern int _bss_end_high; +extern int _data_start_high; +extern int _data_end_high; +#endif +#endif + +/* Regions for the user defined variable locations */ extern int _coredump_dram_start; extern int _coredump_dram_end; extern int _coredump_iram_start; @@ -160,6 +179,7 @@ FORCE_INLINE_ATTR void esp_core_dump_setup_stack(void) FORCE_INLINE_ATTR void esp_core_dump_report_stack_usage(void) { } + #endif // CONFIG_ESP_COREDUMP_STACK_SIZE > 0 static void* s_exc_frame = NULL; @@ -254,19 +274,29 @@ uint32_t esp_core_dump_get_user_ram_segments(void) return total_sz; } -uint32_t esp_core_dump_get_user_ram_size(void) -{ - uint32_t total_sz = 0; - - total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_dram_end, &_coredump_dram_start); +static const struct { + int *start; + int *end; +} s_memory_sections[COREDUMP_MEMORY_MAX] = { + [COREDUMP_MEMORY_IRAM] = { &_coredump_iram_start, &_coredump_iram_end }, +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM +#if !CONFIG_IDF_TARGET_ESP32P4 + [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end }, + [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end }, +#else + [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start_low, &_bss_end_low }, + [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start_low, &_data_end_low }, + [COREDUMP_MEMORY_DRAM_BSS_HIGH] = { &_bss_start_high, &_bss_end_high }, + [COREDUMP_MEMORY_DRAM_DATA_HIGH] = { &_data_start_high, &_data_end_high }, +#endif +#else + [COREDUMP_MEMORY_DRAM] = { &_coredump_dram_start, &_coredump_dram_end }, +#endif #if SOC_RTC_MEM_SUPPORTED - total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_end, &_coredump_rtc_start); - total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_rtc_fast_end, &_coredump_rtc_fast_start); + [COREDUMP_MEMORY_RTC] = { &_coredump_rtc_start, &_coredump_rtc_end }, + [COREDUMP_MEMORY_RTC_FAST] = { &_coredump_rtc_fast_start, &_coredump_rtc_fast_end }, #endif - total_sz += COREDUMP_GET_MEMORY_SIZE(&_coredump_iram_end, &_coredump_iram_start); - - return total_sz; -} +}; int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start) { @@ -274,36 +304,34 @@ int esp_core_dump_get_user_ram_info(coredump_region_t region, uint32_t *start) ESP_COREDUMP_DEBUG_ASSERT(start != NULL); - switch (region) { - case COREDUMP_MEMORY_DRAM: - *start = (uint32_t)&_coredump_dram_start; - total_sz = (uint8_t *)&_coredump_dram_end - (uint8_t *)&_coredump_dram_start; - break; - - case COREDUMP_MEMORY_IRAM: - *start = (uint32_t)&_coredump_iram_start; - total_sz = (uint8_t *)&_coredump_iram_end - (uint8_t *)&_coredump_iram_start; - break; - -#if SOC_RTC_MEM_SUPPORTED - case COREDUMP_MEMORY_RTC: - *start = (uint32_t)&_coredump_rtc_start; - total_sz = (uint8_t *)&_coredump_rtc_end - (uint8_t *)&_coredump_rtc_start; - break; - - case COREDUMP_MEMORY_RTC_FAST: - *start = (uint32_t)&_coredump_rtc_fast_start; - total_sz = (uint8_t *)&_coredump_rtc_fast_end - (uint8_t *)&_coredump_rtc_fast_start; - break; -#endif - - default: - break; + if (region >= COREDUMP_MEMORY_START && region < COREDUMP_MEMORY_MAX) { + total_sz = (uint8_t *)s_memory_sections[region].end - (uint8_t *)s_memory_sections[region].start; + *start = (uint32_t)s_memory_sections[region].start; } return total_sz; } +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM +void esp_core_dump_get_own_stack_info(uint32_t *addr, uint32_t *size) +{ +#if CONFIG_ESP_COREDUMP_STACK_SIZE > 0 + /* Custom stack reserved for the coredump */ + *addr = (uint32_t)s_coredump_stack; + *size = sizeof(s_coredump_stack); +#else + /* Shared stack with the crashed task */ + core_dump_task_handle_t handle = esp_core_dump_get_current_task_handle(); + TaskSnapshot_t rtos_snapshot = { 0 }; + vTaskGetSnapshot(handle, &rtos_snapshot); + StaticTask_t *current = (StaticTask_t *)handle; + *addr = (uint32_t)current->pxDummy6; //pxStack + *size = (uint32_t)rtos_snapshot.pxTopOfStack - (uint32_t)current->pxDummy6; /* free */ +#endif +} + +#endif /* CONFIG_ESP_COREDUMP_CAPTURE_DRAM */ + inline bool esp_core_dump_tcb_addr_is_sane(uint32_t addr) { return esp_core_dump_mem_seg_is_sane(addr, esp_core_dump_get_tcb_len()); diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 74a1ac5a8d2..be99de24966 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -80,6 +80,11 @@ typedef struct _core_dump_elf_t { uint16_t segs_count; core_dump_write_data_t write_data; uint32_t note_data_size; /* can be used where static storage needed */ +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + /* To avoid checksum failure, coredump stack region will be excluded while storing the sections. */ + uint32_t coredump_stack_start; + uint32_t coredump_stack_size; +#endif } core_dump_elf_t; typedef struct { @@ -474,10 +479,17 @@ static int elf_write_tasks_data(core_dump_elf_t *self) bad_tasks_num++; continue; } - ret = elf_save_task(self, &task_hdr); - ELF_CHECK_ERR((ret > 0), ret, - "Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, ret); - elf_len += ret; + +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + /* Only crashed task data will be saved here. The other task's data will be automatically saved within the sections */ + if (esp_core_dump_get_current_task_handle() != task_iter.pxTaskHandle) +#endif + { + ret = elf_save_task(self, &task_hdr); + ELF_CHECK_ERR((ret > 0), ret, + "Task %x, TCB write failed, return (%d).", task_iter.pxTaskHandle, ret); + elf_len += ret; + } if (interrupted_stack.size > 0) { ESP_COREDUMP_LOG_PROCESS("Add interrupted task stack %lu bytes @ %x", interrupted_stack.size, interrupted_stack.start); @@ -493,28 +505,148 @@ static int elf_write_tasks_data(core_dump_elf_t *self) return elf_len; } +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + +/* Coredump stack will also be used by the checksum functions while saving sections. + * There is a potential for inconsistency when writing coredump stack to the flash and calculating checksum simultaneously. + * This is because, coredump stack will be modified during the process, leading to incorrect checksum calculations. + * To mitigate this issue, it's important to ensure that the coredump stack excluded from checksum calculation by + * filter out from the written regions. + * Typically, the coredump stack can be located in two different sections. + * 1. In the bss section; + * 1.a if `CONFIG_ESP_COREDUMP_STACK_SIZE` set to a nonzero value + * 1.b if the crashed task is created with a static task buffer using the xTaskCreateStatic() api + * 2. In the heap section, if custom stack is not defined and the crashed task buffer is allocated in the heap + * with the xTaskCreate() api + * + * esp_core_dump_store_section() will check if the coredump stack is located inside the section. + * If it is, this part will be skipped. + * |+++++++++| xxxxxxxxxxxxxx |++++++++| + * |+++++++++| coredump stack |++++++++| +*/ +static int esp_core_dump_store_section(core_dump_elf_t *self, uint32_t start, uint32_t data_len) +{ + uint32_t end = start + data_len; + int total_sz = 0; + int ret; + + if (self->coredump_stack_start > start && self->coredump_stack_start < end) { + /* write until the coredump stack. */ + data_len = self->coredump_stack_start - start; + ret = elf_add_segment(self, PT_LOAD, + start, + (void*)start, + data_len); + + if (ret <= 0) { + return ret; + } + total_sz += ret; + + /* Skip coredump stack and set offset for the rest of the section */ + start = self->coredump_stack_start + self->coredump_stack_size; + data_len = end - start; + } + + if (data_len > 0) { + ret = elf_add_segment(self, PT_LOAD, + (uint32_t)start, + (void*)start, + (uint32_t)data_len); + if (ret <= 0) { + return ret; + } + total_sz += ret; + } + + return total_sz; +} + +typedef struct { + core_dump_elf_t *self; + int *total_sz; + int ret; +} heap_block_data_t; + +bool esp_core_dump_write_heap_blocks(walker_heap_into_t heap_info, walker_block_info_t block_info, void* user_data) +{ + heap_block_data_t *param = user_data; + int *total_sz = param->total_sz; + core_dump_elf_t *self = param->self; + int *ret = ¶m->ret; + + if (*ret <= 0) { + /* There was a flash write failure at the previous write attempt */ + return false; + } + + if ((intptr_t)heap_info.end - (intptr_t)block_info.ptr < block_info.size) { + ESP_COREDUMP_LOGE("Block corruption detected in the heap (%p-%p)", heap_info.start, heap_info.end); + ESP_COREDUMP_LOGE("Corrupted block addr:%p size:%x)", block_info.ptr, block_info.size); + /* Heap walker will skip the next block in the same heap region and it will continue from the next heap region's block. */ + return false; + } + + if (block_info.used && block_info.size > 0) { + ESP_COREDUMP_LOG_PROCESS("heap block @%p sz:(%x)", (void *)block_info.ptr, block_info.size); + + if (!esp_core_dump_mem_seg_is_sane((uint32_t)block_info.ptr, block_info.size)) { + return false; + } + + if (self->coredump_stack_start == (uint32_t)block_info.ptr) { + /* skip writing coredump stack block */ + return true; + } + + *ret = elf_add_segment(self, PT_LOAD, + (uint32_t)block_info.ptr, + (void*)block_info.ptr, + block_info.size); + if (*ret <= 0) { + return false; + } + *total_sz += *ret; + } + + return true; +} + +#else + +static int esp_core_dump_store_section(core_dump_elf_t *self, uint32_t start, uint32_t data_len) +{ + return elf_add_segment(self, PT_LOAD, + start, + (void*)start, + data_len); +} + +#endif + static int elf_write_core_dump_user_data(core_dump_elf_t *self) { - int data_len = 0; int total_sz = 0; uint32_t start = 0; for (coredump_region_t i = COREDUMP_MEMORY_START; i < COREDUMP_MEMORY_MAX; i++) { - data_len = esp_core_dump_get_user_ram_info(i, &start); + int data_len = esp_core_dump_get_user_ram_info(i, &start); ELF_CHECK_ERR((data_len >= 0), ELF_PROC_ERR_OTHER, "invalid memory region"); if (data_len > 0) { - int ret = elf_add_segment(self, PT_LOAD, - (uint32_t)start, - (void*)start, - (uint32_t) data_len); - + int ret = esp_core_dump_store_section(self, start, data_len); ELF_CHECK_ERR((ret > 0), ret, "memory region write failed. Returned (%d).", ret); total_sz += ret; } } +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + heap_block_data_t user_data = {.self = self, .total_sz = &total_sz, .ret = 1}; + heap_caps_walk(MALLOC_CAP_8BIT, esp_core_dump_write_heap_blocks, &user_data); + ELF_CHECK_ERR((user_data.ret > 0), user_data.ret, "Heap memory write failed. Returned (%d).", user_data.ret); +#endif + return total_sz; } @@ -676,6 +808,12 @@ static esp_err_t esp_core_dump_write_elf(void) int tot_len = sizeof(dump_hdr); int write_len = sizeof(dump_hdr); +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + esp_core_dump_get_own_stack_info(&self.coredump_stack_start, &self.coredump_stack_size); + ESP_COREDUMP_LOG_PROCESS("Core dump stack start=%p size = %d", + (void *)self.coredump_stack_start, self.coredump_stack_size); +#endif + esp_err_t err = esp_core_dump_write_init(); if (err != ESP_OK) { ESP_COREDUMP_LOGE("Elf write init failed!"); diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index c544ab98276..8bc5799b577 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -56,9 +56,26 @@ Setting this option to 0 bytes will cause the core dump routines to run from the .. note:: - If a separate stack is used, the recommended stack size should be larger than 800 bytes to ensure that the core dump routines themselves do not cause a stack overflow. + If a separate stack is used, the recommended stack size should be larger than 1300 bytes to ensure that the core dump routines themselves do not cause a stack overflow. +Core Dump Memory Regions +^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, core dumps typically save CPU registers, tasks data and summary of the panic reason. When the :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` option is selected, ``.bss`` and ``.data`` sections and ``heap`` data will also be part of the dump. + +For a better debugging experience, it is recommended to dump these sections. However, this will result in a larger coredump file. The required additional storage space may vary based on the amount of DRAM the application uses. + +.. note:: + + .. only:: SOC_SPIRAM_SUPPORTED + + Apart from the crashed task's TCB and stack, data located in the external RAM will not be stored in the core dump file, this include variables defined with ``EXT_RAM_BSS_ATTR`` or ``EXT_RAM_NOINIT_ATTR`` attributes, as well as any data stored in the ``extram_bss`` section. + +.. note:: + + This feature is only enabled when using the ELF file format. + Core Dump to Flash ------------------ diff --git a/docs/zh_CN/api-guides/core_dump.rst b/docs/zh_CN/api-guides/core_dump.rst index 83e4e8af77b..6844072c573 100644 --- a/docs/zh_CN/api-guides/core_dump.rst +++ b/docs/zh_CN/api-guides/core_dump.rst @@ -56,7 +56,25 @@ ELF 格式具备扩展特性,支持在发生崩溃时保存更多关于错误 .. note:: - 如果使用了独立的栈,建议栈大小应大于 800 字节,确保核心转储例程本身不会导致栈溢出。 + 如果使用了独立的栈,建议栈大小应大于 1300 字节,确保核心转储例程本身不会导致栈溢出。 + + +Core Dump Memory Regions +^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, core dumps typically save CPU registers, tasks data and summary of the panic reason. When the :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` option is selected, ``.bss`` and ``.data`` sections and ``heap`` data will also be part of the dump. + +For a better debugging experience, it is recommended to dump these sections. However, this will result in a larger coredump file. The required additional storage space may vary based on the amount of DRAM the application uses. + +.. note:: + + .. only:: SOC_SPIRAM_SUPPORTED + + Apart from the crashed task's TCB and stack, data located in the external RAM will not be stored in the core dump file, this include variables defined with ``EXT_RAM_BSS_ATTR`` or ``EXT_RAM_NOINIT_ATTR`` attributes, as well as any data stored in the ``extram_bss`` section. + +.. note:: + + This feature is only enabled when using the ELF file format. 将核心转储保存到 flash diff --git a/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c b/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c index 69bae474a83..7f3980e3a9c 100644 --- a/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c +++ b/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c @@ -21,7 +21,7 @@ void foo(void) void app_main(void) { - printf("tested app is runnig.\n"); + printf("tested app is running.\n"); vTaskDelay(5000 / portTICK_PERIOD_MS); diff --git a/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py b/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py index b97fdc3b71f..040e7f2c835 100644 --- a/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py +++ b/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py @@ -1,6 +1,5 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import os.path as path import sys @@ -23,9 +22,9 @@ def get_line_number(lookup: str, offset: int = 0) -> int: @pytest.mark.supported_targets @pytest.mark.generic def test_gdbstub_runtime(dut: PanicTestDut) -> None: - dut.expect_exact('tested app is runnig.') + dut.expect_exact('tested app is running.') dut.write(b'\x03') # send Ctrl-C - dut.start_gdb() + dut.start_gdb_for_gdbstub() # Test breakpoint cmd = '-break-insert --source test_app_main.c --function app_main --label label_1' @@ -162,9 +161,9 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None: @pytest.mark.generic @pytest.mark.temp_skip_ci(targets=['esp32', 'esp32s2', 'esp32s3'], reason='fix IDF-7927') def test_gdbstub_runtime_xtensa_stepping_bug(dut: PanicTestDut) -> None: - dut.expect_exact('tested app is runnig.') + dut.expect_exact('tested app is running.') dut.write(b'\x03') # send Ctrl-C - dut.start_gdb() + dut.start_gdb_for_gdbstub() # Test breakpoint cmd = '-break-insert --source test_app_main.c --function app_main --label label_1' diff --git a/tools/test_apps/system/panic/main/include/test_panic.h b/tools/test_apps/system/panic/main/include/test_panic.h index 5e96b2000c2..6454d9db824 100644 --- a/tools/test_apps/system/panic/main/include/test_panic.h +++ b/tools/test_apps/system/panic/main/include/test_panic.h @@ -61,6 +61,8 @@ void test_assert_cache_disabled(void); void test_illegal_access(void); +void test_capture_dram(void); + #ifdef __cplusplus } #endif diff --git a/tools/test_apps/system/panic/main/test_app_main.c b/tools/test_apps/system/panic/main/test_app_main.c index 1a387f0018b..d426ebc6a7f 100644 --- a/tools/test_apps/system/panic/main/test_app_main.c +++ b/tools/test_apps/system/panic/main/test_app_main.c @@ -98,6 +98,9 @@ void app_main(void) #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY HANDLE_TEST(test_name, test_panic_extram_stack); #endif +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM + HANDLE_TEST(test_name, test_capture_dram); +#endif #if !CONFIG_FREERTOS_UNICORE HANDLE_TEST(test_name, test_task_wdt_cpu1); #endif diff --git a/tools/test_apps/system/panic/main/test_panic.c b/tools/test_apps/system/panic/main/test_panic.c index eab2c082ee8..2e1e47aca33 100644 --- a/tools/test_apps/system/panic/main/test_panic.c +++ b/tools/test_apps/system/panic/main/test_panic.c @@ -252,3 +252,30 @@ void test_illegal_access(void) printf("[2] val: %d at %p\n", val, (void *)addr); } #endif + +#if CONFIG_ESP_COREDUMP_CAPTURE_DRAM +int g_data_var = 42; +int g_bss_var; +char *g_heap_ptr; +COREDUMP_IRAM_DATA_ATTR uint32_t g_cd_iram = 0x4242; +COREDUMP_DRAM_ATTR uint32_t g_cd_dram = 0x4343; +#if SOC_RTC_MEM_SUPPORTED +COREDUMP_RTC_FAST_ATTR uint32_t g_rtc_fast_var; +COREDUMP_RTC_DATA_ATTR uint32_t g_rtc_data_var = 0x55A9; +#endif + +void test_capture_dram(void) +{ + g_data_var++; + g_bss_var = 55; + g_heap_ptr = strdup("Coredump Test"); + assert(g_heap_ptr); + g_cd_iram++; + g_cd_dram++; +#if SOC_RTC_MEM_SUPPORTED + g_rtc_fast_var = 0xAABBCCDD; + g_rtc_data_var++; +#endif + assert(0); +} +#endif diff --git a/tools/test_apps/system/panic/partitions_capture_dram.csv b/tools/test_apps/system/panic/partitions_capture_dram.csv new file mode 100644 index 00000000000..3d69de38757 --- /dev/null +++ b/tools/test_apps/system/panic/partitions_capture_dram.csv @@ -0,0 +1,6 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs,data,nvs,0x9000,24K, +phy_init,data,phy,0xf000,4K, +factory,app,factory,0x10000,1M, +coredump,data,coredump,0x110000,128K, diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 90154a40d2e..bb0d4b8f294 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -89,6 +89,8 @@ pytest.param('panic', marks=TARGETS_RISCV_DUAL_CORE), ] +CONFIG_CAPTURE_DRAM = [pytest.param('coredump_flash_capture_dram', marks=TARGETS_ALL)] + # Panic abort information will start with this string. PANIC_ABORT_PREFIX = 'Panic reason: ' @@ -101,7 +103,7 @@ def common_test(dut: PanicTestDut, config: str, expected_backtrace: Optional[Lis expected_coredump: Optional[List[Union[str, re.Pattern]]] = None) -> None: if 'gdbstub' in config: dut.expect_exact('Entering gdb stub now.') - dut.start_gdb() + dut.start_gdb_for_gdbstub() frames = dut.gdb_backtrace() if expected_backtrace is not None: dut.verify_gdb_backtrace(frames, expected_backtrace) @@ -861,7 +863,7 @@ def test_gdbstub_coredump(dut: PanicTestDut) -> None: dut.process_coredump_uart() dut.expect_exact('Entering gdb stub now.') - dut.start_gdb() + dut.start_gdb_for_gdbstub() frames = dut.gdb_backtrace() dut.verify_gdb_backtrace(frames, get_default_backtrace(test_func_name)) dut.revert_log_level() @@ -913,3 +915,25 @@ def test_illegal_access(dut: PanicTestDut, config: str, test_func_name: str) -> dut.expect_backtrace() dut.expect_elf_sha256() dut.expect_none('Guru Meditation') + + +@pytest.mark.parametrize('config', CONFIG_CAPTURE_DRAM, indirect=True) +@pytest.mark.generic +def test_capture_dram(dut: PanicTestDut, config: str, test_func_name: str) -> None: + dut.run_test_func(test_func_name) + + dut.expect_elf_sha256() + dut.expect_none(['Guru Meditation', 'Re-entered core dump']) + + core_elf_file = dut.process_coredump_flash() + dut.start_gdb_for_coredump(core_elf_file) + + assert dut.gdb_data_eval_expr('g_data_var') == '43' + assert dut.gdb_data_eval_expr('g_bss_var') == '55' + assert re.search(r'0x[0-9a-fA-F]+ "Coredump Test"', dut.gdb_data_eval_expr('g_heap_ptr')) + assert int(dut.gdb_data_eval_expr('g_cd_iram')) == 0x4243 + assert int(dut.gdb_data_eval_expr('g_cd_dram')) == 0x4344 + + if dut.target != 'esp32c2': + assert int(dut.gdb_data_eval_expr('g_rtc_data_var')) == 0x55AA + assert int(dut.gdb_data_eval_expr('g_rtc_fast_var')) == 0xAABBCCDD diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram new file mode 100644 index 00000000000..03f5a738059 --- /dev/null +++ b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram @@ -0,0 +1,6 @@ +CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y +CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y +CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y +CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_capture_dram.csv" diff --git a/tools/test_apps/system/panic/test_panic_util/panic_dut.py b/tools/test_apps/system/panic/test_panic_util/panic_dut.py index d7eae8d3060..205035e5b03 100644 --- a/tools/test_apps/system/panic/test_panic_util/panic_dut.py +++ b/tools/test_apps/system/panic/test_panic_util/panic_dut.py @@ -120,15 +120,15 @@ def expect_coredump(self, output_file_name: str, patterns: List[Union[str, re.Pa for pattern in patterns: if isinstance(pattern, str): position = coredump.find(pattern) - assert position != -1, f"'{pattern}' not found in the coredump output" + assert position != -1, f"'{pattern}' not in the coredump output" elif isinstance(pattern, re.Pattern): match = pattern.findall(coredump) - assert match, f"'{pattern.pattern}' not found in the coredump output" + assert match, f"'{pattern.pattern}' not in the coredump output" else: raise ValueError(f'Unsupported input type: {type(pattern).__name__}') def _call_espcoredump( - self, extra_args: List[str], coredump_file_name: str, output_file_name: str + self, extra_args: List[str], output_file_name: str ) -> None: # no "with" here, since we need the file to be open for later inspection by the test case if not self.coredump_output: @@ -142,14 +142,13 @@ def _call_espcoredump( espcoredump_script, '-b115200', 'info_corefile', - '--core', - coredump_file_name, ] espcoredump_args += extra_args espcoredump_args.append(self.app.elf_file) logging.info('Running %s', ' '.join(espcoredump_args)) logging.info('espcoredump output is written to %s', self.coredump_output.name) + self.serial.close() subprocess.check_call(espcoredump_args, stdout=self.coredump_output) self.coredump_output.flush() self.coredump_output.seek(0) @@ -165,33 +164,31 @@ def process_coredump_uart(self, expected: Optional[List[Union[str, re.Pattern]]] output_file_name = os.path.join(self.logdir, 'coredump_uart_result.txt') self._call_espcoredump( - ['--core-format', 'b64'], coredump_file.name, output_file_name + ['--core-format', 'b64', '--core', coredump_file.name], output_file_name ) if expected: self.expect_coredump(output_file_name, expected) - def process_coredump_flash(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> None: - """Extract the core dump from flash, run espcoredump on it""" + def process_coredump_flash(self, expected: Optional[List[Union[str, re.Pattern]]] = None) -> Any: coredump_file_name = os.path.join(self.logdir, 'coredump_data.bin') logging.info('Writing flash binary core dump to %s', coredump_file_name) - self.serial.dump_flash(partition='coredump', output=coredump_file_name) - output_file_name = os.path.join(self.logdir, 'coredump_flash_result.txt') self._call_espcoredump( - ['--core-format', 'raw'], coredump_file_name, output_file_name + ['--core-format', 'raw', '--save-core', coredump_file_name], output_file_name ) if expected: self.expect_coredump(output_file_name, expected) + return coredump_file_name def gdb_write(self, command: str) -> Any: """ Wrapper to write to gdb with a longer timeout, as test runner host can be slow sometimes """ - assert self.gdbmi, 'This function should be called only after start_gdb' + assert self.gdbmi, 'This function should be called only after run_gdb' return self.gdbmi.write(command, timeout_sec=10) - def start_gdb(self) -> None: + def run_gdb(self) -> None: """ Runs GDB and connects it to the "serial" port of the DUT. After this, the DUT expect methods can no longer be used to capture output. @@ -262,6 +259,11 @@ def start_gdb(self) -> None: # Load the ELF file self.gdb_write('-file-exec-and-symbols {}'.format(self.app.elf_file)) + # Prepare gdb for the gdb stub + def start_gdb_for_gdbstub(self) -> None: + + self.run_gdb() + # Connect GDB to UART self.serial.close() logging.info('Connecting to GDB Stub...') @@ -290,7 +292,14 @@ def start_gdb(self) -> None: logging.info('Stopped in {func} at {addr} ({file}:{line})'.format(**frame)) # Drain remaining responses - self.gdbmi.get_gdb_response(raise_error_on_timeout=False) + if self.gdbmi: + self.gdbmi.get_gdb_response(raise_error_on_timeout=False) + + # Prepare gdb to debug coredump file + def start_gdb_for_coredump(self, elf_file: str) -> None: + + self.run_gdb() + self.gdb_write('core {}'.format(elf_file)) def gdb_backtrace(self) -> Any: """ @@ -302,6 +311,10 @@ def gdb_backtrace(self) -> Any: responses = self.gdb_write('-stack-list-frames') return self.find_gdb_response('done', 'result', responses)['payload']['stack'] + def gdb_data_eval_expr(self, expr: str) -> Any: + responses = self.gdb_write('-data-evaluate-expression "%s"' % expr) + return self.find_gdb_response('done', 'result', responses)['payload']['value'] + @staticmethod def verify_gdb_backtrace( gdb_backtrace: List[Any], expected_functions_list: List[Any] From 52b36a60f449e85ae8d4add308582470ebd66f1e Mon Sep 17 00:00:00 2001 From: Wang Fang Date: Mon, 22 Apr 2024 10:13:24 +0800 Subject: [PATCH 128/548] Update CN translation for coredump --- docs/en/api-guides/core_dump.rst | 18 ++++++++++-------- docs/zh_CN/api-guides/core_dump.rst | 18 +++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/en/api-guides/core_dump.rst b/docs/en/api-guides/core_dump.rst index 8bc5799b577..065101d6bf0 100644 --- a/docs/en/api-guides/core_dump.rst +++ b/docs/en/api-guides/core_dump.rst @@ -59,22 +59,24 @@ Setting this option to 0 bytes will cause the core dump routines to run from the If a separate stack is used, the recommended stack size should be larger than 1300 bytes to ensure that the core dump routines themselves do not cause a stack overflow. -Core Dump Memory Regions -^^^^^^^^^^^^^^^^^^^^^^^^ +.. only:: not esp32c5 -By default, core dumps typically save CPU registers, tasks data and summary of the panic reason. When the :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` option is selected, ``.bss`` and ``.data`` sections and ``heap`` data will also be part of the dump. + Core Dump Memory Regions + ^^^^^^^^^^^^^^^^^^^^^^^^ -For a better debugging experience, it is recommended to dump these sections. However, this will result in a larger coredump file. The required additional storage space may vary based on the amount of DRAM the application uses. + By default, core dumps typically save CPU registers, tasks data and summary of the panic reason. When the :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` option is selected, ``.bss`` and ``.data`` sections and ``heap`` data will also be part of the dump. -.. note:: + For a better debugging experience, it is recommended to dump these sections. However, this will result in a larger coredump file. The required additional storage space may vary based on the amount of DRAM the application uses. .. only:: SOC_SPIRAM_SUPPORTED - Apart from the crashed task's TCB and stack, data located in the external RAM will not be stored in the core dump file, this include variables defined with ``EXT_RAM_BSS_ATTR`` or ``EXT_RAM_NOINIT_ATTR`` attributes, as well as any data stored in the ``extram_bss`` section. + .. note:: -.. note:: + Apart from the crashed task's TCB and stack, data located in the external RAM will not be stored in the core dump file, this include variables defined with ``EXT_RAM_BSS_ATTR`` or ``EXT_RAM_NOINIT_ATTR`` attributes, as well as any data stored in the ``extram_bss`` section. + + .. note:: - This feature is only enabled when using the ELF file format. + This feature is only enabled when using the ELF file format. Core Dump to Flash ------------------ diff --git a/docs/zh_CN/api-guides/core_dump.rst b/docs/zh_CN/api-guides/core_dump.rst index 6844072c573..27505a32707 100644 --- a/docs/zh_CN/api-guides/core_dump.rst +++ b/docs/zh_CN/api-guides/core_dump.rst @@ -58,24 +58,24 @@ ELF 格式具备扩展特性,支持在发生崩溃时保存更多关于错误 如果使用了独立的栈,建议栈大小应大于 1300 字节,确保核心转储例程本身不会导致栈溢出。 +.. only:: not esp32c5 -Core Dump Memory Regions -^^^^^^^^^^^^^^^^^^^^^^^^ + 核心转储内存区域 + ^^^^^^^^^^^^^^^^ -By default, core dumps typically save CPU registers, tasks data and summary of the panic reason. When the :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` option is selected, ``.bss`` and ``.data`` sections and ``heap`` data will also be part of the dump. + 核心转储默认保存 CPU 寄存器、任务数据和崩溃原因。选择 :ref:`CONFIG_ESP_COREDUMP_CAPTURE_DRAM` 选项后,``.bss`` 段和 ``.data`` 段以及 ``heap`` 数据也将保存到转储中。 -For a better debugging experience, it is recommended to dump these sections. However, this will result in a larger coredump file. The required additional storage space may vary based on the amount of DRAM the application uses. - -.. note:: + 推荐将上面提到的几个数据段都保存到核心转储中,以方便调试。但这会导致核心转储文件变大,具体所需的额外存储空间取决于应用程序使用的 DRAM 大小。 .. only:: SOC_SPIRAM_SUPPORTED - Apart from the crashed task's TCB and stack, data located in the external RAM will not be stored in the core dump file, this include variables defined with ``EXT_RAM_BSS_ATTR`` or ``EXT_RAM_NOINIT_ATTR`` attributes, as well as any data stored in the ``extram_bss`` section. + .. note:: -.. note:: + 除了崩溃任务的 TCB 和栈外,位于外部 RAM 中的数据不会保存到核心转储文件中,包括使用 ``EXT_RAM_BSS_ATTR`` 或 ``EXT_RAM_NOINIT_ATTR`` 属性定义的变量,以及存储在 ``extram_bss`` 段中的任何数据。 - This feature is only enabled when using the ELF file format. + .. note:: + 该功能仅在使用 ELF 文件格式时可用。 将核心转储保存到 flash ----------------------- From 0f96e5114668f2a8e86f40c47fe5a6888f1ec1cf Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 6 May 2024 15:41:25 +0200 Subject: [PATCH 129/548] ci(coredump): fix capture dram tests --- components/espcoredump/src/core_dump_elf.c | 2 +- tools/test_apps/system/panic/CMakeLists.txt | 2 +- tools/test_apps/system/panic/pytest_panic.py | 11 ++++++++++- .../panic/sdkconfig.ci.coredump_flash_capture_dram | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index be99de24966..183962908e5 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -482,7 +482,7 @@ static int elf_write_tasks_data(core_dump_elf_t *self) #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM /* Only crashed task data will be saved here. The other task's data will be automatically saved within the sections */ - if (esp_core_dump_get_current_task_handle() != task_iter.pxTaskHandle) + if (esp_core_dump_get_current_task_handle() == task_iter.pxTaskHandle) #endif { ret = elf_save_task(self, &task_hdr); diff --git a/tools/test_apps/system/panic/CMakeLists.txt b/tools/test_apps/system/panic/CMakeLists.txt index 5d922b1b13e..e9db4327f57 100644 --- a/tools/test_apps/system/panic/CMakeLists.txt +++ b/tools/test_apps/system/panic/CMakeLists.txt @@ -17,7 +17,7 @@ if(CONFIG_TEST_MEMPROT) endif() endif() -if(NOT CONFIG_TEST_MEMPROT) +if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM) # Enable UBSAN checks # # shift-base sanitizer is disabled due to the following pattern found in register header files: diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index bb0d4b8f294..28203b099fc 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -921,10 +921,19 @@ def test_illegal_access(dut: PanicTestDut, config: str, test_func_name: str) -> @pytest.mark.generic def test_capture_dram(dut: PanicTestDut, config: str, test_func_name: str) -> None: dut.run_test_func(test_func_name) - + regex_pattern = rb'assert failed:[\s\w()]*?\s[.\w/]*\.(?:c|cpp|h|hpp):\d.*$' + dut.expect(re.compile(regex_pattern, re.MULTILINE)) + if dut.is_xtensa: + dut.expect_backtrace() + else: + dut.expect_stack_dump() dut.expect_elf_sha256() dut.expect_none(['Guru Meditation', 'Re-entered core dump']) + dut.expect_exact('Save core dump to flash...') + dut.expect_exact('Core dump has been saved to flash.') + dut.expect('Rebooting...') + core_elf_file = dut.process_coredump_flash() dut.start_gdb_for_coredump(core_elf_file) diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram index 03f5a738059..d8e5231dc19 100644 --- a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram +++ b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_capture_dram @@ -4,3 +4,4 @@ CONFIG_ESP_COREDUMP_CHECKSUM_SHA256=y CONFIG_ESP_COREDUMP_CAPTURE_DRAM=y CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_capture_dram.csv" +CONFIG_LOG_DEFAULT_LEVEL_INFO=y From 75faae29a8f62ea030e80a3fe6e49ac1107f942f Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Thu, 16 May 2024 13:36:22 +0530 Subject: [PATCH 130/548] feat(cjson): update submodule to v1.7.18 Changelog: https://github.com/DaveGamble/cJSON/releases/tag/v1.7.18 --- .gitmodules | 4 ++-- components/json/cJSON | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 19beee5d3b6..f3060884937 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,12 +49,12 @@ [submodule "components/json/cJSON"] path = components/json/cJSON url = ../../DaveGamble/cJSON.git - sbom-version = 1.7.17 + sbom-version = 1.7.18 sbom-cpe = cpe:2.3:a:cjson_project:cjson:{}:*:*:*:*:*:*:* sbom-supplier = Person: Dave Gamble sbom-url = https://github.com/DaveGamble/cJSON sbom-description = Ultralightweight JSON parser in ANSI C - sbom-hash = 87d8f0961a01bf09bef98ff89bae9fdec42181ee + sbom-hash = acc76239bee01d8e9c858ae2cab296704e52d916 [submodule "components/mbedtls/mbedtls"] path = components/mbedtls/mbedtls diff --git a/components/json/cJSON b/components/json/cJSON index 87d8f0961a0..acc76239bee 160000 --- a/components/json/cJSON +++ b/components/json/cJSON @@ -1 +1 @@ -Subproject commit 87d8f0961a01bf09bef98ff89bae9fdec42181ee +Subproject commit acc76239bee01d8e9c858ae2cab296704e52d916 From 6eba7a536a200377b1428c7d44505467a64c9b5b Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Tue, 30 Apr 2024 10:37:42 +0800 Subject: [PATCH 131/548] feat(riscv): add support for PIE coprocessor and HWLP feature FreeRTOS tasks may now freely use the PIE coprocessor and HWLP feature. Just like the FPU, usiing these coprocessors result in the task being pinned to the core it is currently running on. --- .../FreeRTOS-Kernel/portable/riscv/port.c | 35 +- .../FreeRTOS-Kernel/portable/riscv/portasm.S | 446 +++++++++++++----- .../freertos/port/test_fpu_in_task.c | 4 +- .../test_apps/freertos/port/test_hwlp.c | 151 ++++++ .../freertos/port/test_pie_in_task.c | 253 ++++++++++ .../freertos/port/test_pie_watermark.c | 86 ++++ components/riscv/include/riscv/csr_hwlp.h | 28 ++ components/riscv/include/riscv/csr_pie.h | 21 + .../riscv/include/riscv/rvruntime-frames.h | 106 ++++- components/riscv/vectors.S | 35 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 10 +- components/soc/esp32p4/include/soc/soc_caps.h | 4 +- 12 files changed, 1027 insertions(+), 152 deletions(-) create mode 100644 components/freertos/test_apps/freertos/port/test_hwlp.c create mode 100644 components/freertos/test_apps/freertos/port/test_pie_in_task.c create mode 100644 components/freertos/test_apps/freertos/port/test_pie_watermark.c create mode 100644 components/riscv/include/riscv/csr_hwlp.h create mode 100644 components/riscv/include/riscv/csr_pie.h diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 18aa79db670..7406cdbccb1 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -230,7 +230,7 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters) { - __asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (inital) frame + __asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (initial) frame extern void __attribute__((noreturn)) panic_abort(const char *details); static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0"; pxCode(pvParameters); @@ -356,7 +356,7 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC HIGH ADDRESS |---------------------------| <- pxTopOfStack on entry | TLS Variables | - | ------------------------- | <- Start of useable stack + | ------------------------- | <- Start of usable stack | Starting stack frame | | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP) | | | @@ -374,7 +374,7 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC | Coproc. Save Area | <- RvCoprocSaveArea | ------------------------- | | TLS Variables | - | ------------------------- | <- Start of useable stack + | ------------------------- | <- Start of usable stack | Starting stack frame | | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP) | | | @@ -430,7 +430,7 @@ BaseType_t xPortInIsrContext(void) /* Disable interrupts to fetch the coreID atomically */ irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); - /* Return the interrupt nexting counter for this core */ + /* Return the interrupt nesting counter for this core */ ret = port_uxInterruptNesting[xPortGetCoreID()]; /* Restore interrupts */ @@ -445,7 +445,7 @@ BaseType_t xPortInIsrContext(void) BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) { - /* Return the interrupt nexting counter for this core */ + /* Return the interrupt nesting counter for this core */ return port_uxInterruptNesting[xPortGetCoreID()]; } @@ -536,7 +536,7 @@ BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TY void __attribute__((optimize("-O3"))) vPortExitCriticalMultiCore(portMUX_TYPE *mux) { /* This function may be called in a nested manner. Therefore, we only need - * to reenable interrupts if this is the last call to exit the critical. We + * to re-enable interrupts if this is the last call to exit the critical. We * can use the nesting count to determine whether this is the last exit call. */ spinlock_release(mux); @@ -787,9 +787,14 @@ RvCoprocSaveArea* pxPortGetCoprocArea(StaticTask_t* task, bool allocate, int cop /* Check if coprocessor area is allocated */ if (allocate && sa->sa_coprocs[coproc] == NULL) { const uint32_t coproc_sa_sizes[] = { - RV_COPROC0_SIZE, RV_COPROC1_SIZE + RV_COPROC0_SIZE, RV_COPROC1_SIZE, RV_COPROC2_SIZE }; - /* The allocator points to a usable part of the stack, use it for the coprocessor */ + const uint32_t coproc_sa_align[] = { + RV_COPROC0_ALIGN, RV_COPROC1_ALIGN, RV_COPROC2_ALIGN + }; + /* The allocator points to a usable part of the stack, use it for the coprocessor. + * Align it up to the coprocessor save area requirement */ + sa->sa_allocator = (sa->sa_allocator + coproc_sa_align[coproc] - 1) & ~(coproc_sa_align[coproc] - 1); sa->sa_coprocs[coproc] = (void*) (sa->sa_allocator); sa->sa_allocator += coproc_sa_sizes[coproc]; /* Update the lowest address of the stack to prevent FreeRTOS performing overflow/watermark checks on the coprocessors contexts */ @@ -800,9 +805,9 @@ RvCoprocSaveArea* pxPortGetCoprocArea(StaticTask_t* task, bool allocate, int cop if (task_sp <= task->pxDummy6) { /* In theory we need to call vApplicationStackOverflowHook to trigger the stack overflow callback, * but in practice, since we are already in an exception handler, this won't work, so let's manually - * trigger an exception with the previous FPU owner's TCB */ + * trigger an exception with the previous coprocessor owner's TCB */ g_panic_abort = true; - g_panic_abort_details = (char *) "ERROR: Stack overflow while saving FPU context!\n"; + g_panic_abort_details = (char *) "ERROR: Stack overflow while saving coprocessor context!\n"; xt_unhandled_exception(task_sp); } } @@ -821,7 +826,8 @@ RvCoprocSaveArea* pxPortGetCoprocArea(StaticTask_t* task, bool allocate, int cop * @param coreid Current core * @param coproc Coprocessor to save context of * - * @returns Coprocessor former owner's save area + * @returns Coprocessor former owner's save are, can be NULL is there was no owner yet, can be -1 if + * the former owner is the same as the new owner. */ RvCoprocSaveArea* pxPortUpdateCoprocOwner(int coreid, int coproc, StaticTask_t* owner) { @@ -830,8 +836,11 @@ RvCoprocSaveArea* pxPortUpdateCoprocOwner(int coreid, int coproc, StaticTask_t* StaticTask_t** owner_addr = &port_uxCoprocOwner[ coreid ][ coproc ]; /* Atomically exchange former owner with the new one */ StaticTask_t* former = Atomic_SwapPointers_p32((void**) owner_addr, owner); - /* Get the save area of former owner */ - if (former != NULL) { + /* Get the save area of former owner. small optimization here, if the former owner is the new owner, + * return -1. This will simplify the assembly code while making it faster. */ + if (former == owner) { + sa = (void*) -1; + } else if (former != NULL) { /* Allocate coprocessor memory if not available yet */ sa = pxPortGetCoprocArea(former, true, coproc); } diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index 6a99e7ebb9d..067c846c3e1 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -8,6 +8,8 @@ #include "freertos/FreeRTOSConfig.h" #include "soc/soc_caps.h" #include "riscv/rvruntime-frames.h" +#include "riscv/csr_hwlp.h" +#include "riscv/csr_pie.h" .extern pxCurrentTCBs @@ -33,6 +35,257 @@ #if SOC_CPU_COPROC_NUM > 0 +/** + * @brief Macro to generate a routine that saves a coprocessor's registers in the previous owner's TCB dedicated save area. + * This routine aborts if the coprocessor is used from an ISR, since this is not allowed in ESP-IDF. + * However it is allowed to use these coprocessors in the init process, so no error will be triggered if the + * current TCB is NULL. + * + * @param name The name of the coprocessor, this will be used to generate the label, so it must not contain special characters + * @param coproc_idx Index of the coprocessor in the coprocessor save area, this value can be found in rvruntime definition + * @param enable_coproc Macro that takes a scratch register as a parameter and enables the coprocessor. + * @param save_coproc_regs Macro that takes a frame as a parameter and saves all the coprocessors' registers in that frame. + * @param restore_coproc_regs Macro that takes a frame as a parameter and restores all the coprocessors' registers from that. + * + * Note: macros given as parameters can freely use temporary registers + */ +.macro generate_coprocessor_routine name, coproc_idx, enable_coproc, save_coproc_regs, restore_coproc_regs + + .global rtos_save_\name\()_coproc + .type rtos_save_\name\()_coproc, @function +rtos_save_\name\()_coproc: + /* If we are in an interrupt context, we have to abort. We don't allow using the coprocessors from ISR */ +#if ( configNUM_CORES > 1 ) + csrr a2, mhartid /* a2 = coreID */ + slli a2, a2, 2 /* a2 = coreID * 4 */ + la a1, port_uxInterruptNesting /* a1 = &port_uxInterruptNesting */ + add a1, a1, a2 /* a1 = &port_uxInterruptNesting[coreID] */ + lw a1, 0(a1) /* a1 = port_uxInterruptNesting[coreID] */ +#else /* ( configNUM_CORES <= 1 ) */ + lw a1, (port_uxInterruptNesting) /* a1 = port_uxInterruptNesting */ +#endif /* ( configNUM_CORES > 1 ) */ + /* SP still contains the RvExcFrame address */ + mv a0, sp + bnez a1, vPortCoprocUsedInISR + /* Enable the coprocessor needed by the current task */ + \enable_coproc a1 + mv s0, ra + call rtos_current_tcb + /* If the current TCB is NULL, the coprocessor is used during initialization, even before + * the scheduler started. Consider this a valid usage, it will be disabled as soon as the + * scheduler is started anyway */ + beqz a0, rtos_save_\name\()_coproc_norestore + mv s1, a0 /* s1 = pxCurrentTCBs */ + /* Prepare parameters of pxPortUpdateCoprocOwner */ + mv a2, a0 + li a1, \coproc_idx + csrr a0, mhartid + call pxPortUpdateCoprocOwner + /* If the save area is NULL, no need to save context */ + beqz a0, rtos_save_\name\()_coproc_nosave + /* If the former owner is the current task (new owner), the return value is -1, we can skip restoring the + * coprocessor context and return directly */ + li a1, -1 + beq a0, a1, rtos_save_\name\()_coproc_norestore + /* Save the coprocessor context in the structure */ + lw a0, RV_COPROC_SA+\coproc_idx*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[coproc_idx] */ + \save_coproc_regs a0 +rtos_save_\name\()_coproc_nosave: +#if ( configNUM_CORES > 1 ) + /* Pin current task to current core */ + mv a0, s1 + csrr a1, mhartid + call vPortTaskPinToCore +#endif /* configNUM_CORES > 1 */ + /* Check if we have to restore a previous context from the current TCB */ + mv a0, s1 + /* Do not allocate memory for the coprocessor yet, delay this until another task wants to use it. + * This guarantees that if a stack overflow occurs when allocating the coprocessor context on the stack, + * the current task context is flushed and updated in the TCB, generating a correct backtrace + * from the panic handler. */ + li a1, 0 + li a2, \coproc_idx + call pxPortGetCoprocArea + /* Get the enable flags from the coprocessor save area */ + lw a1, RV_COPROC_ENABLE(a0) + /* To avoid having branches below, set the coprocessor enable flag now */ + ori a2, a1, 1 << \coproc_idx + sw a2, RV_COPROC_ENABLE(a0) + /* Check if the former coprocessor enable bit was set */ + andi a2, a1, 1 << \coproc_idx + beqz a2, rtos_save_\name\()_coproc_norestore + /* Enable bit was set, restore the coprocessor context */ + lw a0, RV_COPROC_SA+\coproc_idx*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[\coproc_idx] */ + \restore_coproc_regs a0 +rtos_save_\name\()_coproc_norestore: + /* Return from routine via s0, instead of ra */ + jr s0 + .size rtos_save_\name\()_coproc, .-rtos_save_\name\()_coproc + +.endm + + + +#if SOC_CPU_HAS_HWLOOP + +/** + * @brief Macros to enable and disable the hardware loop feature on the current core + */ +.macro hwlp_enable scratch_reg=a0 + li \scratch_reg, 1 + csrw CSR_HWLP_STATE_REG, \scratch_reg +.endm + +/** + * @brief Disable HW Loop CPU feature while returning the former status in the given register + */ +.macro hwlp_disable reg + csrrw \reg, CSR_HWLP_STATE_REG, zero + /* Only keep the lowest two bits */ + andi \reg, \reg, 0b11 + /* If register is 0, HWLP was off */ + beqz \reg, 1f + /* It was ON, return the enable bit in \reg */ + li \reg, 1 << HWLP_COPROC_IDX +1: +.endm + +/** + * @brief Macros to save and restore the hardware loop registers to and from the given frame + */ +.macro hwlp_save_regs frame=sp + csrr a1, CSR_LOOP0_START_ADDR + sw a1, RV_HWLOOP_START0(\frame) + csrr a1, CSR_LOOP0_END_ADDR + sw a1, RV_HWLOOP_END0(\frame) + csrr a1, CSR_LOOP0_COUNT + sw a1, RV_HWLOOP_COUNT0(\frame) + csrr a1, CSR_LOOP1_START_ADDR + sw a1, RV_HWLOOP_START1(\frame) + csrr a1, CSR_LOOP1_END_ADDR + sw a1, RV_HWLOOP_END1(\frame) + csrr a1, CSR_LOOP1_COUNT + sw a1, RV_HWLOOP_COUNT1(\frame) +.endm + +.macro hwlp_restore_regs frame=sp + lw a1, RV_HWLOOP_START0(\frame) + csrw CSR_LOOP0_START_ADDR, a1 + lw a1, RV_HWLOOP_END0(\frame) + csrw CSR_LOOP0_END_ADDR, a1 + lw a1, RV_HWLOOP_COUNT0(\frame) + csrw CSR_LOOP0_COUNT, a1 + lw a1, RV_HWLOOP_START1(\frame) + csrw CSR_LOOP1_START_ADDR, a1 + lw a1, RV_HWLOOP_END1(\frame) + csrw CSR_LOOP1_END_ADDR, a1 + lw a1, RV_HWLOOP_COUNT1(\frame) + csrw CSR_LOOP1_COUNT, a1 +.endm + + +generate_coprocessor_routine hwlp, HWLP_COPROC_IDX, hwlp_enable, hwlp_save_regs, hwlp_restore_regs + +#endif /* SOC_CPU_HAS_HWLOOP */ + + +#if SOC_CPU_HAS_PIE + +/** + * @brief Macros to enable and disable the hardware loop feature on the current core + */ +.macro pie_enable scratch_reg=a0 + li \scratch_reg, 1 + csrw CSR_PIE_STATE_REG, \scratch_reg +.endm + +/** + * @brief Disable HW Loop CPU feature while returning the former status in the given register + */ +.macro pie_disable reg + csrrw \reg, CSR_PIE_STATE_REG, zero + /* Only keep the lowest two bits, if register is 0, PIE was off */ + andi \reg, \reg, 0b11 + beqz \reg, 1f + /* It was ON, return the enable bit in \reg */ + li \reg, 1 << PIE_COPROC_IDX +1: +.endm + +/** + * @brief Macros to save and restore the hardware loop registers to and from the given frame + */ +.macro pie_save_regs frame=a0 + /* Save the 128-bit Q registers from the frame memory and then frame += 16 */ + esp.vst.128.ip q0, \frame, 16 + esp.vst.128.ip q1, \frame, 16 + esp.vst.128.ip q2, \frame, 16 + esp.vst.128.ip q4, \frame, 16 + esp.vst.128.ip q5, \frame, 16 + esp.vst.128.ip q6, \frame, 16 + esp.vst.128.ip q7, \frame, 16 + /* Save the QACC_H and QACC_L registers, each being 256 bits big */ + esp.st.qacc.l.l.128.ip \frame, 16 + esp.st.qacc.l.h.128.ip \frame, 16 + esp.st.qacc.h.l.128.ip \frame, 16 + esp.st.qacc.h.h.128.ip \frame, 16 + /* UA_STATE register (128 bits) */ + esp.st.ua.state.ip \frame, 16 + /* XACC register (40 bits) */ + esp.st.u.xacc.ip \frame, 8 + /* The following registers will be stored in the same word */ + /* SAR register (6 bits) */ + esp.movx.r.sar a1 + slli a2, a1, 8 + /* SAR_BYTES register (4 bits) */ + esp.movx.r.sar.bytes a1 + slli a1, a1, 4 + or a2, a2, a1 + /* FFT_BIT_WIDTH register (4 bits) */ + esp.movx.r.fft.bit.width a1 + or a2, a2, a1 + sw a2, (\frame) +.endm + + +.macro pie_restore_regs frame=a0 + /* Restore the 128-bit Q registers from the frame memory and then frame += 16 */ + esp.vld.128.ip q0, \frame, 16 + esp.vld.128.ip q1, \frame, 16 + esp.vld.128.ip q2, \frame, 16 + esp.vld.128.ip q4, \frame, 16 + esp.vld.128.ip q5, \frame, 16 + esp.vld.128.ip q6, \frame, 16 + esp.vld.128.ip q7, \frame, 16 + /* Save the QACC_H and QACC_L registers, each being 256 bits big */ + esp.ld.qacc.l.l.128.ip \frame, 16 + esp.ld.qacc.l.h.128.ip \frame, 16 + esp.ld.qacc.h.l.128.ip \frame, 16 + esp.ld.qacc.h.h.128.ip \frame, 16 + /* UA_STATE register (128 bits) */ + esp.ld.ua.state.ip \frame, 16 + /* XACC register (40 bits) */ + esp.ld.xacc.ip \frame, 8 + /* The following registers are stored in the same word */ + lw a2, (\frame) + /* FFT_BIT_WIDTH register (4 bits) */ + andi a1, a2, 0xf + esp.movx.w.sar a1 + /* SAR_BYTES register (4 bits) */ + srli a2, a2, 4 + andi a1, a2, 0xf + esp.movx.w.sar.bytes a1 + /* SAR register (6 bits) */ + srli a2, a2, 4 + andi a1, a2, 0x3f + esp.movx.w.fft.bit.width a1 +.endm + +generate_coprocessor_routine pie, PIE_COPROC_IDX, pie_enable, pie_save_regs, pie_restore_regs + +#endif /* SOC_CPU_HAS_PIE */ + + #if SOC_CPU_HAS_FPU /* Bit to set in mstatus to enable the FPU */ @@ -40,7 +293,7 @@ /* Bit to clear in mstatus to disable the FPU */ #define CSR_MSTATUS_FPU_DISABLE (3 << 13) -.macro save_fpu_regs frame=sp +.macro fpu_save_regs frame=sp fsw ft0, RV_FPU_FT0(\frame) fsw ft1, RV_FPU_FT1(\frame) fsw ft2, RV_FPU_FT2(\frame) @@ -73,9 +326,11 @@ fsw ft9, RV_FPU_FT9 (\frame) fsw ft10, RV_FPU_FT10(\frame) fsw ft11, RV_FPU_FT11(\frame) + csrr a1, fcsr + sw a1, RV_FPU_FCSR(\frame) .endm -.macro restore_fpu_regs frame=sp +.macro fpu_restore_regs frame=sp flw ft0, RV_FPU_FT0(\frame) flw ft1, RV_FPU_FT1(\frame) flw ft2, RV_FPU_FT2(\frame) @@ -108,6 +363,8 @@ flw ft9, RV_FPU_FT9(\frame) flw ft10, RV_FPU_FT10(\frame) flw ft11, RV_FPU_FT11(\frame) + lw a1, RV_FPU_FCSR(\frame) + csrw fcsr, a1 .endm @@ -125,98 +382,17 @@ .macro fpu_enable reg - li \reg, CSR_MSTATUS_FPU_ENABLE + li \reg, CSR_MSTATUS_FPU_ENABLE csrs mstatus, \reg .endm .macro fpu_disable reg - li \reg, CSR_MSTATUS_FPU_DISABLE + li \reg, CSR_MSTATUS_FPU_DISABLE csrc mstatus, \reg .endm - .global vPortTaskPinToCore - .global vPortCoprocUsedInISR - .global pxPortUpdateCoprocOwner - -/** - * @brief Save the current FPU context in the FPU owner's save area - * - * @param sp Interuptee's RvExcFrame address - * - * Note: Since this routine is ONLY meant to be called from _panic_handler routine, - * it is possible to alter `s0-s11` registers - */ - .global rtos_save_fpu_coproc - .type rtos_save_fpu_coproc, @function -rtos_save_fpu_coproc: - /* If we are in an interrupt context, we have to abort. We don't allow using the FPU from ISR */ -#if ( configNUM_CORES > 1 ) - csrr a2, mhartid /* a2 = coreID */ - slli a2, a2, 2 /* a2 = coreID * 4 */ - la a1, port_uxInterruptNesting /* a1 = &port_uxInterruptNesting */ - add a1, a1, a2 /* a1 = &port_uxInterruptNesting[coreID] */ - lw a1, 0(a1) /* a1 = port_uxInterruptNesting[coreID] */ -#else /* ( configNUM_CORES <= 1 ) */ - lw a1, (port_uxInterruptNesting) /* a1 = port_uxInterruptNesting */ -#endif /* ( configNUM_CORES > 1 ) */ - /* SP still contains the RvExcFrame address */ - mv a0, sp - bnez a1, vPortCoprocUsedInISR - /* Enable the FPU needed by the current task */ - fpu_enable a1 - mv s0, ra - call rtos_current_tcb - /* If the current TCB is NULL, the FPU is used during initialization, even before - * the scheduler started. Consider this a valid usage, the FPU will be disabled - * as soon as the scheduler is started anyway*/ - beqz a0, rtos_save_fpu_coproc_norestore - mv s1, a0 /* s1 = pxCurrentTCBs */ - /* Prepare parameters of pxPortUpdateCoprocOwner */ - mv a2, a0 - li a1, FPU_COPROC_IDX - csrr a0, mhartid - call pxPortUpdateCoprocOwner - /* If the save area is NULL, no need to save context */ - beqz a0, rtos_save_fpu_coproc_nosave - /* Save the FPU context in the structure */ - lw a0, RV_COPROC_SA+FPU_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[FPU_COPROC_IDX] */ - save_fpu_regs a0 - csrr a1, fcsr - sw a1, RV_FPU_FCSR(a0) -rtos_save_fpu_coproc_nosave: -#if ( configNUM_CORES > 1 ) - /* Pin current task to current core */ - mv a0, s1 - csrr a1, mhartid - call vPortTaskPinToCore -#endif /* configNUM_CORES > 1 */ - /* Check if we have to restore a previous FPU context from the current TCB */ - mv a0, s1 - /* Do not allocate memory for the FPU yet, delay this until another task wants to use it. - * This guarantees that if a stack overflow occurs when allocating FPU context on the stack, - * the current task context is flushed and updated in the TCB, generating a correct backtrace - * from the panic handler. */ - li a1, 0 - li a2, FPU_COPROC_IDX - call pxPortGetCoprocArea - /* Get the enable flags from the coprocessor save area */ - lw a1, RV_COPROC_ENABLE(a0) - /* To avoid having branches below, set the FPU enable flag now */ - ori a2, a1, 1 << FPU_COPROC_IDX - sw a2, RV_COPROC_ENABLE(a0) - /* Check if the former FPU enable bit was set */ - andi a2, a1, 1 << FPU_COPROC_IDX - beqz a2, rtos_save_fpu_coproc_norestore - /* FPU enable bit was set, restore the FPU context */ - lw a0, RV_COPROC_SA+FPU_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[FPU_COPROC_IDX] */ - restore_fpu_regs a0 - lw a1, RV_FPU_FCSR(a0) - csrw fcsr, a1 -rtos_save_fpu_coproc_norestore: - /* Return from routine via s0, instead of ra */ - jr s0 - .size rtos_save_fpu_coproc, .-rtos_save_fpu_coproc +generate_coprocessor_routine fpu, FPU_COPROC_IDX, fpu_enable, fpu_save_regs, fpu_restore_regs #endif /* SOC_CPU_HAS_FPU */ @@ -249,6 +425,8 @@ rtos_current_tcb: * TODO: ISR nesting code improvements ? * In the routines below, let's use a0-a5 registers to let the compiler generate * 16-bit instructions. + * @returns Context that should be given to `rtos_int_exit`. On targets that have coprocessors, + * this value is a bitmap where bit i is 1 if coprocessor i is enable, 0 if it is disabled. */ .global rtos_int_enter .type rtos_int_enter, @function @@ -262,6 +440,7 @@ rtos_int_enter: #else lw a0, port_xSchedulerRunning /* a0 = port_xSchedulerRunning */ #endif /* ( configNUM_CORES > 1 ) */ + /* In case we jump, return value (a0) is correct */ beqz a0, rtos_int_enter_end /* if (port_xSchedulerRunning[coreID] == 0) jump to rtos_int_enter_end */ /* Increment the ISR nesting count */ @@ -274,12 +453,27 @@ rtos_int_enter: sw a2, 0(a0) /* port_uxInterruptNesting[coreID] = a2 */ /* If we reached here from another low-priority ISR, i.e, port_uxInterruptNesting[coreID] > 0, then skip stack pushing to TCB */ + li a0, 0 /* return 0 in case we are going to branch */ bnez a1, rtos_int_enter_end /* if (port_uxInterruptNesting[coreID] > 0) jump to rtos_int_enter_end */ + li a7, 0 #if SOC_CPU_COPROC_NUM > 0 - /* Disable the FPU to forbid the ISR from using it. We don't need to re-enable it manually since the caller - * will restore `mstatus` before returning from interrupt. */ + /* Disable the coprocessors to forbid the ISR from using it */ +#if SOC_CPU_HAS_HWLOOP + /* The current HWLP status will be returned in a0 */ + hwlp_disable a0 + or a7, a7, a0 +#endif /* SOC_CPU_HAS_HWLOOP */ + +#if SOC_CPU_HAS_PIE + /* The current HWLP status will be returned in a0 */ + pie_disable a0 + or a7, a7, a0 +#endif /* SOC_CPU_HAS_PIE */ + +#if SOC_CPU_HAS_FPU fpu_disable a0 +#endif /* SOC_CPU_HAS_FPU */ #endif /* SOC_CPU_COPROC_NUM > 0 */ @@ -320,6 +514,8 @@ rtos_int_enter: ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */ + /* Return the coprocessor context from a7 */ + mv a0, a7 rtos_int_enter_end: ret @@ -327,6 +523,8 @@ rtos_int_enter_end: * @brief Restore the stack pointer of the next task to run. * * @param a0 Former mstatus + * @param a1 Context returned by `rtos_int_enter`. On targets that have coprocessors, this value is a bitmap + * where bit i is 1 if coprocessor i was enable, 0 if it was disabled. * * @returns New mstatus (potentially with coprocessors disabled) */ @@ -334,9 +532,14 @@ rtos_int_enter_end: .type rtos_int_exit, @function rtos_int_exit: /* To speed up this routine and because this current routine is only meant to be called from the interrupt - * handler, let's use callee-saved registers instead of stack space. Registers `s3-s11` are not used by + * handler, let's use callee-saved registers instead of stack space. Registers `s5-s11` are not used by * the caller */ mv s11, a0 +#if SOC_CPU_COPROC_NUM > 0 + /* Save a1 as it contains the bitmap with the enabled coprocessors */ + mv s8, a1 +#endif + #if ( configNUM_CORES > 1 ) csrr a1, mhartid /* a1 = coreID */ slli a1, a1, 2 /* a1 = a1 * 4 */ @@ -366,12 +569,12 @@ isr_skip_decrement: /* If the CPU reached this label, a2 (uxInterruptNesting) is 0 for sure */ /* Schedule the next task if a yield is pending */ - la a0, xPortSwitchFlag /* a0 = &xPortSwitchFlag */ + la s7, xPortSwitchFlag /* a0 = &xPortSwitchFlag */ #if ( configNUM_CORES > 1 ) - add a0, a0, a1 /* a0 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4 */ + add s7, s7, a1 /* a0 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4 */ #endif /* ( configNUM_CORES > 1 ) */ - lw a2, 0(a0) /* a2 = xPortSwitchFlag[coreID] */ - beqz a2, no_switch /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch */ + lw a0, 0(s7) /* a2 = xPortSwitchFlag[coreID] */ + beqz a0, no_switch_restore_coproc /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch_restore_coproc */ /* Preserve return address and schedule next task. To speed up the process, and because this current routine * is only meant to be called from the interrupt handle, let's save some speed and space by using callee-saved @@ -379,33 +582,52 @@ isr_skip_decrement: mv s10, ra #if ( SOC_CPU_COPROC_NUM > 0 ) /* In the cases where the newly scheduled task is different from the previously running one, - * we have to disable the coprocessor(s) to let them trigger an exception on first use. - * Else, if the same task is scheduled, do not change the coprocessor(s) state. */ + * we have to disable the coprocessors to let them trigger an exception on first use. + * Else, if the same task is scheduled, restore the former coprocessors state (before the interrupt) */ call rtos_current_tcb + /* Keep former TCB in s9 */ mv s9, a0 +#endif call vTaskSwitchContext +#if ( SOC_CPU_COPROC_NUM == 0 ) + mv ra, s10 /* Restore original return address */ +#endif + /* Clears the switch pending flag (stored in s7) */ + sw zero, 0(s7) /* xPortSwitchFlag[coreID] = 0; */ + +#if ( SOC_CPU_COPROC_NUM > 0 ) + /* If the Task to schedule is NOT the same as the former one (s9), keep the coprocessors disabled */ call rtos_current_tcb - beq a0, s9, rtos_int_exit_no_change - /* Disable the coprocessors in s11 register (former mstatus) */ + mv ra, s10 /* Restore original return address */ + beq a0, s9, no_switch_restore_coproc + +#if SOC_CPU_HAS_FPU + /* Disable the FPU in the `mstatus` value to return */ li a0, ~CSR_MSTATUS_FPU_DISABLE and s11, s11, a0 -rtos_int_exit_no_change: -#else /* ( SOC_CPU_COPROC_NUM == 0 ) */ - call vTaskSwitchContext -#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */ - mv ra, s10 +#endif /* SOC_CPU_HAS_FPU */ + j no_switch_restored - /* Clears the switch pending flag */ - la a0, xPortSwitchFlag /* a0 = &xPortSwitchFlag */ -#if ( configNUM_CORES > 1 ) - /* C routine vTaskSwitchContext may change the temp registers, so we read again */ - csrr a1, mhartid /* a1 = coreID */ - slli a1, a1, 2 /* a1 = a1 * 4 */ - add a0, a0, a1 /* a0 = &xPortSwitchFlag[coreID]; */ -#endif /* ( configNUM_CORES > 1 ) */ - sw zero, 0(a0) /* xPortSwitchFlag[coreID] = 0; */ +#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */ -no_switch: +no_switch_restore_coproc: + /* We reach here either because there is no switch scheduled or because the TCB that is going to be scheduled + * is the same as the one that has been interrupted. In both cases, we need to restore the coprocessors status */ +#if SOC_CPU_HAS_HWLOOP + andi a0, s8, 1 << HWLP_COPROC_IDX + beqz a0, 1f + hwlp_enable a0 +1: +#endif /* SOC_CPU_HAS_HWLOOP */ + +#if SOC_CPU_HAS_PIE + andi a0, s8, 1 << PIE_COPROC_IDX + beqz a0, 1f + pie_enable a0 +1: +#endif /* SOC_CPU_HAS_PIE */ + +no_switch_restored: #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* esp_hw_stack_guard_monitor_stop(); pass the scratch registers */ diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c index 6c52f314d9b..8779a282380 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c @@ -165,7 +165,7 @@ static void unpinned_task(void *arg) TEST_ASSERT_EQUAL(cur_core_num, xTaskGetCoreID(NULL)); #endif #endif // !CONFIG_FREERTOS_UNICORE - // Reenable scheduling/preemption + // Re-enable scheduling/preemption #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) ) vTaskPreemptionEnable(NULL); #else @@ -242,7 +242,7 @@ TEST_CASE("FPU: Unsolicited context switch between tasks using FPU", "[freertos] }; xTaskCreatePinnedToCore(fpu_calculation, "Task1", 2048, params + 0, UNITY_FREERTOS_PRIORITY + 1, &tasks[0], 1); - xTaskCreatePinnedToCore(fpu_calculation, "Task2", 2048, params + 1, UNITY_FREERTOS_PRIORITY + 2, &tasks[2], 1); + xTaskCreatePinnedToCore(fpu_calculation, "Task2", 2048, params + 1, UNITY_FREERTOS_PRIORITY + 1, &tasks[1], 1); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); diff --git a/components/freertos/test_apps/freertos/port/test_hwlp.c b/components/freertos/test_apps/freertos/port/test_hwlp.c new file mode 100644 index 00000000000..6d32263fcf2 --- /dev/null +++ b/components/freertos/test_apps/freertos/port/test_hwlp.c @@ -0,0 +1,151 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include "soc/soc_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" + +/** + * On RISC-V targets that have coprocessors, the contexts are saved at the lowest address of the stack, + * which can lead to wrong stack watermark calculation in FreeRTOS in theory. + * As such, the port layer of FreeRTOS will adjust the lowest address of the stack when a coprocessor + * context is saved. + */ +#if SOC_CPU_HAS_HWLOOP + +static uint32_t use_hwlp(uint32_t count) +{ + uint32_t ret; + asm volatile( + /* The toolchain doesn't support HWLP instructions yet, manually set it up */ + "la a2, start\n" + "csrw 0x7c6, a2\n" + "la a2, end\n" + "csrw 0x7c7, a2\n" + "csrw 0x7c8, a0\n" + "li a1, 0\n" + /* Hardware loops must have at least 8 32-bit instructions or 16 16-bit instructions */ + "start:\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "addi a1, a1, 1\n" + "end:\n" + "addi a1, a1, 1\n" + "mv %0, a1\n" + "ret\n" + : "=r"(ret) :); + return ret; +} + +static void other_task(void* arg) +{ + const TaskHandle_t main_task = (TaskHandle_t) arg; + + use_hwlp(10); + + xTaskNotifyGive(main_task); + vTaskDelete(NULL); +} + +TEST_CASE("HWLP: Context save does not affect stack watermark", "[freertos]") +{ + TaskHandle_t pvCreatedTask; + /* Force the FreeRTOS port layer to store a HWLP context in the current task. + * So let's use the it and make sure another task, on the SAME CORE, also uses it */ + const int core_id = xPortGetCoreID(); + const TaskHandle_t current_handle = xTaskGetCurrentTaskHandle(); + + /* Get the current stack watermark */ + const UBaseType_t before_watermark = uxTaskGetStackHighWaterMark(current_handle); + + /* Use the HWLP unit, the context will NOT be flushed until another task starts using it */ + use_hwlp(20); + + xTaskCreatePinnedToCore(other_task, + "OtherTask", + 2048, + (void*) current_handle, + CONFIG_UNITY_FREERTOS_PRIORITY - 1, + &pvCreatedTask, + core_id); + + vTaskDelay(10); + + /* Wait for other task to complete */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + const UBaseType_t after_watermark = uxTaskGetStackHighWaterMark(current_handle); + + TEST_ASSERT_TRUE(after_watermark > before_watermark / 2); +} + +typedef struct { + uint32_t count; + TaskHandle_t main; +} ParamsHWLP; + +void calculation(void* arg) +{ + ParamsHWLP* p = (ParamsHWLP*) arg; + const uint32_t count = p->count; + uint32_t result = 0; + int i = 0; + + for (i = 0; i < 10; i++) { + uint32_t current = use_hwlp(count); + result += current; + + /* Give some time to the other to interrupt us before checking `f` value */ + esp_rom_delay_us(1000); + + /* Using TEST_ASSERT_TRUE triggers a stack overflow, make sure the count is still correct. + * The function `use_hwlp` should return (count * 16) */ + assert(count * 16 == current); + + /* Give the hand back to FreeRTOS to avoid any watchdog error */ + vTaskDelay(2); + } + + /* Make sure the result is correct */ + assert(count * 16 * i == result); + + xTaskNotifyGive(p->main); + vTaskDelete(NULL); +} + +TEST_CASE("HWLP: Unsolicited context switch between tasks using the PIE", "[freertos]") +{ + /* Create two tasks that are on the same core and use the same FPU */ + TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); + TaskHandle_t tasks[2]; + ParamsHWLP params[2] = { + { .count = 10, .main = unity_task_handle }, + { .count = 200, .main = unity_task_handle }, + }; + + xTaskCreatePinnedToCore(calculation, "Task1", 2048, params + 0, CONFIG_UNITY_FREERTOS_PRIORITY + 1, &tasks[0], 1); + xTaskCreatePinnedToCore(calculation, "Task2", 2048, params + 1, CONFIG_UNITY_FREERTOS_PRIORITY + 1, &tasks[1], 1); + + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); +} + +#endif // SOC_CPU_HAS_HWLOOP diff --git a/components/freertos/test_apps/freertos/port/test_pie_in_task.c b/components/freertos/test_apps/freertos/port/test_pie_in_task.c new file mode 100644 index 00000000000..c5f632ed91b --- /dev/null +++ b/components/freertos/test_apps/freertos/port/test_pie_in_task.c @@ -0,0 +1,253 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include "soc/soc_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" +#include "test_utils.h" + +#if SOC_CPU_HAS_PIE + +/** + * @brief Performs the sum of two 4-word vectors using the PIE. + * + * @param a First vector + * @param b Second vector + * @param dst Destination to store the sum + * + * @returns a will store a + b + */ +static void pie_vector_add(const int32_t a[4], const int32_t b[4], int32_t dst[4]) +{ + asm volatile("esp.vld.128.ip q0, a0, 0\n" + "esp.vld.128.ip q1, a1, 0\n" + "esp.vadd.s32 q2, q0, q1\n" + "esp.vst.128.ip q2, a2, 0\n" + ::); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ + +/* +Test PIE usage from a task context + +Purpose: + - Test that the PIE can be used from a task context + - Test that PIE context is properly saved and restored + - Test that PIE context is cleaned up on task deletion by running multiple iterations +Procedure: + - Create TEST_PINNED_NUM_TASKS tasks pinned to each core + - Start each task + - Each task updates a float variable and then blocks (to allow other tasks to run thus forcing the a PIE context + save and restore). + - Delete each task + - Repeat test for TEST_PINNED_NUM_ITERS iterations +Expected: + - Correct float value calculated by each task + - Each task cleans up its PIE context on deletion +*/ + +#define TEST_PINNED_NUM_TASKS 3 +#define TEST_PINNED_NUM_ITERS 5 + +static void pinned_task(void *arg) +{ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + int32_t a[4] = { 42, 42, 42, 42}; + int32_t b[4] = { 10, 20, 30, 40 }; + int32_t dst[4] = { 0 }; + + pie_vector_add(a, b, dst); + + // Indicate done wand wait to be deleted + xSemaphoreGive((SemaphoreHandle_t)arg); + vTaskSuspend(NULL); +} + +TEST_CASE("PIE: Usage in task", "[freertos]") +{ + SemaphoreHandle_t done_sem = xSemaphoreCreateCounting(CONFIG_FREERTOS_NUMBER_OF_CORES * TEST_PINNED_NUM_TASKS, 0); + TEST_ASSERT_NOT_EQUAL(NULL, done_sem); + + for (int iter = 0; iter < TEST_PINNED_NUM_ITERS; iter++) { + TaskHandle_t task_handles[CONFIG_FREERTOS_NUMBER_OF_CORES][TEST_PINNED_NUM_TASKS]; + + // Create test tasks for each core + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { + for (int j = 0; j < TEST_PINNED_NUM_TASKS; j++) { + TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(pinned_task, "task", 4096, (void *)done_sem, UNITY_FREERTOS_PRIORITY + 1, &task_handles[i][j], i)); + } + } + + // Start the created tasks simultaneously + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { + for (int j = 0; j < TEST_PINNED_NUM_TASKS; j++) { + xTaskNotifyGive(task_handles[i][j]); + } + } + + // Wait for the tasks to complete + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES * TEST_PINNED_NUM_TASKS; i++) { + xSemaphoreTake(done_sem, portMAX_DELAY); + } + + // Delete the tasks + for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { + for (int j = 0; j < TEST_PINNED_NUM_TASKS; j++) { + vTaskDelete(task_handles[i][j]); + } + } + + vTaskDelay(10); // Short delay to allow idle task to be free task memory and FPU contexts + } + + vSemaphoreDelete(done_sem); +} + +/* ------------------------------------------------------------------------------------------------------------------ */ + +/* +Test PIE usage will pin an unpinned task + +Purpose: + - Test that unpinned tasks are automatically pinned to the current core on the task's first use of the PIE + - Test that PIE context is cleaned up on task deletion by running multiple iterations +Procedure: + - Create an unpinned task + - Task disables scheduling/preemption to ensure that it does not switch cores + - Task uses the PIE + - Task checks its core affinity after PIE usage + - Task deletes itself + - Repeat test for TEST_UNPINNED_NUM_ITERS iterations +Expected: + - Task remains unpinned until its first usage of the PIE + - The task becomes pinned to the current core after first use of the PIE + - Each task cleans up its PIE context on deletion +*/ + +#if CONFIG_FREERTOS_NUMBER_OF_CORES > 1 + +#define TEST_UNPINNED_NUM_ITERS 5 + +static void unpinned_task(void *arg) +{ + // Disable scheduling/preemption to make sure current core ID doesn't change +#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) ) + vTaskPreemptionDisable(NULL); +#else + vTaskSuspendAll(); +#endif + BaseType_t cur_core_num = xPortGetCoreID(); + // Check that the task is unpinned +#if !CONFIG_FREERTOS_UNICORE +#if CONFIG_FREERTOS_SMP + TEST_ASSERT_EQUAL(tskNO_AFFINITY, vTaskCoreAffinityGet(NULL)); +#else + TEST_ASSERT_EQUAL(tskNO_AFFINITY, xTaskGetCoreID(NULL)); +#endif +#endif // !CONFIG_FREERTOS_UNICORE + + int32_t a[4] = { 0, 1, 2, 3}; + int32_t b[4] = { 111, 222, 333, 444 }; + int32_t dst[4] = { 0 }; + + pie_vector_add(a, b, dst); + + for (int i = 0; i < sizeof(a) / sizeof(uint32_t); i++) { + TEST_ASSERT_EQUAL(dst[i], a[i] + b[i]); + } + +#if !CONFIG_FREERTOS_UNICORE +#if CONFIG_FREERTOS_SMP + TEST_ASSERT_EQUAL(1 << cur_core_num, vTaskCoreAffinityGet(NULL)); +#else + TEST_ASSERT_EQUAL(cur_core_num, xTaskGetCoreID(NULL)); +#endif +#endif // !CONFIG_FREERTOS_UNICORE + // Re-enable scheduling/preemption +#if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) ) + vTaskPreemptionEnable(NULL); +#else + xTaskResumeAll(); +#endif + + // Indicate done and self delete + xTaskNotifyGive((TaskHandle_t)arg); + vTaskDelete(NULL); +} + +TEST_CASE("PIE: Usage in unpinned task", "[freertos]") +{ + TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); + for (int iter = 0; iter < TEST_UNPINNED_NUM_ITERS; iter++) { + // Create unpinned task + xTaskCreate(unpinned_task, "unpin", 4096, (void *)unity_task_handle, UNITY_FREERTOS_PRIORITY + 1, NULL); + // Wait for task to complete + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + vTaskDelay(10); // Short delay to allow task memory to be freed + } +} + +typedef struct { + int32_t cst; + TaskHandle_t main; +} ParamsPIE; + +/** + * @brief Function performing some simple calculation using the PIE coprocessor. + * The goal is to be preempted by a task that also uses the PIE on the same core. + */ +void pie_calculation(void* arg) +{ + ParamsPIE* p = (ParamsPIE*) arg; + const int32_t cst = p->cst; + int32_t a[4] = { cst, cst, cst, cst }; + int32_t dst[4] = { 0 }; + + for (int i = 0; i < 10; i++) { + pie_vector_add(a, dst, dst); + + /* Give some time to the other to interrupt us before checking `f` value */ + esp_rom_delay_us(1000); + + /* Using TEST_ASSERT_TRUE triggers a stack overflow, make sure the sign is still correct */ + assert((dst[0] < 0 && cst < 0) || (dst[0] > 0 && cst > 0)); + + /* Give the hand back to FreeRTOS to avoid any watchdog error */ + vTaskDelay(2); + } + + /* Make sure the result is correct */ + assert((dst[0] * cst == 10)); + + xTaskNotifyGive(p->main); + vTaskDelete(NULL); +} + +TEST_CASE("PIE: Unsolicited context switch between tasks using the PIE", "[freertos]") +{ + /* Create two tasks that are on the same core and use the same FPU */ + TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); + TaskHandle_t tasks[2]; + ParamsPIE params[2] = { + { .cst = 1, .main = unity_task_handle }, + { .cst = -1, .main = unity_task_handle }, + }; + + xTaskCreatePinnedToCore(pie_calculation, "Task1", 2048, params + 0, UNITY_FREERTOS_PRIORITY + 1, &tasks[0], 1); + xTaskCreatePinnedToCore(pie_calculation, "Task2", 2048, params + 1, UNITY_FREERTOS_PRIORITY + 1, &tasks[1], 1); + + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); +} + +#endif // CONFIG_FREERTOS_NUMBER_OF_CORES > 1 +#endif // SOC_CPU_HAS_PIE diff --git a/components/freertos/test_apps/freertos/port/test_pie_watermark.c b/components/freertos/test_apps/freertos/port/test_pie_watermark.c new file mode 100644 index 00000000000..5f5725cf293 --- /dev/null +++ b/components/freertos/test_apps/freertos/port/test_pie_watermark.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include "soc/soc_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" + +#define TASKS_STATUS_ARRAY_LEN 16 + +/** + * On RISC-V targets that have coprocessors, the contexts are saved at the lowest address of the stack, + * which can lead to wrong stack watermark calculation in FreeRTOS in theory. + * As such, the port layer of FreeRTOS will adjust the lowest address of the stack when a coprocessor + * context is saved. + */ +#if SOC_CPU_HAS_PIE + +static void use_pie(uint32_t a[4], uint32_t b[4]) +{ + asm volatile("esp.vld.128.ip q0, %0, 0\n" + "esp.vld.128.ip q1, %2, 0\n" + "esp.vadd.u32 q2, q0, q1\n" + "esp.vst.128.ip q2, %0, 0\n" + : "=r"(a) : "r"(a), "r"(b)); +} + +static void other_task(void* arg) +{ + uint32_t a[4] = { 1, 2, 3, 4}; + uint32_t b[4] = { 42, 43, 44, 45}; + const TaskHandle_t main_task = (TaskHandle_t) arg; + + /* This task must also use the PIE coprocessor to force a PIE context flush on the main task */ + use_pie(a, b); + + xTaskNotifyGive(main_task); + vTaskDelete(NULL); +} + +TEST_CASE("PIE: Context save does not affect stack watermark", "[freertos]") +{ + /* Setup some random values */ + uint32_t a[4] = { 0x3f00ffff, 0xffe10045, 0xffe10096, 0x42434546}; + uint32_t b[4] = { 0x42, 0xbb43, 0x6644, 0x845}; + + TaskHandle_t pvCreatedTask; + /* Force the FreeRTOS port layer to store a PIE context in the current task. + * So let's use the PIE and make sure another task, on the SAME CORE, also uses it */ + const int core_id = xPortGetCoreID(); + const TaskHandle_t current_handle = xTaskGetCurrentTaskHandle(); + + /* Get the current stack watermark */ + const UBaseType_t before_watermark = uxTaskGetStackHighWaterMark(current_handle); + + /* Use the PIE unit, the context will NOT be flushed until another task starts using it */ + use_pie(a, b); + + xTaskCreatePinnedToCore(other_task, + "OtherTask", + 2048, + (void*) current_handle, + CONFIG_UNITY_FREERTOS_PRIORITY - 1, + &pvCreatedTask, + core_id); + + vTaskDelay(10); + + /* Wait for other task to complete */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + const UBaseType_t after_watermark = uxTaskGetStackHighWaterMark(current_handle); + + /* The current task has seen a PIE registers context save, so we have at least 8 16-byte registers saved on the + * stack, which represents 128 bytes. In practice, it may be very different, for example a call to printf would + * result is more than 1KB of additional stack space used. So let's just make sure that the watermark is bigger + * than 50% of the former watermark. */ + TEST_ASSERT_TRUE(after_watermark > before_watermark / 2); +} + +#endif // SOC_CPU_HAS_PIE diff --git a/components/riscv/include/riscv/csr_hwlp.h b/components/riscv/include/riscv/csr_hwlp.h new file mode 100644 index 00000000000..91c946a50a3 --- /dev/null +++ b/components/riscv/include/riscv/csr_hwlp.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_CPU_HAS_HWLOOP + +/* CSR 0x7F1 lowest 2 bits describe the following states: + * 00: OFF + * 01: Initial + * 10: Clean + * 11: Dirty + */ +#define CSR_HWLP_STATE_REG 0x7F1 + +#define CSR_LOOP0_START_ADDR 0x7C6 +#define CSR_LOOP0_END_ADDR 0x7C7 +#define CSR_LOOP0_COUNT 0x7C8 +#define CSR_LOOP1_START_ADDR 0x7C9 +#define CSR_LOOP1_END_ADDR 0x7CA +#define CSR_LOOP1_COUNT 0x7CB + +#endif /* SOC_CPU_HAS_HWLOOP */ diff --git a/components/riscv/include/riscv/csr_pie.h b/components/riscv/include/riscv/csr_pie.h new file mode 100644 index 00000000000..59b5c8f25d7 --- /dev/null +++ b/components/riscv/include/riscv/csr_pie.h @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" + +#if SOC_CPU_HAS_PIE + +/* CSR lowest 2 bits describe the following states: + * 00: OFF + * 01: Initial + * 10: Clean + * 11: Dirty + */ +#define CSR_PIE_STATE_REG 0x7F2 + +#endif /* SOC_CPU_HAS_PIE */ diff --git a/components/riscv/include/riscv/rvruntime-frames.h b/components/riscv/include/riscv/rvruntime-frames.h index e218d6a5ad3..45f013b0e5f 100644 --- a/components/riscv/include/riscv/rvruntime-frames.h +++ b/components/riscv/include/riscv/rvruntime-frames.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -86,7 +86,21 @@ STRUCT_END(RvExcFrame) #if SOC_CPU_COPROC_NUM > 0 +/* Define the default size of each coprocessor save area */ +#define RV_COPROC0_SIZE 0 +#define RV_COPROC1_SIZE 0 +#define RV_COPROC2_SIZE 0 +/* And the alignment for each of them */ +#define RV_COPROC0_ALIGN 4 +#define RV_COPROC1_ALIGN 4 +#define RV_COPROC2_ALIGN 4 + + #if SOC_CPU_HAS_FPU + +/* Floating-Point Unit coprocessor is now considered coprocessor 0 */ +#define FPU_COPROC_IDX 0 + /** * @brief Floating-Point Unit save area */ @@ -126,29 +140,97 @@ STRUCT_FIELD (long, 4, RV_FPU_FT11, ft11) STRUCT_FIELD (long, 4, RV_FPU_FCSR, fcsr) /* fcsr special register */ STRUCT_END(RvFPUSaveArea) -/* Floating-Point Unit coprocessor is now considered coprocessor 0 */ -#define FPU_COPROC_IDX 0 -/* PIE/AIA coprocessor is coprocessor 1 */ -#define PIE_COPROC_IDX 1 - -/* Define the size of each coprocessor save area */ +/* Redefine the coprocessor area size previously defined to 0 */ +#undef RV_COPROC0_SIZE #if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) -#define RV_COPROC0_SIZE RvFPUSaveAreaSize -#define RV_COPROC1_SIZE 0 // PIE/AIA coprocessor area + #define RV_COPROC0_SIZE RvFPUSaveAreaSize #else -#define RV_COPROC0_SIZE sizeof(RvFPUSaveArea) -#define RV_COPROC1_SIZE 0 // PIE/AIA coprocessor area + #define RV_COPROC0_SIZE sizeof(RvFPUSaveArea) #endif /* defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) */ #endif /* SOC_CPU_HAS_FPU */ + +#if SOC_CPU_HAS_HWLOOP + +/* Hardware Loop extension is "coprocessor" 1 */ +#define HWLP_COPROC_IDX 1 + +/** + * @brief Hardware loop save area + */ +STRUCT_BEGIN +STRUCT_FIELD (long, 4, RV_HWLOOP_START0, start0) +STRUCT_FIELD (long, 4, RV_HWLOOP_END0, end0) +STRUCT_FIELD (long, 4, RV_HWLOOP_COUNT0, count0) +STRUCT_FIELD (long, 4, RV_HWLOOP_START1, start1) +STRUCT_FIELD (long, 4, RV_HWLOOP_END1, end1) +STRUCT_FIELD (long, 4, RV_HWLOOP_COUNT1, count1) +STRUCT_END(RvHWLPSaveArea) + +/* Redefine the coprocessor area size previously defined to 0 */ +#undef RV_COPROC1_SIZE +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) + #define RV_COPROC1_SIZE RvHWLPSaveAreaSize +#else + #define RV_COPROC1_SIZE sizeof(RvHWLPSaveArea) +#endif /* defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) */ + +#endif /* SOC_CPU_HAS_HWLOOP */ + + + +#if SOC_CPU_HAS_PIE + +/* PIE/AIA coprocessor is now considered coprocessor 2 */ +#define PIE_COPROC_IDX 2 + +/** + * @brief PIE save area + */ +STRUCT_BEGIN +STRUCT_AFIELD (long, 4, RV_PIE_Q0, q0, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q1, q1, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q2, q2, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q3, q3, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q4, q4, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q5, q5, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q6, q6, 4) +STRUCT_AFIELD (long, 4, RV_PIE_Q7, q7, 4) +STRUCT_AFIELD (long, 4, RV_PIE_QACC_L_L, qacc_l_l, 4) +STRUCT_AFIELD (long, 4, RV_PIE_QACC_L_H, qacc_l_h, 4) +STRUCT_AFIELD (long, 4, RV_PIE_QACC_H_L, qacc_h_l, 4) +STRUCT_AFIELD (long, 4, RV_PIE_QACC_H_H, qacc_h_h, 4) +STRUCT_AFIELD (long, 4, RV_PIE_UA_STATE, ua_state, 4) +STRUCT_FIELD (long, 4, RV_PIE_XACC, xacc) +/* This register contains SAR, SAR_BYTES and FFT_BIT_WIDTH in this order (from top to low) */ +STRUCT_FIELD (long, 4, RV_PIE_MISC, misc) +STRUCT_END(RvPIESaveArea) + +/* Redefine the coprocessor area size previously defined to 0 */ +#undef RV_COPROC2_SIZE + +#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) + #define RV_COPROC2_SIZE RvPIESaveAreaSize +#else + #define RV_COPROC2_SIZE sizeof(RvPIESaveArea) +#endif /* defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) */ + +/* The PIE save area structure must be aligned on 16 bytes */ +#undef RV_COPROC2_ALIGN +#define RV_COPROC2_ALIGN 16 + +#endif /* SOC_CPU_HAS_PIE */ + + + /** * @brief Coprocessors save area, containing each coprocessor save area */ STRUCT_BEGIN /* Enable bitmap: BIT(i) represents coprocessor i, 1 is used, 0 else */ STRUCT_FIELD (long, 4, RV_COPROC_ENABLE, sa_enable) -/* Address of the original lowest stack address, convenient when the stack needs to re-initialized */ +/* Address of the original lowest stack address, convenient when the stack needs to be re-initialized */ STRUCT_FIELD (void*, 4, RV_COPROC_TCB_STACK, sa_tcbstack) /* Address of the pool of memory used to allocate coprocessors save areas */ STRUCT_FIELD (long, 4, RV_COPROC_ALLOCATOR, sa_allocator) diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index 0b46681416b..4a5db19afdb 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -25,11 +25,11 @@ /* EXT_ILL CSR reasons are stored as follows: * - Bit 0: FPU core instruction (Load/Store instructions NOT concerned) - * - Bit 1: Low-power core + * - Bit 1: Hardware Loop instructions * - Bit 2: PIE core */ - .equ EXT_ILL_RSN_FPU, 1 - .equ EXT_ILL_RSN_LP, 2 - .equ EXT_ILL_RSN_PIE, 4 + .equ EXT_ILL_RSN_FPU, 1 + .equ EXT_ILL_RSN_HWLP, 2 + .equ EXT_ILL_RSN_PIE, 4 #endif /* SOC_CPU_COPROC_NUM > 0 */ /* Macro which first allocates space on the stack to save general @@ -166,12 +166,24 @@ _panic_handler: /* In case this is due to a coprocessor, set ra right now to simplify the logic below */ la ra, _return_from_exception /* EXT_ILL CSR should contain the reason for the Illegal Instruction */ - csrr a0, EXT_ILL_CSR - mv a2, a0 + csrrw a0, EXT_ILL_CSR, zero + +#if SOC_CPU_HAS_HWLOOP + /* Check if the HWLOOP bit is set. */ + andi a1, a0, EXT_ILL_RSN_HWLP + bnez a1, rtos_save_hwlp_coproc +#endif // SOC_CPU_HAS_HWLOOP + +#if SOC_CPU_HAS_PIE + /* Check if the HWLOOP bit is set. */ + andi a1, a0, EXT_ILL_RSN_PIE + bnez a1, rtos_save_pie_coproc +#endif // SOC_CPU_HAS_HWLOOP + +#if SOC_CPU_HAS_FPU /* Check if the FPU bit is set. When targets have the FPU reason bug (SOC_CPU_HAS_FPU_EXT_ILL_BUG), * it is possible that another bit is set even if the reason is an FPU instruction. * For example, bit 1 can be set and bit 0 won't, even if the reason is an FPU instruction. */ -#if SOC_CPU_HAS_FPU andi a1, a0, EXT_ILL_RSN_FPU bnez a1, rtos_save_fpu_coproc #if SOC_CPU_HAS_FPU_EXT_ILL_BUG @@ -202,8 +214,6 @@ _panic_handler_not_fpu: #endif /* SOC_CPU_HAS_FPU_EXT_ILL_BUG */ #endif /* SOC_CPU_HAS_FPU */ - /* Need to check the other coprocessors reason now, instruction is in register a2 */ - /* Ignore LP and PIE for now, continue the exception */ _panic_handler_not_coproc: #endif /* ( SOC_CPU_COPROC_NUM > 0 ) */ @@ -298,9 +308,11 @@ _interrupt_handler: /* Save SP former value */ sw a0, RV_STK_SP(sp) - /* Notify the RTOS that an interrupt ocurred, it will save the current stack pointer - * in the running TCB, no need to pass it as a parameter */ + /* Notify the RTOS that an interrupt occurred, it will save the current stack pointer + * in the running TCB, no need to pass it as a parameter + * Returns an abstract context in a0, needs to be passed to `rtos_int_exit` */ call rtos_int_enter + mv s4, a0 /* If this is a non-nested interrupt, SP now points to the interrupt stack */ /* Before dispatch c handler, restore interrupt to enable nested intr */ @@ -366,6 +378,7 @@ _interrupt_handler: /* The RTOS will restore the current TCB stack pointer. This routine will preserve s1 and s2. * Returns the new `mstatus` value. */ mv a0, s2 /* a0 = mstatus */ + mv a1, s4 /* a1 = abstract context returned by `rtos_int_enter` */ call rtos_int_exit /* Restore the rest of the registers. diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..b65d924e3f6 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -411,9 +411,17 @@ config SOC_CPU_HAS_FPU_EXT_ILL_BUG bool default y +config SOC_CPU_HAS_HWLOOP + bool + default y + +config SOC_CPU_HAS_PIE + bool + default y + config SOC_CPU_COPROC_NUM int - default 2 + default 3 config SOC_HP_CPU_HAS_MULTIPLE_CORES bool diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..a708d9cd748 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -159,7 +159,9 @@ #define SOC_BRANCH_PREDICTOR_SUPPORTED 1 #define SOC_CPU_HAS_FPU 1 #define SOC_CPU_HAS_FPU_EXT_ILL_BUG 1 // EXT_ILL CSR doesn't support FLW/FSW -#define SOC_CPU_COPROC_NUM 2 +#define SOC_CPU_HAS_HWLOOP 1 +#define SOC_CPU_HAS_PIE 1 +#define SOC_CPU_COPROC_NUM 3 #define SOC_HP_CPU_HAS_MULTIPLE_CORES 1 // Convenience boolean macro used to determine if a target has multiple cores. #define SOC_CPU_BREAKPOINTS_NUM 3 From 0928ff027b2808f84e5f40429802b20587779947 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Tue, 30 Apr 2024 16:37:40 +0800 Subject: [PATCH 132/548] fix(riscv): make HWLP feature use direct saving of lazy saving --- .../FreeRTOS-Kernel/portable/riscv/port.c | 23 ++- .../FreeRTOS-Kernel/portable/riscv/portasm.S | 131 +++++++++++++----- components/freertos/app_startup.c | 2 +- .../freertos/port/test_fpu_in_task.c | 6 +- .../test_apps/freertos/port/test_hwlp.c | 89 +++--------- .../freertos/port/test_hwlp_routines.S | 52 +++++++ .../freertos/port/test_pie_in_task.c | 65 +++++---- .../freertos/port/test_pie_routines.S | 50 +++++++ .../freertos/port/test_pie_watermark.c | 22 +-- components/riscv/include/riscv/csr_hwlp.h | 5 + components/riscv/include/riscv/rv_utils.h | 22 +++ components/riscv/vectors.S | 11 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 +- components/soc/esp32p4/include/soc/soc_caps.h | 6 +- 14 files changed, 325 insertions(+), 167 deletions(-) create mode 100644 components/freertos/test_apps/freertos/port/test_hwlp_routines.S create mode 100644 components/freertos/test_apps/freertos/port/test_pie_routines.S diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 7406cdbccb1..068668e9657 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -60,6 +60,11 @@ #include "soc/hp_system_reg.h" #endif +#if SOC_CPU_HAS_HWLOOP +#include "riscv/csr.h" +#include "riscv/csr_hwlp.h" +#endif + #if ( SOC_CPU_COPROC_NUM > 0 ) #include "esp_private/panic_internal.h" @@ -125,9 +130,23 @@ StackType_t *xIsrStackBottom[portNUM_PROCESSORS] = {0}; BaseType_t xPortStartScheduler(void) { #if ( SOC_CPU_COPROC_NUM > 0 ) + +#if SOC_CPU_HAS_FPU /* Disable FPU so that the first task to use it will trigger an exception */ rv_utils_disable_fpu(); -#endif +#endif /* SOC_CPU_HAS_FPU */ + +#if SOC_CPU_HAS_PIE + /* Similarly, disable PIE */ + rv_utils_disable_pie(); +#endif /* SOC_CPU_HAS_FPU */ + +#if SOC_CPU_HAS_HWLOOP + /* Initialize the Hardware loop feature */ + RV_WRITE_CSR(CSR_HWLP_STATE_REG, HWLP_INITIAL_STATE); +#endif /* SOC_CPU_HAS_HWLOOP */ +#endif /* ( SOC_CPU_COPROC_NUM > 0 ) */ + /* Initialize all kernel state tracking variables */ BaseType_t coreID = xPortGetCoreID(); port_uxInterruptNesting[coreID] = 0; @@ -826,7 +845,7 @@ RvCoprocSaveArea* pxPortGetCoprocArea(StaticTask_t* task, bool allocate, int cop * @param coreid Current core * @param coproc Coprocessor to save context of * - * @returns Coprocessor former owner's save are, can be NULL is there was no owner yet, can be -1 if + * @returns Coprocessor former owner's save area, can be NULL if there was no owner yet, can be -1 if * the former owner is the same as the new owner. */ RvCoprocSaveArea* pxPortUpdateCoprocOwner(int coreid, int coproc, StaticTask_t* owner) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S index 067c846c3e1..b737e58d7c2 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S @@ -92,7 +92,7 @@ rtos_save_\name\()_coproc: \save_coproc_regs a0 rtos_save_\name\()_coproc_nosave: #if ( configNUM_CORES > 1 ) - /* Pin current task to current core */ + /* Pin current task to current core, s1 has pxCurrentTCBs */ mv a0, s1 csrr a1, mhartid call vPortTaskPinToCore @@ -184,7 +184,33 @@ rtos_save_\name\()_coproc_norestore: .endm -generate_coprocessor_routine hwlp, HWLP_COPROC_IDX, hwlp_enable, hwlp_save_regs, hwlp_restore_regs + /** + * @brief Restore the HWLP registers contained in the dedicated save area if the given task ever used it. + * This routine sets the HWLP context to clean in any case. + * + * @param a0 StaticTask address for the newly scheduled task + */ +hwlp_restore_if_used: + addi sp, sp, -16 + sw ra, (sp) + /* Check if the HWLP was in use beforehand */ + li a1, 0 + li a2, HWLP_COPROC_IDX + call pxPortGetCoprocArea + /* Get the enable flags from the coprocessor save area */ + lw a1, RV_COPROC_ENABLE(a0) + /* To avoid having branches below, set the coprocessor enable flag now */ + andi a2, a1, 1 << HWLP_COPROC_IDX + beqz a2, _hwlp_restore_never_used + /* Enable bit was set, restore the coprocessor context */ + lw a0, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[HWLP_COPROC_IDX] */ + hwlp_restore_regs a0 +_hwlp_restore_never_used: + /* Clear the context */ + csrwi CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE + lw ra, (sp) + addi sp, sp, 16 + ret #endif /* SOC_CPU_HAS_HWLOOP */ @@ -192,7 +218,7 @@ generate_coprocessor_routine hwlp, HWLP_COPROC_IDX, hwlp_enable, hwlp_save_regs, #if SOC_CPU_HAS_PIE /** - * @brief Macros to enable and disable the hardware loop feature on the current core + * @brief Macros to enable and disable the PIE coprocessor on the current core */ .macro pie_enable scratch_reg=a0 li \scratch_reg, 1 @@ -200,7 +226,7 @@ generate_coprocessor_routine hwlp, HWLP_COPROC_IDX, hwlp_enable, hwlp_save_regs, .endm /** - * @brief Disable HW Loop CPU feature while returning the former status in the given register + * @brief Disable the PIE coprocessor while returning the former status in the given register */ .macro pie_disable reg csrrw \reg, CSR_PIE_STATE_REG, zero @@ -213,7 +239,7 @@ generate_coprocessor_routine hwlp, HWLP_COPROC_IDX, hwlp_enable, hwlp_save_regs, .endm /** - * @brief Macros to save and restore the hardware loop registers to and from the given frame + * @brief Macros to save and restore the PIE coprocessor registers to and from the given frame */ .macro pie_save_regs frame=a0 /* Save the 128-bit Q registers from the frame memory and then frame += 16 */ @@ -427,15 +453,16 @@ rtos_current_tcb: * 16-bit instructions. * @returns Context that should be given to `rtos_int_exit`. On targets that have coprocessors, * this value is a bitmap where bit i is 1 if coprocessor i is enable, 0 if it is disabled. + * This routine can use the s registers too since they are not used by the caller (yet) */ .global rtos_int_enter .type rtos_int_enter, @function rtos_int_enter: #if ( configNUM_CORES > 1 ) - csrr a5, mhartid /* a5 = coreID */ - slli a5, a5, 2 /* a5 = coreID * 4 */ + csrr s0, mhartid /* s0 = coreID */ + slli s0, s0, 2 /* s0 = coreID * 4 */ la a0, port_xSchedulerRunning /* a0 = &port_xSchedulerRunning */ - add a0, a0, a5 /* a0 = &port_xSchedulerRunning[coreID] */ + add a0, a0, s0 /* a0 = &port_xSchedulerRunning[coreID] */ lw a0, (a0) /* a0 = port_xSchedulerRunning[coreID] */ #else lw a0, port_xSchedulerRunning /* a0 = port_xSchedulerRunning */ @@ -446,7 +473,7 @@ rtos_int_enter: /* Increment the ISR nesting count */ la a0, port_uxInterruptNesting /* a0 = &port_uxInterruptNesting */ #if ( configNUM_CORES > 1 ) - add a0, a0, a5 /* a0 = &port_uxInterruptNesting[coreID] // a5 already contains coreID * 4 */ + add a0, a0, s0 /* a0 = &port_uxInterruptNesting[coreID] // s0 contains coreID * 4 */ #endif /* ( configNUM_CORES > 1 ) */ lw a1, 0(a0) /* a1 = port_uxInterruptNesting[coreID] */ addi a2, a1, 1 /* a2 = a1 + 1 */ @@ -456,19 +483,13 @@ rtos_int_enter: li a0, 0 /* return 0 in case we are going to branch */ bnez a1, rtos_int_enter_end /* if (port_uxInterruptNesting[coreID] > 0) jump to rtos_int_enter_end */ - li a7, 0 + li s2, 0 #if SOC_CPU_COPROC_NUM > 0 /* Disable the coprocessors to forbid the ISR from using it */ -#if SOC_CPU_HAS_HWLOOP - /* The current HWLP status will be returned in a0 */ - hwlp_disable a0 - or a7, a7, a0 -#endif /* SOC_CPU_HAS_HWLOOP */ - #if SOC_CPU_HAS_PIE - /* The current HWLP status will be returned in a0 */ + /* The current PIE coprocessor status will be returned in a0 */ pie_disable a0 - or a7, a7, a0 + or s2, s2, a0 #endif /* SOC_CPU_HAS_PIE */ #if SOC_CPU_HAS_FPU @@ -485,24 +506,48 @@ rtos_int_enter: /* Save the current sp in pxCurrentTCBs[coreID] and load the ISR stack on to sp */ #if ( configNUM_CORES > 1 ) la a0, pxCurrentTCBs /* a0 = &pxCurrentTCBs */ - add a0, a0, a5 /* a0 = &pxCurrentTCBs[coreID] // a5 already contains coreID * 4 */ + add a0, a0, s0 /* a0 = &pxCurrentTCBs[coreID] // s0 already contains coreID * 4 */ lw a0, (a0) /* a0 = pxCurrentTCBs[coreID] */ sw sp, 0(a0) /* pxCurrentTCBs[coreID] = sp */ - la a0, xIsrStackTop /* a0 = &xIsrStackTop */ - add a0, a0, a5 /* a0 = &xIsrStackTop[coreID] // a5 already contains coreID * 4 */ - lw sp, (a0) /* sp = xIsrStackTop[coreID] */ + /* We may need a0 below to call pxPortGetCoprocArea */ + la a1, xIsrStackTop /* a1 = &xIsrStackTop */ + add a1, a1, s0 /* a1 = &xIsrStackTop[coreID] // s0 already contains coreID * 4 */ + lw sp, (a1) /* sp = xIsrStackTop[coreID] */ #else lw a0, pxCurrentTCBs /* a0 = pxCurrentTCBs */ sw sp, 0(a0) /* pxCurrentTCBs[0] = sp */ lw sp, xIsrStackTop /* sp = xIsrStackTop */ #endif /* ( configNUM_CORES > 1 ) */ +#if SOC_CPU_HAS_HWLOOP + /* Check if the current task used the Hardware loop feature, by reading the state */ + csrr a1, CSR_HWLP_STATE_REG + addi a1, a1, -HWLP_DIRTY_STATE + bnez a1, 1f + /* State is dirty! The hardware loop feature was used, save the registers */ + li a1, 1 /* Allocate the save area if not already allocated */ + li a2, HWLP_COPROC_IDX + mv s1, ra + call pxPortGetCoprocArea + mv ra, s1 + /* Set the enable flags from the coprocessor save area */ + lw a1, RV_COPROC_ENABLE(a0) + ori a1, a1, 1 << HWLP_COPROC_IDX + sw a1, RV_COPROC_ENABLE(a0) + /* Get the area where we need to save the HWLP registers */ + lw a0, RV_COPROC_SA+HWLP_COPROC_IDX*4(a0) /* a0 = RvCoprocSaveArea->sa_coprocs[\coproc_idx] */ + hwlp_save_regs a0 + /* Disable the HWLP feature so that ISR cannot use them */ + csrwi CSR_HWLP_STATE_REG, HWLP_CLEAN_STATE +1: +#endif + #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD /* Prepare the parameters for esp_hw_stack_guard_set_bounds(xIsrStackBottom, xIsrStackTop); */ #if ( configNUM_CORES > 1 ) /* Load the xIsrStack for the current core and set the new bounds */ la a0, xIsrStackBottom - add a0, a0, a5 /* a0 = &xIsrStackBottom[coreID] */ + add a0, a0, s0 /* a0 = &xIsrStackBottom[coreID] */ lw a0, (a0) /* a0 = xIsrStackBottom[coreID] */ #else lw a0, xIsrStackBottom @@ -514,8 +559,8 @@ rtos_int_enter: ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */ - /* Return the coprocessor context from a7 */ - mv a0, a7 + /* Return the coprocessor context from s2 */ + mv a0, s2 rtos_int_enter_end: ret @@ -569,11 +614,11 @@ isr_skip_decrement: /* If the CPU reached this label, a2 (uxInterruptNesting) is 0 for sure */ /* Schedule the next task if a yield is pending */ - la s7, xPortSwitchFlag /* a0 = &xPortSwitchFlag */ + la s7, xPortSwitchFlag /* s7 = &xPortSwitchFlag */ #if ( configNUM_CORES > 1 ) - add s7, s7, a1 /* a0 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4 */ + add s7, s7, a1 /* s7 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4 */ #endif /* ( configNUM_CORES > 1 ) */ - lw a0, 0(s7) /* a2 = xPortSwitchFlag[coreID] */ + lw a0, 0(s7) /* a0 = xPortSwitchFlag[coreID] */ beqz a0, no_switch_restore_coproc /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch_restore_coproc */ /* Preserve return address and schedule next task. To speed up the process, and because this current routine @@ -601,10 +646,19 @@ isr_skip_decrement: mv ra, s10 /* Restore original return address */ beq a0, s9, no_switch_restore_coproc +#if SOC_CPU_HAS_HWLOOP + /* We have to restore the context of the HWLP if the newly scheduled task used it before. In all cases, this + * routine will also clean the state and set it to clean */ + mv s7, ra + /* a0 contains the current TCB address */ + call hwlp_restore_if_used + mv ra, s7 +#endif /* SOC_CPU_HAS_HWLOOP */ + #if SOC_CPU_HAS_FPU /* Disable the FPU in the `mstatus` value to return */ - li a0, ~CSR_MSTATUS_FPU_DISABLE - and s11, s11, a0 + li a1, ~CSR_MSTATUS_FPU_DISABLE + and s11, s11, a1 #endif /* SOC_CPU_HAS_FPU */ j no_switch_restored @@ -614,17 +668,24 @@ no_switch_restore_coproc: /* We reach here either because there is no switch scheduled or because the TCB that is going to be scheduled * is the same as the one that has been interrupted. In both cases, we need to restore the coprocessors status */ #if SOC_CPU_HAS_HWLOOP - andi a0, s8, 1 << HWLP_COPROC_IDX - beqz a0, 1f - hwlp_enable a0 + /* Check if the ISR altered the state of the HWLP */ + csrr a1, CSR_HWLP_STATE_REG + addi a1, a1, -HWLP_DIRTY_STATE + bnez a1, 1f + /* ISR used the HWLP, restore the HWLP context! */ + mv s7, ra + /* a0 contains the current TCB address */ + call hwlp_restore_if_used + mv ra, s7 1: + /* Else, the ISR hasn't touched HWLP registers, we don't need to restore the HWLP registers */ #endif /* SOC_CPU_HAS_HWLOOP */ #if SOC_CPU_HAS_PIE andi a0, s8, 1 << PIE_COPROC_IDX - beqz a0, 1f + beqz a0, 2f pie_enable a0 -1: +2: #endif /* SOC_CPU_HAS_PIE */ no_switch_restored: diff --git a/components/freertos/app_startup.c b/components/freertos/app_startup.c index 7e4439d0b81..c7f81167695 100644 --- a/components/freertos/app_startup.c +++ b/components/freertos/app_startup.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c index 8779a282380..fe59eb4bc21 100644 --- a/components/freertos/test_apps/freertos/port/test_fpu_in_task.c +++ b/components/freertos/test_apps/freertos/port/test_fpu_in_task.c @@ -192,7 +192,7 @@ TEST_CASE("FPU: Usage in unpinned task", "[freertos]") typedef struct { bool negative; TaskHandle_t main; -} ParamsFPU; +} fpu_params_t; /** * @brief Function performing some simple calculation using several FPU registers. @@ -200,7 +200,7 @@ typedef struct { */ void fpu_calculation(void* arg) { - ParamsFPU* p = (ParamsFPU*) arg; + fpu_params_t* p = (fpu_params_t*) arg; const bool negative = p->negative; const float init = negative ? -1.f : 1.f; float f = init; @@ -236,7 +236,7 @@ TEST_CASE("FPU: Unsolicited context switch between tasks using FPU", "[freertos] /* Create two tasks that are on the same core and use the same FPU */ TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); TaskHandle_t tasks[2]; - ParamsFPU params[2] = { + fpu_params_t params[2] = { { .negative = false, .main = unity_task_handle }, { .negative = true, .main = unity_task_handle }, }; diff --git a/components/freertos/test_apps/freertos/port/test_hwlp.c b/components/freertos/test_apps/freertos/port/test_hwlp.c index 6d32263fcf2..49347318f56 100644 --- a/components/freertos/test_apps/freertos/port/test_hwlp.c +++ b/components/freertos/test_apps/freertos/port/test_hwlp.c @@ -19,109 +19,50 @@ */ #if SOC_CPU_HAS_HWLOOP -static uint32_t use_hwlp(uint32_t count) -{ - uint32_t ret; - asm volatile( - /* The toolchain doesn't support HWLP instructions yet, manually set it up */ - "la a2, start\n" - "csrw 0x7c6, a2\n" - "la a2, end\n" - "csrw 0x7c7, a2\n" - "csrw 0x7c8, a0\n" - "li a1, 0\n" - /* Hardware loops must have at least 8 32-bit instructions or 16 16-bit instructions */ - "start:\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "addi a1, a1, 1\n" - "end:\n" - "addi a1, a1, 1\n" - "mv %0, a1\n" - "ret\n" - : "=r"(ret) :); - return ret; -} - -static void other_task(void* arg) -{ - const TaskHandle_t main_task = (TaskHandle_t) arg; - - use_hwlp(10); - - xTaskNotifyGive(main_task); - vTaskDelete(NULL); -} +uint32_t use_hwlp(uint32_t count); TEST_CASE("HWLP: Context save does not affect stack watermark", "[freertos]") { - TaskHandle_t pvCreatedTask; /* Force the FreeRTOS port layer to store a HWLP context in the current task. * So let's use the it and make sure another task, on the SAME CORE, also uses it */ - const int core_id = xPortGetCoreID(); const TaskHandle_t current_handle = xTaskGetCurrentTaskHandle(); /* Get the current stack watermark */ const UBaseType_t before_watermark = uxTaskGetStackHighWaterMark(current_handle); - /* Use the HWLP unit, the context will NOT be flushed until another task starts using it */ + /* Use the HWLP unit, the context will NOT be flushed until a context switch is done */ use_hwlp(20); - xTaskCreatePinnedToCore(other_task, - "OtherTask", - 2048, - (void*) current_handle, - CONFIG_UNITY_FREERTOS_PRIORITY - 1, - &pvCreatedTask, - core_id); - + /* Make sure FreeRTOS switches to another task, even Idle task, so that the current Task saves + * the HWLP current context */ vTaskDelay(10); - /* Wait for other task to complete */ - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - const UBaseType_t after_watermark = uxTaskGetStackHighWaterMark(current_handle); TEST_ASSERT_TRUE(after_watermark > before_watermark / 2); } +#if CONFIG_FREERTOS_NUMBER_OF_CORES > 1 + typedef struct { uint32_t count; TaskHandle_t main; -} ParamsHWLP; +} hwlp_params_t; -void calculation(void* arg) +static void calculation(void* arg) { - ParamsHWLP* p = (ParamsHWLP*) arg; + hwlp_params_t* p = (hwlp_params_t*) arg; const uint32_t count = p->count; uint32_t result = 0; int i = 0; - for (i = 0; i < 10; i++) { + for (i = 0; i < 50000; i++) { uint32_t current = use_hwlp(count); result += current; - /* Give some time to the other to interrupt us before checking `f` value */ - esp_rom_delay_us(1000); - /* Using TEST_ASSERT_TRUE triggers a stack overflow, make sure the count is still correct. * The function `use_hwlp` should return (count * 16) */ assert(count * 16 == current); - - /* Give the hand back to FreeRTOS to avoid any watchdog error */ - vTaskDelay(2); } /* Make sure the result is correct */ @@ -131,14 +72,14 @@ void calculation(void* arg) vTaskDelete(NULL); } -TEST_CASE("HWLP: Unsolicited context switch between tasks using the PIE", "[freertos]") +TEST_CASE("HWLP: Unsolicited context switch between tasks using HWLP", "[freertos]") { /* Create two tasks that are on the same core and use the same FPU */ TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); TaskHandle_t tasks[2]; - ParamsHWLP params[2] = { - { .count = 10, .main = unity_task_handle }, - { .count = 200, .main = unity_task_handle }, + hwlp_params_t params[2] = { + { .count = 1024, .main = unity_task_handle }, + { .count = 2048, .main = unity_task_handle }, }; xTaskCreatePinnedToCore(calculation, "Task1", 2048, params + 0, CONFIG_UNITY_FREERTOS_PRIORITY + 1, &tasks[0], 1); @@ -148,4 +89,6 @@ TEST_CASE("HWLP: Unsolicited context switch between tasks using the PIE", "[free ulTaskNotifyTake(pdTRUE, portMAX_DELAY); } +#endif /* CONFIG_FREERTOS_NUMBER_OF_CORES > 1 */ + #endif // SOC_CPU_HAS_HWLOOP diff --git a/components/freertos/test_apps/freertos/port/test_hwlp_routines.S b/components/freertos/test_apps/freertos/port/test_hwlp_routines.S new file mode 100644 index 00000000000..80bd9557764 --- /dev/null +++ b/components/freertos/test_apps/freertos/port/test_hwlp_routines.S @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +#if SOC_CPU_HAS_HWLOOP + + .text + .align 4 + +/** + * @brief Perform a hardware loop with a given number of iterations + * + * @param a0 Number of iterations + */ + .global use_hwlp + .type use_hwlp, @function +use_hwlp: + /* The toolchain doesn't support HWLP instructions yet, manually set it up */ + la a2, start + csrw 0x7c6, a2 + la a2, end + csrw 0x7c7, a2 + csrw 0x7c8, a0 + li a1, 0 + /* Hardware loops must have at least 8 32-bit instructions or 16 16-bit instructions */ +start: + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 + addi a1, a1, 1 +end: + addi a1, a1, 1 + mv a0, a1 + ret + .size use_hwlp, .-use_hwlp + +#endif /* SOC_CPU_HAS_HWLOOP */ diff --git a/components/freertos/test_apps/freertos/port/test_pie_in_task.c b/components/freertos/test_apps/freertos/port/test_pie_in_task.c index c5f632ed91b..aa9bcf658e5 100644 --- a/components/freertos/test_apps/freertos/port/test_pie_in_task.c +++ b/components/freertos/test_apps/freertos/port/test_pie_in_task.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,28 +13,26 @@ #include "unity.h" #include "test_utils.h" +/* PIE instructions set is currently only supported in GCC compiler */ #if SOC_CPU_HAS_PIE /** - * @brief Performs the sum of two 4-word vectors using the PIE. + * @brief Performs the signed sum of two 4-word vectors using the PIE. * * @param a First vector * @param b Second vector * @param dst Destination to store the sum - * - * @returns a will store a + b */ -static void pie_vector_add(const int32_t a[4], const int32_t b[4], int32_t dst[4]) -{ - asm volatile("esp.vld.128.ip q0, a0, 0\n" - "esp.vld.128.ip q1, a1, 0\n" - "esp.vadd.s32 q2, q0, q1\n" - "esp.vst.128.ip q2, a2, 0\n" - ::); -} +void pie_vector_signed_add(const int32_t a[4], const int32_t b[4], int32_t dst[4]); /* ------------------------------------------------------------------------------------------------------------------ */ +typedef struct { + int32_t cst; + TaskHandle_t main; + SemaphoreHandle_t sem; +} pie_params_t; + /* Test PIE usage from a task context @@ -59,16 +57,22 @@ Test PIE usage from a task context static void pinned_task(void *arg) { + pie_params_t *param = (pie_params_t*) arg; ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - int32_t a[4] = { 42, 42, 42, 42}; + int32_t constant = 42 * param->cst; + int32_t a[4] = { constant, constant, constant, constant }; int32_t b[4] = { 10, 20, 30, 40 }; int32_t dst[4] = { 0 }; - pie_vector_add(a, b, dst); + pie_vector_signed_add(a, b, dst); + + for (int i = 0; i < sizeof(a) / sizeof(uint32_t); i++) { + TEST_ASSERT_EQUAL(dst[i], a[i] + b[i]); + } - // Indicate done wand wait to be deleted - xSemaphoreGive((SemaphoreHandle_t)arg); + // Indicate done and wait to be deleted + xSemaphoreGive((SemaphoreHandle_t)param->sem); vTaskSuspend(NULL); } @@ -79,15 +83,20 @@ TEST_CASE("PIE: Usage in task", "[freertos]") for (int iter = 0; iter < TEST_PINNED_NUM_ITERS; iter++) { TaskHandle_t task_handles[CONFIG_FREERTOS_NUMBER_OF_CORES][TEST_PINNED_NUM_TASKS]; + pie_params_t params[CONFIG_FREERTOS_NUMBER_OF_CORES][TEST_PINNED_NUM_TASKS]; // Create test tasks for each core for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { for (int j = 0; j < TEST_PINNED_NUM_TASKS; j++) { - TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(pinned_task, "task", 4096, (void *)done_sem, UNITY_FREERTOS_PRIORITY + 1, &task_handles[i][j], i)); + params[i][j] = (pie_params_t) { + .cst = i + j + 1, + .sem = done_sem, + }; + TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(pinned_task, "task", 4096, (void *) ¶ms[i][j], UNITY_FREERTOS_PRIORITY + 1, &task_handles[i][j], i)); } } - // Start the created tasks simultaneously + // Start the created tasks for (int i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES; i++) { for (int j = 0; j < TEST_PINNED_NUM_TASKS; j++) { xTaskNotifyGive(task_handles[i][j]); @@ -159,7 +168,7 @@ static void unpinned_task(void *arg) int32_t b[4] = { 111, 222, 333, 444 }; int32_t dst[4] = { 0 }; - pie_vector_add(a, b, dst); + pie_vector_signed_add(a, b, dst); for (int i = 0; i < sizeof(a) / sizeof(uint32_t); i++) { TEST_ASSERT_EQUAL(dst[i], a[i] + b[i]); @@ -196,24 +205,19 @@ TEST_CASE("PIE: Usage in unpinned task", "[freertos]") } } -typedef struct { - int32_t cst; - TaskHandle_t main; -} ParamsPIE; - /** * @brief Function performing some simple calculation using the PIE coprocessor. * The goal is to be preempted by a task that also uses the PIE on the same core. */ -void pie_calculation(void* arg) +static void pie_calculation(void* arg) { - ParamsPIE* p = (ParamsPIE*) arg; + pie_params_t* p = (pie_params_t*) arg; const int32_t cst = p->cst; int32_t a[4] = { cst, cst, cst, cst }; int32_t dst[4] = { 0 }; for (int i = 0; i < 10; i++) { - pie_vector_add(a, dst, dst); + pie_vector_signed_add(a, dst, dst); /* Give some time to the other to interrupt us before checking `f` value */ esp_rom_delay_us(1000); @@ -237,7 +241,7 @@ TEST_CASE("PIE: Unsolicited context switch between tasks using the PIE", "[freer /* Create two tasks that are on the same core and use the same FPU */ TaskHandle_t unity_task_handle = xTaskGetCurrentTaskHandle(); TaskHandle_t tasks[2]; - ParamsPIE params[2] = { + pie_params_t params[2] = { { .cst = 1, .main = unity_task_handle }, { .cst = -1, .main = unity_task_handle }, }; @@ -249,5 +253,6 @@ TEST_CASE("PIE: Unsolicited context switch between tasks using the PIE", "[freer ulTaskNotifyTake(pdTRUE, portMAX_DELAY); } -#endif // CONFIG_FREERTOS_NUMBER_OF_CORES > 1 -#endif // SOC_CPU_HAS_PIE +#endif /* CONFIG_FREERTOS_NUMBER_OF_CORES > 1 */ + +#endif /* SOC_CPU_HAS_PIE */ diff --git a/components/freertos/test_apps/freertos/port/test_pie_routines.S b/components/freertos/test_apps/freertos/port/test_pie_routines.S new file mode 100644 index 00000000000..7de3a4da28a --- /dev/null +++ b/components/freertos/test_apps/freertos/port/test_pie_routines.S @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "soc/soc_caps.h" + +/* PIE instructions set is currently only supported in GCC compiler */ +#if SOC_CPU_HAS_PIE + + .text + .align 4 + +/** + * @brief Performs the unsigned sum of two 4-word vectors using the PIE. + * + * @param a0 First vector + * @param a1 Second vector + * @param a2 Destination to store the sum + */ + .type pie_vector_unsigned_add, @function + .global pie_vector_unsigned_add +pie_vector_unsigned_add: + esp.vld.128.ip q0, a0, 0 + esp.vld.128.ip q1, a1, 0 + esp.vadd.u32 q2, q0, q1 + esp.vst.128.ip q2, a2, 0 + ret + .size pie_vector_unsigned_add, .-pie_vector_unsigned_add + + +/** + * @brief Performs the signed sum of two 4-word vectors using the PIE. + * + * @param a0 First vector + * @param a1 Second vector + * @param a2 Destination to store the sum + */ + .type pie_vector_signed_add, @function + .global pie_vector_signed_add +pie_vector_signed_add: + esp.vld.128.ip q0, a0, 0 + esp.vld.128.ip q1, a1, 0 + esp.vadd.s32 q2, q0, q1 + esp.vst.128.ip q2, a2, 0 + ret + .size pie_vector_signed_add, .-pie_vector_signed_add + +#endif /* SOC_CPU_HAS_PIE */ diff --git a/components/freertos/test_apps/freertos/port/test_pie_watermark.c b/components/freertos/test_apps/freertos/port/test_pie_watermark.c index 5f5725cf293..075b40b34f5 100644 --- a/components/freertos/test_apps/freertos/port/test_pie_watermark.c +++ b/components/freertos/test_apps/freertos/port/test_pie_watermark.c @@ -21,23 +21,24 @@ */ #if SOC_CPU_HAS_PIE -static void use_pie(uint32_t a[4], uint32_t b[4]) -{ - asm volatile("esp.vld.128.ip q0, %0, 0\n" - "esp.vld.128.ip q1, %2, 0\n" - "esp.vadd.u32 q2, q0, q1\n" - "esp.vst.128.ip q2, %0, 0\n" - : "=r"(a) : "r"(a), "r"(b)); -} +/** + * @brief Performs the signed sum of two 4-word vectors using the PIE. + * + * @param a First vector + * @param b Second vector + * @param dst Destination to store the sum + */ +void pie_vector_unsigned_add(const uint32_t a[4], const uint32_t b[4], uint32_t dst[4]); static void other_task(void* arg) { uint32_t a[4] = { 1, 2, 3, 4}; uint32_t b[4] = { 42, 43, 44, 45}; + uint32_t dst[4] = { 0 }; const TaskHandle_t main_task = (TaskHandle_t) arg; /* This task must also use the PIE coprocessor to force a PIE context flush on the main task */ - use_pie(a, b); + pie_vector_unsigned_add(a, b, dst); xTaskNotifyGive(main_task); vTaskDelete(NULL); @@ -48,6 +49,7 @@ TEST_CASE("PIE: Context save does not affect stack watermark", "[freertos]") /* Setup some random values */ uint32_t a[4] = { 0x3f00ffff, 0xffe10045, 0xffe10096, 0x42434546}; uint32_t b[4] = { 0x42, 0xbb43, 0x6644, 0x845}; + uint32_t dst[4] = { 0 }; TaskHandle_t pvCreatedTask; /* Force the FreeRTOS port layer to store a PIE context in the current task. @@ -59,7 +61,7 @@ TEST_CASE("PIE: Context save does not affect stack watermark", "[freertos]") const UBaseType_t before_watermark = uxTaskGetStackHighWaterMark(current_handle); /* Use the PIE unit, the context will NOT be flushed until another task starts using it */ - use_pie(a, b); + pie_vector_unsigned_add(a, b, dst); xTaskCreatePinnedToCore(other_task, "OtherTask", diff --git a/components/riscv/include/riscv/csr_hwlp.h b/components/riscv/include/riscv/csr_hwlp.h index 91c946a50a3..83a44ea4413 100644 --- a/components/riscv/include/riscv/csr_hwlp.h +++ b/components/riscv/include/riscv/csr_hwlp.h @@ -18,6 +18,11 @@ */ #define CSR_HWLP_STATE_REG 0x7F1 +#define HWLP_OFF_STATE 0 +#define HWLP_INITIAL_STATE 1 +#define HWLP_CLEAN_STATE 2 +#define HWLP_DIRTY_STATE 3 + #define CSR_LOOP0_START_ADDR 0x7C6 #define CSR_LOOP0_END_ADDR 0x7C7 #define CSR_LOOP0_COUNT 0x7C8 diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 716fee6e80b..c0d3a64b2f0 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -14,6 +14,7 @@ #include "esp_attr.h" #include "riscv/csr.h" #include "riscv/interrupt.h" +#include "riscv/csr_pie.h" #ifdef __cplusplus extern "C" { @@ -168,6 +169,27 @@ FORCE_INLINE_ATTR void rv_utils_disable_fpu(void) #endif /* SOC_CPU_HAS_FPU */ +/* ------------------------------------------------- PIE Related ---------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ + +#if SOC_CPU_HAS_PIE + +FORCE_INLINE_ATTR void rv_utils_enable_pie(void) +{ + RV_WRITE_CSR(CSR_PIE_STATE_REG, 1); +} + + +FORCE_INLINE_ATTR void rv_utils_disable_pie(void) +{ + RV_WRITE_CSR(CSR_PIE_STATE_REG, 0); +} + +#endif /* SOC_CPU_HAS_FPU */ + + + /* -------------------------------------------------- Memory Ports ----------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index 4a5db19afdb..058877f8ed6 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -168,17 +168,12 @@ _panic_handler: /* EXT_ILL CSR should contain the reason for the Illegal Instruction */ csrrw a0, EXT_ILL_CSR, zero -#if SOC_CPU_HAS_HWLOOP - /* Check if the HWLOOP bit is set. */ - andi a1, a0, EXT_ILL_RSN_HWLP - bnez a1, rtos_save_hwlp_coproc -#endif // SOC_CPU_HAS_HWLOOP - + /* Hardware loop cannot be treated lazily, so we should never end here if a HWLP instruction is used */ #if SOC_CPU_HAS_PIE - /* Check if the HWLOOP bit is set. */ + /* Check if the PIE bit is set. */ andi a1, a0, EXT_ILL_RSN_PIE bnez a1, rtos_save_pie_coproc -#endif // SOC_CPU_HAS_HWLOOP +#endif /* SOC_CPU_HAS_PIE */ #if SOC_CPU_HAS_FPU /* Check if the FPU bit is set. When targets have the FPU reason bug (SOC_CPU_HAS_FPU_EXT_ILL_BUG), diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b65d924e3f6..2d25d7f982b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -403,6 +403,10 @@ config SOC_BRANCH_PREDICTOR_SUPPORTED bool default y +config SOC_CPU_COPROC_NUM + int + default 3 + config SOC_CPU_HAS_FPU bool default y @@ -419,10 +423,6 @@ config SOC_CPU_HAS_PIE bool default y -config SOC_CPU_COPROC_NUM - int - default 3 - config SOC_HP_CPU_HAS_MULTIPLE_CORES bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index a708d9cd748..e0a8f06cf3c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -157,11 +157,15 @@ #define SOC_INT_CLIC_SUPPORTED 1 #define SOC_INT_HW_NESTED_SUPPORTED 1 // Support for hardware interrupts nesting #define SOC_BRANCH_PREDICTOR_SUPPORTED 1 +#define SOC_CPU_COPROC_NUM 3 #define SOC_CPU_HAS_FPU 1 #define SOC_CPU_HAS_FPU_EXT_ILL_BUG 1 // EXT_ILL CSR doesn't support FLW/FSW #define SOC_CPU_HAS_HWLOOP 1 +/* PIE coprocessor assembly is only supported with GCC compiler */ +#ifndef __clang__ #define SOC_CPU_HAS_PIE 1 -#define SOC_CPU_COPROC_NUM 3 +#endif + #define SOC_HP_CPU_HAS_MULTIPLE_CORES 1 // Convenience boolean macro used to determine if a target has multiple cores. #define SOC_CPU_BREAKPOINTS_NUM 3 From 2f10ca582b537ca4b03e693a832f7e25042d897e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Wed, 8 May 2024 11:52:11 +0200 Subject: [PATCH 133/548] fix(storage): Fix SD card examples for SoCs with SOC_SDMMC_IO_POWER_EXTERNAL 1 --- examples/storage/perf_benchmark/README.md | 31 ++++++++++++---- .../perf_benchmark/main/Kconfig.projbuild | 22 +++++++++++ .../main/perf_benchmark_example_sd_utils.c | 37 +++++++++++++++++++ examples/storage/sd_card/sdmmc/README.md | 6 ++- .../sd_card/sdmmc/main/Kconfig.projbuild | 17 +++++---- .../sd_card/sdmmc/main/sd_card_example_main.c | 24 ++++++------ .../sdmmc/pytest_sdmmc_card_example.py | 4 +- examples/storage/sd_card/sdspi/README.md | 34 ++++++++++++++--- .../sd_card/sdspi/main/Kconfig.projbuild | 15 ++++++++ .../sd_card/sdspi/main/sd_card_example_main.c | 32 +++++++++++++++- .../sdspi/pytest_sdspi_card_example.py | 4 +- 11 files changed, 185 insertions(+), 41 deletions(-) diff --git a/examples/storage/perf_benchmark/README.md b/examples/storage/perf_benchmark/README.md index fefb02b31f2..d3f4f6b5d17 100644 --- a/examples/storage/perf_benchmark/README.md +++ b/examples/storage/perf_benchmark/README.md @@ -54,14 +54,14 @@ This example doesn't utilize card detect (CD) and write protect (WP) signals fro The table below shows the default pin assignments. -SD card pin | SPI pin | ESP32 pin | ESP32-S2 | ESP32-S3 | ESP32-H2 | ESP32-C3 and other chips | Notes -------------|---------|---------------|----------|----------|----------|--------------------------|------------- - D0 | MISO | GPIO2 | GPIO37 | GPIO37 | GPIO0 | GPIO6 | 10k pullup - D1 | - | GPIO4 | - | GPIO38 | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode - D2 | - | GPIO12 (MTDI) | - | GPIO33 | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode - D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO34 | GPIO1 | GPIO1 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup - CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO36 | GPIO4 | GPIO5 | 10k pullup - CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO35 | GPIO5 | GPIO4 | 10k pullup +SD card pin | SPI pin | ESP32 pin | ESP32-S2 | ESP32-S3 | ESP32-P4 SDMMC | ESP32-P4 SDSPI | ESP32-H2 | ESP32-C3 and other chips | Notes +------------|---------|---------------|----------|----------|----------------|----------------|----------|--------------------------|------------- + D0 | MISO | GPIO2 | GPIO37 | GPIO37 | GPIO43 | GPIO13 | GPIO0 | GPIO6 | 10k pullup + D1 | - | GPIO4 | - | GPIO38 | GPIO44 | - | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode + D2 | - | GPIO12 (MTDI) | - | GPIO33 | GPIO39 | - | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode + D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO34 | GPIO40 | GPIO10 | GPIO1 | GPIO1 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup + CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO36 | GPIO41 | GPIO12 | GPIO4 | GPIO5 | 10k pullup + CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO35 | GPIO42 | GPIO11 | GPIO5 | GPIO4 | 10k pullup ### 4-line and 1-line SD modes @@ -97,6 +97,21 @@ This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and `XPD_SDIO_REG` See [the document about pullup requirements](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/sd_pullup_requirements.html) for more details about pullup support and compatibility of modules and development boards. +#### ESP32-P4 related notes + +This only applies when `Test SD card` setting in `Performance Benchmark Example Configuration` is enabled. + +On ESP32-P4, Slot 1 of the SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways: + +1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open `Performance Benchmark Example Configuration` menu. +2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code. + +If pins selected correspond with default pins used for ESP32-P4 SDMMC (i.e. SD card slot is connected to them), possibly an additional setting up needs to be done. + +These pins are able to connect to an ultra high-speed SD card (UHS-I) which requires 1.8V switching (instead of the regular 3.3V). This means the user has to provide an external LDO power supply to use them, or to enable and configure an internal LDO via `idf.py menuconfig` -> `SD/MMC Example Configuration` -> `SD power supply comes from internal LDO IO`. + +When using different GPIO pins this is not required and `SD power supply comes from internal LDO IO` setting can be disabled. + ### Note about SPIFFS The test for SPIFFS is run only once, because SPIFFS has a problem with deleting files. diff --git a/examples/storage/perf_benchmark/main/Kconfig.projbuild b/examples/storage/perf_benchmark/main/Kconfig.projbuild index e12a3268ab7..82debaba8f0 100644 --- a/examples/storage/perf_benchmark/main/Kconfig.projbuild +++ b/examples/storage/perf_benchmark/main/Kconfig.projbuild @@ -179,28 +179,34 @@ menu "Performance Benchmark Example Configuration" config EXAMPLE_PIN_CMD int "CMD GPIO number" default 35 if IDF_TARGET_ESP32S3 + default 44 if IDF_TARGET_ESP32P4 config EXAMPLE_PIN_CLK int "CLK GPIO number" default 36 if IDF_TARGET_ESP32S3 + default 43 if IDF_TARGET_ESP32P4 config EXAMPLE_PIN_D0 int "D0 GPIO number" default 37 if IDF_TARGET_ESP32S3 + default 39 if IDF_TARGET_ESP32P4 if EXAMPLE_SDMMC_BUS_WIDTH_4 config EXAMPLE_PIN_D1 int "D1 GPIO number" default 38 if IDF_TARGET_ESP32S3 + default 40 if IDF_TARGET_ESP32P4 config EXAMPLE_PIN_D2 int "D2 GPIO number" default 33 if IDF_TARGET_ESP32S3 + default 41 if IDF_TARGET_ESP32P4 config EXAMPLE_PIN_D3 int "D3 GPIO number" default 34 if IDF_TARGET_ESP32S3 + default 42 if IDF_TARGET_ESP32P4 endif # EXAMPLE_SDMMC_BUS_WIDTH_4 @@ -243,6 +249,22 @@ menu "Performance Benchmark Example Configuration" endif # EXAMPLE_USE_SDSPI + config EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + depends on SOC_SDMMC_IO_POWER_EXTERNAL + bool "SD power supply comes from internal LDO IO (READ HELP!)" + default y + help + Only needed when the SD card is connected to specific IO pins which can be used for high-speed SDMMC. + Please read the schematic first and check if the SD VDD is connected to any internal LDO output. + Unselect this option if the SD card is powered by an external power supply. + + config EXAMPLE_SD_PWR_CTRL_LDO_IO_ID + depends on SOC_SDMMC_IO_POWER_EXTERNAL && EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + int "LDO ID" + default 4 if IDF_TARGET_ESP32P4 + help + Please read the schematic first and input your LDO ID. + endmenu # "SD card test config" endmenu # "Performance Monitor Example Configuration" diff --git a/examples/storage/perf_benchmark/main/perf_benchmark_example_sd_utils.c b/examples/storage/perf_benchmark/main/perf_benchmark_example_sd_utils.c index bfd64778869..9979d6d821d 100644 --- a/examples/storage/perf_benchmark/main/perf_benchmark_example_sd_utils.c +++ b/examples/storage/perf_benchmark/main/perf_benchmark_example_sd_utils.c @@ -13,6 +13,10 @@ #if SOC_SDMMC_HOST_SUPPORTED #include "driver/sdmmc_host.h" #endif +#if SOC_SDMMC_IO_POWER_EXTERNAL +#include "sd_pwr_ctrl_by_on_chip_ldo.h" +#endif +#include "esp_err.h" #include "esp_log.h" #ifdef CONFIG_EXAMPLE_TEST_SD_CARD @@ -32,6 +36,22 @@ void init_sd_config(sdmmc_host_t *out_host, sdmmc_slot_config_t *out_slot_config void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_config, int freq_khz) { #endif // CONFIG_EXAMPLE_USE_SDSPI + // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply. + // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card + // and the internal LDO power supply, we need to initialize the power supply first. +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + sd_pwr_ctrl_ldo_config_t ldo_config = { + .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID, + }; + sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; + + esp_err_t sd_pwr_ctrl_ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle); + if (sd_pwr_ctrl_ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to create a new an on-chip LDO power control driver"); + ESP_ERROR_CHECK(sd_pwr_ctrl_ret); + } +#endif // CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) // For setting a specific frequency, use host.max_freq_khz // (range 400kHz - 40MHz for SDMMC, 400kHz - 20MHz for SDSPI) @@ -91,6 +111,11 @@ void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_conf slot_config.gpio_cs = CONFIG_EXAMPLE_PIN_CS; slot_config.host_id = host.slot; #endif // CONFIG_EXAMPLE_USE_SDSPI + +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + host.pwr_ctrl_handle = pwr_ctrl_handle; +#endif // CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + *out_host = host; *out_slot_config = slot_config; } @@ -137,6 +162,18 @@ void deinit_sd_card(sdmmc_card_t **card) { #else // CONFIG_EXAMPLE_USE_SDMMC sdspi_host_deinit(); #endif // CONFIG_EXAMPLE_USE_SDSPI + + // Deinitialize the power control driver if it was used +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + sd_pwr_ctrl_handle_t pwr_ctrl_handle = (*card)->host.pwr_ctrl_handle; + esp_err_t ret = sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to delete the on-chip LDO power control driver"); + ESP_ERROR_CHECK(ret); + } + pwr_ctrl_handle = NULL; +#endif + free(*card); *card = NULL; } diff --git a/examples/storage/sd_card/sdmmc/README.md b/examples/storage/sd_card/sdmmc/README.md index 3e5006020b0..8f665f208e0 100644 --- a/examples/storage/sd_card/sdmmc/README.md +++ b/examples/storage/sd_card/sdmmc/README.md @@ -70,7 +70,7 @@ GPIO34 | D3 | not used in 1-line SD mode, but card's D3 pin must On ESP32-P4, Slot 1 of the SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways: -1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open "SD/MMC Example Configuration" menu. +1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open `SD/MMC Example Configuration` menu. 2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code. The table below lists the default pin assignments. @@ -84,6 +84,10 @@ GPIO40 | D1 | not used in 1-line SD mode; 10k pullup in 4-line m GPIO41 | D2 | not used in 1-line SD mode; 10k pullup in 4-line mode GPIO42 | D3 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup +Default dedicated pins on ESP32-P4 are able to connect to an ultra high-speed SD card (UHS-I) which requires 1.8V switching (instead of the regular 3.3V). This means the user has to provide an external LDO power supply to use them, or to enable and configure an internal LDO via `idf.py menuconfig` -> `SD/MMC Example Configuration` -> `SD power supply comes from internal LDO IO`. + +When using different GPIO pins this is not required and `SD power supply comes from internal LDO IO` setting can be disabled. + ### 4-line and 1-line SD modes By default, this example uses 4 line SD mode, utilizing 6 pins: CLK, CMD, D0 - D3. It is possible to use 1-line mode (CLK, CMD, D0) by changing "SD/MMC bus width" in the example configuration menu (see `CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1`). diff --git a/examples/storage/sd_card/sdmmc/main/Kconfig.projbuild b/examples/storage/sd_card/sdmmc/main/Kconfig.projbuild index 3e74dfacf75..70449a8e395 100644 --- a/examples/storage/sd_card/sdmmc/main/Kconfig.projbuild +++ b/examples/storage/sd_card/sdmmc/main/Kconfig.projbuild @@ -152,18 +152,19 @@ menu "SD/MMC Example Configuration" endif # EXAMPLE_SDMMC_BUS_WIDTH_4 - config EXAMPLE_SDMMC_IO_POWER_INTERNAL_LDO + config EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO depends on SOC_SDMMC_IO_POWER_EXTERNAL - bool "SDMMC IO power supply comes from internal LDO (READ HELP!)" + bool "SD power supply comes from internal LDO IO (READ HELP!)" default y help - Please read the schematic first and check if the SDMMC VDD is connected to any internal LDO output. - If the SDMMC is powered by an external supplier, unselect me + Only needed when the SD card is connected to specific IO pins which can be used for high-speed SDMMC. + Please read the schematic first and check if the SD VDD is connected to any internal LDO output. + Unselect this option if the SD card is powered by an external power supply. - config EXAMPLE_SDMMC_IO_LDO_ID - depends on SOC_SDMMC_IO_POWER_EXTERNAL + config EXAMPLE_SD_PWR_CTRL_LDO_IO_ID + depends on SOC_SDMMC_IO_POWER_EXTERNAL && EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO int "LDO ID" - default 4 + default 4 if IDF_TARGET_ESP32P4 help - Please read the schematic first and input your LDO ID + Please read the schematic first and input your LDO ID. endmenu diff --git a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c index e752d3a3cbb..6821d05fb24 100644 --- a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c +++ b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c @@ -15,7 +15,9 @@ #include "sdmmc_cmd.h" #include "driver/sdmmc_host.h" #include "sd_test_io.h" +#if SOC_SDMMC_IO_POWER_EXTERNAL #include "sd_pwr_ctrl_by_on_chip_ldo.h" +#endif #define EXAMPLE_MAX_CHAR_SIZE 64 @@ -127,18 +129,18 @@ void app_main(void) // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; sdmmc_host_t host = SDMMC_HOST_DEFAULT(); - /** - * On these chips, the SDMMC IO power is supplied externally - */ -#if CONFIG_EXAMPLE_SDMMC_IO_POWER_INTERNAL_LDO + // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply. + // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card + // and the internal LDO power supply, we need to initialize the power supply first. +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO sd_pwr_ctrl_ldo_config_t ldo_config = { - .ldo_chan_id = 4, // `LDO_VO4` is used as the SDMMC IO power + .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID, }; sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to new an on-chip ldo power control driver"); + ESP_LOGE(TAG, "Failed to create a new on-chip LDO power control driver"); return; } host.pwr_ctrl_handle = pwr_ctrl_handle; @@ -237,7 +239,7 @@ void app_main(void) ESP_LOGI(TAG, "file still exists"); return; } else { - ESP_LOGI(TAG, "file doesnt exist, format done"); + ESP_LOGI(TAG, "file doesn't exist, formatting done"); } #endif // CONFIG_EXAMPLE_FORMAT_SD_CARD @@ -257,14 +259,14 @@ void app_main(void) // All done, unmount partition and disable SDMMC peripheral esp_vfs_fat_sdcard_unmount(mount_point, card); + ESP_LOGI(TAG, "Card unmounted"); -#if SOC_SDMMC_IO_POWER_EXTERNAL + // Deinitialize the power control driver if it was used +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO ret = sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle); if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to delete on-chip ldo power control driver"); + ESP_LOGE(TAG, "Failed to delete the on-chip LDO power control driver"); return; } #endif - - ESP_LOGI(TAG, "Card unmounted"); } diff --git a/examples/storage/sd_card/sdmmc/pytest_sdmmc_card_example.py b/examples/storage/sd_card/sdmmc/pytest_sdmmc_card_example.py index 0a1685e8732..d6bbb9bb55e 100644 --- a/examples/storage/sd_card/sdmmc/pytest_sdmmc_card_example.py +++ b/examples/storage/sd_card/sdmmc/pytest_sdmmc_card_example.py @@ -1,7 +1,5 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 - - import logging import re @@ -32,7 +30,7 @@ def test_examples_sd_card_sdmmc(dut: Dut) -> None: 'Reading file /sdcard/foo.txt', "Read from file: 'Hello {}!'".format(name)) sd_card_format = re.compile(str.encode('Formatting card, allocation unit size=\\S+')) - message_list2 = ('file doesnt exist, format done', + message_list2 = ("file doesn't exist, formatting done", 'Opening file /sdcard/nihao.txt', 'File written', 'Reading file /sdcard/nihao.txt', diff --git a/examples/storage/sd_card/sdspi/README.md b/examples/storage/sd_card/sdspi/README.md index 4e52527838e..1432abf5579 100644 --- a/examples/storage/sd_card/sdspi/README.md +++ b/examples/storage/sd_card/sdspi/README.md @@ -41,12 +41,12 @@ This example doesn't utilize card detect (CD) and write protect (WP) signals fro The table below shows the default pin assignments. -SD card pin | SPI pin | ESP32 pin | ESP32-S2, ESP32-S3 | ESP32-H2 | ESP32-C3 and other chips | Notes -------------|---------|---------------|--------------------|----------|---------------------------|------------- - D0 | MISO | GPIO2 | GPIO37 | GPIO0 | GPIO6 | - D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO1 | GPIO1 | - CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO4 | GPIO5 | - CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO5 | GPIO4 | 10k pullup +SD card pin | SPI pin | ESP32 pin | ESP32-S2, ESP32-S3 | ESP32-P4 | ESP32-H2 | ESP32-C3 and other chips | Notes +------------|---------|---------------|--------------------|----------|----------|--------------------------|------------ + D0 | MISO | GPIO2 | GPIO37 | GPIO13 | GPIO0 | GPIO6 | + D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO10 | GPIO1 | GPIO1 | + CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO12 | GPIO4 | GPIO5 | + CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO11 | GPIO5 | GPIO4 | 10k pullup #### ESP32 related notes @@ -63,6 +63,28 @@ With the default pin assignments, this example is compatible ESP32-S2-USB-OTG an For other development boards, adjust the pin assignments as explained above. +#### ESP32-P4 related notes + +On ESP32-P4, Slot 1 of the SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways: + +1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open `SD SPI Example Configuration` menu. +2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code. + +Default pins for SDSPI are listed in the table above [Pin assignments](#1-pin-assignments) and using them doesn't require any additional settings. + +However on some development boards the SD card slot can be wired to default dedicated pins for SDMMC, which are listed in the table below. + +SD card pin | ESP32-P4 pin +------------|-------------- +D0 (MISO) | GPIO39 +D3 (CS) | GPIO42 +CLK (SCK) | GPIO43 +CMD (MOSI) | GPIO44 + +These pins are able to connect to an ultra high-speed SD card (UHS-I) which requires 1.8V switching (instead of the regular 3.3V). This means the user has to provide an external LDO power supply to use them, or to enable and configure an internal LDO via `idf.py menuconfig` -> `SD/MMC Example Configuration` -> `SD power supply comes from internal LDO IO`. + +When using different GPIO pins this is not required and `SD power supply comes from internal LDO IO` setting can be disabled. + #### Notes for ESP32-C3 and other chips Espressif doesn't offer development boards with an SD card slot for these chips. Please check the pin assignments and adjust them for your board if necessary. The process to change pin assignments is described above. diff --git a/examples/storage/sd_card/sdspi/main/Kconfig.projbuild b/examples/storage/sd_card/sdspi/main/Kconfig.projbuild index 64f1c561e0b..77fd451ed70 100644 --- a/examples/storage/sd_card/sdspi/main/Kconfig.projbuild +++ b/examples/storage/sd_card/sdspi/main/Kconfig.projbuild @@ -93,4 +93,19 @@ menu "SD SPI Example Configuration" default 6 if IDF_TARGET_ESP32S3 default 1 + config EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + depends on SOC_SDMMC_IO_POWER_EXTERNAL + bool "SD power supply comes from internal LDO IO (READ HELP!)" + default n + help + Only needed when the SD card is connected to specific IO pins which can be used for high-speed SDMMC. + Please read the schematic first and check if the SD VDD is connected to any internal LDO output. + Unselect this option if the SD card is powered by an external power supply. + + config EXAMPLE_SD_PWR_CTRL_LDO_IO_ID + depends on SOC_SDMMC_IO_POWER_EXTERNAL && EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + int "LDO ID" + default 4 if IDF_TARGET_ESP32P4 + help + Please read the schematic first and input your LDO ID. endmenu diff --git a/examples/storage/sd_card/sdspi/main/sd_card_example_main.c b/examples/storage/sd_card/sdspi/main/sd_card_example_main.c index d5edc7503ec..7f3a339e416 100644 --- a/examples/storage/sd_card/sdspi/main/sd_card_example_main.c +++ b/examples/storage/sd_card/sdspi/main/sd_card_example_main.c @@ -14,6 +14,9 @@ #include "esp_vfs_fat.h" #include "sdmmc_cmd.h" #include "sd_test_io.h" +#if SOC_SDMMC_IO_POWER_EXTERNAL +#include "sd_pwr_ctrl_by_on_chip_ldo.h" +#endif #define EXAMPLE_MAX_CHAR_SIZE 64 @@ -120,6 +123,23 @@ void app_main(void) // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply. + // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card + // and the internal LDO power supply, we need to initialize the power supply first. +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + sd_pwr_ctrl_ldo_config_t ldo_config = { + .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID, + }; + sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; + + ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to create a new on-chip LDO power control driver"); + return; + } + host.pwr_ctrl_handle = pwr_ctrl_handle; +#endif + spi_bus_config_t bus_cfg = { .mosi_io_num = PIN_NUM_MOSI, .miso_io_num = PIN_NUM_MISO, @@ -128,6 +148,7 @@ void app_main(void) .quadhd_io_num = -1, .max_transfer_sz = 4000, }; + ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize bus."); @@ -205,7 +226,7 @@ void app_main(void) ESP_LOGI(TAG, "file still exists"); return; } else { - ESP_LOGI(TAG, "file doesnt exist, format done"); + ESP_LOGI(TAG, "file doesn't exist, formatting done"); } #endif // CONFIG_EXAMPLE_FORMAT_SD_CARD @@ -229,4 +250,13 @@ void app_main(void) //deinitialize the bus after all devices are removed spi_bus_free(host.slot); + + // Deinitialize the power control driver if it was used +#if CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_INTERNAL_IO + ret = sd_pwr_ctrl_del_on_chip_ldo(pwr_ctrl_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to delete the on-chip LDO power control driver"); + return; + } +#endif } diff --git a/examples/storage/sd_card/sdspi/pytest_sdspi_card_example.py b/examples/storage/sd_card/sdspi/pytest_sdspi_card_example.py index 4f2b42bb58e..ddec7002bf1 100644 --- a/examples/storage/sd_card/sdspi/pytest_sdspi_card_example.py +++ b/examples/storage/sd_card/sdspi/pytest_sdspi_card_example.py @@ -1,7 +1,5 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 - - import logging import re @@ -33,7 +31,7 @@ def test_examples_sd_card_sdspi(dut: Dut) -> None: 'Reading file /sdcard/foo.txt', "Read from file: 'Hello {}!'".format(name)) sd_card_format = re.compile(str.encode('Formatting card, allocation unit size=\\S+')) - message_list2 = ('file doesnt exist, format done', + message_list2 = ("file doesn't exist, formatting done", 'Opening file /sdcard/nihao.txt', 'File written', 'Reading file /sdcard/nihao.txt', From f3b7e0502a796977af3dadd4c7e49ffe483f70fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Wed, 8 May 2024 11:54:11 +0200 Subject: [PATCH 134/548] ci(examples/storage): Enable perf_benchmark spiflash example and build others --- examples/storage/.build-test-rules.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/storage/.build-test-rules.yml b/examples/storage/.build-test-rules.yml index 028df4eb16e..c943c2cb2ed 100644 --- a/examples/storage/.build-test-rules.yml +++ b/examples/storage/.build-test-rules.yml @@ -115,16 +115,13 @@ examples/storage/perf_benchmark: - esp_partition - esp_driver_sdmmc disable: - - if: IDF_TARGET == "esp32p4" and CONFIG_NAME in ["sdmmc_1line", "sdmmc_4line", "sdspi_1line"] - temporary: true - reason: SDMMC and SDSPI not supported on P4 yet # TODO: IDF-6502, IDF-7501 - if: IDF_TARGET == "esp32c5" temporary: true reason: not supported yet # TODO: [ESP32C5] IDF-8704 disable_test: - - if: IDF_TARGET == "esp32p4" and CONFIG_NAME in ["spiflash"] + - if: IDF_TARGET == "esp32p4" and CONFIG_NAME in ["sdmmc_1line", "sdmmc_4line", "sdspi_1line"] temporary: true - reason: SPIFLASH not supported on P4 yet, only build stage enabled # TODO: IDF-7499 + reason: lack of runners, build only # TODO: IDF-8970 examples/storage/sd_card/sdmmc: depends_components: From 2c96e097c998cd8c25e7ea5f323ed4ce8e67ff60 Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 23 Apr 2024 14:20:40 +0800 Subject: [PATCH 135/548] fix(ble_mesh): Create service after service register success --- .../core/bluedroid_host/adapter.c | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index 610d19a5b1f..e0fc33b4844 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2017 Nordic Semiconductor ASA * SPDX-FileCopyrightText: 2015-2016 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,7 +74,7 @@ static struct bt_mesh_conn_cb *bt_mesh_gatts_conn_cb; static tBTA_GATTS_IF bt_mesh_gatts_if; static uint8_t bt_mesh_gatts_addr[BLE_MESH_ADDR_LEN]; static uint16_t svc_handle, char_handle; -static future_t *future_mesh; +static future_t *gatts_future_mesh; /* Static Functions */ static struct bt_mesh_gatt_attr *bt_mesh_gatts_find_attr_by_handle(uint16_t handle); @@ -561,6 +561,9 @@ static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) case BTA_GATTS_REG_EVT: if (p_data->reg_oper.status == BTA_GATT_OK) { bt_mesh_gatts_if = p_data->reg_oper.server_if; + future_ready(gatts_future_mesh, FUTURE_SUCCESS); + } else { + future_ready(gatts_future_mesh, FUTURE_FAIL); } break; case BTA_GATTS_READ_EVT: { @@ -618,27 +621,27 @@ static void bt_mesh_bta_gatts_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) break; case BTA_GATTS_CREATE_EVT: svc_handle = p_data->create.service_id; - BT_DBG("svc_handle %d, future_mesh %p", svc_handle, future_mesh); - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + BT_DBG("svc_handle %d, gatts_future_mesh %p", svc_handle, gatts_future_mesh); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_INCL_SRVC_EVT: svc_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_CHAR_EVT: char_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_ADD_CHAR_DESCR_EVT: char_handle = p_data->add_result.attr_id; - if (future_mesh != NULL) { - future_ready(future_mesh, FUTURE_SUCCESS); + if (gatts_future_mesh != NULL) { + future_ready(gatts_future_mesh, FUTURE_SUCCESS); } break; case BTA_GATTS_DELELTE_EVT: @@ -962,11 +965,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) if (svc->attrs[i].uuid->type == BLE_MESH_UUID_TYPE_16) { switch (BLE_MESH_UUID_16(svc->attrs[i].uuid)->val) { case BLE_MESH_UUID_GATT_PRIMARY_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); BTA_GATTS_CreateService(bt_mesh_gatts_if, &bta_uuid, 0, svc->attr_count, true); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add primary service"); return ESP_FAIL; } @@ -976,11 +979,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) break; } case BLE_MESH_UUID_GATT_SECONDARY_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, (struct bt_mesh_uuid *)svc->attrs[i].user_data); BTA_GATTS_CreateService(bt_mesh_gatts_if, &bta_uuid, 0, svc->attr_count, false); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add secondary service"); return ESP_FAIL; } @@ -993,11 +996,11 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) break; } case BLE_MESH_UUID_GATT_CHRC_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); struct bt_mesh_gatt_char *gatts_chrc = (struct bt_mesh_gatt_char *)svc->attrs[i].user_data; bta_uuid_to_bt_mesh_uuid(&bta_uuid, gatts_chrc->uuid); BTA_GATTS_AddCharacteristic(svc_handle, &bta_uuid, bt_mesh_perm_to_bta_perm(svc->attrs[i + 1].perm), gatts_chrc->properties, NULL, NULL); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add characteristic"); return ESP_FAIL; } @@ -1019,10 +1022,10 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) case BLE_MESH_UUID_ES_CONFIGURATION_VAL: case BLE_MESH_UUID_ES_MEASUREMENT_VAL: case BLE_MESH_UUID_ES_TRIGGER_SETTING_VAL: { - future_mesh = future_new(); + gatts_future_mesh = future_new(); bta_uuid_to_bt_mesh_uuid(&bta_uuid, svc->attrs[i].uuid); BTA_GATTS_AddCharDescriptor(svc_handle, bt_mesh_perm_to_bta_perm(svc->attrs[i].perm), &bta_uuid, NULL, NULL); - if (future_await(future_mesh) == FUTURE_FAIL) { + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { BT_ERR("Failed to add descriptor"); return ESP_FAIL; } @@ -1768,7 +1771,19 @@ void bt_mesh_gatt_init(void) CONFIG_BLE_MESH_GATT_PROXY_SERVER tBT_UUID gatts_app_uuid = {LEN_UUID_128, {0}}; memset(&gatts_app_uuid.uu.uuid128, BLE_MESH_GATTS_APP_UUID_BYTE, LEN_UUID_128); + + gatts_future_mesh = future_new(); + if (!gatts_future_mesh) { + BT_ERR("Mesh gatts sync lock alloc failed"); + return; + } + BTA_GATTS_AppRegister(&gatts_app_uuid, bt_mesh_bta_gatts_cb); + + if (future_await(gatts_future_mesh) == FUTURE_FAIL) { + BT_ERR("Mesh gatts app register failed"); + return; + } #endif #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ From 5890c7450dfeca1e8a984ad81ee176512d8bd32b Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Tue, 21 May 2024 15:37:56 +0200 Subject: [PATCH 136/548] fix(tools): Use GDGBUI arguments based on its version Closes https://github.com/espressif/esp-idf/issues/13665 --- tools/idf_py_actions/debug_ext.py | 56 +++++++++++++++++++------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/tools/idf_py_actions/debug_ext.py b/tools/idf_py_actions/debug_ext.py index ed1eed2ae50..eb05437e925 100644 --- a/tools/idf_py_actions/debug_ext.py +++ b/tools/idf_py_actions/debug_ext.py @@ -15,6 +15,7 @@ from typing import Dict from typing import List from typing import Optional +from typing import Tuple from typing import Union from click import INT @@ -157,10 +158,10 @@ def _terminate_async_target(target: str) -> None: def _get_espcoredump_instance(ctx: Context, args: PropertyDict, - gdb_timeout_sec: int = None, - core: str = None, - chip_rev: str = None, - save_core: str = None) -> CoreDump: + gdb_timeout_sec: Optional[int] = None, + core: Optional[str] = None, + chip_rev: Optional[str] = None, + save_core: Optional[str] = None) -> CoreDump: ensure_build_directory(args, ctx.info_name) project_desc = get_project_desc(args, ctx) @@ -243,7 +244,7 @@ def generate_gdbinit_rom_add_symbols(target: str) -> str: with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), ESP_ROM_INFO_FILE), 'r') as f: roms = json.load(f) if target not in roms: - msg_body = f'Target "{target}" was not found in "{ESP_ROM_INFO_FILE}". Please check IDF integrity.' + msg_body = f'Target "{target}" was not found in "{ESP_ROM_INFO_FILE}". Please check IDF integrity.' # noqa: E713 if os.getenv('ESP_IDF_GDB_TESTING'): raise FatalError(msg_body) print(f'Warning: {msg_body}') @@ -406,6 +407,24 @@ def get_gdb_args(project_desc: Dict[str, Any]) -> List: args.append('-ix={}'.format(debug_prefix_gdbinit)) return args + def _get_gdbgui_version(ctx: Context) -> Tuple[int, ...]: + completed_process = subprocess.run(['gdbgui', '--version'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + captured_output = completed_process.stdout.decode('utf-8', 'ignore') + + if completed_process.returncode != 0: + if sys.version_info[:2] >= (3, 11) and sys.platform == 'win32': + raise SystemExit('Unfortunately, gdbgui is supported only with Python 3.10 or older. ' + 'See: https://github.com/espressif/esp-idf/issues/10116. ' + 'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.') + raise FatalError('Error starting gdbgui. Please make sure gdbgui has been installed with ' + '"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started. ' + f'Error: {captured_output}', ctx) + + v = re.search(r'(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?', captured_output) + if not v: + raise SystemExit(f'Error: "gdbgui --version" returned "{captured_output}"') + return tuple(int(i) if i else 0 for i in (v[1], v[2], v[3], v[4])) + def gdbui(action: str, ctx: Context, args: PropertyDict, gdbgui_port: Optional[str], gdbinit: Optional[str], require_openocd: bool) -> None: """ @@ -416,11 +435,11 @@ def gdbui(action: str, ctx: Context, args: PropertyDict, gdbgui_port: Optional[s gdb = project_desc['monitor_toolprefix'] + 'gdb' generate_gdbinit_files(gdb, gdbinit, project_desc) + gdbgui_version = _get_gdbgui_version(ctx) gdb_args_list = get_gdb_args(project_desc) - if sys.version_info[:2] >= (3, 11): - # If we use Python 3.11+ then the only compatible gdbgui doesn't support the --gdb-args argument. This - # check is easier than checking gdbgui version or re-running the process in case of gdb-args-related - # failure. + if gdbgui_version >= (0, 14, 0, 0): + # See breaking changes https://github.com/cs01/gdbgui/blob/master/CHANGELOG.md#01400, especially the + # replacement of command line arguments. gdb_args = ' '.join(gdb_args_list) args = ['gdbgui', '-g', ' '.join((gdb, gdb_args))] else: @@ -446,12 +465,7 @@ def gdbui(action: str, ctx: Context, args: PropertyDict, gdbgui_port: Optional[s process = subprocess.Popen(args, stdout=gdbgui_out, stderr=subprocess.STDOUT, bufsize=1, env=env) except (OSError, subprocess.CalledProcessError) as e: print(e) - if sys.version_info[:2] >= (3, 11) and sys.platform == 'win32': - raise SystemExit('Unfortunately, gdbgui is supported only with Python 3.10 or older. ' - 'See: https://github.com/espressif/esp-idf/issues/10116. ' - 'Please use "idf.py gdb" or debug in Eclipse/Vscode instead.') - raise FatalError('Error starting gdbgui. Please make sure gdbgui has been installed with ' - '"install.{sh,bat,ps1,fish} --enable-gdbgui" and can be started.', ctx) + raise FatalError('Error starting gdbgui', ctx) processes['gdbgui'] = process processes['gdbgui_outfile'] = gdbgui_out @@ -529,9 +543,9 @@ def coredump_info(action: str, ctx: Context, args: PropertyDict, gdb_timeout_sec: int, - core: str = None, - chip_rev: str = None, - save_core: str = None) -> None: + core: Optional[str] = None, + chip_rev: Optional[str] = None, + save_core: Optional[str] = None) -> None: espcoredump = _get_espcoredump_instance(ctx=ctx, args=args, gdb_timeout_sec=gdb_timeout_sec, core=core, chip_rev=chip_rev, save_core=save_core) @@ -541,9 +555,9 @@ def coredump_info(action: str, def coredump_debug(action: str, ctx: Context, args: PropertyDict, - core: str = None, - chip_rev: str = None, - save_core: str = None) -> None: + core: Optional[str] = None, + chip_rev: Optional[str] = None, + save_core: Optional[str] = None) -> None: espcoredump = _get_espcoredump_instance(ctx=ctx, args=args, core=core, chip_rev=chip_rev, save_core=save_core) espcoredump.dbg_corefile() From 8e66d389591f0a56ba1efb9c44965906f9d91130 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 3 Nov 2023 12:05:11 +0800 Subject: [PATCH 137/548] refactor(cpu_start): move uni/multi core log later --- components/esp_system/port/cpu_start.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 73255e14646..9896d2ccd1f 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -440,17 +440,10 @@ void IRAM_ATTR call_start_cpu0(void) } #endif -#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP -#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - ESP_EARLY_LOGI(TAG, "Unicore app"); -#else - ESP_EARLY_LOGI(TAG, "Multicore app"); -#if !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE && !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // It helps to fix missed cache settings for other cores. It happens when bootloader is unicore. do_multicore_settings(); -#endif // !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #endif -#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP // When the APP is loaded into ram for execution, some hardware initialization behaviors // in the bootloader are still necessary @@ -585,6 +578,11 @@ void IRAM_ATTR call_start_cpu0(void) #endif #endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP +#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + ESP_EARLY_LOGI(TAG, "Unicore app"); +#else + ESP_EARLY_LOGI(TAG, "Multicore app"); +#endif bootloader_init_mem(); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE From 168ff6e268e4b624b98a027d4505d1e0b3c9084d Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 3 Nov 2023 12:07:16 +0800 Subject: [PATCH 138/548] bugfix(cpu_start): check c3 efuse error log on ram app condition Prior to this commit, esp_efuse_check_errors() is only called when it's 2nd stage btld app. This commit moves this error check so under all conditions (including ram app, pure ram app) will check this efuse error --- components/esp_system/port/cpu_start.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 9896d2ccd1f..2938b16d17f 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -583,6 +583,11 @@ void IRAM_ATTR call_start_cpu0(void) #else ESP_EARLY_LOGI(TAG, "Multicore app"); #endif + + if (esp_efuse_check_errors() != ESP_OK) { + esp_restart(); + } + bootloader_init_mem(); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE From 687064b2f8e1346428800ae6029722ebca8351ed Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 3 Nov 2023 12:14:06 +0800 Subject: [PATCH 139/548] change(cpu_start): added note about internal ram only stage --- .../src/bootloader_flash_config_esp32p4.c | 2 +- components/esp_system/port/cpu_start.c | 15 +++++++++++++++ components/spi_flash/flash_ops.c | 7 ------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32p4.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32p4.c index 2ac9b2d0e1b..8766a908a5b 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32p4.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash_config_esp32p4.c @@ -22,7 +22,7 @@ #include "hal/cache_hal.h" #include "hal/cache_ll.h" -void bootloader_flash_update_id() +void IRAM_ATTR bootloader_flash_update_id() { esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip; chip->device_id = bootloader_read_flash_id(); diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 2938b16d17f..316ae2f8357 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -90,6 +90,7 @@ #include "esp_private/spi_flash_os.h" #include "esp_private/mspi_timing_tuning.h" +#include "esp_private/esp_gpio_reserve.h" #include "bootloader_flash_config.h" #include "bootloader_flash.h" #include "esp_private/crosscore_int.h" @@ -576,6 +577,20 @@ void IRAM_ATTR call_start_cpu0(void) #endif } #endif + + //----------------------------------Separator-----------------------------// + /** + * @note + * After this stage, you can place non-internal ram code + */ + + /* Reserve the GPIO pins */ + uint64_t reserve_pin_mask = 0; + for (esp_mspi_io_t i = 0; i < ESP_MSPI_IO_MAX; i++) { + reserve_pin_mask |= BIT64(esp_mspi_get_io(i)); + } + esp_gpio_reserve_pins(reserve_pin_mask); + #endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP #if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 0dd92a78101..f99fcfe4df1 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -24,7 +24,6 @@ #include "esp_private/system_internal.h" #include "esp_private/spi_flash_os.h" #include "esp_private/esp_clk.h" -#include "esp_private/esp_gpio_reserve.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/cache.h" #include "esp32/rom/spi_flash.h" @@ -150,12 +149,6 @@ void IRAM_ATTR esp_mspi_pin_init(void) } //Set F4R4 board pin drive strength. TODO: IDF-3663 #endif - /* Reserve the GPIO pins */ - uint64_t reserve_pin_mask = 0; - for (esp_mspi_io_t i = 0; i < ESP_MSPI_IO_MAX; i++) { - reserve_pin_mask |= BIT64(esp_mspi_get_io(i)); - } - esp_gpio_reserve(reserve_pin_mask); } esp_err_t IRAM_ATTR spi_flash_init_chip_state(void) From e23d24a65d46c16dc7d359ca0a00be71ad9b6f2c Mon Sep 17 00:00:00 2001 From: luoxu Date: Sun, 28 Apr 2024 11:19:31 +0800 Subject: [PATCH 140/548] fix(ble_mesh): reference net_buf on correct positions --- .../bt/esp_ble_mesh/core/transport.enh.c | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 2dc562d94b1..b6245f73e81 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -517,6 +517,12 @@ static bool send_next_segment(struct seg_tx *tx, int *result) net_tx.ctx->net_idx = tx->sub->net_idx; + /** + * Add one to the ref count only if the segment can be further + * processed by the network. + */ + seg = net_buf_ref(seg); + err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); if (err) { BT_ERR("Send seg %u failed (err %d)", tx->last_seg_n, err); @@ -966,7 +972,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, } } - tx->seg[seg_o] = net_buf_ref(seg); + /** + * If the net buffer allocation of the subsequent + * segments of this segment message fails, it will + * cause the ref count of the previously allocated + * successful segments to not be unref, which will + * cause the net buffer leakage to occur, so it is + * necessary to wait until all the segments have been + * allocated, and then when the segment is confirmed + * that it will be network layer for further processing, + * then ref of the net buffer should be plus one. + */ + tx->seg[seg_o] = seg; BT_DBG("Seg %u/%u prepared", seg_o, tx->seg_n); } @@ -975,6 +992,11 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * tx->seg[0] will be NULL here. */ if (tx->seg[0]) { + /** + * Add one to the ref count only if the segment can be further + * processed by the network. + */ + tx->seg[0] = net_buf_ref(tx->seg[0]); err = bt_mesh_net_send(net_tx, tx->seg[0], &seg_sent_cb, tx); if (err) { BT_ERR("Send 1st seg failed (err %d)", err); From 3a7aafe7d628ea0bb142efaf9a3f9a2363efd029 Mon Sep 17 00:00:00 2001 From: luoxu Date: Thu, 25 Apr 2024 15:52:10 +0800 Subject: [PATCH 141/548] fix(ble_mesh): change tx/rx lock to recursive mutex to avoid dead lock --- .../bt/esp_ble_mesh/core/transport.enh.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index b6245f73e81..6ef6c0a55db 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -121,22 +121,22 @@ static bt_mesh_mutex_t seg_rx_lock; static inline void bt_mesh_seg_tx_lock(void) { - bt_mesh_mutex_lock(&seg_tx_lock); + bt_mesh_r_mutex_lock(&seg_tx_lock); } static inline void bt_mesh_seg_tx_unlock(void) { - bt_mesh_mutex_unlock(&seg_tx_lock); + bt_mesh_r_mutex_unlock(&seg_tx_lock); } static inline void bt_mesh_seg_rx_lock(void) { - bt_mesh_mutex_lock(&seg_rx_lock); + bt_mesh_r_mutex_lock(&seg_rx_lock); } static inline void bt_mesh_seg_rx_unlock(void) { - bt_mesh_mutex_unlock(&seg_rx_lock); + bt_mesh_r_mutex_unlock(&seg_rx_lock); } uint8_t bt_mesh_seg_send_interval(void) @@ -2349,8 +2349,8 @@ void bt_mesh_trans_init(void) seg_rx[i].buf.data = seg_rx[i].buf.__buf; } - bt_mesh_mutex_create(&seg_tx_lock); - bt_mesh_mutex_create(&seg_rx_lock); + bt_mesh_r_mutex_create(&seg_tx_lock); + bt_mesh_r_mutex_create(&seg_rx_lock); } #if CONFIG_BLE_MESH_DEINIT @@ -2360,7 +2360,7 @@ void bt_mesh_trans_deinit(bool erase) bt_mesh_tx_reset(); bt_mesh_rpl_reset(erase); - bt_mesh_mutex_free(&seg_tx_lock); - bt_mesh_mutex_free(&seg_rx_lock); + bt_mesh_r_mutex_free(&seg_tx_lock); + bt_mesh_r_mutex_free(&seg_rx_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ From f9b58b0c73c5aca6b4d74ccff0e9205ca7a54eda Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 29 Mar 2024 10:24:32 +0800 Subject: [PATCH 142/548] change(mmu): fix spell issue --- components/hal/esp32p4/include/hal/mmu_ll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hal/esp32p4/include/hal/mmu_ll.h b/components/hal/esp32p4/include/hal/mmu_ll.h index 5a8c01d330b..6162cc9315d 100644 --- a/components/hal/esp32p4/include/hal/mmu_ll.h +++ b/components/hal/esp32p4/include/hal/mmu_ll.h @@ -344,7 +344,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { From 88b300d0646c9e87df52377351a94e5e2da1fa9b Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Fri, 17 May 2024 15:30:45 +0800 Subject: [PATCH 143/548] fix(esp_netif): Fix mldv6 report memory leak in esp_netif --- components/esp_netif/lwip/esp_netif_lwip.c | 39 +++++++++++-------- .../esp_netif/lwip/esp_netif_lwip_internal.h | 2 + 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index 02af33fd68d..4f1b2903b8a 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -140,8 +140,8 @@ static void esp_netif_internal_dhcpc_cb(struct netif *netif); #endif #if LWIP_IPV6 static void esp_netif_internal_nd6_cb(struct netif *p_netif, uint8_t ip_index); -static void netif_set_mldv6_flag(struct netif *netif); -static void netif_unset_mldv6_flag(struct netif *netif); +static void netif_set_mldv6_flag(esp_netif_t *netif); +static void netif_unset_mldv6_flag(esp_netif_t *netif); #endif /* LWIP_IPV6 */ static esp_err_t esp_netif_destroy_api(esp_netif_api_msg_t *msg); @@ -156,7 +156,8 @@ static void netif_callback_fn(struct netif* netif, netif_nsc_reason_t reason, co #if LWIP_IPV6 if ((reason & LWIP_NSC_IPV6_ADDR_STATE_CHANGED) && (args != NULL)) { s8_t addr_idx = args->ipv6_addr_state_changed.addr_index; - if (netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) { + if (!(args->ipv6_addr_state_changed.old_state & IP6_ADDR_VALID) && + netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) { /* address is valid -> call the callback function */ esp_netif_internal_nd6_cb(netif, addr_idx); } @@ -844,7 +845,7 @@ static void esp_netif_lwip_remove(esp_netif_t *esp_netif) #endif #if ESP_MLDV6_REPORT && LWIP_IPV6 if (esp_netif->flags & ESP_NETIF_FLAG_MLDV6_REPORT) { - netif_unset_mldv6_flag(esp_netif->lwip_netif); + netif_unset_mldv6_flag(esp_netif); } #endif if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) { @@ -1692,7 +1693,7 @@ static esp_err_t esp_netif_down_api(esp_netif_api_msg_t *msg) #if CONFIG_LWIP_IPV6 #if ESP_MLDV6_REPORT if (esp_netif->flags & ESP_NETIF_FLAG_MLDV6_REPORT) { - netif_unset_mldv6_flag(esp_netif->lwip_netif); + netif_unset_mldv6_flag(esp_netif); } #endif for(int8_t i = 0 ;i < LWIP_IPV6_NUM_ADDRESSES ;i++) { @@ -1996,25 +1997,31 @@ esp_err_t esp_netif_get_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t ty static void netif_send_mldv6(void *arg) { - struct netif *netif = arg; - if (!netif_is_up(netif)) { + esp_netif_t *esp_netif = arg; + esp_netif->mldv6_report_timer_started = false; + if (!netif_is_up(esp_netif->lwip_netif)) { return; } - mld6_report_groups(netif); - sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, netif); + mld6_report_groups(esp_netif->lwip_netif); + esp_netif->mldv6_report_timer_started = true; + sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, esp_netif); } -static void netif_set_mldv6_flag(struct netif *netif) +static void netif_set_mldv6_flag(esp_netif_t *esp_netif) { - if (!netif_is_up(netif)) { + if (!netif_is_up(esp_netif->lwip_netif) || esp_netif->mldv6_report_timer_started) { return; } - sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, netif); + esp_netif->mldv6_report_timer_started = true; + sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, esp_netif); } -static void netif_unset_mldv6_flag(struct netif *netif) +static void netif_unset_mldv6_flag(esp_netif_t *esp_netif) { - sys_untimeout(netif_send_mldv6, netif); + if (esp_netif->mldv6_report_timer_started) { + esp_netif->mldv6_report_timer_started = false; + sys_untimeout(netif_send_mldv6, esp_netif); + } } #endif @@ -2061,7 +2068,7 @@ static void esp_netif_internal_nd6_cb(struct netif *netif, uint8_t ip_index) if (esp_netif->flags&ESP_NETIF_FLAG_MLDV6_REPORT) { #if ESP_MLDV6_REPORT - netif_set_mldv6_flag(netif); + netif_set_mldv6_flag(esp_netif); #else ESP_LOGW(TAG,"CONFIG_LWIP_ESP_MLDV6_REPORT not enabled, but esp-netif configured with ESP_NETIF_FLAG_MLDV6_REPORT"); #endif diff --git a/components/esp_netif/lwip/esp_netif_lwip_internal.h b/components/esp_netif/lwip/esp_netif_lwip_internal.h index f1fc1f8bf8b..842fc817358 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_internal.h +++ b/components/esp_netif/lwip/esp_netif_lwip_internal.h @@ -112,4 +112,6 @@ struct esp_netif_obj { uint16_t max_fdb_sta_entries; uint8_t max_ports; #endif // CONFIG_ESP_NETIF_BRIDGE_EN + // mldv6 timer + bool mldv6_report_timer_started; }; From cc48efc6ec509c1189f94808a9b2288ba744ce29 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 21 May 2024 10:21:49 +0800 Subject: [PATCH 144/548] feat(isp): added isp bf driver --- components/esp_driver_isp/CMakeLists.txt | 4 + .../esp_driver_isp/include/driver/isp.h | 1 + .../esp_driver_isp/include/driver/isp_bf.h | 70 +++++++++++++++ components/esp_driver_isp/src/isp_bf.c | 74 ++++++++++++++++ components/esp_driver_isp/src/isp_core.c | 1 + components/esp_driver_isp/src/isp_internal.h | 3 +- components/hal/esp32p4/include/hal/isp_ll.h | 86 ++++++++++++++++++- components/hal/include/hal/isp_hal.h | 26 +++++- components/hal/include/hal/isp_types.h | 19 ++++ components/hal/isp_hal.c | 26 +++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 +++ components/soc/esp32p4/include/soc/soc_caps.h | 4 + examples/peripherals/isp/auto_focus/README.md | 2 +- .../isp/auto_focus/main/isp_af_dsi_main.c | 15 ++++ 14 files changed, 336 insertions(+), 7 deletions(-) create mode 100644 components/esp_driver_isp/include/driver/isp_bf.h create mode 100644 components/esp_driver_isp/src/isp_bf.c diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index 1ac8cc1ab76..ac99867c005 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -7,6 +7,10 @@ if(CONFIG_SOC_ISP_SUPPORTED) "src/isp_af.c") endif() +if(CONFIG_SOC_ISP_BF_SUPPORTED) + list(APPEND srcs "src/isp_bf.c") +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${public_include} PRIV_REQUIRES esp_driver_gpio diff --git a/components/esp_driver_isp/include/driver/isp.h b/components/esp_driver_isp/include/driver/isp.h index 5909bf0fac8..50674cb7b2d 100644 --- a/components/esp_driver_isp/include/driver/isp.h +++ b/components/esp_driver_isp/include/driver/isp.h @@ -13,3 +13,4 @@ #include "driver/isp_core.h" #include "driver/isp_af.h" +#include "driver/isp_bf.h" diff --git a/components/esp_driver_isp/include/driver/isp_bf.h b/components/esp_driver_isp/include/driver/isp_bf.h new file mode 100644 index 00000000000..b1301301a9a --- /dev/null +++ b/components/esp_driver_isp/include/driver/isp_bf.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "driver/isp_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ISP BF configurations + */ +typedef struct { + isp_bf_edge_padding_mode_t padding_mode; ///< BF edge padding mode + uint8_t padding_data; ///< BF edge padding pixel data + uint8_t bf_template[ISP_BF_TEMPLATE_X_NUMS][ISP_BF_TEMPLATE_Y_NUMS]; ///< BF template data + uint8_t denoising_level; ///< BF denoising level, from 2 to 20, the bigger the better denoising performance, but the worse detailed + uint8_t padding_line_tail_valid_start_pixel; ///< BF edge padding line tail valid start pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid + uint8_t padding_line_tail_valid_end_pixel; ///< BF edge padding line tail valid end pixel, padding data will only be valid between the valid start pixel and the valid end pixel. Set both the start and end pixel to 0 to make all padding pixel valid +} esp_isp_bf_config_t; + +/** + * @brief ISP BF configuration + * + * @note After calling this API, BF doesn't take into effect until `esp_isp_bf_enable` is called + * + * @param[in] proc Processor handle + * @param[in] config BF configurations, set NULL to de-configure the ISP BF + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_STATE Not allowed to be called under current state + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid + */ +esp_err_t esp_isp_bf_configure(isp_proc_handle_t proc, const esp_isp_bf_config_t *config); + +/** + * @brief Enable ISP BF function + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_bf_enable(isp_proc_handle_t proc); + +/** + * @brief Disable ISP BF function + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_bf_disable(isp_proc_handle_t proc); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_isp/src/isp_bf.c b/components/esp_driver_isp/src/isp_bf.c new file mode 100644 index 00000000000..00bf4d1902e --- /dev/null +++ b/components/esp_driver_isp/src/isp_bf.c @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "esp_clk_tree.h" +#include "driver/isp_core.h" +#include "driver/isp_bf.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/mipi_csi_share_hw_ctrl.h" +#include "hal/hal_utils.h" +#include "soc/mipi_csi_bridge_struct.h" +#include "soc/isp_periph.h" +#include "isp_internal.h" + +static const char *TAG = "ISP_BF"; + +/*--------------------------------------------------------------- + BF +---------------------------------------------------------------*/ +esp_err_t esp_isp_bf_configure(isp_proc_handle_t proc, const esp_isp_bf_config_t *config) +{ + ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(proc->bf_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "bf is enabled already"); + + if (config) { + bool valid_padding_setting = (!config->padding_line_tail_valid_end_pixel && !config->padding_line_tail_valid_start_pixel) || (config->padding_line_tail_valid_end_pixel > config->padding_line_tail_valid_start_pixel); + ESP_RETURN_ON_FALSE(valid_padding_setting, ESP_ERR_INVALID_ARG, TAG, "wrong padding line tail valid pixel setting"); + + isp_hal_bf_cfg_t bf_hal_cfg = { + .denoising_level = config->denoising_level, + .padding_mode = config->padding_mode, + .padding_data = config->padding_data, + .padding_line_tail_valid_start_pixel = config->padding_line_tail_valid_start_pixel, + .padding_line_tail_valid_end_pixel = config->padding_line_tail_valid_end_pixel, + }; + memcpy(bf_hal_cfg.bf_template, config->bf_template, ISP_BF_TEMPLATE_X_NUMS * ISP_BF_TEMPLATE_X_NUMS * sizeof(uint8_t)); + isp_hal_bf_config(&(proc->hal), &bf_hal_cfg); + } else { + isp_hal_bf_config(&(proc->hal), NULL); + } + + return ESP_OK; +} + +esp_err_t esp_isp_bf_enable(isp_proc_handle_t proc) +{ + ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(proc->bf_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "bf is enabled already"); + + isp_ll_bf_enable(proc->hal.hw, true); + proc->bf_fsm = ISP_FSM_ENABLE; + + return ESP_OK; +} + +esp_err_t esp_isp_bf_disable(isp_proc_handle_t proc) +{ + ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(proc->bf_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "bf isn't enabled yet"); + + isp_ll_bf_enable(proc->hal.hw, false); + proc->bf_fsm = ISP_FSM_INIT; + + return ESP_OK; +} diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index 773ca18e5bc..b34057f9ab7 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -13,6 +13,7 @@ #include "freertos/FreeRTOS.h" #include "esp_clk_tree.h" #include "driver/isp_core.h" +#include "driver/isp_bf.h" #include "esp_private/periph_ctrl.h" #include "esp_private/mipi_csi_share_hw_ctrl.h" #include "hal/hal_utils.h" diff --git a/components/esp_driver_isp/src/isp_internal.h b/components/esp_driver_isp/src/isp_internal.h index 1ad011c409c..3d388386773 100644 --- a/components/esp_driver_isp/src/isp_internal.h +++ b/components/esp_driver_isp/src/isp_internal.h @@ -57,7 +57,8 @@ typedef struct isp_processor_t { portMUX_TYPE spinlock; /* sub module contexts */ - isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; + isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; + isp_fsm_t bf_fsm; } isp_processor_t; #ifdef __cplusplus diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index ee837995ec7..c91c8efb255 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -63,14 +63,18 @@ extern "C" { #define ISP_LL_EVENT_TAIL_IDI_FRAME (1<<27) #define ISP_LL_EVENT_HEADER_IDI_FRAME (1<<28) -#define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF) -#define ISP_LL_EVENT_AF_MASK (ISP_LL_EVENT_AF_FDONE | ISP_LL_EVENT_AF_ENV) +#define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF) +#define ISP_LL_EVENT_AF_MASK (ISP_LL_EVENT_AF_FDONE | ISP_LL_EVENT_AF_ENV) /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ -#define ISP_LL_AF_WINDOW_MAX_RANGE ((1<<12) - 1) +#define ISP_LL_AF_WINDOW_MAX_RANGE ((1<<12) - 1) +/*--------------------------------------------------------------- + BF +---------------------------------------------------------------*/ +#define ISP_LL_BF_DEFAULT_TEMPLATE_VAL 15 /** * @brief Env monitor mode @@ -661,6 +665,82 @@ static inline void isp_ll_bf_enable(isp_dev_t *hw, bool enable) hw->cntl.bf_en = enable; } +/** + * @brief Set ISP BF sigma value + * + * @param[in] hw Hardware instance address + * @param[in] sigmal_val sigma value + */ +static inline void isp_ll_bf_set_sigma(isp_dev_t *hw, uint32_t sigma_val) +{ + hw->bf_sigma.sigma = sigma_val; +} + +/** + * @brief Set ISP BF padding mode + * + * @param[in] hw Hardware instance address + * @param[in] padding_mode padding mode + */ +static inline void isp_ll_bf_set_padding_mode(isp_dev_t *hw, isp_bf_edge_padding_mode_t padding_mode) +{ + hw->bf_matrix_ctrl.bf_padding_mode = padding_mode; +} + +/** + * @brief Set ISP BF padding data + * + * @param[in] hw Hardware instance address + * @param[in] padding_data padding data + */ +static inline void isp_ll_bf_set_padding_data(isp_dev_t *hw, uint32_t padding_data) +{ + hw->bf_matrix_ctrl.bf_padding_data = padding_data; +} + +/** + * @brief Set ISP BF tail pixen pulse tl + * + * @param[in] hw Hardware instance address + * @param[in] start_pixel start pixel value + */ +static inline void isp_ll_bf_set_padding_line_tail_valid_start_pixel(isp_dev_t *hw, uint32_t start_pixel) +{ + hw->bf_matrix_ctrl.bf_tail_pixen_pulse_tl = start_pixel; +} + +/** + * @brief Set ISP BF tail pixen pulse th + * + * @param[in] hw Hardware instance address + * @param[in] end_pixel end pixel value + */ +static inline void isp_ll_bf_set_padding_line_tail_valid_end_pixel(isp_dev_t *hw, uint32_t end_pixel) +{ + hw->bf_matrix_ctrl.bf_tail_pixen_pulse_th = end_pixel; +} + +/** + * @brief Set ISP BF template + * + * @param[in] hw Hardware instance address + * @param[in] template_arr 2-d array for the template + */ +static inline void isp_ll_bf_set_template(isp_dev_t *hw, uint8_t template_arr[SOC_ISP_BF_TEMPLATE_X_NUMS][SOC_ISP_BF_TEMPLATE_Y_NUMS]) +{ + int cnt = 0; + for (int i = 0; i < SOC_ISP_BF_TEMPLATE_X_NUMS; i++) { + for (int j = 0; j < SOC_ISP_BF_TEMPLATE_Y_NUMS; j++) { + if (i == 2 && j == 2) { + break; + } + hw->bf_gau0.val = (hw->bf_gau0.val & ~(0xf << (28 - cnt * 4))) | ((template_arr[i][j] & 0xf) << (28 - cnt * 4)); + cnt++; + } + } + + hw->bf_gau1.gau_template22 = template_arr[2][2]; +} /*--------------------------------------------------------------- CCM ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index 2a113ddb3fd..9aacd179d8b 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -19,12 +19,26 @@ extern "C" { #endif +/** + * @brief BF configurations + */ +typedef struct { + isp_bf_edge_padding_mode_t padding_mode; ///< BF edge padding mode + uint8_t padding_data; ///< BF edge padding pixel data + uint8_t bf_template[ISP_BF_TEMPLATE_X_NUMS][ISP_BF_TEMPLATE_Y_NUMS]; ///< BF template data + uint8_t denoising_level; ///< BF denoising level, from 2 to 20, the bigger the better denoising performance, but the worse detailed + uint8_t padding_line_tail_valid_start_pixel; ///< BF edge padding line tail valid start pixel + uint8_t padding_line_tail_valid_end_pixel; ///< BF edge padding line tail valid end pixel +} isp_hal_bf_cfg_t; /** - * Context that should be maintained by both the driver and the HAL + * @brief Context that should be maintained by both the driver and the HAL */ typedef struct { void *hw; ///< Beginning address of the ISP registers + + /* BF */ + isp_hal_bf_cfg_t bf_cfg; ///< BF configurations } isp_hal_context_t; /** @@ -61,6 +75,16 @@ void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const */ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t mask); +/*--------------------------------------------------------------- + BF +---------------------------------------------------------------*/ +/** + * @brief Configure ISP BF registers + * + * @param[in] hal Context of the HAL layer + * @param[in] config BF config, set NULL to de-config the ISP BF + */ +void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config); #ifdef __cplusplus } diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 8a2fb0fc76f..0d5bc4be3fe 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -72,6 +72,25 @@ typedef struct { int luminance[ISP_AF_WINDOW_NUM]; ///< Luminance, it refers how luminant an image is } isp_af_result_t; +/*--------------------------------------------------------------- + BF +---------------------------------------------------------------*/ +#if SOC_ISP_BF_SUPPORTED +#define ISP_BF_TEMPLATE_X_NUMS SOC_ISP_BF_TEMPLATE_X_NUMS // BF template x field nums +#define ISP_BF_TEMPLATE_Y_NUMS SOC_ISP_BF_TEMPLATE_Y_NUMS // BF template y field nums +#else +#define ISP_BF_TEMPLATE_X_NUMS 0 +#define ISP_BF_TEMPLATE_Y_NUMS 0 +#endif + +/** + * @brief ISP BF edge padding mode + */ +typedef enum { + ISP_BF_EDGE_PADDING_MODE_SRND_DATA, ///< Fill BF edge padding data with surrounding pixel data + ISP_BF_EDGE_PADDING_MODE_CUSTOM_DATA, ///< Fill BF edge padding data with custom pixel data +} isp_bf_edge_padding_mode_t; + #ifdef __cplusplus } #endif diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index d897c07080a..3bb38906939 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -5,12 +5,14 @@ */ #include +#include #include "sdkconfig.h" #include "soc/soc_caps.h" #include "hal/assert.h" #include "hal/log.h" #include "hal/isp_hal.h" #include "hal/isp_ll.h" +#include "hal/isp_types.h" /** * ISP HAL layer @@ -22,7 +24,6 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id) isp_ll_init(hal->hw); } - /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ @@ -31,6 +32,29 @@ void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_ll_af_set_window_range(hal->hw, window_id, window->top_left_x, window->top_left_y, window->bottom_right_x, window->bottom_right_y); } +/*--------------------------------------------------------------- + BF +---------------------------------------------------------------*/ +void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config) +{ + if (config) { + isp_ll_bf_set_sigma(hal->hw, config->denoising_level); + isp_ll_bf_set_padding_mode(hal->hw, config->padding_mode); + isp_ll_bf_set_padding_data(hal->hw, config->padding_data); + isp_ll_bf_set_padding_line_tail_valid_start_pixel(hal->hw, config->padding_line_tail_valid_start_pixel); + isp_ll_bf_set_padding_line_tail_valid_end_pixel(hal->hw, config->padding_line_tail_valid_end_pixel); + isp_ll_bf_set_template(hal->hw, config->bf_template); + } else { + isp_ll_bf_set_sigma(hal->hw, 0); + isp_ll_bf_set_padding_mode(hal->hw, 0); + isp_ll_bf_set_padding_data(hal->hw, 0); + isp_ll_bf_set_padding_line_tail_valid_start_pixel(hal->hw, 0); + isp_ll_bf_set_padding_line_tail_valid_end_pixel(hal->hw, 0); + uint8_t default_template[SOC_ISP_BF_TEMPLATE_X_NUMS][SOC_ISP_BF_TEMPLATE_Y_NUMS] = {}; + memset(default_template, SOC_ISP_BF_TEMPLATE_X_NUMS, sizeof(default_template)); + isp_ll_bf_set_template(hal->hw, default_template); + } +} /*--------------------------------------------------------------- INTR, put in iram ---------------------------------------------------------------*/ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..76fe088d5a3 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -727,6 +727,10 @@ config SOC_I2S_TDM_FULL_DATA_WIDTH bool default y +config SOC_ISP_BF_SUPPORTED + bool + default y + config SOC_ISP_NUMS int default 1 @@ -743,6 +747,14 @@ config SOC_ISP_SHARE_CSI_BRG bool default y +config SOC_ISP_BF_TEMPLATE_X_NUMS + int + default 3 + +config SOC_ISP_BF_TEMPLATE_Y_NUMS + int + default 3 + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..298b8816977 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -304,10 +304,14 @@ #define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */ /*-------------------------- ISP CAPS ----------------------------------------*/ +#define SOC_ISP_BF_SUPPORTED 1 + #define SOC_ISP_NUMS 1U #define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_WINDOW_NUMS 3 #define SOC_ISP_SHARE_CSI_BRG 1 +#define SOC_ISP_BF_TEMPLATE_X_NUMS 3 +#define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/examples/peripherals/isp/auto_focus/README.md b/examples/peripherals/isp/auto_focus/README.md index a38446fd9ec..3e3ba628b48 100644 --- a/examples/peripherals/isp/auto_focus/README.md +++ b/examples/peripherals/isp/auto_focus/README.md @@ -6,7 +6,7 @@ ## Overview -This example demonstrates how to use the ISP (image signal processor) to work with esp_driver_cam component. This example will capture camera sensor signals via CSI interface and display it via DSI interface. This example also enables the ISP AF (auto-focus) feature. +This example demonstrates how to use the ISP (image signal processor) to work with esp_driver_cam component. This example will capture camera sensor signals via CSI interface and display it via DSI interface. This example also enables the ISP AF (auto-focus) feature and ISP BF (bayer denoise) feature. ## Usage diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c index 6cca1612bc7..4ff9f323efe 100644 --- a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -16,6 +16,7 @@ #include "esp_cache.h" #include "driver/i2c_master.h" #include "driver/isp.h" +#include "driver/isp_bf.h" #include "isp_af_scheme_sa.h" #include "esp_cam_ctlr_csi.h" #include "esp_cam_ctlr.h" @@ -263,6 +264,20 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_new_processor(&isp_config, &isp_proc)); ESP_ERROR_CHECK(esp_isp_enable(isp_proc)); + esp_isp_bf_config_t bf_config = { + .denoising_level = 5, + .padding_mode = ISP_BF_EDGE_PADDING_MODE_SRND_DATA, + .bf_template = { + {1, 2, 1}, + {2, 4, 2}, + {1, 2, 1}, + }, + .padding_line_tail_valid_start_pixel = 0, + .padding_line_tail_valid_end_pixel = 0, + }; + ESP_ERROR_CHECK(esp_isp_bf_configure(isp_proc, &bf_config)); + ESP_ERROR_CHECK(esp_isp_bf_enable(isp_proc)); + typedef struct af_task_param_t { isp_proc_handle_t isp_proc; esp_sccb_io_handle_t dw9714_io_handle; From 096db7521b81b5fe31bc1d823c89ceee1a8291d7 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Tue, 7 May 2024 02:45:43 +0800 Subject: [PATCH 145/548] feat(sdmmc_io): support sending CMD53 with fixed address --- .../host_sdmmc/main/test_sdio_sdhost.c | 77 +++++++++++++++++-- .../sdio/main/test_sdio_slave.c | 18 +++++ components/sdmmc/include/sdmmc_cmd.h | 18 ++++- components/sdmmc/sdmmc_io.c | 45 +++++++---- 4 files changed, 138 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc/main/test_sdio_sdhost.c b/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc/main/test_sdio_sdhost.c index f33985da786..8a63f2b9b6a 100644 --- a/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc/main/test_sdio_sdhost.c +++ b/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/host_sdmmc/main/test_sdio_sdhost.c @@ -14,6 +14,7 @@ #include "freertos/task.h" #include "esp_timer.h" #include "ccomp_timer.h" +#include "string.h" #include "sdmmc_cmd.h" #include "driver/sdmmc_host.h" @@ -43,7 +44,7 @@ typedef struct { ---------------------------------------------------------------*/ static sdmmc_card_t s_card; -static void s_master_init(test_sdio_param_t *host_param, essl_handle_t *out_handle) +static void s_master_init(test_sdio_param_t *host_param, essl_handle_t *out_handle, sdmmc_card_t** out_card) { sdmmc_host_t host_config = (sdmmc_host_t)SDMMC_HOST_DEFAULT(); host_config.flags = host_param->host_flags; @@ -81,6 +82,10 @@ static void s_master_init(test_sdio_param_t *host_param, essl_handle_t *out_hand TEST_ESP_OK(essl_sdio_init_dev(out_handle, &essl_sdio_config)); TEST_ESP_OK(essl_init(*out_handle, TEST_TIMEOUT_MAX)); + + if (out_card) { + *out_card = card; + } } static void s_master_deinit(void) @@ -114,7 +119,7 @@ TEST_CASE("SDIO_SDMMC: test interrupt", "[sdio]") .max_freq_khz = SDMMC_FREQ_HIGHSPEED, }; //essl init and sdmmc init - s_master_init(&test_param, &handle); + s_master_init(&test_param, &handle, NULL); TEST_ESP_OK(essl_set_intr_ena(handle, TEST_INT_MASK_ALL, TEST_TIMEOUT_MAX)); ret = essl_wait_int(handle, 0); @@ -149,7 +154,7 @@ TEST_CASE("SDIO_SDMMC: test register", "[sdio]") .max_freq_khz = SDMMC_FREQ_HIGHSPEED, }; //essl init and sdmmc init - s_master_init(&test_param, &handle); + s_master_init(&test_param, &handle, NULL); uint32_t init_val = 30; srand(850); @@ -183,7 +188,7 @@ TEST_CASE("SDIO_SDMMC: test reset", "[sdio]") .max_freq_khz = SDMMC_FREQ_HIGHSPEED, }; //essl init and sdmmc init - s_master_init(&test_param, &handle); + s_master_init(&test_param, &handle, NULL); //wait for the slave to stop, reset and start again vTaskDelay(10); @@ -215,6 +220,66 @@ TEST_CASE("SDIO_SDMMC: test reset", "[sdio]") s_master_deinit(); } +/*--------------------------------------------------------------- + SDMMC_SDIO: test fixed addr +---------------------------------------------------------------*/ +#include "soc/soc.h" +#define HOST_SLCHOST_CONF_W0_REG (DR_REG_SLCHOST_BASE + 0x6C) + +TEST_CASE("SDIO_SDMMC: test fixed addr", "[sdio]") +{ + essl_handle_t handle = NULL; + sdmmc_card_t* card; + test_sdio_param_t test_param = { + .host_flags = SDMMC_HOST_FLAG_4BIT | SDMMC_HOST_FLAG_ALLOC_ALIGNED_BUF, + .max_freq_khz = SDMMC_FREQ_HIGHSPEED, + }; + //essl init and sdmmc init + s_master_init(&test_param, &handle, &card); + + vTaskDelay(10); + + const int test_size = 128; + const int write_addr = 6; + uint8_t buf[test_size] = {}; + srand(850); + for (int i = 0; i < test_size; i++) { + buf[i] = rand(); + } + ESP_LOG_BUFFER_HEX("write_val", buf, test_size); + + TEST_ESP_OK(sdmmc_io_write_bytes(card, 1, ((HOST_SLCHOST_CONF_W0_REG + write_addr) & 0x3FF) | SDMMC_IO_FIXED_ADDR, buf, test_size)); + + const int max_size = 64; + uint8_t read_buf[max_size] = {}; + TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, HOST_SLCHOST_CONF_W0_REG & 0x3FF, read_buf, max_size)); + ESP_LOG_BUFFER_HEX("read_all", read_buf, max_size); + for (int i = 0; i < max_size; i++) { + if (i >= 24 && i < 28) { + continue; + } + if (i >= 32 && i < 48) { + continue; + } + if (i == write_addr) { + TEST_ASSERT_EQUAL_HEX8(buf[test_size - 1], read_buf[i]); + } else { + TEST_ASSERT_EQUAL_HEX8(0xcc, read_buf[i]); + } + } + + const int read_size = (test_size > max_size ? max_size : test_size); + memset(read_buf, 0, read_size); + TEST_ESP_OK(sdmmc_io_read_bytes(card, 1, ((HOST_SLCHOST_CONF_W0_REG + write_addr) & 0x3FF) | SDMMC_IO_FIXED_ADDR, read_buf, read_size)); + ESP_LOG_BUFFER_HEX("read_fixed", read_buf, read_size); + for (int i = 0; i < read_size; i++) { + TEST_ASSERT_EQUAL_HEX8(buf[test_size - 1], read_buf[i]); + } + + s_send_finish_test(handle); + s_master_deinit(); +} + /*--------------------------------------------------------------- Transaction Tests ---------------------------------------------------------------*/ @@ -241,7 +306,7 @@ static void test_from_host(bool check_data) ESP_LOGI(TAG, "host speed: %"PRIu32" kHz", test_param_lists[i].max_freq_khz); essl_handle_t handle = NULL; - s_master_init(&test_param_lists[i], &handle); + s_master_init(&test_param_lists[i], &handle, NULL); // Two counters are used. The `esp_timer_get_time()` is for the typical time, and the // `ccomp_timer` is for performance test to reduce influence caused by cache miss. @@ -298,7 +363,7 @@ static void test_to_host(bool check_data) ESP_LOGI(TAG, "host speed: %"PRIu32" kHz", test_param_lists[i].max_freq_khz); essl_handle_t handle = NULL; - s_master_init(&test_param_lists[i], &handle); + s_master_init(&test_param_lists[i], &handle, NULL); esp_err_t ret; int offset = 0; diff --git a/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/test_sdio_slave.c b/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/test_sdio_slave.c index ca3e6816d2e..d91e19dd7ce 100644 --- a/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/test_sdio_slave.c +++ b/components/esp_driver_sdio/test_apps/sdio/sdio_common_tests/sdio/main/test_sdio_slave.c @@ -155,6 +155,24 @@ TEST_CASE("SDIO_Slave: test reset", "[sdio]") sdio_slave_deinit(); } +/*--------------------------------------------------------------- + SDMMC_SDIO: test fixed addr +---------------------------------------------------------------*/ +TEST_CASE("SDIO_Slave: test fixed addr", "[sdio]") +{ + s_slave_init(SDIO_SLAVE_SEND_PACKET); + TEST_ESP_OK(sdio_slave_start()); + ESP_LOGI(TAG, "slave ready"); + + for (int i = 0; i < 64; i++) { + sdio_slave_write_reg(i, 0xcc); + } + + wait_for_finish(&s_test_slv_ctx); + + sdio_slave_stop(); + sdio_slave_deinit(); +} /*--------------------------------------------------------------- Transaction Tests ---------------------------------------------------------------*/ diff --git a/components/sdmmc/include/sdmmc_cmd.h b/components/sdmmc/include/sdmmc_cmd.h index c4d7194f12d..0510defd7bd 100644 --- a/components/sdmmc/include/sdmmc_cmd.h +++ b/components/sdmmc/include/sdmmc_cmd.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,10 @@ extern "C" { #endif +/** Call `sdmmc_io_read_bytes`, `sdmmc_io_write_bytes`, `sdmmc_io_read_blocks` or `sdmmc_io_write_bocks` APIs with + * address ORed by this flag to send CMD53 with OP Code clear (fixed address) */ +#define SDMMC_IO_FIXED_ADDR BIT(31) + /** * Probe and initialize SD/MMC card using given host * @@ -196,6 +200,9 @@ esp_err_t sdmmc_io_write_byte(sdmmc_card_t* card, uint32_t function, * This function performs read operation using CMD53 in byte mode. * For block mode, see sdmmc_io_read_blocks. * + * By default OP Code is set (incrementing address). To send CMD53 without this bit, OR the argument `addr` with + * `SDMMC_IO_FIXED_ADDR`. + * * @param card pointer to card information structure previously initialized * using sdmmc_card_init * @param function IO function number @@ -218,6 +225,9 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, * This function performs write operation using CMD53 in byte mode. * For block mode, see sdmmc_io_write_blocks. * + * By default OP Code is set (incrementing address). To send CMD53 without this bit, OR the argument `addr` with + * `SDMMC_IO_FIXED_ADDR`. + * * @param card pointer to card information structure previously initialized * using sdmmc_card_init * @param function IO function number @@ -239,6 +249,9 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, * This function performs read operation using CMD53 in block mode. * For byte mode, see sdmmc_io_read_bytes. * + * By default OP Code is set (incrementing address). To send CMD53 without this bit, OR the argument `addr` with + * `SDMMC_IO_FIXED_ADDR`. + * * @param card pointer to card information structure previously initialized * using sdmmc_card_init * @param function IO function number @@ -261,6 +274,9 @@ esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, * This function performs write operation using CMD53 in block mode. * For byte mode, see sdmmc_io_write_bytes. * + * By default OP Code is set (incrementing address). To send CMD53 without this bit, OR the argument `addr` with + * `SDMMC_IO_FIXED_ADDR`. + * * @param card pointer to card information structure previously initialized * using sdmmc_card_init * @param function IO function number diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index 80a3cc26c91..376cebc9e5e 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -336,6 +336,13 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func, esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, uint32_t addr, void* dst, size_t size) { + uint32_t arg = SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT; + //Extract and unset the bit used to indicate the OP Code (inverted logic) + if (addr & SDMMC_IO_FIXED_ADDR) { + arg &= ~SD_ARG_CMD53_INCREMENT; + addr &= ~SDMMC_IO_FIXED_ADDR; + } + /* host quirk: SDIO transfer with length not divisible by 4 bytes * has to be split into two transfers: one with aligned length, * the other one for the remaining 1-3 bytes. @@ -347,9 +354,7 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, // Note: sdmmc_io_rw_extended has an internal timeout, // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS - esp_err_t err = sdmmc_io_rw_extended(card, function, addr, - SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT, - pc_dst, will_transfer); + esp_err_t err = sdmmc_io_rw_extended(card, function, addr, arg, pc_dst, will_transfer); if (unlikely(err != ESP_OK)) { return err; } @@ -363,18 +368,22 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, uint32_t addr, const void* src, size_t size) { + uint32_t arg = SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT; + //Extract and unset the bit used to indicate the OP Code (inverted logic) + if (addr & SDMMC_IO_FIXED_ADDR) { + arg &= ~SD_ARG_CMD53_INCREMENT; + addr &= ~SDMMC_IO_FIXED_ADDR; + } + /* same host quirk as in sdmmc_io_read_bytes */ const uint8_t *pc_src = (const uint8_t*) src; - while (size > 0) { size_t size_aligned = size & (~3); size_t will_transfer = size_aligned > 0 ? size_aligned : size; // Note: sdmmc_io_rw_extended has an internal timeout, // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS - esp_err_t err = sdmmc_io_rw_extended(card, function, addr, - SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT, - (void*) pc_src, will_transfer); + esp_err_t err = sdmmc_io_rw_extended(card, function, addr, arg, (void*) pc_src, will_transfer); if (unlikely(err != ESP_OK)) { return err; } @@ -388,27 +397,37 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, esp_err_t sdmmc_io_read_blocks(sdmmc_card_t* card, uint32_t function, uint32_t addr, void* dst, size_t size) { + uint32_t arg = SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE; + //Extract and unset the bit used to indicate the OP Code (inverted logic) + if (addr & SDMMC_IO_FIXED_ADDR) { + arg &= ~SD_ARG_CMD53_INCREMENT; + addr &= ~SDMMC_IO_FIXED_ADDR; + } + esp_dma_mem_info_t dma_mem_info; card->host.get_dma_info(card->host.slot, &dma_mem_info); if (unlikely(!esp_dma_is_buffer_alignment_satisfied(dst, size, dma_mem_info))) { return ESP_ERR_INVALID_ARG; } - return sdmmc_io_rw_extended(card, function, addr, - SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE, - dst, size); + return sdmmc_io_rw_extended(card, function, addr, arg, dst, size); } esp_err_t sdmmc_io_write_blocks(sdmmc_card_t* card, uint32_t function, uint32_t addr, const void* src, size_t size) { + uint32_t arg = SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE; + //Extract and unset the bit used to indicate the OP Code (inverted logic) + if (addr & SDMMC_IO_FIXED_ADDR) { + arg &= ~SD_ARG_CMD53_INCREMENT; + addr &= ~SDMMC_IO_FIXED_ADDR; + } + esp_dma_mem_info_t dma_mem_info; card->host.get_dma_info(card->host.slot, &dma_mem_info); if (unlikely(!esp_dma_is_buffer_alignment_satisfied(src, size, dma_mem_info))) { return ESP_ERR_INVALID_ARG; } - return sdmmc_io_rw_extended(card, function, addr, - SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT | SD_ARG_CMD53_BLOCK_MODE, - (void*) src, size); + return sdmmc_io_rw_extended(card, function, addr, arg, (void*) src, size); } esp_err_t sdmmc_io_enable_int(sdmmc_card_t* card) From 1b1005a1d86c93eab66764e3aebc78a7a6e4b5f9 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 5 Feb 2024 22:04:37 +0800 Subject: [PATCH 146/548] feat(ppa): add PPA driver support for ESP32P4 --- components/esp_driver_ppa/CMakeLists.txt | 13 + .../esp_driver_ppa/include/driver/ppa.h | 292 ++++++++++ components/esp_driver_ppa/src/ppa_blend.c | 284 ++++++++++ components/esp_driver_ppa/src/ppa_core.c | 517 ++++++++++++++++++ components/esp_driver_ppa/src/ppa_fill.c | 148 +++++ components/esp_driver_ppa/src/ppa_priv.h | 232 ++++++++ components/esp_driver_ppa/src/ppa_srm.c | 289 ++++++++++ .../test_apps/.build-test-rules.yml | 7 + .../esp_driver_ppa/test_apps/CMakeLists.txt | 9 + components/esp_driver_ppa/test_apps/README.md | 2 + .../test_apps/main/CMakeLists.txt | 9 + .../test_apps/main/idf_component.yml | 2 + .../test_apps/main/test_app_main.c | 42 ++ .../esp_driver_ppa/test_apps/main/test_ppa.c | 489 +++++++++++++++++ .../esp_driver_ppa/test_apps/pytest_ppa.py | 17 + .../test_apps/sdkconfig.ci.release | 6 + .../test_apps/sdkconfig.defaults | 3 + .../test_apps/sdkconfig.defaults.esp32p4 | 3 + components/esp_hw_support/dma/dma2d.c | 22 +- .../dma/include/esp_private/dma2d.h | 25 +- components/esp_hw_support/dma/linker.lf | 1 + components/hal/CMakeLists.txt | 4 + components/hal/esp32p4/include/hal/dma2d_ll.h | 16 +- components/hal/esp32p4/include/hal/ppa_ll.h | 252 +++++---- components/hal/include/hal/color_types.h | 38 ++ components/hal/include/hal/dma2d_types.h | 12 +- components/hal/include/hal/ppa_hal.h | 44 ++ components/hal/include/hal/ppa_types.h | 99 +++- components/hal/ppa_hal.c | 19 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32p4/include/soc/dma2d_channel.h | 8 +- .../soc/esp32p4/include/soc/dma2d_reg.h | 20 +- .../soc/esp32p4/include/soc/dma2d_struct.h | 8 +- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- docs/_static/diagrams/ppa/pic_blk_concept.png | Bin 0 -> 26960 bytes docs/conf_common.py | 3 + docs/doxygen/Doxyfile_esp32p4 | 2 + docs/en/api-reference/peripherals/index.rst | 1 + docs/en/api-reference/peripherals/ppa.rst | 149 +++++ .../zh_CN/api-reference/peripherals/index.rst | 1 + docs/zh_CN/api-reference/peripherals/ppa.rst | 1 + 41 files changed, 2926 insertions(+), 169 deletions(-) create mode 100644 components/esp_driver_ppa/CMakeLists.txt create mode 100644 components/esp_driver_ppa/include/driver/ppa.h create mode 100644 components/esp_driver_ppa/src/ppa_blend.c create mode 100644 components/esp_driver_ppa/src/ppa_core.c create mode 100644 components/esp_driver_ppa/src/ppa_fill.c create mode 100644 components/esp_driver_ppa/src/ppa_priv.h create mode 100644 components/esp_driver_ppa/src/ppa_srm.c create mode 100644 components/esp_driver_ppa/test_apps/.build-test-rules.yml create mode 100644 components/esp_driver_ppa/test_apps/CMakeLists.txt create mode 100644 components/esp_driver_ppa/test_apps/README.md create mode 100644 components/esp_driver_ppa/test_apps/main/CMakeLists.txt create mode 100644 components/esp_driver_ppa/test_apps/main/idf_component.yml create mode 100644 components/esp_driver_ppa/test_apps/main/test_app_main.c create mode 100644 components/esp_driver_ppa/test_apps/main/test_ppa.c create mode 100644 components/esp_driver_ppa/test_apps/pytest_ppa.py create mode 100644 components/esp_driver_ppa/test_apps/sdkconfig.ci.release create mode 100644 components/esp_driver_ppa/test_apps/sdkconfig.defaults create mode 100644 components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32p4 create mode 100644 components/hal/include/hal/ppa_hal.h create mode 100644 components/hal/ppa_hal.c create mode 100644 docs/_static/diagrams/ppa/pic_blk_concept.png create mode 100644 docs/en/api-reference/peripherals/ppa.rst create mode 100644 docs/zh_CN/api-reference/peripherals/ppa.rst diff --git a/components/esp_driver_ppa/CMakeLists.txt b/components/esp_driver_ppa/CMakeLists.txt new file mode 100644 index 00000000000..ed0d3ac201d --- /dev/null +++ b/components/esp_driver_ppa/CMakeLists.txt @@ -0,0 +1,13 @@ +set(srcs) +set(public_include "include") +if(CONFIG_SOC_PPA_SUPPORTED) + list(APPEND srcs "src/ppa_core.c" + "src/ppa_srm.c" + "src/ppa_blend.c" + "src/ppa_fill.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${public_include} + PRIV_REQUIRES esp_mm esp_pm + ) diff --git a/components/esp_driver_ppa/include/driver/ppa.h b/components/esp_driver_ppa/include/driver/ppa.h new file mode 100644 index 00000000000..5f209e85e05 --- /dev/null +++ b/components/esp_driver_ppa/include/driver/ppa.h @@ -0,0 +1,292 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "hal/ppa_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enumeration of all PPA available operations + */ +typedef enum { + PPA_OPERATION_SRM, /*!< Do scale-rotate-mirror operation */ + PPA_OPERATION_BLEND, /*!< Do blend operation */ + PPA_OPERATION_FILL, /*!< Do fill operation, use one constant pixel to fill a target window */ + PPA_OPERATION_INVALID, /*!< Invalid PPA operations, indicates the quantity of available PPA operations */ +} ppa_operation_t; + +/** + * @brief Type of PPA client handle + */ +typedef struct ppa_client_t *ppa_client_handle_t; + +/** + * @brief A collection of configuration items that used for registering a PPA client + */ +typedef struct { + ppa_operation_t oper_type; /*!< The desired PPA operation for the client */ + uint32_t max_pending_trans_num; /*!< The maximum number of pending transactions for the client. + By default, it will be 1, which is sufficient if all transactions are performed with `PPA_TRANS_MODE_BLOCKING` */ + ppa_data_burst_length_t data_burst_length; /*!< The desired data burst length for all the transactions of the client. + Use a small burst length will decrease PPA performance, but can save burst bandwidth for other peripheral usages. + By default, it will be at the maximum burst length, `PPA_DATA_BURST_LENGTH_128` */ +} ppa_client_config_t; + +/** + * @brief Register a PPA client to do a specific PPA operation + * + * @param[in] config Pointer to a collection of configurations for the client + * @param[out] ret_client Returned client handle + * + * @return + * - ESP_OK: Register the PPA client successfully + * - ESP_ERR_INVALID_ARG: Register the PPA client failed because of invalid argument + * - ESP_ERR_NO_MEM: Register the PPA client failed because out of memory + * - ESP_FAIL: Register the PPA client failed because of other error + */ +esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_handle_t *ret_client); + +/** + * @brief Unregister a PPA client + * + * @note This will also free the resources occupied by the client + * + * @param[in] ppa_client PPA client handle, allocated by `ppa_register_client` + * + * @return + * - ESP_OK: Unregister the PPA client successfully + * - ESP_ERR_INVALID_ARG: Unregister the PPA client failed because of invalid argument + * - ESP_ERR_INVALID_STATE: Unregister the PPA client failed because there are unfinished transactions + */ +esp_err_t ppa_unregister_client(ppa_client_handle_t ppa_client); + +/** + * @brief Type of PPA event data + */ +typedef struct { +} ppa_event_data_t; + +/** + * @brief Type of PPA event callback + * + * @param[in] ppa_client PPA client handle + * @param[in] event_data PPA event data + * @param[in] user_data User registered data from calling `ppa_do_xxx` to perform an operation + * + * @return Whether a task switch is needed after the callback function returns, this is usually due to the callback + * wakes up some high priority task. + */ +typedef bool (*ppa_event_callback_t)(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data); + +/** + * @brief Group of supported PPA callbacks + */ +typedef struct { + ppa_event_callback_t on_trans_done; /*!< Invoked when a PPA transaction finishes */ +} ppa_event_callbacks_t; + +/** + * @brief Register event callbacks for a PPA client + * + * @param[in] ppa_client PPA client handle + * @param[in] cbs Structure with all PPA callbacks + * + * @note Any user private data that wants to be passed directly to callback's user_data is provided per PPA transaction. + * Please check the `user_data` field in `ppa_xxx_oper_config_t` structure. + * + * @return + * - ESP_OK: Register event callbacks for the PPA client successfully + * - ESP_ERR_INVALID_ARG: Register event callbacks for the PPA client failed because of invalid argument + */ +esp_err_t ppa_client_register_event_callbacks(ppa_client_handle_t ppa_client, const ppa_event_callbacks_t *cbs); + +/** + * @brief A collection of configuration items for an input picture and the target block inside the picture + */ +typedef struct { + const void *buffer; /*!< Pointer to the input picture buffer */ + uint32_t pic_w; /*!< Input picture width (unit: pixel) */ + uint32_t pic_h; /*!< Input picture height (unit: pixel) */ + uint32_t block_w; /*!< Target block width (unit: pixel) */ + uint32_t block_h; /*!< Target block height (unit: pixel) */ + uint32_t block_offset_x; /*!< Target block offset in x direction in the picture (unit: pixel) */ + uint32_t block_offset_y; /*!< Target block offset in y direction in the picture (unit: pixel) */ + union { + ppa_srm_color_mode_t srm_cm; /*!< Color mode of the picture in a PPA SRM operation. Supported color mode in `ppa_srm_color_mode_t` */ + ppa_blend_color_mode_t blend_cm; /*!< Color mode of the picture in a PPA blend operation. Supported color mode in `ppa_blend_color_mode_t` */ + ppa_fill_color_mode_t fill_cm; /*!< Color mode of the picture in a PPA fill operation. Supported color mode in `ppa_fill_color_mode_t` */ + }; + ppa_color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */ + ppa_color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */ +} ppa_in_pic_blk_config_t; + +/** + * @brief A collection of configuration items for an output picture and the target block inside the picture + */ +typedef struct { + void *buffer; /*!< Pointer to the output picture buffer (requires alignment: internal memory needs align to L1 cache line size, external memory needs align to L1 and L2 cache line size) */ + uint32_t buffer_size; /*!< Size of the output picture buffer (requires alignment: internal memory needs align to L1 cache line size, external memory needs align to L1 and L2 cache line size) */ + uint32_t pic_w; /*!< Output picture width (unit: pixel) */ + uint32_t pic_h; /*!< Output picture height (unit: pixel) */ + uint32_t block_offset_x; /*!< Target block offset in x direction in the picture (unit: pixel) */ + uint32_t block_offset_y; /*!< Target block offset in y direction in the picture (unit: pixel) */ + union { + ppa_srm_color_mode_t srm_cm; /*!< Color mode of the picture in a PPA SRM operation. Supported color mode in `ppa_srm_color_mode_t` */ + ppa_blend_color_mode_t blend_cm; /*!< Color mode of the picture in a PPA blend operation. Supported color mode in `ppa_blend_color_mode_t` */ + ppa_fill_color_mode_t fill_cm; /*!< Color mode of the picture in a PPA fill operation. Supported color mode in `ppa_fill_color_mode_t` */ + }; + ppa_color_range_t yuv_range; /*!< When the color mode is any YUV color space, this field is to describe its color range */ + ppa_color_conv_std_rgb_yuv_t yuv_std; /*!< When the color mode is any YUV color space, this field is to describe its YUV<->RGB conversion standard */ +} ppa_out_pic_blk_config_t; + +/** + * @brief Modes to perform the PPA operations + */ +typedef enum { + PPA_TRANS_MODE_BLOCKING, /*!< `ppa_do_xxx` function will block until the PPA operation is finished */ + PPA_TRANS_MODE_NON_BLOCKING, /*!< `ppa_do_xxx` function will return immediately after the PPA operation is pushed to the internal queue */ +} ppa_trans_mode_t; + +/** + * @brief A collection of configuration items to do a PPA SRM operation transaction + */ +typedef struct { + ppa_in_pic_blk_config_t in; /*!< Information of the input picture and the target block */ + ppa_out_pic_blk_config_t out; /*!< Information of the output picture and the target block */ + + // scale-rotate-mirror manipulation + ppa_srm_rotation_angle_t rotation_angle; /*!< Rotation (counter-clockwise) to the target block, select from `ppa_srm_rotation_angle_t` */ + float scale_x; /*!< Scaling factor to the target block in the x direction */ + float scale_y; /*!< Scaling factor to the target block in the y direction */ + bool mirror_x; /*!< Whether to mirror the target block in the x direction */ + bool mirror_y; /*!< Whether to mirror the target block in the y direction */ + + // input data manipulation + bool rgb_swap; /*!< Whether to swap the input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ + bool byte_swap; /*!< Whether to swap the input data in byte. Only available feature if input picture color mode is ARGB8888 or RGB565 */ + ppa_alpha_update_mode_t alpha_update_mode; /*!< Select whether the alpha channel of the input picture needs update */ + union { + uint32_t alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; + + ppa_trans_mode_t mode; /*!< Determines whether to block inside the operation functions, see `ppa_trans_mode_t` */ + void *user_data; /*!< User registered data to be passed into `done_cb` callback function */ +} ppa_srm_oper_config_t; + +/** + * @brief Perform a scaling-rotating-mirroring (SRM) operation to a picture + * + * @param[in] ppa_client PPA client handle that has been registered to do SRM operations + * @param[in] config Pointer to a collection of configurations for the SRM operation transaction, ppa_srm_oper_config_t + * + * @return + * - ESP_OK: Perform a SRM operation successfully + * - ESP_ERR_INVALID_ARG: Perform a SRM operation failed because of invalid argument + * - ESP_FAIL: Perform a SRM operation failed because the client's pending transactions has reached its maximum capacity + */ +esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_srm_oper_config_t *config); + +/** + * @brief A collection of configuration items to do a PPA blend operation transaction + */ +typedef struct { + ppa_in_pic_blk_config_t in_bg; /*!< Information of the input background picture and the target block */ + ppa_in_pic_blk_config_t in_fg; /*!< Information of the input foreground picture and the target block */ + ppa_out_pic_blk_config_t out; /*!< Information of the output picture and the target block */ + + // input data manipulation + bool bg_rgb_swap; /*!< Whether to swap the background input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ + bool bg_byte_swap; /*!< Whether to swap the background input data in byte. Only available feature if input BG picture color mode is ARGB8888 or RGB565 */ + ppa_alpha_update_mode_t bg_alpha_update_mode; /*!< Select whether the alpha channel of the input background picture needs update */ + union { + uint32_t bg_alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float bg_alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; + bool fg_rgb_swap; /*!< Whether to swap the foreground input data in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) */ + bool fg_byte_swap; /*!< Whether to swap the foreground input data in byte. Only available feature if input FG picture color mode is ARGB8888 or RGB565 */ + ppa_alpha_update_mode_t fg_alpha_update_mode; /*!< Select whether the alpha channel of the input foreground picture needs update */ + union { + uint32_t fg_alpha_fix_val; /*!< Range: [0, 255] + When PPA_ALPHA_FIX_VALUE mode is selected, alpha_fix_val is the new alpha value to replace the input alpha value (output_alpha = alpha_fix_val) */ + float fg_alpha_scale_ratio; /*!< Range: (0, 1) + When PPA_ALPHA_SCALE mode is selected, alpha_scale_ratio is the multiplier to the input alpha value (output_alpha = alpha_scale_ratio * input_alpha) + Ratio resolution is 1/256 */ + }; + color_pixel_rgb888_data_t fg_fix_rgb_val; /*!< When in_fg.blend_cm is PPA_BLEND_COLOR_MODE_A8/4, this field can be used to set a fixed color for the foreground, in RGB888 format */ + + // color-keying + // A pixel, where its background element and foreground element are both out of their color-keying ranges, will follow Alpha Blending + bool bg_ck_en; /*!< Whether to enable color keying for background + If not enabled, all background pixels are considered as out of the color-keying range */ + color_pixel_rgb888_data_t bg_ck_rgb_low_thres; /*!< The lower threshold of the color-keying range for the background, in RGB888 format */ + color_pixel_rgb888_data_t bg_ck_rgb_high_thres;/*!< The higher threshold of the color-keying range for the background, in RGB888 format */ + bool fg_ck_en; /*!< Whether to enable color keying for foreground + If not enabled, all foreground pixels are considered as out of the color-keying range */ + color_pixel_rgb888_data_t fg_ck_rgb_low_thres; /*!< The lower threshold of the color-keying range for the foreground, in RGB888 format */ + color_pixel_rgb888_data_t fg_ck_rgb_high_thres;/*!< The higher threshold of the color-keying range for the foreground, in RGB888 format */ + color_pixel_rgb888_data_t ck_rgb_default_val; /*!< The color to overwrite when a pixel, where its background element and foreground element are both within their color-keying ranges, in RGB888 format */ + bool ck_reverse_bg2fg; /*!< If this bit is set, in color-keying, for the pixel, where its background element is in the color range, but its foreground element is not in the color range, it will output the foreground element instead of the background element */ + + ppa_trans_mode_t mode; /*!< Determines whether to block inside the operation functions, see `ppa_trans_mode_t` */ + void *user_data; /*!< User registered data to be passed into `done_cb` callback function */ +} ppa_blend_oper_config_t; + +/** + * @brief Perform a blending operation to a picture + * + * @param[in] ppa_client PPA client handle that has been registered to do blend operations + * @param[in] config Pointer to a collection of configurations for the blend operation transaction, ppa_blend_oper_config_t + * + * @return + * - ESP_OK: Perform a blend operation successfully + * - ESP_ERR_INVALID_ARG: Perform a blend operation failed because of invalid argument + * - ESP_FAIL: Perform a blend operation failed because the client's pending transactions has reached its maximum capacity + */ +esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_config_t *config); + +/** + * @brief A collection of configuration items to do a PPA fill operation transaction + */ +typedef struct { + ppa_out_pic_blk_config_t out; /*!< Information of the output picture and the target block */ + + uint32_t fill_block_w; /*!< The width of the block to be filled (unit: pixel) */ + uint32_t fill_block_h; /*!< The height of the block to be filled (unit: pixel) */ + color_pixel_argb8888_data_t fill_argb_color; /*!< The color to be filled, in ARGB8888 format */ + + ppa_trans_mode_t mode; /*!< Determines whether to block inside the operation functions, see `ppa_trans_mode_t` */ + void *user_data; /*!< User registered data to be passed into `done_cb` callback function */ +} ppa_fill_oper_config_t; + +/** + * @brief Perform a filling operation to a picture + * + * @param[in] ppa_client PPA client handle that has been registered to do fill operations + * @param[in] config Pointer to a collection of configurations for the fill operation transaction, ppa_fill_oper_config_t + * + * @return + * - ESP_OK: Perform a fill operation successfully + * - ESP_ERR_INVALID_ARG: Perform a fill operation failed because of invalid argument + * - ESP_FAIL: Perform a fill operation failed because the client's pending transactions has reached its maximum capacity + */ +esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config_t *config); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c new file mode 100644 index 00000000000..e9b96ff5634 --- /dev/null +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -0,0 +1,284 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "driver/ppa.h" +#include "ppa_priv.h" +#include "esp_private/dma2d.h" +#include "hal/ppa_ll.h" +#include "esp_cache.h" +#include "esp_memory_utils.h" +#include "soc/dma2d_channel.h" + +static const char *TAG = "ppa_blend"; + +bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config) +{ + assert(num_chans == 3 && dma2d_chans && user_config); + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)user_config; + assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_BLEND && trans_on_picked_desc->blend_desc && trans_on_picked_desc->ppa_engine); + + ppa_blend_oper_t *blend_trans_desc = (ppa_blend_oper_t *)trans_on_picked_desc->blend_desc; + ppa_blend_engine_t *blend_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_blend_engine_t, base); + ppa_platform_t *platform = blend_engine->base.platform; + + // Reset blending engine + ppa_ll_blend_reset(platform->hal.dev); + + // Get the required 2D-DMA channel handles + dma2d_channel_handle_t dma2d_tx_bg_chan = NULL; + dma2d_channel_handle_t dma2d_tx_fg_chan = NULL; + dma2d_channel_handle_t dma2d_rx_chan = NULL; + for (uint32_t i = 0; i < num_chans; i++) { + if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_TX) { + if (!dma2d_tx_bg_chan) { + dma2d_tx_bg_chan = dma2d_chans[i].chan; + } else { + dma2d_tx_fg_chan = dma2d_chans[i].chan; + } + } + if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_RX) { + dma2d_rx_chan = dma2d_chans[i].chan; + } + } + assert(dma2d_tx_bg_chan && dma2d_tx_fg_chan && dma2d_rx_chan); + + color_space_pixel_format_t in_bg_pixel_format = { + .color_type_id = blend_trans_desc->in_bg.blend_cm, + }; + color_space_pixel_format_t in_fg_pixel_format = { + .color_type_id = blend_trans_desc->in_fg.blend_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = blend_trans_desc->out.blend_cm, + }; + + // Fill 2D-DMA descriptors + blend_engine->dma_tx_bg_desc->vb_size = blend_trans_desc->in_bg.block_h; + blend_engine->dma_tx_bg_desc->hb_length = blend_trans_desc->in_bg.block_w; + blend_engine->dma_tx_bg_desc->err_eof = 0; + blend_engine->dma_tx_bg_desc->dma2d_en = 1; + blend_engine->dma_tx_bg_desc->suc_eof = 1; + blend_engine->dma_tx_bg_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + blend_engine->dma_tx_bg_desc->va_size = blend_trans_desc->in_bg.pic_h; + blend_engine->dma_tx_bg_desc->ha_length = blend_trans_desc->in_bg.pic_w; + blend_engine->dma_tx_bg_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(in_bg_pixel_format); + blend_engine->dma_tx_bg_desc->y = blend_trans_desc->in_bg.block_offset_y; + blend_engine->dma_tx_bg_desc->x = blend_trans_desc->in_bg.block_offset_x; + blend_engine->dma_tx_bg_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + blend_engine->dma_tx_bg_desc->buffer = (void *)blend_trans_desc->in_bg.buffer; + blend_engine->dma_tx_bg_desc->next = NULL; + + blend_engine->dma_tx_fg_desc->vb_size = blend_trans_desc->in_fg.block_h; + blend_engine->dma_tx_fg_desc->hb_length = blend_trans_desc->in_fg.block_w; + blend_engine->dma_tx_fg_desc->err_eof = 0; + blend_engine->dma_tx_fg_desc->dma2d_en = 1; + blend_engine->dma_tx_fg_desc->suc_eof = 1; + blend_engine->dma_tx_fg_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + blend_engine->dma_tx_fg_desc->va_size = blend_trans_desc->in_fg.pic_h; + blend_engine->dma_tx_fg_desc->ha_length = blend_trans_desc->in_fg.pic_w; + blend_engine->dma_tx_fg_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(in_fg_pixel_format); + blend_engine->dma_tx_fg_desc->y = blend_trans_desc->in_fg.block_offset_y; + blend_engine->dma_tx_fg_desc->x = blend_trans_desc->in_fg.block_offset_x; + blend_engine->dma_tx_fg_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + blend_engine->dma_tx_fg_desc->buffer = (void *)blend_trans_desc->in_fg.buffer; + blend_engine->dma_tx_fg_desc->next = NULL; + + blend_engine->dma_rx_desc->vb_size = blend_trans_desc->in_fg.block_h; // in_bg.block_h == in_fg.block_h + blend_engine->dma_rx_desc->hb_length = blend_trans_desc->in_fg.block_w; // in_bg.block_w == in_fg.block_w + blend_engine->dma_rx_desc->err_eof = 0; + blend_engine->dma_rx_desc->dma2d_en = 1; + blend_engine->dma_rx_desc->suc_eof = 1; + blend_engine->dma_rx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + blend_engine->dma_rx_desc->va_size = blend_trans_desc->out.pic_h; + blend_engine->dma_rx_desc->ha_length = blend_trans_desc->out.pic_w; + blend_engine->dma_rx_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(out_pixel_format); + blend_engine->dma_rx_desc->y = blend_trans_desc->out.block_offset_y; + blend_engine->dma_rx_desc->x = blend_trans_desc->out.block_offset_x; + blend_engine->dma_rx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + blend_engine->dma_rx_desc->buffer = (void *)blend_trans_desc->out.buffer; + blend_engine->dma_rx_desc->next = NULL; + + esp_cache_msync((void *)blend_engine->dma_tx_bg_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync((void *)blend_engine->dma_tx_fg_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync((void *)blend_engine->dma_rx_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + // Configure 2D-DMA channels + dma2d_trigger_t trig_periph = { + .periph = DMA2D_TRIG_PERIPH_PPA_BLEND, + .periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_BG_TX, + }; + dma2d_connect(dma2d_tx_bg_chan, &trig_periph); + trig_periph.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_FG_TX; + dma2d_connect(dma2d_tx_fg_chan, &trig_periph); + trig_periph.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX; + dma2d_connect(dma2d_rx_chan, &trig_periph); + + dma2d_transfer_ability_t dma_transfer_ability = { + .data_burst_length = blend_trans_desc->data_burst_length, + .desc_burst_en = true, + .mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE, + }; + dma2d_set_transfer_ability(dma2d_tx_bg_chan, &dma_transfer_ability); + dma2d_set_transfer_ability(dma2d_tx_fg_chan, &dma_transfer_ability); + dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability); + + dma2d_rx_event_callbacks_t dma_event_cbs = { + .on_recv_eof = ppa_transaction_done_cb, + }; + dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm); + + dma2d_set_desc_addr(dma2d_tx_bg_chan, (intptr_t)blend_engine->dma_tx_bg_desc); + dma2d_set_desc_addr(dma2d_tx_fg_chan, (intptr_t)blend_engine->dma_tx_fg_desc); + dma2d_set_desc_addr(dma2d_rx_chan, (intptr_t)blend_engine->dma_rx_desc); + dma2d_start(dma2d_tx_bg_chan); + dma2d_start(dma2d_tx_fg_chan); + dma2d_start(dma2d_rx_chan); + + // Configure PPA Blending engine + ppa_ll_blend_set_rx_bg_color_mode(platform->hal.dev, blend_trans_desc->in_bg.blend_cm); + ppa_ll_blend_enable_rx_bg_byte_swap(platform->hal.dev, blend_trans_desc->bg_byte_swap); + ppa_ll_blend_enable_rx_bg_rgb_swap(platform->hal.dev, blend_trans_desc->bg_rgb_swap); + ppa_ll_blend_configure_rx_bg_alpha(platform->hal.dev, blend_trans_desc->bg_alpha_update_mode, blend_trans_desc->bg_alpha_value); + + ppa_ll_blend_set_rx_fg_color_mode(platform->hal.dev, blend_trans_desc->in_fg.blend_cm); + if (COLOR_SPACE_TYPE((uint32_t)blend_trans_desc->in_fg.blend_cm) == COLOR_SPACE_ALPHA) { + ppa_ll_blend_set_rx_fg_fix_rgb(platform->hal.dev, &blend_trans_desc->fg_fix_rgb_val); + } + ppa_ll_blend_enable_rx_fg_byte_swap(platform->hal.dev, blend_trans_desc->fg_byte_swap); + ppa_ll_blend_enable_rx_fg_rgb_swap(platform->hal.dev, blend_trans_desc->fg_rgb_swap); + ppa_ll_blend_configure_rx_fg_alpha(platform->hal.dev, blend_trans_desc->fg_alpha_update_mode, blend_trans_desc->fg_alpha_value); + + ppa_ll_blend_set_tx_color_mode(platform->hal.dev, blend_trans_desc->out.blend_cm); + + // Color keying + color_pixel_rgb888_data_t rgb888_min = {.b = 0x00, .g = 0x00, .r = 0x00}; + color_pixel_rgb888_data_t rgb888_max = {.b = 0xFF, .g = 0xFF, .r = 0xFF}; + ppa_ll_blend_configure_rx_bg_ck_range(platform->hal.dev, + blend_trans_desc->bg_ck_en ? &blend_trans_desc->bg_ck_rgb_low_thres : &rgb888_max, + blend_trans_desc->bg_ck_en ? &blend_trans_desc->bg_ck_rgb_high_thres : &rgb888_min); + ppa_ll_blend_configure_rx_fg_ck_range(platform->hal.dev, + blend_trans_desc->fg_ck_en ? &blend_trans_desc->fg_ck_rgb_low_thres : &rgb888_max, + blend_trans_desc->fg_ck_en ? &blend_trans_desc->fg_ck_rgb_high_thres : &rgb888_min); + ppa_ll_blend_set_ck_default_rgb(platform->hal.dev, (blend_trans_desc->bg_ck_en && blend_trans_desc->fg_ck_en) ? &blend_trans_desc->ck_rgb_default_val : &rgb888_min); + ppa_ll_blend_enable_ck_fg_bg_reverse(platform->hal.dev, blend_trans_desc->ck_reverse_bg2fg); + + ppa_ll_blend_start(platform->hal.dev, PPA_LL_BLEND_TRANS_MODE_BLEND); + + // No need to yield + return false; +} + +esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_config_t *config) +{ + ESP_RETURN_ON_FALSE(ppa_client && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(ppa_client->oper_type == PPA_OPERATION_BLEND, ESP_ERR_INVALID_ARG, TAG, "client is not for blend operations"); + ESP_RETURN_ON_FALSE(config->mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode"); + // in_buffer could be anywhere (ram, flash, psram), out_buffer ptr cannot in flash region + ESP_RETURN_ON_FALSE(esp_ptr_internal(config->out.buffer) || esp_ptr_external_ram(config->out.buffer), ESP_ERR_INVALID_ARG, TAG, "invalid out.buffer addr"); + uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; + ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0, + ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); + color_space_pixel_format_t out_pixel_format = { + .color_type_id = config->out.blend_cm, + }; + uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8; + ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size"); + ESP_RETURN_ON_FALSE(config->in_bg.block_w == config->in_fg.block_w && config->in_bg.block_h == config->in_fg.block_h, + ESP_ERR_INVALID_ARG, TAG, "in_bg.block_w/h must be equal to in_fg.block_w/h"); + if (config->bg_byte_swap) { + PPA_CHECK_CM_SUPPORT_BYTE_SWAP("in_bg.blend", (uint32_t)config->in_bg.blend_cm); + } + if (config->bg_rgb_swap) { + PPA_CHECK_CM_SUPPORT_RGB_SWAP("in_bg.blend", (uint32_t)config->in_bg.blend_cm); + } + if (config->fg_byte_swap) { + PPA_CHECK_CM_SUPPORT_BYTE_SWAP("in_fg.blend", (uint32_t)config->in_fg.blend_cm); + } + if (config->fg_rgb_swap) { + PPA_CHECK_CM_SUPPORT_RGB_SWAP("in_fg.blend", (uint32_t)config->in_fg.blend_cm); + } + uint32_t new_bg_alpha_value = 0; + if (config->bg_alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->bg_alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid bg_alpha_fix_val"); + new_bg_alpha_value = config->bg_alpha_fix_val; + } else if (config->bg_alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->bg_alpha_scale_ratio > 0 && config->bg_alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid bg_alpha_scale_ratio"); + new_bg_alpha_value = (uint32_t)(config->bg_alpha_scale_ratio * 256); + } + uint32_t new_fg_alpha_value = 0; + if (config->fg_alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->fg_alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid fg_alpha_fix_val"); + new_fg_alpha_value = config->fg_alpha_fix_val; + } else if (config->fg_alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->fg_alpha_scale_ratio > 0 && config->fg_alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid fg_alpha_scale_ratio"); + new_fg_alpha_value = (uint32_t)(config->fg_alpha_scale_ratio * 256); + } + // if (config->in_bg.blend_cm == PPA_BLEND_COLOR_MODE_L4) { + // ESP_RETURN_ON_FALSE(config->in_bg.block_w % 2 == 0 && config->in_bg.block_offset_x % 2 == 0, + // ESP_ERR_INVALID_ARG, TAG, "in_bg.block_w and in_bg.block_offset_x must be even"); + // } + if (config->in_fg.blend_cm == PPA_BLEND_COLOR_MODE_A4) { // || config->in_fg.blend_cm == PPA_BLEND_COLOR_MODE_L4 + ESP_RETURN_ON_FALSE(config->in_fg.block_w % 2 == 0 && config->in_fg.block_offset_x % 2 == 0, + ESP_ERR_INVALID_ARG, TAG, "in_fg.block_w and in_fg.block_offset_x must be even"); + } + // To reduce complexity, color_mode, alpha_update_mode correctness are checked in their corresponding LL functions + + // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) + // Write back in_bg_buffer, in_fg_buffer extended windows (alignment not necessary on C2M direction) + color_space_pixel_format_t in_bg_pixel_format = { + .color_type_id = config->in_bg.blend_cm, + }; + uint32_t in_bg_pixel_depth = color_hal_pixel_format_get_bit_depth(in_bg_pixel_format); // bits + uint32_t in_bg_ext_window = (uint32_t)config->in_bg.buffer + config->in_bg.block_offset_y * config->in_bg.pic_w * in_bg_pixel_depth / 8; + uint32_t in_bg_ext_window_len = config->in_bg.pic_w * config->in_bg.block_h * in_bg_pixel_depth / 8; + esp_cache_msync((void *)in_bg_ext_window, in_bg_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + color_space_pixel_format_t in_fg_pixel_format = { + .color_type_id = config->in_fg.blend_cm, + }; + uint32_t in_fg_pixel_depth = color_hal_pixel_format_get_bit_depth(in_fg_pixel_format); // bits + uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; + uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; + esp_cache_msync((void *)in_fg_ext_window, in_fg_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + // Invalidate out_buffer entire picture (alignment strict on M2C direction) + esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + + esp_err_t ret = ESP_OK; + ppa_trans_t *trans_elm = NULL; + if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) { + dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc; + + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config; + + ppa_blend_oper_t *blend_trans_desc = (ppa_blend_oper_t *)trans_on_picked_desc->blend_desc; + memcpy(blend_trans_desc, config, sizeof(ppa_blend_oper_config_t)); + blend_trans_desc->bg_alpha_value = new_bg_alpha_value; + blend_trans_desc->fg_alpha_value = new_fg_alpha_value; + blend_trans_desc->data_burst_length = ppa_client->data_burst_length; + + trans_on_picked_desc->ppa_engine = ppa_client->engine; + trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND; + + dma_trans_desc->tx_channel_num = 2; + dma_trans_desc->rx_channel_num = 1; + dma_trans_desc->channel_flags = 0; + dma_trans_desc->specified_tx_channel_mask = 0; + dma_trans_desc->specified_rx_channel_mask = 0; + + trans_elm->client = ppa_client; + trans_elm->user_data = config->user_data; + xSemaphoreTake(trans_elm->sem, 0); // Ensure no transaction semaphore before transaction starts + + ret = ppa_do_operation(ppa_client, ppa_client->engine, trans_elm, config->mode); + if (ret != ESP_OK) { + ppa_recycle_transaction(ppa_client, trans_elm); + } + } else { + ret = ESP_FAIL; + ESP_LOGE(TAG, "exceed maximum pending transactions for the client, consider increase max_pending_trans_num"); + } + return ret; +} diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c new file mode 100644 index 00000000000..6f309d92051 --- /dev/null +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -0,0 +1,517 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_check.h" +#include "esp_log.h" +#include "freertos/portmacro.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/idf_additions.h" +#include "freertos/queue.h" +#include "esp_heap_caps.h" +#include "esp_cache.h" +#include "esp_private/esp_cache_private.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "driver/ppa.h" +#include "ppa_priv.h" +#include "esp_private/dma2d.h" +#include "hal/dma2d_ll.h" +#include "hal/ppa_hal.h" +#include "hal/ppa_ll.h" +#include "hal/ppa_types.h" +#include "esp_private/periph_ctrl.h" + +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) + +static const char *TAG = "ppa_core"; + +// PPA driver platform +static ppa_platform_t s_platform = { + .spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, +}; + +static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine); +static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine); +static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t trans_elm_num, ppa_operation_t oper_type); +static void ppa_free_transaction(ppa_trans_t *trans_elm); + +const dma2d_trans_on_picked_callback_t ppa_oper_trans_on_picked_func[PPA_OPERATION_INVALID] = { + [PPA_OPERATION_SRM] = ppa_srm_transaction_on_picked, + [PPA_OPERATION_BLEND] = ppa_blend_transaction_on_picked, + [PPA_OPERATION_FILL] = ppa_fill_transaction_on_picked, +}; + +static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(config && ret_engine, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->engine == PPA_ENGINE_TYPE_SRM || config->engine == PPA_ENGINE_TYPE_BLEND, ESP_ERR_INVALID_ARG, TAG, "invalid engine"); + + *ret_engine = NULL; + + uint32_t data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + size_t alignment = MAX(DMA2D_LL_DESC_ALIGNMENT, data_cache_line_size); + + _lock_acquire(&s_platform.mutex); + if (s_platform.dma_desc_mem_size == 0) { + s_platform.dma_desc_mem_size = ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); + } + if (s_platform.buf_alignment_size == 0) { + esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.buf_alignment_size); + } + + if (config->engine == PPA_ENGINE_TYPE_SRM) { + if (!s_platform.srm) { + ppa_srm_engine_t *srm_engine = heap_caps_calloc(1, sizeof(ppa_srm_engine_t), PPA_MEM_ALLOC_CAPS); + SemaphoreHandle_t srm_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS); + dma2d_descriptor_t *srm_tx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + dma2d_descriptor_t *srm_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (srm_engine && srm_sem && srm_tx_dma_desc && srm_rx_dma_desc) { + srm_engine->dma_tx_desc = srm_tx_dma_desc; + srm_engine->dma_rx_desc = srm_rx_dma_desc; + srm_engine->base.platform = &s_platform; + srm_engine->base.type = PPA_ENGINE_TYPE_SRM; + srm_engine->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + srm_engine->base.sem = srm_sem; + xSemaphoreGive(srm_engine->base.sem); + STAILQ_INIT(&srm_engine->base.trans_stailq); + s_platform.srm = srm_engine; + s_platform.srm_engine_ref_count++; + *ret_engine = &srm_engine->base; + + // TODO: Register PPA interrupt? Useful for SRM parameter error. If SRM parameter error, blocks at 2D-DMA, transaction can never finish, stuck... + // need a way to force end + } else { + ret = ESP_ERR_NO_MEM; + ESP_LOGE(TAG, "no mem to register PPA SRM engine"); + free(srm_engine); + if (srm_sem) { + vSemaphoreDeleteWithCaps(srm_sem); + } + free(srm_tx_dma_desc); + free(srm_rx_dma_desc); + } + +#if CONFIG_PM_ENABLE + if (ret == ESP_OK) { + ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ppa_srm", &srm_engine->base.pm_lock); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "create pm lock failed"); + } + } +#endif + } else { + // SRM engine already registered + s_platform.srm_engine_ref_count++; + *ret_engine = &s_platform.srm->base; + } + } else if (config->engine == PPA_ENGINE_TYPE_BLEND) { + if (!s_platform.blending) { + ppa_blend_engine_t *blending_engine = heap_caps_calloc(1, sizeof(ppa_blend_engine_t), PPA_MEM_ALLOC_CAPS); + SemaphoreHandle_t blending_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS); + dma2d_descriptor_t *blending_tx_bg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + dma2d_descriptor_t *blending_tx_fg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + dma2d_descriptor_t *blending_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + if (blending_engine && blending_sem && blending_tx_bg_dma_desc && blending_tx_fg_dma_desc && blending_rx_dma_desc) { + blending_engine->dma_tx_bg_desc = blending_tx_bg_dma_desc; + blending_engine->dma_tx_fg_desc = blending_tx_fg_dma_desc; + blending_engine->dma_rx_desc = blending_rx_dma_desc; + blending_engine->base.platform = &s_platform; + blending_engine->base.type = PPA_ENGINE_TYPE_BLEND; + blending_engine->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + blending_engine->base.sem = blending_sem; + xSemaphoreGive(blending_engine->base.sem); + STAILQ_INIT(&blending_engine->base.trans_stailq); + s_platform.blending = blending_engine; + s_platform.blend_engine_ref_count++; + *ret_engine = &blending_engine->base; + } else { + ret = ESP_ERR_NO_MEM; + ESP_LOGE(TAG, "no mem to register PPA Blending engine"); + free(blending_engine); + if (blending_sem) { + vSemaphoreDeleteWithCaps(blending_sem); + } + free(blending_tx_bg_dma_desc); + free(blending_tx_fg_dma_desc); + free(blending_rx_dma_desc); + } + +#if CONFIG_PM_ENABLE + if (ret == ESP_OK) { + ret = esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "ppa_blending", &blending_engine->base.pm_lock); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "create pm lock failed"); + } + } +#endif + } else { + // Blending engine already registered + s_platform.blend_engine_ref_count++; + *ret_engine = &s_platform.blending->base; + } + } + + if (ret == ESP_OK) { + if (!s_platform.hal.dev) { + assert(!s_platform.dma2d_pool_handle); + + // Enable the bus clock to access PPA registers + PERIPH_RCC_ATOMIC() { + ppa_ll_enable_bus_clock(true); + ppa_ll_reset_register(); + } + + ppa_hal_init(&s_platform.hal); // initialize HAL context + + // Get 2D-DMA pool handle + dma2d_pool_config_t dma2d_config = { + .pool_id = 0, + }; + ret = dma2d_acquire_pool(&dma2d_config, &s_platform.dma2d_pool_handle); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "install 2D-DMA failed"); + goto wrap_up; + } + } + } +wrap_up: + _lock_release(&s_platform.mutex); + + if (ret != ESP_OK && *ret_engine != NULL) { + ppa_engine_release(*ret_engine); + } + + return ret; +} + +static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(ppa_engine, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + _lock_acquire(&s_platform.mutex); + if (ppa_engine->type == PPA_ENGINE_TYPE_SRM) { + ppa_srm_engine_t *srm_engine = __containerof(ppa_engine, ppa_srm_engine_t, base); + s_platform.srm_engine_ref_count--; + if (s_platform.srm_engine_ref_count == 0) { + assert(STAILQ_EMPTY(&srm_engine->base.trans_stailq)); + // Now, time to free + s_platform.srm = NULL; + free(srm_engine->dma_tx_desc); + free(srm_engine->dma_rx_desc); + vSemaphoreDeleteWithCaps(srm_engine->base.sem); +#if CONFIG_PM_ENABLE + if (srm_engine->base.pm_lock) { + ret = esp_pm_lock_delete(srm_engine->base.pm_lock); + assert(ret == ESP_OK); + } +#endif + free(srm_engine); + } + } else if (ppa_engine->type == PPA_ENGINE_TYPE_BLEND) { + ppa_blend_engine_t *blending_engine = __containerof(ppa_engine, ppa_blend_engine_t, base); + s_platform.blend_engine_ref_count--; + if (s_platform.blend_engine_ref_count == 0) { + assert(STAILQ_EMPTY(&blending_engine->base.trans_stailq)); + // Now, time to free + s_platform.blending = NULL; + free(blending_engine->dma_tx_bg_desc); + free(blending_engine->dma_tx_fg_desc); + free(blending_engine->dma_rx_desc); + vSemaphoreDeleteWithCaps(blending_engine->base.sem); +#if CONFIG_PM_ENABLE + if (blending_engine->base.pm_lock) { + ret = esp_pm_lock_delete(blending_engine->base.pm_lock); + assert(ret == ESP_OK); + } +#endif + free(blending_engine); + } + } + + if (!s_platform.srm && !s_platform.blending) { + assert(s_platform.srm_engine_ref_count == 0 && s_platform.blend_engine_ref_count == 0); + + if (s_platform.dma2d_pool_handle) { + dma2d_release_pool(s_platform.dma2d_pool_handle); // TODO: check return value. If not ESP_OK, then must be error on other 2D-DMA clients :( Give a warning log? + s_platform.dma2d_pool_handle = NULL; + } + + ppa_hal_deinit(&s_platform.hal); // De-initialize HAL context + + // Disable the bus clock to access PPA registers + PERIPH_RCC_ATOMIC() { + ppa_ll_enable_bus_clock(false); + } + } + _lock_release(&s_platform.mutex); + return ret; +} + +esp_err_t ppa_register_client(const ppa_client_config_t *config, ppa_client_handle_t *ret_client) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(config && ret_client, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(config->oper_type < PPA_OPERATION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown operation"); + + ppa_client_t *client = (ppa_client_t *)heap_caps_calloc(1, sizeof(ppa_client_t), PPA_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(client, ESP_ERR_NO_MEM, TAG, "no mem to register client"); + + // Allocate memory for storing transaction contexts and create a queue to save these trans_elm_ptr + uint32_t queue_size = MAX(1, config->max_pending_trans_num); + client->trans_elm_ptr_queue = xQueueCreateWithCaps(queue_size, sizeof(uint32_t), PPA_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(client->trans_elm_ptr_queue && ppa_malloc_transaction(client->trans_elm_ptr_queue, queue_size, config->oper_type), + ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage"); + + client->oper_type = config->oper_type; + client->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + client->data_burst_length = config->data_burst_length ? config->data_burst_length : PPA_DATA_BURST_LENGTH_128; + if (config->oper_type == PPA_OPERATION_SRM) { + ppa_engine_config_t engine_config = { + .engine = PPA_ENGINE_TYPE_SRM, + }; + ESP_GOTO_ON_ERROR(ppa_engine_acquire(&engine_config, &client->engine), err, TAG, "unable to acquire SRM engine"); + } else if (config->oper_type == PPA_OPERATION_BLEND || config->oper_type == PPA_OPERATION_FILL) { + ppa_engine_config_t engine_config = { + .engine = PPA_ENGINE_TYPE_BLEND, + }; + ESP_GOTO_ON_ERROR(ppa_engine_acquire(&engine_config, &client->engine), err, TAG, "unable to acquire Blending engine"); + } + *ret_client = client; + +err: + if (ret != ESP_OK) { + ppa_unregister_client(client); + } + return ret; +} + +esp_err_t ppa_unregister_client(ppa_client_handle_t ppa_client) +{ + ESP_RETURN_ON_FALSE(ppa_client, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + bool do_unregister = false; + portENTER_CRITICAL(&ppa_client->spinlock); + if (ppa_client->trans_cnt == 0) { + do_unregister = true; + } + portEXIT_CRITICAL(&ppa_client->spinlock); + ESP_RETURN_ON_FALSE(do_unregister, ESP_ERR_INVALID_STATE, TAG, "client still has unprocessed trans"); + + if (ppa_client->engine) { + ppa_engine_release(ppa_client->engine); + } + + if (ppa_client->trans_elm_ptr_queue) { + ppa_trans_t *trans_elm = NULL; + while (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) { + ppa_free_transaction(trans_elm); + } + vQueueDeleteWithCaps(ppa_client->trans_elm_ptr_queue); + } + free(ppa_client); + return ESP_OK; +} + +esp_err_t ppa_client_register_event_callbacks(ppa_client_handle_t ppa_client, const ppa_event_callbacks_t *cbs) +{ + ESP_RETURN_ON_FALSE(ppa_client && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + ppa_client->done_cb = cbs->on_trans_done; + return ESP_OK; +} + +// Each PPA engine should only have one transaction being pushed to 2D-DMA queue, the rest transactions should stay in engine's own transaction queue. +// This is to avoid 2D-DMA channels being hold, but not actually being used (waiting for PPA engine to be free) +static esp_err_t ppa_dma2d_enqueue(const ppa_trans_t *trans_elm) +{ + return dma2d_enqueue(s_platform.dma2d_pool_handle, trans_elm->trans_desc, trans_elm->dma_trans_placeholder); +} + +static bool ppa_malloc_transaction(QueueHandle_t trans_elm_ptr_queue, uint32_t trans_elm_num, ppa_operation_t oper_type) +{ + bool res = true; + size_t ppa_trans_desc_size = (oper_type == PPA_OPERATION_SRM) ? sizeof(ppa_srm_oper_t) : + (oper_type == PPA_OPERATION_BLEND) ? sizeof(ppa_blend_oper_t) : + (oper_type == PPA_OPERATION_FILL) ? sizeof(ppa_fill_oper_t) : 0; + assert(ppa_trans_desc_size != 0); + size_t trans_elm_storage_size = sizeof(ppa_trans_t) + SIZEOF_DMA2D_TRANS_T + sizeof(dma2d_trans_config_t) + sizeof(ppa_dma2d_trans_on_picked_config_t) + ppa_trans_desc_size; + for (int i = 0; i < trans_elm_num; i++) { + void *trans_elm_storage = heap_caps_calloc(1, trans_elm_storage_size, PPA_MEM_ALLOC_CAPS); + SemaphoreHandle_t ppa_trans_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS); + + if (!trans_elm_storage || !ppa_trans_sem) { + if (trans_elm_storage) { + free(trans_elm_storage); + } + if (ppa_trans_sem) { + vSemaphoreDeleteWithCaps(ppa_trans_sem); + } + res = false; + break; + } + + // Construct trans_elm + ppa_trans_t *new_trans_elm = (ppa_trans_t *)trans_elm_storage; + dma2d_trans_t *dma_trans_elm = (dma2d_trans_t *)((uint32_t)trans_elm_storage + sizeof(ppa_trans_t)); + dma2d_trans_config_t *dma_trans_desc = (dma2d_trans_config_t *)((uint32_t)dma_trans_elm + SIZEOF_DMA2D_TRANS_T); + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)((uint32_t)dma_trans_desc + sizeof(dma2d_trans_config_t)); + void *ppa_trans_desc = (void *)((uint32_t)trans_on_picked_desc + sizeof(ppa_dma2d_trans_on_picked_config_t)); + + trans_on_picked_desc->op_desc = ppa_trans_desc; + trans_on_picked_desc->trans_elm = new_trans_elm; + dma_trans_desc->user_config = (void *)trans_on_picked_desc; + dma_trans_desc->on_job_picked = ppa_oper_trans_on_picked_func[oper_type]; + new_trans_elm->trans_desc = dma_trans_desc; + new_trans_elm->dma_trans_placeholder = dma_trans_elm; + new_trans_elm->sem = ppa_trans_sem; + + // Fill the queue with allocated transaction element pointer + BaseType_t sent = xQueueSend(trans_elm_ptr_queue, &new_trans_elm, 0); + assert(sent); + } + return res; +} + +static void ppa_free_transaction(ppa_trans_t *trans_elm) +{ + if (trans_elm) { + if (trans_elm->sem) { + vSemaphoreDeleteWithCaps(trans_elm->sem); + } + free(trans_elm); + } +} + +bool ppa_recycle_transaction(ppa_client_handle_t ppa_client, ppa_trans_t *trans_elm) +{ + // Reset transaction and send back to client's trans_elm_ptr_queue + // TODO: To be very safe, we shall memset all to 0, and reconnect necessary pointers? + BaseType_t HPTaskAwoken; + BaseType_t sent = xQueueSendFromISR(ppa_client->trans_elm_ptr_queue, &trans_elm, &HPTaskAwoken); + assert(sent); + return HPTaskAwoken; +} + +esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_engine_base, ppa_trans_t *trans_elm, ppa_trans_mode_t mode) +{ + esp_err_t ret = ESP_OK; + esp_err_t pm_lock_ret __attribute__((unused)); + + portENTER_CRITICAL(&ppa_client->spinlock); + // Send transaction into PPA engine queue + portENTER_CRITICAL(&ppa_engine_base->spinlock); + STAILQ_INSERT_TAIL(&ppa_engine_base->trans_stailq, trans_elm, entry); + portEXIT_CRITICAL(&ppa_engine_base->spinlock); + ppa_client->trans_cnt++; + portEXIT_CRITICAL(&ppa_client->spinlock); + + TickType_t ticks_to_wait = (mode == PPA_TRANS_MODE_NON_BLOCKING) ? 0 : portMAX_DELAY; + if (xSemaphoreTake(ppa_engine_base->sem, ticks_to_wait) == pdTRUE) { + // Check if the transaction has already been started from the ISR + // If so, then the transaction should have been removed from queue at this moment (transaction completed) + bool found = false; + ppa_trans_t *temp = NULL; + portENTER_CRITICAL(&ppa_engine_base->spinlock); + STAILQ_FOREACH(temp, &ppa_engine_base->trans_stailq, entry) { + if (temp == trans_elm) { + found = true; + break; + } + } + portEXIT_CRITICAL(&ppa_engine_base->spinlock); + if (found) { +#if CONFIG_PM_ENABLE + pm_lock_ret = esp_pm_lock_acquire(ppa_engine_base->pm_lock); + assert((pm_lock_ret == ESP_OK) && "acquire pm_lock failed"); +#endif + ret = ppa_dma2d_enqueue(trans_elm); + if (ret != ESP_OK) { + portENTER_CRITICAL(&ppa_engine_base->spinlock); + STAILQ_REMOVE(&ppa_engine_base->trans_stailq, trans_elm, ppa_trans_s, entry); + portEXIT_CRITICAL(&ppa_engine_base->spinlock); + xSemaphoreGive(ppa_engine_base->sem); +#if CONFIG_PM_ENABLE + pm_lock_ret = esp_pm_lock_release(ppa_engine_base->pm_lock); + assert((pm_lock_ret == ESP_OK) && "release pm_lock failed"); +#endif + portENTER_CRITICAL(&ppa_client->spinlock); + ppa_client->trans_cnt--; + portEXIT_CRITICAL(&ppa_client->spinlock); + goto err; + } + } else { + xSemaphoreGive(ppa_engine_base->sem); + } + } + + if (mode == PPA_TRANS_MODE_BLOCKING) { + xSemaphoreTake(trans_elm->sem, portMAX_DELAY); // Given in the ISR + } + +err: + return ret; +} + +bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data) +{ + bool need_yield = false; + BaseType_t HPTaskAwoken; + ppa_trans_t *trans_elm = (ppa_trans_t *)user_data; + ppa_client_t *client = trans_elm->client; + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)trans_elm->trans_desc->user_config; + ppa_engine_t *engine_base = trans_on_picked_desc->ppa_engine; + // Save callback contexts + ppa_event_callback_t done_cb = client->done_cb; + void *trans_elm_user_data = trans_elm->user_data; + + ppa_trans_t *next_start_trans = NULL; + portENTER_CRITICAL_ISR(&engine_base->spinlock); + // Remove this transaction from transaction queue + STAILQ_REMOVE(&engine_base->trans_stailq, trans_elm, ppa_trans_s, entry); + next_start_trans = STAILQ_FIRST(&engine_base->trans_stailq); + portEXIT_CRITICAL_ISR(&engine_base->spinlock); + + portENTER_CRITICAL_ISR(&client->spinlock); + // Release transaction semaphore to unblock ppa_do_operation + xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken); + need_yield |= (HPTaskAwoken == pdTRUE); + + // Then recycle transaction elm + need_yield |= ppa_recycle_transaction(client, trans_elm); + + client->trans_cnt--; + portEXIT_CRITICAL_ISR(&client->spinlock); + + // If there is next trans in PPA engine queue, send it to DMA queue; otherwise, release the engine semaphore + if (next_start_trans) { + ppa_dma2d_enqueue(next_start_trans); + } else { + xSemaphoreGiveFromISR(engine_base->sem, &HPTaskAwoken); + need_yield |= (HPTaskAwoken == pdTRUE); +#if CONFIG_PM_ENABLE + esp_err_t pm_lock_ret = esp_pm_lock_release(engine_base->pm_lock); + assert(pm_lock_ret == ESP_OK); +#endif + } + + // Process last transaction's callback + if (done_cb) { + ppa_event_data_t edata = {}; + need_yield |= done_cb(client, &edata, trans_elm_user_data); + } + + return need_yield; +} diff --git a/components/esp_driver_ppa/src/ppa_fill.c b/components/esp_driver_ppa/src/ppa_fill.c new file mode 100644 index 00000000000..0411a47daaa --- /dev/null +++ b/components/esp_driver_ppa/src/ppa_fill.c @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "driver/ppa.h" +#include "ppa_priv.h" +#include "esp_private/dma2d.h" +#include "hal/ppa_ll.h" +#include "esp_cache.h" +#include "esp_memory_utils.h" +#include "soc/dma2d_channel.h" + +static const char *TAG = "ppa_fill"; + +bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config) +{ + assert(num_chans == 1 && dma2d_chans && user_config); + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)user_config; + assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_BLEND && trans_on_picked_desc->fill_desc && trans_on_picked_desc->ppa_engine); + + ppa_fill_oper_t *fill_trans_desc = (ppa_fill_oper_t *)trans_on_picked_desc->fill_desc; + ppa_blend_engine_t *blend_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_blend_engine_t, base); + ppa_platform_t *platform = blend_engine->base.platform; + + // Reset blending engine + ppa_ll_blend_reset(platform->hal.dev); + + // Get the required 2D-DMA channel handles + assert(dma2d_chans[0].dir == DMA2D_CHANNEL_DIRECTION_RX); + dma2d_channel_handle_t dma2d_rx_chan = dma2d_chans[0].chan; + + color_space_pixel_format_t out_pixel_format = { + .color_type_id = fill_trans_desc->out.fill_cm, + }; + + // Fill 2D-DMA descriptors + blend_engine->dma_rx_desc->vb_size = fill_trans_desc->fill_block_h; + blend_engine->dma_rx_desc->hb_length = fill_trans_desc->fill_block_w; + blend_engine->dma_rx_desc->err_eof = 0; + blend_engine->dma_rx_desc->dma2d_en = 1; + blend_engine->dma_rx_desc->suc_eof = 1; + blend_engine->dma_rx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + blend_engine->dma_rx_desc->va_size = fill_trans_desc->out.pic_h; + blend_engine->dma_rx_desc->ha_length = fill_trans_desc->out.pic_w; + blend_engine->dma_rx_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(out_pixel_format); + blend_engine->dma_rx_desc->y = fill_trans_desc->out.block_offset_y; + blend_engine->dma_rx_desc->x = fill_trans_desc->out.block_offset_x; + blend_engine->dma_rx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + blend_engine->dma_rx_desc->buffer = (void *)fill_trans_desc->out.buffer; + blend_engine->dma_rx_desc->next = NULL; + + esp_cache_msync((void *)blend_engine->dma_rx_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + // Configure 2D-DMA channels + dma2d_trigger_t trig_periph = { + .periph = DMA2D_TRIG_PERIPH_PPA_BLEND, + .periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX, + }; + dma2d_connect(dma2d_rx_chan, &trig_periph); + + dma2d_transfer_ability_t dma_transfer_ability = { + .data_burst_length = fill_trans_desc->data_burst_length, + .desc_burst_en = true, + .mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE, + }; + dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability); + + dma2d_rx_event_callbacks_t dma_event_cbs = { + .on_recv_eof = ppa_transaction_done_cb, + }; + dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm); + + dma2d_set_desc_addr(dma2d_rx_chan, (intptr_t)blend_engine->dma_rx_desc); + dma2d_start(dma2d_rx_chan); + + // Configure PPA Blending engine + ppa_ll_blend_configure_filling_block(platform->hal.dev, &fill_trans_desc->fill_argb_color, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h); + ppa_ll_blend_set_tx_color_mode(platform->hal.dev, fill_trans_desc->out.fill_cm); + + ppa_ll_blend_start(platform->hal.dev, PPA_LL_BLEND_TRANS_MODE_FILL); + + // No need to yield + return false; +} + +esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config_t *config) +{ + ESP_RETURN_ON_FALSE(ppa_client && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(ppa_client->oper_type == PPA_OPERATION_FILL, ESP_ERR_INVALID_ARG, TAG, "client is not for fill operations"); + ESP_RETURN_ON_FALSE(config->mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode"); + // out_buffer ptr cannot in flash region + ESP_RETURN_ON_FALSE(esp_ptr_internal(config->out.buffer) || esp_ptr_external_ram(config->out.buffer), ESP_ERR_INVALID_ARG, TAG, "invalid out.buffer addr"); + uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; + ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0, + ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); + color_space_pixel_format_t out_pixel_format = { + .color_type_id = config->out.fill_cm, + }; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); + uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * out_pixel_depth / 8; + ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size"); + // To reduce complexity, color_mode, fill_block_w/h correctness are checked in their corresponding LL functions + + // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) + // Write back buffer extended window (alignment not necessary on C2M direction) + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; + esp_cache_msync((void *)out_ext_window, out_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + // Invalidate out_buffer entire picture (alignment strict on M2C direction) + esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + + esp_err_t ret = ESP_OK; + ppa_trans_t *trans_elm = NULL; + if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) { + dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc; + + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config; + + ppa_fill_oper_t *fill_trans_desc = (ppa_fill_oper_t *)trans_on_picked_desc->fill_desc; + memcpy(fill_trans_desc, config, sizeof(ppa_fill_oper_config_t)); + fill_trans_desc->data_burst_length = ppa_client->data_burst_length; + + trans_on_picked_desc->ppa_engine = ppa_client->engine; + trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND; + + dma_trans_desc->tx_channel_num = 0; + dma_trans_desc->rx_channel_num = 1; + dma_trans_desc->channel_flags = 0; + dma_trans_desc->specified_tx_channel_mask = 0; + dma_trans_desc->specified_rx_channel_mask = 0; + + trans_elm->client = ppa_client; + trans_elm->user_data = config->user_data; + xSemaphoreTake(trans_elm->sem, 0); // Ensure no transaction semaphore before transaction starts + + ret = ppa_do_operation(ppa_client, ppa_client->engine, trans_elm, config->mode); + if (ret != ESP_OK) { + ppa_recycle_transaction(ppa_client, trans_elm); + } + } else { + ret = ESP_FAIL; + ESP_LOGE(TAG, "exceed maximum pending transactions for the client, consider increase max_pending_trans_num"); + } + return ret; +} diff --git a/components/esp_driver_ppa/src/ppa_priv.h b/components/esp_driver_ppa/src/ppa_priv.h new file mode 100644 index 00000000000..e63322df08b --- /dev/null +++ b/components/esp_driver_ppa/src/ppa_priv.h @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "sdkconfig.h" +#include "driver/ppa.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "esp_private/dma2d.h" +#include "hal/dma2d_types.h" +#include "hal/ppa_types.h" +#include "hal/ppa_hal.h" +#include "esp_pm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PPA_MEM_ALLOC_CAPS (MALLOC_CAP_DEFAULT) + +#define PPA_PM_LOCK_NAME_LEN_MAX 16 + +#define PPA_CHECK_CM_SUPPORT_BYTE_SWAP(str, color_type_id) \ + ESP_RETURN_ON_FALSE(color_type_id == COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888) || color_type_id == COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), \ + ESP_ERR_INVALID_ARG, TAG, str "_cm does not support byte_swap"); + +#define PPA_CHECK_CM_SUPPORT_RGB_SWAP(str, color_type_id) \ + ESP_RETURN_ON_FALSE(COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_ARGB || COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_RGB, \ + ESP_ERR_INVALID_ARG, TAG, str "_cm does not support rgb_swap"); + +typedef struct ppa_platform_t ppa_platform_t; + +/******************************** ENGINE *************************************/ +// PPA module contains SRM engine and Blending engine + +typedef struct ppa_engine_t ppa_engine_t; + +struct ppa_engine_t { + ppa_platform_t *platform; // PPA driver platform + ppa_engine_type_t type; // Type of the PPA engine + portMUX_TYPE spinlock; // Engine level spinlock + SemaphoreHandle_t sem; // Semaphore for whether the engine is processing a transaction + STAILQ_HEAD(trans, ppa_trans_s) trans_stailq; // link head of pending transactions for the PPA engine +#if CONFIG_PM_ENABLE + esp_pm_lock_handle_t pm_lock; // Power management lock +#endif +}; + +typedef struct ppa_srm_engine_t { + ppa_engine_t base; // PPA engine base structure + dma2d_descriptor_t *dma_tx_desc; // Into PPA SRM engine direction 2D-DMA descriptor + dma2d_descriptor_t *dma_rx_desc; // Out from PPA SRM engine direction 2D-DMA descriptor +} ppa_srm_engine_t; + +typedef struct ppa_blend_engine_t { + ppa_engine_t base; // PPA engine base structure + dma2d_descriptor_t *dma_tx_bg_desc; // Into PPA Blending engine direction background channel 2D-DMA descriptor + dma2d_descriptor_t *dma_tx_fg_desc; // Into PPA Blending engine direction foreground channel 2D-DMA descriptor + dma2d_descriptor_t *dma_rx_desc; // Out from PPA blending engine direction 2D-DMA descriptor +} ppa_blend_engine_t; + +typedef struct { + ppa_engine_type_t engine; // Engine type +} ppa_engine_config_t; + +/******************************** CLIENT *************************************/ + +typedef struct ppa_client_t ppa_client_t; + +struct ppa_client_t { + ppa_operation_t oper_type; // The PPA operation type that the client wants to do in speciality + ppa_engine_t *engine; // Pointer to the PPA engine that in charge of performing the PPA operation + uint32_t trans_cnt; // Number of pending PPA transactions + portMUX_TYPE spinlock; // Client level spinlock + ppa_event_callback_t done_cb; // Transaction done callback + QueueHandle_t trans_elm_ptr_queue; // Queue that contains the pointers to the allocated memory to save the transaction contexts + ppa_data_burst_length_t data_burst_length; // The desired data burst length for all the transactions of the client +}; + +/****************************** OPERATION ************************************/ + +// The elements in this structure listed first are identical to the elements in structure `ppa_srm_oper_config_t` +// With adding a few extra elements at the end +// This allows memcpy +typedef struct { + ppa_in_pic_blk_config_t in; + ppa_out_pic_blk_config_t out; + + // scale-rotate-mirror manipulation + ppa_srm_rotation_angle_t rotation_angle; + float scale_x; + float scale_y; + bool mirror_x; + bool mirror_y; + + // input data manipulation + bool rgb_swap; + bool byte_swap; + ppa_alpha_update_mode_t alpha_update_mode; + union { + uint32_t alpha_fix_val; + float alpha_scale_ratio; + }; + + ppa_trans_mode_t mode; + void *user_data; + + uint32_t scale_x_int; // Calculation result for the integral part of the scale_x to be directly written to register + uint32_t scale_x_frag; // Calculation result for the fractional part of the scale_x to be directly written to register + uint32_t scale_y_int; // Calculation result for the integral part of the scale_y to be directly written to register + uint32_t scale_y_frag; // Calculation result for the fractional part of the scale_y to be directly written to register + uint32_t alpha_value; // Calculation result for the fix alpha value to be directly written to register + ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client +} ppa_srm_oper_t; + +// The elements in this structure listed first are identical to the elements in structure `ppa_blend_oper_config_t` +// With adding a few extra elements at the end +// This allows memcpy +typedef struct { + ppa_in_pic_blk_config_t in_bg; + ppa_in_pic_blk_config_t in_fg; + ppa_out_pic_blk_config_t out; + + // input data manipulation + bool bg_rgb_swap; + bool bg_byte_swap; + ppa_alpha_update_mode_t bg_alpha_update_mode; + union { + uint32_t bg_alpha_fix_val; + float bg_alpha_scale_ratio; + }; + bool fg_rgb_swap; + bool fg_byte_swap; + ppa_alpha_update_mode_t fg_alpha_update_mode; + union { + uint32_t fg_alpha_fix_val; + float fg_alpha_scale_ratio; + }; + color_pixel_rgb888_data_t fg_fix_rgb_val; + + // color-keying + bool bg_ck_en; + color_pixel_rgb888_data_t bg_ck_rgb_low_thres; + color_pixel_rgb888_data_t bg_ck_rgb_high_thres; + bool fg_ck_en; + color_pixel_rgb888_data_t fg_ck_rgb_low_thres; + color_pixel_rgb888_data_t fg_ck_rgb_high_thres; + color_pixel_rgb888_data_t ck_rgb_default_val; + bool ck_reverse_bg2fg; + + ppa_trans_mode_t mode; + void *user_data; + + uint32_t bg_alpha_value; // Calculation result for the fix alpha value for BG to be directly written to register + uint32_t fg_alpha_value; // Calculation result for the fix alpha value for FG to be directly written to register + ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client +} ppa_blend_oper_t; + +// The elements in this structure listed first are identical to the elements in structure `ppa_fill_oper_config_t` +// With adding a few extra elements at the end +// This allows memcpy +typedef struct { + ppa_out_pic_blk_config_t out; + + uint32_t fill_block_w; + uint32_t fill_block_h; + color_pixel_argb8888_data_t fill_argb_color; + + ppa_trans_mode_t mode; + void *user_data; + + ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client +} ppa_fill_oper_t; + +/***************************** TRANSACTION ***********************************/ + +// PPA transaction element +typedef struct ppa_trans_s { + STAILQ_ENTRY(ppa_trans_s) entry; // Link entry + dma2d_trans_config_t *trans_desc; // Pointer to the structure containing the configurations for a 2D-DMA transaction + dma2d_trans_t *dma_trans_placeholder; // Pointer to the memory to store the 2D-DMA transaction context + SemaphoreHandle_t sem; // Semaphore to block when the transaction has not finished + ppa_client_t *client; // Pointer to the client who requested the transaction + void *user_data; // User registered event data (per transaction) +} ppa_trans_t; + +typedef struct { + union { + ppa_srm_oper_t *srm_desc; // Pointer to the structure containing the configurations for a PPA SRM operation transaction + ppa_blend_oper_t *blend_desc; // Pointer to the structure containing the configurations for a PPA blend operation transaction + ppa_fill_oper_t *fill_desc; // Pointer to the structure containing the configurations for a PPA fill operation transaction + void *op_desc; // General pointer to the structure containing the configurations for a PPA transaction + }; + ppa_engine_t *ppa_engine; // Pointer to the PPA engine + ppa_trans_t *trans_elm; // Pointer to the PPA transaction element + dma2d_trigger_peripheral_t trigger_periph; // The 2D-DMA trigger peripheral +} ppa_dma2d_trans_on_picked_config_t; + +bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); +bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); +bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); + +esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_engine_base, ppa_trans_t *trans_elm, ppa_trans_mode_t mode); + +bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data); + +bool ppa_recycle_transaction(ppa_client_handle_t ppa_client, ppa_trans_t *trans_elm); + +/****************************** PPA DRIVER ***********************************/ + +struct ppa_platform_t { + _lock_t mutex; // Platform level mutex lock to protect the ppa_engine_acquire/ppa_engine_release process + portMUX_TYPE spinlock; // Platform level spinlock + ppa_hal_context_t hal; // PPA HAL context + dma2d_pool_handle_t dma2d_pool_handle; // Pointer to the acquired 2D-DMA pool + ppa_srm_engine_t *srm; // Pointer to the PPA SRM engine + ppa_blend_engine_t *blending; // Pointer to the PPA blending engine + uint32_t srm_engine_ref_count; // Reference count used to protect PPA SRM engine acquire and release + uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release + size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size + uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size +}; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c new file mode 100644 index 00000000000..244a18bff9f --- /dev/null +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -0,0 +1,289 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "driver/ppa.h" +#include "ppa_priv.h" +#include "esp_private/dma2d.h" +#include "hal/ppa_ll.h" +#include "esp_cache.h" +#include "esp_memory_utils.h" +#include "soc/dma2d_channel.h" + +static const char *TAG = "ppa_srm"; + +bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config) +{ + assert(num_chans == 2 && dma2d_chans && user_config); + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)user_config; + assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_SRM && trans_on_picked_desc->srm_desc && trans_on_picked_desc->ppa_engine); + + ppa_srm_oper_t *srm_trans_desc = (ppa_srm_oper_t *)trans_on_picked_desc->srm_desc; + ppa_srm_engine_t *srm_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_srm_engine_t, base); + ppa_platform_t *platform = srm_engine->base.platform; + + // Reset SRM engine + ppa_ll_srm_reset(platform->hal.dev); + + // Get the required 2D-DMA channel handles + dma2d_channel_handle_t dma2d_tx_chan = NULL; + dma2d_channel_handle_t dma2d_rx_chan = NULL; + for (uint32_t i = 0; i < num_chans; i++) { + if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_TX) { + dma2d_tx_chan = dma2d_chans[i].chan; + } + if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_RX) { + dma2d_rx_chan = dma2d_chans[i].chan; + } + } + assert(dma2d_tx_chan && dma2d_rx_chan); + + color_space_pixel_format_t in_pixel_format = { + .color_type_id = srm_trans_desc->in.srm_cm, + }; + + // Fill 2D-DMA descriptors + srm_engine->dma_tx_desc->vb_size = srm_trans_desc->in.block_h; + srm_engine->dma_tx_desc->hb_length = srm_trans_desc->in.block_w; + srm_engine->dma_tx_desc->err_eof = 0; + srm_engine->dma_tx_desc->dma2d_en = 1; + srm_engine->dma_tx_desc->suc_eof = 1; + srm_engine->dma_tx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + srm_engine->dma_tx_desc->va_size = srm_trans_desc->in.pic_h; + srm_engine->dma_tx_desc->ha_length = srm_trans_desc->in.pic_w; + srm_engine->dma_tx_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(in_pixel_format); + srm_engine->dma_tx_desc->y = srm_trans_desc->in.block_offset_y; + srm_engine->dma_tx_desc->x = srm_trans_desc->in.block_offset_x; + srm_engine->dma_tx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + srm_engine->dma_tx_desc->buffer = (void *)srm_trans_desc->in.buffer; + srm_engine->dma_tx_desc->next = NULL; + + // vb_size, hb_length can be any value (auto writeback) + // However, if vb_size/hb_length is 0, it triggers 2D-DMA DESC_ERROR interrupt, and dma2d driver will automatically ends the transaction + // Moreover, for YUV420, hb/vb have to be even + // Therefore, we set them to 2 + srm_engine->dma_rx_desc->vb_size = 2; + srm_engine->dma_rx_desc->hb_length = 2; + srm_engine->dma_rx_desc->err_eof = 0; + srm_engine->dma_rx_desc->dma2d_en = 1; + srm_engine->dma_rx_desc->suc_eof = 1; + srm_engine->dma_rx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; + srm_engine->dma_rx_desc->va_size = srm_trans_desc->out.pic_h; + srm_engine->dma_rx_desc->ha_length = srm_trans_desc->out.pic_w; + // pbyte can be any value + srm_engine->dma_rx_desc->y = srm_trans_desc->out.block_offset_y; + srm_engine->dma_rx_desc->x = srm_trans_desc->out.block_offset_x; + srm_engine->dma_rx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; + srm_engine->dma_rx_desc->buffer = (void *)srm_trans_desc->out.buffer; + srm_engine->dma_rx_desc->next = NULL; + + esp_cache_msync((void *)srm_engine->dma_tx_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync((void *)srm_engine->dma_rx_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + + // Configure 2D-DMA channels + dma2d_trigger_t trig_periph = { + .periph = DMA2D_TRIG_PERIPH_PPA_SRM, + .periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_SRM_TX, + }; + dma2d_connect(dma2d_tx_chan, &trig_periph); + trig_periph.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_SRM_RX; + dma2d_connect(dma2d_rx_chan, &trig_periph); + + dma2d_transfer_ability_t dma_transfer_ability = { + .data_burst_length = srm_trans_desc->data_burst_length, + .desc_burst_en = true, + .mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE, + }; + dma2d_set_transfer_ability(dma2d_tx_chan, &dma_transfer_ability); + dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability); + + // Configure the block size to be received by the SRM engine, which is passed from the 2D-DMA TX channel (i.e. 2D-DMA dscr-port mode) + dma2d_dscr_port_mode_config_t dma_dscr_port_mode_config = { + .block_h = (srm_trans_desc->in.srm_cm == PPA_SRM_COLOR_MODE_YUV420) ? PPA_LL_SRM_YUV420_BLOCK_SIZE : PPA_LL_SRM_DEFAULT_BLOCK_SIZE, + .block_v = (srm_trans_desc->in.srm_cm == PPA_SRM_COLOR_MODE_YUV420) ? PPA_LL_SRM_YUV420_BLOCK_SIZE : PPA_LL_SRM_DEFAULT_BLOCK_SIZE, + }; + dma2d_configure_dscr_port_mode(dma2d_tx_chan, &dma_dscr_port_mode_config); + + // YUV444 is not supported by PPA module, need to utilize 2D-DMA color space conversion feature to do a conversion + ppa_srm_color_mode_t ppa_in_color_mode = srm_trans_desc->in.srm_cm; + if (ppa_in_color_mode == PPA_SRM_COLOR_MODE_YUV444) { + ppa_in_color_mode = PPA_SRM_COLOR_MODE_RGB888; + dma2d_csc_config_t dma_tx_csc = {0}; + if (srm_trans_desc->in.yuv_std == PPA_COLOR_CONV_STD_RGB_YUV_BT601) { + dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV444_TO_RGB888_601; + } else { + dma_tx_csc.tx_csc_option = DMA2D_CSC_TX_YUV444_TO_RGB888_709; + } + dma2d_configure_color_space_conversion(dma2d_tx_chan, &dma_tx_csc); + } + + ppa_srm_color_mode_t ppa_out_color_mode = srm_trans_desc->out.srm_cm; + if (ppa_out_color_mode == PPA_SRM_COLOR_MODE_YUV444) { + ppa_out_color_mode = PPA_SRM_COLOR_MODE_YUV420; + dma2d_csc_config_t dma_rx_csc = { + .rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444, + }; + dma2d_configure_color_space_conversion(dma2d_rx_chan, &dma_rx_csc); + } + + dma2d_rx_event_callbacks_t dma_event_cbs = { + .on_recv_eof = ppa_transaction_done_cb, + }; + dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm); + + dma2d_set_desc_addr(dma2d_tx_chan, (intptr_t)srm_engine->dma_tx_desc); + dma2d_set_desc_addr(dma2d_rx_chan, (intptr_t)srm_engine->dma_rx_desc); + dma2d_start(dma2d_tx_chan); + dma2d_start(dma2d_rx_chan); + + // Configure PPA SRM engine + ppa_ll_srm_set_rx_color_mode(platform->hal.dev, ppa_in_color_mode); + if (COLOR_SPACE_TYPE((uint32_t)ppa_in_color_mode) == COLOR_SPACE_YUV) { + ppa_ll_srm_set_rx_yuv_range(platform->hal.dev, srm_trans_desc->in.yuv_range); + ppa_ll_srm_set_rx_yuv2rgb_std(platform->hal.dev, srm_trans_desc->in.yuv_std); + } + ppa_ll_srm_enable_rx_byte_swap(platform->hal.dev, srm_trans_desc->byte_swap); + ppa_ll_srm_enable_rx_rgb_swap(platform->hal.dev, srm_trans_desc->rgb_swap); + ppa_ll_srm_configure_rx_alpha(platform->hal.dev, srm_trans_desc->alpha_update_mode, srm_trans_desc->alpha_value); + + ppa_ll_srm_set_tx_color_mode(platform->hal.dev, ppa_out_color_mode); + if (COLOR_SPACE_TYPE((uint32_t)ppa_out_color_mode) == COLOR_SPACE_YUV) { + ppa_ll_srm_set_tx_yuv_range(platform->hal.dev, srm_trans_desc->out.yuv_range); + ppa_ll_srm_set_tx_rgb2yuv_std(platform->hal.dev, srm_trans_desc->out.yuv_std); + } + + ppa_ll_srm_set_rotation_angle(platform->hal.dev, srm_trans_desc->rotation_angle); + ppa_ll_srm_set_scaling_x(platform->hal.dev, srm_trans_desc->scale_x_int, srm_trans_desc->scale_x_frag); + ppa_ll_srm_set_scaling_y(platform->hal.dev, srm_trans_desc->scale_y_int, srm_trans_desc->scale_y_frag); + ppa_ll_srm_enable_mirror_x(platform->hal.dev, srm_trans_desc->mirror_x); + ppa_ll_srm_enable_mirror_y(platform->hal.dev, srm_trans_desc->mirror_y); + + ppa_ll_srm_start(platform->hal.dev); + + // No need to yield + return false; +} + +esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_srm_oper_config_t *config) +{ + ESP_RETURN_ON_FALSE(ppa_client && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(ppa_client->oper_type == PPA_OPERATION_SRM, ESP_ERR_INVALID_ARG, TAG, "client is not for SRM operations"); + ESP_RETURN_ON_FALSE(config->mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode"); + // in_buffer could be anywhere (ram, flash, psram), out_buffer ptr cannot in flash region + ESP_RETURN_ON_FALSE(esp_ptr_internal(config->out.buffer) || esp_ptr_external_ram(config->out.buffer), ESP_ERR_INVALID_ARG, TAG, "invalid out.buffer addr"); + uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; + ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0, + ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); + // For YUV420 input/output: in desc, ha/hb/va/vb/x/y must be even number + if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV420) { + ESP_RETURN_ON_FALSE(config->in.pic_h % 2 == 0 && config->in.pic_w % 2 == 0 && + config->in.block_h % 2 == 0 && config->in.block_w % 2 == 0 && + config->in.block_offset_x % 2 == 0 && config->in.block_offset_y % 2 == 0, + ESP_ERR_INVALID_ARG, TAG, "YUV420 input does not support odd h/w/offset_x/offset_y"); + } + // TODO: P4 ECO2 support YUV422 + // else if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV422) { + // ESP_RETURN_ON_FALSE(config->in.pic_w % 2 == 0 && config->in.block_w % 2 == 0 && config->in.block_offset_x % 2 == 0, + // ESP_ERR_INVALID_ARG, TAG, "YUV422 input does not support odd w/offset_x"); + // } + if (config->out.srm_cm == PPA_SRM_COLOR_MODE_YUV420) { + ESP_RETURN_ON_FALSE(config->out.pic_h % 2 == 0 && config->out.pic_w % 2 == 0 && + config->out.block_offset_x % 2 == 0 && config->out.block_offset_y % 2 == 0, + ESP_ERR_INVALID_ARG, TAG, "YUV420 output does not support odd h/w/offset_x/offset_y"); + } + color_space_pixel_format_t out_pixel_format = { + .color_type_id = config->out.srm_cm, + }; + uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8; + ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size"); + ESP_RETURN_ON_FALSE(config->scale_x < (PPA_LL_SRM_SCALING_INT_MAX + 1) && config->scale_x >= (1.0 / PPA_LL_SRM_SCALING_FRAG_MAX) && + config->scale_y < (PPA_LL_SRM_SCALING_INT_MAX + 1) && config->scale_y >= (1.0 / PPA_LL_SRM_SCALING_FRAG_MAX), + ESP_ERR_INVALID_ARG, TAG, "invalid scale"); + uint32_t new_block_w = 0; + uint32_t new_block_h = 0; + if (config->rotation_angle == PPA_SRM_ROTATION_ANGLE_0 || config->rotation_angle == PPA_SRM_ROTATION_ANGLE_180) { + new_block_w = (uint32_t)(config->scale_x * config->in.block_w); + new_block_h = (uint32_t)(config->scale_y * config->in.block_h); + } else { + new_block_w = (uint32_t)(config->scale_y * config->in.block_h); + new_block_h = (uint32_t)(config->scale_x * config->in.block_w); + } + ESP_RETURN_ON_FALSE(new_block_w <= (config->out.pic_w - config->out.block_offset_x) && + new_block_h <= (config->out.pic_h - config->out.block_offset_y), + ESP_ERR_INVALID_ARG, TAG, "scale does not fit in the out pic"); + if (config->byte_swap) { + PPA_CHECK_CM_SUPPORT_BYTE_SWAP("in.srm", (uint32_t)config->in.srm_cm); + } + if (config->rgb_swap) { + PPA_CHECK_CM_SUPPORT_RGB_SWAP("in.srm", (uint32_t)config->in.srm_cm); + } + uint32_t new_alpha_value = 0; + if (config->alpha_update_mode == PPA_ALPHA_FIX_VALUE) { + ESP_RETURN_ON_FALSE(config->alpha_fix_val <= 0xFF, ESP_ERR_INVALID_ARG, TAG, "invalid alpha_fix_val"); + new_alpha_value = config->alpha_fix_val; + } else if (config->alpha_update_mode == PPA_ALPHA_SCALE) { + ESP_RETURN_ON_FALSE(config->alpha_scale_ratio > 0 && config->alpha_scale_ratio < 1, ESP_ERR_INVALID_ARG, TAG, "invalid alpha_scale_ratio"); + new_alpha_value = (uint32_t)(config->alpha_scale_ratio * 256); + } + // To reduce complexity, rotation_angle, color_mode, alpha_update_mode correctness are checked in their corresponding LL functions + + // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) + // Write back in_buffer extended window (alignment not necessary on C2M direction) + color_space_pixel_format_t in_pixel_format = { + .color_type_id = config->in.srm_cm, + }; + uint32_t in_pixel_depth = color_hal_pixel_format_get_bit_depth(in_pixel_format); // bits + uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; + uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; + esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + // Invalidate out_buffer entire picture (alignment strict on M2C direction) + esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + + esp_err_t ret = ESP_OK; + ppa_trans_t *trans_elm = NULL; + if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) { + dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc; + + ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config; + + ppa_srm_oper_t *srm_trans_desc = (ppa_srm_oper_t *)trans_on_picked_desc->srm_desc; + memcpy(srm_trans_desc, config, sizeof(ppa_srm_oper_config_t)); + srm_trans_desc->scale_x_int = (uint32_t)srm_trans_desc->scale_x; + srm_trans_desc->scale_x_frag = (uint32_t)(srm_trans_desc->scale_x * (PPA_LL_SRM_SCALING_FRAG_MAX + 1)) & PPA_LL_SRM_SCALING_FRAG_MAX; + srm_trans_desc->scale_y_int = (uint32_t)srm_trans_desc->scale_y; + srm_trans_desc->scale_y_frag = (uint32_t)(srm_trans_desc->scale_y * (PPA_LL_SRM_SCALING_FRAG_MAX + 1)) & PPA_LL_SRM_SCALING_FRAG_MAX; + srm_trans_desc->alpha_value = new_alpha_value; + srm_trans_desc->data_burst_length = ppa_client->data_burst_length; + + trans_on_picked_desc->ppa_engine = ppa_client->engine; + trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_SRM; + + dma_trans_desc->tx_channel_num = 1; + dma_trans_desc->rx_channel_num = 1; + dma_trans_desc->channel_flags = 0; + if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { + dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC; + } + if (config->out.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { + dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_RX_CSC; + } + dma_trans_desc->specified_tx_channel_mask = 0; + dma_trans_desc->specified_rx_channel_mask = 0; + + trans_elm->client = ppa_client; + trans_elm->user_data = config->user_data; + xSemaphoreTake(trans_elm->sem, 0); // Ensure no transaction semaphore before transaction starts + + ret = ppa_do_operation(ppa_client, ppa_client->engine, trans_elm, config->mode); + if (ret != ESP_OK) { + ppa_recycle_transaction(ppa_client, trans_elm); + } + } else { + ret = ESP_FAIL; + ESP_LOGE(TAG, "exceed maximum pending transactions for the client, consider increase max_pending_trans_num"); + } + return ret; +} diff --git a/components/esp_driver_ppa/test_apps/.build-test-rules.yml b/components/esp_driver_ppa/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..7767104a7fb --- /dev/null +++ b/components/esp_driver_ppa/test_apps/.build-test-rules.yml @@ -0,0 +1,7 @@ +# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps + +components/esp_driver_ppa/test_apps: + disable: + - if: SOC_PPA_SUPPORTED != 1 + depends_components: + - esp_driver_ppa diff --git a/components/esp_driver_ppa/test_apps/CMakeLists.txt b/components/esp_driver_ppa/test_apps/CMakeLists.txt new file mode 100644 index 00000000000..dde41419437 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/CMakeLists.txt @@ -0,0 +1,9 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +project(ppa_test) diff --git a/components/esp_driver_ppa/test_apps/README.md b/components/esp_driver_ppa/test_apps/README.md new file mode 100644 index 00000000000..909282018f2 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | diff --git a/components/esp_driver_ppa/test_apps/main/CMakeLists.txt b/components/esp_driver_ppa/test_apps/main/CMakeLists.txt new file mode 100644 index 00000000000..25e36806850 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/main/CMakeLists.txt @@ -0,0 +1,9 @@ +set(srcs "test_app_main.c" + "test_ppa.c") + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES esp_driver_ppa esp_psram unity + WHOLE_ARCHIVE) diff --git a/components/esp_driver_ppa/test_apps/main/idf_component.yml b/components/esp_driver_ppa/test_apps/main/idf_component.yml new file mode 100644 index 00000000000..2ae836a9359 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/main/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + ccomp_timer: "^1.0.0" diff --git a/components/esp_driver_ppa/test_apps/main/test_app_main.c b/components/esp_driver_ppa/test_apps/main/test_app_main.c new file mode 100644 index 00000000000..bdc0d7ecb3e --- /dev/null +++ b/components/esp_driver_ppa/test_apps/main/test_app_main.c @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" +#include "unity_test_utils.h" + +// Some resources are lazy allocated in the driver, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (300) + +void setUp(void) +{ + unity_utils_record_free_mem(); +} + +void tearDown(void) +{ + esp_reent_cleanup(); //clean up some of the newlib's lazy allocations + unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); +} + +void app_main(void) +{ + printf(" ________ \n"); + printf("|___ ___ \\ \n"); + printf(" | \\_/ | \n"); + printf(" '.___.' \n"); + printf(" ________ \n"); + printf("|___ ___ \\ \n"); + printf(" | \\_/ | \n"); + printf(" '.___.' \n"); + printf(" _______ \n"); + printf("|__. _ '. \n"); + printf(" __||_/ / \n"); + printf("|______.' \n"); + + unity_run_menu(); +} diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c new file mode 100644 index 00000000000..0dd676c6648 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -0,0 +1,489 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "unity.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "driver/ppa.h" +#include "esp_heap_caps.h" +#include "esp_err.h" +#include "ccomp_timer.h" +#include "hal/color_hal.h" + +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) + +TEST_CASE("ppa_client_do_ppa_operation", "[PPA]") +{ + const uint32_t w = 480; + const uint32_t h = 480; + const uint32_t buf_1_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); + const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); + + color_space_pixel_format_t buf_1_cm = { + .color_type_id = buf_1_color_type_id, + }; + color_space_pixel_format_t buf_2_cm = { + .color_type_id = buf_2_color_type_id, + }; + + uint32_t buf_1_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8, 64); + uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64); + uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(buf_1); + uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(buf_2); + + // Register different types of PPA clients + ppa_client_handle_t ppa_client_srm_handle; + ppa_client_handle_t ppa_client_blend_handle; + ppa_client_handle_t ppa_client_fill_handle_a; + ppa_client_handle_t ppa_client_fill_handle_b; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_srm_handle)); + ppa_client_config.oper_type = PPA_OPERATION_BLEND; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_blend_handle)); + ppa_client_config.oper_type = PPA_OPERATION_FILL; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_fill_handle_a)); + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_fill_handle_b)); + + ppa_srm_oper_config_t srm_oper_config = { + .in.buffer = buf_1, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = w, + .in.block_h = h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = buf_1_color_type_id, + + .out.buffer = buf_2, + .out.buffer_size = buf_2_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = buf_2_color_type_id, + + .rotation_angle = PPA_SRM_ROTATION_ANGLE_0, + .scale_x = 1.0, + .scale_y = 1.0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + // A SRM client can request to do a SRM operation + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_srm_handle, &srm_oper_config)); + // A non-SRM client can not request to do a SRM operation + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ppa_do_scale_rotate_mirror(ppa_client_blend_handle, &srm_oper_config)); + + ppa_blend_oper_config_t blend_oper_config = { + .in_bg.buffer = buf_1, + .in_bg.pic_w = w, + .in_bg.pic_h = h, + .in_bg.block_w = w, + .in_bg.block_h = h, + .in_bg.block_offset_x = 0, + .in_bg.block_offset_y = 0, + .in_bg.blend_cm = buf_1_color_type_id, + + .in_fg.buffer = buf_2, + .in_fg.pic_w = w, + .in_fg.pic_h = h, + .in_fg.block_w = w, + .in_fg.block_h = h, + .in_fg.block_offset_x = 0, + .in_fg.block_offset_y = 0, + .in_fg.blend_cm = buf_2_color_type_id, + + .out.buffer = buf_1, + .out.buffer_size = buf_1_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.blend_cm = buf_1_color_type_id, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + // A blend client can request to do a blend operation + TEST_ESP_OK(ppa_do_blend(ppa_client_blend_handle, &blend_oper_config)); + // A non-blend client can not request to do a blend operation + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ppa_do_blend(ppa_client_fill_handle_b, &blend_oper_config)); + + ppa_fill_oper_config_t fill_oper_config = { + .out.buffer = buf_1, + .out.buffer_size = buf_1_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.fill_cm = buf_1_color_type_id, + + .fill_block_w = w, + .fill_block_h = h, + .fill_argb_color = { + .val = 0xFF00FF00, + }, + + .mode = PPA_TRANS_MODE_NON_BLOCKING, + }; + // A fill client can request to do a fill operation + TEST_ESP_OK(ppa_do_fill(ppa_client_fill_handle_a, &fill_oper_config)); + // Another fill client can also request another fill operation at the same time + TEST_ESP_OK(ppa_do_fill(ppa_client_fill_handle_b, &fill_oper_config)); + + vTaskDelay(pdMS_TO_TICKS(500)); + + // Unregister all PPA clients + TEST_ESP_OK(ppa_unregister_client(ppa_client_srm_handle)); + TEST_ESP_OK(ppa_unregister_client(ppa_client_blend_handle)); + TEST_ESP_OK(ppa_unregister_client(ppa_client_fill_handle_a)); + TEST_ESP_OK(ppa_unregister_client(ppa_client_fill_handle_b)); + + free(buf_1); + free(buf_2); +} + +static bool ppa_trans_done_cb(ppa_client_handle_t ppa_client, ppa_event_data_t *event_data, void *user_data) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + SemaphoreHandle_t sem = (SemaphoreHandle_t)user_data; + xSemaphoreGiveFromISR(sem, &xHigherPriorityTaskWoken); + return (xHigherPriorityTaskWoken == pdTRUE); +} + +TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]") +{ + // A big picture block takes longer time to process, desired for this test case + const uint32_t w = 1920; + const uint32_t h = 1080; + const uint32_t buf_1_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); + const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); + + color_space_pixel_format_t buf_1_cm = { + .color_type_id = buf_1_color_type_id, + }; + color_space_pixel_format_t buf_2_cm = { + .color_type_id = buf_2_color_type_id, + }; + + uint32_t buf_1_size = w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8; + uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64); + uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(buf_1); + uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(buf_2); + + // Register two PPA SRM clients with different max_pending_trans_num + ppa_client_handle_t ppa_client_a_handle; + ppa_client_handle_t ppa_client_b_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_a_handle)); + ppa_client_config.max_pending_trans_num = 3; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_b_handle)); + + ppa_event_callbacks_t cbs = { + .on_trans_done = ppa_trans_done_cb, + }; + ppa_client_register_event_callbacks(ppa_client_a_handle, &cbs); + + SemaphoreHandle_t sem = xSemaphoreCreateBinary(); + + ppa_srm_oper_config_t oper_config = { + .in.buffer = buf_1, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = w, + .in.block_h = h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = buf_1_color_type_id, + + .out.buffer = buf_2, + .out.buffer_size = buf_2_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = buf_2_color_type_id, + + .rotation_angle = PPA_SRM_ROTATION_ANGLE_0, + .scale_x = 1.0, + .scale_y = 1.0, + + .user_data = (void *)sem, + .mode = PPA_TRANS_MODE_NON_BLOCKING, + }; + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config)); + + // Another transaction cannot be accept since client_a can only hold one transaction + TEST_ESP_ERR(ESP_FAIL, ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config)); + + // Wait for the last transaction finishes + xSemaphoreTake(sem, portMAX_DELAY); + // Then a new transaction can be accepted again + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_a_handle, &oper_config)); + + // Client can not be unregistered when there are unfinished transactions + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ppa_unregister_client(ppa_client_a_handle)); + + oper_config.mode = PPA_TRANS_MODE_BLOCKING; + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config)); + // Every PPA engine can only process one operation at a time + // Transactions are being processed with First-In-First-Out + // So, at the moment, the new transaction requested by client_b has finished, the last transaction requested by client_a for sure has finished + TEST_ASSERT(xSemaphoreTake(sem, 0) == pdTRUE); + // client_b can accept more than one transactions + oper_config.mode = PPA_TRANS_MODE_NON_BLOCKING; + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config)); + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config)); + oper_config.mode = PPA_TRANS_MODE_BLOCKING; + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_b_handle, &oper_config)); + // The last transaction requested is with BLOCKING mode, so the last call to ppa_do_scale_rotate_mirror returned means all transactions finished + + // Unregister all PPA clients + TEST_ESP_OK(ppa_unregister_client(ppa_client_a_handle)); + TEST_ESP_OK(ppa_unregister_client(ppa_client_b_handle)); + + vSemaphoreDelete(sem); + free(buf_1); + free(buf_2); +} + +TEST_CASE("ppa_srm_performance", "[PPA][ignore]") +{ + const uint32_t w = 1920; // 1920 / 1280 / 800 / 640 + const uint32_t h = 1080; // 1080 / 720 / 480 + const uint32_t block_w = w; + const uint32_t block_h = h; + const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_ARGB8888; + const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_YUV420; + const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0; + const float scale_x = 1.0; + const float scale_y = 1.0; + + color_space_pixel_format_t in_pixel_format = { + .color_type_id = in_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8; + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(out_buf); + uint8_t *in_buf = heap_caps_aligned_calloc(64, in_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(in_buf); + + uint8_t *ptr = in_buf; + for (int x = 0; x < in_buf_size; x++) { + ptr[x] = x; + } + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + uint32_t out_pic_w = (rotation == PPA_SRM_ROTATION_ANGLE_0 || rotation == PPA_SRM_ROTATION_ANGLE_180) ? w : h; + uint32_t out_pic_h = (rotation == PPA_SRM_ROTATION_ANGLE_0 || rotation == PPA_SRM_ROTATION_ANGLE_180) ? h : w; + ppa_srm_oper_config_t oper_config = { + .in.buffer = in_buf, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = block_w, + .in.block_h = block_h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = in_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = out_pic_w, + .out.pic_h = out_pic_h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = out_cm, + + .rotation_angle = rotation, + .scale_x = scale_x, + .scale_y = scale_y, + + .rgb_swap = 0, + .byte_swap = 0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + ccomp_timer_start(); + + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); + + int64_t oper_time = ccomp_timer_stop(); + printf("Time passed: %lld us\n", oper_time); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(in_buf); + free(out_buf); +} + +TEST_CASE("ppa_blend_performance", "[PPA][ignore]") +{ + const uint32_t w = 1280; + const uint32_t h = 720; + const uint32_t block_w = w; + const uint32_t block_h = h; + const ppa_blend_color_mode_t in_bg_cm = PPA_BLEND_COLOR_MODE_ARGB8888; + const ppa_blend_color_mode_t in_fg_cm = PPA_BLEND_COLOR_MODE_ARGB8888; + const ppa_blend_color_mode_t out_cm = PPA_BLEND_COLOR_MODE_ARGB8888; + + color_space_pixel_format_t in_bg_pixel_format = { + .color_type_id = in_bg_cm, + }; + color_space_pixel_format_t in_fg_pixel_format = { + .color_type_id = in_fg_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t in_bg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_bg_pixel_format) / 8; + uint32_t in_fg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_fg_pixel_format) / 8; + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(out_buf); + uint8_t *in_bg_buf = heap_caps_aligned_calloc(64, in_bg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(in_bg_buf); + uint8_t *in_fg_buf = heap_caps_aligned_calloc(64, in_fg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(in_fg_buf); + + uint8_t *ptr = in_bg_buf; + for (int x = 0; x < in_bg_buf_size; x++) { + ptr[x] = x & 0x55; + } + ptr = in_fg_buf; + for (int x = 0; x < in_fg_buf_size; x++) { + ptr[x] = x & 0xAA; + } + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_BLEND, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + ppa_blend_oper_config_t oper_config = { + .in_bg.buffer = in_bg_buf, + .in_bg.pic_w = w, + .in_bg.pic_h = h, + .in_bg.block_w = block_w, + .in_bg.block_h = block_h, + .in_bg.block_offset_x = 0, + .in_bg.block_offset_y = 0, + .in_bg.blend_cm = in_bg_cm, + + .in_fg.buffer = in_fg_buf, + .in_fg.pic_w = w, + .in_fg.pic_h = h, + .in_fg.block_w = block_w, + .in_fg.block_h = block_h, + .in_fg.block_offset_x = 0, + .in_fg.block_offset_y = 0, + .in_fg.blend_cm = in_fg_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.blend_cm = out_cm, + + .bg_ck_en = false, + .fg_ck_en = false, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + ccomp_timer_start(); + + TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config)); + + int64_t oper_time = ccomp_timer_stop(); + printf("Time passed: %lld us\n", oper_time); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(in_bg_buf); + free(in_fg_buf); + free(out_buf); +} + +TEST_CASE("ppa_fill_performance", "[PPA][ignore]") +{ + const uint32_t w = 1280; + const uint32_t h = 720; + const uint32_t block_w = 800; + const uint32_t block_h = 480; + const ppa_fill_color_mode_t out_cm = PPA_FILL_COLOR_MODE_RGB565; + + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + TEST_ASSERT_NOT_NULL(out_buf); + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_FILL, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + ppa_fill_oper_config_t oper_config = { + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.fill_cm = out_cm, + + .fill_block_w = block_w, + .fill_block_h = block_h, + .fill_argb_color = { + .val = 0xFF00FFFF, + }, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + ccomp_timer_start(); + + TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config)); + + int64_t oper_time = ccomp_timer_stop(); + printf("Time passed: %lld us\n", oper_time); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(out_buf); +} diff --git a/components/esp_driver_ppa/test_apps/pytest_ppa.py b/components/esp_driver_ppa/test_apps/pytest_ppa.py new file mode 100644 index 00000000000..534d32cee19 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/pytest_ppa.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'release', + ], + indirect=True, +) +def test_ppa(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_ppa/test_apps/sdkconfig.ci.release b/components/esp_driver_ppa/test_apps/sdkconfig.ci.release new file mode 100644 index 00000000000..199b0cf97c3 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/sdkconfig.ci.release @@ -0,0 +1,6 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_PM_DFS_INIT_AUTO=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_ppa/test_apps/sdkconfig.defaults b/components/esp_driver_ppa/test_apps/sdkconfig.defaults new file mode 100644 index 00000000000..1ee5d718bc2 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/sdkconfig.defaults @@ -0,0 +1,3 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32p4 b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32p4 new file mode 100644 index 00000000000..702fac3342d --- /dev/null +++ b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32p4 @@ -0,0 +1,3 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_HEX=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hw_support/dma/dma2d.c b/components/esp_hw_support/dma/dma2d.c index dab310d02cc..bd6f0a4dbb5 100644 --- a/components/esp_hw_support/dma/dma2d.c +++ b/components/esp_hw_support/dma/dma2d.c @@ -571,7 +571,7 @@ esp_err_t dma2d_connect(dma2d_channel_handle_t dma2d_chan, const dma2d_trigger_t // Configure reorder functionality dma2d_ll_tx_enable_reorder(group->hal.dev, channel_id, dma2d_chan->status.reorder_en); // Assume dscr_port enable or not can be directly derived from trig_periph - dma2d_ll_tx_enable_dscr_port(group->hal.dev, channel_id, trig_periph->periph == DMA2D_TRIG_PERIPH_PPA_SR); + dma2d_ll_tx_enable_dscr_port(group->hal.dev, channel_id, trig_periph->periph == DMA2D_TRIG_PERIPH_PPA_SRM); // Reset to certain settings dma2d_ll_tx_enable_owner_check(group->hal.dev, channel_id, false); @@ -596,7 +596,7 @@ esp_err_t dma2d_connect(dma2d_channel_handle_t dma2d_chan, const dma2d_trigger_t // Configure reorder functionality dma2d_ll_rx_enable_reorder(group->hal.dev, channel_id, dma2d_chan->status.reorder_en); // Assume dscr_port enable or not can be directly derived from trig_periph - dma2d_ll_rx_enable_dscr_port(group->hal.dev, channel_id, trig_periph->periph == DMA2D_TRIG_PERIPH_PPA_SR); + dma2d_ll_rx_enable_dscr_port(group->hal.dev, channel_id, trig_periph->periph == DMA2D_TRIG_PERIPH_PPA_SRM); // Reset to certain settings dma2d_ll_rx_enable_owner_check(group->hal.dev, channel_id, false); @@ -871,6 +871,24 @@ esp_err_t dma2d_configure_color_space_conversion(dma2d_channel_handle_t dma2d_ch return ret; } +esp_err_t dma2d_configure_dscr_port_mode(dma2d_channel_handle_t dma2d_chan, const dma2d_dscr_port_mode_config_t *config) +{ + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE_ISR(dma2d_chan && config, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + + dma2d_group_t *group = dma2d_chan->group; + int channel_id = dma2d_chan->channel_id; + + if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) { + ESP_GOTO_ON_FALSE_ISR(config->block_h > 0 && config->block_v > 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + + dma2d_ll_tx_set_dscr_port_block_size(group->hal.dev, channel_id, config->block_h, config->block_v); + } + +err: + return ret; +} + esp_err_t dma2d_enqueue(dma2d_pool_handle_t dma2d_pool, const dma2d_trans_config_t *trans_desc, dma2d_trans_t *trans_placeholder) { esp_err_t ret = ESP_OK; diff --git a/components/esp_hw_support/dma/include/esp_private/dma2d.h b/components/esp_hw_support/dma/include/esp_private/dma2d.h index 33cd74ad569..4524ca95c68 100644 --- a/components/esp_hw_support/dma/include/esp_private/dma2d.h +++ b/components/esp_hw_support/dma/include/esp_private/dma2d.h @@ -104,7 +104,7 @@ typedef struct { * @return Whether a task switch is needed after the callback function returns, * this is usually due to the callback wakes up some high priority task. */ -typedef bool (*dma2d_trans_callback_t)(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); +typedef bool (*dma2d_trans_on_picked_callback_t)(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config); /** * @brief 2D-DMA channel special function flags @@ -131,7 +131,7 @@ typedef struct { uint32_t specified_tx_channel_mask; /*!< Bit mask of the specific TX channels to be used, the specified TX channels should have been reserved */ uint32_t specified_rx_channel_mask; /*!< Bit mask of the specific RX channels to be used, the specified RX channels should have been reserved */ - dma2d_trans_callback_t on_job_picked; /*!< Callback function to be called when all necessary channels to do the transaction have been acquired */ + dma2d_trans_on_picked_callback_t on_job_picked; /*!< Callback function to be called when all necessary channels to do the transaction have been acquired */ void *user_config; /*!< User registered data to be passed into `on_job_picked` callback */ } dma2d_trans_config_t; @@ -271,6 +271,27 @@ typedef struct { */ esp_err_t dma2d_configure_color_space_conversion(dma2d_channel_handle_t dma2d_chan, const dma2d_csc_config_t *config); +/** + * @brief A collection of configurations apply to 2D-DMA channel DSCR-PORT mode + */ +typedef struct { + uint32_t block_h; /*!< Horizontal width of the block in dscr-port mode (unit: pixel) */ + uint32_t block_v; /*!< Vertical height of the block in dscr-port mode (unit: pixel) */ +} dma2d_dscr_port_mode_config_t; + +/** + * @brief Configure 2D-DMA channel DSCR-PORT mode + * + * @note This API only targets PPA SRM, which uses 2D-DMA DSCR-PORT mode. + * + * @param[in] dma2d_chan 2D-DMA channel handle, get from the `on_job_picked` callback input argument `dma2d_chans` + * @param[in] config Configuration of 2D-DMA channel DSCR-PORT mode + * @return + * - ESP_OK: Configure 2D-DMA dscr-port mode successfully + * - ESP_ERR_INVALID_ARG: Configure 2D-DMA dscr-port mode failed because of invalid argument + */ +esp_err_t dma2d_configure_dscr_port_mode(dma2d_channel_handle_t dma2d_chan, const dma2d_dscr_port_mode_config_t *config); + /** * @brief Type of 2D-DMA event data */ diff --git a/components/esp_hw_support/dma/linker.lf b/components/esp_hw_support/dma/linker.lf index 0acf4b6f212..db6159eed14 100644 --- a/components/esp_hw_support/dma/linker.lf +++ b/components/esp_hw_support/dma/linker.lf @@ -113,6 +113,7 @@ entries: dma2d: dma2d_apply_strategy (noflash) dma2d: dma2d_set_transfer_ability (noflash) dma2d: dma2d_configure_color_space_conversion (noflash) + dma2d: dma2d_configure_dscr_port_mode (noflash) dma2d: dma2d_enqueue (noflash) [mapping:dma2d_hal] diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index dea07390ad3..750fddce903 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -217,6 +217,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "jpeg_hal.c") endif() + if(CONFIG_SOC_PPA_SUPPORTED) + list(APPEND srcs "ppa_hal.c") + endif() + if(CONFIG_SOC_GPSPI_SUPPORTED) list(APPEND srcs "spi_hal.c" diff --git a/components/hal/esp32p4/include/hal/dma2d_ll.h b/components/hal/esp32p4/include/hal/dma2d_ll.h index 56209130da2..8ec6f91ea49 100644 --- a/components/hal/esp32p4/include/hal/dma2d_ll.h +++ b/components/hal/esp32p4/include/hal/dma2d_ll.h @@ -55,7 +55,7 @@ extern "C" { #define DMA2D_LL_EVENT_TX_EOF (1<<1) #define DMA2D_LL_EVENT_TX_DONE (1<<0) -// Bit masks that are used to indicate availbility of some sub-features in the channels +// Bit masks that are used to indicate availability of some sub-features in the channels #define DMA2D_LL_TX_CHANNEL_SUPPORT_RO_MASK (0U | BIT0) // TX channels that support reorder feature #define DMA2D_LL_TX_CHANNEL_SUPPORT_CSC_MASK (0U | BIT0 | BIT1 | BIT2) // TX channels that support color space conversion feature @@ -479,7 +479,7 @@ static inline void dma2d_ll_rx_enable_reorder(dma2d_dev_t *dev, uint32_t channel reg->in_reorder_en_chn = enable; } -// COLOR SPACE CONVERTION FUNCTION +// COLOR SPACE CONVERSION FUNCTION /** * @brief Configure 2D-DMA RX channel color space conversion parameters @@ -825,6 +825,16 @@ static inline void dma2d_ll_tx_enable_dscr_port(dma2d_dev_t *dev, uint32_t chann dev->out_channel[channel].out_conf0.out_dscr_port_en_chn = enable; } +/** + * @brief Set 2D-DMA TX channel block size in dscr-port mode + */ +__attribute__((always_inline)) +static inline void dma2d_ll_tx_set_dscr_port_block_size(dma2d_dev_t *dev, uint32_t channel, uint32_t blk_h, uint32_t blk_v) +{ + dev->out_channel[channel].out_dscr_port_blk.out_dscr_port_blk_h_chn = blk_h; + dev->out_channel[channel].out_dscr_port_blk.out_dscr_port_blk_v_chn = blk_v; +} + /** * @brief Select 2D-DMA TX channel macro block size */ @@ -973,7 +983,7 @@ static inline void dma2d_ll_tx_enable_reorder(dma2d_dev_t *dev, uint32_t channel dev->out_channel[channel].out_conf0.out_reorder_en_chn = enable; } -// COLOR SPACE CONVERTION FUNCTION +// COLOR SPACE CONVERSION FUNCTION /** * @brief Configure 2D-DMA TX channel color space conversion parameters diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index 7ab8249bbdb..687e63c5ef2 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -24,15 +24,12 @@ extern "C" { #define PPA_LL_BLEND0_CLUT_MEM_ADDR_OFFSET 0x400 #define PPA_LL_BLEND1_CLUT_MEM_ADDR_OFFSET 0x800 -/** - * @brief Enumeration of alpha value transformation mode - */ -typedef enum { - PPA_LL_RX_ALPHA_NO_CHANGE, /*!< Do not replace alpha value. If input format does not contain alpha info, alpha value 255 will be used. */ - PPA_LL_RX_ALPHA_FIX_VALUE, /*!< Replace the alpha value in received pixel with a new, fixed alpha value */ - PPA_LL_RX_ALPHA_SCALE, /*!< Scale the alpha value in received pixel to be a new alpha value */ - PPA_LL_RX_ALPHA_INVERT, /*!< Invert the alpha value in received pixel */ -} ppa_ll_rx_alpha_mode_t; +#define PPA_LL_SRM_SCALING_INT_MAX PPA_SR_SCAL_X_INT_V +#define PPA_LL_SRM_SCALING_FRAG_MAX PPA_SR_SCAL_X_FRAG_V + +// TODO: On P4 ECO2, SRM block size needs update +#define PPA_LL_SRM_DEFAULT_BLOCK_SIZE 18 // 18 x 18 block size +#define PPA_LL_SRM_YUV420_BLOCK_SIZE 20 // 20 x 20 block size /** * @brief Enumeration of PPA blending mode @@ -71,13 +68,13 @@ static inline void ppa_ll_reset_register(void) /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define ppa_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; ppa_ll_reset_register(__VA_ARGS__) -/////////////////////////// Scaling and Rotating (SR) //////////////////////////////// +///////////////////////// Scaling, Rotating, Mirroring (SRM) ////////////////////////////// /** - * @brief Reset PPA scaling and rotating engine + * @brief Reset PPA scaling-rotating-mirroring engine * * @param dev Peripheral instance address */ -static inline void ppa_ll_sr_reset(ppa_dev_t *dev) +static inline void ppa_ll_srm_reset(ppa_dev_t *dev) { dev->sr_scal_rotate.scal_rotate_rst = 1; dev->sr_scal_rotate.scal_rotate_rst = 0; @@ -90,7 +87,7 @@ static inline void ppa_ll_sr_reset(ppa_dev_t *dev) * @param x_int The integrated part of scaling coefficient in X direction, 0 - 255 * @param x_frag The fragment part of scaling coefficient in X direction, 0 - 15. Corresponding fractional value is x_frag/16. */ -static inline void ppa_ll_sr_set_scaling_x(ppa_dev_t *dev, uint32_t x_int, uint32_t x_frag) +static inline void ppa_ll_srm_set_scaling_x(ppa_dev_t *dev, uint32_t x_int, uint32_t x_frag) { HAL_ASSERT(x_int <= PPA_SR_SCAL_X_INT_V && x_frag <= PPA_SR_SCAL_X_FRAG_V); HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sr_scal_rotate, sr_scal_x_int, x_int); @@ -104,7 +101,7 @@ static inline void ppa_ll_sr_set_scaling_x(ppa_dev_t *dev, uint32_t x_int, uint3 * @param y_int The integrated part of scaling coefficient in Y direction, 0 - 255 * @param y_frag The fragment part of scaling coefficient in Y direction, 0 - 15. Corresponding fractional value is y_frag/16. */ -static inline void ppa_ll_sr_set_scaling_y(ppa_dev_t *dev, uint32_t y_int, uint32_t y_frag) +static inline void ppa_ll_srm_set_scaling_y(ppa_dev_t *dev, uint32_t y_int, uint32_t y_frag) { HAL_ASSERT(y_int <= PPA_SR_SCAL_Y_INT_V && y_frag <= PPA_SR_SCAL_Y_FRAG_V); HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sr_scal_rotate, sr_scal_y_int, y_int); @@ -115,22 +112,22 @@ static inline void ppa_ll_sr_set_scaling_y(ppa_dev_t *dev, uint32_t y_int, uint3 * @brief Set PPA rotation angle (in the counterclockwise direction) * * @param dev Peripheral instance address - * @param angle One of the values in ppa_sr_rotation_angle_t + * @param angle One of the values in ppa_srm_rotation_angle_t */ -static inline void ppa_ll_sr_set_rotation_angle(ppa_dev_t *dev, ppa_sr_rotation_angle_t angle) +static inline void ppa_ll_srm_set_rotation_angle(ppa_dev_t *dev, ppa_srm_rotation_angle_t angle) { uint32_t val = 0; switch (angle) { - case PPA_SR_ROTATION_ANGLE_0: + case PPA_SRM_ROTATION_ANGLE_0: val = 0; break; - case PPA_SR_ROTATION_ANGLE_90: + case PPA_SRM_ROTATION_ANGLE_90: val = 1; break; - case PPA_SR_ROTATION_ANGLE_180: + case PPA_SRM_ROTATION_ANGLE_180: val = 2; break; - case PPA_SR_ROTATION_ANGLE_270: + case PPA_SRM_ROTATION_ANGLE_270: val = 3; break; default: @@ -146,7 +143,7 @@ static inline void ppa_ll_sr_set_rotation_angle(ppa_dev_t *dev, ppa_sr_rotation_ * @param dev Peripheral instance address * @param enable True to enable; False to disable */ -static inline void ppa_ll_sr_enable_mirror_x(ppa_dev_t *dev, bool enable) +static inline void ppa_ll_srm_enable_mirror_x(ppa_dev_t *dev, bool enable) { dev->sr_scal_rotate.sr_mirror_x = enable; } @@ -157,92 +154,92 @@ static inline void ppa_ll_sr_enable_mirror_x(ppa_dev_t *dev, bool enable) * @param dev Peripheral instance address * @param enable True to enable; False to disable */ -static inline void ppa_ll_sr_enable_mirror_y(ppa_dev_t *dev, bool enable) +static inline void ppa_ll_srm_enable_mirror_y(ppa_dev_t *dev, bool enable) { dev->sr_scal_rotate.sr_mirror_y = enable; } /** - * @brief Start PPA scaling and rotating engine to perform PPA SR + * @brief Start PPA scaling and rotating engine to perform PPA SRM * * @param dev Peripheral instance address */ -static inline void ppa_ll_sr_start(ppa_dev_t *dev) +static inline void ppa_ll_srm_start(ppa_dev_t *dev) { dev->sr_scal_rotate.scal_rotate_start = 1; } /** - * @brief Set the source image color mode for PPA Scaling and Rotating engine RX + * @brief Set the source image color mode for PPA Scaling-Rotating-Mirroring engine RX * * @param dev Peripheral instance address - * @param color_mode One of the values in ppa_sr_color_mode_t + * @param color_mode One of the values in ppa_srm_color_mode_t */ -static inline void ppa_ll_sr_set_rx_color_mode(ppa_dev_t *dev, ppa_sr_color_mode_t color_mode) +static inline void ppa_ll_srm_set_rx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) { uint32_t val = 0; switch (color_mode) { - case PPA_SR_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_ARGB8888: val = 0; break; - case PPA_SR_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB888: val = 1; break; - case PPA_SR_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_RGB565: val = 2; break; - case PPA_SR_COLOR_MODE_YUV420: + case PPA_SRM_COLOR_MODE_YUV420: val = 8; break; default: - // Unsupported SR rx color mode + // Unsupported SRM rx color mode abort(); } dev->sr_color_mode.sr_rx_cm = val; } /** - * @brief Set the destination image color mode for PPA Scaling and Rotating engine TX + * @brief Set the destination image color mode for PPA Scaling-Rotating-Mirroring engine TX * * @param dev Peripheral instance address - * @param color_mode One of the values in ppa_sr_color_mode_t + * @param color_mode One of the values in ppa_srm_color_mode_t */ -static inline void ppa_ll_sr_set_tx_color_mode(ppa_dev_t *dev, ppa_sr_color_mode_t color_mode) +static inline void ppa_ll_srm_set_tx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) { uint32_t val = 0; switch (color_mode) { - case PPA_SR_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_ARGB8888: val = 0; break; - case PPA_SR_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB888: val = 1; break; - case PPA_SR_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_RGB565: val = 2; break; - case PPA_SR_COLOR_MODE_YUV420: + case PPA_SRM_COLOR_MODE_YUV420: val = 8; break; default: - // Unsupported SR tx color mode + // Unsupported SRM tx color mode abort(); } dev->sr_color_mode.sr_tx_cm = val; } /** - * @brief Set YUV to RGB protocol when PPA SR pixel color space conversion from RX to TX is YUV to RGB + * @brief Set YUV to RGB protocol when PPA SRM RX pixel color space is YUV * * @param dev Peripheral instance address - * @param std One of the RGB-YUV conversion standards in color_conv_std_rgb_yuv_t + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t */ -static inline void ppa_ll_sr_set_yuv2rgb_std(ppa_dev_t *dev, color_conv_std_rgb_yuv_t std) +static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) { switch (std) { - case COLOR_CONV_STD_RGB_YUV_BT601: + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: dev->sr_color_mode.yuv2rgb_protocol = 0; break; - case COLOR_CONV_STD_RGB_YUV_BT709: + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: dev->sr_color_mode.yuv2rgb_protocol = 1; break; default: @@ -252,18 +249,18 @@ static inline void ppa_ll_sr_set_yuv2rgb_std(ppa_dev_t *dev, color_conv_std_rgb_ } /** - * @brief Set RGB to YUV protocol when PPA SR pixel color space conversion from RX to TX is RGB to YUV + * @brief Set RGB to YUV protocol when PPA SRM TX pixel color space is YUV * * @param dev Peripheral instance address - * @param std One of the RGB-YUV conversion standards in color_conv_std_rgb_yuv_t + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t */ -static inline void ppa_ll_sr_set_rgb2yuv_std(ppa_dev_t *dev, color_conv_std_rgb_yuv_t std) +static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) { switch (std) { - case COLOR_CONV_STD_RGB_YUV_BT601: + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: dev->sr_color_mode.rgb2yuv_protocol = 0; break; - case COLOR_CONV_STD_RGB_YUV_BT709: + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: dev->sr_color_mode.rgb2yuv_protocol = 1; break; default: @@ -273,18 +270,18 @@ static inline void ppa_ll_sr_set_rgb2yuv_std(ppa_dev_t *dev, color_conv_std_rgb_ } /** - * @brief Set PPA SR YUV input range + * @brief Set PPA SRM YUV input range * * @param dev Peripheral instance address - * @param range One of color range options in color_range_t + * @param range One of color range options in ppa_color_range_t */ -static inline void ppa_ll_sr_set_rx_yuv_range(ppa_dev_t *dev, color_range_t range) +static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) { switch (range) { - case COLOR_RANGE_LIMIT: + case PPA_COLOR_RANGE_LIMIT: dev->sr_color_mode.yuv_rx_range = 0; break; - case COLOR_RANGE_FULL: + case PPA_COLOR_RANGE_FULL: dev->sr_color_mode.yuv_rx_range = 1; break; default: @@ -294,18 +291,18 @@ static inline void ppa_ll_sr_set_rx_yuv_range(ppa_dev_t *dev, color_range_t rang } /** - * @brief Set PPA SR YUV output range + * @brief Set PPA SRM YUV output range * * @param dev Peripheral instance address - * @param range One of color range options in color_range_t + * @param range One of color range options in ppa_color_range_t */ -static inline void ppa_ll_sr_set_tx_yuv_range(ppa_dev_t *dev, color_range_t range) +static inline void ppa_ll_srm_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) { switch (range) { - case COLOR_RANGE_LIMIT: + case PPA_COLOR_RANGE_LIMIT: dev->sr_color_mode.yuv_tx_range = 0; break; - case COLOR_RANGE_FULL: + case PPA_COLOR_RANGE_FULL: dev->sr_color_mode.yuv_tx_range = 1; break; default: @@ -315,60 +312,61 @@ static inline void ppa_ll_sr_set_tx_yuv_range(ppa_dev_t *dev, color_range_t rang } /** - * @brief Enable PPA SR input data wrap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * @brief Enable PPA SRM input data swap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) * * @param dev Peripheral instance address * @param enable True to enable; False to disable */ -static inline void ppa_ll_sr_enable_rx_rgb_swap(ppa_dev_t *dev, bool enable) +static inline void ppa_ll_srm_enable_rx_rgb_swap(ppa_dev_t *dev, bool enable) { dev->sr_byte_order.sr_rx_rgb_swap_en = enable; } /** - * @brief Enable PPA SR input data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * @brief Enable PPA SRM input data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) * * Only supported when input color mode is ARGB8888 or RGB565. * * @param dev Peripheral instance address * @param enable True to enable; False to disable */ -static inline void ppa_ll_sr_enable_rx_byte_swap(ppa_dev_t *dev, bool enable) +static inline void ppa_ll_srm_enable_rx_byte_swap(ppa_dev_t *dev, bool enable) { dev->sr_byte_order.sr_rx_byte_swap_en = enable; } /** - * @brief Configure PPA SR alpha value transformation mode + * @brief Configure PPA SRM alpha value update mode * * @param dev Peripheral instance address - * @param mode Alpha value transformation mode, one of the values in ppa_ll_rx_alpha_mode_t - * @param val When PPA_LL_RX_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) - * When PPA_LL_RX_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) * When other modes are selected, this field is not used */ -static inline void ppa_ll_sr_configure_rx_alpha(ppa_dev_t *dev, ppa_ll_rx_alpha_mode_t mode, uint32_t val) +static inline void ppa_ll_srm_configure_rx_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) { switch (mode) { - case PPA_LL_RX_ALPHA_NO_CHANGE: + case PPA_ALPHA_NO_CHANGE: dev->sr_fix_alpha.sr_rx_alpha_mod = 0; dev->sr_fix_alpha.sr_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_FIX_VALUE: + case PPA_ALPHA_FIX_VALUE: dev->sr_fix_alpha.sr_rx_alpha_mod = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sr_fix_alpha, sr_rx_fix_alpha, val); dev->sr_fix_alpha.sr_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_SCALE: + case PPA_ALPHA_SCALE: dev->sr_fix_alpha.sr_rx_alpha_mod = 2; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->sr_fix_alpha, sr_rx_fix_alpha, val); dev->sr_fix_alpha.sr_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_INVERT: + case PPA_ALPHA_INVERT: dev->sr_fix_alpha.sr_rx_alpha_mod = 0; dev->sr_fix_alpha.sr_rx_alpha_inv = 1; + break; default: - // Unsupported alpha transformation mode + // Unsupported alpha update mode abort(); } } @@ -441,12 +439,12 @@ static inline void ppa_ll_blend_set_rx_bg_color_mode(ppa_dev_t *dev, ppa_blend_c case PPA_BLEND_COLOR_MODE_RGB565: val = 2; break; - case PPA_BLEND_COLOR_MODE_L8: - val = 4; - break; - case PPA_BLEND_COLOR_MODE_L4: - val = 5; - break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; default: // Unsupported blending rx background color mode abort(); @@ -473,12 +471,12 @@ static inline void ppa_ll_blend_set_rx_fg_color_mode(ppa_dev_t *dev, ppa_blend_c case PPA_BLEND_COLOR_MODE_RGB565: val = 2; break; - case PPA_BLEND_COLOR_MODE_L8: - val = 4; - break; - case PPA_BLEND_COLOR_MODE_L4: - val = 5; - break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; case PPA_BLEND_COLOR_MODE_A8: val = 6; break; @@ -567,71 +565,73 @@ static inline void ppa_ll_blend_enable_rx_fg_byte_swap(ppa_dev_t *dev, bool enab } /** - * @brief Configure PPA blending input background alpha value transformation mode + * @brief Configure PPA blending input background alpha value update mode * * @param dev Peripheral instance address - * @param mode Alpha value transformation mode, one of the values in ppa_ll_rx_alpha_mode_t - * @param val When PPA_LL_RX_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) - * When PPA_LL_RX_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) * When other modes are selected, this field is not used */ -static inline void ppa_ll_blend_configure_rx_bg_alpha(ppa_dev_t *dev, ppa_ll_rx_alpha_mode_t mode, uint32_t val) +static inline void ppa_ll_blend_configure_rx_bg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) { switch (mode) { - case PPA_LL_RX_ALPHA_NO_CHANGE: + case PPA_ALPHA_NO_CHANGE: dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_FIX_VALUE: + case PPA_ALPHA_FIX_VALUE: dev->blend_fix_alpha.blend0_rx_alpha_mod = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_SCALE: + case PPA_ALPHA_SCALE: dev->blend_fix_alpha.blend0_rx_alpha_mod = 2; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_INVERT: + case PPA_ALPHA_INVERT: dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; dev->blend_fix_alpha.blend0_rx_alpha_inv = 1; + break; default: - // Unsupported alpha transformation mode + // Unsupported alpha update mode abort(); } } /** - * @brief Configure PPA blending input foreground alpha value transformation mode + * @brief Configure PPA blending input foreground alpha value update mode * * @param dev Peripheral instance address - * @param mode Alpha value transformation mode, one of the values in ppa_ll_rx_alpha_mode_t - * @param val When PPA_LL_RX_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) - * When PPA_LL_RX_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) * When other modes are selected, this field is not used */ -static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_ll_rx_alpha_mode_t mode, uint32_t val) +static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) { switch (mode) { - case PPA_LL_RX_ALPHA_NO_CHANGE: + case PPA_ALPHA_NO_CHANGE: dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_FIX_VALUE: + case PPA_ALPHA_FIX_VALUE: dev->blend_fix_alpha.blend1_rx_alpha_mod = 1; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_SCALE: + case PPA_ALPHA_SCALE: dev->blend_fix_alpha.blend1_rx_alpha_mod = 2; HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; break; - case PPA_LL_RX_ALPHA_INVERT: + case PPA_ALPHA_INVERT: dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; dev->blend_fix_alpha.blend1_rx_alpha_inv = 1; + break; default: - // Unsupported alpha transformation mode + // Unsupported alpha update mode abort(); } } @@ -642,12 +642,12 @@ static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_ll_rx_ * @param dev Peripheral instance address * @param data The fix data to be filled to the image block pixels in ARGB8888 format * @param hb The horizontal width of image block that would be filled in fix pixel filling mode. The unit is pixel. - * @param vb The vertical width of image block that would be filled in fix pixel filling mode. The unit is pixel. + * @param vb The vertical height of image block that would be filled in fix pixel filling mode. The unit is pixel. */ -static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, uint32_t data, uint32_t hb, uint32_t vb) +static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, color_pixel_argb8888_data_t *data, uint32_t hb, uint32_t vb) { HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V); - dev->blend_fix_pixel.blend_tx_fix_pixel = data; + dev->blend_fix_pixel.blend_tx_fix_pixel = data->val; dev->blend_tx_size.blend_hb = hb; dev->blend_tx_size.blend_vb = vb; } @@ -658,9 +658,11 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, uint32_t * @param dev Peripheral instance address * @param rgb RGB color for A4/A8 mode in RGB888 format */ -static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, uint32_t rgb) +static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) { - dev->blend_rgb.val = rgb; + dev->blend_rgb.blend1_rx_b = rgb->b; + dev->blend_rgb.blend1_rx_g = rgb->g; + dev->blend_rgb.blend1_rx_r = rgb->r; } /* @@ -678,10 +680,15 @@ static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, uint32_t rgb) * @param rgb_thres_low Color-key lower threshold of background in RGB888 format * @param rgb_thres_high Color-key higher threshold of background in RGB888 format */ -static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, uint32_t rgb_thres_low, uint32_t rgb_thres_high) +static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) { - dev->ck_bg_low.val = rgb_thres_low; - dev->ck_bg_high.val = rgb_thres_high; + dev->ck_bg_low.colorkey_bg_b_low = rgb_thres_low->b; + dev->ck_bg_low.colorkey_bg_g_low = rgb_thres_low->g; + dev->ck_bg_low.colorkey_bg_r_low = rgb_thres_low->r; + + dev->ck_bg_high.colorkey_bg_b_high = rgb_thres_high->b; + dev->ck_bg_high.colorkey_bg_g_high = rgb_thres_high->g; + dev->ck_bg_high.colorkey_bg_r_high = rgb_thres_high->r; } /** @@ -691,10 +698,15 @@ static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, uint32_ * @param rgb_thres_low Color-key lower threshold of foreground in RGB888 format * @param rgb_thres_high Color-key higher threshold of foreground in RGB888 format */ -static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, uint32_t rgb_thres_low, uint32_t rgb_thres_high) +static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) { - dev->ck_fg_low.val = rgb_thres_low; - dev->ck_fg_high.val = rgb_thres_high; + dev->ck_fg_low.colorkey_fg_b_low = rgb_thres_low->b; + dev->ck_fg_low.colorkey_fg_g_low = rgb_thres_low->g; + dev->ck_fg_low.colorkey_fg_r_low = rgb_thres_low->r; + + dev->ck_fg_high.colorkey_fg_b_high = rgb_thres_high->b; + dev->ck_fg_high.colorkey_fg_g_high = rgb_thres_high->g; + dev->ck_fg_high.colorkey_fg_r_high = rgb_thres_high->r; } /** @@ -703,9 +715,11 @@ static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, uint32_ * @param dev Peripheral instance address * @param rgb Default RGB value in RGB888 format */ -static inline void ppa_ll_blend_set_ck_default_rgb(ppa_dev_t *dev, uint32_t rgb) +static inline void ppa_ll_blend_set_ck_default_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) { - dev->ck_default.val = (dev->ck_default.colorkey_fg_bg_reverse << PPA_COLORKEY_FG_BG_REVERSE_S) | rgb; + dev->ck_default.colorkey_default_b = rgb->b; + dev->ck_default.colorkey_default_g = rgb->g; + dev->ck_default.colorkey_default_r = rgb->r; } /** diff --git a/components/hal/include/hal/color_types.h b/components/hal/include/hal/color_types.h index e129bd09db6..4f2e82614c7 100644 --- a/components/hal/include/hal/color_types.h +++ b/components/hal/include/hal/color_types.h @@ -150,6 +150,44 @@ typedef enum { COLOR_RGB_ELEMENT_ORDER_BGR, /*!< RGB element order: BGR */ } color_rgb_element_order_t; +/*--------------------------------------------------------------- + Data Structure for Color Pixel Unit +---------------------------------------------------------------*/ + +/** + * @brief Data structure for ARGB8888 pixel unit + */ +typedef union { + struct { + uint32_t b: 8; /*!< B component [0, 255] */ + uint32_t g: 8; /*!< G component [0, 255] */ + uint32_t r: 8; /*!< R component [0, 255] */ + uint32_t a: 8; /*!< A component [0, 255] */ + }; + uint32_t val; /*!< 32-bit ARGB8888 value */ +} color_pixel_argb8888_data_t; + +/** + * @brief Data structure for RGB888 pixel unit + */ +typedef struct { + uint8_t b; /*!< B component [0, 255] */ + uint8_t g; /*!< G component [0, 255] */ + uint8_t r; /*!< R component [0, 255] */ +} color_pixel_rgb888_data_t; + +/** + * @brief Data structure for RGB565 pixel unit + */ +typedef union { + struct { + uint16_t b: 5; /*!< B component [0, 31] */ + uint16_t g: 6; /*!< G component [0, 63] */ + uint16_t r: 5; /*!< R component [0, 31] */ + }; + uint16_t val; /*!< 16-bit RGB565 value */ +} color_pixel_rgb565_data_t; + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/dma2d_types.h b/components/hal/include/hal/dma2d_types.h index 835fcf139ca..b66c791deb4 100644 --- a/components/hal/include/hal/dma2d_types.h +++ b/components/hal/include/hal/dma2d_types.h @@ -31,7 +31,7 @@ struct dma2d_descriptor_align8_s { uint32_t dma2d_en : 1; /*!< Whether to enable 2D functionality */ uint32_t suc_eof : 1; /*!< Whether the descriptor is the last one in the link */ uint32_t owner : 1; /*!< Who is allowed to access the buffer that this descriptor points to, select DMA2D_DESCRIPTOR_BUFFER_OWNER_CPU or DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA - When owner is chosen to be DMA, after DMA finishs with the descriptor, it will clear this bit + When owner is chosen to be DMA, after DMA finishes with the descriptor, it will clear this bit For data transfer, the bit won't be cleared unless DMA2D_OUT_AUTO_WRBACK is enabled */ }; /*!< Descriptor Word 0 */ struct { @@ -104,7 +104,7 @@ typedef enum { DMA2D_TRIG_PERIPH_M2M, /*!< 2D-DMA trigger peripheral: M2M */ DMA2D_TRIG_PERIPH_JPEG_ENCODER, /*!< 2D-DMA trigger peripheral: JPEG Encoder */ DMA2D_TRIG_PERIPH_JPEG_DECODER, /*!< 2D-DMA trigger peripheral: JPEG Decoder */ - DMA2D_TRIG_PERIPH_PPA_SR, /*!< 2D-DMA trigger peripheral: PPA SR engine */ + DMA2D_TRIG_PERIPH_PPA_SRM, /*!< 2D-DMA trigger peripheral: PPA SRM engine */ DMA2D_TRIG_PERIPH_PPA_BLEND, /*!< 2D-DMA trigger peripheral: PPA Blending engine */ } dma2d_trigger_peripheral_t; @@ -118,9 +118,11 @@ typedef enum { /** * @brief Enumeration of 2D-DMA data burst length options + * + * Starting from 1, saving 0 for special purpose (upper layer could use 0 to be a default burst length) */ typedef enum { - DMA2D_DATA_BURST_LENGTH_8, /*!< 2D-DMA block size: 8 bytes */ + DMA2D_DATA_BURST_LENGTH_8 = 1, /*!< 2D-DMA block size: 8 bytes */ DMA2D_DATA_BURST_LENGTH_16, /*!< 2D-DMA block size: 16 bytes */ DMA2D_DATA_BURST_LENGTH_32, /*!< 2D-DMA block size: 32 bytes */ DMA2D_DATA_BURST_LENGTH_64, /*!< 2D-DMA block size: 64 bytes */ @@ -174,6 +176,10 @@ typedef enum { // B = 1.164 *(Y - 16) + 2.114 *(Cb - 128) // //*********************BT709***********************************// +// R/G/B [0 ... 255] +// Y [16 ... 235] +// Cb/Cr [16 ... 240] + // 256 * Q = A[9:0] * x + B[10:0] * y + C[9:0] * z + D[17:0] #define DMA2D_COLOR_SPACE_CONV_PARAM_RGB2YUV_BT601 \ diff --git a/components/hal/include/hal/ppa_hal.h b/components/hal/include/hal/ppa_hal.h new file mode 100644 index 00000000000..1cbfc300052 --- /dev/null +++ b/components/hal/include/hal/ppa_hal.h @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The HAL is not public api, don't use in application code. + * See readme.md in soc/README.md + ******************************************************************************/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ppa_dev_t *ppa_soc_handle_t; // PPA SOC layer handle + +/** + * Context that should be maintained by both the driver and the HAL + */ +typedef struct { + ppa_soc_handle_t dev; // PPA SOC layer handle (i.e. register base address) +} ppa_hal_context_t; + +/** + * @brief Init the PPA hal. This function should be called first before other hal layer function is called + * + * @param hal Context of the HAL layer + */ +void ppa_hal_init(ppa_hal_context_t *hal); + +/** + * @brief De-init the PPA hal + * + * @param hal Context of the HAL layer + */ +void ppa_hal_deinit(ppa_hal_context_t *hal); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/ppa_types.h b/components/hal/include/hal/ppa_types.h index 1be3e6c9e80..67741433c5c 100644 --- a/components/hal/include/hal/ppa_types.h +++ b/components/hal/include/hal/ppa_types.h @@ -8,6 +8,7 @@ #include #include "hal/color_types.h" +#include "hal/dma2d_types.h" #ifdef __cplusplus extern "C" { @@ -17,43 +18,99 @@ extern "C" { * @brief Enumeration of engines in PPA modules */ typedef enum { - PPA_ENGINE_TYPE_SR, /*!< PPA Scaling and Rotating (SR) engine, used to perform scale_and_rotate */ + PPA_ENGINE_TYPE_SRM, /*!< PPA Scaling-Rotating-Mirroring (SRM) engine, used to perform scale, rotate, mirror */ PPA_ENGINE_TYPE_BLEND, /*!< PPA Blending engine, used to perform blend or fill */ } ppa_engine_type_t; /** - * @brief Enumeration of PPA Scaling and Rotating available rotation angle (in the counterclockwise direction) + * @brief Enumeration of PPA Scaling-Rotating-Mirroring available rotation angle (in the counterclockwise direction) */ typedef enum { - PPA_SR_ROTATION_ANGLE_0, /*!< Picture does no rotation */ - PPA_SR_ROTATION_ANGLE_90, /*!< Picture rotates 90 degrees CCW */ - PPA_SR_ROTATION_ANGLE_180, /*!< Picture rotates 180 degrees CCW */ - PPA_SR_ROTATION_ANGLE_270, /*!< Picture rotates 270 degrees CCW */ -} ppa_sr_rotation_angle_t; + PPA_SRM_ROTATION_ANGLE_0, /*!< Picture does no rotation */ + PPA_SRM_ROTATION_ANGLE_90, /*!< Picture rotates 90 degrees CCW */ + PPA_SRM_ROTATION_ANGLE_180, /*!< Picture rotates 180 degrees CCW */ + PPA_SRM_ROTATION_ANGLE_270, /*!< Picture rotates 270 degrees CCW */ +} ppa_srm_rotation_angle_t; /** - * @brief Enumeration of PPA Scaling and Rotating available color mode + * @brief Enumeration of PPA Scaling-Rotating-Mirroring available color mode */ typedef enum { - PPA_SR_COLOR_MODE_ARGB8888 = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888), /*!< PPA SR color mode: ARGB8888 */ - PPA_SR_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA SR color mode: RGB888 */ - PPA_SR_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA SR color mode: RGB565 */ - PPA_SR_COLOR_MODE_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), /*!< PPA SR color mode: YUV420 */ -} ppa_sr_color_mode_t; + PPA_SRM_COLOR_MODE_ARGB8888 = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888), /*!< PPA SRM color mode: ARGB8888 */ + PPA_SRM_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA SRM color mode: RGB888 */ + PPA_SRM_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA SRM color mode: RGB565 */ + PPA_SRM_COLOR_MODE_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), /*!< PPA SRM color mode: YUV420 */ + PPA_SRM_COLOR_MODE_YUV444 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV444), /*!< PPA SRM color mode: YUV444 (limited range only)*/ + // YUV444 not supported by PPA hardware, but we can use 2D-DMA to do conversion before sending into and after coming out from the PPA module + // If in_pic is YUV444, then TX DMA channel could do DMA2D_CSC_TX_YUV444_TO_RGB888_601/709, so PPA in_color_mode is RGB888 + // If out_pic is YUV444, then RX DMA channel could do DMA2D_CSC_RX_YUV420_TO_YUV444, so PPA out_color_mode is YUV420 + // TODO: P4 ECO2 supports YUV422 + // PPA_SRM_COLOR_MODE_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), /*!< PPA SRM color mode: YUV422 (input only, limited range only) */ +} ppa_srm_color_mode_t; /** - * @brief Enumeration of PPA Blending available color mode + * @brief Enumeration of PPA blend available color mode */ typedef enum { - PPA_BLEND_COLOR_MODE_ARGB8888 = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888), /*!< PPA Blending color mode: ARGB8888 */ - PPA_BLEND_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA Blending color mode: RGB888 */ - PPA_BLEND_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA Blending color mode: RGB565 */ - PPA_BLEND_COLOR_MODE_L8 = COLOR_TYPE_ID(COLOR_SPACE_CLUT, COLOR_PIXEL_L8), /*!< PPA Blending color mode: L8, only available on blending inputs */ - PPA_BLEND_COLOR_MODE_L4 = COLOR_TYPE_ID(COLOR_SPACE_CLUT, COLOR_PIXEL_L4), /*!< PPA Blending color mode: L4, only available on blending inputs */ - PPA_BLEND_COLOR_MODE_A8 = COLOR_TYPE_ID(COLOR_SPACE_ALPHA, COLOR_PIXEL_A8), /*!< PPA Blending color mode: A8, only available on blending foreground input */ - PPA_BLEND_COLOR_MODE_A4 = COLOR_TYPE_ID(COLOR_SPACE_ALPHA, COLOR_PIXEL_A4), /*!< PPA Blending color mode: A4, only available on blending foreground input */ + PPA_BLEND_COLOR_MODE_ARGB8888 = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888), /*!< PPA blend color mode: ARGB8888 */ + PPA_BLEND_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA blend color mode: RGB888 */ + PPA_BLEND_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA blend color mode: RGB565 */ + PPA_BLEND_COLOR_MODE_A8 = COLOR_TYPE_ID(COLOR_SPACE_ALPHA, COLOR_PIXEL_A8), /*!< PPA blend color mode: A8, only available on blend foreground input */ + PPA_BLEND_COLOR_MODE_A4 = COLOR_TYPE_ID(COLOR_SPACE_ALPHA, COLOR_PIXEL_A4), /*!< PPA blend color mode: A4, only available on blend foreground input */ + // TODO: Support CLUT to support L4/L8 color mode + // PPA_BLEND_COLOR_MODE_L8 = COLOR_TYPE_ID(COLOR_SPACE_CLUT, COLOR_PIXEL_L8), /*!< PPA blend color mode: L8, only available on blend inputs */ + // PPA_BLEND_COLOR_MODE_L4 = COLOR_TYPE_ID(COLOR_SPACE_CLUT, COLOR_PIXEL_L4), /*!< PPA blend color mode: L4, only available on blend inputs */ } ppa_blend_color_mode_t; +/** + * @brief Enumeration of PPA fill available color mode + */ +typedef enum { + PPA_FILL_COLOR_MODE_ARGB8888 = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888), /*!< PPA fill color mode: ARGB8888 */ + PPA_FILL_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA fill color mode: RGB888 */ + PPA_FILL_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA fill color mode: RGB565 */ +} ppa_fill_color_mode_t; + +/** + * @brief Enumeration of PPA alpha compositing update mode + */ +typedef enum { + PPA_ALPHA_NO_CHANGE = 0, /*!< Do not replace alpha value (A' = A). + If input format does not contain alpha info, alpha value 255 will be used. */ + PPA_ALPHA_FIX_VALUE, /*!< Replace the alpha value in received pixel with a new, fixed alpha value (A' = val) */ + PPA_ALPHA_SCALE, /*!< Scale the alpha value in received pixel to be a new alpha value (A' = (A * val) >> 8). + If input format does not contain alpha info, A' = (255 * val) >> 8. */ + PPA_ALPHA_INVERT, /*!< Invert the alpha value in received pixel (A' = 255 - A). + If input format does not contain alpha info, A' = 0, i.e. a layer with 0% opacity. */ +} ppa_alpha_update_mode_t; + +/** + * @brief Enumeration of PPA supported color conversion standard between RGB and YUV (determines the YUV<->RGB conversion equation) + */ +typedef enum { + PPA_COLOR_CONV_STD_RGB_YUV_BT601 = COLOR_CONV_STD_RGB_YUV_BT601, /*!< YUV<->RGB conversion standard: BT.601 */ + PPA_COLOR_CONV_STD_RGB_YUV_BT709 = COLOR_CONV_STD_RGB_YUV_BT709, /*!< YUV<->RGB conversion standard: BT.709 */ +} ppa_color_conv_std_rgb_yuv_t; + +/** + * @brief Enumeration of PPA supported color range (determines the YUV<->RGB conversion equation) + */ +typedef enum { + PPA_COLOR_RANGE_LIMIT = COLOR_RANGE_LIMIT, /*!< Limited color range, 16 is the darkest black and 235 is the brightest white */ + PPA_COLOR_RANGE_FULL = COLOR_RANGE_FULL, /*!< Full color range, 0 is the darkest black and 255 is the brightest white */ +} ppa_color_range_t; + +/** + * @brief Enumeration of PPA supported data burst length + */ +typedef enum { + PPA_DATA_BURST_LENGTH_8 = DMA2D_DATA_BURST_LENGTH_8, /*!< Data burst length: 8 bytes */ + PPA_DATA_BURST_LENGTH_16 = DMA2D_DATA_BURST_LENGTH_16, /*!< Data burst length: 16 bytes */ + PPA_DATA_BURST_LENGTH_32 = DMA2D_DATA_BURST_LENGTH_32, /*!< Data burst length: 32 bytes */ + PPA_DATA_BURST_LENGTH_64 = DMA2D_DATA_BURST_LENGTH_64, /*!< Data burst length: 64 bytes */ + PPA_DATA_BURST_LENGTH_128 = DMA2D_DATA_BURST_LENGTH_128, /*!< Data burst length: 128 bytes */ +} ppa_data_burst_length_t; + #ifdef __cplusplus } #endif diff --git a/components/hal/ppa_hal.c b/components/hal/ppa_hal.c new file mode 100644 index 00000000000..a2cd073fe83 --- /dev/null +++ b/components/hal/ppa_hal.c @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "hal/ppa_hal.h" +#include "hal/ppa_ll.h" + +void ppa_hal_init(ppa_hal_context_t *hal) +{ + hal->dev = PPA_LL_GET_HW; +} + +void ppa_hal_deinit(ppa_hal_context_t *hal) +{ + hal->dev = NULL; +} diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..1c3116f0de3 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -259,6 +259,10 @@ config SOC_GP_LDO_SUPPORTED bool default y +config SOC_PPA_SUPPORTED + bool + default y + config SOC_LIGHT_SLEEP_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/dma2d_channel.h b/components/soc/esp32p4/include/soc/dma2d_channel.h index f960fb1c4a3..00ba9dbbda7 100644 --- a/components/soc/esp32p4/include/soc/dma2d_channel.h +++ b/components/soc/esp32p4/include/soc/dma2d_channel.h @@ -8,12 +8,12 @@ // The following macros are matched with the 2D-DMA peri_sel field peripheral selection ID #define SOC_DMA2D_TRIG_PERIPH_JPEG_RX (0) -#define SOC_DMA2D_TRIG_PERIPH_PPA_SR_RX (1) +#define SOC_DMA2D_TRIG_PERIPH_PPA_SRM_RX (1) #define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX (2) #define SOC_DMA2D_TRIG_PERIPH_M2M_RX (-1) // Any value of 3 ~ 7, TX and RX do not have to use same ID value for M2M #define SOC_DMA2D_TRIG_PERIPH_JPEG_TX (0) -#define SOC_DMA2D_TRIG_PERIPH_PPA_SR_TX (1) -#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_FG_TX (2) -#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_BG_TX (3) +#define SOC_DMA2D_TRIG_PERIPH_PPA_SRM_TX (1) +#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_BG_TX (2) +#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_FG_TX (3) #define SOC_DMA2D_TRIG_PERIPH_M2M_TX (-1) // Any value of 4 ~ 7, TX and RX do not have to use same ID value for M2M diff --git a/components/soc/esp32p4/include/soc/dma2d_reg.h b/components/soc/esp32p4/include/soc/dma2d_reg.h index 5a9acb85ae5..2885106a173 100644 --- a/components/soc/esp32p4/include/soc/dma2d_reg.h +++ b/components/soc/esp32p4/include/soc/dma2d_reg.h @@ -899,7 +899,7 @@ extern "C" { #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH0_V 0x00000003U #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH0_S 0 /** DMA2D_OUT_COLOR_3B_PROC_EN_CH0 : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ #define DMA2D_OUT_COLOR_3B_PROC_EN_CH0 (BIT(2)) @@ -1032,14 +1032,14 @@ extern "C" { */ #define DMA2D_OUT_DSCR_PORT_BLK_CH0_REG (DR_REG_DMA2D_BASE + 0x6c) /** DMA2D_OUT_DSCR_PORT_BLK_H_CH0 : R/W; bitpos: [13:0]; default: 18; - * Set the vertical height of tx block size in dscr port mode + * Set the horizontal width of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_H_CH0 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH0_M (DMA2D_OUT_DSCR_PORT_BLK_H_CH0_V << DMA2D_OUT_DSCR_PORT_BLK_H_CH0_S) #define DMA2D_OUT_DSCR_PORT_BLK_H_CH0_V 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH0_S 0 /** DMA2D_OUT_DSCR_PORT_BLK_V_CH0 : R/W; bitpos: [27:14]; default: 18; - * Set the horizontal width of tx block size in dscr port mode + * Set the vertical height of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_V_CH0 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_V_CH0_M (DMA2D_OUT_DSCR_PORT_BLK_V_CH0_V << DMA2D_OUT_DSCR_PORT_BLK_V_CH0_S) @@ -1907,7 +1907,7 @@ extern "C" { #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH1_V 0x00000003U #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH1_S 0 /** DMA2D_OUT_COLOR_3B_PROC_EN_CH1 : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ #define DMA2D_OUT_COLOR_3B_PROC_EN_CH1 (BIT(2)) @@ -2040,14 +2040,14 @@ extern "C" { */ #define DMA2D_OUT_DSCR_PORT_BLK_CH1_REG (DR_REG_DMA2D_BASE + 0x16c) /** DMA2D_OUT_DSCR_PORT_BLK_H_CH1 : R/W; bitpos: [13:0]; default: 18; - * Set the vertical height of tx block size in dscr port mode + * Set the horizontal width of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_H_CH1 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH1_M (DMA2D_OUT_DSCR_PORT_BLK_H_CH1_V << DMA2D_OUT_DSCR_PORT_BLK_H_CH1_S) #define DMA2D_OUT_DSCR_PORT_BLK_H_CH1_V 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH1_S 0 /** DMA2D_OUT_DSCR_PORT_BLK_V_CH1 : R/W; bitpos: [27:14]; default: 18; - * Set the horizontal width of tx block size in dscr port mode + * Set the vertical height of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_V_CH1 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_V_CH1_M (DMA2D_OUT_DSCR_PORT_BLK_V_CH1_V << DMA2D_OUT_DSCR_PORT_BLK_V_CH1_S) @@ -2915,7 +2915,7 @@ extern "C" { #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH2_V 0x00000003U #define DMA2D_OUT_COLOR_OUTPUT_SEL_CH2_S 0 /** DMA2D_OUT_COLOR_3B_PROC_EN_CH2 : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ #define DMA2D_OUT_COLOR_3B_PROC_EN_CH2 (BIT(2)) @@ -3048,14 +3048,14 @@ extern "C" { */ #define DMA2D_OUT_DSCR_PORT_BLK_CH2_REG (DR_REG_DMA2D_BASE + 0x26c) /** DMA2D_OUT_DSCR_PORT_BLK_H_CH2 : R/W; bitpos: [13:0]; default: 18; - * Set the vertical height of tx block size in dscr port mode + * Set the horizontal width of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_H_CH2 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH2_M (DMA2D_OUT_DSCR_PORT_BLK_H_CH2_V << DMA2D_OUT_DSCR_PORT_BLK_H_CH2_S) #define DMA2D_OUT_DSCR_PORT_BLK_H_CH2_V 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_H_CH2_S 0 /** DMA2D_OUT_DSCR_PORT_BLK_V_CH2 : R/W; bitpos: [27:14]; default: 18; - * Set the horizontal width of tx block size in dscr port mode + * Set the vertical height of tx block size in dscr port mode */ #define DMA2D_OUT_DSCR_PORT_BLK_V_CH2 0x00003FFFU #define DMA2D_OUT_DSCR_PORT_BLK_V_CH2_M (DMA2D_OUT_DSCR_PORT_BLK_V_CH2_V << DMA2D_OUT_DSCR_PORT_BLK_V_CH2_S) @@ -3990,7 +3990,7 @@ extern "C" { #define DMA2D_IN_COLOR_OUTPUT_SEL_CH0_V 0x00000003U #define DMA2D_IN_COLOR_OUTPUT_SEL_CH0_S 0 /** DMA2D_IN_COLOR_3B_PROC_EN_CH0 : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ #define DMA2D_IN_COLOR_3B_PROC_EN_CH0 (BIT(2)) diff --git a/components/soc/esp32p4/include/soc/dma2d_struct.h b/components/soc/esp32p4/include/soc/dma2d_struct.h index 03a51a67434..b3f91e92b3c 100644 --- a/components/soc/esp32p4/include/soc/dma2d_struct.h +++ b/components/soc/esp32p4/include/soc/dma2d_struct.h @@ -660,7 +660,7 @@ typedef union { */ uint32_t out_color_output_sel_chn:2; /** out_color_3b_proc_en_chn : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ uint32_t out_color_3b_proc_en_chn:1; @@ -718,11 +718,11 @@ typedef union { typedef union { struct { /** out_dscr_port_blk_h_chn : R/W; bitpos: [13:0]; default: 18; - * Set the vertical height of tx block size in dscr port mode + * Set the horizontal width of tx block size in dscr port mode */ uint32_t out_dscr_port_blk_h_chn:14; /** out_dscr_port_blk_v_chn : R/W; bitpos: [27:14]; default: 18; - * Set the horizontal width of tx block size in dscr port mode + * Set the vertical height of tx block size in dscr port mode */ uint32_t out_dscr_port_blk_v_chn:14; uint32_t reserved_28:4; @@ -1411,7 +1411,7 @@ typedef union { */ uint32_t in_color_output_sel_chn:2; /** in_color_3b_proc_en_chn : R/W; bitpos: [2]; default: 0; - * Enable generic color convert modlue between color input & color output, need to + * Enable generic color convert module between color input & color output, need to * configure parameter. */ uint32_t in_color_3b_proc_en_chn:1; diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..52bd43b65a4 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -88,7 +88,7 @@ // #define SOC_TOUCH_SENSOR_SUPPORTED 1 //TODO: IDF-7477 #define SOC_RNG_SUPPORTED 1 #define SOC_GP_LDO_SUPPORTED 1 // General purpose LDO -// #define SOC_PPA_SUPPORTED 1 //TODO: IDF-6878 +#define SOC_PPA_SUPPORTED 1 #define SOC_LIGHT_SLEEP_SUPPORTED 1 #define SOC_DEEP_SLEEP_SUPPORTED 1 diff --git a/docs/_static/diagrams/ppa/pic_blk_concept.png b/docs/_static/diagrams/ppa/pic_blk_concept.png new file mode 100644 index 0000000000000000000000000000000000000000..21eadd08264db764dfc3fdd8a413ea30219375db GIT binary patch literal 26960 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 literal 0 HcmV?d00001 diff --git a/docs/conf_common.py b/docs/conf_common.py index 812210c89c2..a0b4ace54c4 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -175,6 +175,8 @@ JPEG_DOCS = ['api-reference/peripherals/jpeg.rst'] +PPA_DOCS = ['api-reference/peripherals/ppa.rst'] + QEMU_DOCS = ['api-guides/tools/qemu.rst'] ESP32_DOCS = ['api-reference/system/himem.rst', @@ -277,6 +279,7 @@ 'SOC_SPI_SUPPORT_SLAVE_HD_VER2':SPI_SLAVE_HD_DOCS, 'SOC_WIFI_NAN_SUPPORT':NAN_DOCS, 'SOC_JPEG_CODEC_SUPPORTED':JPEG_DOCS, + 'SOC_PPA_SUPPORTED':PPA_DOCS, 'SOC_GP_LDO_SUPPORTED':LDO_DOCS, 'esp32':ESP32_DOCS, 'esp32s2':ESP32S2_DOCS, diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index 7c914430b39..46821827c2e 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -16,12 +16,14 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_cam/include/esp_cam_ctlr_types.h \ $(PROJECT_PATH)/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h \ $(PROJECT_PATH)/components/hal/include/hal/jpeg_types.h \ + $(PROJECT_PATH)/components/hal/include/hal/ppa_types.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_types.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_types.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_af.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \ + $(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \ $(PROJECT_PATH)/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/adc_channel.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/clk_tree_defs.h \ diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 5094e38dd73..fa847069b12 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -30,6 +30,7 @@ Peripherals API :SOC_MCPWM_SUPPORTED: mcpwm :SOC_PARLIO_SUPPORTED: parlio :SOC_PCNT_SUPPORTED: pcnt + :SOC_PPA_SUPPORTED: ppa :SOC_RMT_SUPPORTED: rmt :SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements :SOC_SDMMC_HOST_SUPPORTED: sdmmc_host diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst new file mode 100644 index 00000000000..e108558839c --- /dev/null +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -0,0 +1,149 @@ +Pixel-Processing Accelerator (PPA) +================================== + +Introduction +------------ + +{IDF_TARGET_NAME} includes a pixel-processing accelerator (PPA) module, to realize hardware-level acceleration of image algorithms, such as image rotation, scaling, mirroring, and blending. + +Terminology +----------- + +The terms used in relation to the PPA driver are given in the table and the diagram below. + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Term + - Definition + * - Picture (pic) + - A complete image stored in the system memory. + * - Block + - A portion cropped from a picture at a certain size, with the maximum size equivalent to the entire picture. + * - Pixel + - The unit to be used in the PPA context. + * - PPA Operation + - Types of image algorithm accelerations, includes scale-rotate-mirror (SRM), blend, and fill. + * - PPA Client + - Who wants to do the PPA operations. Typically, every PPA client is hold by a specific task. + * - PPA Transaction + - One request from a PPA client to do a PPA operation is one PPA transaction. + +.. figure:: ../../../_static/diagrams/ppa/pic_blk_concept.png + :align: center + :alt: PPA picture/block terminology + + PPA picture/block terminology + +Functional Overview +------------------- + +The following sections detail the design of the PPA driver: + +- :ref:`ppa-client-registration` - Covers how to register a PPA client to perform any PPA operations. +- :ref:`ppa-register-callback` - Covers how to hook user specific code to PPA driver event callback function. +- :ref:`ppa-perform-operation` - Covers how to perform a PPA operation. +- :ref:`ppa-thread-safety` - Covers the usage of the PPA operation APIs in thread safety aspect. +- :ref:`ppa-performance-overview` - Covers the performance of PPA operations. + +.. _ppa-client-registration: + +Register PPA Client +^^^^^^^^^^^^^^^^^^^ + +Requests to perform PPA operations are made by PPA clients. Therefore, PPA clients need to be registered first before doing any PPA operations. Call :cpp:func:`ppa_register_client` function to register a new client. :cpp:type:`ppa_client_config_t` structure is used to specific the properties of the client. + +- :cpp:member:`ppa_client_config_t::oper_type` - Each PPA operation type corresponds to one PPA client type, a registered PPA client can only request one specific type of PPA operations. +- :cpp:member:`ppa_client_config_t::max_pending_trans_num` - Decides the maximum number of pending PPA transactions the client can hold. + +It is recommended that every task to register its own PPA clients. For example, an application contains two tasks: Task A requires both the PPA SRM and the PPA fill functionalities, so one PPA SRM client and one PPA fill client should be registered in Task A; While Task B also requires the PPA SRM functionality, then another PPA SRM client should be registered in Task B. + +If the task no longer needs to do PPA operations, the corresponding PPA clients can be deregistered with :cpp:func:`ppa_unregister_client` function. + +.. _ppa-register-callback: + +Register PPA Event Callbacks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When an event occurs (e.g., a PPA transaction is completed), the CPU is notified of this event via an interrupt. If some specific functions need to be called when a particular event occurs, a callback can be registered for that event by calling :cpp:func:`ppa_client_register_event_callbacks`. This can be specifically useful when ``PPA_TRANS_MODE_NON_BLOCKING`` mode is selected to perform the PPA operations. It is worth noticing that the event callbacks are bound to PPA clients, but the user context is provided per transaction in the call to the PPA operation APIs. This allows the maximum flexibility in utilizing the event callbacks. + +The registered callback functions are called in the interrupt context, therefore, the callback functions should follow common ISR (Interrupt Service Routine) rules. + +.. _ppa-perform-operation: + +Perform PPA Operations +^^^^^^^^^^^^^^^^^^^^^^ + +Once the PPA client is registered, a PPA operation can be requested with the returned :cpp:type:`ppa_client_handle_t`. + +PPA operations includes: + +Scale, Rotate, Mirror (SRM) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Call :cpp:func:`ppa_do_scale_rotate_mirror` to apply one or more of the scaling, rotation, mirroring operations to the target block inside a picture. + +Some notes to avoid confusion in configuring :cpp:type:`ppa_srm_oper_config_t`: + +.. list:: + - :cpp:member:`ppa_in_pic_blk_config_t::buffer` and :cpp:member:`ppa_out_pic_blk_config_t::buffer` have to be the pointers to different picture buffers for a SRM operation. + - The precision of :cpp:member:`ppa_srm_oper_config_t::scale_x` and :cpp:member:`ppa_srm_oper_config_t::scale_y` will be truncated to a step size of 1/16. + - Output block's width/height is totally determined by the input block's width/height, scaling factor, and rotation angle, so output block's width/height does not need to be configured. However, please make sure the output block can fit at the offset location in the output picture. + - If the color mode of the input or output picture is ``PPA_SRM_COLOR_MODE_YUV420``, then its ``pic_w``, ``pic_h``, ``block_w``, ``block_h``, ``block_offset_x``, ``block_offset_y`` fields must be even. + +Blend +~~~~~ + +Call :cpp:func:`ppa_do_blend` to blend the two target blocks of two so-called foreground (FG) and background (BG) pictures. + +Blend follows the normal Alpha Blending formula: + +:math:`A_{out} = A_b + A_f - A_b \times A_f` + +:math:`C_{out} = (C_b \times A_b \times (1 - A_f) + C_f \times A_f) / (A_b + A_f - A_b \times A_f)` + +where :math:`A_b` is the Alpha channel of the background layer, :math:`A_f` is the Alpha channel of the foreground layer, :math:`C_b` corresponds to the R, G, B components of the background layer, and :math:`C_f` corresponds to the R, G, B components of the foreground layer. + +Note that this formula is not symmetric to FG and BG. When :math:`A_f = 1`, it calculates :math:`C_{out} = C_f`, :math:`A_{out} = 1`, which means if the color mode of the FG picture is ``PPA_BLEND_COLOR_MODE_RGB565`` or ``PPA_BLEND_COLOR_MODE_RGB888``, since a Alpha value of 255 will be filled by the PPA hardware (i.e. :math:`A_f = 1`), the blended result will be identical to the FG block. + +If :cpp:member:`ppa_blend_oper_config_t::bg_ck_en` or :cpp:member:`ppa_blend_oper_config_t::fg_ck_en` is set to ``true``, the pixels fall into the color-key (also known as Chroma-key) range does not follow Alpha Blending process. Please check **{IDF_TARGET_NAME} Technical Reference Manual** > **Pixel-Processing Accelerator (PPA)** > **Functional Description** > **Layer Blending (BLEND)** [`PDF <{IDF_TARGET_TRM_EN_URL}#ppa>`__] for the detailed rules. + +Similarly, some notes to avoid confusion in configuring :cpp:type:`ppa_blend_oper_config_t`: + +.. list:: + - :cpp:member:`ppa_out_pic_blk_config_t::buffer` can be the same pointer to one of the input's :cpp:member:`ppa_in_pic_blk_config_t::buffer` for a blend operation. + - The blocks' width/height of FG and BG should be identical, and are the width/height values for the output block. + - If the color mode of the input picture is ``PPA_BLEND_COLOR_MODE_A4``, then its ``block_w`` and ``block_offset_x`` fields must be even. + +Fill +~~~~ + +Call :cpp:func:`ppa_do_fill` to fill a target block inside a picture. + +:cpp:type:`ppa_trans_mode_t` is a field configurable to all the PPA operation APIs. It decides whether you want the call to the PPA operation API to block until the transaction finishes or to return immediately after the transaction is pushed to the internal queue. + +.. _ppa-thread-safety: + +Thread Safety +^^^^^^^^^^^^^ + +The PPA driver has guaranteed the thread safety of calling the PPA operation APIs in all following situations: + +.. list:: + - Among clients of different types in one task + - Among clients of same type in different tasks + - Among clients of different types in different tasks + +.. _ppa-performance-overview: + +Performance Overview +^^^^^^^^^^^^^^^^^^^^ + +The PPA operations are acted on the target block of an input picture. Therefore, the time it takes to complete a PPA transaction is proportional to the amount of the data in the block. The size of the entire picture has no influence on the performance. More importantly, the PPA performance highly relies on the PSRAM bandwidth if the pictures are located in the PSRAM section. When there are quite a few peripherals reading and writing to the PSRAM at the same time, the performance of PPA operation will be greatly reduced. + +API Reference +------------- + +.. include-build-file:: inc/ppa.inc +.. include-build-file:: inc/ppa_types.inc diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 36c28c31310..0171c6a5d7d 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -29,6 +29,7 @@ :SOC_MCPWM_SUPPORTED: mcpwm :SOC_PARLIO_SUPPORTED: parlio :SOC_PCNT_SUPPORTED: pcnt + :SOC_PPA_SUPPORTED: ppa :SOC_RMT_SUPPORTED: rmt :SOC_SDMMC_HOST_SUPPORTED or SOC_SDIO_SLAVE_SUPPORTED: sd_pullup_requirements :SOC_SDMMC_HOST_SUPPORTED: sdmmc_host diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst new file mode 100644 index 00000000000..80c3ffb369d --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -0,0 +1 @@ +.. include:: ../../../en/api-reference/peripherals/ppa.rst From 0d94b1cd89e9ea13aa5d2561f13ffba249307697 Mon Sep 17 00:00:00 2001 From: wanlei Date: Sun, 28 Apr 2024 16:18:14 +0800 Subject: [PATCH 147/548] fix(spi_master): fix sct mode descripter oob when data lager then 4092 bytes --- .../esp_driver_spi/src/gpspi/spi_master.c | 100 ++++++++++++------ .../master/main/test_spi_master_sct.c | 67 +++++++++++- 2 files changed, 131 insertions(+), 36 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_master.c b/components/esp_driver_spi/src/gpspi/spi_master.c index ca791e25c53..0cc45980621 100644 --- a/components/esp_driver_spi/src/gpspi/spi_master.c +++ b/components/esp_driver_spi/src/gpspi/spi_master.c @@ -1458,6 +1458,40 @@ esp_err_t spi_bus_get_max_transaction_len(spi_host_device_t host_id, size_t *max /*----------------------------------------------------------- * Below functions should be in the same spinlock *-----------------------------------------------------------*/ +static SPI_MASTER_ISR_ATTR spi_dma_desc_t *s_sct_setup_desc_anywhere(spi_dma_desc_t *desc_root, spi_dma_desc_t *desc_start, uint32_t desc_num, const void *data, int len, bool is_rx) +{ + while (len) { + int dmachunklen = len; + if (dmachunklen > LLDESC_MAX_NUM_PER_DESC) { + dmachunklen = LLDESC_MAX_NUM_PER_DESC; + } + if (is_rx) { + //Receive needs DMA length rounded to next 32-bit boundary + desc_start->dw0.size = (dmachunklen + 3) & (~3); + } else { + desc_start->dw0.size = dmachunklen; + desc_start->dw0.length = dmachunklen; + } + desc_start->buffer = (uint8_t *)data; + desc_start->dw0.suc_eof = 0; + desc_start->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + len -= dmachunklen; + data += dmachunklen; + if (len) { + desc_start->next = (desc_start == &desc_root[desc_num - 1]) ? desc_root : &desc_start[1]; + desc_start = desc_start->next; + } + } + // desc_start is now walk to the end of used desc + desc_start->dw0.suc_eof = 1; //Mark last DMA desc as end of stream. + desc_start->next = NULL; + return desc_start; +} + +static SPI_MASTER_ISR_ATTR int s_sct_desc_get_required_num(uint32_t bytes_len) +{ + return (bytes_len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC; +} /*------------------------- * TX *------------------------*/ @@ -1466,13 +1500,12 @@ static void SPI_MASTER_ISR_ATTR spi_hal_sct_tx_dma_desc_recycle(spi_sct_desc_ctx desc_ctx->tx_free_desc_num += recycle_num; } -static void s_sct_prepare_tx_seg(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head) +static void SPI_MASTER_ISR_ATTR s_sct_prepare_tx_seg(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head) { - HAL_ASSERT(desc_ctx->tx_free_desc_num >= 1 + lldesc_get_required_num(buf_len_bytes)); const spi_dma_ctx_t *dma_ctx = __containerof(desc_ctx, spi_host_t, sct_desc_pool)->dma_ctx; *trans_head = desc_ctx->cur_tx_seg_link; - spicommon_dma_desc_setup_link(desc_ctx->cur_tx_seg_link, conf_buffer, SOC_SPI_SCT_BUFFER_NUM_MAX * 4, false); + s_sct_setup_desc_anywhere(dma_ctx->dmadesc_tx, desc_ctx->cur_tx_seg_link, dma_ctx->dma_desc_num, conf_buffer, SOC_SPI_SCT_BUFFER_NUM_MAX * 4, false); spi_dma_desc_t *conf_buffer_link = desc_ctx->cur_tx_seg_link; desc_ctx->tx_free_desc_num -= 1; @@ -1484,37 +1517,36 @@ static void s_sct_prepare_tx_seg(spi_sct_desc_ctx_t *desc_ctx, const uint32_t co } if (send_buffer && buf_len_bytes) { - spicommon_dma_desc_setup_link(desc_ctx->cur_tx_seg_link, send_buffer, buf_len_bytes, false); + desc_ctx->tx_seg_link_tail = s_sct_setup_desc_anywhere(dma_ctx->dmadesc_tx, desc_ctx->cur_tx_seg_link, dma_ctx->dma_desc_num, send_buffer, buf_len_bytes, false); conf_buffer_link->next = desc_ctx->cur_tx_seg_link; - for (int i = 0; i < lldesc_get_required_num(buf_len_bytes); i++) { - desc_ctx->tx_seg_link_tail = desc_ctx->cur_tx_seg_link; - desc_ctx->cur_tx_seg_link++; - if (desc_ctx->cur_tx_seg_link == dma_ctx->dmadesc_tx + dma_ctx->dma_desc_num) { - //As there is enough space, so we simply point this to the pool head - desc_ctx->cur_tx_seg_link = dma_ctx->dmadesc_tx; - } + desc_ctx->cur_tx_seg_link = desc_ctx->tx_seg_link_tail + 1; + if (desc_ctx->cur_tx_seg_link == dma_ctx->dmadesc_tx + dma_ctx->dma_desc_num) { + //As there is enough space, so we simply point this to the pool head + desc_ctx->cur_tx_seg_link = dma_ctx->dmadesc_tx; } - desc_ctx->tx_free_desc_num -= lldesc_get_required_num(buf_len_bytes); + desc_ctx->tx_free_desc_num -= s_sct_desc_get_required_num(buf_len_bytes); } } -static esp_err_t spi_hal_sct_new_tx_dma_desc_head(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head, uint32_t *used_desc_num) +static esp_err_t SPI_MASTER_ISR_ATTR spi_hal_sct_new_tx_dma_desc_head(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head, uint32_t *used_desc_num) { //1 desc for the conf_buffer, other for data. - if (desc_ctx->tx_free_desc_num < 1 + lldesc_get_required_num(buf_len_bytes)) { + int desc_need = 1 + s_sct_desc_get_required_num(buf_len_bytes); + if (desc_ctx->tx_free_desc_num < desc_need) { return ESP_ERR_NO_MEM; } s_sct_prepare_tx_seg(desc_ctx, conf_buffer, send_buffer, buf_len_bytes, trans_head); - *used_desc_num = 1 + lldesc_get_required_num(buf_len_bytes); + *used_desc_num = desc_need; return ESP_OK; } -static esp_err_t spi_hal_sct_link_tx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, uint32_t *used_desc_num) +static esp_err_t SPI_MASTER_ISR_ATTR spi_hal_sct_link_tx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, const uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX], const void *send_buffer, uint32_t buf_len_bytes, uint32_t *used_desc_num) { //1 desc for the conf_buffer, other for data. - if (desc_ctx->tx_free_desc_num < 1 + lldesc_get_required_num(buf_len_bytes)) { + int desc_need = 1 + s_sct_desc_get_required_num(buf_len_bytes); + if (desc_ctx->tx_free_desc_num < desc_need) { return ESP_ERR_NO_MEM; } @@ -1525,7 +1557,7 @@ static esp_err_t spi_hal_sct_link_tx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, spi_dma_desc_t *internal_head = NULL; s_sct_prepare_tx_seg(desc_ctx, conf_buffer, send_buffer, buf_len_bytes, &internal_head); - *used_desc_num += 1 + lldesc_get_required_num(buf_len_bytes); + *used_desc_num += desc_need; return ESP_OK; } @@ -1538,40 +1570,38 @@ static void SPI_MASTER_ISR_ATTR spi_hal_sct_rx_dma_desc_recycle(spi_sct_desc_ctx desc_ctx->rx_free_desc_num += recycle_num; } -static void s_sct_prepare_rx_seg(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head) +static void SPI_MASTER_ISR_ATTR s_sct_prepare_rx_seg(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head) { - HAL_ASSERT(desc_ctx->rx_free_desc_num >= lldesc_get_required_num(buf_len_bytes)); const spi_dma_ctx_t *dma_ctx = __containerof(desc_ctx, spi_host_t, sct_desc_pool)->dma_ctx; *trans_head = desc_ctx->cur_rx_seg_link; - spicommon_dma_desc_setup_link(desc_ctx->cur_rx_seg_link, recv_buffer, buf_len_bytes, true); - for (int i = 0; i < lldesc_get_required_num(buf_len_bytes); i++) { - desc_ctx->rx_seg_link_tail = desc_ctx->cur_rx_seg_link; - desc_ctx->cur_rx_seg_link++; - if (desc_ctx->cur_rx_seg_link == dma_ctx->dmadesc_rx + dma_ctx->dma_desc_num) { - //As there is enough space, so we simply point this to the pool head - desc_ctx->cur_rx_seg_link = dma_ctx->dmadesc_rx; - } + desc_ctx->rx_seg_link_tail = s_sct_setup_desc_anywhere(dma_ctx->dmadesc_rx, desc_ctx->cur_rx_seg_link, dma_ctx->dma_desc_num, recv_buffer, buf_len_bytes, true); + desc_ctx->cur_rx_seg_link = desc_ctx->rx_seg_link_tail + 1; + if (desc_ctx->cur_rx_seg_link == dma_ctx->dmadesc_rx + dma_ctx->dma_desc_num) { + //As there is enough space, so we simply point this to the pool head + desc_ctx->cur_rx_seg_link = dma_ctx->dmadesc_rx; } - desc_ctx->rx_free_desc_num -= lldesc_get_required_num(buf_len_bytes); + desc_ctx->rx_free_desc_num -= s_sct_desc_get_required_num(buf_len_bytes); } -static esp_err_t spi_hal_sct_new_rx_dma_desc_head(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head, uint32_t *used_desc_num) +static esp_err_t SPI_MASTER_ISR_ATTR spi_hal_sct_new_rx_dma_desc_head(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, spi_dma_desc_t **trans_head, uint32_t *used_desc_num) { - if (desc_ctx->rx_free_desc_num < lldesc_get_required_num(buf_len_bytes)) { + int desc_need = s_sct_desc_get_required_num(buf_len_bytes); + if (desc_ctx->rx_free_desc_num < desc_need) { return ESP_ERR_NO_MEM; } s_sct_prepare_rx_seg(desc_ctx, recv_buffer, buf_len_bytes, trans_head); - *used_desc_num = lldesc_get_required_num(buf_len_bytes); + *used_desc_num = desc_need; return ESP_OK; } -static esp_err_t spi_hal_sct_link_rx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, uint32_t *used_desc_num) +static esp_err_t SPI_MASTER_ISR_ATTR spi_hal_sct_link_rx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, const void *recv_buffer, uint32_t buf_len_bytes, uint32_t *used_desc_num) { - if (desc_ctx->rx_free_desc_num < lldesc_get_required_num(buf_len_bytes)) { + int desc_need = s_sct_desc_get_required_num(buf_len_bytes); + if (desc_ctx->rx_free_desc_num < desc_need) { return ESP_ERR_NO_MEM; } @@ -1582,7 +1612,7 @@ static esp_err_t spi_hal_sct_link_rx_seg_dma_desc(spi_sct_desc_ctx_t *desc_ctx, spi_dma_desc_t *internal_head = NULL; s_sct_prepare_rx_seg(desc_ctx, recv_buffer, buf_len_bytes, &internal_head); - *used_desc_num += lldesc_get_required_num(buf_len_bytes); + *used_desc_num += desc_need; return ESP_OK; } diff --git a/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c b/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c index 527ee76cad1..2efb4184d91 100644 --- a/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c +++ b/components/esp_driver_spi/test_apps/master/main/test_spi_master_sct.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -226,4 +226,69 @@ static void hd_slave(void) TEST_CASE_MULTIPLE_DEVICES("SPI_Master_SCT_HD_Functional", "[spi_ms]", hd_master, hd_slave); +#define SCT_LONG_TRANS_SEG_LEN 10000 //anything lager than 4092 +TEST_CASE("spi_master: test_sct_dma_desc_oob_on_tail", "[spi]") +{ + spi_device_handle_t handle; + + spi_bus_config_t buscfg = SPI_BUS_TEST_DEFAULT_CONFIG(); + buscfg.max_transfer_sz = 4092 * 8; + + spi_device_interface_config_t devcfg = SPI_DEVICE_TEST_DEFAULT_CONFIG(); + devcfg.clock_speed_hz = 100 * 1000; //low speed ensure cpu faster then HW + devcfg.flags = SPI_DEVICE_HALFDUPLEX; + + TEST_ESP_OK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO)); + TEST_ESP_OK(spi_bus_add_device(SPI2_HOST, &devcfg, &handle)); + printf("master init OK\n"); + uint8_t *master_tx_buf = heap_caps_calloc(1, SCT_LONG_TRANS_SEG_LEN, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + + //---------------------Master TX---------------------------// + spi_multi_transaction_t tx_seg_trans_cmd[1] = { //uing 1 dma desc, test trans without data phases + { + .base = { + .cmd = 0x7, + } + }, + }; + spi_multi_transaction_t tx_seg_trans_dummy[1] = { //using 4 dma desc + { + .base = { + .length = SCT_LONG_TRANS_SEG_LEN * 8, + .tx_buffer = master_tx_buf, + }, + }, + }; + spi_multi_transaction_t tx_seg_trans_data[1] = { //using 4 dma desc, should using (last 3 + first 1) of desc pool + { + .base = { + .cmd = 0x3, + .length = SCT_LONG_TRANS_SEG_LEN * 8, + .tx_buffer = master_tx_buf, + }, + .dummy_bits = 8, + .seg_trans_flags = SPI_MULTI_TRANS_DUMMY_LEN_UPDATED, + }, + }; + + spi_multi_transaction_t *ret_seg_trans; + printf("enabling sct multi trans mode ...\n"); + TEST_ESP_OK(spi_bus_multi_trans_mode_enable(handle, true)); + printf("start sct transaction\n"); + TEST_ESP_OK(spi_device_queue_multi_trans(handle, tx_seg_trans_cmd, 1, portMAX_DELAY)); + TEST_ESP_OK(spi_device_queue_multi_trans(handle, tx_seg_trans_dummy, 1, portMAX_DELAY)); + vTaskDelay(10 / portTICK_PERIOD_MS); //ensure `tx_seg_trans_cmd` had finish + TEST_ESP_OK(spi_device_queue_multi_trans(handle, tx_seg_trans_data, 1, portMAX_DELAY)); + + printf("waiting result ...\n"); + TEST_ESP_OK(spi_device_get_multi_trans_result(handle, &ret_seg_trans, portMAX_DELAY)); + TEST_ESP_OK(spi_device_get_multi_trans_result(handle, &ret_seg_trans, portMAX_DELAY)); + TEST_ESP_OK(spi_device_get_multi_trans_result(handle, &ret_seg_trans, portMAX_DELAY)); + TEST_ESP_OK(spi_bus_multi_trans_mode_enable(handle, false)); + + free(master_tx_buf); + TEST_ESP_OK(spi_bus_remove_device(handle)); + TEST_ESP_OK(spi_bus_free(SPI2_HOST)); +} + #endif //#if (SOC_SPI_SUPPORT_SLAVE_HD_VER2 && SOC_SPI_SCT_SUPPORTED) From 91cedfe89d3268128ece567f62bbeb44f2785a6f Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Thu, 16 May 2024 18:29:39 +0800 Subject: [PATCH 148/548] feat(brownout): Add brownout detector support on esp32p4 --- components/esp_system/port/brownout.c | 4 +- .../port/soc/esp32p4/Kconfig.system | 45 ++++++ .../hal/esp32c6/include/hal/brownout_ll.h | 12 ++ .../hal/esp32h2/include/hal/brownout_ll.h | 14 +- .../hal/esp32p4/include/hal/brownout_ll.h | 128 ++++++++++++++++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32p4/include/soc/regi2c_brownout.h | 9 +- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- 8 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 components/hal/esp32p4/include/hal/brownout_ll.h diff --git a/components/esp_system/port/brownout.c b/components/esp_system/port/brownout.c index 271384ac64d..cce5f65deff 100644 --- a/components/esp_system/port/brownout.c +++ b/components/esp_system/port/brownout.c @@ -76,7 +76,9 @@ void esp_brownout_init(void) #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 // TODO: [ESP32C5] IDF-8647, [ESP32C61] IDF-9254 // TODO IDF-6606: LP_RTC_TIMER interrupt source is shared by lp_timer and brownout detector, but lp_timer interrupt // is not used now. An interrupt allocator is needed when lp_timer intr gets supported. - esp_intr_alloc(ETS_LP_RTC_TIMER_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_brownout_isr_handler, NULL, NULL); + esp_intr_alloc_intrstatus(ETS_LP_RTC_TIMER_INTR_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED, (uint32_t)brownout_ll_intr_get_status_reg(), BROWNOUT_DETECTOR_LL_INTERRUPT_MASK, &rtc_brownout_isr_handler, NULL, NULL); +#elif CONFIG_IDF_TARGET_ESP32P4 + esp_intr_alloc(ETS_LP_ANAPERI_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_brownout_isr_handler, NULL, NULL); #else rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M, RTC_INTR_FLAG_IRAM); #endif diff --git a/components/esp_system/port/soc/esp32p4/Kconfig.system b/components/esp_system/port/soc/esp32p4/Kconfig.system index e69de29bb2d..5ffec7fe769 100644 --- a/components/esp_system/port/soc/esp32p4/Kconfig.system +++ b/components/esp_system/port/soc/esp32p4/Kconfig.system @@ -0,0 +1,45 @@ +menu "Brownout Detector" + config ESP_BROWNOUT_DET + bool "Hardware brownout detect & reset" + depends on !IDF_ENV_FPGA + default y + help + The ESP32-P4 has a built-in brownout detector which can detect if the voltage is lower than + a specific value. If this happens, it will reset the chip in order to prevent unintended + behaviour. + + choice ESP_BROWNOUT_DET_LVL_SEL + prompt "Brownout voltage level" + depends on ESP_BROWNOUT_DET + default ESP_BROWNOUT_DET_LVL_SEL_7 + help + The brownout detector will reset the chip when the supply voltage is approximately + below this level. Note that there may be some variation of brownout voltage level + between each chip. + + #The voltage levels here are estimates, more work needs to be done to figure out the exact voltages + #of the brownout threshold levels. + config ESP_BROWNOUT_DET_LVL_SEL_7 + bool "2.51V" + config ESP_BROWNOUT_DET_LVL_SEL_6 + bool "2.64V" + config ESP_BROWNOUT_DET_LVL_SEL_5 + bool "2.76V" + config ESP_BROWNOUT_DET_LVL_SEL_4 + bool "2.92V" + config ESP_BROWNOUT_DET_LVL_SEL_3 + bool "3.10V" + config ESP_BROWNOUT_DET_LVL_SEL_2 + bool "3.27V" + endchoice + + config ESP_BROWNOUT_DET_LVL + int + default 2 if ESP_BROWNOUT_DET_LVL_SEL_2 + default 3 if ESP_BROWNOUT_DET_LVL_SEL_3 + default 4 if ESP_BROWNOUT_DET_LVL_SEL_4 + default 5 if ESP_BROWNOUT_DET_LVL_SEL_5 + default 6 if ESP_BROWNOUT_DET_LVL_SEL_6 + default 7 if ESP_BROWNOUT_DET_LVL_SEL_7 + +endmenu diff --git a/components/hal/esp32c6/include/hal/brownout_ll.h b/components/hal/esp32c6/include/hal/brownout_ll.h index 032ada35ac2..d5d46b33389 100644 --- a/components/hal/esp32c6/include/hal/brownout_ll.h +++ b/components/hal/esp32c6/include/hal/brownout_ll.h @@ -20,6 +20,8 @@ extern "C" { #endif +#define BROWNOUT_DETECTOR_LL_INTERRUPT_MASK (BIT(31)) + /** * @brief power down the flash when a brown out happens. * @@ -123,6 +125,16 @@ static inline void brownout_ll_clear_count(void) LP_ANA_PERI.bod_mode0_cntl.bod_mode0_cnt_clr = 0; } +/** + * @brief Get interrupt status register address + * + * @return Register address + */ +static inline volatile void *brownout_ll_intr_get_status_reg(void) +{ + return &LP_ANA_PERI.int_st; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32h2/include/hal/brownout_ll.h b/components/hal/esp32h2/include/hal/brownout_ll.h index f0b3d63263e..5ee9dcb73e7 100644 --- a/components/hal/esp32h2/include/hal/brownout_ll.h +++ b/components/hal/esp32h2/include/hal/brownout_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,8 @@ extern "C" { #endif +#define BROWNOUT_DETECTOR_LL_INTERRUPT_MASK (BIT(31)) + /** * @brief power down the flash when a brown out happens. * @@ -124,6 +126,16 @@ static inline void brownout_ll_clear_count(void) LP_ANA_PERI.bod_mode0_cntl.bod_mode0_cnt_clr = 0; } +/** + * @brief Get interrupt status register address + * + * @return Register address + */ +static inline volatile void *brownout_ll_intr_get_status_reg(void) +{ + return &LP_ANA_PERI.int_st; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/brownout_ll.h b/components/hal/esp32p4/include/hal/brownout_ll.h new file mode 100644 index 00000000000..e4b338d8a68 --- /dev/null +++ b/components/hal/esp32p4/include/hal/brownout_ll.h @@ -0,0 +1,128 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The ll is not public api, don't use in application code. + * See readme.md in hal/readme.md + ******************************************************************************/ + +#pragma once +#include +#include "soc/lp_analog_peri_struct.h" +#include "hal/regi2c_ctrl.h" +#include "soc/regi2c_brownout.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief power down the flash when a brown out happens. + * + * @param enable true: power down flash. false: not power down + */ +static inline void brownout_ll_enable_flash_power_down(bool enable) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_close_flash_ena = enable; +} + +/** + * @brief power down the RF circuits when a brown out happens + * + * @param enable true: power down. false: not power done. + */ +static inline void brownout_ll_enable_rf_power_down(bool enable) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_pd_rf_ena = enable; +} + +/** + * @brief Enable this to reset brown out + * + * @note: If brown out interrupt is used, this should be disabled. + * + * @param reset_ena true: enable reset. false: disable reset. + * @param reset_wait brown out reset wait cycles + * @param select 1: chip reset, 0: system reset + */ +static inline void brownout_ll_reset_config(bool reset_ena, uint32_t reset_wait, uint8_t select) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_reset_wait = reset_wait; + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_reset_ena = reset_ena; + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_reset_sel = select; +} +/** + * @brief Set brown out threshold + * + * @param threshold brownout threshold + */ +static inline void brownout_ll_set_threshold(uint8_t threshold) +{ + REGI2C_WRITE_MASK(I2C_BOD, I2C_BOD_THRESHOLD, threshold); +} + +/** + * @brief Set this bit to enable the brown out detection + * + * @param bod_enable true: enable, false: disable + */ +static inline void brownout_ll_bod_enable(bool bod_enable) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_intr_ena = bod_enable; +} + +/** + * @brief configure the waiting cycles before sending an interrupt + * + * @param cycle waiting cycles. + */ +static inline void brownout_ll_set_intr_wait_cycles(uint8_t cycle) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_intr_wait = cycle; +} + +/** + * @brief Enable brown out interrupt + * + * @param enable true: enable, false: disable + */ +static inline void brownout_ll_intr_enable(bool enable) +{ + LP_ANA_PERI.int_ena.bod_mode0_int_ena = enable; +} + +/** + * @brief Enable brownout hardware reset + * + * @param enable + */ +static inline void brownout_ll_ana_reset_enable(bool enable) +{ + LP_ANA_PERI.bod_mode1_cntl.bod_mode1_reset_ena = enable; +} + +/** + * @brief Clear interrupt bits. + */ +__attribute__((always_inline)) +static inline void brownout_ll_intr_clear(void) +{ + LP_ANA_PERI.int_clr.bod_mode0_int_clr = 1; +} + +/** + * @brief Clear BOD internal count. + */ +static inline void brownout_ll_clear_count(void) +{ + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_cnt_clr = 1; + LP_ANA_PERI.bod_mode0_cntl.bod_mode0_cnt_clr = 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..bf34d16f791 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -191,6 +191,10 @@ config SOC_SECURE_BOOT_SUPPORTED bool default y +config SOC_BOD_SUPPORTED + bool + default y + config SOC_PMU_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/regi2c_brownout.h b/components/soc/esp32p4/include/soc/regi2c_brownout.h index 24377f93566..0504a137056 100644 --- a/components/soc/esp32p4/include/soc/regi2c_brownout.h +++ b/components/soc/esp32p4/include/soc/regi2c_brownout.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,3 +13,10 @@ * This file lists register fields of the brownout detector, located on an internal configuration * bus. These definitions are used via macros defined in regi2c_ctrl.h. */ + +#define I2C_BOD 0x61 +#define I2C_BOD_HOSTID 0 + +#define I2C_BOD_THRESHOLD 0x5 +#define I2C_BOD_THRESHOLD_MSB 2 +#define I2C_BOD_THRESHOLD_LSB 0 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..e08d88c4165 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -67,7 +67,7 @@ #define SOC_KEY_MANAGER_SUPPORTED 1 #define SOC_FLASH_ENC_SUPPORTED 1 #define SOC_SECURE_BOOT_SUPPORTED 1 -// #define SOC_BOD_SUPPORTED 1 //TODO: IDF-7519 +#define SOC_BOD_SUPPORTED 1 // #define SOC_APM_SUPPORTED 1 //TODO: IDF-7542 #define SOC_PMU_SUPPORTED 1 #define SOC_DCDC_SUPPORTED 1 From 5a7a9c06386cf8cffb35f8e47378463d1c7bfba4 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 20 May 2024 20:22:19 +0800 Subject: [PATCH 149/548] test(esp_intr_dump): Fix the esp intr dump expected output because the changes happened in brownout --- .../system/esp_intr_dump/expected_output/esp32c6.txt | 4 ++-- .../system/esp_intr_dump/expected_output/esp32h2.txt | 4 ++-- .../system/esp_intr_dump/expected_output/esp32p4.txt | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/test_apps/system/esp_intr_dump/expected_output/esp32c6.txt b/tools/test_apps/system/esp_intr_dump/expected_output/esp32c6.txt index b72d4796328..2bb11d11c41 100644 --- a/tools/test_apps/system/esp_intr_dump/expected_output/esp32c6.txt +++ b/tools/test_apps/system/esp_intr_dump/expected_output/esp32c6.txt @@ -2,7 +2,7 @@ CPU 0 interrupt status: Int Level Type Status 0 * * Reserved 1 * * Reserved - 2 1 Level Used: LP_RTC_TIMER + 2 1 Level Shared: LP_RTC_TIMER 3 * * Reserved 4 * * Reserved 5 1 Level Used: CPU_FROM_CPU_0 @@ -33,4 +33,4 @@ CPU 0 interrupt status: 30 * * Free 31 * * Free Interrupts available for general use: 18 -Shared interrupts: 0 +Shared interrupts: 1 diff --git a/tools/test_apps/system/esp_intr_dump/expected_output/esp32h2.txt b/tools/test_apps/system/esp_intr_dump/expected_output/esp32h2.txt index e46e94fcc55..3af2a0d3d95 100644 --- a/tools/test_apps/system/esp_intr_dump/expected_output/esp32h2.txt +++ b/tools/test_apps/system/esp_intr_dump/expected_output/esp32h2.txt @@ -2,7 +2,7 @@ CPU 0 interrupt status: Int Level Type Status 0 * * Reserved 1 * * Reserved - 2 1 Level Used: LP_RTC_TIMER + 2 1 Level Shared: LP_RTC_TIMER 3 * * Reserved 4 * * Reserved 5 1 Level Used: CPUFROM_CPU_0 @@ -33,4 +33,4 @@ CPU 0 interrupt status: 30 * * Free 31 * * Free Interrupts available for general use: 18 -Shared interrupts: 0 +Shared interrupts: 1 diff --git a/tools/test_apps/system/esp_intr_dump/expected_output/esp32p4.txt b/tools/test_apps/system/esp_intr_dump/expected_output/esp32p4.txt index 0e92e63a9ab..653010b71ef 100644 --- a/tools/test_apps/system/esp_intr_dump/expected_output/esp32p4.txt +++ b/tools/test_apps/system/esp_intr_dump/expected_output/esp32p4.txt @@ -1,10 +1,10 @@ CPU 0 interrupt status: Int Level Type Status - 0 1 Level Used: CPU_INT_FROM_CPU_0 - 1 1 Level Used: SYSTIMER_TARGET0 - 2 1 Level Used: TG0_WDT_LEVEL - 3 1 Level Used: UART0 - 4 * * Free + 0 1 Level Used: LP_ANAPERI + 1 1 Level Used: CPU_INT_FROM_CPU_0 + 2 1 Level Used: SYSTIMER_TARGET0 + 3 1 Level Used: TG0_WDT_LEVEL + 4 1 Level Used: UART0 5 * * Free 6 * * Reserved 7 * * Free @@ -66,4 +66,4 @@ CPU 1 interrupt status: 29 * * Free 30 * * Free 31 * * Free -Interrupts available for general use: 48 +Interrupts available for general use: 47 From dcc7cf93796916f3f81c49c66a5372ea648f25a9 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 23 Jan 2024 19:39:51 +0800 Subject: [PATCH 150/548] feat(parlio_rx): support parlio rx on p4 --- .../esp_driver_parlio/src/parlio_common.c | 2 + .../esp_driver_parlio/src/parlio_private.h | 18 +- components/esp_driver_parlio/src/parlio_rx.c | 172 +++++++++++++----- components/esp_driver_parlio/src/parlio_tx.c | 2 +- .../test_apps/.build-test-rules.yml | 4 +- .../test_apps/parlio/README.md | 4 +- .../test_apps/parlio/main/test_board.h | 22 ++- .../test_apps/parlio/main/test_parlio_rx.c | 42 ++++- .../test_apps/parlio/pytest_parlio_unity.py | 2 - .../hal/esp32p4/include/hal/parlio_ll.h | 11 +- components/hal/include/hal/dma_types.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 + .../soc/esp32p4/include/soc/clk_tree_defs.h | 2 +- components/soc/esp32p4/include/soc/soc_caps.h | 3 +- examples/peripherals/.build-test-rules.yml | 6 +- .../parlio/parlio_rx/logic_analyzer/README.md | 4 +- .../components/esp_probe/esp_probe_private.h | 11 +- .../esp_probe/hw_impl/esp_probe_impl_parlio.c | 11 +- .../parlio_tx/simple_rgb_led_matrix/README.md | 4 +- 19 files changed, 238 insertions(+), 91 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_common.c b/components/esp_driver_parlio/src/parlio_common.c index f8358d90c8c..48518ddb0cc 100644 --- a/components/esp_driver_parlio/src/parlio_common.c +++ b/components/esp_driver_parlio/src/parlio_common.c @@ -48,6 +48,8 @@ parlio_group_t *parlio_acquire_group_handle(int group_id) } // hal layer initialize parlio_hal_init(&group->hal); + group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + group->dma_align = group->dma_align < 4 ? 4 : group->dma_align; } } else { // group already install group = s_platform.groups[group_id]; diff --git a/components/esp_driver_parlio/src/parlio_private.h b/components/esp_driver_parlio/src/parlio_private.h index 52ab3bec1c4..d728359b09e 100644 --- a/components/esp_driver_parlio/src/parlio_private.h +++ b/components/esp_driver_parlio/src/parlio_private.h @@ -30,6 +30,7 @@ #else #define PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif +#define PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) #if SOC_PARLIO_TX_RX_SHARE_INTERRUPT #define PARLIO_INTR_ALLOC_FLAG_SHARED ESP_INTR_FLAG_SHARED @@ -57,6 +58,12 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t; #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED +#else +#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED +#endif + #ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR /* The descriptor address can be mapped by a fixed offset */ #define PARLIO_GET_NON_CACHED_DESC_ADDR(desc) (desc ? (parlio_dma_desc_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(desc)) : NULL) @@ -107,11 +114,12 @@ typedef enum { typedef struct parlio_unit_t *parlio_unit_base_handle_t; typedef struct parlio_group_t { - int group_id; // group ID, index from 0 - portMUX_TYPE spinlock; // to protect per-group register level concurrent access - parlio_hal_context_t hal; // hal layer context - parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles - parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles + int group_id; // group ID, index from 0 + portMUX_TYPE spinlock; // to protect per-group register level concurrent access + parlio_hal_context_t hal; // hal layer context + uint32_t dma_align; // DMA buffer alignment + parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles + parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles } parlio_group_t; /** diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 6ea8fcd0384..a3390947cad 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,7 +33,9 @@ #include "esp_memory_utils.h" #include "esp_clk_tree.h" #include "esp_attr.h" +#include "esp_dma_utils.h" #include "esp_private/gdma.h" +#include "esp_cache.h" static const char *TAG = "parlio-rx"; @@ -81,8 +83,9 @@ typedef struct parlio_rx_unit_t { gdma_channel_handle_t dma_chan; /*!< DMA channel */ size_t max_recv_size; /*!< Maximum receive size for a normal transaction */ size_t desc_num; /*!< DMA descriptor number */ - dma_descriptor_t *dma_descs; /*!< DMA descriptor array pointer */ - dma_descriptor_t *curr_desc; /*!< The pointer of the current descriptor */ + size_t desc_size; /*!< DMA descriptors total size */ + parlio_dma_desc_t **dma_descs; /*!< DMA descriptor array pointer */ + parlio_dma_desc_t *curr_desc; /*!< The pointer of the current descriptor */ void *usr_recv_buf; /*!< The pointe to the user's receiving buffer */ /* Infinite transaction specific */ void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */ @@ -125,19 +128,21 @@ typedef struct parlio_rx_delimiter_t { } flags; } parlio_rx_delimiter_t; +#define PRALIO_RX_MOUNT_SIZE_CALC(total_size, div, align) ((((total_size) / (align)) / (div)) * (align)) + static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans) { - dma_descriptor_t *p_desc = rx_unit->dma_descs; + parlio_dma_desc_t **p_desc = rx_unit->dma_descs; /* Update the current transaction to the next one, and declare the delimiter is under using of the rx unit */ memcpy(&rx_unit->curr_trans, trans, sizeof(parlio_rx_transaction_t)); portENTER_CRITICAL_SAFE(&s_rx_spinlock); trans->delimiter->under_using = true; portEXIT_CRITICAL_SAFE(&s_rx_spinlock); - uint32_t desc_num = trans->size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; - uint32_t remain_num = trans->size % DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; + uint32_t desc_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; + uint32_t remain_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; /* If there are still data remained, need one more descriptor */ desc_num += remain_num ? 1 : 0; if (trans->flags.infinite && desc_num < 2) { @@ -146,30 +151,40 @@ static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_ } size_t mount_size = 0; size_t offset = 0; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + uint32_t alignment = rx_unit->base.group->dma_align; +#else + uint32_t alignment = 4; +#endif /* Loop the descriptors to assign the data */ for (int i = 0; i < desc_num; i++) { size_t rest_size = trans->size - offset; - if (rest_size >= 2 * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) { - mount_size = trans->size / desc_num; - } else if (rest_size <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) { - mount_size = (desc_num == 2) && (i == 0) ? rest_size / 2 : rest_size; + + if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { + mount_size = PRALIO_RX_MOUNT_SIZE_CALC(trans->size, desc_num, alignment); + } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { + mount_size = (desc_num == 2) && (i == 0) ? PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size; } else { - mount_size = rest_size / 2; + mount_size = PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment); } - p_desc[i].buffer = (void *)((uint8_t *)trans->payload + offset); - p_desc[i].dw0.size = mount_size; - p_desc[i].dw0.length = mount_size; - p_desc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + p_desc[i]->buffer = (void *)((uint8_t *)trans->payload + offset); + p_desc[i]->dw0.size = mount_size; + p_desc[i]->dw0.length = mount_size; + p_desc[i]->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; // Link the descriptor - if (i > 0) { - p_desc[i - 1].next = &p_desc[i]; + if (i < desc_num - 1) { + p_desc[i]->next = p_desc[i + 1]; + } else { + /* For infinite transaction, link the descriptor as a ring */ + p_desc[i]->next = trans->flags.infinite ? p_desc[0] : NULL; } offset += mount_size; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(p_desc[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif } - /* For infinite transaction, link the descriptor as a ring */ - p_desc[desc_num - 1].next = trans->flags.infinite ? &p_desc[0] : NULL; /* Reset the current DMA node */ - rx_unit->curr_desc = p_desc; + rx_unit->curr_desc = p_desc[0]; return offset; } @@ -251,6 +266,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons gpio_conf.mode = config->flags.io_loop_back ? GPIO_MODE_INPUT_OUTPUT : GPIO_MODE_INPUT; gpio_conf.pin_bit_mask = BIT64(config->clk_in_gpio_num); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk in GPIO failed"); + } else { + gpio_ll_input_enable(&GPIO, config->clk_in_gpio_num); } esp_rom_gpio_connect_in_signal(config->clk_in_gpio_num, parlio_periph_signals.groups[group_id].rx_units[unit_id].clk_in_sig, false); @@ -275,6 +292,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons if (!config->flags.io_no_init) { gpio_conf.pin_bit_mask = BIT64(config->valid_gpio_num); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed"); + } else { + gpio_ll_input_enable(&GPIO, config->valid_gpio_num); } /* Not connect the signal here, the signal is lazy connected until the delimiter takes effect */ } @@ -286,7 +305,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons if (!config->flags.io_no_init) { gpio_conf.pin_bit_mask = BIT64(config->data_gpio_nums[i]); ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed"); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->data_gpio_nums[i]], PIN_FUNC_GPIO); + } else { + gpio_ll_input_enable(&GPIO, config->data_gpio_nums[i]); } esp_rom_gpio_connect_in_signal(config->data_gpio_nums[i], parlio_periph_signals.groups[group_id].rx_units[unit_id].data_sigs[i], false); @@ -330,18 +350,22 @@ static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma /* The current transaction finished, try to get the next transaction from the transaction queue */ if (xQueueReceiveFromISR(rx_unit->trans_que, &next_trans, &high_task_woken) == pdTRUE) { if (rx_unit->cfg.flags.free_clk) { - parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); + } } /* If the delimiter of the next transaction is not same as the current one, need to re-config the hardware */ - if (next_trans.delimiter != rx_unit->curr_trans.delimiter) { + if ((next_trans.delimiter != NULL) && (next_trans.delimiter != rx_unit->curr_trans.delimiter)) { s_parlio_set_delimiter_config(rx_unit, next_trans.delimiter); } /* Mount the new transaction buffer and start the new transaction */ s_parlio_mount_transaction_buffer(rx_unit, &next_trans); - gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs); + gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs[0]); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(rx_unit->base.group->hal.regs, true); - parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); + } } } else if (rx_unit->curr_trans.delimiter) { // Add condition in case the curr_trans has been cleared in the last timeout isr /* No more transaction pending to receive, clear the current transaction */ @@ -368,7 +392,15 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle } /* Get the finished descriptor from the current descriptor */ - dma_descriptor_t *finished_desc = rx_unit->curr_desc; + parlio_dma_desc_t *finished_desc = rx_unit->curr_desc; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_err_t ret = ESP_OK; + ret |= esp_cache_msync((void *)finished_desc, rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + ret |= esp_cache_msync((void *)(finished_desc->buffer), finished_desc->dw0.size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + if (ret != ESP_OK) { + ESP_EARLY_LOGW(TAG, "failed to sync dma buffer from memory to cache"); + } +#endif parlio_rx_event_data_t evt_data = { .delimiter = rx_unit->curr_trans.delimiter, .data = finished_desc->buffer, @@ -399,21 +431,41 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle static esp_err_t s_parlio_rx_create_dma_descriptors(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size) { ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param"); - + esp_err_t ret = ESP_OK; uint32_t desc_num = max_recv_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + 1; /* set at least 2 descriptors */ if (desc_num < 2) { - desc_num = 4; + desc_num = 2; } rx_unit->desc_num = desc_num; /* Allocated and link the descriptor nodes */ - rx_unit->dma_descs = (dma_descriptor_t *)heap_caps_calloc(desc_num, sizeof(dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); - ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptors"); + rx_unit->dma_descs = heap_caps_calloc(desc_num, sizeof(parlio_dma_desc_t *), MALLOC_CAP_DMA); + ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptor array"); + uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + size_t alignment = MAX(cache_line_size, PARLIO_DMA_DESC_ALIGNMENT); + rx_unit->desc_size = ALIGN_UP(sizeof(parlio_dma_desc_t), alignment); + for (int i = 0; i < desc_num; i++) { + rx_unit->dma_descs[i] = heap_caps_aligned_calloc(alignment, 1, rx_unit->desc_size, PARLIO_DMA_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(rx_unit->dma_descs[i], ESP_ERR_NO_MEM, err, TAG, "no memory for DMA descriptors"); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_cache_msync(rx_unit->dma_descs[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); +#endif + } rx_unit->max_recv_size = max_recv_size; - return ESP_OK; + return ret; +err: + for (int i = 0; i < desc_num; i++) { + if (rx_unit->dma_descs[i]) { + free(rx_unit->dma_descs[i]); + rx_unit->dma_descs[i] = NULL; + } + } + free(rx_unit->dma_descs); + rx_unit->dma_descs = NULL; + return ret; } static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) @@ -422,7 +474,7 @@ static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) gdma_channel_alloc_config_t dma_chan_config = { .direction = GDMA_CHANNEL_DIRECTION_RX, }; - ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed"); + ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed"); gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0)); /* Set GDMA strategy */ @@ -487,8 +539,10 @@ static esp_err_t s_parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, c #endif /* Set clock configuration */ - parlio_ll_rx_set_clock_source(hal->regs, clk_src); - parlio_ll_rx_set_clock_div(hal->regs, &clk_div); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_set_clock_source(hal->regs, clk_src); + parlio_ll_rx_set_clock_div(hal->regs, &clk_div); + } rx_unit->clk_src = clk_src; /* warning if precision lost due to division */ @@ -525,7 +579,14 @@ static esp_err_t s_parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit) } /* Free the DMA descriptors */ if (rx_unit->dma_descs) { + for (int i = 0; i < rx_unit->desc_num; i++) { + if (rx_unit->dma_descs[i]) { + free(rx_unit->dma_descs[i]); + rx_unit->dma_descs[i] = NULL; + } + } free(rx_unit->dma_descs); + rx_unit->dma_descs = NULL; } /* Free the internal DMA buffer */ if (rx_unit->dma_buf) { @@ -591,9 +652,13 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un /* Install DMA service */ ESP_GOTO_ON_ERROR(s_parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed"); /* Reset RX module */ - parlio_ll_rx_reset_clock(hal->regs); + PARLIO_RCC_ATOMIC() { + parlio_ll_rx_reset_clock(hal->regs); + } parlio_ll_rx_reset_fifo(hal->regs); - parlio_ll_rx_enable_clock(hal->regs, false); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(hal->regs, false); + } parlio_ll_rx_start(hal->regs, false); /* parlio_ll_clock_source_t and parlio_clock_source_t are binary compatible if the clock source is from internal */ ESP_GOTO_ON_ERROR(s_parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed"); @@ -651,7 +716,9 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu if (!rx_unit->cfg.flags.free_clk) { parlio_ll_rx_reset_fifo(hal->regs); parlio_ll_rx_start(hal->regs, true); - parlio_ll_rx_enable_clock(hal->regs, true); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(hal->regs, true); + } } /* Check if we need to start a pending transaction */ @@ -663,14 +730,18 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu // The semaphore always supposed to be taken successfully assert(xSemaphoreTake(rx_unit->trans_sem, 0) == pdTRUE); if (rx_unit->cfg.flags.free_clk) { - parlio_ll_rx_enable_clock(hal->regs, false); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(hal->regs, false); + } } s_parlio_set_delimiter_config(rx_unit, trans.delimiter); s_parlio_mount_transaction_buffer(rx_unit, &trans); gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(hal->regs, true); - parlio_ll_rx_enable_clock(hal->regs, true); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(hal->regs, true); + } } } err: @@ -691,7 +762,9 @@ esp_err_t parlio_rx_unit_disable(parlio_rx_unit_handle_t rx_unit) rx_unit->is_enabled = false; /* stop the RX engine */ gdma_stop(rx_unit->dma_chan); - parlio_ll_rx_enable_clock(hal->regs, false); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(hal->regs, false); + } parlio_ll_rx_start(hal->regs, false); if (rx_unit->curr_trans.delimiter) { portENTER_CRITICAL(&s_rx_spinlock); @@ -842,7 +915,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit portEXIT_CRITICAL_ISR(&s_rx_spinlock); if (is_stopped) { if (rx_unit->cfg.flags.free_clk) { - parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false); + } } if (trans->delimiter != rx_unit->curr_trans.delimiter) { s_parlio_set_delimiter_config(rx_unit, trans->delimiter); @@ -853,7 +928,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(rx_unit->base.group->hal.regs, true); - parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true); + } } } else { // Otherwise send to the queue /* Send the transaction to the queue */ @@ -871,8 +948,17 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified"); ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large"); + uint32_t alignment = rx_unit->base.group->dma_align; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + ESP_RETURN_ON_FALSE(payload_size % alignment == 0, ESP_ERR_INVALID_ARG, TAG, "The payload size should align with %"PRIu32, alignment); + if (recv_cfg->flags.partial_rx_en) { + ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment); + } +#endif #if CONFIG_GDMA_ISR_IRAM_SAFE ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); +#else + ESP_RETURN_ON_FALSE(recv_cfg->flags.indirect_mount || esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); #endif if (recv_cfg->delimiter->eof_data_len) { ESP_RETURN_ON_FALSE(payload_size >= recv_cfg->delimiter->eof_data_len, ESP_ERR_INVALID_ARG, @@ -895,7 +981,7 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) { ESP_RETURN_ON_FALSE(!rx_unit->dma_buf, ESP_ERR_INVALID_STATE, TAG, "infinite transaction is using the internal DMA buffer"); /* Allocate the internal DMA buffer to store the data temporary */ - rx_unit->dma_buf = heap_caps_calloc(1, payload_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + rx_unit->dma_buf = heap_caps_aligned_calloc(alignment, 1, payload_size, PARLIO_DMA_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, TAG, "No memory for the internal DMA buffer"); /* Use the internal DMA buffer so that the user buffer can always be available */ p_buffer = rx_unit->dma_buf; diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index c0384967545..20a0fdc4bca 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -405,7 +405,7 @@ static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const #if CONFIG_IDF_TARGET_ESP32P4 // Write back to cache to synchronize the cache before DMA start - esp_cache_msync(buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync((void *)buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif // CONFIG_IDF_TARGET_ESP32P4 } diff --git a/components/esp_driver_parlio/test_apps/.build-test-rules.yml b/components/esp_driver_parlio/test_apps/.build-test-rules.yml index bc30d2fe7ba..c2c576d51f4 100644 --- a/components/esp_driver_parlio/test_apps/.build-test-rules.yml +++ b/components/esp_driver_parlio/test_apps/.build-test-rules.yml @@ -4,8 +4,8 @@ components/esp_driver_parlio/test_apps/parlio: disable: - if: SOC_PARLIO_SUPPORTED != 1 disable_test: - - if: IDF_TARGET == "esp32p4" + - if: IDF_TARGET in ["esp32h2", "esp32p4"] temporary: true - reason: lack of runner + reason: IDF-9806 waiting for the fix of the bit shift issue after reset depends_components: - esp_driver_parlio diff --git a/components/esp_driver_parlio/test_apps/parlio/README.md b/components/esp_driver_parlio/test_apps/parlio/README.md index b450dc5ffac..7b822bdb0ef 100644 --- a/components/esp_driver_parlio/test_apps/parlio/README.md +++ b/components/esp_driver_parlio/test_apps/parlio/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h index 81c64cbc8c7..931cc957f7d 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_board.h +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_board.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ extern "C" { #define TEST_PARLIO_CALLBACK_ATTR #define TEST_PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif +#define TEST_PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) #if CONFIG_IDF_TARGET_ESP32C6 #define TEST_CLK_GPIO 10 @@ -42,15 +43,16 @@ extern "C" { #define TEST_DATA6_GPIO 8 #define TEST_DATA7_GPIO 9 #elif CONFIG_IDF_TARGET_ESP32P4 -#define TEST_CLK_GPIO 20 -#define TEST_DATA0_GPIO 21 -#define TEST_DATA1_GPIO 22 -#define TEST_DATA2_GPIO 34 -#define TEST_DATA3_GPIO 35 -#define TEST_DATA4_GPIO 48 -#define TEST_DATA5_GPIO 49 -#define TEST_DATA6_GPIO 10 -#define TEST_DATA7_GPIO 11 +#define TEST_CLK_GPIO 32 +#define TEST_VALID_GPIO 36 +#define TEST_DATA0_GPIO 20 +#define TEST_DATA1_GPIO 21 +#define TEST_DATA2_GPIO 22 +#define TEST_DATA3_GPIO 23 +#define TEST_DATA4_GPIO 45 +#define TEST_DATA5_GPIO 46 +#define TEST_DATA6_GPIO 47 +#define TEST_DATA7_GPIO 48 #else #error "Unsupported target" #endif diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index c9b38bde6af..4f4dd596a23 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,16 +17,26 @@ #include "driver/spi_master.h" #include "driver/gpio.h" #include "hal/gpio_hal.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" #include "soc/soc_caps.h" #include "soc/i2s_periph.h" #include "soc/spi_periph.h" #include "soc/parlio_periph.h" +#include "esp_dma_utils.h" #include "esp_attr.h" #include "test_board.h" #define TEST_SPI_HOST SPI2_HOST #define TEST_I2S_PORT I2S_NUM_0 #define TEST_VALID_SIG (PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1) + +#if SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT +#define TEST_OUTPUT_CLK_PIN TEST_CLK_GPIO +#else +#define TEST_OUTPUT_CLK_PIN -1 +#endif + #define TEST_DEFAULT_UNIT_CONFIG(_clk_src, _clk_freq) { \ .trans_queue_depth = 10, \ .max_recv_size = 10 * 1024, \ @@ -35,7 +45,7 @@ .ext_clk_freq_hz = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? _clk_freq : 0, \ .clk_in_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? TEST_CLK_GPIO : -1, \ .exp_clk_freq_hz = _clk_freq, \ - .clk_out_gpio_num = -1, \ + .clk_out_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? -1 : TEST_OUTPUT_CLK_PIN, \ .valid_gpio_num = TEST_VALID_GPIO, \ .data_gpio_nums = { \ [0] = TEST_DATA0_GPIO, \ @@ -56,6 +66,10 @@ typedef struct { uint32_t timeout_cnt; } test_data_t; +#ifndef ALIGN_UP +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#endif + TEST_PARLIO_CALLBACK_ATTR static bool test_parlio_rx_partial_recv_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_data) { @@ -285,11 +299,15 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_ .delimiter = deli, .flags.partial_rx_en = false, }; - uint8_t recv_buff[TEST_EOF_DATA_LEN]; + uint8_t *recv_buff = NULL; + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + alignment = alignment < 4 ? 4 : alignment; + size_t buff_size = ALIGN_UP(TEST_EOF_DATA_LEN, alignment); + recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); bool is_success = false; // sample 5 times for (int i = 0; i < 5 && !is_success; i++) { - TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, TEST_EOF_DATA_LEN, &recv_config)); + TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, buff_size, &recv_config)); TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000)); for (int k = 0; k < TEST_EOF_DATA_LEN; k++) { printf("%x ", recv_buff[k]); @@ -315,6 +333,7 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_ } // Delete the sender task vTaskDelete(sender_task); + free(recv_buff); TEST_ESP_OK(parlio_rx_unit_disable(rx_unit)); TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); @@ -409,8 +428,7 @@ TEST_CASE("parallel_rx_unit_install_uninstall", "[parlio_rx]") TEST_ESP_OK(parlio_rx_unit_disable(units[0])); TEST_ESP_OK(parlio_del_rx_unit(units[0])); } - -#define TEST_PAYLOAD_SIZE 5000 +#define TEST_PAYLOAD_SIZE 5120 // This test case uses soft delimiter TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") @@ -444,7 +462,11 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") .delimiter = deli, .flags.partial_rx_en = false, }; - uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS); + uint8_t *payload = NULL; + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + alignment = alignment < 4 ? 4 : alignment; + size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment); + payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); TEST_ASSERT(payload); printf("Testing one normal transaction...\n"); @@ -535,7 +557,11 @@ TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]") .delimiter = timeout_deli, .flags.partial_rx_en = false, }; - uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS); + uint8_t *payload = NULL; + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + alignment = alignment < 4 ? 4 : alignment; + size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment); + payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); TEST_ASSERT(payload); printf("Testing the timeout callback...\n"); diff --git a/components/esp_driver_parlio/test_apps/parlio/pytest_parlio_unity.py b/components/esp_driver_parlio/test_apps/parlio/pytest_parlio_unity.py index 4f572edd207..dbb3f9d4e06 100644 --- a/components/esp_driver_parlio/test_apps/parlio/pytest_parlio_unity.py +++ b/components/esp_driver_parlio/test_apps/parlio/pytest_parlio_unity.py @@ -1,12 +1,10 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @pytest.mark.esp32c6 -@pytest.mark.esp32h2 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/hal/esp32p4/include/hal/parlio_ll.h b/components/hal/esp32p4/include/hal/parlio_ll.h index fe96975c2a4..b7cc5558d51 100644 --- a/components/hal/esp32p4/include/hal/parlio_ll.h +++ b/components/hal/esp32p4/include/hal/parlio_ll.h @@ -213,13 +213,13 @@ static inline void parlio_ll_rx_set_recv_bit_len(parl_io_dev_t *dev, uint32_t bi * @brief Set the sub mode of the level controlled receive mode * * @param dev Parallel IO register base address - * @param active_level Level of the external enable signal, true for active high, false for active low + * @param active_low_en Level of the external enable signal, true for active low, false for active high */ __attribute__((always_inline)) -static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_level) +static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_low_en) { dev->rx_mode_cfg.rx_smp_mode_sel = 0; - dev->rx_mode_cfg.rx_ext_en_inv = !active_level; // 0: active low, 1: active high + dev->rx_mode_cfg.rx_ext_en_inv = active_low_en; } /** @@ -359,7 +359,7 @@ static inline void parlio_ll_rx_treat_data_line_as_en(parl_io_dev_t *dev, uint32 } /** - * @brief Wether to enable the RX clock gating + * @brief whether to enable the RX clock gating * * @param dev Parallel IO register base address * @param en True to enable, False to disable @@ -519,7 +519,7 @@ static inline void parlio_ll_tx_set_eof_condition(parl_io_dev_t *dev, parlio_ll_ } /** - * @brief Wether to enable the TX clock gating + * @brief whether to enable the TX clock gating * * @note The MSB of TXD will be taken as the gating enable signal * @@ -589,7 +589,6 @@ static inline void parlio_ll_tx_set_bus_width(parl_io_dev_t *dev, uint32_t width { uint32_t width_sel = 0; switch (width) { - // TODO: check this field (IDF-8284) case 16: width_sel = 4; break; diff --git a/components/hal/include/hal/dma_types.h b/components/hal/include/hal/dma_types.h index 435ac5cd96f..03146740aa0 100644 --- a/components/hal/include/hal/dma_types.h +++ b/components/hal/include/hal/dma_types.h @@ -58,6 +58,7 @@ ESP_STATIC_ASSERT(sizeof(dma_descriptor_align8_t) == 16, "dma_descriptor_align8_ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED (4095-3) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 4B */ #define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_16B_ALIGNED (4095-15) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 16B */ +#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED (4095-63) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 64B */ /** * Get the number of DMA descriptors required for a given buffer size. diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..7fc01d249a5 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -63,6 +63,10 @@ config SOC_ETM_SUPPORTED bool default y +config SOC_PARLIO_SUPPORTED + bool + default y + config SOC_ASYNC_MEMCPY_SUPPORTED bool default y @@ -991,6 +995,10 @@ config SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH int default 16 +config SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT + bool + default y + config SOC_PARLIO_TX_SIZE_BY_DMA bool default y diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 5626e7f2b00..5679247b501 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -635,8 +635,8 @@ typedef enum { */ typedef enum { PARLIO_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ - PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ PARLIO_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ PARLIO_CLK_SRC_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */ PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */ } soc_periph_parlio_clk_src_t; diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..9c54eaaec58 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -34,7 +34,7 @@ #define SOC_MCPWM_SUPPORTED 1 #define SOC_TWAI_SUPPORTED 1 #define SOC_ETM_SUPPORTED 1 -// #define SOC_PARLIO_SUPPORTED 1 //TODO: IDF-7471 +#define SOC_PARLIO_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_EMAC_SUPPORTED 1 #define SOC_USB_OTG_SUPPORTED 1 @@ -393,6 +393,7 @@ #define SOC_PARLIO_RX_UNITS_PER_GROUP 1U /*!< number of RX units in each group */ #define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */ #define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */ +#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */ #define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */ /*--------------------------- MPI CAPS ---------------------------------------*/ diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 0217624acc7..3d34d63abc5 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -261,9 +261,11 @@ examples/peripherals/parlio: examples/peripherals/parlio/parlio_rx: disable: - - if: SOC_PARLIO_SUPPORTED != 1 or IDF_TARGET == "esp32p4" + - if: SOC_PARLIO_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" temporary: true - reason: not support esp32p4 yet (IDF-7471) + reason: lack of runner depends_components: - esp_driver_parlio diff --git a/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md b/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md index 6f91587df24..1881bdf2238 100644 --- a/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md +++ b/examples/peripherals/parlio/parlio_rx/logic_analyzer/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | # Logic Analyzer Example diff --git a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/esp_probe_private.h b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/esp_probe_private.h index 77d6b4b517e..94bd1e521ff 100644 --- a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/esp_probe_private.h +++ b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/esp_probe_private.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" +#include "soc/soc_caps.h" +#include "hal/dma_types.h" #include "esp_heap_caps.h" #include "esp_probe.h" @@ -19,12 +21,17 @@ extern "C" { #endif #define ESP_PROBE_DEFAULT_Q_DEPTH 8 -#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * 4092) +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED) +#else +#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) +#endif #if CONFIG_PARLIO_ISR_IRAM_SAFE #define ESP_PROBE_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define ESP_PROBE_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif +#define ESP_PROBE_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) struct esp_probe_t { uint32_t sample_width; /*!< sample width, i.e., enabled probe channel nums */ diff --git a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c index 389687f609a..f317c3b39ef 100644 --- a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c +++ b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,8 +8,11 @@ #include #include "sdkconfig.h" #include "driver/parlio_rx.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" #include "esp_clk_tree.h" #include "esp_heap_caps.h" +#include "esp_dma_utils.h" #include "esp_check.h" #include "esp_probe_private.h" @@ -43,7 +46,11 @@ esp_err_t esp_probe_priv_init_hardware(esp_probe_handle_t handle, esp_probe_conf esp_err_t ret = ESP_OK; s_ephi = calloc(1, sizeof(esp_probe_impl_pralio_t)); ESP_RETURN_ON_FALSE(s_ephi, ESP_ERR_NO_MEM, TAG, "no memory for the esp probe hardware implementation"); - s_ephi->payload = heap_caps_calloc(1, ESP_PROBE_DEFAULT_MAX_RECV_SIZE, ESP_PROBE_ALLOC_CAPS); + + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + alignment = alignment < 4 ? 4 : alignment; + size_t payload_aligned_size = ESP_PROBE_DEFAULT_MAX_RECV_SIZE & ~(alignment - 1); + s_ephi->payload = heap_caps_aligned_calloc(alignment, 1, payload_aligned_size, ESP_PROBE_DMA_ALLOC_CAPS); ESP_GOTO_ON_FALSE(s_ephi->payload, ESP_ERR_NO_MEM, err, TAG, "no memory for payload"); // Get the channel number, the channel number can only be the power of 2 diff --git a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md index d995f56c6d9..db62a41730d 100644 --- a/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md +++ b/examples/peripherals/parlio/parlio_tx/simple_rgb_led_matrix/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C6 | ESP32-H2 | -| ----------------- | -------- | -------- | +| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 | +| ----------------- | -------- | -------- | -------- | # Parallel IO TX Example: Simple RGB LED Matrix From bf604e91a61b5a0b6583edb80735296256a28bbd Mon Sep 17 00:00:00 2001 From: gaoxu Date: Fri, 17 May 2024 20:20:19 +0800 Subject: [PATCH 151/548] feat(gpio): remove io_mux_reg array in gpio_periph.c from c5 --- .../src/bootloader_common.c | 6 ++-- .../src/bootloader_console.c | 12 +++---- components/hal/esp32/include/hal/gpio_ll.h | 2 +- components/soc/esp32c5/beta3/gpio_periph.c | 30 ----------------- components/soc/esp32c5/mp/gpio_periph.c | 32 ------------------- components/soc/esp32c61/gpio_periph.c | 28 ---------------- 6 files changed, 10 insertions(+), 100 deletions(-) diff --git a/components/bootloader_support/src/bootloader_common.c b/components/bootloader_support/src/bootloader_common.c index 28178594975..e37a5b41c38 100644 --- a/components/bootloader_support/src/bootloader_common.c +++ b/components/bootloader_support/src/bootloader_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,8 +37,8 @@ esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, ui esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio_level(uint32_t num_pin, uint32_t delay_sec, bool level) { esp_rom_gpio_pad_select_gpio(num_pin); - if (GPIO_PIN_MUX_REG[num_pin]) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[num_pin]); + if (((1ULL << num_pin) & SOC_GPIO_VALID_GPIO_MASK) != 0) { + gpio_ll_input_enable(&GPIO, num_pin); } esp_rom_gpio_pad_pullup_only(num_pin); uint32_t tm_start = esp_log_early_timestamp(); diff --git a/components/bootloader_support/src/bootloader_console.c b/components/bootloader_support/src/bootloader_console.c index 2408d0a093c..66ee195a3b1 100644 --- a/components/bootloader_support/src/bootloader_console.c +++ b/components/bootloader_support/src/bootloader_console.c @@ -13,7 +13,7 @@ #include "soc/gpio_periph.h" #include "soc/gpio_sig_map.h" #include "soc/rtc.h" -#include "hal/gpio_hal.h" +#include "hal/gpio_ll.h" #if CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/usb/cdc_acm.h" #include "esp32s2/rom/usb/usb_common.h" @@ -63,17 +63,17 @@ void bootloader_console_init(void) uart_tx_gpio != UART_NUM_0_TXD_DIRECT_GPIO_NUM || uart_rx_gpio != UART_NUM_0_RXD_DIRECT_GPIO_NUM) { // Change default UART pins back to GPIOs - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[UART_NUM_0_RXD_DIRECT_GPIO_NUM], PIN_FUNC_GPIO); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[UART_NUM_0_TXD_DIRECT_GPIO_NUM], PIN_FUNC_GPIO); + gpio_ll_func_sel(&GPIO, UART_NUM_0_RXD_DIRECT_GPIO_NUM, PIN_FUNC_GPIO); + gpio_ll_func_sel(&GPIO, UART_NUM_0_TXD_DIRECT_GPIO_NUM, PIN_FUNC_GPIO); // Route GPIO signals to/from pins const uint32_t tx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX); const uint32_t rx_idx = UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[uart_rx_gpio], PIN_FUNC_GPIO); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[uart_rx_gpio]); + gpio_ll_func_sel(&GPIO, uart_rx_gpio, PIN_FUNC_GPIO); + gpio_ll_input_enable(&GPIO, uart_rx_gpio); esp_rom_gpio_pad_pullup_only(uart_rx_gpio); esp_rom_gpio_connect_out_signal(uart_tx_gpio, tx_idx, 0, 0); esp_rom_gpio_connect_in_signal(uart_rx_gpio, rx_idx, 0); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[uart_tx_gpio], PIN_FUNC_GPIO); + gpio_ll_func_sel(&GPIO, uart_tx_gpio, PIN_FUNC_GPIO); // Enable the peripheral uart_ll_enable_bus_clock(uart_num, true); uart_ll_reset_register(uart_num); diff --git a/components/hal/esp32/include/hal/gpio_ll.h b/components/hal/esp32/include/hal/gpio_ll.h index 20833e1ddb8..3839e39360c 100644 --- a/components/hal/esp32/include/hal/gpio_ll.h +++ b/components/hal/esp32/include/hal/gpio_ll.h @@ -355,7 +355,7 @@ static inline void gpio_ll_input_disable(gpio_dev_t *hw, uint32_t gpio_num) */ static inline void gpio_ll_input_enable(gpio_dev_t *hw, uint32_t gpio_num) { - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[gpio_num]); + PIN_INPUT_ENABLE(DR_REG_IO_MUX_BASE + GPIO_PIN_MUX_REG_OFFSET[gpio_num]); } /** diff --git a/components/soc/esp32c5/beta3/gpio_periph.c b/components/soc/esp32c5/beta3/gpio_periph.c index 417b781b6b8..00d0ebeaa9e 100644 --- a/components/soc/esp32c5/beta3/gpio_periph.c +++ b/components/soc/esp32c5/beta3/gpio_periph.c @@ -6,36 +6,6 @@ #include "soc/gpio_periph.h" -const uint32_t GPIO_PIN_MUX_REG[] = { - IO_MUX_GPIO0_REG, - IO_MUX_GPIO1_REG, - IO_MUX_GPIO2_REG, - IO_MUX_GPIO3_REG, - IO_MUX_GPIO4_REG, - IO_MUX_GPIO5_REG, - IO_MUX_GPIO6_REG, - IO_MUX_GPIO7_REG, - IO_MUX_GPIO8_REG, - IO_MUX_GPIO9_REG, - IO_MUX_GPIO10_REG, - IO_MUX_GPIO11_REG, - IO_MUX_GPIO12_REG, - IO_MUX_GPIO13_REG, - IO_MUX_GPIO14_REG, - IO_MUX_GPIO15_REG, - IO_MUX_GPIO16_REG, - IO_MUX_GPIO17_REG, - IO_MUX_GPIO18_REG, - IO_MUX_GPIO19_REG, - IO_MUX_GPIO20_REG, - IO_MUX_GPIO21_REG, - IO_MUX_GPIO22_REG, - IO_MUX_GPIO23_REG, - IO_MUX_GPIO24_REG, - IO_MUX_GPIO25_REG, - IO_MUX_GPIO26_REG, -}; - _Static_assert(sizeof(GPIO_PIN_MUX_REG) == SOC_GPIO_PIN_COUNT * sizeof(uint32_t), "Invalid size of GPIO_PIN_MUX_REG"); const uint32_t GPIO_HOLD_MASK[] = { diff --git a/components/soc/esp32c5/mp/gpio_periph.c b/components/soc/esp32c5/mp/gpio_periph.c index bd23783dd96..1d1d4969723 100644 --- a/components/soc/esp32c5/mp/gpio_periph.c +++ b/components/soc/esp32c5/mp/gpio_periph.c @@ -6,38 +6,6 @@ #include "soc/gpio_periph.h" -const uint32_t GPIO_PIN_MUX_REG[] = { - IO_MUX_GPIO0_REG, - IO_MUX_GPIO1_REG, - IO_MUX_GPIO2_REG, - IO_MUX_GPIO3_REG, - IO_MUX_GPIO4_REG, - IO_MUX_GPIO5_REG, - IO_MUX_GPIO6_REG, - IO_MUX_GPIO7_REG, - IO_MUX_GPIO8_REG, - IO_MUX_GPIO9_REG, - IO_MUX_GPIO10_REG, - IO_MUX_GPIO11_REG, - IO_MUX_GPIO12_REG, - IO_MUX_GPIO13_REG, - IO_MUX_GPIO14_REG, - IO_MUX_GPIO15_REG, - IO_MUX_GPIO16_REG, - IO_MUX_GPIO17_REG, - IO_MUX_GPIO18_REG, - IO_MUX_GPIO19_REG, - IO_MUX_GPIO20_REG, - IO_MUX_GPIO21_REG, - IO_MUX_GPIO22_REG, - IO_MUX_GPIO23_REG, - IO_MUX_GPIO24_REG, - IO_MUX_GPIO25_REG, - IO_MUX_GPIO26_REG, - IO_MUX_GPIO27_REG, - IO_MUX_GPIO28_REG, -}; - _Static_assert(sizeof(GPIO_PIN_MUX_REG) == SOC_GPIO_PIN_COUNT * sizeof(uint32_t), "Invalid size of GPIO_PIN_MUX_REG"); const uint32_t GPIO_HOLD_MASK[] = { diff --git a/components/soc/esp32c61/gpio_periph.c b/components/soc/esp32c61/gpio_periph.c index 22c9d3f627a..fb953db697f 100644 --- a/components/soc/esp32c61/gpio_periph.c +++ b/components/soc/esp32c61/gpio_periph.c @@ -6,34 +6,6 @@ #include "soc/gpio_periph.h" -const uint32_t GPIO_PIN_MUX_REG[] = { - IO_MUX_GPIO0_REG, - IO_MUX_GPIO1_REG, - IO_MUX_GPIO2_REG, - IO_MUX_GPIO3_REG, - IO_MUX_GPIO4_REG, - IO_MUX_GPIO5_REG, - IO_MUX_GPIO6_REG, - IO_MUX_GPIO7_REG, - IO_MUX_GPIO8_REG, - IO_MUX_GPIO9_REG, - IO_MUX_GPIO10_REG, - IO_MUX_GPIO11_REG, - IO_MUX_GPIO12_REG, - IO_MUX_GPIO13_REG, - IO_MUX_GPIO14_REG, - IO_MUX_GPIO15_REG, - IO_MUX_GPIO16_REG, - IO_MUX_GPIO17_REG, - IO_MUX_GPIO18_REG, - IO_MUX_GPIO19_REG, - IO_MUX_GPIO20_REG, - IO_MUX_GPIO21_REG, - IO_MUX_GPIO22_REG, - IO_MUX_GPIO23_REG, - IO_MUX_GPIO24_REG, -}; - _Static_assert(sizeof(GPIO_PIN_MUX_REG) == SOC_GPIO_PIN_COUNT * sizeof(uint32_t), "Invalid size of GPIO_PIN_MUX_REG"); const uint32_t GPIO_HOLD_MASK[] = { From 0be44b6cccdc5ac4dbadfd55dc89b5c85b187277 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Fri, 17 May 2024 20:23:15 +0800 Subject: [PATCH 152/548] feat(gpio): fix gpio matrix const input addr on C5 MP --- components/soc/esp32c5/mp/include/soc/gpio_pins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/soc/esp32c5/mp/include/soc/gpio_pins.h b/components/soc/esp32c5/mp/include/soc/gpio_pins.h index c630ae47649..268506ce391 100644 --- a/components/soc/esp32c5/mp/include/soc/gpio_pins.h +++ b/components/soc/esp32c5/mp/include/soc/gpio_pins.h @@ -11,8 +11,8 @@ extern "C" { #endif -#define GPIO_MATRIX_CONST_ONE_INPUT (0x38) -#define GPIO_MATRIX_CONST_ZERO_INPUT (0x3C) +#define GPIO_MATRIX_CONST_ONE_INPUT (0x40) +#define GPIO_MATRIX_CONST_ZERO_INPUT (0x50) #ifdef __cplusplus } From 6bb35c551cd839eeaf32d91aef4a0670a22b78ad Mon Sep 17 00:00:00 2001 From: Wang Fang Date: Tue, 16 Apr 2024 16:26:07 +0800 Subject: [PATCH 153/548] docs: Updated Getting Started for ESP32-P4 support --- docs/docs_not_updated/esp32p4.txt | 9 ----- docs/en/get-started/esp32p4_output_log.inc | 40 ++++++++++++++++++- .../establish-serial-connection.rst | 10 +++-- .../get-started/flashing-troubleshooting.rst | 2 +- docs/en/get-started/index.rst | 12 ++++++ docs/en/get-started/start-project.rst | 8 ++-- docs/en/get-started/windows-setup.rst | 4 +- docs/zh_CN/get-started/esp32p4_output_log.inc | 40 ++++++++++++++++++- .../establish-serial-connection.rst | 11 +++-- .../get-started/flashing-troubleshooting.rst | 2 +- docs/zh_CN/get-started/index.rst | 12 ++++++ docs/zh_CN/get-started/start-project.rst | 8 ++-- docs/zh_CN/get-started/windows-setup.rst | 2 + 13 files changed, 132 insertions(+), 28 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 16c57f06ea2..c4bcd86b1fd 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -49,12 +49,3 @@ api-reference/system/app_trace.rst api-reference/system/random.rst api-reference/system/power_management.rst api-reference/system/inc/power_management_esp32p4.rst -get-started/establish-serial-connection.rst -get-started/linux-macos-setup.rst -get-started/linux-macos-start-project.rst -get-started/windows-setup.rst -get-started/start-project.rst -get-started/flashing-troubleshooting.rst -get-started/windows-start-project.rst -get-started/index.rst -get-started/windows-setup-update.rst diff --git a/docs/en/get-started/esp32p4_output_log.inc b/docs/en/get-started/esp32p4_output_log.inc index 69a66d4736d..e8d0eb6553f 100644 --- a/docs/en/get-started/esp32p4_output_log.inc +++ b/docs/en/get-started/esp32p4_output_log.inc @@ -1 +1,39 @@ -.. output_log \ No newline at end of file +.. output_log + + +.. code-block:: none + + ... + esptool.py v4.8.dev3 + Serial port /dev/cu.SLAB_USBtoUART + Connecting.... + Chip is ESP32-P4 (revision v0.0) + Features: High-Performance MCU + Crystal is 40MHz + MAC: 00:00:00:00:00:00 + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 460800 + Changed. + Configuring flash size... + Flash will be erased from 0x00002000 to 0x00007fff... + Flash will be erased from 0x00010000 to 0x0003bfff... + Flash will be erased from 0x00008000 to 0x00008fff... + SHA digest in image updated + Compressed 20960 bytes to 12653... + Writing at 0x00002000... (100 %) + Wrote 20960 bytes (12653 compressed) at 0x00002000 in 0.6 seconds (effective 277.1 kbit/s)... + Hash of data verified. + Compressed 179584 bytes to 94528... + Writing at 0x00035efb... (100 %) + Wrote 179584 bytes (94528 compressed) at 0x00010000 in 2.6 seconds (effective 549.9 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 103... + Writing at 0x00008000... (100 %) + Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 420.7 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting via RTS pin... + Done diff --git a/docs/en/get-started/establish-serial-connection.rst b/docs/en/get-started/establish-serial-connection.rst index fff30cf6649..bce1fb158a2 100644 --- a/docs/en/get-started/establish-serial-connection.rst +++ b/docs/en/get-started/establish-serial-connection.rst @@ -141,12 +141,12 @@ Sometimes the USB-to-UART bridge is external. This is often used in small develo For the {IDF_TARGET_NAME}, the USB peripheral is available, allowing you to flash the binaries without the need for an external USB-to-UART bridge. - {IDF_TARGET_USB_PIN_DM:default="Not Updated!", esp32c3="GPIO18", esp32s3="GPIO19", esp32s2="GPIO19", esp32c6="GPIO12", esp32h2="GPIO26"} - {IDF_TARGET_USB_PIN_DP:default="Not Updated!", esp32c3="GPIO19", esp32s3="GPIO20", esp32s2="GPIO20", esp32c6="GPIO13", esp32h2="GPIO27"} + {IDF_TARGET_USB_PIN_DM:default="Not Updated!", esp32c3="GPIO18", esp32s3="GPIO19", esp32s2="GPIO19", esp32c6="GPIO12", esp32h2="GPIO26", esp32p4="GPIO24/26"} + {IDF_TARGET_USB_PIN_DP:default="Not Updated!", esp32c3="GPIO19", esp32s3="GPIO20", esp32s2="GPIO20", esp32c6="GPIO13", esp32h2="GPIO27", esp32p4="GPIO25/27"} The USB on the {IDF_TARGET_NAME} uses the **{IDF_TARGET_USB_PIN_DP}** for **D+** and **{IDF_TARGET_USB_PIN_DM}** for **D-**. - .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED + .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED and not esp32s3 and not esp32p4 .. only:: not SOC_USB_OTG_SUPPORTED @@ -348,6 +348,8 @@ To spare you the trouble of installing a serial terminal program, macOS offers t Example Output ^^^^^^^^^^^^^^ +{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9", esp32p4="GPIO35"} + An example log is shown below. Reset the board if you do not see anything. .. highlight:: none @@ -376,7 +378,7 @@ If you can see readable log output, it means serial connection is working and yo .. note:: - For some serial port wiring configurations, the serial RTS & DTR pins need to be disabled in the terminal program before the {IDF_TARGET_NAME} booting and producing serial output. This depends on the hardware itself, most development boards (including all Espressif boards) *do not* have this issue. The issue is present if RTS & DTR are wired directly to the EN & GPIO0 pins. See the `esptool documentation`_ for more details. + For some serial port wiring configurations, the serial RTS & DTR pins need to be disabled in the terminal program before the {IDF_TARGET_NAME} booting and producing serial output. This depends on the hardware itself, most development boards (including all Espressif boards) *do not* have this issue. The issue is present if RTS & DTR are wired directly to the EN & {IDF_TARGET_STRAP_GPIO} pins. See the `esptool documentation`_ for more details. If you got here from :ref:`get-started-connect` when installing s/w for {IDF_TARGET_NAME} development, then you can continue with :ref:`get-started-configure`. diff --git a/docs/en/get-started/flashing-troubleshooting.rst b/docs/en/get-started/flashing-troubleshooting.rst index 7f0bdcc6462..8664fe1ede6 100644 --- a/docs/en/get-started/flashing-troubleshooting.rst +++ b/docs/en/get-started/flashing-troubleshooting.rst @@ -6,7 +6,7 @@ Flashing Troubleshooting Failed to Connect ----------------- -{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9"} +{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9", esp32p4="GPIO35"} If you run the given command and see errors such as "Failed to connect", there might be several reasons for this. One of the reasons might be issues encountered by ``esptool.py``, the utility that is called by the build system to reset the chip, interact with the ROM bootloader, and flash firmware. One simple solution to try is to manually reset as described below. If it does not help, you can find more details about possible issues in the `esptool troubleshooting `_ page. diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index e8869448e52..b3ad096349d 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -76,6 +76,14 @@ Introduction * Multiple peripherals * Built-in security hardware +.. only:: esp32p4 + + * High performance MCU with RISC-V dual-core processors + * Powerful image and voice processing capability + * Single-precision FPU and AI extensions + * Rich set of peripherals including MIPI, USB, SDIO, and Ethernet + * Built-in security hardware + Powered by 40 nm technology, {IDF_TARGET_NAME} provides a robust, highly integrated platform, which helps meet the continuous demands for efficient power usage, compact design, security, high performance, and reliability. Espressif provides basic hardware and software resources to help application developers realize their ideas using the {IDF_TARGET_NAME} series hardware. The software development framework by Espressif is intended for development of Internet-of-Things (IoT) applications with Wi-Fi, Bluetooth, power management and several other system features. @@ -150,6 +158,10 @@ If you have one of {IDF_TARGET_NAME} official development boards listed below, y ESP32-C6-DevKitC-1 ESP32-C6-DevKitM-1 +.. only:: esp32p4 + + To be announced. + .. _get-started-get-prerequisites: Software diff --git a/docs/en/get-started/start-project.rst b/docs/en/get-started/start-project.rst index 1e837f8edd0..9826f7130c0 100644 --- a/docs/en/get-started/start-project.rst +++ b/docs/en/get-started/start-project.rst @@ -1,6 +1,6 @@ -{IDF_TARGET_FEATURES:default="[NEEDS TO BE UPDATED]", esp32="WiFi/BT/BLE, silicon revision 1, 2 MB external flash", esp32s2="WiFi, silicon revision 0, 2 MB external flash", esp32s3="This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c2="WiFi/BLE, silicon revision 0, 2 MB embedded flash", esp32c3="WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c6="WiFi/BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.0, 2 MB external flash", esp32h2="BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.1, 2 MB external flash"} +{IDF_TARGET_FEATURES:default="[NEEDS TO BE UPDATED]", esp32="WiFi/BT/BLE, silicon revision 1, 2 MB external flash", esp32s2="WiFi, silicon revision 0, 2 MB external flash", esp32s3="This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c2="WiFi/BLE, silicon revision 0, 2 MB embedded flash", esp32c3="WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c6="WiFi/BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.0, 2 MB external flash", esp32h2="BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.1, 2 MB external flash", esp32p4="silicon revision v0.0, 2 MB external flash"} -{IDF_TARGET_HEAP_SIZE:default="[NEEDS TO BE UPDATED]", esp32="298968", esp32s2="253900", esp32s3="390684", esp32c2="203888", esp32c3="337332", esp32c6="473816", esp32h2="268256"} +{IDF_TARGET_HEAP_SIZE:default="[NEEDS TO BE UPDATED]", esp32="298968", esp32s2="253900", esp32s3="390684", esp32c2="203888", esp32c3="337332", esp32c6="473816", esp32h2="268256", esp32p4="618848"} Build the Project ================= @@ -72,7 +72,9 @@ Monitor the Output To check if "hello_world" is indeed running, type ``idf.py -p PORT monitor`` (Do not forget to replace PORT with your serial port name). -This command launches the :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` application:: +This command launches the :doc:`IDF Monitor <../api-guides/tools/idf-monitor>` application. + +.. code-block:: bash $ idf.py -p monitor Running idf_monitor in directory [...]/esp/hello_world/build diff --git a/docs/en/get-started/windows-setup.rst b/docs/en/get-started/windows-setup.rst index b9a0ad6deea..9911b9b7c4a 100644 --- a/docs/en/get-started/windows-setup.rst +++ b/docs/en/get-started/windows-setup.rst @@ -12,7 +12,9 @@ ESP-IDF requires some prerequisite tools to be installed so you can build firmwa For this Getting Started we are going to use the Command Prompt, but after ESP-IDF is installed you can use `Eclipse Plugin `_ or another graphical IDE with CMake support instead. .. note:: + Limitations: + - The installation path of ESP-IDF and ESP-IDF Tools must not be longer than 90 characters. Too long installation paths might result in a failed build. - The installation path of Python or ESP-IDF must not contain white spaces or parentheses. - The installation path of Python or ESP-IDF should not contain special characters (non-ASCII) unless the operating system is configured with "Unicode UTF-8" support. @@ -41,7 +43,7 @@ What Is the Usecase for Online and Offline Installer Online Installer is very small and allows the installation of all available releases of ESP-IDF. The installer downloads only necessary dependencies including `Git For Windows`_ during the installation process. The installer stores downloaded files in the cache directory ``%userprofile%\.espressif`` -Offline Installer does not require any network connection. The installer contains all required dependencies including `Git For Windows`_ . +Offline Installer does not require any network connection. The installer contains all required dependencies including `Git For Windows`_. Components of the Installation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/zh_CN/get-started/esp32p4_output_log.inc b/docs/zh_CN/get-started/esp32p4_output_log.inc index 69a66d4736d..e8d0eb6553f 100644 --- a/docs/zh_CN/get-started/esp32p4_output_log.inc +++ b/docs/zh_CN/get-started/esp32p4_output_log.inc @@ -1 +1,39 @@ -.. output_log \ No newline at end of file +.. output_log + + +.. code-block:: none + + ... + esptool.py v4.8.dev3 + Serial port /dev/cu.SLAB_USBtoUART + Connecting.... + Chip is ESP32-P4 (revision v0.0) + Features: High-Performance MCU + Crystal is 40MHz + MAC: 00:00:00:00:00:00 + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 460800 + Changed. + Configuring flash size... + Flash will be erased from 0x00002000 to 0x00007fff... + Flash will be erased from 0x00010000 to 0x0003bfff... + Flash will be erased from 0x00008000 to 0x00008fff... + SHA digest in image updated + Compressed 20960 bytes to 12653... + Writing at 0x00002000... (100 %) + Wrote 20960 bytes (12653 compressed) at 0x00002000 in 0.6 seconds (effective 277.1 kbit/s)... + Hash of data verified. + Compressed 179584 bytes to 94528... + Writing at 0x00035efb... (100 %) + Wrote 179584 bytes (94528 compressed) at 0x00010000 in 2.6 seconds (effective 549.9 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 103... + Writing at 0x00008000... (100 %) + Wrote 3072 bytes (103 compressed) at 0x00008000 in 0.1 seconds (effective 420.7 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting via RTS pin... + Done diff --git a/docs/zh_CN/get-started/establish-serial-connection.rst b/docs/zh_CN/get-started/establish-serial-connection.rst index 0141ba239c9..f4cda3c71ad 100644 --- a/docs/zh_CN/get-started/establish-serial-connection.rst +++ b/docs/zh_CN/get-started/establish-serial-connection.rst @@ -141,12 +141,12 @@ {IDF_TARGET_NAME} 支持 USB 外设,无需外部 USB 至 UART 桥,即可烧录二进制文件。 - {IDF_TARGET_USB_PIN_DM:default="尚未更新!", esp32c3="GPIO18", esp32s3="GPIO19", esp32s2="GPIO19", esp32c6="GPIO12", esp32h2="GPIO26"} - {IDF_TARGET_USB_PIN_DP:default="尚未更新!", esp32c3="GPIO19", esp32s3="GPIO20", esp32s2="GPIO20", esp32c6="GPIO13", esp32h2="GPIO27"} + {IDF_TARGET_USB_PIN_DM:default="尚未更新!", esp32c3="GPIO18", esp32s3="GPIO19", esp32s2="GPIO19", esp32c6="GPIO12", esp32h2="GPIO26", esp32p4="GPIO24/26"} + {IDF_TARGET_USB_PIN_DP:default="尚未更新!", esp32c3="GPIO19", esp32s3="GPIO20", esp32s2="GPIO20", esp32c6="GPIO13", esp32h2="GPIO27", esp32p4="GPIO24/26"} {IDF_TARGET_NAME} 上的 USB 使用 **{IDF_TARGET_USB_PIN_DP}** 作为 **D+**, **{IDF_TARGET_USB_PIN_DM}** 作为 **D-**。 - .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED and not esp32s3 + .. only:: SOC_USB_SERIAL_JTAG_SUPPORTED and not esp32s3 and not esp32p4 .. note:: {IDF_TARGET_NAME} 仅支持 *USB CDC and JTAG*。 @@ -348,6 +348,9 @@ macOS 提供了 **屏幕** 命令,因此无需安装串口终端程序。 输出示例 ^^^^^^^^^^^ + +{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9", esp32p4="GPIO35"} + 以下是一个日志示例。如果没看到任何输出,请尝试重置开发板。 .. highlight:: none @@ -376,7 +379,7 @@ macOS 提供了 **屏幕** 命令,因此无需安装串口终端程序。 .. 注解:: - 在某些串口接线方式下,在 {IDF_TARGET_NAME} 启动并开始打印串口日志前,需要在终端程序中禁用串口 RTS & DTR 管脚。该问题仅存在于将 RTS & DTR 管脚直接连接到 EN & GPIO0 管脚上的情况,绝大多数开发板(包括乐鑫所有的开发板)都没有这个问题。更多详细信息,请参考 `esptool 文档`_。 + 在某些串口接线方式下,在 {IDF_TARGET_NAME} 启动并开始打印串口日志前,需要在终端程序中禁用串口 RTS & DTR 管脚。该问题仅存在于将 RTS & DTR 管脚直接连接到 EN & {IDF_TARGET_STRAP_GPIO} 管脚上的情况,绝大多数开发板(包括乐鑫所有的开发板)都没有这个问题。更多详细信息,请参考 `esptool 文档`_。 如在安装 {IDF_TARGET_NAME} 硬件开发的软件环境时,从 :ref:`get-started-connect` 跳转到了这里,请从 :ref:`get-started-configure` 继续阅读。 diff --git a/docs/zh_CN/get-started/flashing-troubleshooting.rst b/docs/zh_CN/get-started/flashing-troubleshooting.rst index 992b2310bec..278196ccf65 100644 --- a/docs/zh_CN/get-started/flashing-troubleshooting.rst +++ b/docs/zh_CN/get-started/flashing-troubleshooting.rst @@ -6,7 +6,7 @@ 连接失败 ----------------- -{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9"} +{IDF_TARGET_STRAP_GPIO:default="[NEEDS TO BE UPDATED]", esp32="GPIO0", esp32s2="GPIO0", esp32s3="GPIO0", esp32c2="GPIO9", esp32c3="GPIO9", esp32c6="GPIO9", esp32h2="GPIO9", esp32p4="GPIO35"} 如果在运行给定命令时出现如“连接失败”这样的错误,造成该错误的原因之一可能是运行 ``esptool.py`` 时出现错误。 ``esptool.py`` 是构建系统调用的程序,用于重置芯片、与 ROM 引导加载器交互以及烧录固件的工具。可以按照以下步骤进行手动复位,轻松解决该问题。如果问题仍未解决,请参考 `esptool 故障排除 `_ 获取更多信息。 diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 1d5a54b0d6d..d651c66a7e9 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -76,6 +76,14 @@ * 多种外设 * 内置安全硬件 +.. only:: esp32p4 + + * 搭载 RISC-V 32 位双核处理器的高性能 MCU + * 强大的图像与语音处理能力 + * 支持单精度 FPU 和 AI 扩展 + * 外设丰富包括 MIPI、USB、SDIO、以太网等 + * 内置安全硬件 + {IDF_TARGET_NAME} 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用场景和不同功耗需求。 乐鑫为用户提供完整的软、硬件资源,进行 {IDF_TARGET_NAME} 硬件设备的开发。其中,乐鑫的软件开发环境 ESP-IDF 旨在协助用户快速开发物联网 (IoT) 应用,可满足用户对 Wi-Fi、蓝牙、低功耗等方面的要求。 @@ -150,6 +158,10 @@ ESP32-C6-DevKitC-1 ESP32-C6-DevKitM-1 +.. only:: esp32p4 + + 即将发布 + .. _get-started-get-prerequisites: 软件: diff --git a/docs/zh_CN/get-started/start-project.rst b/docs/zh_CN/get-started/start-project.rst index 96346ea0486..982e78deca6 100644 --- a/docs/zh_CN/get-started/start-project.rst +++ b/docs/zh_CN/get-started/start-project.rst @@ -1,6 +1,6 @@ -{IDF_TARGET_FEATURES:default="[NEEDS TO BE UPDATED]", esp32="WiFi/BT/BLE, silicon revision 1, 2 MB external flash", esp32s2="WiFi, silicon revision 0, 2 MB external flash", esp32s3="This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c2="WiFi/BLE, silicon revision 0, 2 MB embedded flash", esp32c3="WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c6="WiFi/BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.0, 2 MB external flash", esp32h2="BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.1, 2 MB external flash"} +{IDF_TARGET_FEATURES:default="[NEEDS TO BE UPDATED]", esp32="WiFi/BT/BLE, silicon revision 1, 2 MB external flash", esp32s2="WiFi, silicon revision 0, 2 MB external flash", esp32s3="This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c2="WiFi/BLE, silicon revision 0, 2 MB embedded flash", esp32c3="WiFi/BLE, silicon revision 0, 2 MB external flash", esp32c6="WiFi/BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.0, 2 MB external flash", esp32h2="BLE, 802.15.4 (Zigbee/Thread), silicon revision v0.1, 2 MB external flash", esp32p4="silicon revision v0.0, 2 MB external flash"} -{IDF_TARGET_HEAP_SIZE:default="[NEEDS TO BE UPDATED]", esp32="298968", esp32s2="253900", esp32s3="390684", esp32c2="203888", esp32c3="337332", esp32c6="473816", esp32h2="268256"} +{IDF_TARGET_HEAP_SIZE:default="[NEEDS TO BE UPDATED]", esp32="298968", esp32s2="253900", esp32s3="390684", esp32c2="203888", esp32c3="337332", esp32c6="473816", esp32h2="268256", esp32p4="618848"} 编译工程 ========================= @@ -72,7 +72,9 @@ 可以使用 ``idf.py -p PORT monitor`` 命令,监视 “hello_world” 工程的运行情况。注意,不要忘记将 PORT 替换为自己的串口名称。 -运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动::: +运行该命令后,:doc:`IDF 监视器 <../api-guides/tools/idf-monitor>` 应用程序将启动。 + +.. code-block:: bash $ idf.py -p monitor Running idf_monitor in directory [...]/esp/hello_world/build diff --git a/docs/zh_CN/get-started/windows-setup.rst b/docs/zh_CN/get-started/windows-setup.rst index 2c109110c97..a447a7110de 100644 --- a/docs/zh_CN/get-started/windows-setup.rst +++ b/docs/zh_CN/get-started/windows-setup.rst @@ -12,7 +12,9 @@ ESP-IDF 需要安装一些必备工具,才能围绕 {IDF_TARGET_NAME} 构建 本入门指南介绍了如何通过 **命令提示符** 进行有关操作。不过,安装 ESP-IDF 后,还可以使用 `Eclipse Plugin `_ 或其他支持 CMake 的图形化工具 IDE。 .. note:: + 限定条件: + - 请注意 ESP-IDF 和 ESP-IDF 工具的安装路径不能超过 90 个字符,安装路径过长可能会导致构建失败。 - Python 或 ESP-IDF 的安装路径中一定不能包含空格或括号。 - 除非操作系统配置为支持 Unicode UTF-8,否则 Python 或 ESP-IDF 的安装路径中也不能包括特殊字符(非 ASCII 码字符) From 48e06fafea2e3c3435b562043d27e8552c9bfa14 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 10 May 2024 16:11:39 +0800 Subject: [PATCH 154/548] feat(xip_psram): support xip psram feature on esp32p4 --- components/bootloader_support/CMakeLists.txt | 9 +- .../include/bootloader_memory_utils.h | 28 ++- .../include/esp_private/image_process.h | 64 ++++++ components/bootloader_support/linker.lf | 5 + .../src/bootloader_utility.c | 43 +++- .../bootloader_support/src/esp_image_format.c | 12 +- .../bootloader_support/src/image_process.c | 215 ++++++++++++++++++ components/esp_hw_support/CMakeLists.txt | 2 +- components/esp_hw_support/clk_ctrl_os.c | 13 +- components/esp_hw_support/ldo/linker.lf | 6 + .../rgb_lcd/sdkconfig.defaults.esp32s3 | 3 +- components/esp_mm/esp_mmu_map.c | 41 ++-- components/esp_mm/linker.lf | 7 + components/esp_psram/CMakeLists.txt | 16 +- components/esp_psram/esp32p4/Kconfig.spiram | 34 +++ components/esp_psram/esp32s2/Kconfig.spiram | 26 ++- components/esp_psram/esp32s3/Kconfig.spiram | 27 ++- components/esp_psram/esp_psram.c | 94 ++++++-- .../include/esp_private/mmu_psram_flash.h | 15 +- components/esp_psram/linker.lf | 7 + components/esp_psram/mmu_psram_flash_v2.c | 173 ++++++++++++++ .../esp_psram/test_apps/psram/pytest_psram.py | 2 +- .../test_apps/psram/sdkconfig.ci.esp32p4_xip | 14 ++ components/esp_system/CMakeLists.txt | 3 +- components/esp_system/ld/esp32p4/memory.ld.in | 10 + components/esp_system/port/cpu_start.c | 29 ++- components/hal/esp32/include/hal/mmu_ll.h | 7 +- components/hal/esp32c2/include/hal/mmu_ll.h | 7 +- components/hal/esp32c3/include/hal/mmu_ll.h | 4 +- components/hal/esp32c5/include/hal/mmu_ll.h | 5 +- components/hal/esp32c6/include/hal/mmu_ll.h | 7 +- components/hal/esp32c61/include/hal/mmu_ll.h | 5 +- components/hal/esp32h2/include/hal/mmu_ll.h | 4 +- components/hal/esp32p4/clk_tree_hal.c | 3 +- components/hal/esp32p4/include/hal/ldo_ll.h | 26 +-- components/hal/esp32p4/include/hal/mmu_ll.h | 9 +- components/hal/esp32s2/include/hal/mmu_ll.h | 7 +- components/hal/esp32s3/include/hal/mmu_ll.h | 4 +- components/hal/include/hal/cache_hal.h | 1 + components/hal/linker.lf | 2 - components/hal/mmu_hal.c | 3 +- .../soc/esp32/include/soc/ext_mem_defs.h | 3 - .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32p4/include/soc/ext_mem_defs.h | 3 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../soc/esp32s3/include/soc/ext_mem_defs.h | 8 +- components/spi_flash/flash_mmap.c | 15 +- components/spi_flash/flash_ops.c | 10 + .../include/esp_private/spi_flash_os.h | 7 +- .../flash_mmap/main/test_flash_mmap.c | 32 ++- docs/en/api-guides/external-ram.rst | 52 +++-- tools/ci/check_ldgen_mapping_exceptions.txt | 2 + 52 files changed, 968 insertions(+), 161 deletions(-) create mode 100644 components/bootloader_support/include/esp_private/image_process.h create mode 100644 components/bootloader_support/linker.lf create mode 100644 components/bootloader_support/src/image_process.c create mode 100644 components/esp_hw_support/ldo/linker.lf create mode 100644 components/esp_psram/mmu_psram_flash_v2.c create mode 100644 components/esp_psram/test_apps/psram/sdkconfig.ci.esp32p4_xip diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index fbe9adf5fd1..8d70b1f8c61 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -28,6 +28,10 @@ if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) ) endif() +if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP AND NOT BOOTLOADER_BUILD) + list(APPEND srcs "src/image_process.c") +endif() + if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT) list(APPEND srcs "src/bootloader_utility.c" @@ -60,7 +64,7 @@ else() set(include_dirs "include" "bootloader_flash/include") set(priv_include_dirs "private_include") # heap is required for `heap_memory_layout.h` header - set(priv_requires spi_flash mbedtls efuse heap esp_bootloader_format esp_app_format) + set(priv_requires spi_flash mbedtls efuse heap esp_bootloader_format esp_app_format esp_mm) endif() if(BOOTLOADER_BUILD) @@ -112,7 +116,8 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" REQUIRES "${requires}" - PRIV_REQUIRES "${priv_requires}") + PRIV_REQUIRES "${priv_requires}" + LDFRAGMENTS linker.lf) if(NOT BOOTLOADER_BUILD) if(CONFIG_SECURE_SIGNED_ON_UPDATE) diff --git a/components/bootloader_support/include/bootloader_memory_utils.h b/components/bootloader_support/include/bootloader_memory_utils.h index bb81697a89f..adbf72a275f 100644 --- a/components/bootloader_support/include/bootloader_memory_utils.h +++ b/components/bootloader_support/include/bootloader_memory_utils.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "soc/soc.h" +#include "soc/ext_mem_defs.h" #include "soc/soc_caps.h" #include "sdkconfig.h" #include "esp_attr.h" @@ -179,6 +180,31 @@ inline static bool esp_ptr_in_tcm(const void *p) { #endif //#if SOC_MEM_TCM_SUPPORTED /** End of the common section that has to be in sync with esp_memory_utils.h **/ + +/** + * @brief Check if the pointer is in PSRAM vaddr space + * + * @note This function is only used when in bootloader, where the PSRAM isn't initialised. + * This function simply check if the pointer is the in the PSRAM vaddr space. + * The PSRAM vaddr space is not always the same as the actual PSRAM vaddr range used in APP + * + * @param p pointer + * + * @return true: is in PSRAM; false: not in PSRAM + */ +__attribute__((always_inline)) +inline static bool esp_ptr_in_extram(const void *p) { + bool valid = false; +#if SOC_IRAM_PSRAM_ADDRESS_LOW + valid |= ((intptr_t)p >= SOC_IRAM_PSRAM_ADDRESS_LOW && (intptr_t)p < SOC_IRAM_PSRAM_ADDRESS_HIGH); +#endif + +#if SOC_DRAM_PSRAM_ADDRESS_LOW + valid |= ((intptr_t)p >= SOC_DRAM_PSRAM_ADDRESS_LOW && (intptr_t)p < SOC_DRAM_PSRAM_ADDRESS_HIGH); +#endif + return valid; +} + /** Don't add new functions below **/ #ifdef __cplusplus diff --git a/components/bootloader_support/include/esp_private/image_process.h b/components/bootloader_support/include/esp_private/image_process.h new file mode 100644 index 00000000000..809055a6822 --- /dev/null +++ b/components/bootloader_support/include/esp_private/image_process.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "esp_err.h" +#include "esp_image_format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Image process driver + */ +typedef struct image_process_driver_s image_process_driver_t; + +/** + * @brief Image process driver + */ +struct image_process_driver_s { + + /** + * @brief Process segments + * + * @param[in] data image meta data + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_INVALID_STATE: invalid state + */ + esp_err_t (*process_segments)(esp_image_metadata_t *data); +}; + +/** + * @brief Image process flow + * @note This API first reads the image header, then process the segments from the image header. + * This API can be further inserted with more steps about the image processing by registering + * more function pointer in `image_process_driver_t`. + * + * @return + * - ESP_OK + * - ESP_FAIL: image process flow fails + */ +esp_err_t image_process(void); + +/** + * @brief get flash segments info, only available after image_process() has been called + * + * @param[out] out_drom_paddr_start drom paddr start + * @param[out] out_irom_paddr_start irom paddr start + */ +void image_process_get_flash_segments_info(uint32_t *out_drom_paddr_start, uint32_t *out_irom_paddr_start); + +#ifdef __cplusplus +} +#endif diff --git a/components/bootloader_support/linker.lf b/components/bootloader_support/linker.lf new file mode 100644 index 00000000000..d2cf44a6e01 --- /dev/null +++ b/components/bootloader_support/linker.lf @@ -0,0 +1,5 @@ +[mapping:bootloader_support] +archive: libbootloader_support.a +entries: + if APP_BUILD_TYPE_RAM = n: + image_process (noflash) diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index 7aad0fa5b5a..9089dce1bb1 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -25,6 +25,7 @@ #include "soc/rtc_periph.h" #include "soc/timer_periph.h" #include "hal/mmu_hal.h" +#include "hal/mmu_ll.h" #include "hal/cache_types.h" #include "hal/cache_ll.h" #include "hal/cache_hal.h" @@ -43,6 +44,7 @@ #include "bootloader_sha.h" #include "bootloader_console.h" #include "bootloader_soc.h" +#include "bootloader_memory_utils.h" #include "esp_efuse.h" #include "esp_fault.h" @@ -715,10 +717,20 @@ static void unpack_load_app(const esp_image_metadata_t *data) // Find DROM & IROM addresses, to configure MMU mappings for (int i = 0; i < data->image.segment_count; i++) { const esp_image_segment_header_t *header = &data->segments[i]; + bool text_or_rodata = false; + //`SOC_DROM_LOW` and `SOC_DROM_HIGH` are the same as `SOC_IROM_LOW` and `SOC_IROM_HIGH`, reasons are in above `note` if (header->load_addr >= SOC_DROM_LOW && header->load_addr < SOC_DROM_HIGH) { + text_or_rodata = true; + } +#if SOC_MMU_PER_EXT_MEM_TARGET + if (header->load_addr >= SOC_EXTRAM_LOW && header->load_addr < SOC_EXTRAM_HIGH) { + text_or_rodata = true; + } +#endif + if (text_or_rodata) { /** - * D/I are shared, but there should not be a third segment on flash + * D/I are shared, but there should not be a third segment on flash/psram */ assert(rom_index < 2); rom_addr[rom_index] = data->segment_data[i]; @@ -785,6 +797,20 @@ static void unpack_load_app(const esp_image_metadata_t *data) } #endif //#if SOC_MMU_DI_VADDR_SHARED +//unused for esp32 +__attribute__((unused)) +static bool s_flash_seg_needs_map(uint32_t vaddr) +{ +#if SOC_MMU_PER_EXT_MEM_TARGET + //For these chips, segments on PSRAM will be mapped in app + bool is_psram = esp_ptr_in_extram((void *)vaddr); + return !is_psram; +#else + //For these chips, segments on Flash always need to be mapped + return true; +#endif +} + static void set_cache_and_start_app( uint32_t drom_addr, uint32_t drom_load_addr, @@ -822,8 +848,13 @@ static void set_cache_and_start_app( ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, drom_page_count * SPI_FLASH_MMU_PAGE_SIZE); #else uint32_t actual_mapped_len = 0; - mmu_hal_map_region(0, MMU_TARGET_FLASH0, drom_load_addr_aligned, drom_addr_aligned, drom_size, &actual_mapped_len); - ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len); + if (s_flash_seg_needs_map(drom_load_addr_aligned)) { + mmu_hal_map_region(0, MMU_TARGET_FLASH0, drom_load_addr_aligned, drom_addr_aligned, drom_size, &actual_mapped_len); + ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len); + } + //we use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition + mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_LL_END_DROM_ENTRY_VADDR, drom_addr_aligned, CONFIG_MMU_PAGE_SIZE, &actual_mapped_len); + ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len); #endif //-----------------------MAP IROM-------------------------- @@ -840,8 +871,10 @@ static void set_cache_and_start_app( ESP_LOGV(TAG, "rc=%d", rc); ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, irom_page_count * SPI_FLASH_MMU_PAGE_SIZE); #else - mmu_hal_map_region(0, MMU_TARGET_FLASH0, irom_load_addr_aligned, irom_addr_aligned, irom_size, &actual_mapped_len); - ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, actual_mapped_len); + if (s_flash_seg_needs_map(irom_load_addr_aligned)) { + mmu_hal_map_region(0, MMU_TARGET_FLASH0, irom_load_addr_aligned, irom_addr_aligned, irom_size, &actual_mapped_len); + ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, actual_mapped_len); + } #endif //----------------------Enable corresponding buses---------------- diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 03bb2b0f1ef..60498bab4e0 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -771,8 +771,14 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header static bool should_map(uint32_t load_addr) { - return (load_addr >= SOC_IROM_LOW && load_addr < SOC_IROM_HIGH) - || (load_addr >= SOC_DROM_LOW && load_addr < SOC_DROM_HIGH); + bool is_irom = (load_addr >= SOC_IROM_LOW) && (load_addr < SOC_IROM_HIGH); + bool is_drom = (load_addr >= SOC_DROM_LOW) && (load_addr < SOC_DROM_HIGH); + bool is_psram = false; +#if SOC_MMU_PER_EXT_MEM_TARGET + is_psram = (load_addr >= SOC_EXTRAM_LOW) && (load_addr < SOC_EXTRAM_HIGH); +#endif + + return (is_irom || is_drom || is_psram); } static bool should_load(uint32_t load_addr) @@ -857,7 +863,7 @@ static esp_err_t process_appended_hash_and_sig(esp_image_metadata_t *data, uint3 // Case I: Bootloader part if (part_offset == ESP_BOOTLOADER_OFFSET) { - // For bootloader with secure boot v1, signature stays in an independant flash + // For bootloader with secure boot v1, signature stays in an independent flash // sector (offset 0x0) and does not get appended to the image. #if CONFIG_SECURE_BOOT_V2_ENABLED // Sanity check - secure boot v2 signature block starts on 4K boundary diff --git a/components/bootloader_support/src/image_process.c b/components/bootloader_support/src/image_process.c new file mode 100644 index 00000000000..4c0100e4747 --- /dev/null +++ b/components/bootloader_support/src/image_process.c @@ -0,0 +1,215 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_types.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_check.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_image_format.h" +#include "esp_app_format.h" +#include "esp_flash_partitions.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "hal/mmu_hal.h" +#include "hal/mmu_ll.h" +#include "soc/soc.h" +#include "soc/soc_caps.h" +#include "soc/ext_mem_defs.h" +#include "esp_private/image_process.h" +#include "esp_private/esp_cache_esp32_private.h" + +#if CONFIG_IDF_TARGET_ESP32 +#define MMAP_MMU_SIZE 0x320000 +#elif CONFIG_IDF_TARGET_ESP32S2 +#define MMAP_MMU_SIZE (SOC_DRAM0_CACHE_ADDRESS_HIGH - SOC_DRAM0_CACHE_ADDRESS_LOW) +#else +#define MMAP_MMU_SIZE (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_DRAM_FLASH_ADDRESS_LOW) +#endif + +#if CONFIG_IDF_TARGET_ESP32 +#define FLASH_READ_VADDR (SOC_DROM_LOW + MMAP_MMU_SIZE) +#else +#define FLASH_READ_VADDR (SOC_DROM_LOW + MMAP_MMU_SIZE - CONFIG_MMU_PAGE_SIZE) +#endif + +#define MMU_FLASH_MASK (~(CONFIG_MMU_PAGE_SIZE - 1)) + +const static char *TAG = "image_process"; + +static uint32_t s_current_read_mapping = UINT32_MAX; +static uint32_t s_flash_drom_paddr_start = 0; +static uint32_t s_flash_irom_paddr_start = 0; +static esp_err_t process_segments(esp_image_metadata_t *data); + +static image_process_driver_t s_image_process_driver = { + process_segments, +}; + +static esp_err_t flash_read(size_t src_addr, void *dest, size_t size) +{ + if (src_addr & 3) { + ESP_EARLY_LOGE(TAG, "flash_read src_addr 0x%x not 4-byte aligned", src_addr); + return ESP_ERR_INVALID_ARG; + } + if (size & 3) { + ESP_EARLY_LOGE(TAG, "flash_read size 0x%x not 4-byte aligned", size); + return ESP_ERR_INVALID_ARG; + } + if ((intptr_t)dest & 3) { + ESP_EARLY_LOGE(TAG, "flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest); + return ESP_ERR_INVALID_ARG; + } + + uint32_t *dest_words = (uint32_t *)dest; + + for (size_t word = 0; word < size / 4; word++) { + uint32_t word_src = src_addr + word * 4; /* Read this offset from flash */ + uint32_t map_at = word_src & MMU_FLASH_MASK; /* Map this 64KB block from flash */ + uint32_t *map_ptr; + + /* Move the 64KB mmu mapping window to fit map_at */ + if (map_at != s_current_read_mapping) { + + cache_hal_suspend(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); + uint32_t actual_mapped_len = 0; + mmu_hal_map_region(0, MMU_TARGET_FLASH0, FLASH_READ_VADDR, map_at, CONFIG_MMU_PAGE_SIZE - 1, &actual_mapped_len); + s_current_read_mapping = map_at; + ESP_EARLY_LOGD(TAG, "starting from paddr=0x%" PRIx32 " and vaddr=0x%" PRIx32 ", 0x%" PRIx32 " bytes are mapped", map_at, FLASH_READ_VADDR, actual_mapped_len); +#if CONFIG_IDF_TARGET_ESP32 + cache_sync(); +#else + cache_hal_invalidate_addr(FLASH_READ_VADDR, actual_mapped_len); +#endif + cache_hal_resume(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); + } + map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at)); + dest_words[word] = *map_ptr; + } + + return ESP_OK; +} + +static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset) +{ + bzero(data, sizeof(esp_image_metadata_t)); + data->start_addr = part_offset; + + ESP_RETURN_ON_ERROR_ISR(flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t)), TAG, "failed to read image"); + data->image_len = sizeof(esp_image_header_t); + ESP_EARLY_LOGD(TAG, "reading image header=0x%"PRIx32" image_len=0x%"PRIx32" image.segment_count=0x%x", data->start_addr, data->image_len, data->image.segment_count); + + return ESP_OK; +} + +static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, esp_image_metadata_t *metadata, int *cnt) +{ + /* read segment header */ + ESP_RETURN_ON_ERROR_ISR(flash_read(flash_addr, header, sizeof(esp_image_segment_header_t)), TAG, "failed to do flash read"); + + intptr_t load_addr = header->load_addr; + uint32_t data_len = header->data_len; + uint32_t data_addr = flash_addr + sizeof(esp_image_segment_header_t); + +#if SOC_MMU_DI_VADDR_SHARED +#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM + if (load_addr >= SOC_DRAM_PSRAM_ADDRESS_LOW && load_addr < SOC_DRAM_PSRAM_ADDRESS_HIGH) { + if (*cnt == 0) { + s_flash_drom_paddr_start = data_addr; + } else if (*cnt == 1) { + s_flash_irom_paddr_start = data_addr; + } + (*cnt)++; + } +#else + if (load_addr >= SOC_DRAM_FLASH_ADDRESS_LOW && load_addr < SOC_DRAM_FLASH_ADDRESS_HIGH) { + if (*cnt == 0) { + s_flash_drom_paddr_start = data_addr; + } else if (*cnt == 1) { + s_flash_irom_paddr_start = data_addr; + } + (*cnt)++; + } +#endif +#else + if (load_addr >= SOC_IRAM_FLASH_ADDRESS_LOW && load_addr < SOC_IRAM_FLASH_ADDRESS_HIGH) { + s_flash_drom_paddr_start = data_addr; + (*cnt)++; + } + if (load_addr >= SOC_DRAM_FLASH_ADDRESS_LOW && load_addr < SOC_DRAM_FLASH_ADDRESS_HIGH) { + s_flash_irom_paddr_start = data_addr; + (*cnt)++; + } +#endif + + ESP_EARLY_LOGD(TAG, "load_addr: %x, data_len: %x, flash_addr: 0x%x, data_addr: %x", load_addr, data_len, flash_addr, data_addr); + if (data_len % 4 != 0) { + ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "unaligned segment length 0x%"PRIx32, data_len); + } + + return ESP_OK; +} + +static esp_err_t process_segments(esp_image_metadata_t *data) +{ + uint32_t start_segments = data->start_addr + data->image_len; + uint32_t next_addr = start_segments; + int cnt = 0; + + for (int i = 0; i < data->image.segment_count; i++) { + esp_image_segment_header_t *header = &data->segments[i]; + ESP_EARLY_LOGD(TAG, "loading segment header %d at offset 0x%"PRIx32, i, next_addr); + ESP_RETURN_ON_ERROR_ISR(process_segment(i, next_addr, header, data, &cnt), TAG, "failed to process segment"); + next_addr += sizeof(esp_image_segment_header_t); + data->segment_data[i] = next_addr; + next_addr += header->data_len; + } + assert(cnt == 2); + + uint32_t end_addr = next_addr; + if (end_addr < data->start_addr) { + return ESP_FAIL; + } + + data->image_len += end_addr - start_segments; + + return ESP_OK; +} + +void image_process_get_flash_segments_info(uint32_t *out_drom_paddr_start, uint32_t *out_irom_paddr_start) +{ + assert(out_drom_paddr_start && out_irom_paddr_start); + *out_drom_paddr_start = s_flash_drom_paddr_start; + *out_irom_paddr_start = s_flash_irom_paddr_start; +} + +esp_err_t image_process(void) +{ + esp_err_t ret = ESP_FAIL; + /** + * We use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition + * This depends on 2nd bootloader to set the entry + */ + uint32_t paddr_base = mmu_ll_entry_id_to_paddr_base(0, MMU_LL_END_DROM_ENTRY_ID); + uint32_t part_offset = paddr_base; + esp_image_metadata_t image_data = {0}; + ret = process_image_header(&image_data, part_offset); + if (ret != ESP_OK) { + ESP_EARLY_LOGE(TAG, "failed to process image header"); + abort(); + } + + ret = s_image_process_driver.process_segments(&image_data); + if (ret != ESP_OK) { + ESP_EARLY_LOGE(TAG, "failed to process segments"); + return ESP_FAIL; + } + + mmu_ll_set_entry_invalid(0, MMU_LL_END_DROM_ENTRY_ID); + + return ESP_OK; +} diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index db2c68dadd8..d42a328190d 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -185,7 +185,7 @@ idf_component_register(SRCS ${srcs} PRIV_INCLUDE_DIRS port/include include/esp_private REQUIRES ${requires} PRIV_REQUIRES "${priv_requires}" - LDFRAGMENTS linker.lf dma/linker.lf) + LDFRAGMENTS linker.lf dma/linker.lf ldo/linker.lf) idf_build_get_property(target IDF_TARGET) add_subdirectory(port/${target}) diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c index 4866b65a8eb..a8b2560abb8 100644 --- a/components/esp_hw_support/clk_ctrl_os.c +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -10,6 +10,8 @@ #include "esp_ldo_regulator.h" #include "esp_private/esp_clk_tree_common.h" #include "esp_check.h" +#include "hal/clk_tree_hal.h" +#include "hal/clk_tree_ll.h" #if SOC_CLK_MPLL_SUPPORTED #include "rtc_clk.h" #endif @@ -137,7 +139,7 @@ esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq) #endif // SOC_CLK_APLL_SUPPORTED #if SOC_CLK_MPLL_SUPPORTED -esp_err_t periph_rtc_mpll_acquire(void) +esp_err_t IRAM_ATTR periph_rtc_mpll_acquire(void) { // power up LDO for the MPLL #if defined(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN) && CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN != -1 @@ -176,7 +178,7 @@ void periph_rtc_mpll_release(void) portEXIT_CRITICAL(&periph_spinlock); } -esp_err_t periph_rtc_mpll_freq_set(uint32_t expt_freq, uint32_t *real_freq) +esp_err_t IRAM_ATTR periph_rtc_mpll_freq_set(uint32_t expt_freq, uint32_t *real_freq) { esp_err_t ret = ESP_OK; @@ -190,10 +192,9 @@ esp_err_t periph_rtc_mpll_freq_set(uint32_t expt_freq, uint32_t *real_freq) /* If MPLL is not in use or only one peripheral in use, its frequency can be changed as will * But when more than one peripheral refers MPLL, its frequency is not allowed to change once it is set */ if (s_cur_mpll_freq == 0 || s_mpll_ref_cnt < 2) { - uint32_t xtal_freq = 0; - ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_freq)); - rtc_clk_mpll_configure(xtal_freq / MHZ, expt_freq / MHZ); - ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_MPLL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &s_cur_mpll_freq)); + uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); + rtc_clk_mpll_configure(xtal_freq_mhz, expt_freq / MHZ); + s_cur_mpll_freq = clk_ll_mpll_get_freq_mhz(xtal_freq_mhz); } else { ret = ESP_ERR_INVALID_STATE; } diff --git a/components/esp_hw_support/ldo/linker.lf b/components/esp_hw_support/ldo/linker.lf new file mode 100644 index 00000000000..462edd8b930 --- /dev/null +++ b/components/esp_hw_support/ldo/linker.lf @@ -0,0 +1,6 @@ +[mapping:ldo_driver] +archive: libesp_hw_support.a +entries: + if SOC_GP_LDO_SUPPORTED = y: + if SPIRAM_FLASH_LOAD_TO_PSRAM = y: + esp_ldo_regulator: esp_ldo_acquire_channel (noflash) diff --git a/components/esp_lcd/test_apps/rgb_lcd/sdkconfig.defaults.esp32s3 b/components/esp_lcd/test_apps/rgb_lcd/sdkconfig.defaults.esp32s3 index 36a4a647ea7..aea303d4f9e 100644 --- a/components/esp_lcd/test_apps/rgb_lcd/sdkconfig.defaults.esp32s3 +++ b/components/esp_lcd/test_apps/rgb_lcd/sdkconfig.defaults.esp32s3 @@ -3,5 +3,4 @@ CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_SPEED_80M=y # Enable the XIP-PSRAM feature, so the ext-mem cache won't be disabled when SPI1 is operating the main flash -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c index 24e06c5298c..226ec38e0c9 100644 --- a/components/esp_mm/esp_mmu_map.c +++ b/components/esp_mm/esp_mmu_map.c @@ -38,7 +38,7 @@ #define MEM_REGION_MERGED -1 /** - * We have some hw related tests for vaddr region capabilites + * We have some hw related tests for vaddr region capabilities * Use this macro to disable paddr check as we need to reuse certain paddr blocks */ #define ENABLE_PADDR_CHECK !ESP_MMAP_TEST_ALLOW_MAP_TO_MAPPED_PADDR @@ -185,6 +185,13 @@ static void s_reserve_drom_region(mem_region_t *hw_mem_regions, int region_nums) } #endif //#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +#if SOC_MMU_PER_EXT_MEM_TARGET +static inline uint32_t s_get_mmu_id_from_target(mmu_target_t target) +{ + return (target == MMU_TARGET_FLASH0) ? MMU_LL_FLASH_MMU_ID : MMU_LL_PSRAM_MMU_ID; +} +#endif + void esp_mmu_map_init(void) { mem_region_t hw_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = {}; @@ -381,16 +388,11 @@ static void IRAM_ATTR NOINLINE_ATTR s_do_cache_invalidate(uint32_t vaddr_start, #endif // CONFIG_IDF_TARGET_ESP32 } -#if MMU_LL_MMU_PER_TARGET +#if SOC_MMU_PER_EXT_MEM_TARGET FORCE_INLINE_ATTR uint32_t s_mapping_operation(mmu_target_t target, uint32_t vaddr_start, esp_paddr_t paddr_start, uint32_t size) { uint32_t actual_mapped_len = 0; - uint32_t mmu_id = 0; - if (target == MMU_TARGET_FLASH0) { - mmu_id = MMU_LL_FLASH_MMU_ID; - } else { - mmu_id = MMU_LL_PSRAM_MMU_ID; - } + uint32_t mmu_id = s_get_mmu_id_from_target(target); mmu_hal_map_region(mmu_id, target, vaddr_start, paddr_start, size, &actual_mapped_len); return actual_mapped_len; @@ -584,17 +586,11 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target, return ret; } -#if MMU_LL_MMU_PER_TARGET +#if SOC_MMU_PER_EXT_MEM_TARGET FORCE_INLINE_ATTR void s_unmapping_operation(uint32_t vaddr_start, uint32_t size) { - uint32_t mmu_id = 0; mmu_target_t target = mmu_ll_vaddr_to_target(vaddr_start); - - if (target == MMU_TARGET_FLASH0) { - mmu_id = MMU_LL_FLASH_MMU_ID; - } else { - mmu_id = MMU_LL_PSRAM_MMU_ID; - } + uint32_t mmu_id = s_get_mmu_id_from_target(target); mmu_hal_unmap_region(mmu_id, vaddr_start, size); } #else @@ -748,8 +744,12 @@ static bool NOINLINE_ATTR IRAM_ATTR s_vaddr_to_paddr(uint32_t vaddr, esp_paddr_t { //we call this for now, but this will be refactored to move out of `spi_flash` spi_flash_disable_interrupts_caches_and_other_cpu(); - //On ESP32, core 1 settings should be the same as the core 0 bool is_mapped = mmu_hal_vaddr_to_paddr(0, vaddr, out_paddr, out_target); +#if SOC_MMU_PER_EXT_MEM_TARGET + if (!is_mapped) { + is_mapped = mmu_hal_vaddr_to_paddr(1, vaddr, out_paddr, out_target); + } +#endif spi_flash_enable_interrupts_caches_and_other_cpu(); return is_mapped; @@ -776,8 +776,11 @@ static bool NOINLINE_ATTR IRAM_ATTR s_paddr_to_vaddr(esp_paddr_t paddr, mmu_targ { //we call this for now, but this will be refactored to move out of `spi_flash` spi_flash_disable_interrupts_caches_and_other_cpu(); - //On ESP32, core 1 settings should be the same as the core 0 - bool found = mmu_hal_paddr_to_vaddr(0, paddr, target, type, out_vaddr); + uint32_t mmu_id = 0; +#if SOC_MMU_PER_EXT_MEM_TARGET + mmu_id = s_get_mmu_id_from_target(target); +#endif + bool found = mmu_hal_paddr_to_vaddr(mmu_id, paddr, target, type, out_vaddr); spi_flash_enable_interrupts_caches_and_other_cpu(); return found; diff --git a/components/esp_mm/linker.lf b/components/esp_mm/linker.lf index a48fe34cbf9..1af07775ddb 100644 --- a/components/esp_mm/linker.lf +++ b/components/esp_mm/linker.lf @@ -7,3 +7,10 @@ entries: if IDF_TARGET_ESP32 = y: cache_esp32 (noflash) + + if SPIRAM_FLASH_LOAD_TO_PSRAM = y: + esp_mmu_map: s_get_bus_mask (noflash) + esp_mmu_map: s_reserve_irom_region (noflash) + esp_mmu_map: s_reserve_drom_region (noflash) + esp_mmu_map: esp_mmu_map_init (noflash) + ext_mem_layout (noflash) diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index 41068ce78d4..9083aca4440 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -8,7 +8,6 @@ set(includes "include") set(priv_requires heap spi_flash esp_mm) if(${target} STREQUAL "esp32") - list(APPEND priv_requires bootloader_support) # [refactor-todo]: requires "driver" for `spicommon_periph_claim` list(APPEND priv_requires driver) endif() @@ -16,14 +15,25 @@ endif() set(srcs) if(CONFIG_SPIRAM) - list(APPEND srcs "esp_psram.c" - "mmu_psram_flash.c") + list(APPEND srcs "esp_psram.c") if(${target} STREQUAL "esp32") list(APPEND srcs "esp32/esp_psram_extram_cache.c" "esp32/esp_himem.c") endif() + if(${target} STREQUAL "esp32s2") + list(APPEND srcs "mmu_psram_flash.c") + endif() + + if(${target} STREQUAL "esp32s3") + list(APPEND srcs "mmu_psram_flash.c") + endif() + + if(CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM) + list(APPEND srcs "mmu_psram_flash_v2.c") + endif() + if(CONFIG_SPIRAM_MODE_QUAD) list(APPEND srcs "${target}/esp_psram_impl_quad.c") elseif(CONFIG_SPIRAM_MODE_OCT) diff --git a/components/esp_psram/esp32p4/Kconfig.spiram b/components/esp_psram/esp32p4/Kconfig.spiram index ea37e7f54b7..b83d0acefde 100644 --- a/components/esp_psram/esp32p4/Kconfig.spiram +++ b/components/esp_psram/esp32p4/Kconfig.spiram @@ -44,6 +44,40 @@ menu "PSRAM config" default 100 if SPIRAM_SPEED_100M default 200 if SPIRAM_SPEED_200M + config SPIRAM_FETCH_INSTRUCTIONS + bool + help + Enable this option allows moving application's instruction segment from the SPI Flash to + PSRAM + + config SPIRAM_RODATA + bool + help + Enable this option allows moving application's rodata segment from the SPI Flash to + PSRAM + + config SPIRAM_XIP_FROM_PSRAM + bool "Enable Executable in place from (XiP) from PSRAM feature" + default n + select SPIRAM_FETCH_INSTRUCTIONS + select SPIRAM_RODATA + select SPIRAM_FLASH_LOAD_TO_PSRAM + help + If enabled, firmware in flash including instructions and data will be moved into PSRAM on startup, + firmware code will execute directly from PSRAM. + + With this option enabled, code that requires execution during an MSPI1 Flash operation + does not have to be placed in IRAM. Therefore codes that need to be executing during Flash + operations can continue working normally. + + Enabling this option will have better performance (see External RAM documentation for more details). + + config SPIRAM_FLASH_LOAD_TO_PSRAM + bool + help + This is a helper indicating this condition: + `CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_IDF_TARGET_ESP32P4` + config SPIRAM_ECC_ENABLE bool "Enable PSRAM ECC" default n diff --git a/components/esp_psram/esp32s2/Kconfig.spiram b/components/esp_psram/esp32s2/Kconfig.spiram index e732ac147b7..1af865756aa 100644 --- a/components/esp_psram/esp32s2/Kconfig.spiram +++ b/components/esp_psram/esp32s2/Kconfig.spiram @@ -47,25 +47,39 @@ menu "SPI RAM config" int default 26 + config SPIRAM_XIP_FROM_PSRAM + bool "Enable Executable in place from (XiP) from PSRAM feature" + default n + select SPIRAM_FETCH_INSTRUCTIONS + select SPIRAM_RODATA + help + Helper for selecting both `SPIRAM_FETCH_INSTRUCTIONS` and `SPIRAM_RODATA` + config SPIRAM_FETCH_INSTRUCTIONS bool "Move Instructions in Flash to PSRAM" default n help If enabled, instructions in flash will be moved into PSRAM on startup. - If SPIRAM_RODATA is also enabled, code that requires execution during an SPI1 Flash operation - can forgo being placed in IRAM, thus optimizing RAM usage (see External RAM documentation - for more details). + If SPIRAM_RODATA is also enabled, code that requires execution during an MSPI1 Flash operation + can forgo being placed in IRAM. Therefore codes that need to be executing during Flash + operation can continue working normally. + This feature is useful for high throughput peripheral involved applications to improve + the performance during MSPI1 flash operations. PSRAM access speed is faster than Flash access. + So the performance is better. (see External RAM documentation for more details). config SPIRAM_RODATA bool "Move Read-Only Data in Flash to PSRAM" default n help If enabled, rodata in flash will be moved into PSRAM on startup. - If SPIRAM_FETCH_INSTRUCTIONS is also enabled, code that requires execution during an SPI1 Flash operation - can forgo being placed in IRAM, thus optimizing RAM usage (see External RAM documentation - for more details). + If SPIRAM_FETCH_INSTRUCTIONS is also enabled, code that requires execution during an MSPI1 Flash operation + is not necessary to be placed in IRAM. Therefore codes that need to be executing during Flash + operation can continue working normally. + This feature is useful for high throughput peripheral involved applications to improve + the performance during MSPI1 flash operations. PSRAM access speed is faster than Flash access. + So the performance is better. (see External RAM documentation for more details). choice SPIRAM_SPEED prompt "Set RAM clock speed" diff --git a/components/esp_psram/esp32s3/Kconfig.spiram b/components/esp_psram/esp32s3/Kconfig.spiram index fe97ed014f7..8152ff680a0 100644 --- a/components/esp_psram/esp32s3/Kconfig.spiram +++ b/components/esp_psram/esp32s3/Kconfig.spiram @@ -56,24 +56,39 @@ menu "SPI RAM config" int default 26 + config SPIRAM_XIP_FROM_PSRAM + bool "Enable Executable in place from (XiP) from PSRAM feature" + default n + select SPIRAM_FETCH_INSTRUCTIONS + select SPIRAM_RODATA + help + Helper for selecting both `SPIRAM_FETCH_INSTRUCTIONS` and `SPIRAM_RODATA` + config SPIRAM_FETCH_INSTRUCTIONS bool "Move Instructions in Flash to PSRAM" default n help If enabled, instructions in flash will be moved into PSRAM on startup. - If SPIRAM_RODATA is also enabled, code that requires execution during an SPI1 Flash operation - can forgo being placed in IRAM, thus optimizing RAM usage (see External RAM documentation - for more details). + If SPIRAM_RODATA is also enabled, code that requires execution during an MSPI1 Flash operation + can forgo being placed in IRAM. Therefore codes that need to be executing during Flash + operation can continue working normally. + This feature is useful for high throughput peripheral involved applications to improve + the performance during MSPI1 flash operations. PSRAM access speed is faster than Flash access. + So the performance is better. (see External RAM documentation for more details). config SPIRAM_RODATA bool "Move Read-Only Data in Flash to PSRAM" default n help If enabled, rodata in flash will be moved into PSRAM on startup. - If SPIRAM_FETCH_INSTRUCTIONS is also enabled, code that requires execution during an SPI1 Flash operation - can forgo being placed in IRAM, thus optimizing RAM usage (see External RAM documentation - for more details). + If SPIRAM_FETCH_INSTRUCTIONS is also enabled, code that requires execution during an MSPI1 Flash operation + is not necessary to be placed in IRAM. Therefore codes that need to be executing during Flash + operation can continue working normally. + + This feature is useful for high throughput peripheral involved applications to improve + the performance during MSPI1 flash operations. PSRAM access speed is faster than Flash access. + So the performance is better. (see External RAM documentation for more details). choice SPIRAM_SPEED prompt "Set RAM clock speed" diff --git a/components/esp_psram/esp_psram.c b/components/esp_psram/esp_psram.c index 7064c84b2bd..23cd5f1b59f 100644 --- a/components/esp_psram/esp_psram.c +++ b/components/esp_psram/esp_psram.c @@ -5,7 +5,7 @@ */ /*---------------------------------------------------------------------------------------------------- - * Abstraction layer for PSRAM. PSRAM device related registers and MMU/Cache related code shouls be + * Abstraction layer for PSRAM. PSRAM device related registers and MMU/Cache related code should be * abstracted to lower layers. * * When we add more types of external RAM memory, this can be made into a more intelligent dispatcher. @@ -20,6 +20,7 @@ #include "hal/mmu_hal.h" #include "hal/mmu_ll.h" #include "hal/cache_ll.h" +#include "soc/soc_caps.h" #include "esp_private/esp_psram_io.h" #include "esp_private/esp_psram_extram.h" #include "esp_private/mmu_psram_flash.h" @@ -43,6 +44,12 @@ #define PSRAM_MEM_8BIT_ALIGNED 0 #define PSRAM_MEM_32BIT_ALIGNED 1 +#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM +#define PSRAM_EARLY_LOGI ESP_DRAM_LOGI +#else +#define PSRAM_EARLY_LOGI ESP_EARLY_LOGI +#endif + #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY extern uint8_t _ext_ram_bss_start; extern uint8_t _ext_ram_bss_end; @@ -80,7 +87,7 @@ typedef struct { } psram_ctx_t; static psram_ctx_t s_psram_ctx; -static const char* TAG = "esp_psram"; +static const DRAM_ATTR char TAG[] = "esp_psram"; ESP_SYSTEM_INIT_FN(init_psram, CORE, BIT(0), 103) { @@ -120,7 +127,7 @@ static void IRAM_ATTR s_mapping(int v_start, int size) } #endif //CONFIG_IDF_TARGET_ESP32 -esp_err_t esp_psram_init(void) +static esp_err_t s_psram_chip_init(uint32_t *out_available_size) { if (s_psram_ctx.is_initialised) { return ESP_ERR_INVALID_STATE; @@ -140,8 +147,8 @@ esp_err_t esp_psram_init(void) ret = esp_psram_impl_get_physical_size(&psram_physical_size); assert(ret == ESP_OK); - ESP_EARLY_LOGI(TAG, "Found %" PRIu32 "MB PSRAM device", psram_physical_size / (1024 * 1024)); - ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED); + PSRAM_EARLY_LOGI(TAG, "Found %" PRIu32 "MB PSRAM device", psram_physical_size / (1024 * 1024)); + PSRAM_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED); #if CONFIG_IDF_TARGET_ESP32 #if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in normal (1-core) mode."); @@ -154,7 +161,16 @@ esp_err_t esp_psram_init(void) ret = esp_psram_impl_get_available_size(&psram_available_size); assert(ret == ESP_OK); - __attribute__((unused)) uint32_t total_available_size = psram_available_size; + *out_available_size = psram_available_size; + + return ESP_OK; +} + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA +static void s_xip_psram_placement(uint32_t *psram_available_size, uint32_t *out_start_page) +{ + __attribute__((unused)) uint32_t total_available_size = *psram_available_size; + uint32_t available_size = *psram_available_size; /** * `start_page` is the psram physical address in MMU page size. * MMU page size on ESP32S2 is 64KB @@ -162,10 +178,21 @@ esp_err_t esp_psram_init(void) * * Here we plan to copy FLASH instructions to psram physical address 0, which is the No.0 page. */ - __attribute__((unused)) uint32_t start_page = 0; -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA + uint32_t start_page = 0; uint32_t used_page = 0; -#endif + esp_err_t ret = ESP_FAIL; + + //------------------------------------Copy Flash .rodata to PSRAM-------------------------------------// +#if CONFIG_SPIRAM_RODATA + ret = mmu_config_psram_rodata_segment(start_page, total_available_size, &used_page); + if (ret != ESP_OK) { + ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!"); + abort(); + } + start_page += used_page; + available_size -= MMU_PAGE_TO_BYTES(used_page); + ESP_EARLY_LOGV(TAG, "after copy .rodata, used page is %d, start_page is %d, available_size is %d B", used_page, start_page, available_size); +#endif //#if CONFIG_SPIRAM_RODATA //------------------------------------Copy Flash .text to PSRAM-------------------------------------// #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS @@ -175,22 +202,18 @@ esp_err_t esp_psram_init(void) abort(); } start_page += used_page; - psram_available_size -= MMU_PAGE_TO_BYTES(used_page); + available_size -= MMU_PAGE_TO_BYTES(used_page); ESP_EARLY_LOGV(TAG, "after copy .text, used page is %" PRIu32 ", start_page is %" PRIu32 ", psram_available_size is %" PRIu32 " B", used_page, start_page, psram_available_size); #endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - //------------------------------------Copy Flash .rodata to PSRAM-------------------------------------// -#if CONFIG_SPIRAM_RODATA - ret = mmu_config_psram_rodata_segment(start_page, total_available_size, &used_page); - if (ret != ESP_OK) { - ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!"); - abort(); - } - start_page += used_page; - psram_available_size -= MMU_PAGE_TO_BYTES(used_page); - ESP_EARLY_LOGV(TAG, "after copy .rodata, used page is %" PRIu32 ", start_page is %" PRIu32 ", psram_available_size is %" PRIu32 " B", used_page, start_page, psram_available_size); -#endif //#if CONFIG_SPIRAM_RODATA + *psram_available_size = available_size; + *out_start_page = start_page; +} +#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA +static void s_psram_mapping(uint32_t psram_available_size, uint32_t start_page) +{ + esp_err_t ret = ESP_FAIL; //----------------------------------Map the PSRAM physical range to MMU-----------------------------// /** * @note 2 @@ -213,7 +236,7 @@ esp_err_t esp_psram_init(void) s_mapping((int)v_start_8bit_aligned, size_to_map); #else uint32_t actual_mapped_len = 0; -#if MMU_LL_MMU_PER_TARGET +#if SOC_MMU_PER_EXT_MEM_TARGET mmu_hal_map_region(1, MMU_TARGET_PSRAM0, (intptr_t)v_start_8bit_aligned, MMU_PAGE_TO_BYTES(start_page), size_to_map, &actual_mapped_len); #else mmu_hal_map_region(0, MMU_TARGET_PSRAM0, (intptr_t)v_start_8bit_aligned, MMU_PAGE_TO_BYTES(start_page), size_to_map, &actual_mapped_len); @@ -280,7 +303,7 @@ esp_err_t esp_psram_init(void) } /*------------------------------------------------------------------------------ - * After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE! + * After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESS ANYMORE! *----------------------------------------------------------------------------*/ //------------------------------------Configure .bss in PSRAM-------------------------------------// @@ -302,6 +325,31 @@ esp_err_t esp_psram_init(void) #if CONFIG_IDF_TARGET_ESP32 s_psram_ctx.regions_to_heap[PSRAM_MEM_8BIT_ALIGNED].size -= esp_himem_reserved_area_size() - 1; #endif +} + +esp_err_t esp_psram_init(void) +{ + esp_err_t ret = ESP_FAIL; + uint32_t psram_available_size = 0; + ret = s_psram_chip_init(&psram_available_size); + if (ret != ESP_OK) { + return ret; + } + + /** + * `start_page` is the psram physical address in MMU page size. + * MMU page size on ESP32S2 is 64KB + * e.g.: psram physical address 16 is in page 0 + * + * Here we plan to copy FLASH instructions to psram physical address 0, which is the No.0 page. + */ + __attribute__((unused)) uint32_t start_page = 0; + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA + s_xip_psram_placement(&psram_available_size, &start_page); +#endif + + s_psram_mapping(psram_available_size, start_page); //will be removed, TODO: IDF-6944 #if CONFIG_IDF_TARGET_ESP32 diff --git a/components/esp_psram/include/esp_private/mmu_psram_flash.h b/components/esp_psram/include/esp_private/mmu_psram_flash.h index b45b1401000..554ab77d164 100644 --- a/components/esp_psram/include/esp_private/mmu_psram_flash.h +++ b/components/esp_psram/include/esp_private/mmu_psram_flash.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,6 +63,18 @@ esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_si /*---------------------------------------------------------------------------- Part 2 APIs (See @Backgrounds on top of this file) -------------------------------------------------------------------------------*/ +#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM +/** + * TODO: IDF-9049 + * @brief Vaddr to paddr, when XIP on PSRAM + * @note This API only works for the original flash.text and flash.rodata, others vaddrs will return UINT32_MAX + * + * @param[in] ptr Pointer + * + * @return Pointer corresponding physical addr + */ +size_t mmu_xip_psram_flash_vaddr_to_paddr(const void *ptr); +#else #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS /** * @brief Init other file requested MMU variables @@ -130,6 +142,7 @@ uint32_t rodata_flash_end_page_get(void); */ int rodata_flash2spiram_offset(void); #endif // #if CONFIG_SPIRAM_RODATA +#endif // #if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM #ifdef __cplusplus } diff --git a/components/esp_psram/linker.lf b/components/esp_psram/linker.lf index 389c28abcfd..1069e782313 100644 --- a/components/esp_psram/linker.lf +++ b/components/esp_psram/linker.lf @@ -16,3 +16,10 @@ entries: if SPIRAM_MODE_HEX = y: esp_psram_impl_ap_hex (noflash) + + if SPIRAM_FLASH_LOAD_TO_PSRAM = y: + esp_psram_impl_ap_hex (noflash) + mmu_psram_flash_v2 (noflash) + esp_psram: esp_psram_init (noflash) + esp_psram: s_psram_chip_init (noflash) + esp_psram: s_xip_psram_placement (noflash) diff --git a/components/esp_psram/mmu_psram_flash_v2.c b/components/esp_psram/mmu_psram_flash_v2.c new file mode 100644 index 00000000000..0ae669c838a --- /dev/null +++ b/components/esp_psram/mmu_psram_flash_v2.c @@ -0,0 +1,173 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief + * This is for P4 and future chips with similar arch. + * The XIP PSRAM is done by CPU copy, v1(see mmu_psram_flash.c) is done by Cache copy + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "esp_err.h" +#include "soc/ext_mem_defs.h" +#include "hal/mmu_hal.h" +#include "hal/mmu_ll.h" +#include "hal/cache_hal.h" +#include "esp_private/mmu_psram_flash.h" +#include "esp_mmu_map.h" +#include "esp_heap_caps.h" +#include "esp_private/image_process.h" + +#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#define ALIGN_DOWN_BY(num, align) ((num) & (~((align) - 1))) + +extern int _instruction_reserved_start; +extern int _instruction_reserved_end; +extern int _rodata_reserved_start; +extern int _rodata_reserved_end; + +const static char *TAG = "mmu_psram"; +static uint32_t s_irom_vaddr_start; +static uint32_t s_drom_vaddr_start; +static size_t s_irom_size; +static size_t s_drom_size; +static int s_irom_paddr_offset; +static int s_drom_paddr_offset; + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA +static uint32_t s_do_load_from_flash(uint32_t flash_paddr_start, uint32_t size, uint32_t target_vaddr_start, uint32_t target_paddr_start) +{ + uint32_t flash_end_page_vaddr = SOC_DRAM_FLASH_ADDRESS_HIGH - CONFIG_MMU_PAGE_SIZE; + ESP_EARLY_LOGV(TAG, "flash_paddr_start: 0x%"PRIx32", flash_end_page_vaddr: 0x%"PRIx32", size: 0x%"PRIx32", target_vaddr_start: 0x%"PRIx32, flash_paddr_start, flash_end_page_vaddr, size, target_vaddr_start); + assert((flash_paddr_start % CONFIG_MMU_PAGE_SIZE) == 0); + assert((flash_end_page_vaddr % CONFIG_MMU_PAGE_SIZE) == 0); + assert((target_vaddr_start % CONFIG_MMU_PAGE_SIZE) == 0); + + uint32_t mapped_size = 0; + while (mapped_size < size) { + uint32_t actual_mapped_len = 0; + mmu_hal_map_region(MMU_LL_PSRAM_MMU_ID, MMU_TARGET_PSRAM0, target_vaddr_start, target_paddr_start + mapped_size, CONFIG_MMU_PAGE_SIZE, &actual_mapped_len); + assert(actual_mapped_len == CONFIG_MMU_PAGE_SIZE); + + mmu_hal_map_region(MMU_LL_FLASH_MMU_ID, MMU_TARGET_FLASH0, flash_end_page_vaddr, flash_paddr_start + mapped_size, CONFIG_MMU_PAGE_SIZE, &actual_mapped_len); + assert(actual_mapped_len == CONFIG_MMU_PAGE_SIZE); + + cache_hal_invalidate_addr(target_vaddr_start, CONFIG_MMU_PAGE_SIZE); + cache_hal_invalidate_addr(flash_end_page_vaddr, CONFIG_MMU_PAGE_SIZE); + memcpy((void *)target_vaddr_start, (void *)flash_end_page_vaddr, CONFIG_MMU_PAGE_SIZE); + + ESP_EARLY_LOGV(TAG, "target_vaddr_start: 0x%"PRIx32, target_vaddr_start); + mapped_size += CONFIG_MMU_PAGE_SIZE; + target_vaddr_start += CONFIG_MMU_PAGE_SIZE; + } + + ESP_EARLY_LOGV(TAG, "mapped_size: 0x%"PRIx32, mapped_size); + assert(mapped_size == ALIGN_UP_BY(size, CONFIG_MMU_PAGE_SIZE)); + + return mapped_size; +} +#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS +esp_err_t mmu_config_psram_text_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page) +{ + size_t irom_size = ALIGN_UP_BY((uint32_t)&_instruction_reserved_end, CONFIG_MMU_PAGE_SIZE) - ALIGN_DOWN_BY((uint32_t)&_instruction_reserved_start, CONFIG_MMU_PAGE_SIZE); + s_irom_size = irom_size; + + uint32_t flash_drom_paddr_start = 0; + uint32_t flash_irom_paddr_start = 0; + image_process_get_flash_segments_info(&flash_drom_paddr_start, &flash_irom_paddr_start); + flash_irom_paddr_start = ALIGN_DOWN_BY(flash_irom_paddr_start, CONFIG_MMU_PAGE_SIZE); + ESP_EARLY_LOGI(TAG, "flash_irom_paddr_start: 0x%x", flash_irom_paddr_start); + + if ((MMU_PAGE_TO_BYTES(start_page) + irom_size) > psram_size) { + ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash instructions, need %"PRId32" B, from %"PRId32" B to %"PRId32" B", irom_size, MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + irom_size); + return ESP_ERR_NO_MEM; + } + + uint32_t irom_load_addr_aligned = ALIGN_DOWN_BY((uint32_t)&_instruction_reserved_start, CONFIG_MMU_PAGE_SIZE); + s_irom_paddr_offset = flash_irom_paddr_start - MMU_PAGE_TO_BYTES(start_page); + s_irom_vaddr_start = irom_load_addr_aligned; + ESP_EARLY_LOGV(TAG, "flash_irom_paddr_start: 0x%"PRIx32", MMU_PAGE_TO_BYTES(start_page): 0x%"PRIx32", s_irom_paddr_offset: 0x%"PRIx32", s_irom_vaddr_start: 0x%"PRIx32, flash_irom_paddr_start, MMU_PAGE_TO_BYTES(start_page), s_irom_paddr_offset, s_irom_vaddr_start); + + uint32_t mapped_size = 0; + mapped_size = s_do_load_from_flash(flash_irom_paddr_start, irom_size, irom_load_addr_aligned, MMU_PAGE_TO_BYTES(start_page)); + cache_hal_writeback_addr(irom_load_addr_aligned, irom_size); + + ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08"PRIx32" and vaddr=0x%08"PRIx32", 0x%"PRIx32" bytes are mapped", MMU_PAGE_TO_BYTES(start_page), irom_load_addr_aligned, mapped_size); + + start_page += BYTES_TO_MMU_PAGE(irom_size); + *out_page = start_page; + + return ESP_OK; +} +#endif //#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + +#if CONFIG_SPIRAM_RODATA +esp_err_t mmu_config_psram_rodata_segment(uint32_t start_page, uint32_t psram_size, uint32_t *out_page) +{ + size_t drom_size = ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, CONFIG_MMU_PAGE_SIZE) - ALIGN_DOWN_BY((uint32_t)&_rodata_reserved_start, CONFIG_MMU_PAGE_SIZE); + s_drom_size = drom_size; + + uint32_t flash_drom_paddr_start = 0; + uint32_t flash_irom_paddr_start = 0; + image_process_get_flash_segments_info(&flash_drom_paddr_start, &flash_irom_paddr_start); + flash_drom_paddr_start = ALIGN_DOWN_BY(flash_drom_paddr_start, CONFIG_MMU_PAGE_SIZE); + ESP_EARLY_LOGI(TAG, "flash_drom_paddr_start: 0x%x", flash_drom_paddr_start); + + if ((MMU_PAGE_TO_BYTES(start_page) + drom_size) > psram_size) { + ESP_EARLY_LOGE(TAG, "PSRAM space not enough for the Flash rodata, need %"PRId32" B, from %"PRId32" B to %"PRId32" B", drom_size, MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + drom_size); + return ESP_ERR_NO_MEM; + } + + uint32_t drom_load_addr_aligned = ALIGN_DOWN_BY((uint32_t)&_rodata_reserved_start, CONFIG_MMU_PAGE_SIZE); + s_drom_paddr_offset = flash_drom_paddr_start - MMU_PAGE_TO_BYTES(start_page); + s_drom_vaddr_start = drom_load_addr_aligned; + ESP_EARLY_LOGV(TAG, "flash_drom_paddr_start: 0x%"PRIx32", MMU_PAGE_TO_BYTES(start_page): 0x%"PRIx32", s_drom_paddr_offset: 0x%"PRIx32", s_drom_vaddr_start: 0x%"PRIx32, flash_drom_paddr_start, MMU_PAGE_TO_BYTES(start_page), s_drom_paddr_offset, s_drom_vaddr_start); + + uint32_t mapped_size = 0; + mapped_size = s_do_load_from_flash(flash_drom_paddr_start, drom_size, drom_load_addr_aligned, MMU_PAGE_TO_BYTES(start_page)); + cache_hal_writeback_addr(drom_load_addr_aligned, drom_size); + + ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08"PRIx32" and vaddr=0x%08"PRIx32", 0x%"PRIx32" bytes are mapped", MMU_PAGE_TO_BYTES(start_page), drom_load_addr_aligned, mapped_size); + + start_page += BYTES_TO_MMU_PAGE(drom_size); + *out_page = start_page; + + return ESP_OK; +} +#endif //#if CONFIG_SPIRAM_RODATA + +size_t mmu_xip_psram_flash_vaddr_to_paddr(const void *ptr) +{ + if (ptr == NULL) { + return UINT32_MAX; + } + + size_t paddr_on_flash = 0; + uint32_t psram_paddr = 0; + mmu_target_t target = MMU_TARGET_FLASH0; + + if ((uint32_t)ptr >= s_irom_vaddr_start && (uint32_t)ptr < (s_irom_vaddr_start + s_irom_size)) { + bool is_mapped = mmu_hal_vaddr_to_paddr(MMU_LL_PSRAM_MMU_ID, (uint32_t)ptr, &psram_paddr, &target); + assert(is_mapped); + assert(target == MMU_TARGET_PSRAM0); + paddr_on_flash = psram_paddr + s_irom_paddr_offset; + } else if ((uint32_t)ptr >= s_drom_vaddr_start && (uint32_t)ptr < (s_drom_vaddr_start + s_drom_size)) { + bool is_mapped = mmu_hal_vaddr_to_paddr(MMU_LL_PSRAM_MMU_ID, (uint32_t)ptr, &psram_paddr, &target); + assert(is_mapped); + assert(target == MMU_TARGET_PSRAM0); + paddr_on_flash = psram_paddr + s_drom_paddr_offset; + } else { + paddr_on_flash = UINT32_MAX; + } + + return paddr_on_flash; +} diff --git a/components/esp_psram/test_apps/psram/pytest_psram.py b/components/esp_psram/test_apps/psram/pytest_psram.py index 7ceb29e7fb3..327a201311a 100644 --- a/components/esp_psram/test_apps/psram/pytest_psram.py +++ b/components/esp_psram/test_apps/psram/pytest_psram.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @@ -81,6 +80,7 @@ def test_psram_esp32s3_octal(dut: Dut) -> None: 'config', [ 'esp32p4_200m_release', + 'esp32p4_xip' ], indirect=True, ) diff --git a/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32p4_xip b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32p4_xip new file mode 100644 index 00000000000..e163e81b0bf --- /dev/null +++ b/components/esp_psram/test_apps/psram/sdkconfig.ci.esp32p4_xip @@ -0,0 +1,14 @@ +CONFIG_IDF_TARGET="esp32p4" + +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y + +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index eac1a98ced6..80dca0e81d1 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -67,7 +67,8 @@ else() # [refactor-todo] requirements due to init code, # should be removable once using component init functions # link-time registration is used. - bootloader_support esp_pm + esp_pm + REQUIRES bootloader_support LDFRAGMENTS "linker.lf" "app.lf") add_subdirectory(port) diff --git a/components/esp_system/ld/esp32p4/memory.ld.in b/components/esp_system/ld/esp32p4/memory.ld.in index 775ae8ab94b..8c76daee195 100644 --- a/components/esp_system/ld/esp32p4/memory.ld.in +++ b/components/esp_system/ld/esp32p4/memory.ld.in @@ -47,6 +47,10 @@ MEMORY tcm_idram_seg (RX) : org = 0x30100000, len = 0x2000 #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + /* PSRAM mapped instruction data */ + irom_seg (RX) : org = 0x48000020, len = IDROM_SEG_SIZE - 0x20 +#else /* Flash mapped instruction data */ irom_seg (RX) : org = 0x40000020, len = IDROM_SEG_SIZE - 0x20 @@ -57,6 +61,7 @@ MEMORY * header. Setting this offset makes it simple to meet the flash cache MMU's * constraint that (paddr % 64KB == vaddr % 64KB).) */ +#endif // CONFIG_SPIRAM_FETCH_INSTRUCTIONS #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** @@ -68,8 +73,13 @@ MEMORY sram_high (RW) : org = SRAM_HIGH_START, len = SRAM_HIGH_SIZE #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +#if CONFIG_SPIRAM_RODATA + /* PSRAM mapped constant data */ + drom_seg (R) : org = 0x48000020, len = IDROM_SEG_SIZE - 0x20 +#else /* Flash mapped constant data */ drom_seg (R) : org = 0x40000020, len = IDROM_SEG_SIZE - 0x20 +#endif // CONFIG_SPIRAM_RODATA /* (See irom_seg for meaning of 0x20 offset in the above.) */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 316ae2f8357..248f3fee15e 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -82,6 +82,7 @@ #endif // SOC_INT_CLIC_SUPPORTED #include "esp_private/esp_mmu_map_private.h" +#include "esp_private/image_process.h" #if CONFIG_SPIRAM #include "esp_psram.h" #include "esp_private/mmu_psram_flash.h" @@ -90,7 +91,6 @@ #include "esp_private/spi_flash_os.h" #include "esp_private/mspi_timing_tuning.h" -#include "esp_private/esp_gpio_reserve.h" #include "bootloader_flash_config.h" #include "bootloader_flash.h" #include "esp_private/crosscore_int.h" @@ -532,7 +532,7 @@ void IRAM_ATTR call_start_cpu0(void) #if CONFIG_ESPTOOLPY_OCT_FLASH && !CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT bool efuse_opflash_en = efuse_ll_get_flash_type(); if (!efuse_opflash_en) { - ESP_EARLY_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!"); + ESP_DRAM_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!"); abort(); } #endif @@ -562,17 +562,23 @@ void IRAM_ATTR call_start_cpu0(void) esp_mmu_map_init(); +#if !CONFIG_APP_BUILD_TYPE_ELF_RAM +#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM + ESP_ERROR_CHECK(image_process()); +#endif +#endif + #if CONFIG_SPIRAM_BOOT_INIT if (esp_psram_init() != ESP_OK) { #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); + ESP_DRAM_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); abort(); #endif #if CONFIG_SPIRAM_IGNORE_NOTFOUND ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); #else - ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); + ESP_DRAM_LOGE(TAG, "Failed to init external RAM!"); abort(); #endif } @@ -581,15 +587,10 @@ void IRAM_ATTR call_start_cpu0(void) //----------------------------------Separator-----------------------------// /** * @note - * After this stage, you can place non-internal ram code + * After this stage, you can access the flash through the cache, i.e. run code which is not placed in IRAM + * or print string which locates on flash */ - - /* Reserve the GPIO pins */ - uint64_t reserve_pin_mask = 0; - for (esp_mspi_io_t i = 0; i < ESP_MSPI_IO_MAX; i++) { - reserve_pin_mask |= BIT64(esp_mspi_get_io(i)); - } - esp_gpio_reserve_pins(reserve_pin_mask); + esp_mspi_pin_reserve(); #endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP @@ -599,10 +600,6 @@ void IRAM_ATTR call_start_cpu0(void) ESP_EARLY_LOGI(TAG, "Multicore app"); #endif - if (esp_efuse_check_errors() != ESP_OK) { - esp_restart(); - } - bootloader_init_mem(); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE diff --git a/components/hal/esp32/include/hal/mmu_ll.h b/components/hal/esp32/include/hal/mmu_ll.h index 82212d12aed..fd1171bb295 100644 --- a/components/hal/esp32/include/hal/mmu_ll.h +++ b/components/hal/esp32/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,9 @@ extern "C" { #endif #define MMU_LL_PSRAM_ENTRY_START_ID 1152 +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (64 - 1) + /** * Convert MMU virtual address to linear address @@ -302,7 +305,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32c2/include/hal/mmu_ll.h b/components/hal/esp32c2/include/hal/mmu_ll.h index 8f1429692b5..15ebd45c6fc 100644 --- a/components/hal/esp32c2/include/hal/mmu_ll.h +++ b/components/hal/esp32c2/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,9 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) + /** * Convert MMU virtual address to linear address * @@ -263,7 +266,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32c3/include/hal/mmu_ll.h b/components/hal/esp32c3/include/hal/mmu_ll.h index c7618366a93..5fe5fb363c9 100644 --- a/components/hal/esp32c3/include/hal/mmu_ll.h +++ b/components/hal/esp32c3/include/hal/mmu_ll.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - 0x10000) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) /** * Convert MMU virtual address to linear address * @@ -230,7 +232,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32c5/include/hal/mmu_ll.h b/components/hal/esp32c5/include/hal/mmu_ll.h index 69d97db39e8..5ecb06998aa 100644 --- a/components/hal/esp32c5/include/hal/mmu_ll.h +++ b/components/hal/esp32c5/include/hal/mmu_ll.h @@ -24,6 +24,9 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) + /** * Convert MMU virtual address to linear address * @@ -284,7 +287,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32c6/include/hal/mmu_ll.h b/components/hal/esp32c6/include/hal/mmu_ll.h index 8637909bde7..0d570f7e87a 100644 --- a/components/hal/esp32c6/include/hal/mmu_ll.h +++ b/components/hal/esp32c6/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,6 +19,9 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) + /** * Convert MMU virtual address to linear address * @@ -275,7 +278,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32c61/include/hal/mmu_ll.h b/components/hal/esp32c61/include/hal/mmu_ll.h index f59cf5aa756..44aac374f6e 100644 --- a/components/hal/esp32c61/include/hal/mmu_ll.h +++ b/components/hal/esp32c61/include/hal/mmu_ll.h @@ -20,6 +20,9 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) + /** * Convert MMU virtual address to linear address * @@ -277,7 +280,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32h2/include/hal/mmu_ll.h b/components/hal/esp32h2/include/hal/mmu_ll.h index f59ca5685ae..19a975d33bd 100644 --- a/components/hal/esp32h2/include/hal/mmu_ll.h +++ b/components/hal/esp32h2/include/hal/mmu_ll.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) /** * Convert MMU virtual address to linear address @@ -282,7 +284,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32p4/clk_tree_hal.c b/components/hal/esp32p4/clk_tree_hal.c index b6337524844..8b21821507d 100644 --- a/components/hal/esp32p4/clk_tree_hal.c +++ b/components/hal/esp32p4/clk_tree_hal.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_attr.h" #include "hal/clk_tree_hal.h" #include "hal/clk_tree_ll.h" #include "hal/assert.h" @@ -70,7 +71,7 @@ uint32_t clk_hal_lp_slow_get_freq_hz(void) } } -uint32_t clk_hal_xtal_get_freq_mhz(void) +IRAM_ATTR uint32_t clk_hal_xtal_get_freq_mhz(void) { uint32_t freq = clk_ll_xtal_load_freq_mhz(); if (freq == 0) { diff --git a/components/hal/esp32p4/include/hal/ldo_ll.h b/components/hal/esp32p4/include/hal/ldo_ll.h index d470107d5cb..96ae2250f0b 100644 --- a/components/hal/esp32p4/include/hal/ldo_ll.h +++ b/components/hal/esp32p4/include/hal/ldo_ll.h @@ -42,17 +42,6 @@ extern "C" { #define LDO_LL_EXT_LDO_MUL_VOL_BASE 1000 #define LDO_LL_EXT_LDO_MUL_VOL_STEP 250 -/** - * Trick to be adapted to the LDO register structure - * - * In pmu_ext_ldo_info_t ext_ldo[6] registers: - * - ext_ldo[0] is LDO1 - * - ext_ldo[3] is LDO2 - * - ext_ldo[1] is LDO3 - * - ext_ldo[4] is LDO4 - */ -#define LDO_ID2INDEX(id) (uint8_t[]){0,3,1,4}[id] - /** * LDO ID to real unit ID */ @@ -79,8 +68,8 @@ __attribute__((always_inline)) static inline void ldo_ll_enable(int ldo_id, bool enable) { HAL_ASSERT(ldo_id < LDO_LL_UNIT_NUM); - - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo.xpd = enable; + uint8_t index_array[LDO_LL_UNIT_NUM] = {0,3,1,4}; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.xpd = enable; } /** @@ -150,11 +139,12 @@ static inline void ldo_ll_set_output_voltage_mv(int ldo_id, int voltage_mv) * - 0: efuse * - 1: tieh_sel */ - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo.tieh_sel = 0; - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo.tieh = 0; - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo.force_tieh_sel = 1; - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo_ana.dref = dref; - PMU.ext_ldo[LDO_ID2INDEX(ldo_id)].pmu_ext_ldo_ana.mul = mul; + uint8_t index_array[LDO_LL_UNIT_NUM] = {0,3,1,4}; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.tieh_sel = 0; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.tieh = 0; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.force_tieh_sel = 1; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo_ana.dref = dref; + PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo_ana.mul = mul; } #ifdef __cplusplus diff --git a/components/hal/esp32p4/include/hal/mmu_ll.h b/components/hal/esp32p4/include/hal/mmu_ll.h index 6162cc9315d..bca29735a64 100644 --- a/components/hal/esp32p4/include/hal/mmu_ll.h +++ b/components/hal/esp32p4/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,11 +20,12 @@ extern "C" { #endif -///< MMU is per target -#define MMU_LL_MMU_PER_TARGET 1 - #define MMU_LL_FLASH_MMU_ID 0 #define MMU_LL_PSRAM_MMU_ID 1 +#define MMU_LL_FLASH_VADDR_TO_PSRAM_VADDR(flash_vaddr) ((flash_vaddr) + SOC_IRAM_FLASH_PSRAM_OFFSET) +#define MMU_LL_PSRAM_VADDR_TO_FLASH_VADDR(psram_vaddr) ((psram_vaddr) - SOC_IRAM_FLASH_PSRAM_OFFSET) +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_MMU_PAGE_SIZE) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) /** * Convert MMU virtual address to linear address diff --git a/components/hal/esp32s2/include/hal/mmu_ll.h b/components/hal/esp32s2/include/hal/mmu_ll.h index 396942e5d0a..7c166c5cca6 100644 --- a/components/hal/esp32s2/include/hal/mmu_ll.h +++ b/components/hal/esp32s2/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,9 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - 0x10000) +#define MMU_LL_END_DROM_ENTRY_ID (192 - 1) + /** * Convert MMU virtual address to linear address * @@ -249,7 +252,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/esp32s3/include/hal/mmu_ll.h b/components/hal/esp32s3/include/hal/mmu_ll.h index 1188df3d5f9..8877c31402a 100644 --- a/components/hal/esp32s3/include/hal/mmu_ll.h +++ b/components/hal/esp32s3/include/hal/mmu_ll.h @@ -19,6 +19,8 @@ extern "C" { #endif +#define MMU_LL_END_DROM_ENTRY_VADDR (SOC_DRAM_FLASH_ADDRESS_HIGH - 0x10000) +#define MMU_LL_END_DROM_ENTRY_ID (SOC_MMU_ENTRY_NUM - 1) /** * Convert MMU virtual address to linear address * @@ -230,7 +232,7 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) * @param mmu_id MMU ID * @param entry_id MMU entry ID * - * @return Ture for MMU entry is valid; False for invalid + * @return True for MMU entry is valid; False for invalid */ static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { diff --git a/components/hal/include/hal/cache_hal.h b/components/hal/include/hal/cache_hal.h index 5a4f0b86aa7..28753e6e9c4 100644 --- a/components/hal/include/hal/cache_hal.h +++ b/components/hal/include/hal/cache_hal.h @@ -9,6 +9,7 @@ #include #include +#include "soc/soc_caps.h" #include "hal/cache_types.h" #ifdef __cplusplus diff --git a/components/hal/linker.lf b/components/hal/linker.lf index ed8d9f00f5a..b2d5f76a76c 100644 --- a/components/hal/linker.lf +++ b/components/hal/linker.lf @@ -24,5 +24,3 @@ entries: spi_flash_hal_gpspi (noflash) if SOC_PMU_SUPPORTED = y: pmu_hal (noflash) - if SOC_CLK_MPLL_SUPPORTED = y: - clk_tree_hal: clk_hal_xtal_get_freq_mhz (noflash) diff --git a/components/hal/mmu_hal.c b/components/hal/mmu_hal.c index b3ee4918154..e3c9c87c4e0 100644 --- a/components/hal/mmu_hal.c +++ b/components/hal/mmu_hal.c @@ -12,6 +12,7 @@ #include "hal/assert.h" #include "hal/mmu_hal.h" #include "hal/mmu_ll.h" +#include "soc/soc_caps.h" #include "rom/cache.h" void mmu_hal_init(void) @@ -26,7 +27,7 @@ void mmu_hal_init(void) void mmu_hal_unmap_all(void) { -#if MMU_LL_MMU_PER_TARGET +#if SOC_MMU_PER_EXT_MEM_TARGET mmu_ll_unmap_all(MMU_LL_FLASH_MMU_ID); mmu_ll_unmap_all(MMU_LL_PSRAM_MMU_ID); #else diff --git a/components/soc/esp32/include/soc/ext_mem_defs.h b/components/soc/esp32/include/soc/ext_mem_defs.h index 40054fa7cb4..b4bebe97024 100644 --- a/components/soc/esp32/include/soc/ext_mem_defs.h +++ b/components/soc/esp32/include/soc/ext_mem_defs.h @@ -34,9 +34,6 @@ extern "C" { #define SOC_DRAM_FLASH_ADDRESS_LOW SOC_DROM0_CACHE_ADDRESS_LOW #define SOC_DRAM_FLASH_ADDRESS_HIGH SOC_DROM0_CACHE_ADDRESS_HIGH -#define SOC_DRAM_PSRAM_ADDRESS_LOW SOC_DRAM1_CACHE_ADDRESS_LOW -#define SOC_DRAM_PSRAM_ADDRESS_HIGH SOC_DRAM1_CACHE_ADDRESS_HIGH - #define SOC_BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) #define SOC_ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) #define SOC_ADDRESS_IN_IRAM0_CACHE(vaddr) SOC_ADDRESS_IN_BUS(SOC_IRAM0_CACHE, vaddr) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..f5b754fca0a 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -791,6 +791,10 @@ config SOC_MMU_DI_VADDR_SHARED bool default y +config SOC_MMU_PER_EXT_MEM_TARGET + bool + default y + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32p4/include/soc/ext_mem_defs.h b/components/soc/esp32p4/include/soc/ext_mem_defs.h index 8ecd5a3c474..c305e724535 100644 --- a/components/soc/esp32p4/include/soc/ext_mem_defs.h +++ b/components/soc/esp32p4/include/soc/ext_mem_defs.h @@ -43,6 +43,9 @@ extern "C" { #define SOC_DRAM_PSRAM_ADDRESS_LOW SOC_IRAM_PSRAM_ADDRESS_LOW #define SOC_DRAM_PSRAM_ADDRESS_HIGH SOC_IRAM_PSRAM_ADDRESS_HIGH +#define SOC_IRAM_FLASH_PSRAM_OFFSET (SOC_IRAM_PSRAM_ADDRESS_LOW - SOC_IRAM_FLASH_ADDRESS_LOW) +#define SOC_DRAM_FLASH_PSRAM_OFFSET SOC_IRAM_FLASH_PSRAM_OFFSET + #define SOC_BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) #define SOC_ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..f2f9845829b 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -324,6 +324,7 @@ #define SOC_MMU_PERIPH_NUM (2U) #define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (2U) #define SOC_MMU_DI_VADDR_SHARED (1) /*!< D/I vaddr are shared */ +#define SOC_MMU_PER_EXT_MEM_TARGET (1) /*!< MMU is per physical external memory target (flash, psram) */ /*-------------------------- MPU CAPS ----------------------------------------*/ #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 diff --git a/components/soc/esp32s3/include/soc/ext_mem_defs.h b/components/soc/esp32s3/include/soc/ext_mem_defs.h index 7c50019572e..9f9e36390b6 100644 --- a/components/soc/esp32s3/include/soc/ext_mem_defs.h +++ b/components/soc/esp32s3/include/soc/ext_mem_defs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,6 +29,12 @@ extern "C" { #define SOC_DRAM_FLASH_ADDRESS_LOW SOC_DRAM0_CACHE_ADDRESS_LOW #define SOC_DRAM_FLASH_ADDRESS_HIGH SOC_DRAM0_CACHE_ADDRESS_HIGH +#define SOC_IRAM_PSRAM_ADDRESS_LOW SOC_IRAM0_CACHE_ADDRESS_LOW +#define SOC_IRAM_PSRAM_ADDRESS_HIGH SOC_IRAM0_CACHE_ADDRESS_HIGH + +#define SOC_DRAM_PSRAM_ADDRESS_LOW SOC_DRAM0_CACHE_ADDRESS_LOW +#define SOC_DRAM_PSRAM_ADDRESS_HIGH SOC_DRAM0_CACHE_ADDRESS_HIGH + #define SOC_BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) #define SOC_ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index da4e991566a..d7482f92b4a 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -281,12 +281,22 @@ size_t spi_flash_cache2phys(const void *cached) uint32_t paddr = 0; mmu_target_t target = 0; +#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM //TODO: IDF-9049 + paddr = mmu_xip_psram_flash_vaddr_to_paddr(cached); + //SPI_FLASH_CACHE2PHYS_FAIL is UINT32_MAX + if (paddr != SPI_FLASH_CACHE2PHYS_FAIL) { + return paddr; + } +#endif + ret = esp_mmu_vaddr_to_paddr((void *)cached, &paddr, &target); if (ret != ESP_OK) { return SPI_FLASH_CACHE2PHYS_FAIL; } int offset = 0; + +#if !SOC_MMU_PER_EXT_MEM_TARGET //TODO: IDF-9049 #if CONFIG_SPIRAM_RODATA if ((uint32_t)cached >= (uint32_t)&_rodata_reserved_start && (uint32_t)cached <= (uint32_t)&_rodata_reserved_end) { offset = rodata_flash2spiram_offset(); @@ -297,6 +307,7 @@ size_t spi_flash_cache2phys(const void *cached) offset = instruction_flash2spiram_offset(); } #endif +#endif //#if !SOC_MMU_PER_EXT_MEM_TARGET return paddr + offset * CONFIG_MMU_PAGE_SIZE; } @@ -309,6 +320,7 @@ const void * spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memo mmu_target_t target = MMU_TARGET_FLASH0; __attribute__((unused)) uint32_t phys_page = phys_offs / CONFIG_MMU_PAGE_SIZE; +#if !SOC_MMU_PER_EXT_MEM_TARGET #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS if (phys_page >= instruction_flash_start_page_get() && phys_page <= instruction_flash_end_page_get()) { target = MMU_TARGET_PSRAM0; @@ -322,6 +334,7 @@ const void * spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memo phys_offs -= rodata_flash2spiram_offset() * CONFIG_MMU_PAGE_SIZE; } #endif +#endif //#if !SOC_MMU_PER_EXT_MEM_TARGET mmu_vaddr_t type = (memory == SPI_FLASH_MMAP_DATA) ? MMU_VADDR_DATA : MMU_VADDR_INSTRUCTION; ret = esp_mmu_paddr_to_vaddr(phys_offs, target, type, &ptr); diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index f99fcfe4df1..d88259ec7d2 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -24,6 +24,7 @@ #include "esp_private/system_internal.h" #include "esp_private/spi_flash_os.h" #include "esp_private/esp_clk.h" +#include "esp_private/esp_gpio_reserve.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/cache.h" #include "esp32/rom/spi_flash.h" @@ -151,6 +152,15 @@ void IRAM_ATTR esp_mspi_pin_init(void) #endif } +void esp_mspi_pin_reserve(void) +{ + uint64_t reserve_pin_mask = 0; + for (esp_mspi_io_t i = 0; i < ESP_MSPI_IO_MAX; i++) { + reserve_pin_mask |= BIT64(esp_mspi_get_io(i)); + } + esp_gpio_reserve(reserve_pin_mask); +} + esp_err_t IRAM_ATTR spi_flash_init_chip_state(void) { #if SOC_SPI_MEM_SUPPORT_OPI_MODE diff --git a/components/spi_flash/include/esp_private/spi_flash_os.h b/components/spi_flash/include/esp_private/spi_flash_os.h index 3d8512c9e92..e68b0c8fb33 100644 --- a/components/spi_flash/include/esp_private/spi_flash_os.h +++ b/components/spi_flash/include/esp_private/spi_flash_os.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,6 +55,11 @@ esp_err_t spi_flash_init_chip_state(void); */ void esp_mspi_pin_init(void); +/** + * @brief Reserve MSPI IOs + */ +void esp_mspi_pin_reserve(void); + /** * @brief Get the number of the GPIO corresponding to the given MSPI io * diff --git a/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c index 548de17285a..83b0453bcbd 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c +++ b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -23,7 +23,7 @@ static uint32_t buffer[1024]; -/* read-only region used for mmap tests, intialised in setup_mmap_tests() */ +/* read-only region used for mmap tests, initialised in setup_mmap_tests() */ static uint32_t start; static uint32_t end; @@ -359,7 +359,14 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]") /* esp_partition_find is in IROM */ uint32_t phys = spi_flash_cache2phys(esp_partition_find); TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); +#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM + /** + * On CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM=y condition + * spi_flash_phys2cache will return exactly the flash paddr corresponding vaddr. + * Whereas `constant_data` is now actually on PSRAM + */ TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); +#endif #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); #endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 @@ -371,8 +378,14 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]") /* 'constant_data' should be in DROM */ phys = spi_flash_cache2phys(&constant_data); TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); - TEST_ASSERT_EQUAL_PTR(&constant_data, - spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); +#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM + /** + * On CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM=y condition, + * spi_flash_phys2cache will return exactly the flash paddr corresponding vaddr. + * Whereas `constant_data` is now actually on PSRAM + */ + TEST_ASSERT_EQUAL_PTR(&constant_data, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA)); +#endif #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST)); #endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 @@ -404,7 +417,18 @@ TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash][mmap]") spi_flash_munmap(handle1); handle1 = 0; + esp_rom_printf("ptr; 0x%x\n", ptr); + +#if !CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM + /** + * On CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM=y condition, this is reasonable as there are two MMUs. + * Unmapping flash one, if it's XIP_PSRAM, we can still find it via `spi_flash_cache2phys` + * + * TODO, design a new API dedicated for `esp_ota_get_running_partition` usage, then here we can + * update this `spi_flash_cache2phys` back to its normal behaviour + */ TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr)); +#endif } TEST_CASE("munmap followed by mmap flushes cache", "[spi_flash][mmap]") diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index f566897aeef..e0f779f78a5 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -137,35 +137,55 @@ Remaining external RAM can also be added to the capability heap allocator using .. only:: SOC_SPIRAM_XIP_SUPPORTED - .. _external_ram_config_instructions: + .. only:: esp32s2 or esp32s3 - Move Instructions in Flash to PSRAM - ----------------------------------- + .. _external_ram_config_instructions: - The :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` option allows the flash ``.text`` sections (use for instructions) to be placed in PSRAM. + Move Instructions in Flash to PSRAM + ----------------------------------- - By enabling the :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` option + The :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` option allows the flash ``.text`` sections (for instructions) to be placed in PSRAM. - - Instructions from the ``.text`` sections of flash are moved into PSRAM on system startup. + By enabling the :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` option, - - The corresponding virtual memory range of those instructions will also be re-mapped to PSRAM. + - Instructions from the ``.text`` sections of flash are moved into PSRAM on system startup. - If :ref:`CONFIG_SPIRAM_RODATA` is also enabled, the cache will not be disabled during an SPI1 flash operation. You do not need to make sure ISRs, ISR callbacks and involved data are placed in internal RAM, thus internal RAM usage can be optimized. + - The corresponding virtual memory range of those instructions will also be re-mapped to PSRAM. - .. _external_ram_config_rodata: + .. _external_ram_config_rodata: - Move Read-Only Data in Flash to PSRAM - --------------------------------------- + Move Read-Only Data in Flash to PSRAM + --------------------------------------- - The :ref:`CONFIG_SPIRAM_RODATA` option allows the flash ``.rodata`` sections (use for read only data) to be placed in PSRAM. + The :ref:`CONFIG_SPIRAM_RODATA` option allows the flash ``.rodata`` sections (for read only data) to be placed in PSRAM. - By enabling the :ref:`CONFIG_SPIRAM_RODATA` option + By enabling the :ref:`CONFIG_SPIRAM_RODATA` option, - - Instructions from the ``.rodata`` sections of flash are moved into PSRAM on system startup. + - Instructions from the ``.rodata`` sections of flash are moved into PSRAM on system startup. - - The corresponding virtual memory range of those rodata will also be re-mapped to PSRAM. + - The corresponding virtual memory range of those rodata will also be re-mapped to PSRAM. + + + Execute In Place (XiP) from PSRAM + ------------------------------------ + + The :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` is a helper option for you to select both the :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` and :ref:`CONFIG_SPIRAM_RODATA`. + + The benefits of XiP from PSRAM is: + + - PSRAM access speed is faster than Flash access. So the performance is better. + + - The cache will not be disabled during an SPI1 flash operation, thus optimizing the code execution performance during SPI1 flash operations. For ISRs, ISR callbacks and data which might be accessed during this period, you do not need to place them in internal RAM, thus internal RAM usage can be optimized. This feature is useful for high throughput peripheral involved applications to improve the performance during SPI1 flash operations. + + .. only:: esp32p4 + + Execute In Place (XiP) from PSRAM + ------------------------------------ + + The :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` option enables the executable in place (XiP) from PSRAM feature. With this option sections that are normally placed in flash ,``.text`` (for instructions) and ``.rodata`` (for read only data), will be loaded in PSRAM. + + With this option enabled, the cache will not be disabled during an SPI1 flash operation, so code that requires executing during an SPI1 Flash operation does not have to be placed in internal RAM. Because P4 Flash and PSRAM are using two separate SPI buses, moving Flash content to PSRAM will actually increase the load of the PSRAM MSPI bus, so the access speed is relatively slower. The exact impact on performance will be very dependent on your apps usage of PSRAM, and we suggest doing performance profiling to determine if enabling this option will significantly impact your app's performance. - If :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` is also enabled, the cache will not be disabled during an SPI1 flash operation. You do not need to make sure ISRs, ISR callbacks and involved data are placed in internal RAM, thus internal RAM usage can be optimized. Restrictions ============ diff --git a/tools/ci/check_ldgen_mapping_exceptions.txt b/tools/ci/check_ldgen_mapping_exceptions.txt index c1920680641..6d470c462d6 100644 --- a/tools/ci/check_ldgen_mapping_exceptions.txt +++ b/tools/ci/check_ldgen_mapping_exceptions.txt @@ -3,3 +3,5 @@ sha256_coredump gcc clang_rt_builtins freertos_common +esp_psram +esp_mm From 58ebdb7ae3255a37f2d95bbceca7abbc99ced08b Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 21 May 2024 16:45:58 +0800 Subject: [PATCH 155/548] change(image): move image_process driver from bootloader_support to esp_system --- components/bootloader_support/CMakeLists.txt | 9 ++------- components/bootloader_support/linker.lf | 5 ----- components/esp_system/linker.lf | 3 +++ components/esp_system/port/CMakeLists.txt | 4 ++++ .../src => esp_system/port}/image_process.c | 11 +++++++++++ .../port/include/private}/esp_private/image_process.h | 0 6 files changed, 20 insertions(+), 12 deletions(-) delete mode 100644 components/bootloader_support/linker.lf rename components/{bootloader_support/src => esp_system/port}/image_process.c (96%) rename components/{bootloader_support/include => esp_system/port/include/private}/esp_private/image_process.h (100%) diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 8d70b1f8c61..fbe9adf5fd1 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -28,10 +28,6 @@ if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) ) endif() -if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP AND NOT BOOTLOADER_BUILD) - list(APPEND srcs "src/image_process.c") -endif() - if(CONFIG_APP_BUILD_TYPE_APP_2NDBOOT) list(APPEND srcs "src/bootloader_utility.c" @@ -64,7 +60,7 @@ else() set(include_dirs "include" "bootloader_flash/include") set(priv_include_dirs "private_include") # heap is required for `heap_memory_layout.h` header - set(priv_requires spi_flash mbedtls efuse heap esp_bootloader_format esp_app_format esp_mm) + set(priv_requires spi_flash mbedtls efuse heap esp_bootloader_format esp_app_format) endif() if(BOOTLOADER_BUILD) @@ -116,8 +112,7 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" PRIV_INCLUDE_DIRS "${priv_include_dirs}" REQUIRES "${requires}" - PRIV_REQUIRES "${priv_requires}" - LDFRAGMENTS linker.lf) + PRIV_REQUIRES "${priv_requires}") if(NOT BOOTLOADER_BUILD) if(CONFIG_SECURE_SIGNED_ON_UPDATE) diff --git a/components/bootloader_support/linker.lf b/components/bootloader_support/linker.lf deleted file mode 100644 index d2cf44a6e01..00000000000 --- a/components/bootloader_support/linker.lf +++ /dev/null @@ -1,5 +0,0 @@ -[mapping:bootloader_support] -archive: libbootloader_support.a -entries: - if APP_BUILD_TYPE_RAM = n: - image_process (noflash) diff --git a/components/esp_system/linker.lf b/components/esp_system/linker.lf index f3eac77bc05..666714c4952 100644 --- a/components/esp_system/linker.lf +++ b/components/esp_system/linker.lf @@ -30,6 +30,9 @@ entries: usb_console:esp_usb_console_before_restart (noflash) usb_console:esp_usb_console_on_restart_timeout (noflash) + if APP_BUILD_TYPE_RAM = n: + image_process (noflash) + [mapping:vfs_cdcacm] archive: libvfs.a entries: diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 7f6861b5127..05a476f8cfe 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -8,6 +8,10 @@ target_include_directories(${COMPONENT_LIB} PRIVATE ${INCLUDE_FILES} include/pri set(srcs "cpu_start.c" "panic_handler.c" "esp_system_chip.c") +if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) + list(APPEND srcs "image_process.c") +endif() + if(CONFIG_SOC_BOD_SUPPORTED) list(APPEND srcs "brownout.c") endif() diff --git a/components/bootloader_support/src/image_process.c b/components/esp_system/port/image_process.c similarity index 96% rename from components/bootloader_support/src/image_process.c rename to components/esp_system/port/image_process.c index 4c0100e4747..d4ff4ed8d08 100644 --- a/components/bootloader_support/src/image_process.c +++ b/components/esp_system/port/image_process.c @@ -23,6 +23,11 @@ #include "esp_private/image_process.h" #include "esp_private/esp_cache_esp32_private.h" +/** + * ESP32 bootloader size is not enough, not enable this feature for now + */ +#define IMAGE_PROCESS_SUPPORTED_TARGETS (!CONFIG_IDF_TARGET_ESP32) + #if CONFIG_IDF_TARGET_ESP32 #define MMAP_MMU_SIZE 0x320000 #elif CONFIG_IDF_TARGET_ESP32S2 @@ -94,6 +99,7 @@ static esp_err_t flash_read(size_t src_addr, void *dest, size_t size) return ESP_OK; } +#if IMAGE_PROCESS_SUPPORTED_TARGETS static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_offset) { bzero(data, sizeof(esp_image_metadata_t)); @@ -105,6 +111,7 @@ static esp_err_t process_image_header(esp_image_metadata_t *data, uint32_t part_ return ESP_OK; } +#endif static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, esp_image_metadata_t *metadata, int *cnt) { @@ -189,6 +196,7 @@ void image_process_get_flash_segments_info(uint32_t *out_drom_paddr_start, uint3 esp_err_t image_process(void) { +#if IMAGE_PROCESS_SUPPORTED_TARGETS esp_err_t ret = ESP_FAIL; /** * We use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition @@ -210,6 +218,9 @@ esp_err_t image_process(void) } mmu_ll_set_entry_invalid(0, MMU_LL_END_DROM_ENTRY_ID); +#else + (void)s_image_process_driver; +#endif return ESP_OK; } diff --git a/components/bootloader_support/include/esp_private/image_process.h b/components/esp_system/port/include/private/esp_private/image_process.h similarity index 100% rename from components/bootloader_support/include/esp_private/image_process.h rename to components/esp_system/port/include/private/esp_private/image_process.h From 1129f0834e0fb438df66cdecef13b853de8b6b38 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 27 May 2024 13:23:16 +0800 Subject: [PATCH 156/548] fix(dsi): fixed wrong RGB666 pixel size --- components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 54 ++++++++++++---------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 4db6af27690..5d3d22cd5e0 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -38,7 +38,7 @@ struct esp_lcd_dpi_panel_t { uint32_t h_pixels; // Horizontal pixels uint32_t v_pixels; // Vertical pixels size_t frame_buffer_size; // Frame buffer size - size_t bytes_per_pixel; // Bytes per pixel + size_t bits_per_pixel; // Bits per pixel lcd_color_rgb_pixel_format_t pixel_format; // RGB Pixel format dw_gdma_channel_handle_t dma_chan; // DMA channel dw_gdma_link_list_handle_t link_lists[DPI_PANEL_MAX_FB_NUM]; // DMA link list @@ -161,6 +161,22 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ } ESP_RETURN_ON_FALSE(num_fbs <= DPI_PANEL_MAX_FB_NUM, ESP_ERR_INVALID_ARG, TAG, "num_fbs not within [1,%d]", DPI_PANEL_MAX_FB_NUM); + size_t bits_per_pixel = 0; + switch (panel_config->pixel_format) { + case LCD_COLOR_PIXEL_FORMAT_RGB565: + bits_per_pixel = 16; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB666: + // RGB data in the memory must be constructed in 6-6-6 (18 bits) for each pixel + bits_per_pixel = 18; + break; + case LCD_COLOR_PIXEL_FORMAT_RGB888: + bits_per_pixel = 24; + break; + } + ESP_RETURN_ON_FALSE(panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel % 8 == 0, + ESP_ERR_INVALID_ARG, TAG, "frame buffer size not aligned to byte boundary"); + int bus_id = bus->bus_id; mipi_dsi_hal_context_t *hal = &bus->hal; @@ -172,22 +188,10 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ dpi_panel->num_fbs = num_fbs; // allocate frame buffer from PSRAM - size_t bytes_per_pixel = 0; - switch (panel_config->pixel_format) { - case LCD_COLOR_PIXEL_FORMAT_RGB565: - bytes_per_pixel = 2; - break; - case LCD_COLOR_PIXEL_FORMAT_RGB666: - bytes_per_pixel = 3; - break; - case LCD_COLOR_PIXEL_FORMAT_RGB888: - bytes_per_pixel = 3; - break; - } uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); // DMA doesn't have requirement on the buffer alignment, but the cache does uint32_t alignment = cache_line_size; - size_t frame_buffer_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bytes_per_pixel; + size_t frame_buffer_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8; uint8_t *frame_buffer = NULL; for (int i = 0; i < num_fbs; i++) { frame_buffer = heap_caps_aligned_calloc(alignment, 1, frame_buffer_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); @@ -202,7 +206,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ err, TAG, "cache write back failed"); } dpi_panel->frame_buffer_size = frame_buffer_size; - dpi_panel->bytes_per_pixel = bytes_per_pixel; + dpi_panel->bits_per_pixel = bits_per_pixel; dpi_panel->h_pixels = panel_config->video_timing.h_size; dpi_panel->v_pixels = panel_config->video_timing.v_size; @@ -274,7 +278,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ panel_config->video_timing.vsync_back_porch, panel_config->video_timing.v_size, panel_config->video_timing.vsync_front_porch); - mipi_dsi_brg_ll_set_num_pixel_bits(hal->bridge, panel_config->video_timing.h_size * panel_config->video_timing.v_size * bytes_per_pixel * 8); + mipi_dsi_brg_ll_set_num_pixel_bits(hal->bridge, panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel); mipi_dsi_brg_ll_set_underrun_discard_count(hal->bridge, panel_config->video_timing.h_size); // let the DSI bridge as the DMA flow controller mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_BRIDGE); @@ -416,7 +420,7 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int uint8_t *frame_buffer = dpi_panel->fbs[cur_fb_index]; uint8_t *draw_buffer = (uint8_t *)color_data; size_t frame_buffer_size = dpi_panel->frame_buffer_size; - size_t bytes_per_pixel = dpi_panel->bytes_per_pixel; + size_t bits_per_pixel = dpi_panel->bits_per_pixel; // clip to boundaries int h_res = dpi_panel->h_pixels; @@ -443,8 +447,8 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int if (!do_copy) { // no copy, just do cache memory write back ESP_LOGD(TAG, "draw buffer is in frame buffer memory range, do cache write back only"); // only write back the LCD lines that updated by the draw buffer - uint8_t *cache_sync_start = dpi_panel->fbs[draw_buf_fb_index] + (y_start * dpi_panel->h_pixels) * bytes_per_pixel; - size_t cache_sync_size = (y_end - y_start) * dpi_panel->h_pixels * bytes_per_pixel; + uint8_t *cache_sync_start = dpi_panel->fbs[draw_buf_fb_index] + (y_start * dpi_panel->h_pixels) * bits_per_pixel / 8; + size_t cache_sync_size = (y_end - y_start) * dpi_panel->h_pixels * bits_per_pixel / 8; // the buffer to be flushed is still within the frame buffer, so even an unaligned address is OK esp_cache_msync(cache_sync_start, cache_sync_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); @@ -456,9 +460,9 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int } else if (!dpi_panel->fbcpy_handle) { // copy by CPU ESP_LOGD(TAG, "copy draw buffer by CPU"); const uint8_t *from = draw_buffer; - uint8_t *to = frame_buffer + (y_start * dpi_panel->h_pixels + x_start) * bytes_per_pixel; - uint32_t copy_bytes_per_line = (x_end - x_start) * bytes_per_pixel; - uint32_t bytes_per_line = bytes_per_pixel * dpi_panel->h_pixels; + uint8_t *to = frame_buffer + (y_start * dpi_panel->h_pixels + x_start) * bits_per_pixel / 8; + uint32_t copy_bytes_per_line = (x_end - x_start) * bits_per_pixel / 8; + uint32_t bytes_per_line = bits_per_pixel * dpi_panel->h_pixels / 8; // please note, we assume the user provided draw_buffer is compact, // but the destination is a sub-window of the frame buffer, so we need to skip the stride for (int y = y_start; y < y_end; y++) { @@ -466,8 +470,8 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int to += bytes_per_line; from += copy_bytes_per_line; } - uint8_t *cache_sync_start = frame_buffer + (y_start * dpi_panel->h_pixels) * bytes_per_pixel; - size_t cache_sync_size = (y_end - y_start) * dpi_panel->h_pixels * bytes_per_pixel; + uint8_t *cache_sync_start = frame_buffer + (y_start * dpi_panel->h_pixels) * bits_per_pixel / 8; + size_t cache_sync_size = (y_end - y_start) * dpi_panel->h_pixels * bits_per_pixel / 8; // the buffer to be flushed is still within the frame buffer, so even an unaligned address is OK esp_cache_msync(cache_sync_start, cache_sync_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); // invoke the trans done callback @@ -482,7 +486,7 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int // write back the user's draw buffer, so that the DMA can see the correct data // Note, the user draw buffer should be 1D array, and contiguous in memory, no stride - size_t color_data_size = (x_end - x_start) * (y_end - y_start) * bytes_per_pixel; + size_t color_data_size = (x_end - x_start) * (y_end - y_start) * bits_per_pixel / 8; esp_cache_msync(draw_buffer, color_data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); esp_async_fbcpy_trans_desc_t fbcpy_trans_config = { From b1b182f2588d78c999af1ef034cf8d2a2847efec Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 27 May 2024 18:41:02 +0800 Subject: [PATCH 157/548] change(dsi): use DW_GDMA as the flow controller previously the DSI_Bridge was set as the flow controller --- components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 5d3d22cd5e0..e3d0e8a8b93 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -118,7 +118,7 @@ static esp_err_t dpi_panel_create_dma_link(esp_lcd_dpi_panel_t *dpi_panel) .handshake_type = DW_GDMA_HANDSHAKE_HW, .num_outstanding_requests = 2, }, - .flow_controller = DW_GDMA_FLOW_CTRL_DST, // the DSI bridge as the DMA flow controller + .flow_controller = DW_GDMA_FLOW_CTRL_SELF, // DMA as the flow controller .chan_priority = 1, }; ESP_RETURN_ON_ERROR(dw_gdma_new_channel(&dma_alloc_config, &dma_chan), TAG, "create DMA channel failed"); @@ -280,8 +280,8 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ panel_config->video_timing.vsync_front_porch); mipi_dsi_brg_ll_set_num_pixel_bits(hal->bridge, panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel); mipi_dsi_brg_ll_set_underrun_discard_count(hal->bridge, panel_config->video_timing.h_size); - // let the DSI bridge as the DMA flow controller - mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_BRIDGE); + // use the DW_GDMA as the flow controller + mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_DMA); mipi_dsi_brg_ll_set_burst_len(hal->bridge, 256); mipi_dsi_brg_ll_set_empty_threshold(hal->bridge, 1024 - 256); // enable DSI bridge From 10f89fe52e145668a25321f624b6ed067020b87f Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Tue, 28 May 2024 16:59:13 +0800 Subject: [PATCH 158/548] fix(ppa): fix mismatching writeback and invalidate data size on the same buffer --- components/esp_driver_ppa/src/ppa_blend.c | 9 ++++++--- components/esp_driver_ppa/src/ppa_core.c | 4 +--- components/esp_driver_ppa/src/ppa_fill.c | 6 ++---- components/esp_driver_ppa/src/ppa_priv.h | 3 +++ components/esp_driver_ppa/src/ppa_srm.c | 9 ++++++--- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c index e9b96ff5634..08c3e93e8cc 100644 --- a/components/esp_driver_ppa/src/ppa_blend.c +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -185,7 +185,8 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf color_space_pixel_format_t out_pixel_format = { .color_type_id = config->out.blend_cm, }; - uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); // bits + uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * out_pixel_depth / 8; ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size"); ESP_RETURN_ON_FALSE(config->in_bg.block_w == config->in_fg.block_w && config->in_bg.block_h == config->in_fg.block_h, ESP_ERR_INVALID_ARG, TAG, "in_bg.block_w/h must be equal to in_fg.block_w/h"); @@ -243,8 +244,10 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; esp_cache_msync((void *)in_fg_ext_window, in_fg_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); - // Invalidate out_buffer entire picture (alignment strict on M2C direction) - esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + // Invalidate out_buffer extended window (alignment strict on M2C direction) + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_len = config->out.pic_w * config->in_bg.block_h * out_pixel_depth / 8; + esp_cache_msync((void *)PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size), PPA_ALIGN_UP(out_ext_window_len, buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c index 6f309d92051..a622abdbb56 100644 --- a/components/esp_driver_ppa/src/ppa_core.c +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -32,8 +32,6 @@ #include "hal/ppa_types.h" #include "esp_private/periph_ctrl.h" -#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) - static const char *TAG = "ppa_core"; // PPA driver platform @@ -65,7 +63,7 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin _lock_acquire(&s_platform.mutex); if (s_platform.dma_desc_mem_size == 0) { - s_platform.dma_desc_mem_size = ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); + s_platform.dma_desc_mem_size = PPA_ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); } if (s_platform.buf_alignment_size == 0) { esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.buf_alignment_size); diff --git a/components/esp_driver_ppa/src/ppa_fill.c b/components/esp_driver_ppa/src/ppa_fill.c index 0411a47daaa..d34c338dcaa 100644 --- a/components/esp_driver_ppa/src/ppa_fill.c +++ b/components/esp_driver_ppa/src/ppa_fill.c @@ -105,12 +105,10 @@ esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config // To reduce complexity, color_mode, fill_block_w/h correctness are checked in their corresponding LL functions // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) - // Write back buffer extended window (alignment not necessary on C2M direction) + // Write back and invalidate buffer extended window (alignment not necessary on C2M direction, but alignment strict on M2C direction) uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; - esp_cache_msync((void *)out_ext_window, out_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); - // Invalidate out_buffer entire picture (alignment strict on M2C direction) - esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + esp_cache_msync((void *)PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size), PPA_ALIGN_UP(out_ext_window_len, buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_priv.h b/components/esp_driver_ppa/src/ppa_priv.h index e63322df08b..2a3b1e5d57d 100644 --- a/components/esp_driver_ppa/src/ppa_priv.h +++ b/components/esp_driver_ppa/src/ppa_priv.h @@ -34,6 +34,9 @@ extern "C" { ESP_RETURN_ON_FALSE(COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_ARGB || COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_RGB, \ ESP_ERR_INVALID_ARG, TAG, str "_cm does not support rgb_swap"); +#define PPA_ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#define PPA_ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) + typedef struct ppa_platform_t ppa_platform_t; /******************************** ENGINE *************************************/ diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 244a18bff9f..6fbcc4f7edd 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -197,7 +197,8 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s color_space_pixel_format_t out_pixel_format = { .color_type_id = config->out.srm_cm, }; - uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); // bits + uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * out_pixel_depth / 8; ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size"); ESP_RETURN_ON_FALSE(config->scale_x < (PPA_LL_SRM_SCALING_INT_MAX + 1) && config->scale_x >= (1.0 / PPA_LL_SRM_SCALING_FRAG_MAX) && config->scale_y < (PPA_LL_SRM_SCALING_INT_MAX + 1) && config->scale_y >= (1.0 / PPA_LL_SRM_SCALING_FRAG_MAX), @@ -239,8 +240,10 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); - // Invalidate out_buffer entire picture (alignment strict on M2C direction) - esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + // Invalidate out_buffer extended window (alignment strict on M2C direction) + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_len = config->out.pic_w * config->in.block_h * out_pixel_depth / 8; + esp_cache_msync((void *)PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size), PPA_ALIGN_UP(out_ext_window_len, buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; From 60c2068fef8fdad602fbc508c3a20b8b9f27b421 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 2 May 2024 15:24:55 +0300 Subject: [PATCH 159/548] docs(app_trace): Update docs for ESP32-P4 --- docs/docs_not_updated/esp32p4.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 16c57f06ea2..510f80ceb20 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -1,5 +1,4 @@ api-guides/partition-tables.rst -api-guides/app_trace.rst api-guides/RF_calibration.rst api-guides/deep-sleep-stub.rst api-guides/coexist.rst @@ -7,7 +6,6 @@ api-guides/flash_psram_config.rst api-guides/wifi.rst api-guides/usb-otg-console.rst api-guides/esp-wifi-mesh.rst -api-guides/SYSVIEW_FreeRTOS.txt api-guides/dfu.rst api-guides/current-consumption-measurement-modules.rst api-guides/wifi-security.rst @@ -45,7 +43,6 @@ api-reference/network/esp_nan.rst api-reference/network/esp_wifi.rst api-reference/network/index.rst api-reference/system/sleep_modes.rst -api-reference/system/app_trace.rst api-reference/system/random.rst api-reference/system/power_management.rst api-reference/system/inc/power_management_esp32p4.rst From baf60289748b7f7a23256def8cbebc47225bb653 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 24 Apr 2024 11:14:20 +0200 Subject: [PATCH 160/548] fix(docs): tcpip_adapter: Document replacement of tcpip_adapter_get_sta_list --- docs/en/migration-guides/release-5.x/5.0/networking.rst | 2 ++ docs/zh_CN/migration-guides/release-5.x/5.0/networking.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/en/migration-guides/release-5.x/5.0/networking.rst b/docs/en/migration-guides/release-5.x/5.0/networking.rst index ba52226cac4..bf778800362 100644 --- a/docs/en/migration-guides/release-5.x/5.0/networking.rst +++ b/docs/en/migration-guides/release-5.x/5.0/networking.rst @@ -140,6 +140,8 @@ All the ``tcpip_adapter`` functions have their ``esp-netif`` counter-part. Pleas * :component_file:`DNS ` * :component_file:`IP address ` +The TCP/IP Adapter API ``tcpip_adapter_get_sta_list()`` that was used to acquire a list of associated Wi-Fi stations to the Software Access Point (softAP) has been moved to the Wi-Fi component and renamed to :cpp:func:`esp_wifi_ap_get_sta_list_with_ip()`, which is a special case of the ESP-NETIF API :cpp:func:`esp_netif_dhcps_get_clients_by_mac()` that could be used more generally to provide a list of clients connected to a DHCP server no matter which network interface the server is running on. + Default Event Handlers ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/migration-guides/release-5.x/5.0/networking.rst b/docs/zh_CN/migration-guides/release-5.x/5.0/networking.rst index 4293fd438c2..cbf492f7982 100644 --- a/docs/zh_CN/migration-guides/release-5.x/5.0/networking.rst +++ b/docs/zh_CN/migration-guides/release-5.x/5.0/networking.rst @@ -140,6 +140,8 @@ TCP/IP 适配器是在 ESP-IDF v4.1 之前使用的网络接口抽象组件。 * :component_file:`DNS ` * :component_file:`IP address ` +TCP/IP 适配器 API ``tcpip_adapter_get_sta_list()`` 用于获取与软件接入点 (softAP) 相关联的 Wi-Fi 站点列表,现已移到 Wi-Fi 组件,并更名为 :cpp:func:`esp_wifi_ap_get_sta_list_with_ip()`,它是 ESP-NETIF API :cpp:func:`esp_netif_dhcps_get_clients_by_mac()` 一个特例。无论服务器在哪个网络接口上运行,该 API 都可更方便地提供连接到 DHCP 服务器的客户端列表。 + 默认事件处理程序 ^^^^^^^^^^^^^^^^^^^^^^ From 52a922f953058439fbd230fd395788ea368d6ad0 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 22 May 2024 11:27:48 +0800 Subject: [PATCH 161/548] fix(wifi): fixed the issue of tg0 watchdog reset caused by wifi module retention --- .../port/esp32c6/clock_retention_init.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/port/esp32c6/clock_retention_init.c b/components/esp_hw_support/port/esp32c6/clock_retention_init.c index f79c3969399..3027347483c 100644 --- a/components/esp_hw_support/port/esp32c6/clock_retention_init.c +++ b/components/esp_hw_support/port/esp32c6/clock_retention_init.c @@ -29,15 +29,27 @@ esp_err_t sleep_clock_modem_retention_init(void *arg) { #define N_REGS_SYSCON() (((MODEM_SYSCON_MEM_CONF_REG - MODEM_SYSCON_TEST_CONF_REG) / 4) + 1) + #define MODEM_WIFI_RETENTION_CLOCK (MODEM_SYSCON_CLK_WIFI_APB_FO | MODEM_SYSCON_CLK_FE_APB_FO) + #define MODEM_WIFI_RETENTION_CLOCK_MASK (MODEM_SYSCON_CLK_WIFI_APB_FO_M | MODEM_SYSCON_CLK_FE_APB_FO_M) + const static sleep_retention_entries_config_t modem_regs_retention[] = { [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMSYSCON_LINK(0), MODEM_SYSCON_TEST_CONF_REG, MODEM_SYSCON_TEST_CONF_REG, N_REGS_SYSCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) }, /* MODEM SYSCON */ + [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(1), MODEM_SYSCON_CLK_CONF1_FORCE_ON_REG, MODEM_WIFI_RETENTION_CLOCK, MODEM_WIFI_RETENTION_CLOCK_MASK, 0, 0), .owner = ENTRY(0) }, /* WiFi (MAC, BB and FE) retention clock enable */ #if SOC_PM_RETENTION_SW_TRIGGER_REGDMA - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK(0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) } /* MODEM LPCON */ + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEMLPCON_LINK(0), MODEM_LPCON_TEST_CONF_REG, MODEM_LPCON_TEST_CONF_REG, N_REGS_LPCON(), 0, 0), .owner = ENTRY(0) | ENTRY(1) } /* MODEM LPCON */ #endif }; + const static sleep_retention_entries_config_t modem_retention_clock[] = { + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_MODEMSYSCON_LINK(0xf0), MODEM_SYSCON_CLK_CONF1_FORCE_ON_REG, 0x0, MODEM_WIFI_RETENTION_CLOCK_MASK, 0, 0), .owner = ENTRY(0) } /* WiFi (MAC, BB and FE) retention clock disable */ + }; + esp_err_t err = sleep_retention_entries_create(modem_regs_retention, ARRAY_SIZE(modem_regs_retention), REGDMA_LINK_PRI_MODEM_CLK, SLEEP_RETENTION_MODULE_CLOCK_MODEM); ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for modem (SYSCON) retention, 1 level priority"); + + err = sleep_retention_entries_create(modem_retention_clock, ARRAY_SIZE(modem_retention_clock), REGDMA_LINK_PRI_7, SLEEP_RETENTION_MODULE_CLOCK_MODEM); + ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for modem (SYSCON) retention, lowest level priority"); + ESP_LOGI(TAG, "Modem Power, Clock and Reset sleep retention initialization"); return ESP_OK; } From 3d959421b131f8c9602a93276c3fd58a9abd3c97 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 17 May 2024 16:12:56 +0800 Subject: [PATCH 162/548] docs(doxygen): fix misc issues with new version of doxygen --- components/driver/twai/include/driver/twai.h | 2 ++ components/esp_hw_support/include/esp_intr_alloc.h | 3 ++- components/hal/include/hal/twai_types.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/driver/twai/include/driver/twai.h b/components/driver/twai/include/driver/twai.h index fe1bd8abb21..78bc71106a7 100644 --- a/components/driver/twai/include/driver/twai.h +++ b/components/driver/twai/include/driver/twai.h @@ -18,7 +18,9 @@ extern "C" { #endif /* -------------------- Default initializers and flags ---------------------- */ + /** @cond */ //Doxy command to hide preprocessor definitions from docs + /** * @brief Initializer macro for general configuration structure. * diff --git a/components/esp_hw_support/include/esp_intr_alloc.h b/components/esp_hw_support/include/esp_intr_alloc.h index 369084886f1..3106332c0de 100644 --- a/components/esp_hw_support/include/esp_intr_alloc.h +++ b/components/esp_hw_support/include/esp_intr_alloc.h @@ -45,9 +45,10 @@ extern "C" { #define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) ///< Low and medium prio interrupts. These can be handled in C. #define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6|ESP_INTR_FLAG_NMI) ///< High level interrupts. Need to be handled in assembly. +/** Mask for all level flags */ #define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \ ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \ - ESP_INTR_FLAG_NMI) ///< Mask for all level flags + ESP_INTR_FLAG_NMI) /** @addtogroup Intr_Alloc_Pseudo_Src diff --git a/components/hal/include/hal/twai_types.h b/components/hal/include/hal/twai_types.h index 7f3789fe2b7..d22c50d3ff1 100644 --- a/components/hal/include/hal/twai_types.h +++ b/components/hal/include/hal/twai_types.h @@ -27,6 +27,7 @@ extern "C" { #define TWAI_ERR_PASS_THRESH 128 /**< Error counter threshold for error passive */ /** @cond */ //Doxy command to hide preprocessor definitions from docs + /** * @brief TWAI Message flags * From 7f9b5deae1fad1b2e69a09ad5d0629c22c2ec419 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 19 Apr 2024 14:03:29 +0800 Subject: [PATCH 163/548] feat(ulp): support interrupts for C6/P4 LP core Closes https://github.com/espressif/esp-idf/issues/13059 --- .../hal/esp32c6/include/hal/lp_core_ll.h | 11 ++ components/hal/esp32c6/include/hal/pmu_ll.h | 10 ++ .../hal/esp32c6/include/hal/rtc_io_ll.h | 21 +++ components/hal/esp32p4/include/hal/pmu_ll.h | 10 ++ .../hal/esp32p4/include/hal/rtc_io_ll.h | 22 ++- components/ulp/cmake/CMakeLists.txt | 3 +- components/ulp/lp_core/include/ulp_lp_core.h | 8 + components/ulp/lp_core/lp_core.c | 12 +- .../lp_core/include/ulp_lp_core_gpio.h | 42 +++++- .../lp_core/include/ulp_lp_core_interrupts.h | 59 ++++++++ .../lp_core/include/ulp_lp_core_print.h | 6 +- .../lp_core/include/ulp_lp_core_utils.h | 19 ++- .../ulp/lp_core/lp_core/lp_core_interrupt.c | 92 ++++++++++++ .../ulp/lp_core/lp_core/lp_core_print.c | 1 + .../ulp/lp_core/lp_core/lp_core_utils.c | 10 ++ .../ulp/lp_core/lp_core/port/esp32c6/vector.S | 138 ++++++++++++++++++ .../ulp/lp_core/lp_core/port/esp32p4/vector.S | 59 ++++++++ components/ulp/lp_core/lp_core/start.S | 5 + components/ulp/lp_core/lp_core/vector.S | 24 --- .../ulp/test_apps/lp_core/main/CMakeLists.txt | 1 + .../lp_core/main/lp_core/test_main_isr.c | 42 ++++++ .../ulp/test_apps/lp_core/main/test_lp_core.c | 54 +++++++ docs/component_info_ignore_file.txt | 1 + docs/doxygen/Doxyfile_esp32c6 | 1 + docs/doxygen/Doxyfile_esp32p4 | 1 + docs/en/api-reference/system/ulp-lp-core.rst | 20 +++ examples/system/.build-test-rules.yml | 6 + .../ulp/lp_core/interrupt/CMakeLists.txt | 8 + .../system/ulp/lp_core/interrupt/README.md | 19 +++ .../ulp/lp_core/interrupt/main/CMakeLists.txt | 25 ++++ .../ulp/lp_core/interrupt/main/lp_core/main.c | 30 ++++ .../interrupt/main/lp_interrupts_main.c | 53 +++++++ .../lp_core/interrupt/pytest_lp_core_intr.py | 11 ++ .../ulp/lp_core/interrupt/sdkconfig.defaults | 4 + 34 files changed, 796 insertions(+), 32 deletions(-) create mode 100644 components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h create mode 100644 components/ulp/lp_core/lp_core/lp_core_interrupt.c create mode 100644 components/ulp/lp_core/lp_core/port/esp32c6/vector.S create mode 100644 components/ulp/lp_core/lp_core/port/esp32p4/vector.S delete mode 100644 components/ulp/lp_core/lp_core/vector.S create mode 100644 components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c create mode 100644 examples/system/ulp/lp_core/interrupt/CMakeLists.txt create mode 100644 examples/system/ulp/lp_core/interrupt/README.md create mode 100644 examples/system/ulp/lp_core/interrupt/main/CMakeLists.txt create mode 100644 examples/system/ulp/lp_core/interrupt/main/lp_core/main.c create mode 100644 examples/system/ulp/lp_core/interrupt/main/lp_interrupts_main.c create mode 100644 examples/system/ulp/lp_core/interrupt/pytest_lp_core_intr.py create mode 100644 examples/system/ulp/lp_core/interrupt/sdkconfig.defaults diff --git a/components/hal/esp32c6/include/hal/lp_core_ll.h b/components/hal/esp32c6/include/hal/lp_core_ll.h index 7c6c5667ef5..7ac68a96328 100644 --- a/components/hal/esp32c6/include/hal/lp_core_ll.h +++ b/components/hal/esp32c6/include/hal/lp_core_ll.h @@ -12,6 +12,7 @@ #pragma once #include +#include #include "soc/lpperi_struct.h" #include "soc/pmu_struct.h" #include "soc/lp_aon_struct.h" @@ -125,6 +126,16 @@ static inline void lp_core_ll_request_sleep(void) PMU.lp_ext.pwr1.sleep_req = 1; } +/** + * @brief Get which interrupts have triggered on the LP core + * + * @return uint8_t bit mask of triggered LP interrupt sources + */ +static inline uint8_t lp_core_ll_get_triggered_interrupt_srcs(void) +{ + return LPPERI.interrupt_source.lp_interrupt_source; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/pmu_ll.h b/components/hal/esp32c6/include/hal/pmu_ll.h index 2470f73247c..2d47479166f 100644 --- a/components/hal/esp32c6/include/hal/pmu_ll.h +++ b/components/hal/esp32c6/include/hal/pmu_ll.h @@ -541,6 +541,16 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) hw->lp_ext.int_clr.val = mask; } +FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw) +{ + hw->lp_ext.int_clr.sw_trigger = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_enable_sw_intr(pmu_dev_t *hw, bool enable) +{ + hw->lp_ext.int_ena.sw_trigger = enable; +} + FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index 550d6accf06..987c2b94b79 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -40,6 +40,15 @@ typedef enum { RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; +typedef enum { + RTCIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + RTCIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + RTCIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + RTCIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ +} rtcio_ll_intr_type_t; + typedef enum { RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ @@ -316,6 +325,18 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_IO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } +/** + * Enable interrupt function and set interrupt type + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param type Interrupt type on high level or low level. + */ + +static inline void rtcio_ll_intr_enable(int rtcio_num, rtcio_ll_intr_type_t type) +{ + LP_IO.pin[rtcio_num].int_type = type; +} + /** * Enable rtc io output in deep sleep. * diff --git a/components/hal/esp32p4/include/hal/pmu_ll.h b/components/hal/esp32p4/include/hal/pmu_ll.h index 057428e1326..9534196f0c4 100644 --- a/components/hal/esp32p4/include/hal/pmu_ll.h +++ b/components/hal/esp32p4/include/hal/pmu_ll.h @@ -30,6 +30,16 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) hw->lp_ext.int_clr.val = mask; } +FORCE_INLINE_ATTR void pmu_ll_lp_clear_sw_intr_status(pmu_dev_t *hw) +{ + hw->lp_ext.int_clr.hp_sw_trigger = 1; +} + +FORCE_INLINE_ATTR void pmu_ll_lp_enable_sw_intr(pmu_dev_t *hw, bool enable) +{ + hw->lp_ext.int_ena.hp_sw_trigger = enable; +} + FORCE_INLINE_ATTR void pmu_ll_hp_set_dig_power(pmu_dev_t *hw, pmu_hp_mode_t mode, uint32_t flag) { hw->hp_sys[mode].dig_power.val = flag; diff --git a/components/hal/esp32p4/include/hal/rtc_io_ll.h b/components/hal/esp32p4/include/hal/rtc_io_ll.h index 763e8f2eeee..a23bb2ead03 100644 --- a/components/hal/esp32p4/include/hal/rtc_io_ll.h +++ b/components/hal/esp32p4/include/hal/rtc_io_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,15 @@ typedef enum { RTCIO_LL_WAKEUP_HIGH_LEVEL = 0x5, /*!< GPIO interrupt type : input high level trigger */ } rtcio_ll_wake_type_t; +typedef enum { + RTCIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ + RTCIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + RTCIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + RTCIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + RTCIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + RTCIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ +} rtcio_ll_intr_type_t; + typedef enum { RTCIO_LL_OUTPUT_NORMAL = 0, /*!< RTCIO output mode is normal. */ RTCIO_LL_OUTPUT_OD = 0x1, /*!< RTCIO output mode is open-drain. */ @@ -341,6 +350,17 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) LP_GPIO.pin[rtcio_num].int_type = RTCIO_LL_WAKEUP_DISABLE; } +/** + * Enable interrupt function and set interrupt type + * + * @param rtcio_num The index of rtcio. 0 ~ MAX(rtcio). + * @param type Interrupt type on high level or low level. + */ +static inline void rtcio_ll_intr_enable(int rtcio_num, rtcio_ll_intr_type_t type) +{ + LP_GPIO.pin[rtcio_num].int_type = type; +} + /** * @brief Enable RTCIO output in deep sleep. * diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index dceac3f78d1..9b35eb75ba1 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -101,7 +101,7 @@ if(ULP_COCPU_IS_RISCV) elseif(ULP_COCPU_IS_LP_CORE) list(APPEND ULP_S_SOURCES "${IDF_PATH}/components/ulp/lp_core/lp_core/start.S" - "${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S" + "${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector.S" "${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c" "${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c" @@ -111,6 +111,7 @@ elseif(ULP_COCPU_IS_LP_CORE) "${IDF_PATH}/components/hal/uart_hal.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c" + "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c") target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles") diff --git a/components/ulp/lp_core/include/ulp_lp_core.h b/components/ulp/lp_core/include/ulp_lp_core.h index 9a17cd5c800..447c814ddac 100644 --- a/components/ulp/lp_core/include/ulp_lp_core.h +++ b/components/ulp/lp_core/include/ulp_lp_core.h @@ -63,6 +63,14 @@ esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_ */ void ulp_lp_core_stop(void); +/** + * @brief Trigger a SW interrupt to the LP CPU from the PMU + * + * @note This is the same SW trigger that is used to wake up the LP CPU + * + */ +void ulp_lp_core_sw_intr_trigger(void); + #ifdef __cplusplus } #endif diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c index 71aefe24295..e578e077acd 100644 --- a/components/ulp/lp_core/lp_core.c +++ b/components/ulp/lp_core/lp_core.c @@ -36,6 +36,8 @@ const static char* TAG = "ulp-lp-core"; #define WAKEUP_SOURCE_MAX_NUMBER 5 +#define RESET_HANDLER_ADDR (intptr_t)(&_rtc_ulp_memory_start + 0x80 / 4) // Placed after the 0x80 byte long vector table + /* Maps the flags defined in ulp_lp_core.h e.g. ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU to their actual HW values */ static uint32_t wakeup_src_sw_to_hw_flag_lookup[WAKEUP_SOURCE_MAX_NUMBER] = { LP_CORE_LL_WAKEUP_SOURCE_HP_CPU, @@ -68,7 +70,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg) /* If we have a LP ROM we boot from it, before jumping to the app code */ intptr_t boot_addr; if (cfg->skip_lp_rom_boot) { - boot_addr = (intptr_t)(&_rtc_ulp_memory_start); + boot_addr = RESET_HANDLER_ADDR; } else { boot_addr = SOC_LP_ROM_LOW; /* Disable UART init in ROM, it defaults to XTAL clk src @@ -80,7 +82,8 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg) } lp_core_ll_set_boot_address(boot_addr); - lp_core_ll_set_app_boot_address((intptr_t)(&_rtc_ulp_memory_start)); + lp_core_ll_set_app_boot_address(RESET_HANDLER_ADDR); + #endif //ESP_ROM_HAS_LP_ROM LP_CORE_RCC_ATOMIC() { @@ -161,3 +164,8 @@ void ulp_lp_core_stop(void) lp_core_ll_set_wakeup_source(0); lp_core_ll_request_sleep(); } + +void ulp_lp_core_sw_intr_trigger(void) +{ + lp_core_ll_hp_wake_lp(); +} diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h index 42745dc1863..ffae3261141 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ extern "C" { #endif +#include "soc/soc_caps.h" #include "hal/gpio_types.h" #include "hal/rtc_io_ll.h" @@ -25,8 +26,27 @@ typedef enum { LP_IO_NUM_5 = 5, /*!< GPIO5, input and output */ LP_IO_NUM_6 = 6, /*!< GPIO6, input and output */ LP_IO_NUM_7 = 7, /*!< GPIO7, input and output */ +#if SOC_RTCIO_PIN_COUNT > 8 + LP_IO_NUM_8 = 8, /*!< GPIO8, input and output */ + LP_IO_NUM_9 = 9, /*!< GPIO9, input and output */ + LP_IO_NUM_10 = 10, /*!< GPIO10, input and output */ + LP_IO_NUM_11 = 11, /*!< GPIO11, input and output */ + LP_IO_NUM_12 = 12, /*!< GPIO12, input and output */ + LP_IO_NUM_13 = 13, /*!< GPIO13, input and output */ + LP_IO_NUM_14 = 14, /*!< GPIO14, input and output */ + LP_IO_NUM_15 = 15, /*!< GPIO15, input and output */ +#endif } lp_io_num_t; +typedef enum { + LP_IO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ + LP_IO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + LP_IO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + LP_IO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + LP_IO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + LP_IO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ +} lp_io_intr_type_t; + /** * @brief Initialize a rtcio pin * @@ -153,6 +173,26 @@ static inline void ulp_lp_core_gpio_pulldown_disable(lp_io_num_t lp_io_num) rtcio_ll_pulldown_disable(lp_io_num); } +/** + * @brief Enable interrupt for lp io pin + * + * @param lp_io_num The lp io pin to enable interrupt for + * @param intr_type The interrupt type to enable + */ +static inline void ulp_lp_core_gpio_intr_enable(lp_io_num_t lp_io_num, lp_io_intr_type_t intr_type) +{ + rtcio_ll_intr_enable(lp_io_num, intr_type); +} + +/** + * @brief Clear interrupt status for all lp io + * + */ +static inline void ulp_lp_core_gpio_clear_intr_status(void) +{ + rtcio_ll_clear_interrupt_status(); +} + #ifdef __cplusplus } #endif diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h new file mode 100644 index 00000000000..f7577119743 --- /dev/null +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_IDF_TARGET_ESP32C6 +#define LP_CORE_ISR_ATTR // On C6 registers are saved by us before calling the ISR +#else +#define LP_CORE_ISR_ATTR __attribute__((interrupt)) +#endif + +/** + * Available interrupt handlers for the low power core are as follows: + * + * ulp_lp_core_lp_io_intr_handler(void); + * ulp_lp_core_lp_i2c_intr_handler(void); + * ulp_lp_core_lp_uart_intr_handler(void); + * ulp_lp_core_lp_timer_intr_handler(void); + * ulp_lp_core_lp_pmu_intr_handler(void); + * ulp_lp_core_lp_spi_intr_handler(void); + * ulp_lp_core_trng_intr_handler(void); + * ulp_lp_core_lp_adc_intr_handler(void); + * ulp_lp_core_lp_touch_intr_handler(void); + * ulp_lp_core_tsens_intr_handler(void); + * ulp_lp_core_efuse_intr_handler(void); + * ulp_lp_core_lp_sysreg_intr_handler(void); + * ulp_lp_core_lp_ana_peri_intr_handler(void); + * ulp_lp_core_mailbox_intr_handler(void); + * ulp_lp_core_lp_wdt_intr_handler(void); + * ulp_lp_core_lp_rtc_intr_handler(void); + * ulp_lp_core_sw_intr_handler(void); + * + * Not all handlers are available on all chips. Please refer to the Technical Reference Manual for your chip for more information. +*/ + +/** + * @brief Enables interrupts globally for the low power core + * + */ +void ulp_lp_core_intr_enable(void); + +/** + * @brief Disables interrupts globally for the low power core + * + */ +void ulp_lp_core_intr_disable(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h index 56401145d73..6544ba72014 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h @@ -3,6 +3,8 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#pragma once + #include "sdkconfig.h" /** @@ -17,7 +19,7 @@ */ #if CONFIG_ULP_ROM_PRINT_ENABLE extern int ets_printf(const char* format, ...); -int (*lp_core_printf)(const char* format, ...) = ets_printf; +#define lp_core_printf ets_printf #else //TODO: Change return type from void to int in IDF 6.0 void lp_core_printf(const char* format, ...); @@ -33,5 +35,5 @@ void lp_core_printf(const char* format, ...); * powered down during sleep. */ extern void ets_install_uart_printf(void); -void (*lp_core_install_uart_printf)(void) = ets_install_uart_printf; +#define lp_core_install_uart_print ets_install_uart_printf #endif /* CONFIG_ULP_ROM_PRINT_ENABLE */ diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h index bee3d6c574f..89845252202 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ extern "C" { #include #include +#include /** * @brief Traverse all possible wake-up sources and update the wake-up cause so that @@ -72,6 +73,22 @@ __attribute__((__noreturn__)) void ulp_lp_core_halt(void); */ __attribute__((__noreturn__)) void ulp_lp_core_stop_lp_core(void); +/** + * @brief Enable the SW triggered interrupt from the PMU + * + * @note This is the same SW trigger interrupt that is used to wake up the LP CPU + * + * @param enable true to enable, false to disable + * + */ +void ulp_lp_core_sw_intr_enable(bool enable); + +/** + * @brief Clear the interrupt status for the SW triggered interrupt from the PMU + * + */ +void ulp_lp_core_sw_intr_clear(void); + #ifdef __cplusplus } #endif diff --git a/components/ulp/lp_core/lp_core/lp_core_interrupt.c b/components/ulp/lp_core/lp_core/lp_core_interrupt.c new file mode 100644 index 00000000000..114973b9cba --- /dev/null +++ b/components/ulp/lp_core/lp_core/lp_core_interrupt.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "sdkconfig.h" +#include "hal/lp_core_ll.h" +#include "riscv/rv_utils.h" + +#if CONFIG_IDF_TARGET_ESP32C6 +/* Enable interrupt 30, which all external interrupts are routed to*/ +#define MIE_ALL_INTS_MASK (1 << 30) +#else +/* Enable all external interrupts routed to CPU, expect HP_INTR, + as this would trigger an LP core interrupt for every single interrupt + that triggers on HP Core. + */ +#define MIE_ALL_INTS_MASK 0x3FFF0888 +#endif + +void ulp_lp_core_intr_enable(void) +{ + /* Enable interrupt globally */ + RV_SET_CSR(mstatus, MSTATUS_MIE); + RV_SET_CSR(mie, MIE_ALL_INTS_MASK); + +} + +void ulp_lp_core_intr_disable(void) +{ + RV_CLEAR_CSR(mie, MIE_ALL_INTS_MASK); + /* Disable interrupts globally */ + RV_CLEAR_CSR(mstatus, MSTATUS_MIE); +} + +static void ulp_lp_core_default_intr_handler(void) +{ + abort(); +} + +/* Default ISR handlers, intended to be overwritten by users */ +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_io_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_i2c_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_uart_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_timer_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_pmu_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_spi_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_trng_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_adc_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_touch_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_tsens_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_efuse_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_sysreg_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_ana_peri_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_mailbox_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_wdt_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_rtc_intr_handler(void); +void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_sw_intr_handler(void); + +void ulp_lp_core_panic_handler(void) +{ + abort(); +} + +#if CONFIG_IDF_TARGET_ESP32C6 + +static void* s_intr_handlers[] = { + ulp_lp_core_lp_io_intr_handler, + ulp_lp_core_lp_i2c_intr_handler, + ulp_lp_core_lp_uart_intr_handler, + ulp_lp_core_lp_timer_intr_handler, + 0, // Reserved / Unused + ulp_lp_core_lp_pmu_intr_handler, +}; + +void __attribute__((weak)) ulp_lp_core_intr_handler(void) +{ + uint8_t intr_source = lp_core_ll_get_triggered_interrupt_srcs(); + for (int i = 0; i < sizeof(s_intr_handlers) / 4; i++) { + if (intr_source & (1 << i)) { + void (*handler)(void) = s_intr_handlers[i]; + if (handler) { + handler(); + } + } + } +} + +#endif diff --git a/components/ulp/lp_core/lp_core/lp_core_print.c b/components/ulp/lp_core/lp_core/lp_core_print.c index 785d59e6c47..a14a91bcc64 100644 --- a/components/ulp/lp_core/lp_core/lp_core_print.c +++ b/components/ulp/lp_core/lp_core/lp_core_print.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include "sdkconfig.h" #include "ulp_lp_core_uart.h" #if !CONFIG_ULP_ROM_PRINT_ENABLE diff --git a/components/ulp/lp_core/lp_core/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index 6c48a4ea28e..7fa9657c7f2 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -135,3 +135,13 @@ void __attribute__((noreturn)) abort(void) while (1); } + +void ulp_lp_core_sw_intr_enable(bool enable) +{ + pmu_ll_lp_enable_sw_intr(&PMU, enable); +} + +void ulp_lp_core_sw_intr_clear(void) +{ + pmu_ll_lp_clear_sw_intr_status(&PMU); +} diff --git a/components/ulp/lp_core/lp_core/port/esp32c6/vector.S b/components/ulp/lp_core/lp_core/port/esp32c6/vector.S new file mode 100644 index 00000000000..32331e71b46 --- /dev/null +++ b/components/ulp/lp_core/lp_core/port/esp32c6/vector.S @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "riscv/rvruntime-frames.h" + + .equ SAVE_REGS, 32 + .equ CONTEXT_SIZE, (SAVE_REGS * 4) +/* Macro which first allocates space on the stack to save general + * purpose registers, and then save them. GP register is excluded. + * The default size allocated on the stack is CONTEXT_SIZE, but it + * can be overridden. */ +.macro save_general_regs cxt_size=CONTEXT_SIZE + addi sp, sp, -\cxt_size + sw ra, RV_STK_RA(sp) + sw tp, RV_STK_TP(sp) + sw t0, RV_STK_T0(sp) + sw t1, RV_STK_T1(sp) + sw t2, RV_STK_T2(sp) + sw s0, RV_STK_S0(sp) + sw s1, RV_STK_S1(sp) + sw a0, RV_STK_A0(sp) + sw a1, RV_STK_A1(sp) + sw a2, RV_STK_A2(sp) + sw a3, RV_STK_A3(sp) + sw a4, RV_STK_A4(sp) + sw a5, RV_STK_A5(sp) + sw a6, RV_STK_A6(sp) + sw a7, RV_STK_A7(sp) + sw s2, RV_STK_S2(sp) + sw s3, RV_STK_S3(sp) + sw s4, RV_STK_S4(sp) + sw s5, RV_STK_S5(sp) + sw s6, RV_STK_S6(sp) + sw s7, RV_STK_S7(sp) + sw s8, RV_STK_S8(sp) + sw s9, RV_STK_S9(sp) + sw s10, RV_STK_S10(sp) + sw s11, RV_STK_S11(sp) + sw t3, RV_STK_T3(sp) + sw t4, RV_STK_T4(sp) + sw t5, RV_STK_T5(sp) + sw t6, RV_STK_T6(sp) +.endm + +.macro save_mepc + csrr t0, mepc + sw t0, RV_STK_MEPC(sp) +.endm + +/* Restore the general purpose registers (excluding gp) from the context on + * the stack. The context is then deallocated. The default size is CONTEXT_SIZE + * but it can be overridden. */ +.macro restore_general_regs cxt_size=CONTEXT_SIZE + lw ra, RV_STK_RA(sp) + lw tp, RV_STK_TP(sp) + lw t0, RV_STK_T0(sp) + lw t1, RV_STK_T1(sp) + lw t2, RV_STK_T2(sp) + lw s0, RV_STK_S0(sp) + lw s1, RV_STK_S1(sp) + lw a0, RV_STK_A0(sp) + lw a1, RV_STK_A1(sp) + lw a2, RV_STK_A2(sp) + lw a3, RV_STK_A3(sp) + lw a4, RV_STK_A4(sp) + lw a5, RV_STK_A5(sp) + lw a6, RV_STK_A6(sp) + lw a7, RV_STK_A7(sp) + lw s2, RV_STK_S2(sp) + lw s3, RV_STK_S3(sp) + lw s4, RV_STK_S4(sp) + lw s5, RV_STK_S5(sp) + lw s6, RV_STK_S6(sp) + lw s7, RV_STK_S7(sp) + lw s8, RV_STK_S8(sp) + lw s9, RV_STK_S9(sp) + lw s10, RV_STK_S10(sp) + lw s11, RV_STK_S11(sp) + lw t3, RV_STK_T3(sp) + lw t4, RV_STK_T4(sp) + lw t5, RV_STK_T5(sp) + lw t6, RV_STK_T6(sp) + addi sp,sp, \cxt_size +.endm + +.macro restore_mepc + lw t0, RV_STK_MEPC(sp) + csrw mepc, t0 +.endm + + + .section .init.vector,"ax" + + .global _vector_table + .type _vector_table, @function +_vector_table: + .option push + .option norvc + + .rept 30 + j _panic_handler + .endr + j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry + j _panic_handler + + .option pop + .size _vector_table, .-_vector_table + + +/* _panic_handler: handle all exception */ + .section .text.handlers,"ax" + .global _panic_handler + .type _panic_handler, @function +_panic_handler: + call ulp_lp_core_panic_handler +_end: + j _end /* loop forever */ + + +/* interrupt_handler: handle all interrupt */ + .section .text.handlers,"ax" + .global _interrupt_handler + .type _interrupt_handler, @function +_interrupt_handler: + /* save registers & mepc to stack */ + save_general_regs + save_mepc + + call ulp_lp_core_intr_handler + + /* restore registers & mepc from stack */ + restore_mepc + restore_general_regs + /* exit, this will also re-enable the interrupts */ + mret diff --git a/components/ulp/lp_core/lp_core/port/esp32p4/vector.S b/components/ulp/lp_core/lp_core/port/esp32p4/vector.S new file mode 100644 index 00000000000..3853c6df502 --- /dev/null +++ b/components/ulp/lp_core/lp_core/port/esp32p4/vector.S @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .init.vector,"ax" + + .global _vector_table + .type _vector_table, @function +_vector_table: + .option push + .option norvc + + j _panic_handler + j _panic_handler + j _panic_handler + j ulp_lp_core_sw_intr_handler + j _panic_handler + j _panic_handler + j _panic_handler + j ulp_lp_core_lp_uart_intr_handler + j _panic_handler + j _panic_handler + j _panic_handler + j ulp_lp_core_lp_spi_intr_handler + j _panic_handler + j _panic_handler + j _panic_handler + j _panic_handler + j ulp_lp_core_trng_intr_handler + j ulp_lp_core_lp_i2c_intr_handler + j ulp_lp_core_lp_io_intr_handler + j ulp_lp_core_lp_adc_intr_handler + j ulp_lp_core_lp_touch_intr_handler + j ulp_lp_core_tsens_intr_handler + j ulp_lp_core_efuse_intr_handler + j ulp_lp_core_lp_sysreg_intr_handler + j ulp_lp_core_lp_ana_peri_intr_handler + j ulp_lp_core_lp_pmu_intr_handler + j ulp_lp_core_mailbox_intr_handler + j ulp_lp_core_lp_timer_intr_handler + j ulp_lp_core_lp_wdt_intr_handler + j ulp_lp_core_lp_rtc_intr_handler + j _panic_handler + j _panic_handler + + .option pop + .size _vector_table, .-_vector_table + + +/* _panic_handler: handle all exception */ + .section .text.handlers,"ax" + .global _panic_handler + .type _panic_handler, @function +_panic_handler: + call ulp_lp_core_panic_handler +_end: + j _end /* loop forever */ diff --git a/components/ulp/lp_core/lp_core/start.S b/components/ulp/lp_core/lp_core/start.S index f13a8819bdd..b4665c9a3cb 100644 --- a/components/ulp/lp_core/lp_core/start.S +++ b/components/ulp/lp_core/lp_core/start.S @@ -9,6 +9,11 @@ /* The reset vector, jumps to startup code */ reset_vector: + + /* _vector_table: Only 256-byte aligned addresses are allowed */ + la t0, _vector_table + csrw mtvec, t0 + j __start __start: diff --git a/components/ulp/lp_core/lp_core/vector.S b/components/ulp/lp_core/lp_core/vector.S deleted file mode 100644 index 76c41a81b12..00000000000 --- a/components/ulp/lp_core/lp_core/vector.S +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - - .section .init.vector,"ax" - /* This is the vector table. It is currently empty, but will be populated - * with exception and interrupt handlers when this is supported - */ - - .align 0x4, 0xff - .global _vector_table - .type _vector_table, @function -_vector_table: - .option push - .option norvc - - .rept 32 - nop - .endr - - .option pop - .size _vector_table, .-_vector_table diff --git a/components/ulp/test_apps/lp_core/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/main/CMakeLists.txt index d539efc8fbf..d9084ea2bf6 100644 --- a/components/ulp/test_apps/lp_core/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/main/CMakeLists.txt @@ -26,6 +26,7 @@ set(lp_core_exp_dep_srcs ${app_sources}) ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}") ulp_embed_binary(lp_core_test_app_counter "${lp_core_sources_counter}" "${lp_core_exp_dep_srcs}") +ulp_embed_binary(lp_core_test_app_isr "lp_core/test_main_isr.c" "${lp_core_exp_dep_srcs}") if(CONFIG_SOC_LP_TIMER_SUPPORTED) ulp_embed_binary(lp_core_test_app_set_timer_wakeup "${lp_core_sources_set_timer_wakeup}" "${lp_core_exp_dep_srcs}") diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c new file mode 100644 index 00000000000..c3cc33c9106 --- /dev/null +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_interrupts.h" +#include "ulp_lp_core_gpio.h" +#include "hal/pmu_ll.h" + +volatile uint32_t io_isr_counter = 0; +volatile uint32_t pmu_isr_counter = 0; +volatile bool isr_test_started; + +void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void) +{ + ulp_lp_core_gpio_clear_intr_status(); + io_isr_counter++; +} + +void LP_CORE_ISR_ATTR ulp_lp_core_lp_pmu_intr_handler(void) +{ + ulp_lp_core_sw_intr_clear(); + pmu_isr_counter++; +} + +int main(void) +{ + ulp_lp_core_sw_intr_enable(true); + + ulp_lp_core_intr_enable(); + + isr_test_started = true; + + while (1) { + // Busy wait for the interrupts to occur + } + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core.c b/components/ulp/test_apps/lp_core/main/test_lp_core.c index c1ebaaaf0e0..a1dddc91ca4 100644 --- a/components/ulp/test_apps/lp_core/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/main/test_lp_core.c @@ -11,6 +11,7 @@ #include "esp_rom_caps.h" #include "lp_core_test_app.h" #include "lp_core_test_app_counter.h" +#include "lp_core_test_app_isr.h" #if SOC_LP_TIMER_SUPPORTED #include "lp_core_test_app_set_timer_wakeup.h" @@ -26,6 +27,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "hal/lp_core_ll.h" +#include "hal/rtc_io_ll.h" +#include "driver/rtc_io.h" + extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start"); extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end"); @@ -38,6 +43,9 @@ extern const uint8_t lp_core_main_set_timer_wakeup_bin_end[] asm("_binary_lp_c extern const uint8_t lp_core_main_gpio_bin_start[] asm("_binary_lp_core_test_app_gpio_bin_start"); extern const uint8_t lp_core_main_gpio_bin_end[] asm("_binary_lp_core_test_app_gpio_bin_end"); +extern const uint8_t lp_core_main_isr_bin_start[] asm("_binary_lp_core_test_app_isr_bin_start"); +extern const uint8_t lp_core_main_isr_bin_end[] asm("_binary_lp_core_test_app_isr_bin_end"); + static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) { TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, @@ -329,3 +337,49 @@ TEST_CASE("LP core gpio tests", "[ulp]") } #endif //SOC_LP_TIMER_SUPPORTED + +#define ISR_TEST_ITERATIONS 100 +#define IO_TEST_PIN 0 +#include "lp_core_uart.h" + +TEST_CASE("LP core ISR tests", "[ulp]") +{ + lp_core_uart_cfg_t ucfg = LP_CORE_UART_DEFAULT_CONFIG(); + + ESP_ERROR_CHECK(lp_core_uart_init(&ucfg)); + + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_isr_bin_start, lp_core_main_isr_bin_end); + + while (!ulp_isr_test_started) { + } + + for (int i = 0; i < ISR_TEST_ITERATIONS; i++) { + lp_core_ll_hp_wake_lp(); + vTaskDelay(pdMS_TO_TICKS(10)); + } + + printf("ULP PMU ISR triggered %"PRIu32" times\n", ulp_pmu_isr_counter); + TEST_ASSERT_EQUAL(ISR_TEST_ITERATIONS, ulp_pmu_isr_counter); + + /* Test LP IO interrupt */ + rtc_gpio_init(IO_TEST_PIN); + rtc_gpio_set_direction(IO_TEST_PIN, RTC_GPIO_MODE_INPUT_ONLY); + TEST_ASSERT_EQUAL(0, ulp_io_isr_counter); + + for (int i = 0; i < ISR_TEST_ITERATIONS; i++) { +#if CONFIG_IDF_TARGET_ESP32C6 + LP_IO.status_w1ts.val = 0x00000001; // Set GPIO 0 intr status to high +#else + LP_GPIO.status_w1ts.val = 0x00000001; // Set GPIO 0 intr status to high +#endif + vTaskDelay(pdMS_TO_TICKS(10)); + } + + printf("ULP LP IO ISR triggered %"PRIu32" times\n", ulp_io_isr_counter); + TEST_ASSERT_EQUAL(ISR_TEST_ITERATIONS, ulp_io_isr_counter); +} diff --git a/docs/component_info_ignore_file.txt b/docs/component_info_ignore_file.txt index 32bb50d4eb7..21b0fd9c0c6 100644 --- a/docs/component_info_ignore_file.txt +++ b/docs/component_info_ignore_file.txt @@ -6,6 +6,7 @@ components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h +components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h # ESSL headers do not belong to any IDF component, in a user project it will come from a managed component components/driver/test_apps/components/esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio.h components/driver/test_apps/components/esp_serial_slave_link/include/esp_serial_slave_link/essl_spi.h diff --git a/docs/doxygen/Doxyfile_esp32c6 b/docs/doxygen/Doxyfile_esp32c6 index c99dfba77bc..ddd75aad3c7 100644 --- a/docs/doxygen/Doxyfile_esp32c6 +++ b/docs/doxygen/Doxyfile_esp32c6 @@ -7,6 +7,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \ + $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \ $(PROJECT_PATH)/components/bt/include/esp32c6/include/esp_bt.h \ $(PROJECT_PATH)/components/esp_phy/include/esp_phy_init.h \ $(PROJECT_PATH)/components/esp_phy/include/esp_phy_cert_test.h \ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index 7c914430b39..70c98b4c05c 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -7,6 +7,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \ + $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \ $(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_host.h \ diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index d53d6438d8a..4d80c88c600 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -178,6 +178,24 @@ To enhance the capabilities of the ULP LP-Core coprocessor, it has access to per Since these functions are already present in LP-ROM no matter what, using these in your program allows you to reduce the RAM footprint of your ULP application. +ULP LP-Core interrupts +---------------------- + +The LP-Core coprocessor can be configured to handle interrupts from various sources. Examples of such interrupts could be LP IO low/high or LP timer interrupts. To register a handler for an interrupt simply override any of the weak handlers provided by IDF. A complete list of handlers can be found in :component_file:`ulp_lp_core_interrupts.h `. For details on which interrupts are available on a specific target, please consult the Low Power CPU chapter in the Technical Reference Manual.` + +For example, to override the handler for the LP IO interrupt, you can define the following function in your ULP LP-Core code: + +.. code-block:: c + + void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void) + { + // Handle the interrupt and clear the interrupt source + } + +:c:macro:`LP_CORE_ISR_ATTR` is a macro that is used to define the interrupt handler function. This macro ensures that registers are saved and restored correctly when the interrupt handler is called. + +In addition to configuring the interrupt related registers for the interrupt source you want to handle, you also need to enable the interrupts globally in the LP-Core interrupt controller. This can be done using the :cpp:func:`ulp_lp_core_intr_enable` function. + Application Examples -------------------- @@ -185,6 +203,7 @@ Application Examples * :example:`system/ulp/lp_core/lp_i2c` reads external I2C ambient light sensor (BH1750) while the main CPU is in Deep-sleep and wakes up the main CPU once a threshold is met. * :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` reads data written to a serial console and echoes it back. This example demonstrates the usage of the LP UART driver running on the LP core. * :example:`system/ulp/lp_core/lp_uart/lp_uart_print` shows how to print various statements from a program running on the LP core. +* :example:`system/ulp/lp_core/interrupt` shows how to register an interrupt handler on the LP core to receive an interrupt triggered by the main CPU. API Reference ------------- @@ -204,3 +223,4 @@ LP Core API Reference .. include-build-file:: inc/ulp_lp_core_i2c.inc .. include-build-file:: inc/ulp_lp_core_uart.inc .. include-build-file:: inc/ulp_lp_core_print.inc +.. include-build-file:: inc/ulp_lp_core_interrupts.inc diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index 5bc2392b620..bcfa80fbd39 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -264,6 +264,12 @@ examples/system/ulp/lp_core/gpio: depends_components: - ulp +examples/system/ulp/lp_core/interrupt: + enable: + - if: SOC_LP_CORE_SUPPORTED == 1 + depends_components: + - ulp + examples/system/ulp/lp_core/lp_i2c: enable: - if: SOC_LP_I2C_SUPPORTED == 1 diff --git a/examples/system/ulp/lp_core/interrupt/CMakeLists.txt b/examples/system/ulp/lp_core/interrupt/CMakeLists.txt new file mode 100644 index 00000000000..de93ae527f4 --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(interrupts) diff --git a/examples/system/ulp/lp_core/interrupt/README.md b/examples/system/ulp/lp_core/interrupt/README.md new file mode 100644 index 00000000000..b508bd913da --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/README.md @@ -0,0 +1,19 @@ +| Supported Targets | ESP32-C6 | ESP32-P4 | +| ----------------- | -------- | -------- | + +# LP-Core example with interrupt triggered from HP-Core: + +This example demonstrates how to program the ULP coprocessor to receive an interrupt triggered by the HP-Core + +ULP program written in C can be found across `lp_core/main.c`. The build system compiles and links this program, converts it into binary format, and embeds it into the .rodata section of the ESP-IDF application. + +At runtime, the application running inside the main CPU loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. The main code then configures the ULP and starts the coprocessor by using `ulp_lp_core_run`. Once the ULP program is started, it runs continuously, waiting for interrupts. The main program will periodically trigger interrupts on the LP-Core. + +After triggering a certain amount of interrupts, the main core will read and print the number of interrupts received as reported by the LP-Core. + +## Example output + +``` +LP core loaded with firmware and running successfully +Triggered 10 interrupts on the LP-Core, LP-Core received 10 interrupts +``` \ No newline at end of file diff --git a/examples/system/ulp/lp_core/interrupt/main/CMakeLists.txt b/examples/system/ulp/lp_core/interrupt/main/CMakeLists.txt new file mode 100644 index 00000000000..6eb2981339c --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/main/CMakeLists.txt @@ -0,0 +1,25 @@ +# Register the component +idf_component_register(SRCS "lp_interrupts_main.c" + INCLUDE_DIRS "" + REQUIRES ulp) + +# +# ULP support additions to component CMakeLists.txt. +# +# 1. The LP Core app name must be unique (if multiple components use LP Core). +set(ulp_app_name lp_core_${COMPONENT_NAME}) +# +# 2. Specify all C files. +# Files should be placed into a separate directory (in this case, lp_core/), +# which should not be added to COMPONENT_SRCS. +set(ulp_lp_core_sources "lp_core/main.c") + +# +# 3. List all the component source files which include automatically +# generated LP Core export file, ${ulp_app_name}.h: +set(ulp_exp_dep_srcs "lp_interrupts_main.c") + +# +# 4. Call function to build ULP binary and embed in project using the argument +# values above. +ulp_embed_binary(${ulp_app_name} "${ulp_lp_core_sources}" "${ulp_exp_dep_srcs}") diff --git a/examples/system/ulp/lp_core/interrupt/main/lp_core/main.c b/examples/system/ulp/lp_core/interrupt/main/lp_core/main.c new file mode 100644 index 00000000000..c97f8e4f987 --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/main/lp_core/main.c @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_interrupts.h" + +uint32_t lp_core_pmu_intr_count = 0; + +/* Add LP_CORE_ISR_ATTR to ensure registers are saved and restored */ +void LP_CORE_ISR_ATTR ulp_lp_core_lp_pmu_intr_handler(void) +{ + ulp_lp_core_sw_intr_clear(); + lp_core_pmu_intr_count++; +} + +int main (void) +{ + ulp_lp_core_intr_enable(); + ulp_lp_core_sw_intr_enable(true); + + while(1) { + /* Wait forever, handling interrupts */ + asm volatile("wfi"); + } + return 0; +} diff --git a/examples/system/ulp/lp_core/interrupt/main/lp_interrupts_main.c b/examples/system/ulp/lp_core/interrupt/main/lp_interrupts_main.c new file mode 100644 index 00000000000..274b1b00b24 --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/main/lp_interrupts_main.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_sleep.h" +#include "esp_err.h" +#include "lp_core_main.h" +#include "ulp_lp_core.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_main_bin_start"); +extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_main_bin_end"); + + +static void lp_core_init(void) +{ + /* Set LP core wakeup source as the HP CPU */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + /* Load LP core firmware */ + ESP_ERROR_CHECK(ulp_lp_core_load_binary(lp_core_main_bin_start, (lp_core_main_bin_end - lp_core_main_bin_start))); + + /* Run LP core */ + ESP_ERROR_CHECK(ulp_lp_core_run(&cfg)); + + // Give the LP core time to start up + vTaskDelay(pdMS_TO_TICKS(100)); + + printf("LP core loaded with firmware and running successfully\n"); +} + +#define INTERRUPT_COUNT 10 + +void app_main(void) +{ + /* Load LP Core binary and start the coprocessor */ + lp_core_init(); + + for (int i = 0; i < INTERRUPT_COUNT; i++) { + /* In addition to waking the LP source up, the HP-LP communication bit can also be used to trigger a PMU interrupt on the LP Core */ + ulp_lp_core_sw_intr_trigger(); + vTaskDelay(pdMS_TO_TICKS(100)); + } + + printf("Triggered %d interrupts on the LP-Core, LP-Core received %"PRIu32" interrupts\n", INTERRUPT_COUNT, ulp_lp_core_pmu_intr_count); + +} diff --git a/examples/system/ulp/lp_core/interrupt/pytest_lp_core_intr.py b/examples/system/ulp/lp_core/interrupt/pytest_lp_core_intr.py new file mode 100644 index 00000000000..a9f96aba6c2 --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/pytest_lp_core_intr.py @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32c6 +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_lp_core_intr(dut: Dut) -> None: + dut.expect('Triggered 10 interrupts on the LP-Core, LP-Core received 10 interrupts') diff --git a/examples/system/ulp/lp_core/interrupt/sdkconfig.defaults b/examples/system/ulp/lp_core/interrupt/sdkconfig.defaults new file mode 100644 index 00000000000..2e829c6faa3 --- /dev/null +++ b/examples/system/ulp/lp_core/interrupt/sdkconfig.defaults @@ -0,0 +1,4 @@ +# Enable ULP +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y +CONFIG_ULP_COPROC_RESERVE_MEM=4096 From 87d4172ee5bbdebb7df017c723391864b213c2df Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 19 Apr 2024 14:03:29 +0800 Subject: [PATCH 164/548] feat(ulp): add lp core panic handler --- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c6/include/soc/soc_caps.h | 4 + components/ulp/Kconfig | 16 ++++ components/ulp/cmake/CMakeLists.txt | 4 +- .../ulp/cmake/toolchain-lp-core-riscv.cmake | 6 +- .../ulp/lp_core/lp_core/lp_core_interrupt.c | 11 +-- .../ulp/lp_core/lp_core/lp_core_panic.c | 80 +++++++++++++++++++ .../lp_core/port/esp32c6/vector_table.S | 22 +++++ .../port/esp32p4/{vector.S => vector_table.S} | 10 --- .../lp_core/{port/esp32c6 => }/vector.S | 60 ++++++++------ .../lp_core/main/lp_core/test_main_gpio.c | 3 + .../ulp/test_apps/lp_core/sdkconfig.defaults | 3 +- docs/en/api-reference/system/ulp-lp-core.rst | 20 ++++- .../lp_uart/lp_uart_echo/sdkconfig.defaults | 2 +- 14 files changed, 197 insertions(+), 48 deletions(-) create mode 100644 components/ulp/lp_core/lp_core/lp_core_panic.c create mode 100644 components/ulp/lp_core/lp_core/port/esp32c6/vector_table.S rename components/ulp/lp_core/lp_core/port/esp32p4/{vector.S => vector_table.S} (84%) rename components/ulp/lp_core/lp_core/{port/esp32c6 => }/vector.S (76%) diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 8b522a023ee..f6a4d61f670 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1466,3 +1466,7 @@ config SOC_PHY_COMBO_MODULE config SOC_CAPS_NO_RESET_BY_ANA_BOD bool default y + +config SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR + bool + default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index d9fdc588ce0..facb0cabec9 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -583,3 +583,7 @@ /*------------------------------------- No Reset CAPS -------------------------------------*/ #define SOC_CAPS_NO_RESET_BY_ANA_BOD (1) + + +/*------------------------------------- ULP CAPS -------------------------------------*/ +#define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */ diff --git a/components/ulp/Kconfig b/components/ulp/Kconfig index 1c7f7c29130..94167bd5dfa 100644 --- a/components/ulp/Kconfig +++ b/components/ulp/Kconfig @@ -92,4 +92,20 @@ menu "Ultra Low Power (ULP) Co-processor" Note: For LP ROM prints to work properly, make sure that the LP core boots from the LP ROM. + menu "ULP Debugging Options" + config ULP_PANIC_OUTPUT_ENABLE + depends on ULP_COPROC_TYPE_LP_CORE && SOC_ULP_LP_UART_SUPPORTED + bool + prompt "Enable panic handler which outputs over LP UART" + default "y" if IDF_TARGET_ESP32P4 + help + Set this option to enable panic handler functionality. If this option is + enabled then the LP Core will output a panic dump over LP UART, + similar to what the main core does. Output depends on LP UART already being + initialized and configured. + Disabling this option will reduce the LP core binary size by not + linking in panic handler functionality. + + endmenu + endmenu # Ultra Low Power (ULP) Co-processor diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 9b35eb75ba1..05bddaa68d1 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -101,7 +101,8 @@ if(ULP_COCPU_IS_RISCV) elseif(ULP_COCPU_IS_LP_CORE) list(APPEND ULP_S_SOURCES "${IDF_PATH}/components/ulp/lp_core/lp_core/start.S" - "${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector.S" + "${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S" + "${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector_table.S" "${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c" "${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c" @@ -111,6 +112,7 @@ elseif(ULP_COCPU_IS_LP_CORE) "${IDF_PATH}/components/hal/uart_hal.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c" + "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_panic.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c") diff --git a/components/ulp/cmake/toolchain-lp-core-riscv.cmake b/components/ulp/cmake/toolchain-lp-core-riscv.cmake index 9b9ce09e8ba..eb3a0623bea 100644 --- a/components/ulp/cmake/toolchain-lp-core-riscv.cmake +++ b/components/ulp/cmake/toolchain-lp-core-riscv.cmake @@ -5,11 +5,11 @@ set(CMAKE_C_COMPILER "riscv32-esp-elf-gcc") set(CMAKE_CXX_COMPILER "riscv32-esp-elf-g++") set(CMAKE_ASM_COMPILER "riscv32-esp-elf-gcc") -set(CMAKE_C_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections" +set(CMAKE_C_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections" CACHE STRING "C Compiler Base Flags") -set(CMAKE_CXX_FLAGS "-Os -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections" +set(CMAKE_CXX_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -mdiv -fdata-sections -ffunction-sections" CACHE STRING "C++ Compiler Base Flags") -set(CMAKE_ASM_FLAGS "-march=rv32imac_zicsr_zifencei -x assembler-with-cpp" +set(CMAKE_ASM_FLAGS "-Os -ggdb -march=rv32imac_zicsr_zifencei -x assembler-with-cpp" CACHE STRING "Assembler Base Flags") set(CMAKE_EXE_LINKER_FLAGS "-march=rv32imac_zicsr_zifencei --specs=nano.specs --specs=nosys.specs" CACHE STRING "Linker Base Flags") diff --git a/components/ulp/lp_core/lp_core/lp_core_interrupt.c b/components/ulp/lp_core/lp_core/lp_core_interrupt.c index 114973b9cba..a24b7953e13 100644 --- a/components/ulp/lp_core/lp_core/lp_core_interrupt.c +++ b/components/ulp/lp_core/lp_core/lp_core_interrupt.c @@ -9,6 +9,7 @@ #include "sdkconfig.h" #include "hal/lp_core_ll.h" #include "riscv/rv_utils.h" +#include "riscv/rvruntime-frames.h" #if CONFIG_IDF_TARGET_ESP32C6 /* Enable interrupt 30, which all external interrupts are routed to*/ @@ -36,6 +37,11 @@ void ulp_lp_core_intr_disable(void) RV_CLEAR_CSR(mstatus, MSTATUS_MIE); } +void __attribute__((weak)) ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause) +{ + abort(); +} + static void ulp_lp_core_default_intr_handler(void) { abort(); @@ -60,11 +66,6 @@ void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_cor void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_lp_rtc_intr_handler(void); void __attribute__((weak, alias("ulp_lp_core_default_intr_handler"))) ulp_lp_core_sw_intr_handler(void); -void ulp_lp_core_panic_handler(void) -{ - abort(); -} - #if CONFIG_IDF_TARGET_ESP32C6 static void* s_intr_handlers[] = { diff --git a/components/ulp/lp_core/lp_core/lp_core_panic.c b/components/ulp/lp_core/lp_core/lp_core_panic.c new file mode 100644 index 00000000000..70fac05483f --- /dev/null +++ b/components/ulp/lp_core/lp_core/lp_core_panic.c @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" + +#include +#include +#include "ulp_lp_core_print.h" +#include "riscv/rvruntime-frames.h" + +#if CONFIG_ULP_PANIC_OUTPUT_ENABLE + +static void dump_stack(RvExcFrame *frame, int exccause) +{ + uint32_t i = 0; + uint32_t sp = frame->sp; + lp_core_printf("\n\nStack memory:\n"); + const int per_line = 8; + for (i = 0; i < 1024; i += per_line * sizeof(uint32_t)) { + uint32_t *spp = (uint32_t *)(sp + i); + lp_core_printf("%08x: ", sp + i); + for (int y = 0; y < per_line; y++) { + lp_core_printf("0x%08x%c", spp[y], y == per_line - 1 ? '\n' : ' '); + } + } + lp_core_printf("\n"); +} + +static const char *desc[] = { + "MEPC ", "RA ", "SP ", "GP ", "TP ", "T0 ", "T1 ", "T2 ", + "S0/FP ", "S1 ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ", + "A6 ", "A7 ", "S2 ", "S3 ", "S4 ", "S5 ", "S6 ", "S7 ", + "S8 ", "S9 ", "S10 ", "S11 ", "T3 ", "T4 ", "T5 ", "T6 ", + "MSTATUS ", "MTVEC ", "MCAUSE ", "MTVAL ", "MHARTID " +}; + +static const char *reason[] = { + NULL, + NULL, + "Illegal instruction", + "Breakpoint", + "Load address misaligned", + "Load access fault", + "Store address misaligned", + "Store access fault", +}; + +void ulp_lp_core_panic_handler(RvExcFrame *frame, int exccause) +{ +#define DIM(arr) (sizeof(arr)/sizeof(*arr)) + + const char *exccause_str = "Unhandled interrupt/Unknown cause"; + + if (exccause < DIM(reason) && reason[exccause] != NULL) { + exccause_str = reason[exccause]; + } + + lp_core_printf("Guru Meditation Error: LP Core panic'ed (%s)\n", exccause_str); + lp_core_printf("Core 0 register dump:\n"); + + uint32_t* frame_ints = (uint32_t*) frame; + for (int x = 0; x < DIM(desc); x++) { + if (desc[x][0] != 0) { + const int not_last = (x + 1) % 4; + lp_core_printf("%-8s: 0x%08x %c", desc[x], frame_ints[x], not_last ? ' ' : '\n'); + } + } + + dump_stack(frame, exccause); + + /* idf-monitor uses this string to mark the end of a panic dump */ + lp_core_printf("ELF file SHA256: No SHA256 Embedded\n"); + + while (1) { + } +} + +#endif //#if CONFIG_ULP_PANIC_OUTPUT_ENABLE diff --git a/components/ulp/lp_core/lp_core/port/esp32c6/vector_table.S b/components/ulp/lp_core/lp_core/port/esp32c6/vector_table.S new file mode 100644 index 00000000000..a1309e3cf81 --- /dev/null +++ b/components/ulp/lp_core/lp_core/port/esp32c6/vector_table.S @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .section .init.vector,"ax" + + .global _vector_table + .type _vector_table, @function +_vector_table: + .option push + .option norvc + + .rept 30 + j _panic_handler + .endr + j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry + j _panic_handler + + .option pop + .size _vector_table, .-_vector_table diff --git a/components/ulp/lp_core/lp_core/port/esp32p4/vector.S b/components/ulp/lp_core/lp_core/port/esp32p4/vector_table.S similarity index 84% rename from components/ulp/lp_core/lp_core/port/esp32p4/vector.S rename to components/ulp/lp_core/lp_core/port/esp32p4/vector_table.S index 3853c6df502..c5e7ca9fee9 100644 --- a/components/ulp/lp_core/lp_core/port/esp32p4/vector.S +++ b/components/ulp/lp_core/lp_core/port/esp32p4/vector_table.S @@ -47,13 +47,3 @@ _vector_table: .option pop .size _vector_table, .-_vector_table - - -/* _panic_handler: handle all exception */ - .section .text.handlers,"ax" - .global _panic_handler - .type _panic_handler, @function -_panic_handler: - call ulp_lp_core_panic_handler -_end: - j _end /* loop forever */ diff --git a/components/ulp/lp_core/lp_core/port/esp32c6/vector.S b/components/ulp/lp_core/lp_core/vector.S similarity index 76% rename from components/ulp/lp_core/lp_core/port/esp32c6/vector.S rename to components/ulp/lp_core/lp_core/vector.S index 32331e71b46..b62cbc9ec37 100644 --- a/components/ulp/lp_core/lp_core/port/esp32c6/vector.S +++ b/components/ulp/lp_core/lp_core/vector.S @@ -5,6 +5,7 @@ */ #include "riscv/rvruntime-frames.h" +#include "soc/soc_caps.h" .equ SAVE_REGS, 32 .equ CONTEXT_SIZE, (SAVE_REGS * 4) @@ -92,47 +93,54 @@ .endm - .section .init.vector,"ax" - - .global _vector_table - .type _vector_table, @function -_vector_table: - .option push - .option norvc - - .rept 30 - j _panic_handler - .endr - j _interrupt_handler // All interrupts are routed to mtvec + 4*30, i.e. the 31st entry - j _panic_handler - - .option pop - .size _vector_table, .-_vector_table - - /* _panic_handler: handle all exception */ .section .text.handlers,"ax" .global _panic_handler .type _panic_handler, @function _panic_handler: - call ulp_lp_core_panic_handler + save_general_regs RV_STK_FRMSZ + save_mepc + + addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */ + + /* Save CSRs */ + sw t0, RV_STK_SP(sp) + csrr t0, mstatus + sw t0, RV_STK_MSTATUS(sp) + csrr t0, mcause + sw t0, RV_STK_MCAUSE(sp) + csrr t0, mtvec + sw t0, RV_STK_MTVEC(sp) + csrr t0, mhartid + sw t0, RV_STK_MHARTID(sp) + csrr t0, mtval + sw t0, RV_STK_MTVAL(sp) + + csrr a1, mcause /* exception cause */ + + mv a0, sp /* RvExcFrame *regs */ + call ulp_lp_core_panic_handler _end: - j _end /* loop forever */ + j _end /* loop forever */ + +#if SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR /* interrupt_handler: handle all interrupt */ - .section .text.handlers,"ax" - .global _interrupt_handler - .type _interrupt_handler, @function + .section .text.handlers,"ax" + .global _interrupt_handler + .type _interrupt_handler, @function _interrupt_handler: /* save registers & mepc to stack */ save_general_regs save_mepc - call ulp_lp_core_intr_handler + call ulp_lp_core_intr_handler - /* restore registers & mepc from stack */ + /* restore registers & mepc from stack */ restore_mepc restore_general_regs /* exit, this will also re-enable the interrupts */ - mret + mret + +#endif // SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c index 4d5b09f7b66..53e71fc19c9 100644 --- a/components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c @@ -20,12 +20,15 @@ int main(void) ulp_lp_core_gpio_output_enable(LP_IO_NUM_0); ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 0); + ulp_lp_core_delay_us(100); gpio_test_succeeded = (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 0); ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 1); + ulp_lp_core_delay_us(100); gpio_test_succeeded &= (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 1); ulp_lp_core_gpio_set_level(LP_IO_NUM_0, 0); + ulp_lp_core_delay_us(100); gpio_test_succeeded &= (ulp_lp_core_gpio_get_level(LP_IO_NUM_0) == 0); gpio_test_finished = 1; diff --git a/components/ulp/test_apps/lp_core/sdkconfig.defaults b/components/ulp/test_apps/lp_core/sdkconfig.defaults index b1dc7fcf8c1..c7626f47332 100644 --- a/components/ulp/test_apps/lp_core/sdkconfig.defaults +++ b/components/ulp/test_apps/lp_core/sdkconfig.defaults @@ -2,4 +2,5 @@ CONFIG_ESP_TASK_WDT_INIT=n CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_LP_CORE=y -CONFIG_ULP_COPROC_RESERVE_MEM=4096 +CONFIG_ULP_COPROC_RESERVE_MEM=12000 +CONFIG_ULP_PANIC_OUTPUT_ENABLE=y diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index 4d80c88c600..b2cc75909ef 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -178,7 +178,7 @@ To enhance the capabilities of the ULP LP-Core coprocessor, it has access to per Since these functions are already present in LP-ROM no matter what, using these in your program allows you to reduce the RAM footprint of your ULP application. -ULP LP-Core interrupts +ULP LP-Core Interrupts ---------------------- The LP-Core coprocessor can be configured to handle interrupts from various sources. Examples of such interrupts could be LP IO low/high or LP timer interrupts. To register a handler for an interrupt simply override any of the weak handlers provided by IDF. A complete list of handlers can be found in :component_file:`ulp_lp_core_interrupts.h `. For details on which interrupts are available on a specific target, please consult the Low Power CPU chapter in the Technical Reference Manual.` @@ -196,6 +196,22 @@ For example, to override the handler for the LP IO interrupt, you can define the In addition to configuring the interrupt related registers for the interrupt source you want to handle, you also need to enable the interrupts globally in the LP-Core interrupt controller. This can be done using the :cpp:func:`ulp_lp_core_intr_enable` function. +Debugging ULP LP-Core Applications +---------------------------------- + +When programming the LP-Core, it can sometimes be challenging to figure out why the program is not behaving as expected. Here are some strategies to help you debug your LP-Core program: + + * Use the LP-UART to print: the LP-Core has access to the LP-UART peripheral, which can be used for printing information independently of the main CPU sleep state. See :example:`system/ulp/lp_core/lp_uart/lp_uart_print` for an example of how to use this driver. + + * Share program state through shared variables: as described in :ref:`ulp-lp-core-access-variables`, both the main CPU and the ULP core can easily access global variables in RTC memory. Writing state information to such a variable from the ULP and reading it from the main CPU can help you discern what is happening on the ULP core. The downside of this approach is that it requires the main CPU to be awake, which will not always be the case. Keeping the main CPU awake might even, in some cases, mask problems, as some issues may only occur when certain power domains are powered down. + + * Panic handler: the LP-Core has a panic handler that can dump the state of the LP-Core registers to the LP-UART when an exception is detected. To enable the panic handler, set the :ref:`CONFIG_ULP_PANIC_OUTPUT_ENABLE` option to ``y``. This option can be kept disabled to reduce LP-RAM usage by the LP-Core application. To recover a backtrace from the panic dump it is possible to use esp-idf-monitor_., e.g.: + +.. code-block:: bash + + python -m esp_idf_monitor --toolchain-prefix riscv32-esp-elf- --target {IDF_TARGET_NAME} --decode-panic backtrace PATH_TO_ULP_ELF_FILE + + Application Examples -------------------- @@ -224,3 +240,5 @@ LP Core API Reference .. include-build-file:: inc/ulp_lp_core_uart.inc .. include-build-file:: inc/ulp_lp_core_print.inc .. include-build-file:: inc/ulp_lp_core_interrupts.inc + +.. _esp-idf-monitor: https://github.com/espressif/esp-idf-monitor diff --git a/examples/system/ulp/lp_core/lp_uart/lp_uart_echo/sdkconfig.defaults b/examples/system/ulp/lp_core/lp_uart/lp_uart_echo/sdkconfig.defaults index 53ae7d35bfa..f018081b4da 100644 --- a/examples/system/ulp/lp_core/lp_uart/lp_uart_echo/sdkconfig.defaults +++ b/examples/system/ulp/lp_core/lp_uart/lp_uart_echo/sdkconfig.defaults @@ -1,4 +1,4 @@ # Enable LP Core CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_LP_CORE=y -CONFIG_ULP_COPROC_RESERVE_MEM=4096 +CONFIG_ULP_COPROC_RESERVE_MEM=8192 From 2f1b81cd14396dde22d722bdffcb5d48e01fe274 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 23 Apr 2024 12:27:06 +0800 Subject: [PATCH 165/548] feat(ulp): add pulse counter example for lp core --- .../hal/esp32c6/include/hal/rtc_io_ll.h | 6 ++ .../lp_core/include/ulp_lp_core_utils.h | 8 ++ .../ulp/lp_core/lp_core/lp_core_utils.c | 5 ++ docs/en/api-reference/system/ulp-lp-core.rst | 1 + examples/system/.build-test-rules.yml | 6 ++ .../gpio_intr_pulse_counter/CMakeLists.txt | 8 ++ .../lp_core/gpio_intr_pulse_counter/README.md | 66 ++++++++++++++ .../main/CMakeLists.txt | 22 +++++ .../main/Kconfig.projbuild | 20 +++++ .../main/lp_core_pulse_counter_example_main.c | 85 +++++++++++++++++++ .../gpio_intr_pulse_counter/main/ulp/main.c | 64 ++++++++++++++ .../pytest_lp_core_pcnt.py | 30 +++++++ .../gpio_intr_pulse_counter/sdkconfig.ci | 1 + .../sdkconfig.defaults | 9 ++ 14 files changed, 331 insertions(+) create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/CMakeLists.txt create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/README.md create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/CMakeLists.txt create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/Kconfig.projbuild create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/lp_core_pulse_counter_example_main.c create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/ulp/main.c create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/pytest_lp_core_pcnt.py create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.ci create mode 100644 examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.defaults diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index 987c2b94b79..4f57b0fc7de 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -335,6 +335,12 @@ static inline void rtcio_ll_wakeup_disable(int rtcio_num) static inline void rtcio_ll_intr_enable(int rtcio_num, rtcio_ll_intr_type_t type) { LP_IO.pin[rtcio_num].int_type = type; + + /* Work around for HW issue, + need to also enable this clk, so that LP_IO.status.status_interrupt can get updated, + and trigger the interrupt on the LP Core + */ + LP_IO.date.clk_en = 1; } /** diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h index 89845252202..cfb8f697f28 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h @@ -89,6 +89,14 @@ void ulp_lp_core_sw_intr_enable(bool enable); */ void ulp_lp_core_sw_intr_clear(void); +/** + * @brief Puts the CPU into a wait state until an interrupt is triggered + * + * @note The CPU will draw less power when in this state compared to actively running + * + */ +void ulp_lp_core_wait_for_intr(void); + #ifdef __cplusplus } #endif diff --git a/components/ulp/lp_core/lp_core/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index 7fa9657c7f2..bcc84daa477 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -145,3 +145,8 @@ void ulp_lp_core_sw_intr_clear(void) { pmu_ll_lp_clear_sw_intr_status(&PMU); } + +void ulp_lp_core_wait_for_intr(void) +{ + asm volatile("wfi"); +} diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index b2cc75909ef..cc131a1a801 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -220,6 +220,7 @@ Application Examples * :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` reads data written to a serial console and echoes it back. This example demonstrates the usage of the LP UART driver running on the LP core. * :example:`system/ulp/lp_core/lp_uart/lp_uart_print` shows how to print various statements from a program running on the LP core. * :example:`system/ulp/lp_core/interrupt` shows how to register an interrupt handler on the LP core to receive an interrupt triggered by the main CPU. +* :example:`system/ulp/lp_core/gpio_intr_pulse_counter` shows how to use GPIO interrupts to count pulses while the main CPU is in deep sleep. API Reference ------------- diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index bcfa80fbd39..06812cd7f5f 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -264,6 +264,12 @@ examples/system/ulp/lp_core/gpio: depends_components: - ulp +examples/system/ulp/lp_core/gpio_intr_pulse_counter: + enable: + - if: SOC_LP_CORE_SUPPORTED == 1 + depends_components: + - ulp + examples/system/ulp/lp_core/interrupt: enable: - if: SOC_LP_CORE_SUPPORTED == 1 diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/CMakeLists.txt b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/CMakeLists.txt new file mode 100644 index 00000000000..0d18f968a18 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lp_core_pulse_counter) diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/README.md b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/README.md new file mode 100644 index 00000000000..1164376c153 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/README.md @@ -0,0 +1,66 @@ +| Supported Targets | ESP32-C6 | ESP32-P4 | +| ----------------- | -------- | -------- | + +# LP Core Pulse Counting Example + +This example demonstrates how to program the ULP Core coprocessor to count pulses on an IO while the main CPUs are either running some other code or are in deep sleep. See the README.md file in the upper level 'examples' directory for more information about examples. + +At runtime, the main code running on the ESP (found in lp_core_pulse_counter_example_main.c) loads ULP program into the `RTC_SLOW_MEM` memory region using `ulp_lp_core_load_binary` function. Main code configures the ULP program by setting up values of some variables and then starts it using `ulp_lp_core_run`. Once the ULP program is started, it monitors the IO pin for pulses. + +When the ULP program finds an edge in the input signal, it performs debouncing and increments the variable maintaining the total edge count. Once the edge count reaches certain value, ULP triggers wake up from deep sleep. Note that the ULP program keeps running and monitoring the input signal even when the SoC is woken up. + +## How to use example + +### Hardware Required + +To run this example, you should have a development board based on any of the chips listed in the supported targets table at the top and a host machine with a serial input connection. + +#### Pin Assignment: + +**Note:** The following pin assignments are used by default. + + +| | Uart Tx | Pulse Count Input | +| ----------------------- | ------- | ----------------- | +| ESP32-C6 | GPIO5 | GPIO6 | +| ESP32-P4 | GPIO14 | GPIO6 | +| Host machine | Rx | N/A | + +### Build and Flash + +Enter `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +Use another serial monitor program/instance such as idf.py monitor, minicom or miniterm to send and receive data from the LP core. +The default baudrate used for the example is 115200. Care must be taken that the configuration matches on both the device and the serial terminal. + +## Example Output + +The log output from the serial monitor connected to the main core should indicate that the LP core and the LP UART peripheral have been successfully initialized. The main CPU would then enter deep sleep mode. + +```bash +Using pin 6 as pulse counter input +ULP will wake up processor after every 10 pulses +Not a ULP wakeup, initializing it! +Entering in deep sleep +... +rst:0x5 (SLEEP_WAKEUP),boot:0xc (SPI_FAST_FLASH_BOOT) +... +ULP woke up the main CPU! +Pulse count: 11 +Entering in deep sleep +``` + +The log output from the serial monitor connected to the LP core should display output as below - + +```bash +LP Core pulse counter started +Pulse count: 10, wake-up main CPU +``` + +## Troubleshooting + +(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/CMakeLists.txt b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/CMakeLists.txt new file mode 100644 index 00000000000..79a7104a1f2 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/CMakeLists.txt @@ -0,0 +1,22 @@ +idf_component_register(SRCS "lp_core_pulse_counter_example_main.c" + INCLUDE_DIRS ".") +# +# ULP support additions to component CMakeLists.txt. +# +# 1. The ULP app name must be unique (if multiple components use ULP). +set(ulp_app_name ulp_${COMPONENT_NAME}) +# +# 2. Specify all C and Assembly source files. +# Files should be placed into a separate directory (in this case, ulp/), +# which should not be added to COMPONENT_SRCS. +set(ulp_sources "ulp/main.c") + +# +# 3. List all the component source files which include automatically +# generated ULP export file, ${ulp_app_name}.h: +set(ulp_exp_dep_srcs ${app_sources}) + +# +# 4. Call function to build ULP binary and embed in project using the argument +# values above. +ulp_embed_binary(${ulp_app_name} "${ulp_sources}" "${ulp_exp_dep_srcs}") diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/Kconfig.projbuild b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/Kconfig.projbuild new file mode 100644 index 00000000000..88618cecb26 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/Kconfig.projbuild @@ -0,0 +1,20 @@ +menu "Example Configuration" + config EXAMPLE_PULSE_COUNT_PIN + int "Input pin for the pulse counter" + default 6 + help + GPIO pin used as the input for the pulse counter + + config EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT + int "Wake-up pulse count limit" + default 10 + help + Number of pulses counted after which the ULP will wake up the main CPU + + config EXAMPLE_PULSE_COUNT_SIMULATE + bool "Simulate pulses on input pin" + default n + help + The ULP will periodically toggle the input pin to simulate pulses + +endmenu diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/lp_core_pulse_counter_example_main.c b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/lp_core_pulse_counter_example_main.c new file mode 100644 index 00000000000..65bef47be21 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/lp_core_pulse_counter_example_main.c @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* LP core gpio example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include "esp_sleep.h" +#include "driver/gpio.h" +#include "driver/rtc_io.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "ulp_lp_core.h" +#include "ulp_main.h" +#include "lp_core_uart.h" + +extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); +extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); + + +static void init_ulp_program(void); + +void app_main(void) +{ + /* If user is using USB-serial-jtag then idf monitor needs some time to + * re-connect to the USB port. We wait 1 sec here to allow for it to make the reconnection + * before we print anything. Otherwise the chip will go back to sleep again before the user + * has time to monitor any output. + */ + vTaskDelay(pdMS_TO_TICKS(1000)); + + /* Initialize selected GPIO as RTC IO, enable input/output, disable pullup and pulldown */ + printf("Using pin %d as pulse counter input\n", CONFIG_EXAMPLE_PULSE_COUNT_PIN); + rtc_gpio_init(CONFIG_EXAMPLE_PULSE_COUNT_PIN); + rtc_gpio_set_direction(CONFIG_EXAMPLE_PULSE_COUNT_PIN, RTC_GPIO_MODE_INPUT_OUTPUT); + rtc_gpio_pulldown_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN); + rtc_gpio_pullup_dis(CONFIG_EXAMPLE_PULSE_COUNT_PIN); + + printf("ULP will wake up processor after every %d pulses\n", CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT); + + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + /* not a wakeup from ULP, load the firmware */ + if (cause != ESP_SLEEP_WAKEUP_ULP) { + printf("Not a ULP wakeup, initializing it! \n"); + init_ulp_program(); + } else { + printf("ULP woke up the main CPU!\n"); + printf("Pulse count: %"PRIu32"\n", ulp_pulse_count); + } + + /* Go back to sleep, only the ULP will run */ + printf("Entering in deep sleep\n\n"); + + /* Small delay to ensure the messages are printed */ + ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup()); + + esp_deep_sleep_start(); +} + +static void init_ulp_program(void) +{ + lp_core_uart_cfg_t uart_cfg = LP_CORE_UART_DEFAULT_CONFIG(); + + ESP_ERROR_CHECK(lp_core_uart_init(&uart_cfg)); + + esp_err_t err = ulp_lp_core_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start)); + ESP_ERROR_CHECK(err); + + /* Start the program */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + err = ulp_lp_core_run(&cfg); + ESP_ERROR_CHECK(err); +} diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/ulp/main.c b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/ulp/main.c new file mode 100644 index 00000000000..6a45c04cb9e --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/main/ulp/main.c @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include "sdkconfig.h" +#include "ulp_lp_core.h" +#include "ulp_lp_core_utils.h" +#include "ulp_lp_core_gpio.h" +#include "ulp_lp_core_interrupts.h" +#include "ulp_lp_core_print.h" +#include "riscv/csr.h" + +#define DEBOUNCE_INTERVAL_CYCLES 10 // 10 cycles is about 0.625 us at 16 MHz + +#define SIMULATED_PULSE_FREQUENCY_HZ 2 +#define SIMULATED_PULSE_DELAY_US (1000000 / SIMULATED_PULSE_FREQUENCY_HZ) / 2 + +uint32_t pulse_count; +static uint32_t last_trigger_time_cycles; + +void LP_CORE_ISR_ATTR ulp_lp_core_lp_io_intr_handler(void) +{ + ulp_lp_core_gpio_clear_intr_status(); + uint32_t trigger_time_cycles = RV_READ_CSR(mcycle); + /* Do some simple debouncing, do not count spurious pulses */ + if (trigger_time_cycles - last_trigger_time_cycles > DEBOUNCE_INTERVAL_CYCLES) { + pulse_count++; + last_trigger_time_cycles = trigger_time_cycles; + } + + if (pulse_count % CONFIG_EXAMPLE_PULSE_COUNT_WAKEUP_LIMIT == 0) { + lp_core_printf("Pulse count: %d, wake-up main CPU\n", pulse_count); + ulp_lp_core_wakeup_main_processor(); + } + +} + + + +int main (void) +{ + lp_core_printf("LP Core pulse counter started\n"); + ulp_lp_core_intr_enable(); + ulp_lp_core_gpio_intr_enable(CONFIG_EXAMPLE_PULSE_COUNT_PIN, LP_IO_INTR_POSEDGE); + + while(1) { + +#if CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE + /* No external device connected to generate pulses, we simulate them ourselves instead */ + ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US); + ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 1); + ulp_lp_core_delay_us(SIMULATED_PULSE_DELAY_US); + ulp_lp_core_gpio_set_level(CONFIG_EXAMPLE_PULSE_COUNT_PIN, 0); +#else + /* Put CPU into a wait state to reduce power consumption while waiting for pulses */ + ulp_lp_core_wait_for_intr(); +#endif //CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE + } + + return 0; +} diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/pytest_lp_core_pcnt.py b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/pytest_lp_core_pcnt.py new file mode 100644 index 00000000000..a4d8c0c2e4c --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/pytest_lp_core_pcnt.py @@ -0,0 +1,30 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import logging + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32c6 +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_lp_core_pcnt(dut: Dut) -> None: + + res = dut.expect(r'ULP will wake up processor after every (\d+) pulses') + wakeup_limit = res.group(1).decode('utf-8') + assert (int(wakeup_limit) > 0) + logging.info(f'Wake-up limit: {wakeup_limit} pulses') + + dut.expect_exact('Not a ULP wakeup, initializing it!') + dut.expect_exact('Entering in deep sleep') + + dut.expect_exact('ULP woke up the main CPU!') + + res = dut.expect(r'Pulse count: (\d+)') + pulse_count = res.group(1).decode('utf-8') + logging.info(f'Pulse count: {pulse_count}') + + # Check that pulse count is correct, we could have gotten pulses between triggering + # the wakeup signal and printing the count, but it should at be equal to or greater + assert (int(pulse_count) >= int(wakeup_limit)) diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.ci b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.ci new file mode 100644 index 00000000000..81f55539b97 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.ci @@ -0,0 +1 @@ +CONFIG_EXAMPLE_PULSE_COUNT_SIMULATE=y diff --git a/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.defaults b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.defaults new file mode 100644 index 00000000000..456833bc8c3 --- /dev/null +++ b/examples/system/ulp/lp_core/gpio_intr_pulse_counter/sdkconfig.defaults @@ -0,0 +1,9 @@ +# Enable ULP +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y +CONFIG_ULP_COPROC_RESERVE_MEM=8128 +# Set log level to Warning to produce clean output +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_BOOTLOADER_LOG_LEVEL=2 +CONFIG_LOG_DEFAULT_LEVEL_WARN=y +CONFIG_LOG_DEFAULT_LEVEL=2 From 8800e9d0e51348e569e90318196891751b845c03 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 29 May 2024 18:26:33 +0800 Subject: [PATCH 166/548] fix(gpio): fix IO 21-27 IOMUX registers not being backed up on ESP32H2 --- components/soc/esp32c6/system_retention_periph.c | 4 ++-- components/soc/esp32h2/system_retention_periph.c | 4 ++-- components/soc/esp32p4/system_retention_periph.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/soc/esp32c6/system_retention_periph.c b/components/soc/esp32c6/system_retention_periph.c index 0b643f4e5b9..8e65e7c355a 100644 --- a/components/soc/esp32c6/system_retention_periph.c +++ b/components/soc/esp32c6/system_retention_periph.c @@ -70,7 +70,7 @@ const regdma_entries_config_t tg_regs_retention[] = { _Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); /* IO MUX Registers Context */ -#define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_SPID_U - REG_IO_MUX_BASE) / 4) + 1) +#define N_REGS_IOMUX_0() (((IO_MUX_GPIO30_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC34_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) #define N_REGS_IOMUX_2() (((GPIO_FUNC124_IN_SEL_CFG_REG - GPIO_STATUS_NEXT_REG) / 4) + 1) #define N_REGS_IOMUX_3() (((GPIO_PIN34_REG - DR_REG_GPIO_BASE) / 4) + 1) @@ -83,7 +83,7 @@ const regdma_entries_config_t iomux_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "Inconsistent IOMUX retention link length definitions"); -/* Mememory SPI Registers Context */ +/* Memory SPI Registers Context */ #define N_REGS_SPI1_MEM_0() (((SPI_MEM_SPI_SMEM_DDR_REG(1) - REG_SPI_MEM_BASE(1)) / 4) + 1) #define N_REGS_SPI1_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(1) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1)) / 4) + 1) #define N_REGS_SPI1_MEM_2() (1) diff --git a/components/soc/esp32h2/system_retention_periph.c b/components/soc/esp32h2/system_retention_periph.c index 38b2177c95d..fead39b1238 100644 --- a/components/soc/esp32h2/system_retention_periph.c +++ b/components/soc/esp32h2/system_retention_periph.c @@ -70,7 +70,7 @@ const regdma_entries_config_t tg_regs_retention[] = { _Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); /* IO MUX Registers Context */ -#define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_SPID_U - REG_IO_MUX_BASE) / 4) + 1) +#define N_REGS_IOMUX_0() (((IO_MUX_GPIO27_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC31_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) #define N_REGS_IOMUX_2() (((GPIO_FUNC124_IN_SEL_CFG_REG - GPIO_STATUS_NEXT_REG) / 4) + 1) #define N_REGS_IOMUX_3() (((GPIO_PIN31_REG - DR_REG_GPIO_BASE) / 4) + 1) @@ -82,7 +82,7 @@ const regdma_entries_config_t iomux_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(iomux_regs_retention) == IOMUX_RETENTION_LINK_LEN, "Inconsistent IOMUX retention link length definitions"); -/* Mememory SPI Registers Context */ +/* Memory SPI Registers Context */ #define N_REGS_SPI1_MEM_0() (((SPI_MEM_SPI_SMEM_DDR_REG(1) - REG_SPI_MEM_BASE(1)) / 4) + 1) #define N_REGS_SPI1_MEM_1() (((SPI_MEM_SPI_SMEM_AC_REG(1) - SPI_MEM_SPI_FMEM_PMS0_ATTR_REG(1)) / 4) + 1) #define N_REGS_SPI1_MEM_2() (1) diff --git a/components/soc/esp32p4/system_retention_periph.c b/components/soc/esp32p4/system_retention_periph.c index b1a1b89dbf7..855a47209f9 100644 --- a/components/soc/esp32p4/system_retention_periph.c +++ b/components/soc/esp32p4/system_retention_periph.c @@ -68,7 +68,7 @@ const regdma_entries_config_t tg_regs_retention[] = { _Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); /* IO MUX Registers Context */ -#define N_REGS_IOMUX_0() (((PERIPHS_IO_MUX_U_PAD_GPIO56 - REG_IO_MUX_BASE) / 4) + 1) +#define N_REGS_IOMUX_0() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1) const regdma_entries_config_t iomux_regs_retention[] = { [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_IOMUX_LINK(0x00), REG_IO_MUX_BASE, REG_IO_MUX_BASE, N_REGS_IOMUX_0(), 0, 0), .owner = ENTRY(0) }, /* io_mux */ From df4195062dc1ddda99da936a80f35476f3237632 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 23 Apr 2024 12:59:39 +0800 Subject: [PATCH 167/548] change(system): heap_caps_alloc returns aligned memory if caps indicate a need for it The implicit promise of heap_alloc_caps() and friends is that the memory it returns is fit for the purpose as requested in the caps field. Before this commit, that did not happen; e.g. DMA-capable memory wass returned from a correct region, but not aligned/sized to something the DMA subsystem can handle. This commit adds an API to the esp_mm component that is then used by the heap component to adjust allocation alignment, caps and size dependent on the hardware requirement of the requested allocation caps. --- components/esp_mm/CMakeLists.txt | 2 + components/esp_mm/esp_cache.c | 17 ++- components/esp_mm/heap_align_hw.c | 100 ++++++++++++++++++ .../include/esp_private/esp_cache_private.h | 16 +++ .../include/esp_private/heap_align_hw.h | 39 +++++++ .../mm/main/test_cache_msync_malloc.c | 8 ++ .../esp_rom/include/esp32c61/rom/cache.h | 4 +- .../hal/esp32c61/include/hal/cache_ll.h | 2 +- components/heap/heap_caps_base.c | 78 +++++++------- components/heap/include/esp_heap_caps.h | 7 +- .../test_apps/heap_tests/main/CMakeLists.txt | 3 +- .../heap_tests/main/test_heap_align_hw.c | 87 +++++++++++++++ docs/en/api-reference/system/mem_alloc.rst | 3 +- docs/zh_CN/api-reference/system/mem_alloc.rst | 7 +- .../ram_loadable_app/sdkconfig.defaults | 3 + 15 files changed, 323 insertions(+), 53 deletions(-) create mode 100644 components/esp_mm/heap_align_hw.c create mode 100644 components/esp_mm/include/esp_private/heap_align_hw.h create mode 100644 components/heap/test_apps/heap_tests/main/test_heap_align_hw.c diff --git a/components/esp_mm/CMakeLists.txt b/components/esp_mm/CMakeLists.txt index 9878840babc..06f5b3bc9ee 100644 --- a/components/esp_mm/CMakeLists.txt +++ b/components/esp_mm/CMakeLists.txt @@ -21,6 +21,8 @@ if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) endif() endif() +list(APPEND srcs "heap_align_hw.c") + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${includes} PRIV_REQUIRES ${priv_requires} diff --git a/components/esp_mm/esp_cache.c b/components/esp_mm/esp_cache.c index 213a8094313..84a265a2197 100644 --- a/components/esp_mm/esp_cache.c +++ b/components/esp_mm/esp_cache.c @@ -93,7 +93,10 @@ esp_err_t esp_cache_msync(void *addr, size_t size, int flags) return ESP_OK; } -esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t heap_caps, void **out_ptr, size_t *actual_size) +//The esp_cache_aligned_malloc function is marked deprecated but also called by other +//(also deprecated) functions in this file. In order to work around that generating warnings, it's +//split into a non-deprecated internal function and the stubbed external deprecated function. +static esp_err_t esp_cache_aligned_malloc_internal(size_t size, uint32_t heap_caps, void **out_ptr, size_t *actual_size) { ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); uint32_t valid_caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; @@ -127,6 +130,12 @@ esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t heap_caps, void **out_p return ESP_OK; } +//this is the deprecated stub for the above function +esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t heap_caps, void **out_ptr, size_t *actual_size) +{ + return esp_cache_aligned_malloc_internal(size, heap_caps, out_ptr, actual_size); +} + esp_err_t esp_cache_aligned_malloc_prefer(size_t size, void **out_ptr, size_t *actual_size, size_t flag_nums, ...) { ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); @@ -139,7 +148,7 @@ esp_err_t esp_cache_aligned_malloc_prefer(size_t size, void **out_ptr, size_t *a while (flag_nums--) { flags = va_arg(argp, uint32_t); - ret = esp_cache_aligned_malloc(size, flags, out_ptr, actual_size); + ret = esp_cache_aligned_malloc_internal(size, flags, out_ptr, actual_size); if (ret == ESP_OK) { break; } @@ -161,7 +170,7 @@ esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t heap_caps, vo ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow"); void *ptr = NULL; - ret = esp_cache_aligned_malloc(size_bytes, heap_caps, &ptr, actual_size); + ret = esp_cache_aligned_malloc_internal(size_bytes, heap_caps, &ptr, actual_size); if (ret == ESP_OK) { memset(ptr, 0, size_bytes); *out_ptr = ptr; @@ -188,7 +197,7 @@ esp_err_t esp_cache_aligned_calloc_prefer(size_t n, size_t size, void **out_ptr, int arg; for (int i = 0; i < flag_nums; i++) { arg = va_arg(argp, int); - ret = esp_cache_aligned_malloc_prefer(size_bytes, &ptr, actual_size, flag_nums, arg); + ret = esp_cache_aligned_malloc_internal(size_bytes, arg, &ptr, actual_size); if (ret == ESP_OK) { memset(ptr, 0, size_bytes); *out_ptr = ptr; diff --git a/components/esp_mm/heap_align_hw.c b/components/esp_mm/heap_align_hw.c new file mode 100644 index 00000000000..96787f19d09 --- /dev/null +++ b/components/esp_mm/heap_align_hw.c @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "esp_heap_caps.h" +#include "esp_private/esp_cache_private.h" +#include "soc/soc_caps.h" +#if SOC_GDMA_SUPPORTED +#include "hal/gdma_ll.h" +#endif + +#if CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH +#define HEAP_IRAM_ATTR +#else +#define HEAP_IRAM_ATTR IRAM_ATTR +#endif + +#define CAPS_NEEDING_ALIGNMENT (MALLOC_CAP_DMA|MALLOC_CAP_DMA_DESC_AHB|MALLOC_CAP_DMA_DESC_AXI|MALLOC_CAP_CACHE_ALIGNED) + +HEAP_IRAM_ATTR void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps) +{ + size_t size = *p_size; + size_t alignment = *p_alignment; + uint32_t caps = *p_caps; + + //Bail out early if we don't need alignment + if (!(caps & CAPS_NEEDING_ALIGNMENT)) { + return; + } + +#if CONFIG_APP_BUILD_TYPE_PURE_RAM_APP +//Cache functions aren't linked in so we cannot allocate anything needing alignment. +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + //Cannot do this for either internal or external memory. + *p_caps |= MALLOC_CAP_INVALID; +#else + //Internal memory DMA alloc is allowed. + if (caps & MALLOC_CAP_SPIRAM) { + *p_caps |= MALLOC_CAP_INVALID; + } +#endif + return; +#endif + + //Ask cache driver what alignment is applicable here. + size_t cache_alignment_bytes = 0; + esp_err_t ret = esp_cache_get_alignment(caps, &cache_alignment_bytes); + if (ret != ESP_OK) { + //This is not supposed to happen. + *p_caps |= MALLOC_CAP_INVALID; + return; + } + +#if SOC_GDMA_SUPPORTED && SOC_AXI_GDMA_SUPPORTED + //Special case: AXI DMA descriptors need to be aligned to 8-byte boundaries. + if ((caps & MALLOC_CAP_DMA_DESC_AXI) && (cache_alignment_bytes < GDMA_LL_AXI_DESC_ALIGNMENT)) { + cache_alignment_bytes = GDMA_LL_AXI_DESC_ALIGNMENT; + } +#endif + + // We assume both DMA alignment and requested alignment are powers of two. We can safely + // do this because: + // - DMA alignment in current chips always is a power of two, and is unlikely to ever + // be something else, + // - Requested alignment is checked by heap_caps_aligned_check_args to be a power + // of two. + if (cache_alignment_bytes > alignment) { + alignment = cache_alignment_bytes; + } + // Align up `size` to resulting alignment as well. + size = (size + alignment - 1) & (~(alignment - 1)); + + // For the heap allocator itself, there's no difference between data and descriptor DMA; the regions + // are only marked as DMA-capable. + if (caps & (MALLOC_CAP_DMA_DESC_AHB | MALLOC_CAP_DMA_DESC_AXI)) { + caps &= ~(MALLOC_CAP_DMA_DESC_AHB | MALLOC_CAP_DMA_DESC_AXI); + caps |= MALLOC_CAP_DMA; + } + + // Workaround: the heap allocator doesn't have regions marked `MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM` + // so we need to request those without the DMA flag. + if (caps & MALLOC_CAP_SPIRAM) { + caps &= ~MALLOC_CAP_DMA; + //Note: we do not erase any DMA descriptor caps. DMA descriptors cannot be in external + //memory, so the MALLOC_CAP_SPIRAM|MALLOC_CAP_DMA_DESC_* simply will not return any + //usable memory. + } + // MALLOC_CAP_CACHE_ALIGNED is not a real flag the heap_base component will understand; it + // only sets alignment (which we handled here) + caps &= ~ MALLOC_CAP_CACHE_ALIGNED; + + *p_size = size; + *p_alignment = alignment; + *p_caps = caps; +} diff --git a/components/esp_mm/include/esp_private/esp_cache_private.h b/components/esp_mm/include/esp_private/esp_cache_private.h index 97a4afafcc4..3f28554220a 100644 --- a/components/esp_mm/include/esp_private/esp_cache_private.h +++ b/components/esp_mm/include/esp_private/esp_cache_private.h @@ -25,11 +25,15 @@ extern "C" { * @param[out] out_ptr A pointer to the memory allocated successfully * @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the cache alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value. * + * @deprecated This function is deprecated and will be removed in the future. + * Use 'heap_caps_malloc' with MALLOC_CAP_CACHE_ALIGNED caps instead + * * @return * - ESP_OK: * - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_NO_MEM: No enough memory for allocation */ +__attribute__((deprecated("Use 'heap_caps_malloc' with MALLOC_CAP_CACHE_ALIGNED caps instead"))) esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t heap_caps, void **out_ptr, size_t *actual_size); /** @@ -45,11 +49,15 @@ esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t heap_caps, void **out_p * the next parameter. It will try in this order until allocating a chunk of memory successfully * or fail to allocate memories with any of the parameters. * + * @deprecated This function is deprecated and will be removed in the future. + * Use 'heap_caps_malloc_prefer' with MALLOC_CAP_CACHE_ALIGNED caps instead + * * @return * - ESP_OK: * - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_NO_MEM: No enough memory for allocation */ +__attribute__((deprecated("Use 'heap_caps_malloc_prefer' with MALLOC_CAP_CACHE_ALIGNED caps instead"))) esp_err_t esp_cache_aligned_malloc_prefer(size_t size, void **out_ptr, size_t *actual_size, size_t flag_nums, ...); /** @@ -63,11 +71,15 @@ esp_err_t esp_cache_aligned_malloc_prefer(size_t size, void **out_ptr, size_t *a * @param[out] out_ptr A pointer to the memory allocated successfully * @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the cache alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value. * + * @deprecated This function is deprecated and will be removed in the future. + * Use 'heap_caps_calloc' with MALLOC_CAP_CACHE_ALIGNED caps instead + * * @return * - ESP_OK: * - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_NO_MEM: No enough memory for allocation */ +__attribute__((deprecated("Use 'heap_caps_calloc' with MALLOC_CAP_CACHE_ALIGNED caps instead"))) esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t heap_caps, void **out_ptr, size_t *actual_size); /** @@ -84,11 +96,15 @@ esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t heap_caps, vo * the next parameter. It will try in this order until allocating a chunk of memory successfully * or fail to allocate memories with any of the parameters. * + * @deprecated This function is deprecated and will be removed in the future. + * Use 'heap_caps_calloc_prefer' with MALLOC_CAP_CACHE_ALIGNED caps instead + * * @return * - ESP_OK: * - ESP_ERR_INVALID_ARG: Invalid argument * - ESP_ERR_NO_MEM: No enough memory for allocation */ +__attribute__((deprecated("Use 'heap_caps_calloc' with MALLOC_CAP_CACHE_ALIGNED caps instead"))) esp_err_t esp_cache_aligned_calloc_prefer(size_t n, size_t size, void **out_ptr, size_t *actual_size, size_t flag_nums, ...); /** diff --git a/components/esp_mm/include/esp_private/heap_align_hw.h b/components/esp_mm/include/esp_private/heap_align_hw.h new file mode 100644 index 00000000000..452f00bde86 --- /dev/null +++ b/components/esp_mm/include/esp_private/heap_align_hw.h @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "multi_heap.h" +#include "sdkconfig.h" +#include "esp_err.h" +#include "esp_attr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Adjust size, alignment and caps of a memory allocation request to the specific + * hardware requirements, dependent on where the memory gets allocated. + * + * @note Note that heap_caps_base.c has its own definition for this function in order not to depend + * on this component. + * + * @param[in,out] p_alignment Pointer to alignment requirements. This may be modified upwards if the + * hardware has stricter alignment requirements. + * @param[in,out] p_size Pointer to size of memory to be allocated. This may be modified upwards + * if e.g. the memory needs to be aligned to a cache line. + * @param[in,out] p_caps Pointer to memory requirements. This may be adjusted if the memory + * requirements need modification for the heap caps allocator to work + * properly. + */ +void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_mm/test_apps/mm/main/test_cache_msync_malloc.c b/components/esp_mm/test_apps/mm/main/test_cache_msync_malloc.c index cd3ac554d21..f1e7b590160 100644 --- a/components/esp_mm/test_apps/mm/main/test_cache_msync_malloc.c +++ b/components/esp_mm/test_apps/mm/main/test_cache_msync_malloc.c @@ -11,7 +11,9 @@ #include "esp_log.h" #include "esp_attr.h" #include "unity.h" + #include "esp_private/esp_cache_private.h" + #include "esp_memory_utils.h" const static char *TAG = "CACHE_MALLOC_TEST"; @@ -20,7 +22,10 @@ TEST_CASE("test esp_cache_aligned_malloc_prefer", "[cache]") { void *ptr = NULL; size_t actual_size = 0; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" TEST_ESP_OK(esp_cache_aligned_malloc_prefer(40, &ptr, &actual_size, 1, MALLOC_CAP_DMA, 0)); +#pragma GCC diagnostic pop TEST_ASSERT(esp_ptr_dma_capable(ptr)); ESP_LOGI(TAG, "actual size: 0x%x", actual_size); @@ -31,7 +36,10 @@ TEST_CASE("test esp_cache_aligned_calloc_prefer", "[cache]") { void *ptr = NULL; size_t actual_size = 0; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" TEST_ESP_OK(esp_cache_aligned_calloc_prefer(1, 40, &ptr, &actual_size, 1, MALLOC_CAP_DMA, 0)); +#pragma GCC diagnostic pop TEST_ASSERT(esp_ptr_dma_capable(ptr)); ESP_LOGI(TAG, "actual size: 0d%d", actual_size); diff --git a/components/esp_rom/include/esp32c61/rom/cache.h b/components/esp_rom/include/esp32c61/rom/cache.h index 5ed6740a626..1e0f1baa0e9 100644 --- a/components/esp_rom/include/esp32c61/rom/cache.h +++ b/components/esp_rom/include/esp32c61/rom/cache.h @@ -530,7 +530,7 @@ void Cache_Resume_Cache(uint32_t autoload); * * @return uint32_t: 16, 32, 64 Byte */ -uint32_t Cache_Get_Cache_Line_Size(void); +uint32_t Cache_Get_Line_Size(void); /** * @brief Enable freeze for ICache. @@ -574,7 +574,7 @@ void Cache_Travel_Tag_Memory(struct cache_mode * mode, uint32_t filter_addr, voi * * @param struct cache_mode * mode : the cache to calculate the virtual address and the cache mode. * - * @param uint32_t tag : the tag part fo a tag item, 12-14 bits. + * @param uint32_t tag : the tag part of a tag item, 12-14 bits. * * @param uint32_t addr_offset : the virtual address offset of the cache ways. * diff --git a/components/hal/esp32c61/include/hal/cache_ll.h b/components/hal/esp32c61/include/hal/cache_ll.h index 2fe9c67658b..09306b15411 100644 --- a/components/hal/esp32c61/include/hal/cache_ll.h +++ b/components/hal/esp32c61/include/hal/cache_ll.h @@ -168,7 +168,7 @@ __attribute__((always_inline)) static inline uint32_t cache_ll_get_line_size(uint32_t cache_level, cache_type_t type, uint32_t cache_id) { uint32_t size = 0; - size = Cache_Get_Cache_Line_Size(); + size = Cache_Get_Line_Size(); return size; } diff --git a/components/heap/heap_caps_base.c b/components/heap/heap_caps_base.c index a4598785d9d..e8947907008 100644 --- a/components/heap/heap_caps_base.c +++ b/components/heap/heap_caps_base.c @@ -23,6 +23,12 @@ #define CALL_HOOK(hook, ...) {} #endif +//This is normally provided by the heap-memalign-hw component. +extern void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps); + +//Default alignment the multiheap allocator / tlsf will align 'unaligned' memory to, in bytes +#define UNALIGNED_MEM_ALIGNMENT_BYTES 4 + /* This takes a memory chunk in a region that can be addressed as both DRAM as well as IRAM. It will convert it to IRAM in such a way that it can be later freed. It assumes both the address as well as the length to be word-aligned. @@ -66,14 +72,26 @@ HEAP_IRAM_ATTR void heap_caps_free( void *ptr) CALL_HOOK(esp_heap_trace_free_hook, ptr); } +HEAP_IRAM_ATTR static inline void *aligned_or_unaligned_alloc(multi_heap_handle_t heap, size_t size, size_t alignment, size_t offset) { + if (alignment<=UNALIGNED_MEM_ALIGNMENT_BYTES) { //alloc and friends align to 32-bit by default + return multi_heap_malloc(heap, size); + } else { + return multi_heap_aligned_alloc_offs(heap, size, alignment, offset); + } +} + /* -This function should not be called directly as it does not -check for failure / call heap_caps_alloc_failed() +This function should not be called directly as it does not check for failure / call heap_caps_alloc_failed() +Note that this function does 'unaligned' alloc calls if alignment <= UNALIGNED_MEM_ALIGNMENT_BYTES (=4) as the +allocator will align to that value by default. */ -HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t caps) +HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment, size_t size, uint32_t caps) { void *ret = NULL; + // Alignment, size and caps may need to be modified because of hardware requirements. + esp_heap_adjust_alignment_to_hw(&alignment, &size, &caps); + // remove block owner size to HEAP_SIZE_MAX rather than adding the block owner size // to size to prevent overflows. if (size == 0 || size > MULTI_HEAP_REMOVE_BLOCK_OWNER_SIZE(HEAP_SIZE_MAX) ) { @@ -118,7 +136,8 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t //This is special, insofar that what we're going to get back is a DRAM address. If so, //we need to 'invert' it (lowest address in DRAM == highest address in IRAM and vice-versa) and //add a pointer to the DRAM equivalent before the address we're going to return. - ret = multi_heap_malloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) + 4); // int overflow checked above + ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) + 4, + alignment, MULTI_HEAP_BLOCK_OWNER_SIZE()); // int overflow checked above if (ret != NULL) { MULTI_HEAP_SET_BLOCK_OWNER(ret); ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret); @@ -128,7 +147,8 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t } } else { //Just try to alloc, nothing special. - ret = multi_heap_malloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size)); + ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), + alignment, MULTI_HEAP_BLOCK_OWNER_SIZE()); if (ret != NULL) { MULTI_HEAP_SET_BLOCK_OWNER(ret); ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret); @@ -145,6 +165,11 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t return NULL; } +//Wrapper for heap_caps_aligned_alloc_base as that can also do unaligned allocs. +HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t caps) { + return heap_caps_aligned_alloc_base(UNALIGNED_MEM_ALIGNMENT_BYTES, size, caps); +} + /* This function should not be called directly as it does not check for failure / call heap_caps_alloc_failed() @@ -155,8 +180,12 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_realloc_base( void *ptr, size_t siz heap_t *heap = NULL; void *dram_ptr = NULL; + //See if memory needs alignment because of hardware reasons. + size_t alignment = UNALIGNED_MEM_ALIGNMENT_BYTES; + esp_heap_adjust_alignment_to_hw(&alignment, &size, &caps); + if (ptr == NULL) { - return heap_caps_malloc_base(size, caps); + return heap_caps_aligned_alloc_base(alignment, size, caps); } if (size == 0) { @@ -200,7 +229,9 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_realloc_base( void *ptr, size_t siz // requested ones? bool compatible_caps = (caps & get_all_caps(heap)) == caps; - if (compatible_caps && !ptr_in_diram_case) { + //Note we don't try realloc() on memory that needs to be aligned, that is handled + //by the fallthrough code. + if (compatible_caps && !ptr_in_diram_case && alignment<=UNALIGNED_MEM_ALIGNMENT_BYTES) { // try to reallocate this memory within the same heap // (which will resize the block if it can) void *r = multi_heap_realloc(heap->heap, ptr, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size)); @@ -214,7 +245,7 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_realloc_base( void *ptr, size_t siz // if we couldn't do that, try to see if we can reallocate // in a different heap with requested capabilities. - void *new_p = heap_caps_malloc_base(size, caps); + void *new_p = heap_caps_aligned_alloc_base(alignment, size, caps); if (new_p != NULL) { size_t old_size = 0; @@ -256,34 +287,3 @@ HEAP_IRAM_ATTR void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps } return result; } - -HEAP_IRAM_ATTR void *heap_caps_aligned_alloc_base(size_t alignment, size_t size, uint32_t caps) -{ - for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { - //Iterate over heaps and check capabilities at this priority - heap_t *heap; - SLIST_FOREACH(heap, ®istered_heaps, next) { - if (heap->heap == NULL) { - continue; - } - if ((heap->caps[prio] & caps) != 0) { - //Heap has at least one of the caps requested. If caps has other bits set that this prio - //doesn't cover, see if they're available in other prios. - if ((get_all_caps(heap) & caps) == caps) { - // Just try to alloc, nothing special. Provide the size of the block owner - // as an offset to prevent a miscalculation of the alignment. - void *ret = multi_heap_aligned_alloc_offs(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), alignment, MULTI_HEAP_BLOCK_OWNER_SIZE()); - if (ret != NULL) { - MULTI_HEAP_SET_BLOCK_OWNER(ret); - ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret); - CALL_HOOK(esp_heap_trace_alloc_hook, ret, size, caps); - return ret; - } - } - } - } - } - - //Nothing usable found. - return NULL; -} diff --git a/components/heap/include/esp_heap_caps.h b/components/heap/include/esp_heap_caps.h index 4d590204e59..e875e4badd0 100644 --- a/components/heap/include/esp_heap_caps.h +++ b/components/heap/include/esp_heap_caps.h @@ -43,6 +43,9 @@ extern "C" { #define MALLOC_CAP_RETENTION (1<<14) ///< Memory must be able to accessed by retention DMA #define MALLOC_CAP_RTCRAM (1<<15) ///< Memory must be in RTC fast memory #define MALLOC_CAP_TCM (1<<16) ///< Memory must be in TCM memory +#define MALLOC_CAP_DMA_DESC_AHB (1<<17) ///< Memory must be capable of containing AHB DMA descriptors +#define MALLOC_CAP_DMA_DESC_AXI (1<<18) ///< Memory must be capable of containing AXI DMA descriptors +#define MALLOC_CAP_CACHE_ALIGNED (1<<19) ///< Memory must be aligned to the cache line size of any intermediate caches #define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker @@ -385,7 +388,7 @@ void *heap_caps_malloc_prefer( size_t size, size_t num, ... ); * * @param ptr Pointer to previously allocated memory, or NULL for a new allocation. * @param size Size of the new buffer requested, or 0 to free the buffer. - * @param num Number of variable paramters + * @param num Number of variable parameters * * @return Pointer to a new buffer of size 'size', or NULL if allocation failed. */ @@ -396,7 +399,7 @@ void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, ... ); * * @param n Number of continuing chunks of memory to allocate * @param size Size, in bytes, of a chunk of memory to allocate - * @param num Number of variable paramters + * @param num Number of variable parameters * * @return A pointer to the memory allocated on success, NULL on failure */ diff --git a/components/heap/test_apps/heap_tests/main/CMakeLists.txt b/components/heap/test_apps/heap_tests/main/CMakeLists.txt index 1803d9f1931..69af24fd943 100644 --- a/components/heap/test_apps/heap_tests/main/CMakeLists.txt +++ b/components/heap/test_apps/heap_tests/main/CMakeLists.txt @@ -1,5 +1,6 @@ set(src_test "test_heap_main.c" "test_aligned_alloc_caps.c" + "test_heap_align_hw.c" "test_allocator_timings.c" "test_corruption_check.c" "test_diram.c" @@ -13,5 +14,5 @@ set(src_test "test_heap_main.c" idf_component_register(SRCS ${src_test} INCLUDE_DIRS "." - REQUIRES unity esp_psram spi_flash + REQUIRES unity esp_psram spi_flash esp_mm WHOLE_ARCHIVE) diff --git a/components/heap/test_apps/heap_tests/main/test_heap_align_hw.c b/components/heap/test_apps/heap_tests/main/test_heap_align_hw.c new file mode 100644 index 00000000000..a3fa60cfaae --- /dev/null +++ b/components/heap/test_apps/heap_tests/main/test_heap_align_hw.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include +#include "inttypes.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "unity.h" +#include "esp_private/esp_cache_private.h" +#include "esp_memory_utils.h" +#include "hal/cache_ll.h" +#include "hal/cache_hal.h" + +TEST_CASE("test heap_caps_malloc_prefer for dma memory", "[hw-align]") +{ + void *ptr = NULL; + ptr = heap_caps_malloc_prefer(40, 1, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(ptr); + TEST_ASSERT(esp_ptr_dma_capable(ptr)); + + free(ptr); +} + +TEST_CASE("test heap_caps_calloc_prefer for dma memory", "[hw-align]") +{ + void *ptr = NULL; + ptr = heap_caps_calloc_prefer(40, 1, 1, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(ptr); + TEST_ASSERT(esp_ptr_dma_capable(ptr)); + + free(ptr); +} + +#include "esp_private/heap_align_hw.h" + +#define TEST_ALLOC_COUNT 100 +static bool test_alignment(uint32_t caps, int expected_alignment) { + bool ret=true; + + void *mem[TEST_ALLOC_COUNT]; + size_t size[TEST_ALLOC_COUNT]; + + //First, check if we can allocate memory with these caps anyway. + void *tst=heap_caps_malloc(1, caps); + if (!tst) return true; + free(tst); + + //Step 1: generate sizes and allocate memory. + for (int i=0; i8?int_cache_size:8); + test_alignment(MALLOC_CAP_DMA|MALLOC_CAP_SPIRAM, ext_cache_size); +} diff --git a/docs/en/api-reference/system/mem_alloc.rst b/docs/en/api-reference/system/mem_alloc.rst index f4f47ce0c67..5641ef8254b 100644 --- a/docs/en/api-reference/system/mem_alloc.rst +++ b/docs/en/api-reference/system/mem_alloc.rst @@ -107,7 +107,8 @@ Use the ``MALLOC_CAP_DMA`` flag to allocate memory which is suitable for use wit .. only SOC_SPIRAM_SUPPORTED and not esp32:: - The EDMA hardware feature allows DMA buffers to be placed in external PSRAM, but there may be additional alignment constraints. Consult the {IDF_TARGET_NAME} Technical Reference Manual for details. To allocate a DMA-capable external memory buffer, use the ``MALLOC_CAP_SPIRAM`` capabilities flag together with :cpp:func:`heap_caps_aligned_alloc` with the necessary alignment specified. + The EDMA hardware feature allows DMA buffers to be placed in external PSRAM, but there may be additional alignment constraints. Consult the {IDF_TARGET_NAME} Technical Reference Manual for details. To allocate a DMA-capable external memory buffer, use the ``MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA`` capabilities flags; the heap allocator will take care of alignment requirements imposed by the cache and DMA subsystems. If a peripheral has additional alignment requirements, you can use :cpp:func:`heap_caps_aligned_alloc` with the necessary alignment specified. + .. _32-bit accessible memory: diff --git a/docs/zh_CN/api-reference/system/mem_alloc.rst b/docs/zh_CN/api-reference/system/mem_alloc.rst index 768165115d3..12fef6b8f11 100644 --- a/docs/zh_CN/api-reference/system/mem_alloc.rst +++ b/docs/zh_CN/api-reference/system/mem_alloc.rst @@ -50,7 +50,7 @@ ESP-IDF 应用程序使用常见的计算机架构模式:由程序控制流动 DRAM ^^^^ -启动时,DRAM 堆包含应用程序未静态分配的所有数据内存,减少静态分配的缓冲区将增加可用的空闲堆空间。 +启动时,DRAM 堆包含应用程序未静态分配的所有数据内存,减少静态分配的 buffer 将增加可用的空闲堆空间。 调用命令 :ref:`idf.py size ` 可查找静态分配内存大小。 @@ -107,7 +107,8 @@ DMA 存储器 .. only SOC_SPIRAM_SUPPORTED and not esp32:: - EDMA 硬件功能允许将 DMA 缓冲区放置在外部 PSRAM,但可能存在其他对齐限制,详情请参阅 {IDF_TARGET_NAME} 技术参考手册。要分配一个可用 DMA 的外部内存缓冲区,请使用 ``MALLOC_CAP_SPIRAM`` 属性标志 和 :cpp:func:`heap_caps_aligned_alloc`,并指定必要的对齐方式。 + EDMA 硬件功能可以将 DMA buffer 放置在外部 PSRAM,但可能存在一定的对齐限制,详情请参阅 {IDF_TARGET_NAME} 技术参考手册。若要分配一个可用 DMA 的外部 buffer,请使用 ``MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA`` 属性标志,堆分配器将处理 cache 及 DMA 子系统的对齐要求。如果某个外设有额外的对齐要求,可以调用 :cpp:func:heap_caps_aligned_alloc 并指定必要的对齐方式。 + .. _32-bit accessible memory: @@ -138,7 +139,7 @@ DMA 存储器 堆函数是线程安全的,因此可不受限制,在不同任务中同时调用多个堆函数。 -从中断处理程序 (ISR) 上下文中调用 ``malloc``、 ``free`` 和相关函数虽然在技术层面可行(请参阅 :ref:`calling-heap-related-functions-from-isr`),但不建议使用此种方法,因为调用堆函数可能会延迟其他中断。建议重构应用程序,将 ISR 使用的任何缓冲区预先分配到 ISR 之外。之后可能会删除从 ISR 调用堆函数的功能。 +从中断处理程序 (ISR) 上下文中调用 ``malloc``、 ``free`` 和相关函数虽然在技术层面可行(请参阅 :ref:`calling-heap-related-functions-from-isr`),但不建议使用此种方法,因为调用堆函数可能会延迟其他中断。建议重构应用程序,将 ISR 使用的任何 buffer 预先分配到 ISR 之外。之后可能会删除从 ISR 调用堆函数的功能。 .. _calling-heap-related-functions-from-isr: diff --git a/tools/test_apps/system/ram_loadable_app/sdkconfig.defaults b/tools/test_apps/system/ram_loadable_app/sdkconfig.defaults index ffa7983c0fd..f218f6c43e2 100644 --- a/tools/test_apps/system/ram_loadable_app/sdkconfig.defaults +++ b/tools/test_apps/system/ram_loadable_app/sdkconfig.defaults @@ -4,3 +4,6 @@ CONFIG_APP_BUILD_TYPE_RAM=y CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y CONFIG_APP_BUILD_TYPE_PURE_RAM_APP=n + +CONFIG_COMPILER_OPTIMIZATION_DEBUG=n +CONFIG_COMPILER_OPTIMIZATION_SIZE=y From a168f4cc9b5714d7a9e6bb2796b2307d14d0eb6b Mon Sep 17 00:00:00 2001 From: luoxu Date: Fri, 10 May 2024 19:45:18 +0800 Subject: [PATCH 168/548] fix(ble_mesh): fix issues in mesh deinit --- .../api/core/esp_ble_mesh_common_api.c | 2 +- .../core/include/esp_ble_mesh_common_api.h | 7 +++-- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 31 +++++++++++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c index 9a12de17109..82128786085 100644 --- a/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c +++ b/components/bt/esp_ble_mesh/api/core/esp_ble_mesh_common_api.c @@ -96,7 +96,7 @@ esp_err_t esp_ble_mesh_deinit(esp_ble_mesh_deinit_param_t *param) } /* Take the Semaphore, wait BLE Mesh de-initialization to finish. */ - xSemaphoreTake(semaphore, portMAX_DELAY); + __ASSERT(xSemaphoreTake(semaphore, 3000 / portTICK_PERIOD_MS) == pdTRUE, "BLE Mesh deinit take semaphore failed"); /* Don't forget to delete the semaphore at the end. */ vSemaphoreDelete(semaphore); diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h index f7209d8e5fe..556565e7f22 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_common_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -33,7 +33,10 @@ esp_err_t esp_ble_mesh_init(esp_ble_mesh_prov_t *prov, esp_ble_mesh_comp_t *comp /** * @brief De-initialize BLE Mesh module. * - * @note This function shall be invoked after esp_ble_mesh_client_model_deinit(). + * @note + * 1. This function shall be invoked after esp_ble_mesh_client_model_deinit(). + * 2. This function is strictly forbidden to run in any BTC Task Context + * (e.g. registered Mesh Event Callback). * * @param[in] param: Pointer to the structure of BLE Mesh deinit parameters. * diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 38882680190..67d5353be8f 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -71,6 +71,29 @@ #include "esp_ble_mesh_provisioning_api.h" #include "esp_ble_mesh_networking_api.h" +#if CONFIG_BLE_MESH_DEINIT +static SemaphoreHandle_t deinit_comp_semaphore; +#endif + +static inline void btc_ble_mesh_prov_cb_to_app_reprocess(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { +#if CONFIG_BLE_MESH_DEINIT + case ESP_BLE_MESH_DEINIT_MESH_COMP_EVT: + assert(deinit_comp_semaphore); + /* Give the semaphore when BLE Mesh de-initialization is finished. + * @note: At nimble host, once this lock is released, it will cause + * the btc task to be deleted. + */ + xSemaphoreGive(deinit_comp_semaphore); + break; +#endif + default: + break; + } +} + static inline void btc_ble_mesh_prov_cb_to_app(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param) { @@ -79,6 +102,8 @@ static inline void btc_ble_mesh_prov_cb_to_app(esp_ble_mesh_prov_cb_event_t even if (btc_ble_mesh_cb) { btc_ble_mesh_cb(event, param); } + + btc_ble_mesh_prov_cb_to_app_reprocess(event, param); } static inline void btc_ble_mesh_model_cb_to_app(esp_ble_mesh_model_cb_event_t event, @@ -2825,8 +2850,8 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg) case BTC_BLE_MESH_ACT_DEINIT_MESH: act = ESP_BLE_MESH_DEINIT_MESH_COMP_EVT; param.deinit_mesh_comp.err_code = bt_mesh_deinit((struct bt_mesh_deinit_param *)&arg->mesh_deinit.param); - /* Give the semaphore when BLE Mesh de-initialization is finished. */ - xSemaphoreGive(arg->mesh_deinit.semaphore); + /* Temporarily save the deinit semaphore and release it after the mesh deinit complete event is handled in the app layer */ + deinit_comp_semaphore = arg->mesh_deinit.semaphore; break; #endif /* CONFIG_BLE_MESH_DEINIT */ default: From 3a5ba854192652753c9959909f62e4fce2416478 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 30 May 2024 14:26:35 +0800 Subject: [PATCH 169/548] docs(lowpower): updating low-power statistics in Wi-Fi scenarios --- .../sleep-current/esp32c6_light_sleep.inc | 18 +++++----- .../sleep-current/esp32c6_modem_sleep.inc | 36 +++++++++---------- .../sleep-current/esp32c6_summary.inc | 20 +++++------ 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/zh_CN/api-guides/sleep-current/esp32c6_light_sleep.inc b/docs/zh_CN/api-guides/sleep-current/esp32c6_light_sleep.inc index e2dd10abd0d..5e8500b6517 100644 --- a/docs/zh_CN/api-guides/sleep-current/esp32c6_light_sleep.inc +++ b/docs/zh_CN/api-guides/sleep-current/esp32c6_light_sleep.inc @@ -10,18 +10,18 @@ * - 160 MHz - 1 - - / - - / - - / + - 0.919 + - 103.149 + - 0.053 * - 160 MHz - 3 - - / - - / - - / + - 0.368 + - 102.428 + - 0.052 * - 160 MHz - 10 - - / - - / - - / + - 0.172 + - 102.087 + - 0.052 diff --git a/docs/zh_CN/api-guides/sleep-current/esp32c6_modem_sleep.inc b/docs/zh_CN/api-guides/sleep-current/esp32c6_modem_sleep.inc index f43652792b2..e1c06637ae4 100644 --- a/docs/zh_CN/api-guides/sleep-current/esp32c6_modem_sleep.inc +++ b/docs/zh_CN/api-guides/sleep-current/esp32c6_modem_sleep.inc @@ -12,41 +12,41 @@ * - 160 MHz - ON - 1 - - / - - / - - / + - 14.37 + - 84.40 + - 10.02 * - 160 MHz - OFF - 1 - - / - - / - - / + - 27.48 + - 87.55 + - 26.92 * - 160 MHz - ON - 3 - - / - - / - - / + - 13.9 + - 83.9 + - 10.13 * - 160 MHz - OFF - 3 - - / - - / - - / + - 27.08 + - 87.74 + - 26.91 * - 160 MHz - ON - 10 - - / - - / - - / + - 13.71 + - 82.77 + - 10.04 * - 160 MHz - OFF - 10 - - / - - / - - / + - 26.85 + - 88.07 + - 26.7 diff --git a/docs/zh_CN/api-guides/sleep-current/esp32c6_summary.inc b/docs/zh_CN/api-guides/sleep-current/esp32c6_summary.inc index 581f1b8a38a..e865abc938d 100644 --- a/docs/zh_CN/api-guides/sleep-current/esp32c6_summary.inc +++ b/docs/zh_CN/api-guides/sleep-current/esp32c6_summary.inc @@ -45,25 +45,25 @@ - 关 * - DTIM1 - - / - - / - - / + - 27.48 mA + - 14.37 mA + - 0.919 mA - / * - DTIM3 - - / - - / - - / + - 27.08 mA + - 13.9 mA + - 0.368 mA - / * - DTIM10 - - / - - / - - / + - 26.85 mA + - 13.71 mA + - 0.172 mA - / * - 平均电流 - / - / - / - - / + - 6.7 μA From 63f019565bb9b715f03c2b675a6495f69d77e27c Mon Sep 17 00:00:00 2001 From: "wangtao@espressif.com" Date: Fri, 24 May 2024 21:10:58 +0800 Subject: [PATCH 170/548] fix(wifi): fix send mgmt err when eapol process --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index a89846e501c..deb0e65a743 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit a89846e501cebcdce6be6d4ecbe34dcf1567bf70 +Subproject commit deb0e65a7432cf39915871ed65338bbfda1b6b55 From e22c101034760ce42e701e64a53f3dec691032d5 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Thu, 30 May 2024 19:16:43 +0530 Subject: [PATCH 171/548] fix(wifi): Add back WIFI_AUTH_WPA3_EXT_PSK and WIFI_AUTH_WPA3_EXT_PSK_MIXED_MODE Add back above authmodes instead of removing and merging them with WIFI_AUTH_WPA3_PSK in minor releases during v5.x. These authmodes will be removed from v6.0 --- components/esp_wifi/include/esp_wifi_types_generic.h | 2 ++ components/esp_wifi/lib | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index fdad2e1cbd1..97bb8542ed5 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -70,6 +70,8 @@ typedef enum { WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */ WIFI_AUTH_OWE, /**< authenticate mode : OWE */ WIFI_AUTH_WPA3_ENT_192, /**< authenticate mode : WPA3_ENT_SUITE_B_192_BIT */ + WIFI_AUTH_WPA3_EXT_PSK, /**< this authentication mode will yield same result as WIFI_AUTH_WPA3_PSK and not recommended to be used. It will be deprecated in future, please use WIFI_AUTH_WPA3_PSK instead. */ + WIFI_AUTH_WPA3_EXT_PSK_MIXED_MODE, /**< this authentication mode will yield same result as WIFI_AUTH_WPA3_PSK and not recommended to be used. It will be deprecated in future, please use WIFI_AUTH_WPA3_PSK instead.*/ WIFI_AUTH_DPP, /**< authenticate mode : DPP */ WIFI_AUTH_MAX } wifi_auth_mode_t; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index deb0e65a743..fff3460aafd 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit deb0e65a7432cf39915871ed65338bbfda1b6b55 +Subproject commit fff3460aafdcfef2d1890caa80c1855eb5fac327 From bbe96641b1774bb7494ff8f296b2ffde8841fae0 Mon Sep 17 00:00:00 2001 From: zwl Date: Mon, 27 May 2024 20:25:36 +0800 Subject: [PATCH 172/548] ble: fixed ble some issues on esp32c2 --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index b9a902c3551..3878fc3d687 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit b9a902c3551ef4a2032b6662a4cbb018125ddfda +Subproject commit 3878fc3d687ed70798952e25bdb2514e023d80dc diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 09fca95d4fa..6d813e541d8 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -606,7 +606,6 @@ r_ble_ll_auth_pyld_tmo_event_send = 0x40000d14; r_ble_ll_calc_offset_ticks_us_for_rampup = 0x40000d18; r_ble_ll_calc_session_key = 0x40000d1c; r_ble_ll_calc_ticks_per_slot = 0x40000d20; -r_ble_ll_check_scan_params = 0x40000d24; r_ble_ll_chk_txrx_octets = 0x40000d28; r_ble_ll_chk_txrx_time = 0x40000d2c; r_ble_ll_conn_adjust_pyld_len = 0x40000d30; @@ -783,7 +782,6 @@ r_ble_ll_hci_scan_set_enable = 0x40001070; r_ble_ll_hci_send_adv_report = 0x40001074; r_ble_ll_hci_send_dir_adv_report = 0x40001078; r_ble_ll_hci_send_ext_adv_report = 0x4000107c; -r_ble_ll_hci_send_legacy_ext_adv_report = 0x40001080; r_ble_ll_hci_send_noop = 0x40001084; r_ble_ll_hci_set_adv_data = 0x40001088; r_ble_ll_hci_set_le_event_mask = 0x4000108c; From 9ab7f325cc054404d3612c8a15acd78d7e4f55b3 Mon Sep 17 00:00:00 2001 From: zwl Date: Fri, 31 May 2024 12:00:56 +0800 Subject: [PATCH 173/548] ble: fixed ble some issues on esp32c6 and esp32h2 --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index 66633625971..405de681735 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit 6663362597110007a901eed9c87fa1cff6ac25fe +Subproject commit 405de68173533500319e9e2eb1c5bb13ca0a60f5 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 9bf31906cdb..586a2272642 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 9bf31906cdbef6ac3d271117f1cd439bd411eef5 +Subproject commit 586a22726421eff1bf1bd6e57f378de1f51b8f72 From e10c9778349d1f6009d80772ace2810d5a4a06ae Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Tue, 30 Apr 2024 14:38:33 +0800 Subject: [PATCH 174/548] fix(ble/bluedroid): Fixed BLE no data length change event --- .../btc/profile/std/gap/btc_gap_ble.c | 1 + .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 14 ++++++++++++++ .../bluedroid/stack/btm/include/btm_int.h | 2 ++ .../bt/host/bluedroid/stack/btu/btu_hcif.c | 1 - .../stack/include/stack/btm_ble_api.h | 1 + .../bt/host/bluedroid/stack/l2cap/l2c_ble.c | 19 +++++++++++-------- .../ble/gatt_client/main/gattc_demo.c | 8 +++++++- .../ble/gatt_server/main/gatts_demo.c | 8 +++++++- 8 files changed, 43 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 3ef4bd79169..8b012c15d45 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -2364,6 +2364,7 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) //register connection parameter update callback void btc_gap_callback_init(void) { + BTM_BleRegiseterPktLengthChangeCallback(btc_set_pkt_length_callback); BTM_BleRegiseterConnParamCallback(btc_update_conn_param_callback); #if (BLE_50_FEATURE_SUPPORT == TRUE) BTM_BleGapRegisterCallback(btc_ble_5_gap_callback); diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 3de3f7c1045..bad00076103 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -312,6 +312,20 @@ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn conn_param_update_cb.update_conn_param_cb = update_conn_param_cb; } +/******************************************************************************* +** +** Function BTM_BleRegiseterPktLengthChangeCallback +** +** Description Registers a callback function for packet length changes. +** +** Returns void +** +*******************************************************************************/ +void BTM_BleRegiseterPktLengthChangeCallback(tBTM_SET_PKT_DATA_LENGTH_CBACK *ptk_len_chane_cb) +{ + conn_param_update_cb.set_pkt_data_length_cb = ptk_len_chane_cb; +} + /******************************************************************************* ** ** Function BTM_BleUpdateAdvWhitelist diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index f8ed2d86bec..89cca256793 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -970,6 +970,8 @@ typedef struct { typedef struct{ //connection parameters update callback tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb; + // setting packet data length callback + tBTM_SET_PKT_DATA_LENGTH_CBACK *set_pkt_data_length_cb; }tBTM_CallbackFunc; extern tBTM_CallbackFunc conn_param_update_cb; diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index e856594be4d..5f472214960 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1468,7 +1468,6 @@ static void btu_hcif_command_status_evt(uint8_t status, BT_HDR *command, void *c hack->context = context; event->event = BTU_POST_TO_TASK_NO_GOOD_HORRIBLE_HACK; - if (btu_task_post(SIG_BTU_HCI_MSG, event, OSI_THREAD_MAX_TIMEOUT) == false) { osi_free(event); } diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h index bf431ce6cd2..a53f6dfc6d3 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -1366,6 +1366,7 @@ extern "C" { ** *******************************************************************************/ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb); +void BTM_BleRegiseterPktLengthChangeCallback(tBTM_SET_PKT_DATA_LENGTH_CBACK *ptk_len_chane_cb); /******************************************************************************* ** diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c index 4e6c8534ec5..a599aa1984c 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c @@ -287,7 +287,7 @@ UINT8 L2CA_GetBleConnRole (BD_ADDR bd_addr) ** ** Function l2cble_notify_le_connection ** -** Description This function notifiy the l2cap connection to the app layer +** Description This function notify the l2cap connection to the app layer ** ** Returns none ** @@ -868,7 +868,7 @@ void l2cble_process_sig_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) ** ** Function l2cble_init_direct_conn ** -** Description This function is to initate a direct connection +** Description This function is to initiate a direct connection ** ** Returns TRUE connection initiated, FALSE otherwise. ** @@ -894,7 +894,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) /* There can be only one BLE connection request outstanding at a time */ if (p_dev_rec == NULL) { - L2CAP_TRACE_WARNING ("unknown device, can not initate connection"); + L2CAP_TRACE_WARNING ("unknown device, can not initiate connection"); return (FALSE); } @@ -947,7 +947,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) if (!btm_ble_topology_check(BTM_BLE_STATE_INIT)) { l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate direct connection fail, topology limitation"); + L2CAP_TRACE_ERROR("initiate direct connection fail, topology limitation"); return FALSE; } uint32_t link_timeout = L2CAP_BLE_LINK_CONNECT_TOUT; @@ -981,7 +981,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) BLE_CE_LEN_MIN, /* UINT16 min_len */ BLE_CE_LEN_MIN)) { /* UINT16 max_len */ l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate direct connection fail, no resources"); + L2CAP_TRACE_ERROR("initiate direct connection fail, no resources"); return (FALSE); } else { p_lcb->link_state = LST_CONNECTING; @@ -1033,7 +1033,7 @@ BOOLEAN l2cble_init_direct_conn (tL2C_LCB *p_lcb) btm_ble_set_conn_st (BLE_DIR_CONN); if(!btsnd_hcic_ble_create_ext_conn(&aux_conn)) { l2cu_release_lcb (p_lcb); - L2CAP_TRACE_ERROR("initate Aux connection failed, no resources"); + L2CAP_TRACE_ERROR("initiate Aux connection failed, no resources"); } #else L2CAP_TRACE_ERROR("BLE 5.0 not support!\n"); @@ -1324,15 +1324,18 @@ void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, if(p_acl) { p_acl->data_length_params = data_length_params; if (p_acl->p_set_pkt_data_cback) { + // Only when the corresponding API is called will the callback be registered (*p_acl->p_set_pkt_data_cback)(BTM_SUCCESS, &data_length_params); + } else { + // If the callback is not registered,using global callback + (*conn_param_update_cb.set_pkt_data_length_cb)(BTM_SUCCESS, &data_length_params); } - p_acl->data_len_updating = false; if(p_acl->data_len_waiting) { p_acl->data_len_waiting = false; p_acl->p_set_pkt_data_cback = p_acl->p_set_data_len_cback_waiting; p_acl->p_set_data_len_cback_waiting = NULL; - // if value is same, triger callback directly + // if value is same, trigger callback directly if(p_acl->tx_len_waiting == p_acl->data_length_params.tx_len) { if(p_acl->p_set_pkt_data_cback) { (*p_acl->p_set_pkt_data_cback)(BTM_SUCCESS, &p_acl->data_length_params); diff --git a/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c b/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c index a06f91479f0..f8a6253c3f3 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_client/main/gattc_demo.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -410,6 +410,12 @@ static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *par param->update_conn_params.latency, param->update_conn_params.timeout); break; + case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT: + ESP_LOGI(GATTC_TAG, "packet length updated: rx = %d, tx = %d, status = %d", + param->pkt_data_length_cmpl.params.rx_len, + param->pkt_data_length_cmpl.params.tx_len, + param->pkt_data_length_cmpl.status); + break; default: break; } diff --git a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c index ff240df6cbc..fc808471e10 100644 --- a/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c +++ b/examples/bluetooth/bluedroid/ble/gatt_server/main/gatts_demo.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -235,6 +235,12 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param param->update_conn_params.latency, param->update_conn_params.timeout); break; + case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT: + ESP_LOGI(GATTS_TAG, "packet length updated: rx = %d, tx = %d, status = %d", + param->pkt_data_length_cmpl.params.rx_len, + param->pkt_data_length_cmpl.params.tx_len, + param->pkt_data_length_cmpl.status); + break; default: break; } From 1542b768fdca4961a99681f65054bc380cfdc9e9 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Mon, 6 May 2024 15:43:09 +0800 Subject: [PATCH 175/548] fix(ble/bluedroid): Optimize BLE stack connect callback name --- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 6 +++--- .../bt/host/bluedroid/stack/btm/include/btm_int.h | 2 +- components/bt/host/bluedroid/stack/l2cap/l2c_ble.c | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index bad00076103..cb526248ca8 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -70,7 +70,7 @@ static tBTM_BLE_VSC_CB *cmn_ble_gap_vsc_cb_ptr; static tBTM_BLE_CTRL_FEATURES_CBACK *p_ctrl_le_feature_rd_cmpl_cback = NULL; #endif -tBTM_CallbackFunc conn_param_update_cb; +tBTM_CallbackFunc conn_callback_func; /******************************************************************************* ** Local functions *******************************************************************************/ @@ -309,7 +309,7 @@ void btm_ble_sem_free(void) *******************************************************************************/ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn_param_cb) { - conn_param_update_cb.update_conn_param_cb = update_conn_param_cb; + conn_callback_func.update_conn_param_cb = update_conn_param_cb; } /******************************************************************************* @@ -323,7 +323,7 @@ void BTM_BleRegiseterConnParamCallback(tBTM_UPDATE_CONN_PARAM_CBACK *update_conn *******************************************************************************/ void BTM_BleRegiseterPktLengthChangeCallback(tBTM_SET_PKT_DATA_LENGTH_CBACK *ptk_len_chane_cb) { - conn_param_update_cb.set_pkt_data_length_cb = ptk_len_chane_cb; + conn_callback_func.set_pkt_data_length_cb = ptk_len_chane_cb; } /******************************************************************************* diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index 89cca256793..e8d65311114 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -974,7 +974,7 @@ typedef struct{ tBTM_SET_PKT_DATA_LENGTH_CBACK *set_pkt_data_length_cb; }tBTM_CallbackFunc; -extern tBTM_CallbackFunc conn_param_update_cb; +extern tBTM_CallbackFunc conn_callback_func; /* security action for L2CAP COC channels */ #define BTM_SEC_OK 1 #define BTM_SEC_ENCRYPT 2 /* encrypt the link with current key */ diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c index a599aa1984c..956a4b7fb2c 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_ble.c @@ -175,14 +175,14 @@ BOOLEAN L2CA_UpdateBleConnParams (BD_ADDR rem_bda, UINT16 min_int, UINT16 max_in L2CAP_TRACE_ERROR("There are two connection parameter requests that are being updated, please try later "); } - if ((need_cb == TRUE) && (conn_param_update_cb.update_conn_param_cb != NULL)) { + if ((need_cb == TRUE) && (conn_callback_func.update_conn_param_cb != NULL)) { tBTM_LE_UPDATE_CONN_PRAMS update_param; update_param.max_conn_int = max_int; update_param.min_conn_int = min_int; update_param.conn_int = p_lcb->current_used_conn_interval; update_param.slave_latency = p_lcb->current_used_conn_latency; update_param.supervision_tout = p_lcb->current_used_conn_timeout; - (conn_param_update_cb.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); + (conn_callback_func.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); return (status == HCI_SUCCESS); } @@ -647,7 +647,7 @@ void l2cble_process_conn_update_evt (UINT16 handle, UINT8 status, UINT16 conn_in p_lcb->conn_update_mask &= ~L2C_BLE_UPDATE_PARAM_FULL; btu_stop_timer(&p_lcb->upda_con_timer); - if (conn_param_update_cb.update_conn_param_cb != NULL) { + if (conn_callback_func.update_conn_param_cb != NULL) { l2c_send_update_conn_params_cb(p_lcb, status); } @@ -686,7 +686,7 @@ void l2cble_get_conn_param_format_err_from_contoller (UINT8 status, UINT16 handl btu_stop_timer (&p_lcb->upda_con_timer); - if (conn_param_update_cb.update_conn_param_cb != NULL) { + if (conn_callback_func.update_conn_param_cb != NULL) { l2c_send_update_conn_params_cb(p_lcb, status); } if ((p_lcb->conn_update_mask & L2C_BLE_UPDATE_PARAM_FULL) != 0){ @@ -1328,7 +1328,7 @@ void l2cble_process_data_length_change_event(UINT16 handle, UINT16 tx_data_len, (*p_acl->p_set_pkt_data_cback)(BTM_SUCCESS, &data_length_params); } else { // If the callback is not registered,using global callback - (*conn_param_update_cb.set_pkt_data_length_cb)(BTM_SUCCESS, &data_length_params); + (*conn_callback_func.set_pkt_data_length_cb)(BTM_SUCCESS, &data_length_params); } p_acl->data_len_updating = false; if(p_acl->data_len_waiting) { @@ -1399,7 +1399,7 @@ void l2cble_set_fixed_channel_tx_data_length(BD_ADDR remote_bda, UINT16 fix_cid, *******************************************************************************/ void l2c_send_update_conn_params_cb(tL2C_LCB *p_lcb, UINT8 status) { - if(conn_param_update_cb.update_conn_param_cb != NULL){ + if(conn_callback_func.update_conn_param_cb != NULL){ tBTM_LE_UPDATE_CONN_PRAMS update_param; //if myself update the connection parameters if (p_lcb->updating_param_flag){ @@ -1415,7 +1415,7 @@ void l2c_send_update_conn_params_cb(tL2C_LCB *p_lcb, UINT8 status) update_param.slave_latency = p_lcb->current_used_conn_latency; update_param.supervision_tout = p_lcb->current_used_conn_timeout; - (conn_param_update_cb.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); + (conn_callback_func.update_conn_param_cb)(status, p_lcb->remote_bd_addr, &update_param); } } From fe32b34b20f416236b66fdde6c9134ede3066528 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 21 May 2024 12:20:14 +0800 Subject: [PATCH 176/548] docs(links): fix broken links found in CI --- components/newlib/Kconfig | 2 +- docs/en/api-guides/performance/speed.rst | 2 +- docs/zh_CN/api-guides/performance/speed.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/newlib/Kconfig b/components/newlib/Kconfig index c00ab0cc035..98e63e8c034 100644 --- a/components/newlib/Kconfig +++ b/components/newlib/Kconfig @@ -59,7 +59,7 @@ menu "Newlib" For more details about "nano" formatting option, please see newlib readme file, search for '--enable-newlib-nano-formatted-io': - https://sourceware.org/newlib/README + https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/README;hb=HEAD If this option is enabled and the ROM contains functions from newlib-nano, the build system will use functions available in ROM, reducing the application binary size. diff --git a/docs/en/api-guides/performance/speed.rst b/docs/en/api-guides/performance/speed.rst index 8e6760466e6..d8c9fefc3d8 100644 --- a/docs/en/api-guides/performance/speed.rst +++ b/docs/en/api-guides/performance/speed.rst @@ -231,7 +231,7 @@ Common priorities are: - The Ethernet driver creates a task for the MAC to receive Ethernet frames. If using the default config ``ETH_MAC_DEFAULT_CONFIG`` then the priority is medium-high (15) and the task is not pinned to any core. These settings can be changed by passing a custom :cpp:class:`eth_mac_config_t` struct when initializing the Ethernet MAC. - If using the :doc:`/api-reference/protocols/mqtt` component, it creates a task with default priority 5 (:ref:`configurable `, depending on :ref:`CONFIG_MQTT_USE_CUSTOM_CONFIG`) and not pinned to any core (:ref:`configurable `). - - To see what is the task priority for ``mDNS`` service, please check `Performance Optimization `__. + - To see what is the task priority for ``mDNS`` service, please check `Performance Optimization `__. Choosing Task Priorities of the Application diff --git a/docs/zh_CN/api-guides/performance/speed.rst b/docs/zh_CN/api-guides/performance/speed.rst index e5be50dd983..81c53f0ff56 100644 --- a/docs/zh_CN/api-guides/performance/speed.rst +++ b/docs/zh_CN/api-guides/performance/speed.rst @@ -231,7 +231,7 @@ ESP-IDF 启动的系统任务预设了固定优先级。启动时,一些任务 - 以太网驱动程序会创建一个 MAC 任务,用于接收以太网帧。如果使用默认配置 ``ETH_MAC_DEFAULT_CONFIG`` ,则该任务为中高优先级 (15) 且并未固定在特定内核上执行。可以在以太网 MAC 初始化时输入自定义 :cpp:class:`eth_mac_config_t` 结构体来更改此设置。 - 如果使用 :doc:`/api-reference/protocols/mqtt` 组件,它会创建优先级默认为 5 的任务( :ref:`可配置 ` ,也可通过 :ref:`CONFIG_MQTT_USE_CUSTOM_CONFIG` 调整)。该任务未固定在特定内核上执行( :ref:`可配置 ` )。 - - 关于 ``mDNS`` 服务的任务优先级,参见 `性能优化 `__ 。 + - 关于 ``mDNS`` 服务的任务优先级,参见 `性能优化 `__ 。 设定应用程序任务优先级 From a6c2c4149d9424ba9476f6cb63cc6097bcab2edc Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Mon, 3 Jun 2024 11:54:48 +0800 Subject: [PATCH 177/548] fix(intr): fixed intr threshhold min level on C5 --- components/soc/esp32c5/mp/include/soc/clic_reg.h | 2 +- components/soc/esp32c61/include/soc/clic_reg.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/soc/esp32c5/mp/include/soc/clic_reg.h b/components/soc/esp32c5/mp/include/soc/clic_reg.h index 324cfd8c8ab..35b8003feee 100644 --- a/components/soc/esp32c5/mp/include/soc/clic_reg.h +++ b/components/soc/esp32c5/mp/include/soc/clic_reg.h @@ -10,7 +10,7 @@ extern "C" { #endif -#define NLBITS 3 +#define NLBITS 4 #define CLIC_EXT_INTR_NUM_OFFSET 16 #define DUALCORE_CLIC_CTRL_OFF 0x10000 diff --git a/components/soc/esp32c61/include/soc/clic_reg.h b/components/soc/esp32c61/include/soc/clic_reg.h index d7a51c598c0..219c1756472 100644 --- a/components/soc/esp32c61/include/soc/clic_reg.h +++ b/components/soc/esp32c61/include/soc/clic_reg.h @@ -10,7 +10,7 @@ extern "C" { #endif -#define NLBITS 3 +#define NLBITS 4 #define CLIC_EXT_INTR_NUM_OFFSET 16 #define DR_REG_CLIC_BASE (0x20800000) @@ -144,7 +144,7 @@ extern "C" { #define BYTE_CLIC_INT_CTL_REG(i) (DR_REG_CLIC_CTRL_BASE + 3 + (i)*4) /* BYTE_CLIC_INT_ATTR_MODE: R/W ; bitpos:[7:5] ;default: 3'd0 ; */ -/*description: interrupt pririty */ +/*description: interrupt priority */ #define BYTE_CLIC_INT_CTL 0x00000007 #define BYTE_CLIC_INT_CTL_M ((BYTE_CLIC_INT_CTL_V) << (BYTE_CLIC_INT_CTL_S)) #define BYTE_CLIC_INT_CTL_V 0x7 From d9f9f792705fae9a7a2f798e317d8282b3a5f2a7 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Sat, 1 Jun 2024 01:07:41 +0800 Subject: [PATCH 178/548] fix(kconfig): fixed peripheral driver kconfig inconsistencies --- components/driver/Kconfig | 55 +++++++++++++++++++++++++++++ components/esp_driver_dac/Kconfig | 8 ----- components/esp_driver_i2s/Kconfig | 6 ---- components/esp_driver_pcnt/Kconfig | 8 ----- components/esp_driver_sdm/Kconfig | 8 ----- components/esp_driver_tsens/Kconfig | 8 ----- 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/components/driver/Kconfig b/components/driver/Kconfig index ceda88e3ba8..68634c78f92 100644 --- a/components/driver/Kconfig +++ b/components/driver/Kconfig @@ -63,6 +63,17 @@ menu "Driver Configurations" endmenu # Legacy ADC Calibration Configuration endmenu # Legacy ADC Driver Configuration + menu "Legacy DAC Driver Configurations" + depends on SOC_DAC_SUPPORTED + config DAC_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + Whether to suppress the deprecation warnings when using legacy dac driver (driver/dac.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + endmenu # Legacy DAC Driver Configurations + menu "Legacy MCPWM Driver Configurations" depends on SOC_MCPWM_SUPPORTED config MCPWM_SUPPRESS_DEPRECATE_WARN @@ -97,4 +108,48 @@ menu "Driver Configurations" you can enable this option. endmenu # Legacy RMT Driver Configurations + menu "Legacy I2S Driver Configurations" + depends on SOC_I2S_SUPPORTED + config I2S_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + Whether to suppress the deprecation warnings when using legacy i2s driver (driver/i2s.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + endmenu # Legacy I2S Driver Configurationss + + menu "Legacy PCNT Driver Configurations" + depends on SOC_PCNT_SUPPORTED + config PCNT_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + whether to suppress the deprecation warnings when using legacy PCNT driver (driver/pcnt.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + endmenu # Legacy PCNT Driver Configurationss + + menu "Legacy SDM Driver Configurations" + depends on SOC_SDM_SUPPORTED + config SDM_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + whether to suppress the deprecation warnings when using legacy SDM driver (driver/sigmadelta.h). + If you want to continue using the legacy driver, and don't want to see related deprecation warnings, + you can enable this option. + endmenu # Legacy SDM Driver Configurationss + + menu "Legacy Temperature Sensor Driver Configurations" + depends on SOC_TEMP_SENSOR_SUPPORTED + config TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN + bool "Suppress legacy driver deprecated warning" + default n + help + whether to suppress the deprecation warnings when using legacy temperature sensor driver + (driver/temp_sensor.h). If you want to continue using the legacy driver, + and don't want to see related deprecation warnings, you can enable this option. + endmenu # Legacy Temperature Sensor Driver Configurationss + endmenu # Driver configurations diff --git a/components/esp_driver_dac/Kconfig b/components/esp_driver_dac/Kconfig index e0a1546db50..6fa1356cd61 100644 --- a/components/esp_driver_dac/Kconfig +++ b/components/esp_driver_dac/Kconfig @@ -15,14 +15,6 @@ menu "ESP-Driver:DAC Configurations" Ensure the DAC interrupt is IRAM-Safe by allowing the interrupt handler to be executable when the cache is disabled (e.g. SPI Flash write). - config DAC_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - whether to suppress the deprecation warnings when using legacy DAC driver (driver/dac.h). - If you want to continue using the legacy driver, and don't want to see related deprecation warnings, - you can enable this option. - config DAC_ENABLE_DEBUG_LOG bool "Enable debug log" default n diff --git a/components/esp_driver_i2s/Kconfig b/components/esp_driver_i2s/Kconfig index b3413eafb4b..72628d820e3 100644 --- a/components/esp_driver_i2s/Kconfig +++ b/components/esp_driver_i2s/Kconfig @@ -7,12 +7,6 @@ menu "ESP-Driver:I2S Configurations" Ensure the I2S interrupt is IRAM-Safe by allowing the interrupt handler to be executable when the cache is disabled (e.g. SPI Flash write). - config I2S_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - Enable this option will suppress the deprecation warnings of using APIs in legacy I2S driver. - config I2S_ENABLE_DEBUG_LOG bool "Enable I2S debug log" default n diff --git a/components/esp_driver_pcnt/Kconfig b/components/esp_driver_pcnt/Kconfig index f34768a0fb4..2b1949bd871 100644 --- a/components/esp_driver_pcnt/Kconfig +++ b/components/esp_driver_pcnt/Kconfig @@ -15,14 +15,6 @@ menu "ESP-Driver:PCNT Configurations" Ensure the PCNT interrupt is IRAM-Safe by allowing the interrupt handler to be executable when the cache is disabled (e.g. SPI Flash write). - config PCNT_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - whether to suppress the deprecation warnings when using legacy PCNT driver (driver/pcnt.h). - If you want to continue using the legacy driver, and don't want to see related deprecation warnings, - you can enable this option. - config PCNT_ENABLE_DEBUG_LOG bool "Enable debug log" default n diff --git a/components/esp_driver_sdm/Kconfig b/components/esp_driver_sdm/Kconfig index 50de62c3c66..ba89cac1252 100644 --- a/components/esp_driver_sdm/Kconfig +++ b/components/esp_driver_sdm/Kconfig @@ -8,14 +8,6 @@ menu "ESP-Driver:Sigma Delta Modulator Configurations" so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context. Enabling this option can improve driver performance as well. - config SDM_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - whether to suppress the deprecation warnings when using legacy sigma delta driver. - If you want to continue using the legacy driver, and don't want to see related deprecation warnings, - you can enable this option. - config SDM_ENABLE_DEBUG_LOG bool "Enable debug log" default n diff --git a/components/esp_driver_tsens/Kconfig b/components/esp_driver_tsens/Kconfig index 9bc99c72226..4ed4294078e 100644 --- a/components/esp_driver_tsens/Kconfig +++ b/components/esp_driver_tsens/Kconfig @@ -1,14 +1,6 @@ menu "ESP-Driver:Temperature Sensor Configurations" depends on SOC_TEMP_SENSOR_SUPPORTED - config TEMP_SENSOR_SUPPRESS_DEPRECATE_WARN - bool "Suppress legacy driver deprecated warning" - default n - help - whether to suppress the deprecation warnings when using legacy temperature sensor driver - (driver/temp_sensor.h). If you want to continue using the legacy driver, - and don't want to see related deprecation warnings, you can enable this option. - config TEMP_SENSOR_ENABLE_DEBUG_LOG bool "Enable debug log" default n From 737b5edd5b1d0ac36ecbff72bdf0cde88f86217b Mon Sep 17 00:00:00 2001 From: Abhinav Kudnar Date: Mon, 3 Jun 2024 18:12:31 +0530 Subject: [PATCH 179/548] fix(nimble): Added return code in ble_gap_unpair error logs --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index fdc35261939..794fb12e75b 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit fdc352619392a6f67622d7d07403de4794051362 +Subproject commit 794fb12e75b91e9cc938acf834ad2abd57c31190 From b07a1470c547fd8bdbc7d6424530309f5d9e51c7 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Thu, 30 May 2024 20:42:48 +0000 Subject: [PATCH 180/548] feat(tools): update toolchain version to esp-13.2.0_20240530 --- tools/tools.json | 112 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index 70515fe35d4..5b90890fc0e 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -180,51 +180,51 @@ "versions": [ { "linux-amd64": { - "sha256": "4e43e56cd533a39c6b0ccc8b30320b19ce66b0b17e646b53fa84c9bf956b2c83", - "size": 112254280, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-x86_64-linux-gnu.tar.xz" + "sha256": "fcef03d87eac44c0dbee2bbee98443ed2fcf82720dcd8ebfe00640807b0f07c2", + "size": 112073272, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "06bc30be9d824fa8da507dff228085563baa7f6251e42a14deae0ca0e93ec2eb", - "size": 103677608, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-aarch64-linux-gnu.tar.xz" + "sha256": "cfe55b92b4baeaa4309a948ba65e2adfc2d17a542c64856e36650869b419574a", + "size": 102954792, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "f0ecab5ae0a63abf4e43b1f3873d89181d1772748f028653f5e81264fb451e61", - "size": 106290920, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-arm-linux-gnueabi.tar.xz" + "sha256": "c57a062969ec3d98b02a97cd9240eb31091957788509b60c356b0a6f23032669", + "size": 104791600, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "15ed342e9d5c647dce8c688a4796bf8b0b9e44283f9ebe99e11aba63cc3d85b2", - "size": 102905548, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-arm-linux-gnueabihf.tar.xz" + "sha256": "1adc660f4d7bcf863f54051c5843719456fabc7203c1d4ccbb855924fda82987", + "size": 101896352, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "73fe99abc7d7a33eeb13473902e7025f0b41626891cb358a4dc9bf02b2b53931", - "size": 117286888, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-i586-linux-gnu.tar.xz" + "sha256": "f9203673aa0c42b041847c86b07e6f5b4aa9c90e6ff03d3cd3146928784447ea", + "size": 112724172, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "5bf2b5ececdf92169e5a084d2485b8d0d60480ce130a3035dc407f01e4e7820d", - "size": 115090676, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-x86_64-apple-darwin.tar.xz" + "sha256": "39ee7df749f4ceb93624d73627688d5b86269a7429022f986f2940499936aacd", + "size": 114904912, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "e2bf7886bb39ad6558e1f46160fae887705f903ea8b77cd28bbf77093d3ca286", - "size": 100350656, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-aarch64-apple-darwin.tar.xz" + "sha256": "d967e49a64f823e18fbae273efb1b094ac55e2207aa21fd3947c9d59f999f47e", + "size": 100018744, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.xz" }, - "name": "esp-13.2.0_20240305", + "name": "esp-13.2.0_20240530", "status": "recommended", "win32": { - "sha256": "79ea0dbd314012f199fc9a9bbbcc4c11473ea87f81be4c1b4c60328d3d73b9f8", - "size": 266666180, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-i686-w64-mingw32.zip" + "sha256": "d6b227c50e3c8e21d62502b3140e5ab74a4cb502c2b4169c36238b9858a8fb88", + "size": 266042967, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-i686-w64-mingw32_hotfix.zip" }, "win64": { - "sha256": "a80879c35b7f82ce80332ef0b68b0c7d245bafd9c98a35c45965850f40faf5ba", - "size": 270417276, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/xtensa-esp-elf-13.2.0_20240305-x86_64-w64-mingw32.zip" + "sha256": "155ee97b531236e6a7c763395c68ca793e55e74d2cb4d38a23057a153e01e7d0", + "size": 269831985, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/xtensa-esp-elf-13.2.0_20240530-x86_64-w64-mingw32_hotfix.zip" } } ] @@ -328,51 +328,51 @@ "versions": [ { "linux-amd64": { - "sha256": "2bd71171ddb801e59c85ecbea3b89d6f707627d6c11e501cae43ca7c0db73eda", - "size": 145977452, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-x86_64-linux-gnu.tar.xz" + "sha256": "f69a491d2f42f63e119f9077da995f7743ea8e1bf6944166a42a312cf60728a8", + "size": 145544808, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "806ccd08333a96ae73507625a1762f7ac7a8c82f193602cafb835c4d7f5678ab", - "size": 144233996, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-aarch64-linux-gnu.tar.xz" + "sha256": "276351b883a53e81b695d858be74114a8b627bbe4fc9c69ef46a7127ab143680", + "size": 145564848, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-linux-gnu.tar.xz" }, "linux-armel": { - "sha256": "312f404e86dde7d22f5c4b7216ea386dbf8d5f93dea50f689471cedc2e457f91", - "size": 136753128, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-arm-linux-gnueabi.tar.xz" + "sha256": "14890f2a624e70f11da7268347adf25b6c396f42bcd4d8ac3c5bfa4050b7c934", + "size": 140376832, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabi.tar.xz" }, "linux-armhf": { - "sha256": "a546224d8dc33c6a00a35b5856261232ce9218953e2ee8bcacdcc899d0c19591", - "size": 145140184, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-arm-linux-gnueabihf.tar.xz" + "sha256": "b61ca9ceff25986ec1d166a01319bff09639be1d4ee5bf117502ce564fdae7e9", + "size": 142416372, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-arm-linux-gnueabihf.tar.xz" }, "linux-i686": { - "sha256": "09d0ee10e1e617a93f6597c279bf9388b6384790a45b1d87451a40d1ff4e5f71", - "size": 156611372, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-i586-linux-gnu.tar.xz" + "sha256": "12ef50f96deb9040ce360974a4237c64ae0706b0c429b90cecc8ab664cf6dbb4", + "size": 156221552, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i586-linux-gnu.tar.xz" }, "macos": { - "sha256": "dfb4a2f46c66a9246a25e3c34b19a91c7a3f33a44721cd61ec01d442d5344193", - "size": 152864248, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-x86_64-apple-darwin.tar.xz" + "sha256": "cfbf5deaba05bf217701c8ceab7396bb0c2ca95ab58e134d4b2e175b86c2fd6c", + "size": 152568972, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "1e48833974a8e9ad2a0ac287ad244b825392d623edaf269bd66f4d8a215a0ef8", - "size": 136622828, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-aarch64-apple-darwin.tar.xz" + "sha256": "230628fcf464ca8856c82c55514e40a8919e97fbc5e66b7165ca42c9653d2302", + "size": 136326672, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-aarch64-apple-darwin.tar.xz" }, - "name": "esp-13.2.0_20240305", + "name": "esp-13.2.0_20240530", "status": "recommended", "win32": { - "sha256": "61492d38a0ceaae7b4784820810f9717454a0b4413a9f20ced595122eae3111f", - "size": 362677865, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-i686-w64-mingw32.zip" + "sha256": "590bfb10576702639825581cc00c445da6e577012840a787137417e80d15f46d", + "size": 366573064, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-i686-w64-mingw32.zip" }, "win64": { - "sha256": "e1e63f1926b9c643bc1de72e30cc79fc2079ad169546669e55836efbcc559d11", - "size": 366029146, - "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240305/riscv32-esp-elf-13.2.0_20240305-x86_64-w64-mingw32.zip" + "sha256": "413eb9f6adf8fdaf25544d014c850fc09eb38bb93a2fc5ebd107ab1b0de1bb3a", + "size": 369820297, + "url": "https://github.com/espressif/crosstool-NG/releases/download/esp-13.2.0_20240530/riscv32-esp-elf-13.2.0_20240530-x86_64-w64-mingw32.zip" } } ] From 6cd960928a675affc229fc8e472d93bee536eec7 Mon Sep 17 00:00:00 2001 From: gongyantao Date: Wed, 5 Jun 2024 09:05:29 +0800 Subject: [PATCH 181/548] fix(bt): fix some issues in bluetooth controller 1: fix return incorrect link key with hci command rd_stored_link_key 2: fix the assert triggered during APB TX 3: fix role switch LMP collision bug --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 45e32805359..994490e4b0e 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 45e328053591081abcd387ec2eecc8add43f4b15 +Subproject commit 994490e4b0edca038456324a532ebe63f7fc19ef From 6e7a9de65e818eadf1a0bb6d1497121831bafc15 Mon Sep 17 00:00:00 2001 From: Anton Maklakov Date: Wed, 5 Jun 2024 10:03:45 +0700 Subject: [PATCH 182/548] fix(blink): fix sdkconfig defaults name --- .../{sdkconfig.defaults esp32h2 => sdkconfig.defaults.esp32h2} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/get-started/blink/{sdkconfig.defaults esp32h2 => sdkconfig.defaults.esp32h2} (100%) diff --git a/examples/get-started/blink/sdkconfig.defaults esp32h2 b/examples/get-started/blink/sdkconfig.defaults.esp32h2 similarity index 100% rename from examples/get-started/blink/sdkconfig.defaults esp32h2 rename to examples/get-started/blink/sdkconfig.defaults.esp32h2 From c8474d48f86eb47b548e38cb8db5a83dec70f1a3 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 5 Jun 2024 13:12:03 +0200 Subject: [PATCH 183/548] fix(sdmmc): fix invalid data when reading/writing PSRAM buffers Previous commit has enabled buffers in PSRAM for ESP32-P4. But this also caused a regression for ESP32-S3, where PSRAM is not DMA capable. This commit re-introduces the check for esp_ptr_external_ram in case SOC_SDMMC_PSRAM_DMA_CAPABLE is not set. --- .../common_test_flows/sdmmc_test_rw_common.c | 2 +- .../sdmmc/components/sdmmc_tests/sdmmc_test_rw_sd.c | 7 ++++++- components/sdmmc/sdmmc_cmd.c | 12 ++++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_rw_common.c b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_rw_common.c index 360928efd88..b883e004359 100644 --- a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_rw_common.c +++ b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/common_test_flows/sdmmc_test_rw_common.c @@ -149,7 +149,7 @@ void sdmmc_test_rw_performance(sdmmc_card_t *card, FILE *perf_log) do_single_rw_perf_test(card, offset, 1, 1, perf_log, 0); do_single_rw_perf_test(card, offset, 8, 1, perf_log, 0); do_single_rw_perf_test(card, offset, 128, 1, perf_log, 0); -#if CONFIG_SPIRAM && SOC_SDMMC_PSRAM_DMA_CAPABLE +#if CONFIG_SPIRAM /* spiram */ do_single_rw_perf_test(card, offset, 1, 4, perf_log, MALLOC_CAP_SPIRAM); do_single_rw_perf_test(card, offset, 4, 4, perf_log, MALLOC_CAP_SPIRAM); diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_rw_sd.c b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_rw_sd.c index b8740ff533e..942bae84b77 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_rw_sd.c +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/components/sdmmc_tests/sdmmc_test_rw_sd.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,6 +37,11 @@ TEST_CASE("sdmmc read/write performance, slot 0, 8-bit", "[sdmmc]") do_one_sdmmc_perf_test(SLOT_0, 8, SDMMC_FREQ_HIGHSPEED, NO_DDR, NULL); } +TEST_CASE("sdmmc read/write performance, slot 1, 1-bit", "[sdmmc]") +{ + do_one_sdmmc_perf_test(SLOT_1, 1, SDMMC_FREQ_HIGHSPEED, NO_DDR, NULL); +} + TEST_CASE("sdmmc read/write performance, slot 1, 4-bit", "[sdmmc]") { /* Set up in-memory file for collecting performance logs */ diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 08e5cf3d1c4..fb18a9d6962 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -408,7 +408,11 @@ esp_err_t sdmmc_write_sectors(sdmmc_card_t* card, const void* src, #ifdef SOC_SDMMC_PSRAM_DMA_CAPABLE dma_mem_info.extra_heap_caps |= MALLOC_CAP_SPIRAM; #endif - if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, dma_mem_info)) { + if (esp_dma_is_buffer_alignment_satisfied(src, block_size * block_count, dma_mem_info) + #if !SOC_SDMMC_PSRAM_DMA_CAPABLE + && !esp_ptr_external_ram(src) + #endif + ) { err = sdmmc_write_sectors_dma(card, src, start_block, block_count, block_size * block_count); } else { // SDMMC peripheral needs DMA-capable buffers. Split the write into @@ -531,7 +535,11 @@ esp_err_t sdmmc_read_sectors(sdmmc_card_t* card, void* dst, size_t block_size = card->csd.sector_size; esp_dma_mem_info_t dma_mem_info; card->host.get_dma_info(card->host.slot, &dma_mem_info); - if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, dma_mem_info)) { + if (esp_dma_is_buffer_alignment_satisfied(dst, block_size * block_count, dma_mem_info) + #if !SOC_SDMMC_PSRAM_DMA_CAPABLE + && !esp_ptr_external_ram(dst) + #endif + ) { err = sdmmc_read_sectors_dma(card, dst, start_block, block_count, block_size * block_count); } else { // SDMMC peripheral needs DMA-capable buffers. Split the read into From 091da3d6315445eed1a6a7460af7c021ab21c2ae Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 20 May 2024 20:18:25 +0800 Subject: [PATCH 184/548] fix(esp_driver_gpio): manage lp_io module clock by driver Closes https://github.com/espressif/esp-idf/issues/13683 --- components/esp_driver_gpio/src/gpio.c | 36 ++++++----------- components/esp_driver_gpio/src/rtc_io.c | 28 ++++++------- .../include/esp_private/io_mux.h | 20 +++++++++- .../esp_hw_support/port/esp32c6/io_mux.c | 39 ++++++++++++++++++- .../esp_hw_support/port/esp32h2/io_mux.c | 32 ++++++++++++++- components/esp_hw_support/sleep_modes.c | 30 +++++--------- .../hal/esp32c6/include/hal/rtc_io_ll.h | 11 ++---- .../hal/esp32h2/include/hal/rtc_io_ll.h | 11 ++---- components/hal/include/hal/rtc_io_hal.h | 10 ++++- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32h2/include/soc/soc_caps.h | 3 ++ components/soc/include/soc/rtc_io_periph.h | 2 + .../lp_core/include/ulp_lp_core_gpio.h | 7 +++- .../ulp/test_apps/lp_core/main/test_lp_core.c | 3 ++ 14 files changed, 155 insertions(+), 81 deletions(-) diff --git a/components/esp_driver_gpio/src/gpio.c b/components/esp_driver_gpio/src/gpio.c index d52dcde2975..5e878b7e7d8 100644 --- a/components/esp_driver_gpio/src/gpio.c +++ b/components/esp_driver_gpio/src/gpio.c @@ -22,13 +22,7 @@ #include "hal/gpio_hal.h" #include "esp_rom_gpio.h" #include "esp_private/esp_gpio_reserve.h" -#include "esp_private/periph_ctrl.h" - -#if SOC_LP_IO_CLOCK_IS_INDEPENDENT && !SOC_RTCIO_RCC_IS_INDEPENDENT -#define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() -#else -#define RTCIO_RCC_ATOMIC() -#endif +#include "esp_private/io_mux.h" #if (SOC_RTCIO_PIN_COUNT > 0) #include "hal/rtc_io_hal.h" @@ -66,9 +60,6 @@ typedef struct { gpio_isr_func_t *gpio_isr_func; gpio_isr_handle_t gpio_isr_handle; uint64_t isr_clr_on_entry_mask; // for edge-triggered interrupts, interrupt status bits should be cleared before entering per-pin handlers -#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && SOC_LP_IO_CLOCK_IS_INDEPENDENT - uint32_t gpio_wakeup_mask; -#endif } gpio_context_t; static gpio_hal_context_t _gpio_hal = { @@ -81,9 +72,6 @@ static gpio_context_t gpio_context = { .isr_core_id = GPIO_ISR_CORE_ID_UNINIT, .gpio_isr_func = NULL, .isr_clr_on_entry_mask = 0, -#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP && SOC_LP_IO_CLOCK_IS_INDEPENDENT - .gpio_wakeup_mask = 0, -#endif }; esp_err_t gpio_pullup_en(gpio_num_t gpio_num) @@ -639,6 +627,11 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type) if ((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) { #if SOC_RTCIO_WAKE_SUPPORTED if (rtc_gpio_is_valid_gpio(gpio_num)) { +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + // LP_IO Wake-up function does not depend on LP_IO Matrix, but uses its clock to + // sample the wake-up signal, we need to enable the LP_IO clock here. + io_mux_enable_lp_io_clock(gpio_num, true); +#endif ret = rtc_gpio_wakeup_enable(gpio_num, intr_type); } #endif @@ -664,6 +657,9 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num) #if SOC_RTCIO_WAKE_SUPPORTED if (rtc_gpio_is_valid_gpio(gpio_num)) { ret = rtc_gpio_wakeup_disable(gpio_num); +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + io_mux_enable_lp_io_clock(gpio_num, false); +#endif } #endif portENTER_CRITICAL(&gpio_context.gpio_spinlock); @@ -992,12 +988,7 @@ esp_err_t gpio_deep_sleep_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t int } portENTER_CRITICAL(&gpio_context.gpio_spinlock); #if SOC_LP_IO_CLOCK_IS_INDEPENDENT - if (gpio_context.gpio_wakeup_mask == 0) { - RTCIO_RCC_ATOMIC() { - rtcio_ll_enable_io_clock(true); - } - } - gpio_context.gpio_wakeup_mask |= (1ULL << gpio_num); + io_mux_enable_lp_io_clock(gpio_num, true); #endif gpio_hal_deepsleep_wakeup_enable(gpio_context.gpio_hal, gpio_num, intr_type); #if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO @@ -1019,12 +1010,7 @@ esp_err_t gpio_deep_sleep_wakeup_disable(gpio_num_t gpio_num) gpio_hal_sleep_sel_en(gpio_context.gpio_hal, gpio_num); #endif #if SOC_LP_IO_CLOCK_IS_INDEPENDENT - gpio_context.gpio_wakeup_mask &= ~(1ULL << gpio_num); - if (gpio_context.gpio_wakeup_mask == 0) { - RTCIO_RCC_ATOMIC() { - rtcio_ll_enable_io_clock(false); - } - } + io_mux_enable_lp_io_clock(gpio_num, false); #endif portEXIT_CRITICAL(&gpio_context.gpio_spinlock); return ESP_OK; diff --git a/components/esp_driver_gpio/src/rtc_io.c b/components/esp_driver_gpio/src/rtc_io.c index 9a582b1867d..c382a7c9d8b 100644 --- a/components/esp_driver_gpio/src/rtc_io.c +++ b/components/esp_driver_gpio/src/rtc_io.c @@ -9,6 +9,7 @@ #include "esp_err.h" #include "esp_check.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/io_mux.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/timers.h" @@ -18,16 +19,6 @@ #include "soc/rtc_io_periph.h" #include "soc/soc_caps.h" -#if SOC_LP_IO_CLOCK_IS_INDEPENDENT && !SOC_RTCIO_RCC_IS_INDEPENDENT -// For `rtcio_hal_function_select` using, clock reg option is inlined in it, -// so remove the declaration check of __DECLARE_RCC_RC_ATOMIC_ENV -#define RTCIO_RCC_ATOMIC() \ - for (int i = 1; i ? (periph_rcc_enter(), 1) : 0; \ - periph_rcc_exit(), i--) -#else -#define RTCIO_RCC_ATOMIC() -#endif - static const char __attribute__((__unused__)) *RTCIO_TAG = "RTCIO"; extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished. @@ -56,9 +47,10 @@ esp_err_t rtc_gpio_init(gpio_num_t gpio_num) { ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error"); RTCIO_ENTER_CRITICAL(); - RTCIO_RCC_ATOMIC() { - rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_RTC); - } +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + io_mux_enable_lp_io_clock(gpio_num, true); +#endif + rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_RTC); RTCIO_EXIT_CRITICAL(); return ESP_OK; @@ -68,10 +60,12 @@ esp_err_t rtc_gpio_deinit(gpio_num_t gpio_num) { ESP_RETURN_ON_FALSE(rtc_gpio_is_valid_gpio(gpio_num), ESP_ERR_INVALID_ARG, RTCIO_TAG, "RTCIO number error"); RTCIO_ENTER_CRITICAL(); - RTCIO_RCC_ATOMIC() { - // Select Gpio as Digital Gpio - rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_DIGITAL); - } + // Select Gpio as Digital Gpio + rtcio_hal_function_select(rtc_io_number_get(gpio_num), RTCIO_LL_FUNC_DIGITAL); + +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + io_mux_enable_lp_io_clock(gpio_num, false); +#endif RTCIO_EXIT_CRITICAL(); return ESP_OK; diff --git a/components/esp_hw_support/include/esp_private/io_mux.h b/components/esp_hw_support/include/esp_private/io_mux.h index 3c3056d7620..dd8ea49ffb9 100644 --- a/components/esp_hw_support/include/esp_private/io_mux.h +++ b/components/esp_hw_support/include/esp_private/io_mux.h @@ -1,13 +1,17 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include #include "esp_err.h" #include "soc/clk_tree_defs.h" +#include "soc/gpio_num.h" +#include "soc/soc_caps.h" +#include "soc/io_mux_reg.h" #ifdef __cplusplus extern "C" { @@ -26,6 +30,20 @@ extern "C" { */ esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src); +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT +typedef struct { + uint8_t rtc_io_enabled_cnt[MAX_RTC_GPIO_NUM]; + uint32_t rtc_io_using_mask; +} rtc_io_status_t; + +/** + * Enable/Disable LP_IO peripheral clock. + * @param gpio_num GPIO number + * @param enable true to enable the clock / false to disable the clock + */ +void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/port/esp32c6/io_mux.c b/components/esp_hw_support/port/esp32c6/io_mux.c index e5679e40b4b..bd164ce683e 100644 --- a/components/esp_hw_support/port/esp32c6/io_mux.c +++ b/components/esp_hw_support/port/esp32c6/io_mux.c @@ -1,16 +1,29 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_attr.h" #include "freertos/FreeRTOS.h" #include "esp_private/io_mux.h" +#include "esp_private/periph_ctrl.h" #include "hal/gpio_ll.h" +#include "hal/rtc_io_ll.h" + +#define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED; static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) +#if CONFIG_ULP_COPROC_ENABLED +RTC_DATA_ATTR +#endif +static rtc_io_status_t s_rtc_io_status = { + .rtc_io_enabled_cnt = { 0 }, + .rtc_io_using_mask = 0 +}; + esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) { bool clk_conflict = false; @@ -31,3 +44,27 @@ esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) return ESP_OK; } + +void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) +{ + portENTER_CRITICAL(&s_io_mux_spinlock); + if (enable) { + if (s_rtc_io_status.rtc_io_enabled_cnt[gpio_num] == 0) { + s_rtc_io_status.rtc_io_using_mask |= (1ULL << gpio_num); + } + s_rtc_io_status.rtc_io_enabled_cnt[gpio_num]++; + } else if (!enable && (s_rtc_io_status.rtc_io_enabled_cnt[gpio_num] > 0)) { + s_rtc_io_status.rtc_io_enabled_cnt[gpio_num]--; + if (s_rtc_io_status.rtc_io_enabled_cnt[gpio_num] == 0) { + s_rtc_io_status.rtc_io_using_mask &= ~(1ULL << gpio_num); + } + } + RTCIO_RCC_ATOMIC() { + if (s_rtc_io_status.rtc_io_using_mask == 0) { + rtcio_ll_enable_io_clock(false); + } else { + rtcio_ll_enable_io_clock(true); + } + } + portEXIT_CRITICAL(&s_io_mux_spinlock); +} diff --git a/components/esp_hw_support/port/esp32h2/io_mux.c b/components/esp_hw_support/port/esp32h2/io_mux.c index 653c0b29812..3ff1884c10d 100644 --- a/components/esp_hw_support/port/esp32h2/io_mux.c +++ b/components/esp_hw_support/port/esp32h2/io_mux.c @@ -1,15 +1,21 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "freertos/FreeRTOS.h" #include "esp_private/io_mux.h" +#include "esp_private/periph_ctrl.h" #include "hal/gpio_ll.h" +#include "hal/rtc_io_ll.h" + +#define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() static portMUX_TYPE s_io_mux_spinlock = portMUX_INITIALIZER_UNLOCKED; static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) +static uint8_t s_rtc_io_enabled_cnt[MAX_RTC_GPIO_NUM] = { 0 }; +static uint32_t s_rtc_io_using_mask = 0; esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) { @@ -31,3 +37,27 @@ esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) return ESP_OK; } + +void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) +{ + portENTER_CRITICAL(&s_io_mux_spinlock); + if (enable) { + if (s_rtc_io_enabled_cnt[gpio_num] == 0) { + s_rtc_io_using_mask |= (1ULL << gpio_num); + } + s_rtc_io_enabled_cnt[gpio_num]++; + } else if (!enable && (s_rtc_io_enabled_cnt[gpio_num] > 0)) { + s_rtc_io_enabled_cnt[gpio_num]--; + if (s_rtc_io_enabled_cnt[gpio_num] == 0) { + s_rtc_io_using_mask &= ~(1ULL << gpio_num); + } + } + RTCIO_RCC_ATOMIC() { + if (s_rtc_io_using_mask == 0) { + rtcio_ll_enable_io_clock(false); + } else { + rtcio_ll_enable_io_clock(true); + } + } + portEXIT_CRITICAL(&s_io_mux_spinlock); +} diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 4be257586c3..90827e94d81 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -15,10 +15,10 @@ #include "esp_sleep.h" #include "esp_private/esp_sleep_internal.h" #include "esp_private/esp_timer_private.h" -#include "esp_private/periph_ctrl.h" #include "esp_private/rtc_clk.h" #include "esp_private/sleep_event.h" #include "esp_private/system_internal.h" +#include "esp_private/io_mux.h" #include "esp_log.h" #include "esp_newlib.h" #include "esp_timer.h" @@ -119,16 +119,6 @@ #include "esp_private/sleep_retention.h" #endif -#if SOC_LP_IO_CLOCK_IS_INDEPENDENT && !SOC_RTCIO_RCC_IS_INDEPENDENT -// For `rtcio_hal_function_select` using, clock reg option is inlined in it, -// so remove the declaration check of __DECLARE_RCC_RC_ATOMIC_ENV -#define RTCIO_RCC_ATOMIC() \ - for (int i = 1; i ? (periph_rcc_enter(), 1) : 0; \ - periph_rcc_exit(), i--) -#else -#define RTCIO_RCC_ATOMIC() -#endif - // If light sleep time is less than that, don't power down flash #define FLASH_PD_MIN_SLEEP_TIME_US 2000 @@ -1687,10 +1677,11 @@ esp_err_t esp_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level) static void ext0_wakeup_prepare(void) { int rtc_gpio_num = s_config.ext0_rtc_gpio_num; +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + io_mux_enable_lp_io_clock(rtc_gpio_num, true); +#endif rtcio_hal_ext0_set_wakeup_pin(rtc_gpio_num, s_config.ext0_trigger_level); - RTCIO_RCC_ATOMIC() { - rtcio_hal_function_select(rtc_gpio_num, RTCIO_LL_FUNC_RTC); - } + rtcio_hal_function_select(rtc_gpio_num, RTCIO_LL_FUNC_RTC); rtcio_hal_input_enable(rtc_gpio_num); } @@ -1819,11 +1810,12 @@ static void ext1_wakeup_prepare(void) if ((rtc_gpio_mask & BIT(rtc_pin)) == 0) { continue; } +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + io_mux_enable_lp_io_clock(rtc_pin, true); +#endif #if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED // Route pad to RTC - RTCIO_RCC_ATOMIC() { - rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_RTC); - } + rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_RTC); // set input enable in sleep mode rtcio_hal_input_enable(rtc_pin); #if SOC_PM_SUPPORT_RTC_PERIPH_PD @@ -1838,9 +1830,7 @@ static void ext1_wakeup_prepare(void) * a pathway to EXT1. */ // Route pad to DIGITAL - RTCIO_RCC_ATOMIC() { - rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_DIGITAL); - } + rtcio_hal_function_select(rtc_pin, RTCIO_LL_FUNC_DIGITAL); // set input enable gpio_ll_input_enable(&GPIO, gpio); // hold rtc_pin to use it during sleep state diff --git a/components/hal/esp32c6/include/hal/rtc_io_ll.h b/components/hal/esp32c6/include/hal/rtc_io_ll.h index 550d6accf06..406b07647b1 100644 --- a/components/hal/esp32c6/include/hal/rtc_io_ll.h +++ b/components/hal/esp32c6/include/hal/rtc_io_ll.h @@ -59,11 +59,14 @@ static inline void rtcio_ll_iomux_func_sel(int rtcio_num, int func) /** * @brief Enable/Disable LP_IO peripheral clock. * - * @param enable true to enable the clock / false to enable the clock + * @param enable true to enable the clock / false to disable the clock */ static inline void _rtcio_ll_enable_io_clock(bool enable) { LPPERI.clk_en.lp_io_ck_en = enable; + while (LPPERI.clk_en.lp_io_ck_en != enable) { + ; + } } #define rtcio_ll_enable_io_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _rtcio_ll_enable_io_clock(__VA_ARGS__) @@ -83,9 +86,6 @@ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) if (func == RTCIO_LL_FUNC_RTC) { // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); - if ((sel_mask & SOC_RTCIO_VALID_RTCIO_MASK) == 0) { - _rtcio_ll_enable_io_clock(true); - } sel_mask |= BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); //0:RTC FUNCTION 1,2,3:Reserved @@ -95,9 +95,6 @@ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask &= ~BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); - if ((sel_mask & SOC_RTCIO_VALID_RTCIO_MASK) == 0) { - _rtcio_ll_enable_io_clock(false); - } } } diff --git a/components/hal/esp32h2/include/hal/rtc_io_ll.h b/components/hal/esp32h2/include/hal/rtc_io_ll.h index 5899ce63adf..bfeb758a59b 100644 --- a/components/hal/esp32h2/include/hal/rtc_io_ll.h +++ b/components/hal/esp32h2/include/hal/rtc_io_ll.h @@ -34,11 +34,14 @@ typedef enum { /** * @brief Enable/Disable LP_IO peripheral clock. * - * @param enable true to enable the clock / false to enable the clock + * @param enable true to enable the clock / false to disable the clock */ static inline void _rtcio_ll_enable_io_clock(bool enable) { LPPERI.clk_en.lp_io_ck_en = enable; + while (LPPERI.clk_en.lp_io_ck_en != enable) { + ; + } } #define rtcio_ll_enable_io_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _rtcio_ll_enable_io_clock(__VA_ARGS__) @@ -56,9 +59,6 @@ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) if (func == RTCIO_LL_FUNC_RTC) { // 0: GPIO connected to digital GPIO module. 1: GPIO connected to analog RTC module. uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); - if ((sel_mask & SOC_RTCIO_VALID_RTCIO_MASK) == 0) { - _rtcio_ll_enable_io_clock(true); - } sel_mask |= BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); } else if (func == RTCIO_LL_FUNC_DIGITAL) { @@ -66,9 +66,6 @@ static inline void rtcio_ll_function_select(int rtcio_num, rtcio_ll_func_t func) uint32_t sel_mask = HAL_FORCE_READ_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel); sel_mask &= ~BIT(rtcio_num); HAL_FORCE_MODIFY_U32_REG_FIELD(LP_AON.gpio_mux, gpio_mux_sel, sel_mask); - if((sel_mask & SOC_RTCIO_VALID_RTCIO_MASK) == 0) { - _rtcio_ll_enable_io_clock(false); - } } } diff --git a/components/hal/include/hal/rtc_io_hal.h b/components/hal/include/hal/rtc_io_hal.h index 67b2201bcaa..086bec8c0d1 100644 --- a/components/hal/include/hal/rtc_io_hal.h +++ b/components/hal/include/hal/rtc_io_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -31,6 +31,14 @@ extern "C" { #endif #if SOC_RTCIO_PIN_COUNT > 0 + +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT +/** + * Enable rtcio module clock. + */ +#define rtcio_hal_enable_io_clock(enable) rtcio_ll_output_enable(enable) +#endif + /** * Select the rtcio function. * diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 9606984626f..aa01c911871 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -487,6 +487,10 @@ config SOC_GPIO_SUPPORT_RTC_INDEPENDENT bool default y +config SOC_LP_IO_CLOCK_IS_INDEPENDENT + bool + default y + config SOC_GPIO_IN_RANGE_MAX int default 27 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 2181547f95b..f0b27ffc2fe 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -196,6 +196,9 @@ // However, there is no way to control pullup/down/capability for IOs under LP function since there is no LP_IOMUX registers #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) +// LP IO peripherals have independent clock gating to manage +#define SOC_LP_IO_CLOCK_IS_INDEPENDENT (1) + // GPIO7~14 on ESP32H2 can support chip deep sleep wakeup through EXT1 wake up #define SOC_GPIO_VALID_GPIO_MASK ((1U << SOC_GPIO_PIN_COUNT) - 1) diff --git a/components/soc/include/soc/rtc_io_periph.h b/components/soc/include/soc/rtc_io_periph.h index 3eadcfda1a0..19c4959a57c 100644 --- a/components/soc/include/soc/rtc_io_periph.h +++ b/components/soc/include/soc/rtc_io_periph.h @@ -18,6 +18,8 @@ #include "soc/sens_struct.h" #endif +#include "soc/io_mux_reg.h" + #ifdef __cplusplus extern "C" { diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h index 42745dc1863..c7d22a02640 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -29,11 +29,16 @@ typedef enum { /** * @brief Initialize a rtcio pin + * @note If IO is used in LP application, `rtc_gpio_init` must be called at least once + * for the using IO before loading LP core firmware in HP Code. * * @param lp_io_num The rtc io pin to initialize */ static inline void ulp_lp_core_gpio_init(lp_io_num_t lp_io_num) { +#if SOC_LP_IO_CLOCK_IS_INDEPENDENT + _rtcio_ll_enable_io_clock(true); +#endif rtcio_ll_function_select(lp_io_num, RTCIO_LL_FUNC_RTC); } diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core.c b/components/ulp/test_apps/lp_core/main/test_lp_core.c index c1ebaaaf0e0..5060598f8ea 100644 --- a/components/ulp/test_apps/lp_core/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/main/test_lp_core.c @@ -8,6 +8,7 @@ #include #include #include "soc/soc_caps.h" +#include "soc/gpio_num.h" #include "esp_rom_caps.h" #include "lp_core_test_app.h" #include "lp_core_test_app_counter.h" @@ -23,6 +24,7 @@ #include "unity.h" #include "esp_sleep.h" #include "esp_timer.h" +#include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -320,6 +322,7 @@ TEST_CASE("LP core gpio tests", "[ulp]") .lp_timer_sleep_duration_us = LP_TIMER_TEST_SLEEP_DURATION_US, }; + rtc_gpio_init(GPIO_NUM_0); load_and_start_lp_core_firmware(&cfg, lp_core_main_gpio_bin_start, lp_core_main_gpio_bin_end); while (!ulp_gpio_test_finished) { From 4daaa9c587293d1cc6f50322bf9cb81ca1329042 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Fri, 31 May 2024 19:06:50 +0800 Subject: [PATCH 185/548] fix(bod): Disable fib in bootloader so that interrupt can be triggered properly --- .../bootloader_support/src/esp32p4/bootloader_soc.c | 9 +++++++-- components/soc/esp32p4/include/soc/lp_analog_peri_reg.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/src/esp32p4/bootloader_soc.c b/components/bootloader_support/src/esp32p4/bootloader_soc.c index 2411bfe28f6..f64b88c9589 100644 --- a/components/bootloader_support/src/esp32p4/bootloader_soc.c +++ b/components/bootloader_support/src/esp32p4/bootloader_soc.c @@ -1,9 +1,12 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include "soc/lp_analog_peri_reg.h" +#include "soc/soc.h" +#include "hal/brownout_ll.h" void bootloader_ana_super_wdt_reset_config(bool enable) { @@ -12,7 +15,9 @@ void bootloader_ana_super_wdt_reset_config(bool enable) void bootloader_ana_bod_reset_config(bool enable) { - //TODO: IDF-7514 + REG_CLR_BIT(LP_ANALOG_PERI_FIB_ENABLE_REG, LP_ANALOG_PERI_LP_ANA_FIB_BOD_RST); + + brownout_ll_ana_reset_enable(enable); } void bootloader_ana_clock_glitch_reset_config(bool enable) diff --git a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h index 9b55adfd146..68fcde9d0d3 100644 --- a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h +++ b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h @@ -233,6 +233,8 @@ extern "C" { #define LP_ANALOG_PERI_ANA_FIB_ENA_V 0xFFFFFFFFU #define LP_ANALOG_PERI_ANA_FIB_ENA_S 0 +#define LP_ANALOG_PERI_LP_ANA_FIB_BOD_RST BIT(1) + /** LP_ANALOG_PERI_INT_RAW_REG register * need_des */ From e5429b256aa343b3140c2db959ae20962ad21dee Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 6 Jun 2024 20:07:53 +0800 Subject: [PATCH 186/548] fix(hal): fix LP timer LL half word access --- components/hal/esp32c5/include/hal/lp_timer_ll.h | 9 +++++---- components/hal/esp32c6/include/hal/lp_timer_ll.h | 9 +++++---- components/hal/esp32h2/include/hal/lp_timer_ll.h | 9 +++++---- components/hal/esp32p4/include/hal/lp_timer_ll.h | 9 +++++---- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/components/hal/esp32c5/include/hal/lp_timer_ll.h b/components/hal/esp32c5/include/hal/lp_timer_ll.h index 357a89b8a14..49997480b5c 100644 --- a/components/hal/esp32c5/include/hal/lp_timer_ll.h +++ b/components/hal/esp32c5/include/hal/lp_timer_ll.h @@ -15,6 +15,7 @@ #include "soc/lp_aon_reg.h" #include "hal/assert.h" #include "hal/lp_timer_types.h" +#include "hal/misc.h" #include "esp_attr.h" #ifdef __cplusplus @@ -33,8 +34,8 @@ extern "C" { FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value) { #if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - dev->target[timer_id].hi.main_timer_tar_high = (value >> 32) & 0xFFFF; - dev->target[timer_id].lo.main_timer_tar_low = value & 0xFFFFFFFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, main_timer_tar_high, (value >> 32) & 0xFFFF); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].lo, main_timer_tar_low, value & 0xFFFFFFFF); #else HAL_ASSERT(false && "lp_timer not supported yet"); #endif @@ -69,7 +70,7 @@ FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_ FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t buffer_id) { #if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - return dev->counter[buffer_id].lo.main_timer_buf_low; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].lo, main_timer_buf_low); #else HAL_ASSERT(false && "lp_timer not supported yet"); return 0; @@ -87,7 +88,7 @@ FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t buffer_id) { #if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - return dev->counter[buffer_id].hi.main_timer_buf_high; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].hi, main_timer_buf_high); #else HAL_ASSERT(false && "lp_timer not supported yet"); return 0; diff --git a/components/hal/esp32c6/include/hal/lp_timer_ll.h b/components/hal/esp32c6/include/hal/lp_timer_ll.h index 968366febd9..080555bd899 100644 --- a/components/hal/esp32c6/include/hal/lp_timer_ll.h +++ b/components/hal/esp32c6/include/hal/lp_timer_ll.h @@ -15,6 +15,7 @@ #include "soc/lp_timer_reg.h" #include "soc/lp_aon_reg.h" #include "hal/lp_timer_types.h" +#include "hal/misc.h" #include "esp_attr.h" #ifdef __cplusplus @@ -23,8 +24,8 @@ extern "C" { FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value) { - dev->target[timer_id].hi.target_hi = (value >> 32) & 0xFFFF; - dev->target[timer_id].lo.target_lo = value & 0xFFFFFFFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, target_hi, (value >> 32) & 0xFFFF); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].lo, target_lo, value & 0xFFFFFFFF); } FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en) @@ -34,12 +35,12 @@ FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_ FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t buffer_id) { - return dev->counter[buffer_id].lo.counter_lo; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].lo, counter_lo); } FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t buffer_id) { - return dev->counter[buffer_id].hi.counter_hi; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[buffer_id].hi, counter_hi); } FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev) diff --git a/components/hal/esp32h2/include/hal/lp_timer_ll.h b/components/hal/esp32h2/include/hal/lp_timer_ll.h index f0182585fc6..c8e6e2a0541 100644 --- a/components/hal/esp32h2/include/hal/lp_timer_ll.h +++ b/components/hal/esp32h2/include/hal/lp_timer_ll.h @@ -14,6 +14,7 @@ #include "soc/lp_timer_struct.h" #include "soc/lp_aon_reg.h" #include "hal/lp_timer_types.h" +#include "hal/misc.h" #include "esp_attr.h" #ifdef __cplusplus @@ -22,8 +23,8 @@ extern "C" { FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value) { - dev->target[timer_id].hi.target_hi = (value >> 32) & 0xFFFF; - dev->target[timer_id].lo.target_lo = value & 0xFFFFFFFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, target_hi, (value >> 32) & 0xFFFF); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].lo, target_lo, value & 0xFFFFFFFF); } FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en) @@ -33,12 +34,12 @@ FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_ FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t timer_id) { - return dev->counter[timer_id].lo.counter_lo; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[timer_id].lo, counter_lo); } FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t timer_id) { - return dev->counter[timer_id].hi.counter_hi; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[timer_id].hi, counter_hi); } FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev) diff --git a/components/hal/esp32p4/include/hal/lp_timer_ll.h b/components/hal/esp32p4/include/hal/lp_timer_ll.h index 034d9f5c687..45e8ad3fa86 100644 --- a/components/hal/esp32p4/include/hal/lp_timer_ll.h +++ b/components/hal/esp32p4/include/hal/lp_timer_ll.h @@ -15,6 +15,7 @@ #include "soc/lp_timer_reg.h" #include "soc/lp_system_reg.h" #include "hal/lp_timer_types.h" +#include "hal/misc.h" #include "esp_attr.h" #ifdef __cplusplus @@ -23,8 +24,8 @@ extern "C" { FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value) { - dev->target[timer_id].hi.target_hi = (value >> 32) & 0xFFFF; - dev->target[timer_id].lo.target_lo = value & 0xFFFFFFFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, target_hi, (value >> 32) & 0xFFFF); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].lo, target_lo, value & 0xFFFFFFFF); } FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en) @@ -34,12 +35,12 @@ FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_ FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t timer_id) { - return dev->counter[timer_id].lo.counter_lo; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[timer_id].lo, counter_lo); } FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t timer_id) { - return dev->counter[timer_id].hi.counter_hi; + return HAL_FORCE_READ_U32_REG_FIELD(dev->counter[timer_id].hi, counter_hi); } FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev) From 6a86351373fcca3e1cbd3191e5745c01795fb48c Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 6 Jun 2024 21:03:31 +0800 Subject: [PATCH 187/548] fix(hal): fix PMU LL half word and byte access --- components/hal/esp32c5/include/hal/pmu_ll.h | 29 +++++++++--------- components/hal/esp32c6/include/hal/pmu_ll.h | 31 ++++++++++---------- components/hal/esp32c61/include/hal/pmu_ll.h | 29 +++++++++--------- components/hal/esp32h2/include/hal/pmu_ll.h | 31 ++++++++++---------- components/hal/esp32p4/include/hal/pmu_ll.h | 29 +++++++++--------- 5 files changed, 77 insertions(+), 72 deletions(-) diff --git a/components/hal/esp32c5/include/hal/pmu_ll.h b/components/hal/esp32c5/include/hal/pmu_ll.h index 81f98a9c10a..83793ed62d6 100644 --- a/components/hal/esp32c5/include/hal/pmu_ll.h +++ b/components/hal/esp32c5/include/hal/pmu_ll.h @@ -15,6 +15,7 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" #include "hal/pmu_types.h" +#include "hal/misc.h" #ifdef __cplusplus extern "C" { @@ -488,7 +489,7 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.hp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) @@ -533,27 +534,27 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_reject_cause(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.modify_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.switch_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -578,12 +579,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl5.lp_ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_set_modem_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -598,22 +599,22 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_get_modem_wait_target_cycle(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_xtal_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_xtal_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); } FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_pll_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_pll_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); } FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -638,12 +639,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t * FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl7.ana_wait_target = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl7.ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) diff --git a/components/hal/esp32c6/include/hal/pmu_ll.h b/components/hal/esp32c6/include/hal/pmu_ll.h index 2470f73247c..c79a4809b0a 100644 --- a/components/hal/esp32c6/include/hal/pmu_ll.h +++ b/components/hal/esp32c6/include/hal/pmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" #include "hal/pmu_types.h" +#include "hal/misc.h" #ifdef __cplusplus extern "C" { @@ -488,7 +489,7 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.hp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) @@ -543,27 +544,27 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.modify_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.switch_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -588,12 +589,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl5.lp_ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_set_modem_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -608,22 +609,22 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_get_modem_wait_target_cycle(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_xtal_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_xtal_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); } FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_pll_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_pll_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); } FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -648,12 +649,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t * FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl7.ana_wait_target = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl7.ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) diff --git a/components/hal/esp32c61/include/hal/pmu_ll.h b/components/hal/esp32c61/include/hal/pmu_ll.h index a70c8419b24..85a8c0d3f91 100644 --- a/components/hal/esp32c61/include/hal/pmu_ll.h +++ b/components/hal/esp32c61/include/hal/pmu_ll.h @@ -15,6 +15,7 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" #include "hal/pmu_types.h" +#include "hal/misc.h" // TODO: [ESP32C61] IDF-9250, inherit from c6 @@ -490,7 +491,7 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.hp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) @@ -545,27 +546,27 @@ FORCE_INLINE_ATTR void pmu_ll_lp_clear_intsts_mask(pmu_dev_t *hw, uint32_t mask) FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.modify_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.switch_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -590,12 +591,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl5.lp_ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_set_modem_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -610,22 +611,22 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_get_modem_wait_target_cycle(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_xtal_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_xtal_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); } FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_pll_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_pll_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); } FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -650,12 +651,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t * FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl7.ana_wait_target = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl7.ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) diff --git a/components/hal/esp32h2/include/hal/pmu_ll.h b/components/hal/esp32h2/include/hal/pmu_ll.h index d666973e2fc..1272e2fb24e 100644 --- a/components/hal/esp32h2/include/hal/pmu_ll.h +++ b/components/hal/esp32h2/include/hal/pmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" #include "hal/pmu_types.h" +#include "hal/misc.h" #ifdef __cplusplus extern "C" { @@ -446,7 +447,7 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl3.hp_min_slp_val = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) @@ -486,27 +487,27 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_reject_cause(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.modify_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.switch_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -531,32 +532,32 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl5.lp_ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_xtal_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_xtal_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); } FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_pll_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_pll_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); } FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -581,12 +582,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t * FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl7.ana_wait_target = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl7.ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) diff --git a/components/hal/esp32p4/include/hal/pmu_ll.h b/components/hal/esp32p4/include/hal/pmu_ll.h index 057428e1326..cf5e2e4632b 100644 --- a/components/hal/esp32p4/include/hal/pmu_ll.h +++ b/components/hal/esp32p4/include/hal/pmu_ll.h @@ -15,6 +15,7 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" #include "hal/pmu_types.h" +#include "hal/misc.h" #ifdef __cplusplus extern "C" { @@ -461,7 +462,7 @@ FORCE_INLINE_ATTR void pmu_ll_hp_set_sleep_protect_mode(pmu_dev_t *hw, int mode) FORCE_INLINE_ATTR void pmu_ll_hp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.hp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, hp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_cause(pmu_dev_t *hw) @@ -511,27 +512,27 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_lite_wakeup_cause(pmu_dev_t *hw) FORCE_INLINE_ATTR void pmu_ll_lp_set_min_sleep_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl3.lp_min_slp_val = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl3, lp_min_slp_val, slow_clk_cycle); } FORCE_INLINE_ATTR void pmu_ll_hp_set_modify_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.modify_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_modify_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.modify_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, modify_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_switch_icg_cntl_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->hp_ext.clk_cntl.switch_icg_cntl_wait = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_switch_icg_cntl_wait_cycle(pmu_dev_t *hw) { - return hw->hp_ext.clk_cntl.switch_icg_cntl_wait; + return HAL_FORCE_READ_U32_REG_FIELD(hw->hp_ext.clk_cntl, switch_icg_cntl_wait); } FORCE_INLINE_ATTR void pmu_ll_hp_set_digital_power_down_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -556,32 +557,32 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle) { - hw->wakeup.cntl5.lp_ana_wait_target = slow_clk_cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl5.lp_ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target); } FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_xtal_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_xtal_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_xtal_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_xtal_stable); } FORCE_INLINE_ATTR void pmu_ll_set_pll_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->power.clk_wait.wait_pll_stable = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_get_pll_stable_wait_cycle(pmu_dev_t *hw) { - return hw->power.clk_wait.wait_pll_stable; + return HAL_FORCE_READ_U32_REG_FIELD(hw->power.clk_wait, wait_pll_stable); } FORCE_INLINE_ATTR void pmu_ll_lp_set_digital_power_supply_wait_cycle(pmu_dev_t *hw, uint32_t cycle) @@ -606,12 +607,12 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_up_wait_cycle(pmu_dev_t * FORCE_INLINE_ATTR void pmu_ll_hp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t cycle) { - hw->wakeup.cntl7.ana_wait_target = cycle; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target, cycle); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_analog_wait_target_cycle(pmu_dev_t *hw) { - return hw->wakeup.cntl7.ana_wait_target; + return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl7, ana_wait_target); } FORCE_INLINE_ATTR uint32_t pmu_ll_hp_set_lite_wakeup_enable(pmu_dev_t *hw, bool wakeup_en) From f6420436eb43a2053b4f16b2fbec5a50d839d181 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Fri, 26 Apr 2024 12:27:54 +0200 Subject: [PATCH 188/548] feat(esp_eth): a new folder structure of the driver and other improvements Fixed memory leak in emac_esp_new_dma function. Polished ESP EMAC cache management. Added emac_periph definitions based on SoC features and improved(generalized) ESP EMAC GPIO initialization. Added ESP EMAC GPIO reservation. Added check for frame error condition indicated by EMAC DMA and created a target test. --- components/esp_eth/CMakeLists.txt | 38 +- components/esp_eth/Kconfig | 2 +- components/esp_eth/include/esp_eth_com.h | 13 +- components/esp_eth/include/esp_eth_driver.h | 42 +- components/esp_eth/include/esp_eth_mac.h | 435 +----------------- components/esp_eth/include/esp_eth_mac_esp.h | 296 ++++++++++++ .../esp_eth/include/esp_eth_mac_openeth.h | 31 ++ components/esp_eth/include/esp_eth_mac_spi.h | 236 ++++++++++ components/esp_eth/include/esp_eth_phy.h | 4 +- .../esp_eth/include/esp_eth_phy_802_3.h | 64 +-- .../include/esp_private/eth_mac_esp_dma.h | 134 +++++- .../include/esp_private/eth_mac_esp_gpio.h | 56 +-- components/esp_eth/src/esp_eth.c | 18 + components/esp_eth/src/esp_eth_mac_esp_gpio.c | 358 -------------- components/esp_eth/src/esp_eth_netif_glue.c | 1 - .../esp_eth/src/{ => mac}/esp_eth_mac_esp.c | 175 ++++--- .../src/{ => mac}/esp_eth_mac_esp_dma.c | 268 ++++------- .../esp_eth/src/mac/esp_eth_mac_esp_gpio.c | 265 +++++++++++ .../src/{ => openeth}/esp_eth_mac_openeth.c | 2 +- .../esp_eth/src/{ => openeth}/esp_openeth.h | 2 +- .../esp_eth/src/{ => openeth}/openeth.h | 2 +- .../esp_eth/src/{ => phy}/esp_eth_phy_802_3.c | 0 .../src/{ => phy}/esp_eth_phy_dp83848.c | 0 .../esp_eth/src/{ => phy}/esp_eth_phy_ip101.c | 2 +- .../src/{ => phy}/esp_eth_phy_ksz80xx.c | 0 .../src/{ => phy}/esp_eth_phy_lan87xx.c | 0 .../src/{ => phy}/esp_eth_phy_rtl8201.c | 0 .../esp_eth/src/{ => spi/dm9051}/dm9051.h | 0 .../src/{ => spi/dm9051}/esp_eth_mac_dm9051.c | 2 +- .../src/{ => spi/dm9051}/esp_eth_phy_dm9051.c | 4 +- .../ksz8851snl}/esp_eth_mac_ksz8851snl.c | 2 +- .../ksz8851snl}/esp_eth_phy_ksz8851snl.c | 4 +- .../src/{ => spi/ksz8851snl}/ksz8851.h | 29 +- .../src/{ => spi/w5500}/esp_eth_mac_w5500.c | 6 +- .../src/{ => spi/w5500}/esp_eth_phy_w5500.c | 2 +- .../esp_eth/src/{ => spi/w5500}/w5500.h | 0 .../esp_eth/test_apps/main/CMakeLists.txt | 2 +- .../test_apps/main/esp_eth_test_common.c | 6 +- .../test_apps/main/esp_eth_test_esp_emac.c | 115 ++++- .../test_app_vfs_l2tap/sdkconfig.defaults | 2 + components/hal/esp32/include/hal/emac_ll.h | 5 + components/hal/esp32p4/include/hal/emac_ll.h | 5 + components/hal/include/hal/emac_hal.h | 128 ++---- .../test_apps/test_mqtt/main/CMakeLists.txt | 2 +- .../test_apps/test_mqtt5/main/CMakeLists.txt | 2 +- components/soc/CMakeLists.txt | 4 + components/soc/esp32/emac_periph.c | 224 +++++++++ components/soc/esp32p4/emac_periph.c | 208 +++++++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 10 +- .../soc/esp32p4/include/soc/gpio_sig_map.h | 40 +- .../soc/esp32p4/include/soc/io_mux_reg.h | 77 ++-- components/soc/esp32p4/include/soc/soc_caps.h | 4 +- components/soc/include/soc/emac_periph.h | 100 +++- docs/doxygen/Doxyfile | 2 + docs/en/api-reference/network/esp_eth.rst | 18 +- docs/zh_CN/api-reference/network/esp_eth.rst | 153 ++++-- .../protocol_examples_common/eth_connect.c | 4 +- .../components/ethernet_init/ethernet_init.c | 4 +- .../components/ethernet_init/ethernet_init.h | 14 +- .../http_server/async_handlers/main/main.c | 2 +- .../protocols/http_server/simple/main/main.c | 6 +- .../main/tcp_client_multiple.c | 5 +- tools/ci/check_copyright_ignore.txt | 2 - 63 files changed, 2178 insertions(+), 1459 deletions(-) create mode 100644 components/esp_eth/include/esp_eth_mac_esp.h create mode 100644 components/esp_eth/include/esp_eth_mac_openeth.h create mode 100644 components/esp_eth/include/esp_eth_mac_spi.h delete mode 100644 components/esp_eth/src/esp_eth_mac_esp_gpio.c rename components/esp_eth/src/{ => mac}/esp_eth_mac_esp.c (83%) rename components/esp_eth/src/{ => mac}/esp_eth_mac_esp_dma.c (69%) create mode 100644 components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c rename components/esp_eth/src/{ => openeth}/esp_eth_mac_openeth.c (99%) rename components/esp_eth/src/{ => openeth}/esp_openeth.h (92%) rename components/esp_eth/src/{ => openeth}/openeth.h (99%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_802_3.c (100%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_dp83848.c (100%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_ip101.c (99%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_ksz80xx.c (100%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_lan87xx.c (100%) rename components/esp_eth/src/{ => phy}/esp_eth_phy_rtl8201.c (100%) rename components/esp_eth/src/{ => spi/dm9051}/dm9051.h (100%) rename components/esp_eth/src/{ => spi/dm9051}/esp_eth_mac_dm9051.c (99%) rename components/esp_eth/src/{ => spi/dm9051}/esp_eth_phy_dm9051.c (99%) rename components/esp_eth/src/{ => spi/ksz8851snl}/esp_eth_mac_ksz8851snl.c (99%) rename components/esp_eth/src/{ => spi/ksz8851snl}/esp_eth_phy_ksz8851snl.c (99%) rename components/esp_eth/src/{ => spi/ksz8851snl}/ksz8851.h (95%) rename components/esp_eth/src/{ => spi/w5500}/esp_eth_mac_w5500.c (99%) rename components/esp_eth/src/{ => spi/w5500}/esp_eth_phy_w5500.c (99%) rename components/esp_eth/src/{ => spi/w5500}/w5500.h (100%) create mode 100644 components/soc/esp32/emac_periph.c create mode 100644 components/soc/esp32p4/emac_periph.c diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index 071cb776d80..a3499c07465 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -12,11 +12,11 @@ set(ld_fragments linker.lf) # As CONFIG_ETH_ENABLED comes from Kconfig, it is not evaluated yet # when components are being registered. # Thus, always add the (private) requirements, regardless of Kconfig -set(priv_requires driver log esp_timer) +set(priv_requires log esp_timer esp_driver_spi esp_driver_gpio) # If Ethernet disabled in Kconfig, this is a config-only component if(CONFIG_ETH_ENABLED) - set(srcs "src/esp_eth.c" "src/esp_eth_phy_802_3.c") + set(srcs "src/esp_eth.c" "src/phy/esp_eth_phy_802_3.c") set(include "include") if(NOT CMAKE_BUILD_EARLY_EXPANSION) @@ -27,34 +27,34 @@ if(CONFIG_ETH_ENABLED) endif() if(CONFIG_ETH_USE_ESP32_EMAC) - list(APPEND srcs "src/esp_eth_mac_esp.c" - "src/esp_eth_mac_esp_dma.c" - "src/esp_eth_mac_esp_gpio.c" - "src/esp_eth_phy_dp83848.c" - "src/esp_eth_phy_ip101.c" - "src/esp_eth_phy_ksz80xx.c" - "src/esp_eth_phy_lan87xx.c" - "src/esp_eth_phy_rtl8201.c") + list(APPEND srcs "src/mac/esp_eth_mac_esp.c" + "src/mac/esp_eth_mac_esp_dma.c" + "src/mac/esp_eth_mac_esp_gpio.c" + "src/phy/esp_eth_phy_dp83848.c" + "src/phy/esp_eth_phy_ip101.c" + "src/phy/esp_eth_phy_ksz80xx.c" + "src/phy/esp_eth_phy_lan87xx.c" + "src/phy/esp_eth_phy_rtl8201.c") endif() if(CONFIG_ETH_SPI_ETHERNET_DM9051) - list(APPEND srcs "src/esp_eth_mac_dm9051.c" - "src/esp_eth_phy_dm9051.c") + list(APPEND srcs "src/spi/dm9051/esp_eth_mac_dm9051.c" + "src/spi/dm9051/esp_eth_phy_dm9051.c") endif() if(CONFIG_ETH_SPI_ETHERNET_W5500) - list(APPEND srcs "src/esp_eth_mac_w5500.c" - "src/esp_eth_phy_w5500.c") + list(APPEND srcs "src/spi/w5500/esp_eth_mac_w5500.c" + "src/spi/w5500/esp_eth_phy_w5500.c") endif() if(CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL) - list(APPEND srcs "src/esp_eth_mac_ksz8851snl.c" - "src/esp_eth_phy_ksz8851snl.c") + list(APPEND srcs "src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c" + "src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c") endif() if(CONFIG_ETH_USE_OPENETH) - list(APPEND srcs "src/esp_eth_mac_openeth.c" - "src/esp_eth_phy_dp83848.c") + list(APPEND srcs "src/openeth/esp_eth_mac_openeth.c" + "src/phy/esp_eth_phy_dp83848.c") endif() endif() @@ -66,7 +66,7 @@ idf_component_register(SRCS "${srcs}" if(CONFIG_ETH_ENABLED) if(CONFIG_ETH_USE_SPI_ETHERNET) - idf_component_optional_requires(PUBLIC driver esp_driver_gpio) + idf_component_optional_requires(PUBLIC esp_driver_spi) endif() idf_component_optional_requires(PRIVATE esp_netif esp_pm) if(CONFIG_SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE) diff --git a/components/esp_eth/Kconfig b/components/esp_eth/Kconfig index 9de9df49e0a..fe8fd3961d7 100644 --- a/components/esp_eth/Kconfig +++ b/components/esp_eth/Kconfig @@ -24,7 +24,7 @@ menu "Ethernet" endchoice if ETH_PHY_INTERFACE_RMII - choice ETH_RMII_CLK_MODE + choice ETH_RMII_CLK_MODE # IDF-9724 depends on IDF_TARGET_ESP32 prompt "RMII clock mode" default ETH_RMII_CLK_INPUT diff --git a/components/esp_eth/include/esp_eth_com.h b/components/esp_eth/include/esp_eth_com.h index a81ac058fbb..a2c49459438 100644 --- a/components/esp_eth/include/esp_eth_com.h +++ b/components/esp_eth/include/esp_eth_com.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,17 @@ extern "C" { #endif +/** + * @brief Offset for start of MAC custom ioctl commands + * + */ +#define ETH_CMD_CUSTOM_MAC_CMDS_OFFSET 0x0FFF +/** + * @brief Offset for start of PHY custom ioctl commands + * + */ +#define ETH_CMD_CUSTOM_PHY_CMDS_OFFSET 0x1FFF + /** * @brief Ethernet driver state * diff --git a/components/esp_eth/include/esp_eth_driver.h b/components/esp_eth/include/esp_eth_driver.h index 068a911dfb1..3a253f71c45 100644 --- a/components/esp_eth/include/esp_eth_driver.h +++ b/components/esp_eth/include/esp_eth_driver.h @@ -1,12 +1,20 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "esp_eth_com.h" -#include "esp_eth_mac.h" +#if CONFIG_ETH_USE_SPI_ETHERNET +#include "esp_eth_mac_spi.h" +#endif // CONFIG_ETH_USE_SPI_ETHERNET +#if CONFIG_ETH_USE_ESP32_EMAC +#include "esp_eth_mac_esp.h" +#endif // CONFIG_ETH_USE_ESP32_EMAC +#if CONFIG_ETH_USE_OPENETH +#include "esp_eth_mac_openeth.h" +#endif // CONFIG_ETH_USE_OPENETH #include "esp_eth_phy.h" #ifdef __cplusplus @@ -151,8 +159,8 @@ typedef enum { ETH_CMD_READ_PHY_REG, /*!< Read PHY register */ ETH_CMD_WRITE_PHY_REG, /*!< Write PHY register */ - ETH_CMD_CUSTOM_MAC_CMDS = 0x0FFF, // Offset for start of MAC custom commands - ETH_CMD_CUSTOM_PHY_CMDS = 0x1FFF, // Offset for start of PHY custom commands + ETH_CMD_CUSTOM_MAC_CMDS = ETH_CMD_CUSTOM_MAC_CMDS_OFFSET, // Offset for start of MAC custom commands + ETH_CMD_CUSTOM_PHY_CMDS = ETH_CMD_CUSTOM_PHY_CMDS_OFFSET, // Offset for start of PHY custom commands } esp_eth_io_cmd_t; /** @@ -272,7 +280,7 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length); * @param[in] argc number variable arguments * @param ... variable arguments * @return -* - ESP_OK: transmit successfull +* - ESP_OK: transmit successful * - ESP_ERR_INVALID_STATE: invalid driver state (e.i. driver is not started) * - ESP_ERR_TIMEOUT: transmit frame buffer failed because HW was not get available in predefined period * - ESP_FAIL: transmit frame buffer failed because some other error occurred @@ -280,7 +288,7 @@ esp_err_t esp_eth_transmit(esp_eth_handle_t hdl, void *buf, size_t length); esp_err_t esp_eth_transmit_vargs(esp_eth_handle_t hdl, uint32_t argc, ...); /** -* @brief Misc IO function of Etherent driver +* @brief Misc IO function of Ethernet driver * * @param[in] hdl: handle of Ethernet driver * @param[in] cmd: IO control command @@ -314,6 +322,28 @@ esp_err_t esp_eth_transmit_vargs(esp_eth_handle_t hdl, uint32_t argc, ...); */ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data); +/** +* @brief Get PHY instance memory address +* +* @param[in] hdl handle of Ethernet driver +* @param[out] phy pointer to memory to store the instance +* @return esp_err_t +* - ESP_OK: success +* - ESP_ERR_INVALID_ARG: failed because of some invalid argument +*/ +esp_err_t esp_eth_get_phy_instance(esp_eth_handle_t hdl, esp_eth_phy_t **phy); + +/** +* @brief Get MAC instance memory address +* +* @param[in] hdl handle of Ethernet driver +* @param[out] mac pointer to memory to store the instance +* @return esp_err_t +* - ESP_OK: success +* - ESP_ERR_INVALID_ARG: failed because of some invalid argument +*/ +esp_err_t esp_eth_get_mac_instance(esp_eth_handle_t hdl, esp_eth_mac_t **mac); + /** * @brief Increase Ethernet driver reference * @note Ethernet driver handle can be obtained by os timer, netif, etc. diff --git a/components/esp_eth/include/esp_eth_mac.h b/components/esp_eth/include/esp_eth_mac.h index c10b8137090..cabfb127239 100644 --- a/components/esp_eth/include/esp_eth_mac.h +++ b/components/esp_eth/include/esp_eth_mac.h @@ -9,9 +9,6 @@ #include "soc/soc_caps.h" #include "esp_eth_com.h" #include "sdkconfig.h" -#if CONFIG_ETH_USE_SPI_ETHERNET -#include "driver/spi_master.h" -#endif #ifdef __cplusplus extern "C" { @@ -306,7 +303,7 @@ struct esp_eth_mac_s { * - ESP_FAIL: process io command failed because some other error occurred * - ESP_ERR_NOT_SUPPORTED: requested feature is not supported */ - esp_err_t (*custom_ioctl)(esp_eth_mac_t *mac, uint32_t cmd, void *data); + esp_err_t (*custom_ioctl)(esp_eth_mac_t *mac, int cmd, void *data); /** * @brief Free memory of Ethernet MAC @@ -321,115 +318,6 @@ struct esp_eth_mac_s { esp_err_t (*del)(esp_eth_mac_t *mac); }; -/** - * @brief RMII Clock Mode Options - * - */ -typedef enum { - /** - * @brief Default values configured using Kconfig are going to be used when "Default" selected. - * - * @note May not be supported on all targets. - * - */ - EMAC_CLK_DEFAULT, - - /** - * @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected. - * - * @note MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock. - * - */ - EMAC_CLK_EXT_IN, - - /** - * @brief Output RMII Clock from internal (A/M)PLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected. - * - */ - EMAC_CLK_OUT -} emac_rmii_clock_mode_t; - -#if CONFIG_IDF_TARGET_ESP32 -/** - * @brief RMII Clock GPIO number Options for ESP32 - * - */ -typedef enum { - /** - * @brief MAC will get RMII clock from outside at this GPIO. - * - * @note ESP32 only supports GPIO0 to input the RMII clock. - * - */ - EMAC_CLK_IN_GPIO = 0, - - /** - * @brief Output RMII Clock from internal APLL Clock available at GPIO0 - * - * @note GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock. - * In fact this clock doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t work well with your PHY chip. - * You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice. - * If you want the Ethernet to work with WiFi, don’t select GPIO0 output mode for stability. - * - */ - EMAC_APPL_CLK_OUT_GPIO = 0, - - /** - * @brief Output RMII Clock from internal APLL Clock available at GPIO16 - * - */ - EMAC_CLK_OUT_GPIO = 16, - - /** - * @brief Inverted Output RMII Clock from internal APLL Clock available at GPIO17 - * - */ - EMAC_CLK_OUT_180_GPIO = 17 -} emac_rmii_clock_gpio_t; -#else -/** - * @brief RMII Clock GPIO number - * - */ -typedef int emac_rmii_clock_gpio_t; -#endif // CONFIG_IDF_TARGET_ESP32 - -/** - * @brief Ethernet MAC Clock Configuration - * - */ -typedef union { - struct { - // MII interface is not fully implemented... - // Reserved for GPIO number, clock source, etc. in MII mode - } mii; /*!< EMAC MII Clock Configuration */ - struct { - emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */ - emac_rmii_clock_gpio_t clock_gpio; /*!< RMII Clock GPIO Configuration */ - } rmii; /*!< EMAC RMII Clock Configuration */ -} eth_mac_clock_config_t; - -#if SOC_EMAC_USE_IO_MUX -/** - * @brief Ethernet MAC MII/RMII data plane GPIO configuration - * - */ -typedef union { - struct { - // MII interface is not fully implemented... - // Reserved for data interface GPIO numbers in MII mode - } mii; /*!< EMAC MII Data GPIO Configuration */ - struct { - int32_t tx_en_num; /*!< TX_EN GPIO number */ - int32_t txd0_num; /*!< TXD0 GPIO number */ - int32_t txd1_num; /*!< TXD1 GPIO number */ - int32_t crs_dv_num; /*!< CRS_DV GPIO number */ - int32_t rxd0_num; /*!< RXD0 GPIO number */ - int32_t rxd1_num; /*!< RXD1 GPIO number */ - } rmii; /*!< EMAC RMII Data GPIO Configuration */ -} eth_mac_dataif_gpio_config_t; -#endif // SOC_EMAC_USE_IO_MUX - /** * @brief Configuration of Ethernet MAC object * @@ -456,327 +344,6 @@ typedef struct { .flags = 0, \ } -#if CONFIG_ETH_USE_ESP32_EMAC -/** -* @brief EMAC specific configuration -* -*/ -typedef struct { - int smi_mdc_gpio_num; /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */ - int smi_mdio_gpio_num; /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */ - eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */ - eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */ - eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */ - int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */ -#if SOC_EMAC_USE_IO_MUX - eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */ -#endif // SOC_EMAC_USE_IO_MUX -#if !SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK - eth_mac_clock_config_t clock_config_out_in; /*!< EMAC input clock configuration for internally generated output clock (when output clock is looped back externally) */ -#endif //SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK -} eth_esp32_emac_config_t; - -/** - * @brief Default ESP32's EMAC specific configuration - * - */ -#if CONFIG_IDF_TARGET_ESP32 -#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ - { \ - .smi_mdc_gpio_num = 23, \ - .smi_mdio_gpio_num = 18, \ - .interface = EMAC_DATA_INTERFACE_RMII, \ - .clock_config = \ - { \ - .rmii = \ - { \ - .clock_mode = EMAC_CLK_DEFAULT, \ - .clock_gpio = EMAC_CLK_IN_GPIO \ - } \ - }, \ - .dma_burst_len = ETH_DMA_BURST_LEN_32, \ - .intr_priority = 0, \ - } -#elif CONFIG_IDF_TARGET_ESP32P4 -#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ - { \ - .smi_mdc_gpio_num = 31, \ - .smi_mdio_gpio_num = 27, \ - .interface = EMAC_DATA_INTERFACE_RMII, \ - .clock_config = \ - { \ - .rmii = \ - { \ - .clock_mode = EMAC_CLK_EXT_IN, \ - .clock_gpio = 50 \ - } \ - }, \ - .clock_config_out_in = \ - { \ - .rmii = \ - { \ - .clock_mode = EMAC_CLK_DEFAULT, \ - .clock_gpio = -1 \ - } \ - }, \ - .dma_burst_len = ETH_DMA_BURST_LEN_32, \ - .intr_priority = 0, \ - .emac_dataif_gpio = \ - { \ - .rmii = \ - { \ - .tx_en_num = 49, \ - .txd0_num = 34, \ - .txd1_num = 35, \ - .crs_dv_num = 28, \ - .rxd0_num = 29, \ - .rxd1_num = 30 \ - } \ - }, \ - } -#endif // CONFIG_IDF_TARGET_ESP32P4 - - -/** -* @brief Create ESP32 Ethernet MAC instance -* -* @param esp32_config: EMAC specific configuration -* @param config: Ethernet MAC configuration -* -* @return -* - instance: create MAC instance successfully -* - NULL: create MAC instance failed because some error occurred -*/ -esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config); -#endif // CONFIG_ETH_USE_ESP32_EMAC - -#if CONFIG_ETH_USE_SPI_ETHERNET -/** - * @brief Custom SPI Driver Configuration. - * This structure declares configuration and callback functions to access Ethernet SPI module via - * user's custom SPI driver. - * - */ -typedef struct -{ - /** - * @brief Custom driver specific configuration data used by `init()` function. - * - * @note Type and its content is fully under user's control - * - */ - void *config; - - /** - * @brief Custom driver SPI Initialization - * - * @param[in] spi_config: Custom driver specific configuration - * - * @return - * - spi_ctx: when initialization is successful, a pointer to context structure holding all variables - * needed for subsequent SPI access operations (e.g. SPI bus identification, mutexes, etc.) - * - NULL: driver initialization failed - * - * @note return type and its content is fully under user's control - */ - void *(*init)(const void *spi_config); - - /** - * @brief Custom driver De-initialization - * - * @param[in] spi_ctx: a pointer to driver specific context structure - * - * @return - * - ESP_OK: driver de-initialization was successful - * - ESP_FAIL: driver de-initialization failed - * - any other failure codes are allowed to be used to provide failure isolation - */ - esp_err_t (*deinit)(void *spi_ctx); - - /** - * @brief Custom driver SPI read - * - * @note The read function is responsible to construct command, address and data fields - * of the SPI frame in format expected by particular SPI Ethernet module - * - * @param[in] spi_ctx: a pointer to driver specific context structure - * @param[in] cmd: command - * @param[in] addr: register address - * @param[out] data: read data - * @param[in] data_len: read data length in bytes - * - * @return - * - ESP_OK: read was successful - * - ESP_FAIL: read failed - * - any other failure codes are allowed to be used to provide failure isolation - */ - esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); - - /** - * @brief Custom driver SPI write - * - * @note The write function is responsible to construct command, address and data fields - * of the SPI frame in format expected by particular SPI Ethernet module - * - * @param[in] spi_ctx: a pointer to driver specific context structure - * @param[in] cmd: command - * @param[in] addr: register address - * @param[in] data: data to write - * @param[in] data_len: length of data to write in bytes - * - * @return - * - ESP_OK: write was successful - * - ESP_FAIL: write failed - * - any other failure codes are allowed to be used to provide failure isolation - */ - esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); -} eth_spi_custom_driver_config_t; - -/** - * @brief Default configuration of the custom SPI driver. - * Internal ESP-IDF SPI Master driver is used by default. - * - */ -#define ETH_DEFAULT_SPI \ - { \ - .config = NULL, \ - .init = NULL, \ - .deinit = NULL, \ - .read = NULL, \ - .write = NULL \ - } -#endif // CONFIG_ETH_USE_SPI_ETHERNET - -#if CONFIG_ETH_SPI_ETHERNET_DM9051 -/** - * @brief DM9051 specific configuration - * - */ -typedef struct { - int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ - uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ - spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ - spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ - eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ -} eth_dm9051_config_t; - -/** - * @brief Default DM9051 specific configuration - * - */ -#define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ - { \ - .int_gpio_num = 4, \ - .poll_period_ms = 0, \ - .spi_host_id = spi_host, \ - .spi_devcfg = spi_devcfg_p, \ - .custom_spi_driver = ETH_DEFAULT_SPI, \ - } - -/** -* @brief Create DM9051 Ethernet MAC instance -* -* @param dm9051_config: DM9051 specific configuration -* @param mac_config: Ethernet MAC configuration -* -* @return -* - instance: create MAC instance successfully -* - NULL: create MAC instance failed because some error occurred -*/ -esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config); -#endif // CONFIG_ETH_SPI_ETHERNET_DM9051 - -#if CONFIG_ETH_SPI_ETHERNET_W5500 -/** - * @brief W5500 specific configuration - * - */ -typedef struct { - int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ - uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ - spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/ - spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/ - eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ -} eth_w5500_config_t; - -/** - * @brief Default W5500 specific configuration - * - */ -#define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ - { \ - .int_gpio_num = 4, \ - .poll_period_ms = 0, \ - .spi_host_id = spi_host, \ - .spi_devcfg = spi_devcfg_p, \ - .custom_spi_driver = ETH_DEFAULT_SPI, \ - } - -/** -* @brief Create W5500 Ethernet MAC instance -* -* @param w5500_config: W5500 specific configuration -* @param mac_config: Ethernet MAC configuration -* -* @return -* - instance: create MAC instance successfully -* - NULL: create MAC instance failed because some error occurred -*/ -esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config); -#endif // CONFIG_ETH_SPI_ETHERNET_W5500 - -#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL -/** - * @brief KSZ8851SNL specific configuration - * - */ -typedef struct { - int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ - uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ - spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ - spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ - eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ -} eth_ksz8851snl_config_t; - -/** - * @brief Default KSZ8851SNL specific configuration - * - */ -#define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ - { \ - .int_gpio_num = 4, \ - .poll_period_ms = 0, \ - .spi_host_id = spi_host, \ - .spi_devcfg = spi_devcfg_p, \ - .custom_spi_driver = ETH_DEFAULT_SPI, \ - } - -/** -* @brief Create KSZ8851SNL Ethernet MAC instance -* -* @param ksz8851snl_config: KSZ8851SNL specific configuration -* @param mac_config: Ethernet MAC configuration -* -* @return -* - instance: create MAC instance successfully -* - NULL: create MAC instance failed because some error occurred -*/ -esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config); -#endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851 - -#if CONFIG_ETH_USE_OPENETH -/** -* @brief Create OpenCores Ethernet MAC instance -* -* @param config: Ethernet MAC configuration -* -* @return -* - instance: create MAC instance successfully -* - NULL: create MAC instance failed because some error occurred -*/ -esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config); -#endif // CONFIG_ETH_USE_OPENETH - #ifdef __cplusplus } #endif diff --git a/components/esp_eth/include/esp_eth_mac_esp.h b/components/esp_eth/include/esp_eth_mac_esp.h new file mode 100644 index 00000000000..8c4909b8c55 --- /dev/null +++ b/components/esp_eth/include/esp_eth_mac_esp.h @@ -0,0 +1,296 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/soc_caps.h" +#include "esp_eth_com.h" +#include "esp_eth_mac.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_ETH_USE_ESP32_EMAC + +/** + * @brief RMII Clock Mode Options + * + */ +typedef enum { + /** + * @brief Default values configured using Kconfig are going to be used when "Default" selected. + * + * @warning Deprecated option. Clock configuration using Kconfig is limitedly supported only for ESP32 SoC via @c ETH_ESP32_EMAC_DEFAULT_CONFIG + * and is going to be reevaluated in the next major release. + * Clock mode and clock GPIO number is supposed to be defined in `EMAC specific configuration` structure from user's code. + * + */ + EMAC_CLK_DEFAULT __attribute__((deprecated)), // IDF-9724 + + /** + * @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected. + * + * @note MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock. + * + */ + EMAC_CLK_EXT_IN, + + /** + * @brief Output RMII Clock from internal (A/M)PLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected. + * + */ + EMAC_CLK_OUT +} emac_rmii_clock_mode_t; + +#if CONFIG_IDF_TARGET_ESP32 +/** + * @brief RMII Clock GPIO number Options for ESP32 + * + */ +typedef enum { + /** + * @brief MAC will get RMII clock from outside at this GPIO. + * + * @note ESP32 only supports GPIO0 to input the RMII clock. + * + */ + EMAC_CLK_IN_GPIO = 0, + + /** + * @brief Output RMII Clock from internal APLL Clock available at GPIO0 + * + * @note GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock. + * In fact this clock doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t work well with your PHY chip. + * You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice. + * If you want the Ethernet to work with WiFi, don’t select GPIO0 output mode for stability. + * + */ + EMAC_APPL_CLK_OUT_GPIO = 0, + + /** + * @brief Output RMII Clock from internal APLL Clock available at GPIO16 + * + */ + EMAC_CLK_OUT_GPIO = 16, + + /** + * @brief Inverted Output RMII Clock from internal APLL Clock available at GPIO17 + * + */ + EMAC_CLK_OUT_180_GPIO = 17 +} emac_rmii_clock_gpio_t; +#else +/** + * @brief RMII Clock GPIO number + * + */ +typedef int emac_rmii_clock_gpio_t; +#endif // CONFIG_IDF_TARGET_ESP32 + +/** + * @brief Ethernet MAC Clock Configuration + * + */ +typedef union { + struct { + // MII interface is not fully implemented... + // Reserved for GPIO number, clock source, etc. in MII mode + } mii; /*!< EMAC MII Clock Configuration */ + struct { + emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */ + emac_rmii_clock_gpio_t clock_gpio; /*!< RMII Clock GPIO Configuration */ + } rmii; /*!< EMAC RMII Clock Configuration */ +} eth_mac_clock_config_t; + +/** + * @brief EMAC SMI GPIO configuration + */ +typedef struct { + int mdc_num; /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */ + int mdio_num; /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */ +} emac_esp_smi_gpio_config_t; + +/** + * @brief EMAC MII data interface GPIO configuration + */ +typedef struct { + int tx_clk_num; /*!< TX_CLK GPIO number */ + int tx_en_num; /*!< TX_EN GPIO number */ + int txd0_num; /*!< TXD0 GPIO number */ + int txd1_num; /*!< TXD1 GPIO number */ + int txd2_num; /*!< TXD2 GPIO number */ + int txd3_num; /*!< TXD3 GPIO number */ + int rx_clk_num; /*!< RX_CLK GPIO number */ + int rx_dv_num; /*!< RX_DV GPIO number */ + int rxd0_num; /*!< RXD0 GPIO number */ + int rxd1_num; /*!< RXD1 GPIO number */ + int rxd2_num; /*!< RXD2 GPIO number */ + int rxd3_num; /*!< RXD3 GPIO number */ + int col_in_num; /*!< COL_IN GPIO number */ + int crs_in_num; /*!< CRS_IN GPIO number */ + int tx_er_num; /*!< TX_ER GPIO number */ + int rx_er_num; /*!< RX_ER GPIO number */ +} eth_mac_mii_gpio_config_t; + +/** + * @brief EMAC RMII data interface GPIO configuration + */ +typedef struct { + int tx_en_num; /*!< TX_EN GPIO number */ + int txd0_num; /*!< TXD0 GPIO number */ + int txd1_num; /*!< TXD1 GPIO number */ + int crs_dv_num; /*!< CRS_DV GPIO number */ + int rxd0_num; /*!< RXD0 GPIO number */ + int rxd1_num; /*!< RXD1 GPIO number */ +} eth_mac_rmii_gpio_config_t; + +#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX +/** + * @brief Ethernet MAC MII/RMII data plane GPIO configuration + * + */ +typedef union { + eth_mac_mii_gpio_config_t mii; /*!< EMAC MII Data GPIO Configuration */ + eth_mac_rmii_gpio_config_t rmii; /*!< EMAC RMII Data GPIO Configuration */ +} eth_mac_dataif_gpio_config_t; +#endif // SOC_EMAC_USE_MULTI_IO_MUX + +/** +* @brief EMAC specific configuration +* +*/ +typedef struct { + union { + emac_esp_smi_gpio_config_t smi_gpio; /*!< SMI GPIO numbers */ + struct { + int smi_mdc_gpio_num __attribute__((deprecated("Please use smi_gpio instead"))); /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */ + int smi_mdio_gpio_num __attribute__((deprecated("Please use smi_gpio instead"))); /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */ + }; + }; + eth_data_interface_t interface; /*!< EMAC Data interface to PHY (MII/RMII) */ + eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */ + eth_mac_dma_burst_len_t dma_burst_len; /*!< EMAC DMA burst length for both Tx and Rx */ + int intr_priority; /*!< EMAC interrupt priority, if set to 0 or a negative value, the driver will try to allocate an interrupt with a default priority */ +#if SOC_EMAC_USE_MULTI_IO_MUX || SOC_EMAC_MII_USE_GPIO_MATRIX + eth_mac_dataif_gpio_config_t emac_dataif_gpio; /*!< EMAC MII/RMII data plane GPIO configuration */ +#endif // SOC_EMAC_USE_MULTI_IO_MUX +#if !SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK + eth_mac_clock_config_t clock_config_out_in; /*!< EMAC input clock configuration for internally generated output clock (when output clock is looped back externally) */ +#endif //SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK +} eth_esp32_emac_config_t; + +/** + * @brief List of ESP EMAC specific commands for ioctl API + * + */ +typedef enum { + ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS = ETH_CMD_CUSTOM_MAC_CMDS_OFFSET, /*!< Set Transmit Descriptor Word 0 control bit mask (debug option)*/ + ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, /*!< Clear Transmit Descriptor Word 0 control bit mask (debug option)*/ + ETH_MAC_ESP_CMD_PTP_ENABLE, /*!< Enable IEEE1588 Time stamping */ +} eth_mac_esp_io_cmd_t; + +/** + * @brief Default ESP32's EMAC specific configuration + * + */ +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ETH_RMII_CLK_INPUT // IDF-9724 + #define DEFAULT_RMII_CLK_MODE EMAC_CLK_EXT_IN +#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0 + #define DEFAULT_RMII_CLK_GPIO CONFIG_ETH_RMII_CLK_IN_GPIO +#else + #error "ESP32 EMAC only support input RMII clock to GPIO0" +#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0 +#elif CONFIG_ETH_RMII_CLK_OUTPUT + #define DEFAULT_RMII_CLK_MODE EMAC_CLK_OUT +#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 + #define DEFAULT_RMII_CLK_GPIO EMAC_APPL_CLK_OUT_GPIO +#else + #define DEFAULT_RMII_CLK_GPIO CONFIG_ETH_RMII_CLK_OUT_GPIO +#endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 +#else +#error "Unsupported RMII clock mode" +#endif // CONFIG_ETH_RMII_CLK_INPUT + +#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ + { \ + .smi_gpio = \ + { \ + .mdc_num = 23, \ + .mdio_num = 18 \ + }, \ + .interface = EMAC_DATA_INTERFACE_RMII, \ + .clock_config = \ + { \ + .rmii = \ + { \ + .clock_mode = DEFAULT_RMII_CLK_MODE, \ + .clock_gpio = DEFAULT_RMII_CLK_GPIO \ + } \ + }, \ + .dma_burst_len = ETH_DMA_BURST_LEN_32, \ + .intr_priority = 0, \ + } +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ETH_ESP32_EMAC_DEFAULT_CONFIG() \ + { \ + .smi_gpio = \ + { \ + .mdc_num = 31, \ + .mdio_num = 27 \ + }, \ + .interface = EMAC_DATA_INTERFACE_RMII, \ + .clock_config = \ + { \ + .rmii = \ + { \ + .clock_mode = EMAC_CLK_EXT_IN, \ + .clock_gpio = 50 \ + } \ + }, \ + .clock_config_out_in = \ + { \ + .rmii = \ + { \ + .clock_mode = EMAC_CLK_EXT_IN, \ + .clock_gpio = -1 \ + } \ + }, \ + .dma_burst_len = ETH_DMA_BURST_LEN_32, \ + .intr_priority = 0, \ + .emac_dataif_gpio = \ + { \ + .rmii = \ + { \ + .tx_en_num = 49, \ + .txd0_num = 34, \ + .txd1_num = 35, \ + .crs_dv_num = 28, \ + .rxd0_num = 29, \ + .rxd1_num = 30 \ + } \ + }, \ + } +#endif // CONFIG_IDF_TARGET_ESP32P4 + +/** +* @brief Create ESP32 Ethernet MAC instance +* +* @param esp32_config: EMAC specific configuration +* @param config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config, const eth_mac_config_t *config); +#endif // CONFIG_ETH_USE_ESP32_EMAC + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_mac_openeth.h b/components/esp_eth/include/esp_eth_mac_openeth.h new file mode 100644 index 00000000000..a118a96139a --- /dev/null +++ b/components/esp_eth/include/esp_eth_mac_openeth.h @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "esp_eth_com.h" +#include "esp_eth_mac.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_ETH_USE_OPENETH +/** +* @brief Create OpenCores Ethernet MAC instance +* +* @param config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config); +#endif // CONFIG_ETH_USE_OPENETH + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_mac_spi.h b/components/esp_eth/include/esp_eth_mac_spi.h new file mode 100644 index 00000000000..74f246df724 --- /dev/null +++ b/components/esp_eth/include/esp_eth_mac_spi.h @@ -0,0 +1,236 @@ +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "soc/soc_caps.h" +#include "esp_eth_com.h" +#include "esp_eth_mac.h" +#include "sdkconfig.h" +#include "driver/spi_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_ETH_USE_SPI_ETHERNET + +/** + * @brief Custom SPI Driver Configuration. + * This structure declares configuration and callback functions to access Ethernet SPI module via + * user's custom SPI driver. + * + */ +typedef struct +{ + /** + * @brief Custom driver specific configuration data used by `init()` function. + * + * @note Type and its content is fully under user's control + * + */ + void *config; + + /** + * @brief Custom driver SPI Initialization + * + * @param[in] spi_config: Custom driver specific configuration + * + * @return + * - spi_ctx: when initialization is successful, a pointer to context structure holding all variables + * needed for subsequent SPI access operations (e.g. SPI bus identification, mutexes, etc.) + * - NULL: driver initialization failed + * + * @note return type and its content is fully under user's control + */ + void *(*init)(const void *spi_config); + + /** + * @brief Custom driver De-initialization + * + * @param[in] spi_ctx: a pointer to driver specific context structure + * + * @return + * - ESP_OK: driver de-initialization was successful + * - ESP_FAIL: driver de-initialization failed + * - any other failure codes are allowed to be used to provide failure isolation + */ + esp_err_t (*deinit)(void *spi_ctx); + + /** + * @brief Custom driver SPI read + * + * @note The read function is responsible to construct command, address and data fields + * of the SPI frame in format expected by particular SPI Ethernet module + * + * @param[in] spi_ctx: a pointer to driver specific context structure + * @param[in] cmd: command + * @param[in] addr: register address + * @param[out] data: read data + * @param[in] data_len: read data length in bytes + * + * @return + * - ESP_OK: read was successful + * - ESP_FAIL: read failed + * - any other failure codes are allowed to be used to provide failure isolation + */ + esp_err_t (*read)(void *spi_ctx, uint32_t cmd, uint32_t addr, void *data, uint32_t data_len); + + /** + * @brief Custom driver SPI write + * + * @note The write function is responsible to construct command, address and data fields + * of the SPI frame in format expected by particular SPI Ethernet module + * + * @param[in] spi_ctx: a pointer to driver specific context structure + * @param[in] cmd: command + * @param[in] addr: register address + * @param[in] data: data to write + * @param[in] data_len: length of data to write in bytes + * + * @return + * - ESP_OK: write was successful + * - ESP_FAIL: write failed + * - any other failure codes are allowed to be used to provide failure isolation + */ + esp_err_t (*write)(void *spi_ctx, uint32_t cmd, uint32_t addr, const void *data, uint32_t data_len); +} eth_spi_custom_driver_config_t; + +/** + * @brief Default configuration of the custom SPI driver. + * Internal ESP-IDF SPI Master driver is used by default. + * + */ +#define ETH_DEFAULT_SPI \ + { \ + .config = NULL, \ + .init = NULL, \ + .deinit = NULL, \ + .read = NULL, \ + .write = NULL \ + } +#endif // CONFIG_ETH_USE_SPI_ETHERNET + +#if CONFIG_ETH_SPI_ETHERNET_DM9051 +/** + * @brief DM9051 specific configuration + * + */ +typedef struct { + int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ + uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ + spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ + spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ + eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ +} eth_dm9051_config_t; + +/** + * @brief Default DM9051 specific configuration + * + */ +#define ETH_DM9051_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ + { \ + .int_gpio_num = 4, \ + .poll_period_ms = 0, \ + .spi_host_id = spi_host, \ + .spi_devcfg = spi_devcfg_p, \ + .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + +/** +* @brief Create DM9051 Ethernet MAC instance +* +* @param dm9051_config: DM9051 specific configuration +* @param mac_config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config); +#endif // CONFIG_ETH_SPI_ETHERNET_DM9051 + +#if CONFIG_ETH_SPI_ETHERNET_W5500 +/** + * @brief W5500 specific configuration + * + */ +typedef struct { + int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ + uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ + spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined)*/ + spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined)*/ + eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ +} eth_w5500_config_t; + +/** + * @brief Default W5500 specific configuration + * + */ +#define ETH_W5500_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ + { \ + .int_gpio_num = 4, \ + .poll_period_ms = 0, \ + .spi_host_id = spi_host, \ + .spi_devcfg = spi_devcfg_p, \ + .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + +/** +* @brief Create W5500 Ethernet MAC instance +* +* @param w5500_config: W5500 specific configuration +* @param mac_config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config); +#endif // CONFIG_ETH_SPI_ETHERNET_W5500 + +#if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL +/** + * @brief KSZ8851SNL specific configuration + * + */ +typedef struct { + int int_gpio_num; /*!< Interrupt GPIO number, set -1 to not use interrupt and to poll rx status periodically */ + uint32_t poll_period_ms; /*!< Period in ms to poll rx status when interrupt mode is not used */ + spi_host_device_t spi_host_id; /*!< SPI peripheral (this field is invalid when custom SPI driver is defined) */ + spi_device_interface_config_t *spi_devcfg; /*!< SPI device configuration (this field is invalid when custom SPI driver is defined) */ + eth_spi_custom_driver_config_t custom_spi_driver; /*!< Custom SPI driver definitions */ +} eth_ksz8851snl_config_t; + +/** + * @brief Default KSZ8851SNL specific configuration + * + */ +#define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_host, spi_devcfg_p) \ + { \ + .int_gpio_num = 4, \ + .poll_period_ms = 0, \ + .spi_host_id = spi_host, \ + .spi_devcfg = spi_devcfg_p, \ + .custom_spi_driver = ETH_DEFAULT_SPI, \ + } + +/** +* @brief Create KSZ8851SNL Ethernet MAC instance +* +* @param ksz8851snl_config: KSZ8851SNL specific configuration +* @param mac_config: Ethernet MAC configuration +* +* @return +* - instance: create MAC instance successfully +* - NULL: create MAC instance failed because some error occurred +*/ +esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config); +#endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851 + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_eth/include/esp_eth_phy.h b/components/esp_eth/include/esp_eth_phy.h index 07bcf8fb930..82c16aef41d 100644 --- a/components/esp_eth/include/esp_eth_phy.h +++ b/components/esp_eth/include/esp_eth_phy.h @@ -16,7 +16,7 @@ extern "C" { #define ESP_ETH_PHY_ADDR_AUTO (-1) /** - * @brief Auto-negotiation controll commands + * @brief Auto-negotiation control commands * */ typedef enum { @@ -253,7 +253,7 @@ struct esp_eth_phy_s { * - ESP_FAIL: process io command failed because some other error occurred * - ESP_ERR_NOT_SUPPORTED: requested feature is not supported */ - esp_err_t (*custom_ioctl)(esp_eth_phy_t *phy, uint32_t cmd, void *data); + esp_err_t (*custom_ioctl)(esp_eth_phy_t *phy, int cmd, void *data); /** * @brief Free memory of Ethernet PHY instance diff --git a/components/esp_eth/include/esp_eth_phy_802_3.h b/components/esp_eth/include/esp_eth_phy_802_3.h index 4d1b022f797..0cc83ed1390 100644 --- a/components/esp_eth/include/esp_eth_phy_802_3.h +++ b/components/esp_eth/include/esp_eth_phy_802_3.h @@ -6,7 +6,7 @@ #pragma once #include -#include "esp_eth.h" +#include "esp_eth_phy.h" #include "sdkconfig.h" #include "eth_phy_802_3_regs.h" @@ -45,7 +45,7 @@ typedef enum { * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param eth Ethernet mediator pointer * @return - * - ESP_OK: Ethermet mediator set successfuly + * - ESP_OK: Ethermet mediator set successfully * - ESP_ERR_INVALID_ARG: if @c eth is @c NULL */ esp_err_t esp_eth_phy_802_3_set_mediator(phy_802_3_t *phy_802_3, esp_eth_mediator_t *eth); @@ -55,8 +55,8 @@ esp_err_t esp_eth_phy_802_3_set_mediator(phy_802_3_t *phy_802_3, esp_eth_mediato * * @param phy_802_3 IEEE 802.3 PHY object infostructure * @return - * - ESP_OK: Ethernet PHY reset successfuly - * - ESP_FAIL: reset Ethernet PHY failed because some error occured + * - ESP_OK: Ethernet PHY reset successfully + * - ESP_FAIL: reset Ethernet PHY failed because some error occurred */ esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3); @@ -67,8 +67,8 @@ esp_err_t esp_eth_phy_802_3_reset(phy_802_3_t *phy_802_3); * @param cmd autonegotiation command enumeration * @param[out] autonego_en_stat autonegotiation enabled flag * @return - * - ESP_OK: Ethernet PHY autonegotiation configured successfuly - * - ESP_FAIL: Ethernet PHY autonegotiation configuration fail because some error occured + * - ESP_OK: Ethernet PHY autonegotiation configured successfully + * - ESP_FAIL: Ethernet PHY autonegotiation configuration fail because some error occurred * - ESP_ERR_INVALID_ARG: invalid value of @c cmd */ esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat); @@ -79,8 +79,8 @@ esp_err_t esp_eth_phy_802_3_autonego_ctrl(phy_802_3_t *phy_802_3, eth_phy_autone * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param enable set true to power ON Ethernet PHY; set false to power OFF Ethernet PHY * @return - * - ESP_OK: Ethernet PHY power down mode set successfuly - * - ESP_FAIL: Ethernet PHY power up or power down failed because some error occured + * - ESP_OK: Ethernet PHY power down mode set successfully + * - ESP_FAIL: Ethernet PHY power up or power down failed because some error occurred */ esp_err_t esp_eth_phy_802_3_pwrctl(phy_802_3_t *phy_802_3, bool enable); @@ -100,7 +100,7 @@ esp_err_t esp_eth_phy_802_3_set_addr(phy_802_3_t *phy_802_3, uint32_t addr); * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param[out] addr Ethernet PHY address * @return - * - ESP_OK: Ethernet PHY address read successfuly + * - ESP_OK: Ethernet PHY address read successfully * - ESP_ERR_INVALID_ARG: @c addr pointer is @c NULL */ esp_err_t esp_eth_phy_802_3_get_addr(phy_802_3_t *phy_802_3, uint32_t *addr); @@ -111,8 +111,8 @@ esp_err_t esp_eth_phy_802_3_get_addr(phy_802_3_t *phy_802_3, uint32_t *addr); * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param ability enable or disable pause ability * @return - * - ESP_OK: pause ability set successfuly - * - ESP_FAIL: Advertise pause function ability failed because some error occured + * - ESP_OK: pause ability set successfully + * - ESP_FAIL: Advertise pause function ability failed because some error occurred */ esp_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint32_t ability); @@ -122,8 +122,8 @@ esp_err_t esp_eth_phy_802_3_advertise_pause_ability(phy_802_3_t *phy_802_3, uint * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param enable set true to enable loopback; set false to disable loopback * @return - * - ESP_OK: Ethernet PHY loopback mode set successfuly - * - ESP_FAIL: Ethernet PHY loopback configuration failed because some error occured + * - ESP_OK: Ethernet PHY loopback mode set successfully + * - ESP_FAIL: Ethernet PHY loopback configuration failed because some error occurred */ esp_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable); @@ -133,8 +133,8 @@ esp_err_t esp_eth_phy_802_3_loopback(phy_802_3_t *phy_802_3, bool enable); * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param speed new speed of Ethernet PHY link * @return - * - ESP_OK: Ethernet PHY speed set successfuly - * - ESP_FAIL: Set Ethernet PHY speed failed because some error occured + * - ESP_OK: Ethernet PHY speed set successfully + * - ESP_FAIL: Set Ethernet PHY speed failed because some error occurred */ esp_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed); @@ -144,9 +144,9 @@ esp_err_t esp_eth_phy_802_3_set_speed(phy_802_3_t *phy_802_3, eth_speed_t speed) * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param duplex new duplex mode for Ethernet PHY link * @return - * - ESP_OK: Ethernet PHY duplex mode set successfuly + * - ESP_OK: Ethernet PHY duplex mode set successfully * - ESP_ERR_INVALID_STATE: unable to set duplex mode to Half if loopback is enabled - * - ESP_FAIL: Set Ethernet PHY duplex mode failed because some error occured + * - ESP_FAIL: Set Ethernet PHY duplex mode failed because some error occurred */ esp_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t duplex); @@ -156,7 +156,7 @@ esp_err_t esp_eth_phy_802_3_set_duplex(phy_802_3_t *phy_802_3, eth_duplex_t dupl * @param phy_802_3 IEEE 802.3 PHY object infostructure * @param link new link status * @return - * - ESP_OK: Ethernet PHY link set successfuly + * - ESP_OK: Ethernet PHY link set successfully */ esp_err_t esp_eth_phy_802_3_set_link(phy_802_3_t *phy_802_3, eth_link_t link); @@ -165,7 +165,7 @@ esp_err_t esp_eth_phy_802_3_set_link(phy_802_3_t *phy_802_3, eth_link_t link); * * @param phy_802_3 IEEE 802.3 PHY object infostructure * @return - * - ESP_OK: Ethernet PHY initialized successfuly + * - ESP_OK: Ethernet PHY initialized successfully */ esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3); @@ -174,7 +174,7 @@ esp_err_t esp_eth_phy_802_3_init(phy_802_3_t *phy_802_3); * * @param phy_802_3 IEEE 802.3 PHY object infostructure * @return - * - ESP_OK: Ethernet PHY powered off successfuly + * - ESP_OK: Ethernet PHY powered off successfully */ esp_err_t esp_eth_phy_802_3_deinit(phy_802_3_t *phy_802_3); @@ -275,8 +275,8 @@ esp_err_t esp_eth_phy_802_3_read_manufac_info(phy_802_3_t *phy_802_3, uint8_t *m * @param devaddr Address of MDIO device * @param[out] mmd_addr Current address stored in device's register * @return - * - ESP_OK: Address register read successfuly - * - ESP_FAIL: Address register read failed because of some error occured + * - ESP_OK: Address register read successfully + * - ESP_FAIL: Address register read failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) */ esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t *mmd_addr); @@ -288,8 +288,8 @@ esp_err_t esp_eth_phy_802_3_get_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr * @param devaddr Address of MDIO device * @param[out] mmd_addr New value of MDIO device's address register value * @return - * - ESP_OK: Address register written to successfuly - * - ESP_FAIL: Address register write failed because of some error occured + * - ESP_OK: Address register written to successfully + * - ESP_FAIL: Address register write failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) */ esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr); @@ -302,8 +302,8 @@ esp_err_t esp_eth_phy_802_3_set_mmd_addr(phy_802_3_t *phy_802_3, uint8_t devaddr * @param function MMD function * @param[out] data Data read from the device's memory * @return - * - ESP_OK: Memory read successfuly - * - ESP_FAIL: Memory read failed because of some error occured + * - ESP_OK: Memory read successfully + * - ESP_FAIL: Memory read failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid */ esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t *data); @@ -316,8 +316,8 @@ esp_err_t esp_eth_phy_802_3_read_mmd_data(phy_802_3_t *phy_802_3, uint8_t devadd * @param function MMD function * @param[out] data Data to write to the device's memory * @return - * - ESP_OK: Memory written successfuly - * - ESP_FAIL: Memory write failed because of some error occured + * - ESP_OK: Memory written successfully + * - ESP_FAIL: Memory write failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) or MMD access function is invalid */ esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devaddr, esp_eth_phy_802_3_mmd_func_t function, uint32_t data); @@ -330,8 +330,8 @@ esp_err_t esp_eth_phy_802_3_write_mmd_data(phy_802_3_t *phy_802_3, uint8_t devad * @param mmd_addr Address of MDIO device register * @param[out] data Data read from the device's memory * @return - * - ESP_OK: Memory read successfuly - * - ESP_FAIL: Memory read failed because of some error occured + * - ESP_OK: Memory read successfully + * - ESP_FAIL: Memory read failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) */ esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t *data); @@ -344,8 +344,8 @@ esp_err_t esp_eth_phy_802_3_read_mmd_register(phy_802_3_t *phy_802_3, uint8_t de * @param mmd_addr Address of MDIO device register * @param[out] data Data to write to the device's memory * @return - * - ESP_OK: Memory written to successfuly - * - ESP_FAIL: Memory write failed because of some error occured + * - ESP_OK: Memory written to successfully + * - ESP_FAIL: Memory write failed because of some error occurred * - ESP_ERR_INVALID_ARG: Device address provided is out of range (hardware limits device address to 5 bits) */ esp_err_t esp_eth_phy_802_3_write_mmd_register(phy_802_3_t *phy_802_3, uint8_t devaddr, uint16_t mmd_addr, uint32_t data); diff --git a/components/esp_eth/include/esp_private/eth_mac_esp_dma.h b/components/esp_eth/include/esp_private/eth_mac_esp_dma.h index 9d363c4ebf8..3fc496534cc 100644 --- a/components/esp_eth/include/esp_private/eth_mac_esp_dma.h +++ b/components/esp_eth/include/esp_private/eth_mac_esp_dma.h @@ -15,20 +15,144 @@ extern "C" { * @brief Indicate to ::emac_esp_dma_receive_frame that receive frame buffer was allocated by ::emac_esp_dma_alloc_recv_buf * */ -#define EMAC_HAL_BUF_SIZE_AUTO 0 +#define EMAC_DMA_BUF_SIZE_AUTO 0 +/** + * @brief EMAC DMA handle + * + */ typedef struct emac_esp_dma_t *emac_esp_dma_handle_t; -typedef void *emac_esp_dma_config_t; -void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma); +/** + * @brief EMAC DMA configuration + * @note Currently just a placeholder + * + */ +typedef struct emac_esp_dma_config_t emac_esp_dma_config_t; + +/** + * @brief Reset DMA + * @note This function should be called prior each EMAC start + * + * @param[in] emac_esp_dma EMAC DMA handle + */ +void emac_esp_dma_reset(emac_esp_dma_handle_t emac_esp_dma); + +/** + * @brief Transmit data from buffer over EMAC + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in] buf buffer to be transmitted + * @param[in] length length of the buffer + * @return number of transmitted bytes on success + * zero on fail + */ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t length); + +/** + * @brief Transmit data from multiple buffers over EMAC in single Ethernet frame. Data will be joint into + * single frame in order in which the buffers are stored in input array. + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in] buffs array of pointers to buffers to be transmitted + * @param[in] lengths array of lengths of the buffers + * @param[in] inbuffs_cnt number of buffers (i.e. input arrays size) + * @return number of transmitted bytes on success + * zero on fail + * + * @pre @p lengths array must have the same size as @p buffs array and their elements need to be stored in the same + * order, i.e. lengths[1] is a length associated with data buffer referenced at buffs[1] position. + */ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t **buffs, uint32_t *lengths, uint32_t buffs_cnt); + +/** + * @brief Allocate buffer with size equal to actually received Ethernet frame size. + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in, out] size as an input defines maximum size of buffer to be allocated. As an output, indicates actual size of received + * Ethernet frame which is waiting to be processed. Returned size may be 0 when there is no waiting valid frame. + * + * @note If maximum allowed size of buffer to be allocated is less than actual size of received Ethernet frame, the buffer + * is allocated with that limit and the frame will be truncated by emac_hal_receive_frame. + * + * @return Pointer to allocated buffer + * NULL when allocation fails (returned @p size is non-zero) + * NULL when there is no waiting Ethernet frame (returned @p size is zero) + */ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_t *size); -uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc); -void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma, uint32_t *frames_remain, uint32_t *free_desc); +/** + * @brief Copy received Ethernet frame from EMAC DMA memory space to application. + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in] buf buffer into which the Ethernet frame is to be copied + * @param[in] size buffer size. When buffer was allocated by ::emac_esp_dma_alloc_recv_buf, this parameter needs to be set + * to @c EMAC_DMA_BUF_SIZE_AUTO + * + * @return - number of copied bytes when success + * - number of bytes of received Ethernet frame when maximum allowed buffer @p size is less than actual size of + * received Ethernet frame and @p size is NOT set to @c EMAC_DMA_BUF_SIZE_AUTO + * - 0 when there is no waiting Ethernet frame or on frame error when @p size is NOT set to @c EMAC_DMA_BUF_SIZE_AUTO + * + * @note When this function is called with @c EMAC_DMA_BUF_SIZE_AUTO size option (preferred), buffer needs to be + * successfully allocated by ::emac_esp_dma_alloc_recv_buf function at first. + * @note When this function is NOT called with @c EMAC_DMA_BUF_SIZE_AUTO size option and maximum allowed buffer @p size + * is less than actual size of received Ethernet frame, the frame will be truncated. + * @note FCS field is never copied + */ +uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size); + +/** + * @brief Flush frame stored in Rx DMA + * + * @param[in] emac_esp_dma EMAC DMA handle + */ +void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma); + +/** + * @brief Get number of frames remaining in Rx DMA + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[out] frames_remain number of frames remaining to be processed + * @param[out] free_desc number of free DMA Rx descriptors + */ +void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *used_descs); + +/** + * @brief Set the Transmit Descriptor Word 0 (TDES0) control bits + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in] bit_mask mask of control bits to be set + */ +void emac_esp_dma_set_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t bit_mask); + +/** + * @brief Clear the Transmit Descriptor Word 0 (TDES0) control bits + * + * @param[in] emac_esp_dma EMAC DMA handle + * @param[in] bit_mask mask of control bits to be cleared + */ +void emac_esp_dma_clear_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t bit_mask); + +/** + * @brief Creates a new instance of the ESP EMAC DMA + * + * @param config ESP EMAC DMA configuration + * @param[out] ret_handle EMAC DMA handle + * @return esp_err_t + * ESP_OK on success + * ESP_ERR_NO_MEM when there is not enough memory to allocate instance + */ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_handle_t *ret_handle); + +/** + * @brief Deletes the ESP EMAC DMA instance + * + * @param[in] emac_esp_dma EMAC DMA handle + * @return esp_err_t + * ESP_OK on success + */ esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma); #ifdef __cplusplus diff --git a/components/esp_eth/include/esp_private/eth_mac_esp_gpio.h b/components/esp_eth/include/esp_private/eth_mac_esp_gpio.h index d2c2736575b..6dbe9bd6efd 100644 --- a/components/esp_eth/include/esp_private/eth_mac_esp_gpio.h +++ b/components/esp_eth/include/esp_private/eth_mac_esp_gpio.h @@ -10,53 +10,23 @@ extern "C" { #endif #include "esp_err.h" -#include "esp_eth_mac.h" +#include "esp_eth_mac_esp.h" -/** - * @brief EMAC SMI GPIO configuration - */ -typedef struct { - int mdc_num; - int mdio_num; -} emac_esp_smi_gpio_config_t; - -/** - * @brief EMAC MII data interface GPIO configuration - */ -typedef struct { - uint8_t tx_clk_num; - uint8_t tx_en_num; - uint8_t txd0_num; - uint8_t txd1_num; - uint8_t txd2_num; - uint8_t txd3_num; - uint8_t rx_clk_num; - uint8_t rx_dv_num; - uint8_t rxd0_num; - uint8_t rxd1_num; - uint8_t rxd2_num; - uint8_t rxd3_num; -} emac_esp_mii_gpio_config_t; +#if CONFIG_ETH_USE_ESP32_EMAC -/** - * @brief EMAC RMII data interface GPIO configuration - */ -typedef struct { - uint8_t tx_en_num; - uint8_t txd0_num; - uint8_t txd1_num; - uint8_t crs_dv_num; - uint8_t rxd0_num; - uint8_t rxd1_num; -} emac_esp_rmii_gpio_config_t; - -esp_err_t emac_esp_iomux_init_mii(emac_esp_mii_gpio_config_t *mii_gpio); -esp_err_t emac_esp_iomux_init_rmii(emac_esp_rmii_gpio_config_t *rmii_gpio); +esp_err_t emac_esp_gpio_matrix_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio); +esp_err_t emac_esp_iomux_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio); +esp_err_t emac_esp_iomux_init_rmii(const eth_mac_rmii_gpio_config_t *rmii_gpio); esp_err_t emac_esp_iomux_rmii_clk_input(int num); esp_err_t emac_esp_iomux_rmii_clk_ouput(int num); -esp_err_t emac_esp_iomux_init_tx_er(int num); -esp_err_t emac_esp_iomux_init_rx_er(int num); -void emac_esp32_gpio_init_smi(emac_esp_smi_gpio_config_t *smi_gpio); +esp_err_t emac_esp_iomux_rmii_init_tx_er(int num); +esp_err_t emac_esp_iomux_rmii_init_rx_er(int num); +esp_err_t emac_esp_iomux_mii_init_tx_er(int num); +esp_err_t emac_esp_iomux_mii_init_rx_er(int num); +esp_err_t emac_esp_gpio_init_smi(const emac_esp_smi_gpio_config_t *smi_gpio); +esp_err_t emac_esp_gpio_deinit_all(void); + +#endif // CONFIG_ETH_USE_ESP32_EMAC #ifdef __cplusplus } diff --git a/components/esp_eth/src/esp_eth.c b/components/esp_eth/src/esp_eth.c index e776da16d6c..d9439ca316b 100644 --- a/components/esp_eth/src/esp_eth.c +++ b/components/esp_eth/src/esp_eth.c @@ -499,6 +499,24 @@ esp_err_t esp_eth_ioctl(esp_eth_handle_t hdl, esp_eth_io_cmd_t cmd, void *data) return ret; } +esp_err_t esp_eth_get_phy_instance(esp_eth_handle_t hdl, esp_eth_phy_t **phy) +{ + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null"); + ESP_RETURN_ON_FALSE(phy != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store PHY instance to null"); + *phy = eth_driver->phy; + return ESP_OK; +} + +esp_err_t esp_eth_get_mac_instance(esp_eth_handle_t hdl, esp_eth_mac_t **mac) +{ + esp_eth_driver_t *eth_driver = (esp_eth_driver_t *)hdl; + ESP_RETURN_ON_FALSE(eth_driver, ESP_ERR_INVALID_ARG, TAG, "ethernet driver handle can't be null"); + ESP_RETURN_ON_FALSE(mac != NULL, ESP_ERR_INVALID_ARG, TAG, "can't store MAC instance to null"); + *mac = eth_driver->mac; + return ESP_OK; +} + esp_err_t esp_eth_increase_reference(esp_eth_handle_t hdl) { esp_err_t ret = ESP_OK; diff --git a/components/esp_eth/src/esp_eth_mac_esp_gpio.c b/components/esp_eth/src/esp_eth_mac_esp_gpio.c deleted file mode 100644 index b1499ba96af..00000000000 --- a/components/esp_eth/src/esp_eth_mac_esp_gpio.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "esp_check.h" -#include "sdkconfig.h" -#include "esp_rom_gpio.h" -#include "driver/gpio.h" -#include "soc/soc_caps.h" -#include "soc/gpio_sig_map.h" -#include "soc/io_mux_reg.h" -#include "soc/gpio_periph.h" -#include "esp_private/gpio.h" -#include "esp_private/eth_mac_esp_gpio.h" -#include "esp_log.h" - -static const char *TAG = "esp.emac.gpio"; - -void emac_esp32_gpio_init_smi(emac_esp_smi_gpio_config_t *smi_gpio) -{ - if (smi_gpio->mdc_num >= 0) { - /* Setup SMI MDC GPIO */ - gpio_set_direction(smi_gpio->mdc_num, GPIO_MODE_OUTPUT); -#if CONFIG_IDF_TARGET_ESP32 - esp_rom_gpio_connect_out_signal(smi_gpio->mdc_num, EMAC_MDC_O_IDX, false, false); -#elif CONFIG_IDF_TARGET_ESP32P4 - esp_rom_gpio_connect_out_signal(smi_gpio->mdc_num, GMII_MDC_PAD_OUT_IDX, false, false); -#endif - gpio_func_sel(smi_gpio->mdc_num, PIN_FUNC_GPIO); - } - if (smi_gpio->mdio_num >= 0) { - /* Setup SMI MDIO GPIO */ - gpio_set_direction(smi_gpio->mdio_num, GPIO_MODE_INPUT_OUTPUT); -#if CONFIG_IDF_TARGET_ESP32 - esp_rom_gpio_connect_out_signal(smi_gpio->mdio_num, EMAC_MDO_O_IDX, false, false); - esp_rom_gpio_connect_in_signal(smi_gpio->mdio_num, EMAC_MDI_I_IDX, false); -#elif CONFIG_IDF_TARGET_ESP32P4 - esp_rom_gpio_connect_out_signal(smi_gpio->mdio_num, GMII_MDO_PAD_OUT_IDX, false, false); - esp_rom_gpio_connect_in_signal(smi_gpio->mdio_num, GMII_MDI_PAD_IN_IDX, false); -#endif - gpio_func_sel(smi_gpio->mdio_num, PIN_FUNC_GPIO); - } -} - -esp_err_t emac_esp_iomux_init_mii(emac_esp_mii_gpio_config_t *mii_gpio) -{ - (void)mii_gpio; -#if CONFIG_IDF_TARGET_ESP32 - /* TX_CLK to GPIO0 */ - gpio_func_sel(0, FUNC_GPIO0_EMAC_TX_CLK); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]); - /* TX_EN to GPIO21 */ - gpio_func_sel(21, FUNC_GPIO21_EMAC_TX_EN); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]); - /* TXD0 to GPIO19 */ - gpio_func_sel(19, FUNC_GPIO19_EMAC_TXD0); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]); - /* TXD1 to GPIO22 */ - gpio_func_sel(22, FUNC_GPIO22_EMAC_TXD1); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]); - /* TXD2 to MTMS */ - gpio_func_sel(14, FUNC_MTMS_EMAC_TXD2); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[14]); - /* TXD3 to MTDI */ - gpio_func_sel(12, FUNC_MTDI_EMAC_TXD3); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[12]); - - /* RX_CLK to GPIO5 */ - gpio_func_sel(5, FUNC_GPIO5_EMAC_RX_CLK); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[5]); - /* RX_DV to GPIO27 */ - gpio_func_sel(27, FUNC_GPIO27_EMAC_RX_DV); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]); - /* RXD0 to GPIO25 */ - gpio_func_sel(25, FUNC_GPIO25_EMAC_RXD0); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]); - /* RXD1 to GPIO26 */ - gpio_func_sel(26, FUNC_GPIO26_EMAC_RXD1); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]); - /* RXD2 to U0TXD */ - gpio_func_sel(1, FUNC_U0TXD_EMAC_RXD2); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[1]); - /* RXD3 to MTDO */ - gpio_func_sel(15, FUNC_MTDO_EMAC_RXD3); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[15]); - return ESP_OK; -#elif CONFIG_IDF_TARGET_ESP32P4 - ESP_LOGW(TAG, "MII is currently not supported"); - return ESP_ERR_NOT_SUPPORTED; -#endif -} - -esp_err_t emac_esp_iomux_rmii_clk_input(int num) -{ -#if CONFIG_IDF_TARGET_ESP32 - if (num != 0) { - return ESP_ERR_INVALID_ARG; - } - /* REF_CLK(RMII mode) to GPIO0 */ - gpio_func_sel(0, FUNC_GPIO0_EMAC_TX_CLK); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]); -#elif CONFIG_IDF_TARGET_ESP32P4 - /* REF_CLK(RMII mode) to `num` */ - switch(num) { - case 32: - gpio_func_sel(num, FUNC_GPIO32_GMAC_RMII_CLK_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[32]); - break; - case 44: - gpio_func_sel(num, FUNC_GPIO44_GMAC_RMII_CLK_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[44]); - break; - case 50: - gpio_func_sel(num, FUNC_GPIO50_GMAC_RMII_CLK_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[50]); - break; - default: - ESP_LOGE(TAG, "invalid RMII CLK input GPIO number. Expected [32, 44, 50], actual %i", num); - return ESP_ERR_INVALID_ARG; - } -#endif - return ESP_OK; -} - -esp_err_t emac_esp_iomux_rmii_clk_ouput(int num) -{ -#if CONFIG_IDF_TARGET_ESP32 - switch (num) { - case 0: - /* APLL clock output to GPIO0 (must be configured to 50MHz!) */ - gpio_func_sel(num, FUNC_GPIO0_CLK_OUT1); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]); - break; - case 16: - /* RMII CLK (50MHz) output to GPIO16 */ - gpio_func_sel(num, FUNC_GPIO16_EMAC_CLK_OUT); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]); - break; - case 17: - /* RMII CLK (50MHz) output to GPIO17 */ - gpio_func_sel(num, FUNC_GPIO17_EMAC_CLK_OUT_180); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]); - break; - default: - ESP_LOGE(TAG, "invalid RMII CLK output GPIO number. Expected [0, 16, 17], actual %i", num); - return ESP_ERR_INVALID_ARG; - } -#elif CONFIG_IDF_TARGET_ESP32P4 - /*RMII CLK output to num */ - switch (num) { - case 23: - gpio_func_sel(num, FUNC_GPIO23_REF_50M_CLK_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[23]); - break; - case 39: - gpio_func_sel(num, FUNC_GPIO39_REF_50M_CLK_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[39]); - break; - default: - ESP_LOGE(TAG, "invalid RMII CLK input GPIO number. Expected [23, 39], actual %i", num); - return ESP_ERR_INVALID_ARG; - } -#endif - return ESP_OK; -} - -esp_err_t emac_esp_iomux_init_rmii(emac_esp_rmii_gpio_config_t *rmii_gpio) -{ -#if CONFIG_IDF_TARGET_ESP32 - (void)rmii_gpio; - /* TX_EN to GPIO21 */ - gpio_func_sel(21, FUNC_GPIO21_EMAC_TX_EN); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]); - /* TXD0 to GPIO19 */ - gpio_func_sel(19, FUNC_GPIO19_EMAC_TXD0); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]); - /* TXD1 to GPIO22 */ - gpio_func_sel(22, FUNC_GPIO22_EMAC_TXD1); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]); - - /* CRS_DV to GPIO27 */ - gpio_func_sel(27, FUNC_GPIO27_EMAC_RX_DV); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]); - /* RXD0 to GPIO25 */ - gpio_func_sel(25, FUNC_GPIO25_EMAC_RXD0); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]); - /* RXD1 to GPIO26 */ - gpio_func_sel(26, FUNC_GPIO26_EMAC_RXD1); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]); - return ESP_OK; -#elif CONFIG_IDF_TARGET_ESP32P4 - if (rmii_gpio == NULL) { - return ESP_ERR_INVALID_ARG; - } - /* TX_EN */ - switch(rmii_gpio->tx_en_num) { - case 33: - gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO33_GMAC_PHY_TXEN_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[33]); - break; - case 40: - gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO40_GMAC_PHY_TXEN_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[40]); - break; - case 49: - gpio_func_sel(rmii_gpio->tx_en_num, FUNC_GPIO49_GMAC_PHY_TXEN_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[49]); - break; - default: - ESP_LOGE(TAG, "invalid TX_EN GPIO number. Expected [33, 40, 49], actual %" PRIu8, rmii_gpio->tx_en_num); - return ESP_ERR_INVALID_ARG; - } - /* TXD0 */ - switch(rmii_gpio->txd0_num) { - case 34: - gpio_func_sel(rmii_gpio->txd0_num, FUNC_GPIO34_GMAC_PHY_TXD0_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[34]); - break; - case 41: - gpio_func_sel(rmii_gpio->txd0_num, FUNC_GPIO41_GMAC_PHY_TXD0_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[41]); - break; - default: - ESP_LOGE(TAG, "invalid TXD0 GPIO number. Expected [34, 41], actual %" PRIu8, rmii_gpio->txd0_num); - return ESP_ERR_INVALID_ARG; - } - /* TXD1 */ - switch(rmii_gpio->txd1_num) { - case 35: - gpio_func_sel(rmii_gpio->txd1_num, FUNC_GPIO35_GMAC_PHY_TXD1_PAD ); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[35]); - break; - case 42: - gpio_func_sel(rmii_gpio->txd1_num, FUNC_GPIO42_GMAC_PHY_TXD1_PAD ); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[42]); - break; - default: - ESP_LOGE(TAG, "invalid TXD1 GPIO number. Expected [35, 42], actual %" PRIu8, rmii_gpio->txd1_num); - return ESP_ERR_INVALID_ARG; - } - - /* CRS_DV */ - switch(rmii_gpio->crs_dv_num) { - case 28: - gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO28_GMAC_PHY_RXDV_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[28]); - break; - case 45: - gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO45_GMAC_PHY_RXDV_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[45]); - break; - case 51: - gpio_func_sel(rmii_gpio->crs_dv_num, FUNC_GPIO51_GMAC_PHY_RXDV_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[51]); - break; - default: - ESP_LOGE(TAG, "invalid CRS_DV GPIO number. Expected [28, 45, 51], actual %" PRIu8, rmii_gpio->crs_dv_num); - return ESP_ERR_INVALID_ARG; - } - /* RXD0 */ - switch(rmii_gpio->rxd0_num) { - case 29: - gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO29_GMAC_PHY_RXD0_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[29]); - break; - case 46: - gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO46_GMAC_PHY_RXD0_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[46]); - break; - case 52: - gpio_func_sel(rmii_gpio->rxd0_num, FUNC_GPIO52_GMAC_PHY_RXD0_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[52]); - break; - default: - ESP_LOGE(TAG, "invalid RXD0 GPIO number. Expected [29, 46, 52], actual %" PRIu8, rmii_gpio->rxd0_num); - return ESP_ERR_INVALID_ARG; - } - /* RXD1 */ - switch(rmii_gpio->rxd1_num) { - case 30: - gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO30_GMAC_PHY_RXD1_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[30]); - break; - case 47: - gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO47_GMAC_PHY_RXD1_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[47]); - break; - case 53: - gpio_func_sel(rmii_gpio->rxd1_num, FUNC_GPIO53_GMAC_PHY_RXD1_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[53]); - break; - default: - ESP_LOGE(TAG, "invalid RXD1 GPIO number. Expected [30, 47, 53], actual %" PRIu8, rmii_gpio->rxd1_num); - return ESP_ERR_INVALID_ARG; - } - return ESP_OK; -#endif -} - -esp_err_t emac_esp_iomux_init_tx_er(int num) -{ -#if CONFIG_IDF_TARGET_ESP32 - (void)num; - /* TX_ER to GPIO4 */ - gpio_func_sel(4, FUNC_GPIO4_EMAC_TX_ER); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[4]); -#elif CONFIG_IDF_TARGET_ESP32P4 - /* TX_ER */ - switch (num) - { - case 36: - gpio_func_sel(num, FUNC_GPIO36_GMAC_PHY_TXER_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[36]); - break; - case 43: - gpio_func_sel(num, FUNC_GPIO43_GMAC_PHY_TXER_PAD); - PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[43]); - break; - default: - ESP_LOGE(TAG, "invalid TX_ER GPIO number. Expected [36, 43], actual %i", num); - return ESP_ERR_INVALID_ARG; - } -#endif - return ESP_OK; -} - -esp_err_t emac_esp_iomux_init_rx_er(int num) -{ -#if CONFIG_IDF_TARGET_ESP32 - (void)num; - /* RX_ER to MTCK */ - gpio_func_sel(13, FUNC_MTCK_EMAC_RX_ER); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[13]); -#elif CONFIG_IDF_TARGET_ESP32P4 - /* RX_ER */ - switch (num) - { - case 31: - gpio_func_sel(num, FUNC_GPIO31_GMAC_PHY_RXER_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[31]); - break; - case 48: - gpio_func_sel(num, FUNC_GPIO48_GMAC_PHY_RXER_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[48]); - break; - case 54: - gpio_func_sel(num, FUNC_GPIO54_GMAC_PHY_RXER_PAD); - PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[54]); - break; - default: - ESP_LOGE(TAG, "invalid RX_ER GPIO number. Expected [31, 48, 54], actual %i", num); - return ESP_ERR_INVALID_ARG; - } -#endif - return ESP_OK; -} diff --git a/components/esp_eth/src/esp_eth_netif_glue.c b/components/esp_eth/src/esp_eth_netif_glue.c index ad33eb0d2f6..f3bc3600505 100644 --- a/components/esp_eth/src/esp_eth_netif_glue.c +++ b/components/esp_eth/src/esp_eth_netif_glue.c @@ -6,7 +6,6 @@ #include #include #include "esp_netif.h" -#include "esp_eth_driver.h" #include "esp_eth_netif_glue.h" #include "esp_netif_net_stack.h" #include "esp_event.h" diff --git a/components/esp_eth/src/esp_eth_mac_esp.c b/components/esp_eth/src/mac/esp_eth_mac_esp.c similarity index 83% rename from components/esp_eth/src/esp_eth_mac_esp.c rename to components/esp_eth/src/mac/esp_eth_mac_esp.c index 6ad4157e867..f0813bb7cac 100644 --- a/components/esp_eth/src/esp_eth_mac_esp.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp.c @@ -12,7 +12,6 @@ #include "esp_attr.h" #include "esp_log.h" #include "esp_check.h" -#include "esp_eth_driver.h" #include "esp_pm.h" #include "esp_mac.h" #include "esp_cpu.h" @@ -66,8 +65,6 @@ typedef struct { uint32_t free_rx_descriptor; uint32_t flow_control_high_water_mark; uint32_t flow_control_low_water_mark; - emac_esp_smi_gpio_config_t smi_gpio; - eth_mac_clock_config_t clock_config; uint8_t addr[ETH_ADDR_LEN]; bool isr_need_yield; bool flow_ctrl_enabled; // indicates whether the user want to do flow control @@ -82,19 +79,10 @@ typedef struct { #ifdef CONFIG_IDF_TARGET_ESP32 esp_clock_output_mapping_handle_t rmii_clk_hdl; // we use the esp_clock_output driver to output a pre-configured APLL clock as the RMII reference clock #endif - -#ifdef CONFIG_IDF_TARGET_ESP32P4 - eth_mac_clock_config_t clock_config_out_in; - union - { - emac_esp_mii_gpio_config_t mii_gpio; - emac_esp_rmii_gpio_config_t rmii_gpio; - }; -#endif // CONFIG_IDF_TARGET_ESP32P4 } emac_esp32_t; -static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl); -static void esp_emac_free_driver_obj(emac_esp32_t *emac); +static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl); +static void emac_esp_free_driver_obj(emac_esp32_t *emac); static esp_err_t emac_esp32_start(esp_eth_mac_t *mac); static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac); @@ -209,11 +197,11 @@ static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed) // Set RMII clk_rx/clk_tx divider to get 25MHz for 100mbps mode or 2.5MHz for 10mbps mode if (emac_hal_get_phy_intf(&emac->hal) == EMAC_DATA_INTERFACE_RMII) { if (speed == ETH_SPEED_10M) { - EMAC_IF_RCC_ATOMIC () { + EMAC_IF_RCC_ATOMIC() { emac_hal_clock_rmii_rx_tx_div(&emac->hal, RMII_10M_SPEED_RX_TX_CLK_DIV); } } else { - EMAC_IF_RCC_ATOMIC () { + EMAC_IF_RCC_ATOMIC() { emac_hal_clock_rmii_rx_tx_div(&emac->hal, RMII_100M_SPEED_RX_TX_CLK_DIV); } } @@ -268,6 +256,28 @@ static esp_err_t emac_esp32_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t return ESP_OK; } +esp_err_t emac_esp_custom_ioctl(esp_eth_mac_t *mac, int cmd, void *data) +{ + emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); + + switch (cmd) + { + case ETH_MAC_ESP_CMD_PTP_ENABLE: + return ESP_ERR_NOT_SUPPORTED; + case ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS: + ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot set DMA tx desc flag to null"); + emac_esp_dma_set_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data); + break; + case ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS: + ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot clear DMA tx desc flag with null"); + emac_esp_dma_clear_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data); + break; + default: + ESP_RETURN_ON_ERROR(ESP_ERR_INVALID_ARG, TAG, "unknown io command: %i", cmd); + } + return ESP_OK; +} + static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length) { esp_err_t ret = ESP_OK; @@ -304,7 +314,8 @@ static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t * uint32_t expected_len = *length; emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null"); - uint32_t receive_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buf, expected_len, &emac->frames_remain, &emac->free_rx_descriptor); + uint32_t receive_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buf, expected_len); + emac_esp_dma_get_remain_frames(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor); /* we need to check the return value in case the buffer size is not enough */ ESP_GOTO_ON_FALSE(expected_len >= receive_len, ESP_ERR_INVALID_SIZE, err, TAG, "received buffer longer than expected"); *length = receive_len; @@ -327,12 +338,12 @@ static void emac_esp32_rx_task(void *arg) buffer = emac_esp_dma_alloc_recv_buf(emac->emac_dma_hndl, &frame_len); /* we have memory to receive the frame of maximal size previously defined */ if (buffer != NULL) { - uint32_t recv_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buffer, EMAC_HAL_BUF_SIZE_AUTO, &emac->frames_remain, &emac->free_rx_descriptor); + uint32_t recv_len = emac_esp_dma_receive_frame(emac->emac_dma_hndl, buffer, EMAC_DMA_BUF_SIZE_AUTO); if (recv_len == 0) { ESP_LOGE(TAG, "frame copy error"); free(buffer); /* ensure that interface to EMAC does not get stuck with unprocessed frames */ - emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor); + emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl); } else if (frame_len > recv_len) { ESP_LOGE(TAG, "received frame was truncated"); free(buffer); @@ -344,8 +355,9 @@ static void emac_esp32_rx_task(void *arg) } else if (frame_len) { ESP_LOGE(TAG, "no mem for receive buffer"); /* ensure that interface to EMAC does not get stuck with unprocessed frames */ - emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor); + emac_esp_dma_flush_recv_frame(emac->emac_dma_hndl); } + emac_esp_dma_get_remain_frames(emac->emac_dma_hndl, &emac->frames_remain, &emac->free_rx_descriptor); #if CONFIG_ETH_SOFT_FLOW_CONTROL // we need to do extra checking of remained frames in case there are no unhandled frames left, but pause frame is still undergoing if ((emac->free_rx_descriptor < emac->flow_control_low_water_mark) && emac->do_flow_ctrl && emac->frames_remain) { @@ -401,8 +413,6 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac) emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); esp_eth_mediator_t *eth = emac->eth; - /* init gpio used by smi interface */ - emac_esp32_gpio_init_smi(&emac->smi_gpio); ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed"); /* software reset */ emac_hal_reset(&emac->hal); @@ -451,7 +461,7 @@ static esp_err_t emac_esp32_start(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); /* reset descriptor chain */ - emac_esp_dma_reset_desc_chain(emac->emac_dma_hndl); + emac_esp_dma_reset(emac->emac_dma_hndl); emac_hal_start(&emac->hal); return ESP_OK; } @@ -474,8 +484,9 @@ static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac) static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - esp_emac_free_driver_obj(emac); - /// disable bus clock + emac_esp_free_driver_obj(emac); + emac_esp_gpio_deinit_all(); + // disable bus clock PERIPH_RCC_ATOMIC() { emac_ll_enable_bus_clock(0, false); } @@ -502,7 +513,7 @@ IRAM_ATTR void emac_isr_default_handler(void *args) #endif } -static void esp_emac_free_driver_obj(emac_esp32_t *emac) +static void emac_esp_free_driver_obj(emac_esp32_t *emac) { if (emac) { if (emac->rx_task_hdl) { @@ -537,7 +548,7 @@ static void esp_emac_free_driver_obj(emac_esp32_t *emac) } } -static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl) +static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl) { esp_err_t ret = ESP_OK; emac_esp32_t *emac = NULL; @@ -548,8 +559,7 @@ static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_ } ESP_GOTO_ON_FALSE(emac, ESP_ERR_NO_MEM, err, TAG, "no mem for esp emac object"); - emac_esp_dma_config_t emac_dma_config; - ESP_GOTO_ON_ERROR(emac_esp_new_dma(&emac_dma_config, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed"); + ESP_GOTO_ON_ERROR(emac_esp_new_dma(NULL, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed"); /* alloc PM lock */ #ifdef CONFIG_PM_ENABLE @@ -565,88 +575,65 @@ static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_ ESP_GOTO_ON_FALSE(xReturned == pdPASS, ESP_FAIL, err, TAG, "create emac_rx task failed"); *emac_out_hdl = emac; - return ESP_OK; err: - esp_emac_free_driver_obj(emac); return ret; } -static esp_err_t esp_emac_config_data_interface(const eth_esp32_emac_config_t *esp32_emac_config, emac_esp32_t *emac) +static esp_err_t emac_esp_config_data_interface(const eth_esp32_emac_config_t *esp32_emac_config, emac_esp32_t *emac) { esp_err_t ret = ESP_OK; switch (esp32_emac_config->interface) { case EMAC_DATA_INTERFACE_MII: - emac->clock_config = esp32_emac_config->clock_config; /* MII interface GPIO initialization */ - ESP_GOTO_ON_ERROR(emac_esp_iomux_init_mii(NULL), err, TAG, "invalid EMAC MII data plane GPIO"); +#if SOC_EMAC_MII_USE_GPIO_MATRIX + ESP_GOTO_ON_ERROR(emac_esp_gpio_matrix_init_mii(&esp32_emac_config->emac_dataif_gpio.mii), err, TAG, "failed to initialize EMAC MII GPIO Matrix"); +#else + eth_mac_mii_gpio_config_t *mii_data_gpio = NULL; +#if SOC_EMAC_USE_MULTI_IO_MUX + mii_data_gpio = &esp32_emac_config->emac_dataif_gpio.mii; +#endif // SOC_EMAC_USE_MULTI_IO_MUX + ESP_GOTO_ON_ERROR(emac_esp_iomux_init_mii(mii_data_gpio), err, TAG, "invalid EMAC MII data plane GPIO"); +#endif // SOC_EMAC_MII_USE_GPIO_MATRIX /* Enable MII clock */ EMAC_IF_RCC_ATOMIC() { emac_hal_clock_enable_mii(&emac->hal); } break; case EMAC_DATA_INTERFACE_RMII: - // by default, the clock mode is selected at compile time (by Kconfig) - if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_DEFAULT) { -#ifdef CONFIG_IDF_TARGET_ESP32 -#if CONFIG_ETH_RMII_CLK_INPUT -#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0 - emac->clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN; - emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_IN_GPIO; -#else -#error "ESP32 EMAC only support input RMII clock to GPIO0" -#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0 -#elif CONFIG_ETH_RMII_CLK_OUTPUT - emac->clock_config.rmii.clock_mode = EMAC_CLK_OUT; -#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 - emac->clock_config.rmii.clock_gpio = 0; -#elif CONFIG_ETH_RMII_CLK_OUT_GPIO - emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_OUT_GPIO; -#endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 -#else -#error "Unsupported RMII clock mode" -#endif // CONFIG_ETH_RMII_CLK_INPUT -#else // EMAC_CLK_DEFAULT "not supported for ESP32P4" - this configuration has been kept due to compatibility reasons for ESP32 - ESP_LOGE(TAG, "EMAC_CLK_DEFAULT options is only supported by ESP32"); - return ESP_ERR_INVALID_ARG; -#endif // CONFIG_IDF_TARGET_ESP32 - } else { - emac->clock_config = esp32_emac_config->clock_config; -#ifdef CONFIG_IDF_TARGET_ESP32P4 - emac->clock_config_out_in = esp32_emac_config->clock_config_out_in; -#endif // CONFIG_IDF_TARGET_ESP32P4 - } /* RMII interface GPIO initialization */ -#ifdef CONFIG_IDF_TARGET_ESP32 - ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(NULL), err, TAG, "invalid EMAC RMII data plane GPIO"); -#else - ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(&emac->rmii_gpio), err, TAG, "invalid EMAC RMII data plane GPIO"); -#endif // CONFIG_IDF_TARGET_ESP32 + const eth_mac_rmii_gpio_config_t *rmii_data_gpio = NULL; +#if SOC_EMAC_USE_MULTI_IO_MUX + rmii_data_gpio = &esp32_emac_config->emac_dataif_gpio.rmii; +#endif // SOC_EMAC_USE_MULTI_IO_MUX + ESP_GOTO_ON_ERROR(emac_esp_iomux_init_rmii(rmii_data_gpio), err, TAG, "invalid EMAC RMII data plane GPIO"); /* If ref_clk is configured as input */ - if (emac->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) { - ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(emac->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO"); + if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) { + ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(esp32_emac_config->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO"); EMAC_IF_RCC_ATOMIC() { emac_hal_clock_enable_rmii_input(&emac->hal); } - } else if (emac->clock_config.rmii.clock_mode == EMAC_CLK_OUT) { + } else if (esp32_emac_config->clock_config.rmii.clock_mode == EMAC_CLK_OUT) { ESP_GOTO_ON_ERROR(emac_config_pll_clock(emac), err, TAG, "Configure (A/M)PLL for RMII failed"); -#if CONFIG_IDF_TARGET_ESP32 - // we can also use the IOMUX to route the APLL clock to specific GPIO - if (emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) { - ESP_GOTO_ON_ERROR(esp_clock_output_start(CLKOUT_SIG_APLL, EMAC_APPL_CLK_OUT_GPIO, &emac->rmii_clk_hdl), - err, TAG, "start APLL clock output failed"); - } -#elif CONFIG_IDF_TARGET_ESP32P4 +#if CONFIG_IDF_TARGET_ESP32P4 /* Output RMII clock is routed back to input externally */ - ESP_GOTO_ON_FALSE(emac->clock_config_out_in.rmii.clock_mode == EMAC_CLK_EXT_IN && emac->clock_config_out_in.rmii.clock_gpio >= 0, + ESP_GOTO_ON_FALSE(esp32_emac_config->clock_config_out_in.rmii.clock_mode == EMAC_CLK_EXT_IN && esp32_emac_config->clock_config_out_in.rmii.clock_gpio >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC input of output clock mode"); - ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(emac->clock_config_out_in.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO"); + ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_input(esp32_emac_config->clock_config_out_in.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock input GPIO"); EMAC_IF_RCC_ATOMIC() { emac_hal_clock_enable_rmii_input(&emac->hal); } +#elif CONFIG_IDF_TARGET_ESP32 + // we can also use the IOMUX to route the APLL clock to specific GPIO + if (esp32_emac_config->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) { + ESP_GOTO_ON_ERROR(esp_clock_output_start(CLKOUT_SIG_APLL, EMAC_APPL_CLK_OUT_GPIO, &emac->rmii_clk_hdl), + err, TAG, "start APLL clock output failed"); + } else #endif - ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_ouput(emac->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock output GPIO"); + { + ESP_GOTO_ON_ERROR(emac_esp_iomux_rmii_clk_ouput(esp32_emac_config->clock_config.rmii.clock_gpio), err, TAG, "invalid EMAC RMII clock output GPIO"); + } /* Enable RMII Output clock */ - EMAC_IF_RCC_ATOMIC () { + EMAC_IF_RCC_ATOMIC() { emac_hal_clock_enable_rmii_output(&emac->hal); } } else { @@ -671,7 +658,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config TAG, "invalid interrupt priority: %d", esp32_config->intr_priority); } - ret_code = esp_emac_alloc_driver_obj(config, &emac); + ret_code = emac_esp_alloc_driver_obj(config, &emac); ESP_RETURN_ON_FALSE(ret_code == ESP_OK, NULL, TAG, "alloc driver object failed"); // enable bus clock for the EMAC module, and reset the registers into default state @@ -697,21 +684,15 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config emac_isr_default_handler, &emac->hal, &(emac->intr_hdl)); ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed"); -#ifdef SOC_EMAC_USE_IO_MUX - emac->rmii_gpio.tx_en_num = esp32_config->emac_dataif_gpio.rmii.tx_en_num; - emac->rmii_gpio.txd0_num = esp32_config->emac_dataif_gpio.rmii.txd0_num; - emac->rmii_gpio.txd1_num = esp32_config->emac_dataif_gpio.rmii.txd1_num; - emac->rmii_gpio.crs_dv_num = esp32_config->emac_dataif_gpio.rmii.crs_dv_num; - emac->rmii_gpio.rxd0_num = esp32_config->emac_dataif_gpio.rmii.rxd0_num; - emac->rmii_gpio.rxd1_num = esp32_config->emac_dataif_gpio.rmii.rxd1_num; -#endif // SOC_EMAC_USE_IO_MUX - ret_code = esp_emac_config_data_interface(esp32_config, emac); + /* init GPIO used by SMI interface */ + ret_code = emac_esp_gpio_init_smi(&esp32_config->smi_gpio); + ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "SMI GPIO init failed"); + /* init GPIO and CLK for data interface */ + ret_code = emac_esp_config_data_interface(esp32_config, emac); ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "config emac interface failed"); emac->dma_burst_len = esp32_config->dma_burst_len; emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; - emac->smi_gpio.mdc_num = esp32_config->smi_mdc_gpio_num; - emac->smi_gpio.mdio_num = esp32_config->smi_mdio_gpio_num; emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; @@ -734,9 +715,11 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config emac->parent.transmit = emac_esp32_transmit; emac->parent.transmit_vargs = emac_esp32_transmit_multiple_bufs; emac->parent.receive = emac_esp32_receive; + emac->parent.custom_ioctl = emac_esp_custom_ioctl; return &(emac->parent); err: - esp_emac_free_driver_obj(emac); + emac_esp_free_driver_obj(emac); + emac_esp_gpio_deinit_all(); return ret; } diff --git a/components/esp_eth/src/esp_eth_mac_esp_dma.c b/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c similarity index 69% rename from components/esp_eth/src/esp_eth_mac_esp_dma.c rename to components/esp_eth/src/mac/esp_eth_mac_esp_dma.c index b885fe0cee0..d5eba402c8f 100644 --- a/components/esp_eth/src/esp_eth_mac_esp_dma.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c @@ -16,13 +16,36 @@ #define ETH_CRC_LENGTH (4) -#define EMAC_HAL_BUF_MAGIC_ID 0x1E1C8416 +#define EMAC_ALLOC_BUF_MAGIC_ID 0x1E1C8416 + +#define EMAC_TDES0_FS_CTRL_FLAGS_MASK 0x0FCC0000 // modifiable bits mask associated with the First Segment +#define EMAC_TDES0_LS_CTRL_FLAGS_MASK 0x40000000 // modifiable bits mask associated with the Last Segment + +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#define DMA_CACHE_WB(addr, size) do { \ + esp_err_t msync_ret = esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); \ + assert(msync_ret == ESP_OK); \ + } while(0) +#else +#define DMA_CACHE_WB(addr, size) +#endif + +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#define DMA_CACHE_INVALIDATE(addr, size) do { \ + esp_err_t msync_ret = esp_cache_msync((void *)addr, size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); \ + assert(msync_ret == ESP_OK); \ + } while(0) +#else +#define DMA_CACHE_INVALIDATE(addr, size) +#endif static const char *TAG = "esp.emac.dma"; struct emac_esp_dma_t { emac_hal_context_t hal; + uint32_t tx_desc_flags; + uint32_t rx_desc_flags; void *descriptors; eth_dma_rx_descriptor_t *rx_desc; eth_dma_tx_descriptor_t *tx_desc; @@ -37,13 +60,8 @@ typedef struct { uint32_t copy_len; }__attribute__((packed)) emac_esp_dma_auto_buf_info_t; -void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma) +void emac_esp_dma_reset(emac_esp_dma_handle_t emac_esp_dma) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len; - esp_err_t ret = ESP_OK; -#endif - /* reset DMA descriptors */ emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(emac_esp_dma->descriptors); emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->descriptors + @@ -66,11 +84,7 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma) if (i == CONFIG_ETH_DMA_RX_BUFFER_NUM - 1) { emac_esp_dma->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(emac_esp_dma->rx_desc); } -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)&emac_esp_dma->rx_desc[i], cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(&emac_esp_dma->rx_desc[i], EMAC_HAL_DMA_DESC_SIZE); } /* init tx chain */ @@ -79,10 +93,6 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma) emac_esp_dma->tx_desc[i].TDES0.Own = EMAC_LL_DMADESC_OWNER_CPU; emac_esp_dma->tx_desc[i].TDES0.SecondAddressChained = 1; emac_esp_dma->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE; - /* Enable Ethernet DMA Tx Descriptor interrupt */ - emac_esp_dma->tx_desc[1].TDES0.InterruptOnComplete = 1; - /* Enable Transmit Timestamp */ - emac_esp_dma->tx_desc[i].TDES0.TransmitTimestampEnable = 1; /* point to the buffer */ emac_esp_dma->tx_desc[i].Buffer1Addr = (uint32_t)(emac_esp_dma->tx_buf[i]); /* point to next descriptor */ @@ -92,24 +102,25 @@ void emac_esp_dma_reset_desc_chain(emac_esp_dma_handle_t emac_esp_dma) if (i == CONFIG_ETH_DMA_TX_BUFFER_NUM - 1) { emac_esp_dma->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(emac_esp_dma->tx_desc); } -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_tx_descriptor_t); - ret = esp_cache_msync((void *)&emac_esp_dma->tx_desc[i], cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(&emac_esp_dma->tx_desc[i], EMAC_HAL_DMA_DESC_SIZE); } /* set base address of the first descriptor */ emac_hal_set_rx_tx_desc_addr(&emac_esp_dma->hal, emac_esp_dma->rx_desc, emac_esp_dma->tx_desc); } -uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t length) +void emac_esp_dma_set_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t flag) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_err_t ret; - size_t cache_sync_len; -#endif + emac_esp_dma->tx_desc_flags |= flag; +} +void emac_esp_dma_clear_tdes0_ctrl_bits(emac_esp_dma_handle_t emac_esp_dma, uint32_t flag) +{ + emac_esp_dma->tx_desc_flags &= ~flag; +} + +uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t length) +{ /* Get the number of Tx buffers to use for the frame */ uint32_t bufcount = 0; uint32_t lastlen = length; @@ -128,11 +139,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t eth_dma_tx_descriptor_t *desc_iter = emac_esp_dma->tx_desc; /* A frame is transmitted in multiple descriptor */ for (size_t i = 0; i < bufcount; i++) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_tx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */ if (desc_iter->TDES0.Own != EMAC_LL_DMADESC_OWNER_CPU) { goto err; @@ -140,17 +147,16 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t /* Clear FIRST and LAST segment bits */ desc_iter->TDES0.FirstSegment = 0; desc_iter->TDES0.LastSegment = 0; - desc_iter->TDES0.InterruptOnComplete = 0; + desc_iter->TDES0.Value &= ~(EMAC_TDES0_FS_CTRL_FLAGS_MASK | EMAC_TDES0_LS_CTRL_FLAGS_MASK); if (i == 0) { /* Setting the first segment bit */ desc_iter->TDES0.FirstSegment = 1; - //desc_iter->TDES0.DisableCRC = 1; + desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_FS_CTRL_FLAGS_MASK; } if (i == (bufcount - 1)) { /* Setting the last segment bit */ desc_iter->TDES0.LastSegment = 1; - /* Enable transmit interrupt */ - desc_iter->TDES0.InterruptOnComplete = 1; + desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_LS_CTRL_FLAGS_MASK; /* Program size */ desc_iter->TDES1.TransmitBuffer1Size = lastlen; /* copy data from uplayer stack buffer */ @@ -163,11 +169,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE); sentout += CONFIG_ETH_DMA_BUFFER_SIZE; } -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE; - ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE); /* Point to next descriptor */ desc_iter = (eth_dma_tx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); } @@ -175,11 +177,7 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ for (size_t i = 0; i < bufcount; i++) { emac_esp_dma->tx_desc->TDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_tx_descriptor_t); - ret = esp_cache_msync((void *)emac_esp_dma->tx_desc, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(emac_esp_dma->tx_desc, EMAC_HAL_DMA_DESC_SIZE); emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->tx_desc->Buffer2NextDescAddr); } emac_hal_transmit_poll_demand(&emac_esp_dma->hal); @@ -190,11 +188,6 @@ uint32_t emac_esp_dma_transmit_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t **buffs, uint32_t *lengths, uint32_t buffs_cnt) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_err_t ret; - size_t cache_sync_len; -#endif - /* Get the number of Tx buffers to use for the frame */ uint32_t dma_bufcount = 0; uint32_t sentout = 0; @@ -205,11 +198,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp eth_dma_tx_descriptor_t *desc_iter = emac_esp_dma->tx_desc; /* A frame is transmitted in multiple descriptor */ while (dma_bufcount < CONFIG_ETH_DMA_TX_BUFFER_NUM) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_tx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */ if (desc_iter->TDES0.Own != EMAC_LL_DMADESC_OWNER_CPU) { goto err; @@ -217,11 +206,12 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp /* Clear FIRST and LAST segment bits */ desc_iter->TDES0.FirstSegment = 0; desc_iter->TDES0.LastSegment = 0; - desc_iter->TDES0.InterruptOnComplete = 0; + desc_iter->TDES0.Value &= ~(EMAC_TDES0_FS_CTRL_FLAGS_MASK | EMAC_TDES0_LS_CTRL_FLAGS_MASK); desc_iter->TDES1.TransmitBuffer1Size = 0; if (dma_bufcount == 0) { /* Setting the first segment bit */ desc_iter->TDES0.FirstSegment = 1; + desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_FS_CTRL_FLAGS_MASK; } while (buffs_cnt > 0) { @@ -259,11 +249,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp break; } } -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE; - ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE); /* Increase counter of utilized DMA buffers */ dma_bufcount++; @@ -271,8 +257,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp if (buffs_cnt == 0) { /* Setting the last segment bit */ desc_iter->TDES0.LastSegment = 1; - /* Enable transmit interrupt */ - desc_iter->TDES0.InterruptOnComplete = 1; + desc_iter->TDES0.Value |= emac_esp_dma->tx_desc_flags & EMAC_TDES0_LS_CTRL_FLAGS_MASK; break; } @@ -283,11 +268,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ for (size_t i = 0; i < dma_bufcount; i++) { emac_esp_dma->tx_desc->TDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_tx_descriptor_t); - ret = esp_cache_msync((void *)emac_esp_dma->tx_desc, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(emac_esp_dma->tx_desc, EMAC_HAL_DMA_DESC_SIZE); emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->tx_desc->Buffer2NextDescAddr); } @@ -301,25 +282,20 @@ static esp_err_t emac_esp_dma_get_valid_recv_len(emac_esp_dma_handle_t emac_esp_ { eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; uint32_t used_descs = 0; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* Traverse descriptors owned by CPU */ - while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) { + while ((desc_iter->RDES0.Own == EMAC_LL_DMADESC_OWNER_CPU) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) { used_descs++; /* Last segment in frame */ if (desc_iter->RDES0.LastDescriptor) { -#if CONFIG_IDF_TARGET_ESP32P4 - /* Since Store Forward must be disabled at ESP32P4, DMA descriptors may contain erroneous frames */ + /* Since Store Forward must be disabled on some targets, DMA descriptors may contain erroneous frames */ + /* In addition, "Descriptor Error" (no free descriptors) may truncate a frame even if Store Forward is enabled */ if (desc_iter->RDES0.ErrSummary) { - emac_esp_dma_flush_recv_frame(emac_esp_dma, NULL, NULL); + emac_esp_dma_flush_recv_frame(emac_esp_dma); *ret_len = 0; return ESP_FAIL; } -#endif //CONFIG_IDF_TARGET_ESP32P4 /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ *ret_len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH; break; @@ -330,42 +306,31 @@ static esp_err_t emac_esp_dma_get_valid_recv_len(emac_esp_dma_handle_t emac_esp_ } /* point to next descriptor */ desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); } return ESP_OK; } -static void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *used_descs) +void emac_esp_dma_get_remain_frames(emac_esp_dma_handle_t emac_esp_dma, uint32_t *remain_frames, uint32_t *free_descs) { eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; *remain_frames = 0; - *used_descs = 0; + uint32_t used_descs = 0; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* Traverse descriptors owned by CPU */ - while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (*used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) { - (*used_descs)++; + while ((desc_iter->RDES0.Own == EMAC_LL_DMADESC_OWNER_CPU) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) { + used_descs++; /* Last segment in frame */ if (desc_iter->RDES0.LastDescriptor) { (*remain_frames)++; } /* point to next descriptor */ desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - esp_err_t ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); } + *free_descs = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs; } uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_t *size) @@ -388,7 +353,7 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_ /* no need to check allocated buffer min length prior writing since we know that EMAC DMA is configured to not forward erroneous or undersized frames (less than 64B) on ESP32, see emac_hal_init_dma_default */ #ifndef NDEBUG - buff_info->magic_id = EMAC_HAL_BUF_MAGIC_ID; + buff_info->magic_id = EMAC_ALLOC_BUF_MAGIC_ID; #endif // NDEBUG buff_info->copy_len = copy_len; } @@ -398,20 +363,14 @@ uint8_t *emac_esp_dma_alloc_recv_buf(emac_esp_dma_handle_t emac_esp_dma, uint32_ return buf; } -uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc) +uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t *buf, uint32_t size) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len; - esp_err_t ret; -#endif - eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; - eth_dma_rx_descriptor_t *first_desc = emac_esp_dma->rx_desc; uint32_t ret_len = 0; uint32_t copy_len = 0; - if (size != EMAC_HAL_BUF_SIZE_AUTO) { + if (size != EMAC_DMA_BUF_SIZE_AUTO) { if (emac_esp_dma_get_valid_recv_len(emac_esp_dma, &ret_len) != ESP_OK) { - goto err; + return 0; } /* packets larger than expected will be truncated */ copy_len = ret_len > size ? size : ret_len; @@ -419,106 +378,75 @@ uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t emac_esp_dma_auto_buf_info_t *buff_info = (emac_esp_dma_auto_buf_info_t *)buf; #ifndef NDEBUG /* check that buffer was allocated by emac_esp_dma_alloc_recv_buf */ - assert(buff_info->magic_id == EMAC_HAL_BUF_MAGIC_ID); + assert(buff_info->magic_id == EMAC_ALLOC_BUF_MAGIC_ID); #endif // NDEBUG copy_len = buff_info->copy_len; ret_len = copy_len; } if (copy_len) { - desc_iter = first_desc; + eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; while(copy_len > CONFIG_ETH_DMA_BUFFER_SIZE) { -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE; - ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE); memcpy(buf, (void *)(desc_iter->Buffer1Addr), CONFIG_ETH_DMA_BUFFER_SIZE); buf += CONFIG_ETH_DMA_BUFFER_SIZE; copy_len -= CONFIG_ETH_DMA_BUFFER_SIZE; /* Set Own bit in Rx descriptors: gives the buffers back to DMA */ desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE); desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); } -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // TODO cleanup (IDF-8993) - cache_sync_len = CONFIG_ETH_DMA_BUFFER_SIZE; - ret = esp_cache_msync((void *)desc_iter->Buffer1Addr, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert(ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE); memcpy(buf, (void *)(desc_iter->Buffer1Addr), copy_len); desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* `copy_len` does not include CRC (which may be stored in separate buffer), hence check if we reached the last descriptor */ while (!desc_iter->RDES0.LastDescriptor) { desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert(ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE); } /* update rxdesc */ emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); /* poll rx demand */ emac_hal_receive_poll_demand(&emac_esp_dma->hal); } -err: - /* check how many frames left to handle */ - uint32_t used_descs = 0; - emac_esp_dma_get_remain_frames(emac_esp_dma, frames_remain, &used_descs); - *free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs; return ret_len; } -void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma, uint32_t *frames_remain, uint32_t *free_desc) +void emac_esp_dma_flush_recv_frame(emac_esp_dma_handle_t emac_esp_dma) { eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - size_t cache_sync_len; - esp_err_t ret; - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - assert (ret == ESP_OK); -#endif + DMA_CACHE_INVALIDATE(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* While not last descriptor => return back to DMA */ while (!desc_iter->RDES0.LastDescriptor) { desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert (ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE); desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); } /* the last descriptor */ desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_sync_len = sizeof(eth_dma_rx_descriptor_t); - ret = esp_cache_msync((void *)desc_iter, cache_sync_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); - assert (ret == ESP_OK); -#endif + DMA_CACHE_WB(desc_iter, EMAC_HAL_DMA_DESC_SIZE); /* update rxdesc */ emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr); /* poll rx demand */ emac_hal_receive_poll_demand(&emac_esp_dma->hal); +} - if (frames_remain != NULL && free_desc != NULL) { - /* check how many frames left to handle */ - uint32_t used_descs = 0; - emac_esp_dma_get_remain_frames(emac_esp_dma, frames_remain, &used_descs); - *free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs; +esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma) +{ + if (emac_esp_dma) { + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac_esp_dma->tx_buf[i]); + } + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac_esp_dma->rx_buf[i]); + } + free(emac_esp_dma->descriptors); + free(emac_esp_dma); } + return ESP_OK; } esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_handle_t *ret_handle) @@ -551,20 +479,6 @@ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_han *ret_handle = emac_esp_dma; return ESP_OK; err: + emac_esp_del_dma(emac_esp_dma); return ret; } - -esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma) -{ - if (emac_esp_dma) { - for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac_esp_dma->tx_buf[i]); - } - for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac_esp_dma->rx_buf[i]); - } - free(emac_esp_dma->descriptors); - free(emac_esp_dma); - } - return ESP_OK; -} diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c b/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c new file mode 100644 index 00000000000..cb9ea5c1a21 --- /dev/null +++ b/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c @@ -0,0 +1,265 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_check.h" +#include "sdkconfig.h" +#include "esp_rom_gpio.h" +#include "driver/gpio.h" +#include "soc/soc_caps.h" +#include "soc/gpio_sig_map.h" +#include "soc/io_mux_reg.h" +#include "soc/gpio_periph.h" +#include "soc/emac_periph.h" +#include "esp_private/gpio.h" +#include "esp_private/eth_mac_esp_gpio.h" +#include "esp_private/esp_gpio_reserve.h" +#include "esp_log.h" + +#define GET_GPIO_OR_SINGLE(cfg, num) cfg == NULL ? GPIO_NUM_MAX : cfg->num + +static const char *TAG = "esp.emac.gpio"; + +static uint64_t s_emac_esp_used_gpio_mask = 0x0; + +static esp_err_t emac_esp_gpio_matrix_init(gpio_num_t gpio_num, uint32_t signal_in_idx, uint32_t signal_out_idx, gpio_mode_t mode) +{ + // silently skip when user don't want to connect the signal to GPIO pad + if (gpio_num == GPIO_NUM_NC) { + ESP_LOGD(TAG, "%s skipping signal in_idx %" PRIu32 ", out_idx %" PRIu32, __func__, signal_in_idx, signal_out_idx); + return ESP_OK; + } + ESP_RETURN_ON_ERROR(gpio_set_direction(gpio_num, mode), TAG, "failed to set direction %i at GPIO #%i", mode, gpio_num); + switch(mode) { + case GPIO_MODE_INPUT: + ESP_RETURN_ON_FALSE(signal_in_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED, + TAG, "requested periph signal cannot be connect via GPIO Matrix"); + ESP_RETURN_ON_FALSE(esp_gpio_is_reserved(BIT64(gpio_num)) == false, ESP_ERR_INVALID_STATE, + TAG, "GPIO %i is reserved", gpio_num); + esp_rom_gpio_connect_in_signal(gpio_num, signal_in_idx, false); + break; + case GPIO_MODE_OUTPUT: + ESP_RETURN_ON_FALSE(signal_out_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED, + TAG, "requested periph signal cannot be connect via GPIO Matrix"); + ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num)) == 0, ESP_ERR_INVALID_STATE, + TAG, "GPIO %i is already reserved", gpio_num); + esp_rom_gpio_connect_out_signal(gpio_num, signal_out_idx, false, false); + break; + case GPIO_MODE_INPUT_OUTPUT: + ESP_RETURN_ON_FALSE(signal_in_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED, + TAG, "requested periph signal cannot be connect via GPIO Matrix"); + ESP_RETURN_ON_FALSE(signal_out_idx != SIG_GPIO_OUT_IDX, ESP_ERR_NOT_SUPPORTED, + TAG, "requested periph signal cannot be connect via GPIO Matrix"); + ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num)) == 0, ESP_ERR_INVALID_STATE, + TAG, "GPIO %i is already reserved", gpio_num); + esp_rom_gpio_connect_out_signal(gpio_num, signal_out_idx, false, false); + esp_rom_gpio_connect_in_signal(gpio_num, signal_in_idx, false); + break; + default: + return ESP_ERR_INVALID_ARG; + } + s_emac_esp_used_gpio_mask |= BIT64(gpio_num); + ESP_RETURN_ON_ERROR(gpio_set_pull_mode(gpio_num, GPIO_FLOATING), TAG, "failed to set pull mode at GPIO %i", gpio_num); + ESP_RETURN_ON_ERROR(gpio_func_sel(gpio_num, PIN_FUNC_GPIO), TAG, "failed to set GPIO function at GPIO #%i", gpio_num); + return ESP_OK; +} + +static esp_err_t emac_esp_iomux_init(gpio_num_t gpio_num, const emac_iomux_info_t *iomux_info, bool is_input) +{ + // silently skip undefined iomux functions (for example, ESP32 does not use MII COL_IN/CRS_IN) + if (iomux_info == NULL) { + ESP_LOGD(TAG, "%s skipping target undefined iomux periph function", __func__); + return ESP_OK; + } + // loop over target iomux_info until reached end of list indicated by invalid GPIO num + while (iomux_info->gpio_num != GPIO_NUM_MAX) { + // if requested GPIO number can be IO muxed or select single pad that can be muxed on the target + if(gpio_num == iomux_info->gpio_num || gpio_num == GPIO_NUM_MAX) { + ESP_RETURN_ON_FALSE((esp_gpio_reserve(BIT64(iomux_info->gpio_num)) & BIT64(iomux_info->gpio_num)) == 0, ESP_ERR_INVALID_STATE, + TAG, "GPIO %i is already reserved", iomux_info->gpio_num); + s_emac_esp_used_gpio_mask |= BIT64(iomux_info->gpio_num); + ESP_RETURN_ON_ERROR(gpio_func_sel(iomux_info->gpio_num, iomux_info->func), TAG, "failed to set GPIO function at GPIO %i", iomux_info->gpio_num); + if (is_input) { + PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[iomux_info->gpio_num]); + } else { + PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[iomux_info->gpio_num]); + } + ESP_RETURN_ON_ERROR(gpio_set_pull_mode(iomux_info->gpio_num, GPIO_FLOATING), + TAG, "failed to set pull mode at GPIO %i", iomux_info->gpio_num); + return ESP_OK; + } + iomux_info++; + } + return ESP_FAIL; +} + +esp_err_t emac_esp_gpio_init_smi(const emac_esp_smi_gpio_config_t *smi_gpio) +{ + if (smi_gpio->mdc_num >= 0) { + /* Setup SMI MDC GPIO */ + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(smi_gpio->mdc_num, 0, emac_io_idx.mdc_idx, GPIO_MODE_OUTPUT), + TAG, "MDC GPIO matrix config failed"); + } + if (smi_gpio->mdio_num >= 0) { + /* Setup SMI MDIO GPIO */ + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(smi_gpio->mdio_num, emac_io_idx.mdi_idx, emac_io_idx.mdo_idx, GPIO_MODE_INPUT_OUTPUT), + TAG, "MDIO GPIO matrix config failed"); + } + return ESP_OK; +} + +esp_err_t emac_esp_gpio_matrix_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio) +{ + ESP_RETURN_ON_FALSE(mii_gpio != NULL, ESP_ERR_INVALID_ARG, TAG, "MII IO matrix config cannot be NULL"); + + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_clk_num, emac_io_idx.mii_tx_clk_i_idx, 0, GPIO_MODE_INPUT), + TAG, "TX_CLK GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_en_num, 0, emac_io_idx.mii_tx_en_o_idx, GPIO_MODE_OUTPUT), + TAG, "TX_EN GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd0_num, 0, emac_io_idx.mii_txd0_o_idx, GPIO_MODE_OUTPUT), + TAG, "TDX0 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd1_num, 0, emac_io_idx.mii_txd1_o_idx, GPIO_MODE_OUTPUT), + TAG, "TDX1 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd2_num, 0, emac_io_idx.mii_txd2_o_idx, GPIO_MODE_OUTPUT), + TAG, "TDX2 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->txd3_num, 0, emac_io_idx.mii_txd3_o_idx, GPIO_MODE_OUTPUT), + TAG, "TDX3 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rx_clk_num, emac_io_idx.mii_rx_clk_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RX_CLK GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd0_num, emac_io_idx.mii_rxd0_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RXD0 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd1_num, emac_io_idx.mii_rxd1_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RXD1 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd2_num, emac_io_idx.mii_rxd2_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RXD2 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rxd3_num, emac_io_idx.mii_rxd3_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RXD3 GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->col_in_num, emac_io_idx.mii_col_i_idx, 0, GPIO_MODE_INPUT), + TAG, "COL_IN GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->crs_in_num, emac_io_idx.mii_crs_i_idx, 0, GPIO_MODE_INPUT), + TAG, "CRS_IN GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->tx_er_num, 0, emac_io_idx.mii_tx_er_o_idx, GPIO_MODE_OUTPUT), + TAG, "TX_ER GPIO matrix config failed"); + ESP_RETURN_ON_ERROR(emac_esp_gpio_matrix_init(mii_gpio->rx_er_num, emac_io_idx.mii_rx_er_i_idx, 0, GPIO_MODE_INPUT), + TAG, "RX_ER GPIO matrix config failed"); + + return ESP_OK; +} + +esp_err_t emac_esp_iomux_init_mii(const eth_mac_mii_gpio_config_t *mii_gpio) +{ + ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.clk_tx != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support MII IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, tx_clk_num), emac_mii_iomux_pins.clk_tx, true), + TAG, "invalid TX_CLK GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, tx_en_num), emac_mii_iomux_pins.tx_en, false), + TAG, "invalid TX_EN GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd0_num), emac_mii_iomux_pins.txd0, false), + TAG, "invalid TXD0 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd1_num), emac_mii_iomux_pins.txd1, false), + TAG, "invalid TXD1 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd2_num), emac_mii_iomux_pins.txd2, false), + TAG, "invalid TXD2 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, txd3_num), emac_mii_iomux_pins.txd3, false), + TAG, "invalid TXD3 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rx_clk_num), emac_mii_iomux_pins.clk_rx, true), + TAG, "invalid RX_CLK GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rx_dv_num), emac_mii_iomux_pins.rx_dv, true), + TAG, "invalid RX_DV GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd0_num), emac_mii_iomux_pins.rxd0, true), + TAG, "invalid RXD0 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd1_num), emac_mii_iomux_pins.rxd1, true), + TAG, "invalid RXD1 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd2_num), emac_mii_iomux_pins.rxd2, true), + TAG, "invalid RXD2 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, rxd3_num), emac_mii_iomux_pins.rxd3, true), + TAG, "invalid RXD3 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, col_in_num), emac_mii_iomux_pins.col_in, true), + TAG, "invalid COL_IN GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(mii_gpio, crs_in_num), emac_mii_iomux_pins.crs_in, true), + TAG, "invalid CRS_IN GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_rmii_clk_input(int num) +{ + ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clki != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII CLKI IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.clki, true), TAG, "invalid RMII CLK input GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_rmii_clk_ouput(int num) +{ + ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clko != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII CLKO IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.clko, false), TAG, "invalid RMII CLK output GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_init_rmii(const eth_mac_rmii_gpio_config_t *rmii_gpio) +{ + ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.clki != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, tx_en_num), emac_rmii_iomux_pins.tx_en, false), + TAG, "invalid TX_EN GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, txd0_num), emac_rmii_iomux_pins.txd0, false), + TAG, "invalid TXD0 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, txd1_num), emac_rmii_iomux_pins.txd1, false), + TAG, "invalid TXD1 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, crs_dv_num), emac_rmii_iomux_pins.crs_dv, true), + TAG,"invalid CRS_DV GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, rxd0_num), emac_rmii_iomux_pins.rxd0, true), + TAG,"invalid RXD0 GPIO number"); + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(GET_GPIO_OR_SINGLE(rmii_gpio, rxd1_num), emac_rmii_iomux_pins.rxd1, true), + TAG,"invalid RXD1 GPIO number"); + + return ESP_OK; +} + +esp_err_t emac_esp_iomux_rmii_init_tx_er(int num) +{ + ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.tx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII TX_ER IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.tx_er, false), TAG, "invalid TX_ER GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_rmii_init_rx_er(int num) +{ + ESP_RETURN_ON_FALSE(emac_rmii_iomux_pins.rx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII RX_ER IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_rmii_iomux_pins.rx_er, true), TAG, "invalid RX_ER GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_mii_init_tx_er(int num) +{ + ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.tx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support MII TX_ER IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_mii_iomux_pins.tx_er, false), TAG, "invalid TX_ER GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_iomux_mii_init_rx_er(int num) +{ + ESP_RETURN_ON_FALSE(emac_mii_iomux_pins.rx_er != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "target does not support RMII RX_ER IOMUX"); + + ESP_RETURN_ON_ERROR(emac_esp_iomux_init(num, emac_mii_iomux_pins.rx_er, true), TAG, "invalid RX_ER GPIO number"); + return ESP_OK; +} + +esp_err_t emac_esp_gpio_deinit_all(void) +{ + for (int gpio_num = 0; gpio_num < 64; gpio_num++) { + if (BIT64(gpio_num) & s_emac_esp_used_gpio_mask) { + gpio_reset_pin(gpio_num); + esp_gpio_revoke(BIT64(gpio_num)); + } + s_emac_esp_used_gpio_mask &= ~BIT64(gpio_num); + } + return ESP_OK; +} diff --git a/components/esp_eth/src/esp_eth_mac_openeth.c b/components/esp_eth/src/openeth/esp_eth_mac_openeth.c similarity index 99% rename from components/esp_eth/src/esp_eth_mac_openeth.c rename to components/esp_eth/src/openeth/esp_eth_mac_openeth.c index 60241c8f7e4..0cf8d914423 100644 --- a/components/esp_eth/src/esp_eth_mac_openeth.c +++ b/components/esp_eth/src/openeth/esp_eth_mac_openeth.c @@ -21,12 +21,12 @@ #include "esp_log.h" #include "esp_check.h" #include "esp_cpu.h" -#include "esp_eth_driver.h" #include "esp_intr_alloc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "openeth.h" #include "esp_mac.h" +#include "esp_eth_mac_openeth.h" static const char *TAG = "opencores.emac"; diff --git a/components/esp_eth/src/esp_openeth.h b/components/esp_eth/src/openeth/esp_openeth.h similarity index 92% rename from components/esp_eth/src/esp_openeth.h rename to components/esp_eth/src/openeth/esp_openeth.h index f4d10ea3b85..5eb13d57776 100644 --- a/components/esp_eth/src/esp_openeth.h +++ b/components/esp_eth/src/openeth/esp_openeth.h @@ -11,7 +11,7 @@ #if CONFIG_IDF_TARGET_ESP32C3 /** - * @brief Since ESP32-C3 target in QEMU doesn't support Wifi, re-use its interrupt source for ethernet + * @brief Since ESP32-C3 target in QEMU doesn't support Wifi, reuse its interrupt source for ethernet */ #define ETS_ETH_MAC_INTR_SOURCE ETS_WIFI_MAC_INTR_SOURCE diff --git a/components/esp_eth/src/openeth.h b/components/esp_eth/src/openeth/openeth.h similarity index 99% rename from components/esp_eth/src/openeth.h rename to components/esp_eth/src/openeth/openeth.h index da1e25a0d5d..70a4c9d8209 100644 --- a/components/esp_eth/src/openeth.h +++ b/components/esp_eth/src/openeth/openeth.h @@ -114,7 +114,7 @@ extern "C" { typedef struct { uint16_t cs: 1; //!< Carrier sense lost (flag set by HW) uint16_t df: 1; //!< Defer indication (flag set by HW) - uint16_t lc: 1; //!< Late collision occured (flag set by HW) + uint16_t lc: 1; //!< Late collision occurred (flag set by HW) uint16_t rl: 1; //!< TX failed due to retransmission limit (flag set by HW) uint16_t rtry: 4; //!< Number of retries before the frame was sent (set by HW) uint16_t ur: 1; //!< Underrun status (flag set by HW) diff --git a/components/esp_eth/src/esp_eth_phy_802_3.c b/components/esp_eth/src/phy/esp_eth_phy_802_3.c similarity index 100% rename from components/esp_eth/src/esp_eth_phy_802_3.c rename to components/esp_eth/src/phy/esp_eth_phy_802_3.c diff --git a/components/esp_eth/src/esp_eth_phy_dp83848.c b/components/esp_eth/src/phy/esp_eth_phy_dp83848.c similarity index 100% rename from components/esp_eth/src/esp_eth_phy_dp83848.c rename to components/esp_eth/src/phy/esp_eth_phy_dp83848.c diff --git a/components/esp_eth/src/esp_eth_phy_ip101.c b/components/esp_eth/src/phy/esp_eth_phy_ip101.c similarity index 99% rename from components/esp_eth/src/esp_eth_phy_ip101.c rename to components/esp_eth/src/phy/esp_eth_phy_ip101.c index c9a187d690a..e66fb78b93e 100644 --- a/components/esp_eth/src/esp_eth_phy_ip101.c +++ b/components/esp_eth/src/phy/esp_eth_phy_ip101.c @@ -62,7 +62,7 @@ typedef union { */ typedef union { struct { - uint32_t op_mode : 3; /* Operation Mode Idicator */ + uint32_t op_mode : 3; /* Operation Mode Indicator */ uint32_t force_mdix : 1; /* Force the MDIX channel to be selected */ uint32_t reserved1 : 4; /* Reserved */ uint32_t link_up : 1; /* Indicate the link status is OK or FAIL */ diff --git a/components/esp_eth/src/esp_eth_phy_ksz80xx.c b/components/esp_eth/src/phy/esp_eth_phy_ksz80xx.c similarity index 100% rename from components/esp_eth/src/esp_eth_phy_ksz80xx.c rename to components/esp_eth/src/phy/esp_eth_phy_ksz80xx.c diff --git a/components/esp_eth/src/esp_eth_phy_lan87xx.c b/components/esp_eth/src/phy/esp_eth_phy_lan87xx.c similarity index 100% rename from components/esp_eth/src/esp_eth_phy_lan87xx.c rename to components/esp_eth/src/phy/esp_eth_phy_lan87xx.c diff --git a/components/esp_eth/src/esp_eth_phy_rtl8201.c b/components/esp_eth/src/phy/esp_eth_phy_rtl8201.c similarity index 100% rename from components/esp_eth/src/esp_eth_phy_rtl8201.c rename to components/esp_eth/src/phy/esp_eth_phy_rtl8201.c diff --git a/components/esp_eth/src/dm9051.h b/components/esp_eth/src/spi/dm9051/dm9051.h similarity index 100% rename from components/esp_eth/src/dm9051.h rename to components/esp_eth/src/spi/dm9051/dm9051.h diff --git a/components/esp_eth/src/esp_eth_mac_dm9051.c b/components/esp_eth/src/spi/dm9051/esp_eth_mac_dm9051.c similarity index 99% rename from components/esp_eth/src/esp_eth_mac_dm9051.c rename to components/esp_eth/src/spi/dm9051/esp_eth_mac_dm9051.c index 4ae68ba9a59..6e892b38b78 100644 --- a/components/esp_eth/src/esp_eth_mac_dm9051.c +++ b/components/esp_eth/src/spi/dm9051/esp_eth_mac_dm9051.c @@ -8,12 +8,12 @@ #include #include #include +#include "esp_eth_mac_spi.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "esp_attr.h" #include "esp_log.h" #include "esp_check.h" -#include "esp_eth_driver.h" #include "esp_timer.h" #include "esp_system.h" #include "esp_intr_alloc.h" diff --git a/components/esp_eth/src/esp_eth_phy_dm9051.c b/components/esp_eth/src/spi/dm9051/esp_eth_phy_dm9051.c similarity index 99% rename from components/esp_eth/src/esp_eth_phy_dm9051.c rename to components/esp_eth/src/spi/dm9051/esp_eth_phy_dm9051.c index 6db49f8fad0..4e0507f1e18 100644 --- a/components/esp_eth/src/esp_eth_phy_dm9051.c +++ b/components/esp_eth/src/spi/dm9051/esp_eth_phy_dm9051.c @@ -67,7 +67,7 @@ typedef union { uint32_t monsel1 : 1; /* Vendor monitor select */ uint32_t mdix_down : 1; /* Set 1 to disable HP Auto-MDIX */ uint32_t mdix_fix : 1; /* When mdix_down = 1, MDIX_CNTL value depend on the register value. */ - uint32_t autoneg_lpbk : 1; /* Set 1 to enable autonegotioation loopback */ + uint32_t autoneg_lpbk : 1; /* Set 1 to enable autonegotiation loopback */ uint32_t mdxi_cntl : 1; /* Polarity of MDI/MDIX value */ uint32_t reserved2 : 1; /* Reserved */ uint32_t nway_pwr : 1; /* Set 1 to enable power savings during autonegotiation period */ @@ -195,7 +195,7 @@ static esp_err_t dm9051_loopback(esp_eth_phy_t *phy, bool enable) phy_802_3_t *phy_802_3 = esp_eth_phy_into_phy_802_3(phy); esp_eth_mediator_t *eth = phy_802_3->eth; /* Set Loopback function */ - // Enable Auto-negotiation loopback in Speficic control register + // Enable Auto-negotiation loopback in Specific control register bmcr_reg_t bmcr; scr_reg_t scr; ESP_GOTO_ON_ERROR(eth->phy_reg_read(eth, phy_802_3->addr, ETH_PHY_BMCR_REG_ADDR, &(bmcr.val)), err, TAG, "read BMCR failed"); diff --git a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c b/components/esp_eth/src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c similarity index 99% rename from components/esp_eth/src/esp_eth_mac_ksz8851snl.c rename to components/esp_eth/src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c index 76fa5d99874..ae0b60f8818 100644 --- a/components/esp_eth/src/esp_eth_mac_ksz8851snl.c +++ b/components/esp_eth/src/spi/ksz8851snl/esp_eth_mac_ksz8851snl.c @@ -8,6 +8,7 @@ #include #include +#include "esp_eth_mac_spi.h" #include "esp_log.h" #include "esp_check.h" #include "esp_cpu.h" @@ -17,7 +18,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" -#include "esp_eth_driver.h" #include "ksz8851.h" #include "esp_timer.h" diff --git a/components/esp_eth/src/esp_eth_phy_ksz8851snl.c b/components/esp_eth/src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c similarity index 99% rename from components/esp_eth/src/esp_eth_phy_ksz8851snl.c rename to components/esp_eth/src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c index d520000bd65..cbec083a0cc 100644 --- a/components/esp_eth/src/esp_eth_phy_ksz8851snl.c +++ b/components/esp_eth/src/spi/ksz8851snl/esp_eth_phy_ksz8851snl.c @@ -6,6 +6,7 @@ * SPDX-FileContributor: 2021-2024 Espressif Systems (Shanghai) CO LTD */ #include +#include "esp_eth_phy.h" #include "esp_check.h" #include "esp_heap_caps.h" #include "esp_log.h" @@ -13,7 +14,6 @@ #include "esp_rom_gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp_eth_driver.h" #include "ksz8851.h" @@ -149,7 +149,7 @@ static esp_err_t phy_ksz8851_deinit(esp_eth_phy_t *phy) /** * @note This function is responsible for restarting a new auto-negotiation, - * the result of negotiation won't be relected to uppler layers. + * the result of negotiation won't be reflected to upper layers. * Instead, the negotiation result is fetched by linker timer, see `phy_ksz8851_get_link()` */ static esp_err_t phy_ksz8851_autonego_ctrl(esp_eth_phy_t *phy, eth_phy_autoneg_cmd_t cmd, bool *autonego_en_stat) diff --git a/components/esp_eth/src/ksz8851.h b/components/esp_eth/src/spi/ksz8851snl/ksz8851.h similarity index 95% rename from components/esp_eth/src/ksz8851.h rename to components/esp_eth/src/spi/ksz8851snl/ksz8851.h index 44c1087b6c5..02b2a4e3559 100644 --- a/components/esp_eth/src/ksz8851.h +++ b/components/esp_eth/src/spi/ksz8851snl/ksz8851.h @@ -1,22 +1,11 @@ -// Copyright (c) 2021 Vladimir Chistyakov -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. +/* + * SPDX-FileCopyrightText: 2021 Vladimir Chistyakov + * + * SPDX-License-Identifier: MIT + * + * SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD + */ + #pragma once @@ -314,7 +303,7 @@ typedef enum { P1ANAR_ADV_10_HALF = 0x0020U, ///< RW Adv 10 Half P1ANLPR_NEXT_PAGE = 0x8000U, ///< RO Next page (not supported) - P1ANLPR_LP_ACK = 0x4000U, ///< RO LP ACK (not suppported) + P1ANLPR_LP_ACK = 0x4000U, ///< RO LP ACK (not supported) P1ANLPR_REMOTE_FAULT = 0x2000U, ///< RO Remote fault (not supported) P1ANLPR_PAUSE = 0x0400U, ///< RO Pause P1ANLPR_ADV_100_FULL = 0x0100U, ///< RO Adv 100 Full diff --git a/components/esp_eth/src/esp_eth_mac_w5500.c b/components/esp_eth/src/spi/w5500/esp_eth_mac_w5500.c similarity index 99% rename from components/esp_eth/src/esp_eth_mac_w5500.c rename to components/esp_eth/src/spi/w5500/esp_eth_mac_w5500.c index 89558516036..2f0ea028fe7 100644 --- a/components/esp_eth/src/esp_eth_mac_w5500.c +++ b/components/esp_eth/src/spi/w5500/esp_eth_mac_w5500.c @@ -7,12 +7,12 @@ #include #include #include +#include "esp_eth_mac_spi.h" #include "driver/gpio.h" #include "driver/spi_master.h" #include "esp_attr.h" #include "esp_log.h" #include "esp_check.h" -#include "esp_eth_driver.h" #include "esp_system.h" #include "esp_intr_alloc.h" #include "esp_heap_caps.h" @@ -550,7 +550,7 @@ static esp_err_t emac_w5500_enable_flow_ctrl(esp_eth_mac_t *mac, bool enable) static esp_err_t emac_w5500_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t ability) { - /* w5500 doesn't suppport PAUSE function, so accept any value */ + /* w5500 doesn't support PAUSE function, so accept any value */ return ESP_ERR_NOT_SUPPORTED; } @@ -823,7 +823,7 @@ static esp_err_t emac_w5500_init(esp_eth_mac_t *mac) /* reset w5500 */ ESP_GOTO_ON_ERROR(w5500_reset(emac), err, TAG, "reset w5500 failed"); /* verify chip id */ - ESP_GOTO_ON_ERROR(w5500_verify_id(emac), err, TAG, "vefiry chip ID failed"); + ESP_GOTO_ON_ERROR(w5500_verify_id(emac), err, TAG, "verify chip ID failed"); /* default setup of internal registers */ ESP_GOTO_ON_ERROR(w5500_setup_default(emac), err, TAG, "w5500 default setup failed"); return ESP_OK; diff --git a/components/esp_eth/src/esp_eth_phy_w5500.c b/components/esp_eth/src/spi/w5500/esp_eth_phy_w5500.c similarity index 99% rename from components/esp_eth/src/esp_eth_phy_w5500.c rename to components/esp_eth/src/spi/w5500/esp_eth_phy_w5500.c index d211681c1c1..834cf54088f 100644 --- a/components/esp_eth/src/esp_eth_phy_w5500.c +++ b/components/esp_eth/src/spi/w5500/esp_eth_phy_w5500.c @@ -6,9 +6,9 @@ #include #include #include +#include "esp_eth_phy.h" #include "esp_log.h" #include "esp_check.h" -#include "esp_eth_driver.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" diff --git a/components/esp_eth/src/w5500.h b/components/esp_eth/src/spi/w5500/w5500.h similarity index 100% rename from components/esp_eth/src/w5500.h rename to components/esp_eth/src/spi/w5500/w5500.h diff --git a/components/esp_eth/test_apps/main/CMakeLists.txt b/components/esp_eth/test_apps/main/CMakeLists.txt index a1c785ae45a..ff51914b322 100644 --- a/components/esp_eth/test_apps/main/CMakeLists.txt +++ b/components/esp_eth/test_apps/main/CMakeLists.txt @@ -5,6 +5,6 @@ idf_component_register(SRCS "esp_eth_test_apps.c" "esp_eth_test_main.c" INCLUDE_DIRS "." PRIV_INCLUDE_DIRS "." - PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client + PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client esp_driver_gpio EMBED_TXTFILES dl_espressif_com_root_cert.pem WHOLE_ARCHIVE) diff --git a/components/esp_eth/test_apps/main/esp_eth_test_common.c b/components/esp_eth/test_apps/main/esp_eth_test_common.c index 2e366d12b6f..4876307b863 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_common.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_common.c @@ -36,15 +36,15 @@ esp_eth_mac_t *mac_init(void *vendor_emac_config, eth_mac_config_t *mac_config) #if CONFIG_TARGET_USE_INTERNAL_ETHERNET eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); #if !CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG - esp32_emac_config.smi_mdc_gpio_num = CONFIG_TARGET_IO_MDC; - esp32_emac_config.smi_mdio_gpio_num = CONFIG_TARGET_IO_MDIO; + esp32_emac_config.smi_gpio.mdc_num = CONFIG_TARGET_IO_MDC; + esp32_emac_config.smi_gpio.mdio_num = CONFIG_TARGET_IO_MDIO; #endif // CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG if (vendor_emac_config == NULL) { vendor_emac_config = &esp32_emac_config; } mac = esp_eth_mac_new_esp32(vendor_emac_config, mac_config); #elif CONFIG_TARGET_USE_SPI_ETHERNET - // Install GPIO ISR handler to be able to service SPI Eth modlues interrupts + // Install GPIO ISR handler to be able to service SPI Eth modules interrupts gpio_install_isr_service(0); spi_bus_config_t buscfg = { diff --git a/components/esp_eth/test_apps/main/esp_eth_test_esp_emac.c b/components/esp_eth/test_apps/main/esp_eth_test_esp_emac.c index 43cfa34897d..5056c864825 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_esp_emac.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_esp_emac.c @@ -9,10 +9,11 @@ #include "freertos/event_groups.h" #include "esp_log.h" #include "esp_eth_test_common.h" +#include "hal/emac_hal.h" // for MAC_HAL_TDES0_* control bits -#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via emac_hal_transmit_frame -#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers) -#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via emac_hal_transmit_multiple_buf_frame (3 buffers) +#define ETHERTYPE_TX_STD 0x2222 // frame transmitted via _transmit_frame +#define ETHERTYPE_TX_MULTI_2 0x2223 // frame transmitted via _transmit_multiple_buf_frame (2 buffers) +#define ETHERTYPE_TX_MULTI_3 0x2224 // frame transmitted via _transmit_multiple_buf_frame (3 buffers) #define MINIMUM_TEST_FRAME_SIZE 64 @@ -36,12 +37,12 @@ static esp_err_t eth_recv_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffe ESP_LOGI(TAG, "recv frame size: %" PRIu16, expected_size); TEST_ASSERT_EQUAL(expected_size, length); - // frame transmitted via emac_hal_transmit_frame + // frame transmitted via _transmit_frame if (pkt->proto == ETHERTYPE_TX_STD) { for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) { TEST_ASSERT_EQUAL(pkt->data[i], i & 0xFF); } - // frame transmitted via emac_hal_transmit_multiple_buf_frame (2 buffers) + // frame transmitted via _multiple_buf_frame (2 buffers) } else if (pkt->proto == ETHERTYPE_TX_MULTI_2) { uint8_t *data_p = pkt->data; for (int i = 0; i < recv_info->expected_size - ETH_HEADER_LEN; i++) { @@ -357,15 +358,17 @@ TEST_CASE("internal emac interrupt priority", "[esp_emac]") vEventGroupDelete(eth_event_group); } -#if CONFIG_IDF_TARGET_ESP32P4 // IDF-8993 -#include "hal/emac_hal.h" -#include "hal/emac_ll.h" -#include "soc/emac_mac_struct.h" -static esp_err_t eth_recv_err_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv) +#define TEST_FRAMES_NUM CONFIG_ETH_DMA_RX_BUFFER_NUM + +static uint8_t *s_recv_frames[TEST_FRAMES_NUM]; +static uint8_t s_recv_frames_cnt = 0; + +static esp_err_t eth_recv_esp_emac_err_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv) { SemaphoreHandle_t mutex = (SemaphoreHandle_t)priv; - free(buffer); - xSemaphoreGive(mutex); + s_recv_frames[s_recv_frames_cnt++] = buffer; + if (s_recv_frames_cnt >= TEST_FRAMES_NUM) + xSemaphoreGive(mutex); return ESP_OK; } @@ -394,7 +397,7 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]") bool loopback_en = true; esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en); - TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_err_esp_emac_check_cb, mutex)); + TEST_ESP_OK(esp_eth_update_input_path(eth_handle, eth_recv_esp_emac_err_check_cb, mutex)); // start the driver TEST_ESP_OK(esp_eth_start(eth_handle)); @@ -413,23 +416,96 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]") TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, local_mac_addr)); memcpy(test_pkt->src, local_mac_addr, ETH_ADDR_LEN); // fill with data - for (int i = 0; i < ETH_MAX_PAYLOAD_LEN; i++) { + int i; + for (i = 1; i < ETH_MAX_PAYLOAD_LEN; i++) { test_pkt->data[i] = i & 0xFF; } - emac_ll_checksum_offload_mode(&EMAC_MAC, ETH_CHECKSUM_SW); + size_t transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE; + uint8_t frame_id = 0; - size_t transmit_size = 1072; - TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size)); + ESP_LOGI(TAG, "Verify non-failure frame condition"); + for (i = 1; i <= TEST_FRAMES_NUM; i++) { + test_pkt->data[0] = frame_id++; + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size)); + // if we have only 10 or less Rx buffers, they can be all used pretty fast => wait to be freed prior next Tx + if (CONFIG_ETH_DMA_RX_BUFFER_NUM <= 10 && !(i % (CONFIG_ETH_DMA_RX_BUFFER_NUM / 2))) { + ESP_LOGI(TAG, "wait prior Tx (frame num %i)", i); + vTaskDelay(10); + } + } + ESP_LOGI(TAG, "num of sent frames: %d", TEST_FRAMES_NUM); TEST_ASSERT(xSemaphoreTake(mutex, pdMS_TO_TICKS(500))); + ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt); - free(test_pkt); + for (i = 0; i < s_recv_frames_cnt; i++) { + emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i]; + ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]); + free(recv_frame); + } + TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM, s_recv_frames_cnt); + s_recv_frames_cnt = 0; + + printf("\n"); + ESP_LOGI(TAG, "Verify failure condition when every second frame has invalid CRC"); + uint32_t emac_tx_dbg_flag = EMAC_HAL_TDES0_CRC_APPEND_DISABLE; + for (i = 1; i <= TEST_FRAMES_NUM; i++) { + test_pkt->data[0] = frame_id++; + // make every 2nd frame invalid + if (!(i % 2)) { + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_SET_TDES0_CFG_BITS, &emac_tx_dbg_flag)); + } + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size)); + if (!(i % 2)) { + TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_CLEAR_TDES0_CFG_BITS, &emac_tx_dbg_flag)); + } + } + ESP_LOGI(TAG, "num of sent frames: %d (every 2nd invalid)", TEST_FRAMES_NUM); + TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500))); + ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt); + + for (i = 0; i < s_recv_frames_cnt; i++) { + emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i]; + ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]); + free(recv_frame); + } + TEST_ASSERT_EQUAL_UINT8(TEST_FRAMES_NUM / 2, s_recv_frames_cnt); + s_recv_frames_cnt = 0; + + ESP_LOGI(TAG, "Verify full Rx DMA failure condition"); + // suspend ETH Rx task so the DMA is filled + vTaskSuspend(xTaskGetHandle("emac_rx")); + transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE - 4; // -4 bytes to the frame fit into one descriptor even with CRC + // fill the descriptors, keep one free + for (i = 1; i <= CONFIG_ETH_DMA_RX_BUFFER_NUM - 1; i++) { + test_pkt->data[0] = frame_id++; + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size)); + vTaskDelay(1); // to prevent "insufficient TX buffer size" error + } + transmit_size = CONFIG_ETH_DMA_BUFFER_SIZE; // now, we will need 2 descriptors to store the frame (with CRC) but only one is free + test_pkt->data[0] = frame_id++; + TEST_ESP_OK(esp_eth_transmit(eth_handle, test_pkt, transmit_size)); + vTaskDelay(50); + vTaskResume(xTaskGetHandle("emac_rx")); + + ESP_LOGI(TAG, "num of sent frames: %d", i); + TEST_ASSERT_FALSE(xSemaphoreTake(mutex, pdMS_TO_TICKS(500))); + ESP_LOGI(TAG, "num of recv frames: %d", s_recv_frames_cnt); + + for (i = 0; i < s_recv_frames_cnt; i++) { + emac_frame_t *recv_frame = (emac_frame_t *)s_recv_frames[i]; + ESP_LOGI(TAG, "recv frame id %" PRIu8, recv_frame->data[0]); + free(recv_frame); + } + TEST_ASSERT_EQUAL_INT(CONFIG_ETH_DMA_RX_BUFFER_NUM - 1, s_recv_frames_cnt); // one frame is missing due to "Descriptor Error" + s_recv_frames_cnt = 0; // stop Ethernet driver TEST_ESP_OK(esp_eth_stop(eth_handle)); - /* wait for connection stop */ + // wait for connection stop bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS)); TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT); + free(test_pkt); TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle)); TEST_ESP_OK(phy->del(phy)); TEST_ESP_OK(mac->del(mac)); @@ -439,4 +515,3 @@ TEST_CASE("internal emac erroneous frames", "[esp_emac]") vEventGroupDelete(eth_event_group); vSemaphoreDelete(mutex); } -#endif diff --git a/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults b/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults index c439354b15d..d5365ebde97 100644 --- a/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults +++ b/components/esp_netif/test_apps/test_app_vfs_l2tap/sdkconfig.defaults @@ -1,5 +1,7 @@ CONFIG_UNITY_ENABLE_FIXTURE=y CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y +CONFIG_ETH_USE_ESP32_EMAC=y + CONFIG_ESP_NETIF_L2_TAP=y CONFIG_LWIP_CHECK_THREAD_SAFETY=y diff --git a/components/hal/esp32/include/hal/emac_ll.h b/components/hal/esp32/include/hal/emac_ll.h index b66730acfff..c858552fb27 100644 --- a/components/hal/esp32/include/hal/emac_ll.h +++ b/components/hal/esp32/include/hal/emac_ll.h @@ -437,6 +437,11 @@ static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, b dma_regs->dmaoperation_mode.rx_store_forward = enable; } +static inline bool emac_ll_recv_store_forward_is_enabled(emac_dma_dev_t *dma_regs) +{ + return dma_regs->dmaoperation_mode.rx_store_forward; +} + static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable) { dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable; diff --git a/components/hal/esp32p4/include/hal/emac_ll.h b/components/hal/esp32p4/include/hal/emac_ll.h index 1f72c86177a..6f7e484edf1 100644 --- a/components/hal/esp32p4/include/hal/emac_ll.h +++ b/components/hal/esp32p4/include/hal/emac_ll.h @@ -411,6 +411,11 @@ static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, b dma_regs->dmaoperation_mode.rx_store_forward = enable; } +static inline bool emac_ll_recv_store_forward_is_enabled(emac_dma_dev_t *dma_regs) +{ + return dma_regs->dmaoperation_mode.rx_store_forward; +} + static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable) { dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable; diff --git a/components/hal/include/hal/emac_hal.h b/components/hal/include/hal/emac_hal.h index 2b0a1273ea6..70b5e86478b 100644 --- a/components/hal/include/hal/emac_hal.h +++ b/components/hal/include/hal/emac_hal.h @@ -6,8 +6,6 @@ #pragma once - - #include #include #include "esp_assert.h" @@ -29,15 +27,28 @@ extern "C" { #if CONFIG_IDF_TARGET_ESP32P4 // Descriptor must be 64B aligned for ESP32P4 due to cache arrangement -#define DMA_DESC_SIZE 64 -// ESP32P4 EMAC interface clock configuration is shared among other modules in registers -#define EMAC_IF_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define EMAC_HAL_DMA_DESC_SIZE (64) #else -#define DMA_DESC_SIZE 32 -#define EMAC_IF_RCC_ATOMIC() +#define EMAC_HAL_DMA_DESC_SIZE (32) #endif +/* DMA descriptor control bits */ +#define EMAC_HAL_TDES0_INTR_ON_COMPLET (1 << 30) +#define EMAC_HAL_TDES0_CRC_APPEND_DISABLE (1 << 27) +#define EMAC_HAL_TDES0_PAD_DISABLE (1 << 26) +#define EMAC_HAL_TDES0_TX_TS_ENABLE (1 << 25) +#define EMAC_HAL_TDES0_CRC_REPLACE_CTRL (1 << 24) +#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR (1 << 22) +#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR_PAYLOAD (2 << 22) +#define EMAC_HAL_TDES0_IP_CRC_INSERT_HDR_PAYLOAD_PSEUDO (3 << 22) +#define EMAC_HAL_TDES0_VLAN_REMOVE (1 << 18) +#define EMAC_HAL_TDES0_VLAN_INSERT (2 << 18) +#define EMAC_HAL_TDES0_VLAN_REPLACE (3 << 18) + +#define EMAC_HAL_TDES0_IP_CRC_INSERT_DISABLE_MASK (3 << 22) +#define EMAC_HAL_TDES0_VLAN_INSERT_DISABLE_MASK (3 << 18) + /** * @brief Ethernet DMA TX Descriptor * @@ -65,7 +76,7 @@ typedef struct { uint32_t TransmitEndRing : 1; /*!< Descriptor list reached its final descriptor */ uint32_t ChecksumInsertControl : 2; /*!< Control checksum calculation and insertion */ uint32_t CRCReplacementControl : 1; /*!< Control CRC replace */ - uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 harware timestamping */ + uint32_t TransmitTimestampEnable : 1; /*!< Enable IEEE1588 hardware timestamping */ uint32_t DisablePad : 1; /*!< Control add padding when frame short than 64 bytes */ uint32_t DisableCRC : 1; /*!< Control append CRC to the end of frame */ uint32_t FirstSegment : 1; /*!< Buffer contains the first segment of a frame */ @@ -91,25 +102,12 @@ typedef struct { uint32_t TimeStampLow; /*!< Transmit Frame Timestamp Low */ uint32_t TimeStampHigh; /*!< Transmit Frame Timestamp High */ -#if CONFIG_IDF_TARGET_ESP32P4 -// TODO: must be 64B aligned for ESP32P4 (due to cache arrangement) -// Could be better optimized (EMAC DMA block supports 32/64/128)? - uint32_t Reserved8; - uint32_t Reserved9; - uint32_t Reserved10; - uint32_t Reserved11; - uint32_t Reserved12; - uint32_t Reserved13; - uint32_t Reserved14; - uint32_t Reserved15; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + // descriptor must be aligned (due to cache arrangement) + uint8_t CacheAlign[EMAC_HAL_DMA_DESC_SIZE - 32]; // 32 is size of EMAC DMA descriptor without alignment #endif } eth_dma_tx_descriptor_t; -#define EMAC_DMATXDESC_CHECKSUM_BYPASS 0 /*!< Checksum engine bypass */ -#define EMAC_DMATXDESC_CHECKSUM_IPV4HEADER 1 /*!< IPv4 header checksum insertion */ -#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPSEGMENT 2 /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */ -#define EMAC_DMATXDESC_CHECKSUM_TCPUDPICMPFULL 3 /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */ - -ASSERT_TYPE_SIZE(eth_dma_tx_descriptor_t, DMA_DESC_SIZE); +ASSERT_TYPE_SIZE(eth_dma_tx_descriptor_t, EMAC_HAL_DMA_DESC_SIZE); /** * @brief Ethernet DMA RX Descriptor @@ -182,21 +180,13 @@ typedef struct { uint32_t TimeStampLow; /*!< Receive frame timestamp low */ uint32_t TimeStampHigh; /*!< Receive frame timestamp high */ -#if CONFIG_IDF_TARGET_ESP32P4 -// TODO: must be 64B aligned for ESP32P4 (due to cache arrangement) -// Could be better optimized (EMAC DMA block supports 32/64/128)? - uint32_t Reserved8; - uint32_t Reserved9; - uint32_t Reserved10; - uint32_t Reserved11; - uint32_t Reserved12; - uint32_t Reserved13; - uint32_t Reserved14; - uint32_t Reserved15; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + // descriptor must be aligned (due to cache arrangement) + uint8_t CacheAlign[EMAC_HAL_DMA_DESC_SIZE - 32]; // 32 is size of EMAC DMA descriptor without alignment #endif } eth_dma_rx_descriptor_t; -ASSERT_TYPE_SIZE(eth_dma_rx_descriptor_t, DMA_DESC_SIZE); +ASSERT_TYPE_SIZE(eth_dma_rx_descriptor_t, EMAC_HAL_DMA_DESC_SIZE); typedef struct emac_mac_dev_s *emac_mac_soc_regs_t; typedef struct emac_dma_dev_s *emac_dma_soc_regs_t; @@ -278,72 +268,10 @@ void emac_hal_start(emac_hal_context_t *hal); * @return * - ESP_OK: succeed * - ESP_ERR_INVALID_STATE: previous frame transmission/reception is not completed. When this error occurs, - * wait and reapeat the EMAC stop again. + * wait and repeat the EMAC stop again. */ esp_err_t emac_hal_stop(emac_hal_context_t *hal); -/** - * @brief Transmit data from buffer over EMAC - * - * @param[in] hal EMAC HAL context infostructure - * @param[in] buf buffer to be transmitted - * @param[in] length length of the buffer - * @return number of transmitted bytes when success - */ -uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length); - -/** - * @brief Transmit data from multiple buffers over EMAC in single Ethernet frame. Data will be joint into - * single frame in order in which the buffers are stored in input array. - * - * @param[in] hal EMAC HAL context infostructure - * @param[in] buffs array of pointers to buffers to be transmitted - * @param[in] lengths array of lengths of the buffers - * @param[in] inbuffs_cnt number of buffers (i.e. input arrays size) - * @return number of transmitted bytes when success - * - * @pre @p lengths array must have the same size as @p buffs array and their elements need to be stored in the same - * order, i.e. lengths[1] is a length assocaited with data buffer referenced at buffs[1] position. - */ -uint32_t emac_hal_transmit_multiple_buf_frame(emac_hal_context_t *hal, uint8_t **buffs, uint32_t *lengths, uint32_t inbuffs_cnt); - -/** - * @brief Allocate buffer with size equal to actually received Ethernet frame size. - * - * @param[in] hal EMAC HAL context infostructure - * @param[in, out] size as an input defines maximum size of buffer to be allocated. As an output, indicates actual size of received - * Ethernet frame which is waiting to be processed. Returned size may be 0 when there is no waiting frame. - * - * @note If maximum allowed size of buffer to be allocated is less than actual size of received Ethernet frame, the buffer - * is allocated with that limit and the frame will be truncated by emac_hal_receive_frame. - * - * @return Pointer to allocated buffer - * NULL when allocation fails or when there is no waiting Ethernet frame - */ -uint8_t *emac_hal_alloc_recv_buf(emac_hal_context_t *hal, uint32_t *size); - -/** - * @brief Copy received Ethernet frame from EMAC DMA memory space to application. - * - * @param[in] hal EMAC HAL context infostructure - * @param[in] buf buffer into which the Ethernet frame is to be copied - * @param[in] size buffer size. When buffer was allocated by ::emac_hal_alloc_recv_buf, this parameter needs to be set - * to EMAC_HAL_BUF_SIZE_AUTO - * @param[out] frames_remain number of frames remaining to be processed - * @param[out] free_desc muber of free DMA Rx descriptors - * - * @return number of copied bytes when success - * 0 when there is no waiting Ethernet frame or on error - * - * @note FCS field is never copied - * @note If buffer size is less than actual size of received Ethernet frame, the frame will be truncated. - * @note When this function is called with EMAC_HAL_BUF_SIZE_AUTO size parameter, buffer needs to be allocated by - * ::emac_hal_alloc_recv_buf function at first. - */ -uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc); - -uint32_t emac_hal_flush_recv_frame(emac_hal_context_t *hal, uint32_t *frames_remain, uint32_t *free_desc); - void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable); #define emac_hal_get_intr_enable_status(hal) emac_ll_get_intr_enable_status((hal)->dma_regs) diff --git a/components/mqtt/test_apps/test_mqtt/main/CMakeLists.txt b/components/mqtt/test_apps/test_mqtt/main/CMakeLists.txt index 7a066248042..0647fe29f13 100644 --- a/components/mqtt/test_apps/test_mqtt/main/CMakeLists.txt +++ b/components/mqtt/test_apps/test_mqtt/main/CMakeLists.txt @@ -5,4 +5,4 @@ if(CONFIG_MQTT_PROTOCOL_5) endif() idf_component_register(SRCS "${srcs}" - PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update esp_eth esp_netif spi_flash common) + PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common) diff --git a/components/mqtt/test_apps/test_mqtt5/main/CMakeLists.txt b/components/mqtt/test_apps/test_mqtt5/main/CMakeLists.txt index f152df9c24a..d33a86ceb8d 100644 --- a/components/mqtt/test_apps/test_mqtt5/main/CMakeLists.txt +++ b/components/mqtt/test_apps/test_mqtt5/main/CMakeLists.txt @@ -1,4 +1,4 @@ set(srcs test_mqtt5_client_broker.c test_mqtt5.c) idf_component_register(SRCS "${srcs}" - PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update esp_eth esp_netif spi_flash common) + PRIV_REQUIRES cmock test_utils mqtt nvs_flash app_update spi_flash common) diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 6f64fe017e2..0c3f4ed0bd5 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -39,6 +39,10 @@ if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED) list(APPEND srcs "${target_folder}/dedic_gpio_periph.c") endif() +if(CONFIG_SOC_EMAC_SUPPORTED) + list(APPEND srcs "${target_folder}/emac_periph.c") +endif() + if(CONFIG_SOC_GDMA_SUPPORTED) list(APPEND srcs "${target_folder}/gdma_periph.c") endif() diff --git a/components/soc/esp32/emac_periph.c b/components/soc/esp32/emac_periph.c new file mode 100644 index 00000000000..a3332701159 --- /dev/null +++ b/components/soc/esp32/emac_periph.c @@ -0,0 +1,224 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "soc/emac_periph.h" +#include "soc/io_mux_reg.h" + +const emac_io_info_t emac_io_idx = { + .mdc_idx = EMAC_MDC_O_IDX, + .mdo_idx = EMAC_MDO_O_IDX, + .mdi_idx = EMAC_MDI_I_IDX, + .mii_tx_clk_i_idx = SIG_GPIO_OUT_IDX, // indicates EMAC signal cannot be connected via GPIO Matrix on the target + .mii_tx_en_o_idx = SIG_GPIO_OUT_IDX, + .mii_txd0_o_idx = SIG_GPIO_OUT_IDX, + .mii_txd1_o_idx = SIG_GPIO_OUT_IDX, + .mii_txd2_o_idx = SIG_GPIO_OUT_IDX, + .mii_txd3_o_idx = SIG_GPIO_OUT_IDX, + .mii_rx_clk_i_idx = SIG_GPIO_OUT_IDX, + .mii_rx_dv_i_idx = SIG_GPIO_OUT_IDX, + .mii_rxd0_i_idx = SIG_GPIO_OUT_IDX, + .mii_rxd1_i_idx = SIG_GPIO_OUT_IDX, + .mii_rxd2_i_idx = SIG_GPIO_OUT_IDX, + .mii_rxd3_i_idx = SIG_GPIO_OUT_IDX, + .mii_col_i_idx = SIG_GPIO_OUT_IDX, + .mii_crs_i_idx = SIG_GPIO_OUT_IDX, + .mii_tx_er_o_idx = SIG_GPIO_OUT_IDX, + .mii_rx_er_i_idx = SIG_GPIO_OUT_IDX +}; + +static const emac_iomux_info_t emac_rmii_iomux_clki[] = { + [0] = { + .gpio_num = 0, + .func = FUNC_GPIO0_EMAC_TX_CLK, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, // indicates end of list + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_clko[] = { + [0] = { + .gpio_num = 16, + .func = FUNC_GPIO16_EMAC_CLK_OUT, + }, + [1] = { + .gpio_num = 17, + .func = FUNC_GPIO17_EMAC_CLK_OUT_180, + }, + [2] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_tx_en[] = { + [0] = { + .gpio_num = 21, + .func = FUNC_GPIO21_EMAC_TX_EN, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_txd0[] = { + [0] = { + .gpio_num = 19, + .func = FUNC_GPIO19_EMAC_TXD0, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_txd1[] = { + [0] = { + .gpio_num = 22, + .func = FUNC_GPIO22_EMAC_TXD1, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_crs_dv[] = { + [0] = { + .gpio_num = 27, + .func = FUNC_GPIO27_EMAC_RX_DV, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_rxd0[] = { + [0] = { + .gpio_num = 25, + .func = FUNC_GPIO25_EMAC_RXD0, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_rxd1[] = { + [0] = { + .gpio_num = 26, + .func = FUNC_GPIO26_EMAC_RXD1, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_tx_er[] = { + [0] = { + .gpio_num = 4, + .func = FUNC_GPIO4_EMAC_TX_ER, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_mii_iomux_rx_er[] = { + [0] = { + .gpio_num = 13, + .func = FUNC_MTCK_EMAC_RX_ER, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +// MII Specific +static const emac_iomux_info_t emac_mii_iomux_clk_tx[] = { + [0] = { + .gpio_num = 0, + .func = FUNC_GPIO0_EMAC_TX_CLK, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_mii_iomux_txd2[] = { + [0] = { + .gpio_num = 14, + .func = FUNC_MTMS_EMAC_TXD2, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_mii_iomux_txd3[] = { + [0] = { + .gpio_num = 12, + .func = FUNC_MTDI_EMAC_TXD3, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_mii_iomux_clk_rx[] = { + [0] = { + .gpio_num = 5, + .func = FUNC_GPIO5_EMAC_RX_CLK, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_mii_iomux_rxd2[] = { + [0] = { + .gpio_num = 1, + .func = FUNC_U0TXD_EMAC_RXD2, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_mii_iomux_rxd3[] = { + [0] = { + .gpio_num = 15, + .func = FUNC_MTDO_EMAC_RXD3, + }, + [1] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +const emac_rmii_iomux_info_t emac_rmii_iomux_pins = { + .clki = emac_rmii_iomux_clki, + .clko = emac_rmii_iomux_clko, + .tx_en = emac_rmii_mii_iomux_tx_en, + .txd0 = emac_rmii_mii_iomux_txd0, + .txd1 = emac_rmii_mii_iomux_txd1, + .crs_dv = emac_rmii_mii_iomux_crs_dv, + .rxd0 = emac_rmii_mii_iomux_rxd0, + .rxd1 = emac_rmii_mii_iomux_rxd1, + .tx_er = emac_rmii_mii_iomux_tx_er, + .rx_er = emac_rmii_mii_iomux_rx_er, +}; + +const emac_mii_iomux_info_t emac_mii_iomux_pins = { + .clk_tx = emac_mii_iomux_clk_tx, + .tx_en = emac_rmii_mii_iomux_tx_en, + .txd0 = emac_rmii_mii_iomux_txd0, + .txd1 = emac_rmii_mii_iomux_txd1, + .txd2 = emac_mii_iomux_txd2, + .txd3 = emac_mii_iomux_txd3, + .clk_rx = emac_mii_iomux_clk_rx, + .rx_dv = emac_rmii_mii_iomux_crs_dv, + .rxd0 = emac_rmii_mii_iomux_rxd0, + .rxd1 = emac_rmii_mii_iomux_rxd1, + .rxd2 = emac_mii_iomux_rxd2, + .rxd3 = emac_mii_iomux_rxd3, + .tx_er = emac_rmii_mii_iomux_tx_er, + .rx_er = emac_rmii_mii_iomux_rx_er, +}; diff --git a/components/soc/esp32p4/emac_periph.c b/components/soc/esp32p4/emac_periph.c new file mode 100644 index 00000000000..2ae26ddd25a --- /dev/null +++ b/components/soc/esp32p4/emac_periph.c @@ -0,0 +1,208 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "soc/emac_periph.h" +#include "soc/io_mux_reg.h" + +const emac_io_info_t emac_io_idx = { + .mdc_idx = MII_MDC_PAD_OUT_IDX, + .mdo_idx = MII_MDO_PAD_OUT_IDX, + .mdi_idx = MII_MDI_PAD_IN_IDX, + .mii_tx_clk_i_idx = EMAC_TX_CLK_PAD_IN_IDX, + .mii_tx_en_o_idx = EMAC_PHY_TXEN_PAD_OUT_IDX, + .mii_txd0_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX, + .mii_txd1_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX, + .mii_txd2_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX, + .mii_txd3_o_idx = EMAC_PHY_TXD0_PAD_OUT_IDX, + .mii_rx_clk_i_idx = EMAC_RX_CLK_PAD_IN_IDX, + .mii_rx_dv_i_idx = EMAC_PHY_RXDV_PAD_IN_IDX, + .mii_rxd0_i_idx = EMAC_PHY_RXD0_PAD_IN_IDX, + .mii_rxd1_i_idx = EMAC_PHY_RXD1_PAD_IN_IDX, + .mii_rxd2_i_idx = EMAC_PHY_RXD2_PAD_IN_IDX, + .mii_rxd3_i_idx = EMAC_PHY_RXD3_PAD_IN_IDX, + .mii_col_i_idx = EMAC_PHY_COL_PAD_IN_IDX, + .mii_crs_i_idx = EMAC_PHY_CRS_PAD_IN_IDX, + .mii_tx_er_o_idx = EMAC_PHY_TXER_PAD_OUT_IDX, + .mii_rx_er_i_idx = EMAC_PHY_RXER_PAD_IN_IDX +}; + +static const emac_iomux_info_t emac_rmii_iomux_clki[] = { + [0] = { + .gpio_num = 32, + .func = FUNC_GPIO32_EMAC_RMII_CLK_PAD, + }, + [1] = { + .gpio_num = 44, + .func = FUNC_GPIO44_EMAC_RMII_CLK_PAD, + }, + [2] = { + .gpio_num = 50, + .func = FUNC_GPIO50_EMAC_RMII_CLK_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, // indicates end of list + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_clko[] = { + [0] = { + .gpio_num = 23, + .func = FUNC_GPIO23_REF_50M_CLK_PAD, + }, + [1] = { + .gpio_num = 39, + .func = FUNC_GPIO39_REF_50M_CLK_PAD, + }, + [2] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_tx_en[] = { + [0] = { + .gpio_num = 33, + .func = FUNC_GPIO33_EMAC_PHY_TXEN_PAD, + }, + [1] = { + .gpio_num = 40, + .func = FUNC_GPIO40_EMAC_PHY_TXEN_PAD, + }, + [2] = { + .gpio_num = 49, + .func = FUNC_GPIO40_EMAC_PHY_TXEN_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_txd0[] = { + [0] = { + .gpio_num = 34, + .func = FUNC_GPIO34_EMAC_PHY_TXD0_PAD, + }, + [1] = { + .gpio_num = 41, + .func = FUNC_GPIO41_EMAC_PHY_TXD0_PAD, + }, + [2] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_txd1[] = { + [0] = { + .gpio_num = 35, + .func = FUNC_GPIO35_EMAC_PHY_TXD1_PAD, + }, + [1] = { + .gpio_num = 42, + .func = FUNC_GPIO42_EMAC_PHY_TXD1_PAD, + }, + [2] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_crs_dv[] = { + [0] = { + .gpio_num = 28, + .func = FUNC_GPIO28_EMAC_PHY_RXDV_PAD, + }, + [1] = { + .gpio_num = 45, + .func = FUNC_GPIO45_EMAC_PHY_RXDV_PAD, + }, + [2] = { + .gpio_num = 51, + .func = FUNC_GPIO51_EMAC_PHY_RXDV_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_rxd0[] = { + [0] = { + .gpio_num = 29, + .func = FUNC_GPIO29_EMAC_PHY_RXD0_PAD, + }, + [1] = { + .gpio_num = 46, + .func = FUNC_GPIO46_EMAC_PHY_RXD0_PAD, + }, + [2] = { + .gpio_num = 52, + .func = FUNC_GPIO52_EMAC_PHY_RXD0_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_rxd1[] = { + [0] = { + .gpio_num = 30, + .func = FUNC_GPIO30_EMAC_PHY_RXD1_PAD, + }, + [1] = { + .gpio_num = 47, + .func = FUNC_GPIO47_EMAC_PHY_RXD1_PAD, + }, + [2] = { + .gpio_num = 53, + .func = FUNC_GPIO53_EMAC_PHY_RXD1_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_tx_er[] = { + [0] = { + .gpio_num = 36, + .func = FUNC_GPIO36_EMAC_PHY_TXER_PAD, + }, + [1] = { + .gpio_num = 43, + .func = FUNC_GPIO43_EMAC_PHY_TXER_PAD, + }, + [2] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +static const emac_iomux_info_t emac_rmii_iomux_rx_er[] = { + [0] = { + .gpio_num = 31, + .func = FUNC_GPIO31_EMAC_PHY_RXER_PAD, + }, + [1] = { + .gpio_num = 48, + .func = FUNC_GPIO48_EMAC_PHY_RXER_PAD, + }, + [2] = { + .gpio_num = 54, + .func = FUNC_GPIO54_EMAC_PHY_RXER_PAD, + }, + [3] = { + .gpio_num = GPIO_NUM_MAX, + } +}; + +const emac_rmii_iomux_info_t emac_rmii_iomux_pins = { + .clki = emac_rmii_iomux_clki, + .clko = emac_rmii_iomux_clko, + .tx_en = emac_rmii_iomux_tx_en, + .txd0 = emac_rmii_iomux_txd0, + .txd1 = emac_rmii_iomux_txd1, + .crs_dv = emac_rmii_iomux_crs_dv, + .rxd0 = emac_rmii_iomux_rxd0, + .rxd1 = emac_rmii_iomux_rxd1, + .tx_er = emac_rmii_iomux_tx_er, + .rx_er = emac_rmii_iomux_rx_er, +}; + +const emac_mii_iomux_info_t emac_mii_iomux_pins = { 0 }; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index c8822246f20..ee02366807a 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1559,7 +1559,15 @@ config SOC_ASYNCHRONOUS_BUS_ERROR_MODE bool default y -config SOC_EMAC_USE_IO_MUX +config SOC_EMAC_IEEE_1588_SUPPORT + bool + default y + +config SOC_EMAC_USE_MULTI_IO_MUX + bool + default y + +config SOC_EMAC_MII_USE_GPIO_MATRIX bool default y diff --git a/components/soc/esp32p4/include/soc/gpio_sig_map.h b/components/soc/esp32p4/include/soc/gpio_sig_map.h index d0653170fdd..00aba01a22d 100644 --- a/components/soc/esp32p4/include/soc/gpio_sig_map.h +++ b/components/soc/esp32p4/include/soc/gpio_sig_map.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -207,12 +207,12 @@ #define TWAI0_STANDBY_PAD_OUT_IDX 105 #define PWM1_CAP2_PAD_IN_IDX 106 #define TWAI1_STANDBY_PAD_OUT_IDX 106 -#define GMII_MDI_PAD_IN_IDX 107 +#define MII_MDI_PAD_IN_IDX 107 #define TWAI2_STANDBY_PAD_OUT_IDX 107 -#define GMAC_PHY_COL_PAD_IN_IDX 108 -#define GMII_MDC_PAD_OUT_IDX 108 -#define GMAC_PHY_CRS_PAD_IN_IDX 109 -#define GMII_MDO_PAD_OUT_IDX 109 +#define EMAC_PHY_COL_PAD_IN_IDX 108 +#define MII_MDC_PAD_OUT_IDX 108 +#define EMAC_PHY_CRS_PAD_IN_IDX 109 +#define MII_MDO_PAD_OUT_IDX 109 #define USB_OTG11_IDDIG_PAD_IN_IDX 110 #define USB_SRP_DISCHRGVBUS_PAD_OUT_IDX 110 #define USB_OTG11_AVALID_PAD_IN_IDX 111 @@ -339,21 +339,21 @@ #define LCD_DATA_OUT_PAD_OUT22_IDX 176 #define CAM_DATA_IN_PAD_IN15_IDX 177 #define LCD_DATA_OUT_PAD_OUT23_IDX 177 -#define GMAC_PHY_RXDV_PAD_IN_IDX 178 -#define GMAC_PHY_TXEN_PAD_OUT_IDX 178 -#define GMAC_PHY_RXD0_PAD_IN_IDX 179 -#define GMAC_PHY_TXD0_PAD_OUT_IDX 179 -#define GMAC_PHY_RXD1_PAD_IN_IDX 180 -#define GMAC_PHY_TXD1_PAD_OUT_IDX 180 -#define GMAC_PHY_RXD2_PAD_IN_IDX 181 -#define GMAC_PHY_TXD2_PAD_OUT_IDX 181 -#define GMAC_PHY_RXD3_PAD_IN_IDX 182 -#define GMAC_PHY_TXD3_PAD_OUT_IDX 182 -#define GMAC_PHY_RXER_PAD_IN_IDX 183 -#define GMAC_PHY_TXER_PAD_OUT_IDX 183 -#define GMAC_RX_CLK_PAD_IN_IDX 184 +#define EMAC_PHY_RXDV_PAD_IN_IDX 178 +#define EMAC_PHY_TXEN_PAD_OUT_IDX 178 +#define EMAC_PHY_RXD0_PAD_IN_IDX 179 +#define EMAC_PHY_TXD0_PAD_OUT_IDX 179 +#define EMAC_PHY_RXD1_PAD_IN_IDX 180 +#define EMAC_PHY_TXD1_PAD_OUT_IDX 180 +#define EMAC_PHY_RXD2_PAD_IN_IDX 181 +#define EMAC_PHY_TXD2_PAD_OUT_IDX 181 +#define EMAC_PHY_RXD3_PAD_IN_IDX 182 +#define EMAC_PHY_TXD3_PAD_OUT_IDX 182 +#define EMAC_PHY_RXER_PAD_IN_IDX 183 +#define EMAC_PHY_TXER_PAD_OUT_IDX 183 +#define EMAC_RX_CLK_PAD_IN_IDX 184 #define DBG_CH0_CLK_IDX 184 -#define GMAC_TX_CLK_PAD_IN_IDX 185 +#define EMAC_TX_CLK_PAD_IN_IDX 185 #define DBG_CH1_CLK_IDX 185 #define PARLIO_RX_CLK_PAD_IN_IDX 186 #define PARLIO_RX_CLK_PAD_OUT_IDX 186 diff --git a/components/soc/esp32p4/include/soc/io_mux_reg.h b/components/soc/esp32p4/include/soc/io_mux_reg.h index b4bbe739c2c..85eed690983 100644 --- a/components/soc/esp32p4/include/soc/io_mux_reg.h +++ b/components/soc/esp32p4/include/soc/io_mux_reg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -154,20 +154,21 @@ #define GPIO_PAD_SET_DRV(num, drv) PIN_SET_DRV(IOMUX_REG_GPIO##num, drv) // TODO: IDF-7499, IDF-7495 -// Pins defined here are all wrong (Ln153-164). On P4, these pins are individual pins, don't use normal GPIO pins anymore. +// SPI pins defined here are all wrong. On P4, these pins are individual pins, don't use normal GPIO pins anymore. // Please check iomux_mspi_pin_struct/reg.h -#define SPI_CS1_GPIO_NUM 26 -#define SPI_HD_GPIO_NUM 27 -#define SPI_WP_GPIO_NUM 28 -#define SPI_CS0_GPIO_NUM 29 -#define SPI_CLK_GPIO_NUM 30 -#define SPI_Q_GPIO_NUM 31 -#define SPI_D_GPIO_NUM 32 -#define SPI_D4_GPIO_NUM 33 -#define SPI_D5_GPIO_NUM 34 -#define SPI_D6_GPIO_NUM 35 -#define SPI_D7_GPIO_NUM 36 -#define SPI_DQS_GPIO_NUM 37 +#include "soc/gpio_num.h" +#define SPI_CS1_GPIO_NUM GPIO_NUM_MAX +#define SPI_HD_GPIO_NUM GPIO_NUM_MAX +#define SPI_WP_GPIO_NUM GPIO_NUM_MAX +#define SPI_CS0_GPIO_NUM GPIO_NUM_MAX +#define SPI_CLK_GPIO_NUM GPIO_NUM_MAX +#define SPI_Q_GPIO_NUM GPIO_NUM_MAX +#define SPI_D_GPIO_NUM GPIO_NUM_MAX +#define SPI_D4_GPIO_NUM GPIO_NUM_MAX +#define SPI_D5_GPIO_NUM GPIO_NUM_MAX +#define SPI_D6_GPIO_NUM GPIO_NUM_MAX +#define SPI_D7_GPIO_NUM GPIO_NUM_MAX +#define SPI_DQS_GPIO_NUM GPIO_NUM_MAX #define SD_CLK_GPIO_NUM 43 #define SD_CMD_GPIO_NUM 44 @@ -331,63 +332,63 @@ #define PERIPHS_IO_MUX_U_PAD_GPIO28 (REG_IO_MUX_BASE + 0x74) #define FUNC_GPIO28_DBG_PSRAM_D_PAD 4 -#define FUNC_GPIO28_GMAC_PHY_RXDV_PAD 3 +#define FUNC_GPIO28_EMAC_PHY_RXDV_PAD 3 #define FUNC_GPIO28_SPI2_CS_PAD 2 #define FUNC_GPIO28_GPIO28 1 #define FUNC_GPIO28_GPIO28_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO29 (REG_IO_MUX_BASE + 0x78) #define FUNC_GPIO29_DBG_PSRAM_Q_PAD 4 -#define FUNC_GPIO29_GMAC_PHY_RXD0_PAD 3 +#define FUNC_GPIO29_EMAC_PHY_RXD0_PAD 3 #define FUNC_GPIO29_SPI2_D_PAD 2 #define FUNC_GPIO29_GPIO29 1 #define FUNC_GPIO29_GPIO29_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO30 (REG_IO_MUX_BASE + 0x7C) #define FUNC_GPIO30_DBG_PSRAM_WP_PAD 4 -#define FUNC_GPIO30_GMAC_PHY_RXD1_PAD 3 +#define FUNC_GPIO30_EMAC_PHY_RXD1_PAD 3 #define FUNC_GPIO30_SPI2_CK_PAD 2 #define FUNC_GPIO30_GPIO30 1 #define FUNC_GPIO30_GPIO30_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO31 (REG_IO_MUX_BASE + 0x80) #define FUNC_GPIO31_DBG_PSRAM_HOLD_PAD 4 -#define FUNC_GPIO31_GMAC_PHY_RXER_PAD 3 +#define FUNC_GPIO31_EMAC_PHY_RXER_PAD 3 #define FUNC_GPIO31_SPI2_Q_PAD 2 #define FUNC_GPIO31_GPIO31 1 #define FUNC_GPIO31_GPIO31_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO32 (REG_IO_MUX_BASE + 0x84) #define FUNC_GPIO32_DBG_PSRAM_DQ4_PAD 4 -#define FUNC_GPIO32_GMAC_RMII_CLK_PAD 3 +#define FUNC_GPIO32_EMAC_RMII_CLK_PAD 3 #define FUNC_GPIO32_SPI2_HOLD_PAD 2 #define FUNC_GPIO32_GPIO32 1 #define FUNC_GPIO32_GPIO32_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO33 (REG_IO_MUX_BASE + 0x88) #define FUNC_GPIO33_DBG_PSRAM_DQ5_PAD 4 -#define FUNC_GPIO33_GMAC_PHY_TXEN_PAD 3 +#define FUNC_GPIO33_EMAC_PHY_TXEN_PAD 3 #define FUNC_GPIO33_SPI2_WP_PAD 2 #define FUNC_GPIO33_GPIO33 1 #define FUNC_GPIO33_GPIO33_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO34 (REG_IO_MUX_BASE + 0x8C) #define FUNC_GPIO34_DBG_PSRAM_DQ6_PAD 4 -#define FUNC_GPIO34_GMAC_PHY_TXD0_PAD 3 +#define FUNC_GPIO34_EMAC_PHY_TXD0_PAD 3 #define FUNC_GPIO34_SPI2_IO4_PAD 2 #define FUNC_GPIO34_GPIO34 1 #define FUNC_GPIO34_GPIO34_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO35 (REG_IO_MUX_BASE + 0x90) #define FUNC_GPIO35_DBG_PSRAM_DQ7_PAD 4 -#define FUNC_GPIO35_GMAC_PHY_TXD1_PAD 3 +#define FUNC_GPIO35_EMAC_PHY_TXD1_PAD 3 #define FUNC_GPIO35_SPI2_IO5_PAD 2 #define FUNC_GPIO35_GPIO35 1 #define FUNC_GPIO35_GPIO35_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO36 (REG_IO_MUX_BASE + 0x94) #define FUNC_GPIO36_DBG_PSRAM_DQS_0_PAD 4 -#define FUNC_GPIO36_GMAC_PHY_TXER_PAD 3 +#define FUNC_GPIO36_EMAC_PHY_TXER_PAD 3 #define FUNC_GPIO36_SPI2_IO6_PAD 2 #define FUNC_GPIO36_GPIO36 1 #define FUNC_GPIO36_GPIO36_0 0 @@ -411,99 +412,99 @@ #define PERIPHS_IO_MUX_U_PAD_GPIO40 (REG_IO_MUX_BASE + 0xA4) #define FUNC_GPIO40_DBG_PSRAM_DQ9_PAD 4 -#define FUNC_GPIO40_GMAC_PHY_TXEN_PAD 3 +#define FUNC_GPIO40_EMAC_PHY_TXEN_PAD 3 #define FUNC_GPIO40_BIST_PAD 2 #define FUNC_GPIO40_GPIO40 1 #define FUNC_GPIO40_SD1_CDATA1_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO41 (REG_IO_MUX_BASE + 0xA8) #define FUNC_GPIO41_DBG_PSRAM_DQ10_PAD 4 -#define FUNC_GPIO41_GMAC_PHY_TXD0_PAD 3 +#define FUNC_GPIO41_EMAC_PHY_TXD0_PAD 3 #define FUNC_GPIO41_BIST_PAD 2 #define FUNC_GPIO41_GPIO41 1 #define FUNC_GPIO41_SD1_CDATA2_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO42 (REG_IO_MUX_BASE + 0xAC) #define FUNC_GPIO42_DBG_PSRAM_DQ11_PAD 4 -#define FUNC_GPIO42_GMAC_PHY_TXD1_PAD 3 +#define FUNC_GPIO42_EMAC_PHY_TXD1_PAD 3 #define FUNC_GPIO42_BIST_PAD 2 #define FUNC_GPIO42_GPIO42 1 #define FUNC_GPIO42_SD1_CDATA3_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO43 (REG_IO_MUX_BASE + 0xB0) #define FUNC_GPIO43_DBG_PSRAM_DQ12_PAD 4 -#define FUNC_GPIO43_GMAC_PHY_TXER_PAD 3 +#define FUNC_GPIO43_EMAC_PHY_TXER_PAD 3 #define FUNC_GPIO43_BIST_PAD 2 #define FUNC_GPIO43_GPIO43 1 #define FUNC_GPIO43_SD1_CCLK_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO44 (REG_IO_MUX_BASE + 0xB4) #define FUNC_GPIO44_DBG_PSRAM_DQ13_PAD 4 -#define FUNC_GPIO44_GMAC_RMII_CLK_PAD 3 +#define FUNC_GPIO44_EMAC_RMII_CLK_PAD 3 #define FUNC_GPIO44_BIST_PAD 2 #define FUNC_GPIO44_GPIO44 1 #define FUNC_GPIO44_SD1_CCMD_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO45 (REG_IO_MUX_BASE + 0xB8) #define FUNC_GPIO45_DBG_PSRAM_DQ14_PAD 4 -#define FUNC_GPIO45_GMAC_PHY_RXDV_PAD 3 +#define FUNC_GPIO45_EMAC_PHY_RXDV_PAD 3 #define FUNC_GPIO45_BIST_PAD 2 #define FUNC_GPIO45_GPIO45 1 #define FUNC_GPIO45_SD1_CDATA4_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO46 (REG_IO_MUX_BASE + 0xBC) #define FUNC_GPIO46_DBG_PSRAM_DQ15_PAD 4 -#define FUNC_GPIO46_GMAC_PHY_RXD0_PAD 3 +#define FUNC_GPIO46_EMAC_PHY_RXD0_PAD 3 #define FUNC_GPIO46_BIST_PAD 2 #define FUNC_GPIO46_GPIO46 1 #define FUNC_GPIO46_SD1_CDATA5_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO47 (REG_IO_MUX_BASE + 0xC0) #define FUNC_GPIO47_DBG_PSRAM_DQS_1_PAD 4 -#define FUNC_GPIO47_GMAC_PHY_RXD1_PAD 3 +#define FUNC_GPIO47_EMAC_PHY_RXD1_PAD 3 #define FUNC_GPIO47_BIST_PAD 2 #define FUNC_GPIO47_GPIO47 1 #define FUNC_GPIO47_SD1_CDATA6_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO48 (REG_IO_MUX_BASE + 0xC4) -#define FUNC_GPIO48_GMAC_PHY_RXER_PAD 3 +#define FUNC_GPIO48_EMAC_PHY_RXER_PAD 3 #define FUNC_GPIO48_BIST_PAD 2 #define FUNC_GPIO48_GPIO48 1 #define FUNC_GPIO48_SD1_CDATA7_PAD 0 #define PERIPHS_IO_MUX_U_PAD_GPIO49 (REG_IO_MUX_BASE + 0xC8) #define FUNC_GPIO49_DBG_FLASH_CS_PAD 4 -#define FUNC_GPIO49_GMAC_PHY_TXEN_PAD 3 +#define FUNC_GPIO49_EMAC_PHY_TXEN_PAD 3 #define FUNC_GPIO49_GPIO49 1 #define FUNC_GPIO49_GPIO49_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO50 (REG_IO_MUX_BASE + 0xCC) #define FUNC_GPIO50_DBG_FLASH_Q_PAD 4 -#define FUNC_GPIO50_GMAC_RMII_CLK_PAD 3 +#define FUNC_GPIO50_EMAC_RMII_CLK_PAD 3 #define FUNC_GPIO50_GPIO50 1 #define FUNC_GPIO50_GPIO50_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO51 (REG_IO_MUX_BASE + 0xD0) #define FUNC_GPIO51_DBG_FLASH_WP_PAD 4 -#define FUNC_GPIO51_GMAC_PHY_RXDV_PAD 3 +#define FUNC_GPIO51_EMAC_PHY_RXDV_PAD 3 #define FUNC_GPIO51_GPIO51 1 #define FUNC_GPIO51_GPIO51_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO52 (REG_IO_MUX_BASE + 0xD4) #define FUNC_GPIO52_DBG_FLASH_HOLD_PAD 4 -#define FUNC_GPIO52_GMAC_PHY_RXD0_PAD 3 +#define FUNC_GPIO52_EMAC_PHY_RXD0_PAD 3 #define FUNC_GPIO52_GPIO52 1 #define FUNC_GPIO52_GPIO52_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO53 (REG_IO_MUX_BASE + 0xD8) #define FUNC_GPIO53_DBG_FLASH_CK_PAD 4 -#define FUNC_GPIO53_GMAC_PHY_RXD1_PAD 3 +#define FUNC_GPIO53_EMAC_PHY_RXD1_PAD 3 #define FUNC_GPIO53_GPIO53 1 #define FUNC_GPIO53_GPIO53_0 0 #define PERIPHS_IO_MUX_U_PAD_GPIO54 (REG_IO_MUX_BASE + 0xDC) #define FUNC_GPIO54_DBG_FLASH_D_PAD 4 -#define FUNC_GPIO54_GMAC_PHY_RXER_PAD 3 +#define FUNC_GPIO54_EMAC_PHY_RXER_PAD 3 #define FUNC_GPIO54_GPIO54 1 #define FUNC_GPIO54_GPIO54_0 0 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 8d3fece9edd..016e9c5ed78 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -632,7 +632,9 @@ #define SOC_MEM_NON_CONTIGUOUS_SRAM (1) #define SOC_ASYNCHRONOUS_BUS_ERROR_MODE (1) /*--------------------------- EMAC --------------------------------*/ -#define SOC_EMAC_USE_IO_MUX (1) /*!< GPIO matrix is used to select GPIO pads */ +#define SOC_EMAC_IEEE_1588_SUPPORT (1) /*!< EMAC Supports IEEE1588 time stamping */ +#define SOC_EMAC_USE_MULTI_IO_MUX (1) /*!< Multiple GPIO pad options exist to connect EMAC signal via IO_MUX */ +#define SOC_EMAC_MII_USE_GPIO_MATRIX (1) /*!< EMAC MII signals are connected to GPIO pads via GPIO Matrix */ /*--------------------------- JPEG --------------------------------*/ #define SOC_JPEG_CODEC_SUPPORTED (1) diff --git a/components/soc/include/soc/emac_periph.h b/components/soc/include/soc/emac_periph.h index 6f7323f46fe..bccc1ccb1f9 100644 --- a/components/soc/include/soc/emac_periph.h +++ b/components/soc/include/soc/emac_periph.h @@ -1,15 +1,89 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once +#include +#include "soc/soc_caps.h" +#include "soc/gpio_sig_map.h" +#include "soc/gpio_num.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_EMAC_SUPPORTED +/** + * This structure lists pin numbers + */ +typedef struct { + uint32_t mdc_idx; + uint32_t mdo_idx; + uint32_t mdi_idx; + uint32_t mii_tx_clk_i_idx; + uint32_t mii_tx_en_o_idx; + uint32_t mii_txd0_o_idx; + uint32_t mii_txd1_o_idx; + uint32_t mii_txd2_o_idx; + uint32_t mii_txd3_o_idx; + uint32_t mii_rx_clk_i_idx; + uint32_t mii_rx_dv_i_idx; + uint32_t mii_rxd0_i_idx; + uint32_t mii_rxd1_i_idx; + uint32_t mii_rxd2_i_idx; + uint32_t mii_rxd3_i_idx; + uint32_t mii_col_i_idx; + uint32_t mii_crs_i_idx; + uint32_t mii_rx_er_i_idx; + uint32_t mii_tx_er_o_idx; +} emac_io_info_t; + +typedef struct { + gpio_num_t gpio_num; + uint32_t func; +} emac_iomux_info_t; + +typedef struct { + const emac_iomux_info_t *clki; + const emac_iomux_info_t *clko; + const emac_iomux_info_t *tx_en; + const emac_iomux_info_t *txd0; + const emac_iomux_info_t *txd1; + const emac_iomux_info_t *crs_dv; + const emac_iomux_info_t *rxd0; + const emac_iomux_info_t *rxd1; + const emac_iomux_info_t *tx_er; + const emac_iomux_info_t *rx_er; +} emac_rmii_iomux_info_t; + +typedef struct { + const emac_iomux_info_t *clk_tx; + const emac_iomux_info_t *tx_en; + const emac_iomux_info_t *txd0; + const emac_iomux_info_t *txd1; + const emac_iomux_info_t *txd2; + const emac_iomux_info_t *txd3; + const emac_iomux_info_t *clk_rx; + const emac_iomux_info_t *rx_dv; + const emac_iomux_info_t *rxd0; + const emac_iomux_info_t *rxd1; + const emac_iomux_info_t *rxd2; + const emac_iomux_info_t *rxd3; + const emac_iomux_info_t *tx_er; + const emac_iomux_info_t *rx_er; + const emac_iomux_info_t *col_in; + const emac_iomux_info_t *crs_in; +} emac_mii_iomux_info_t; + +extern const emac_io_info_t emac_io_idx; +extern const emac_rmii_iomux_info_t emac_rmii_iomux_pins; +extern const emac_mii_iomux_info_t emac_mii_iomux_pins; + +#endif // SOC_EMAC_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 73551440033..539be4296aa 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -149,6 +149,8 @@ INPUT = \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_com.h \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_driver.h \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac.h \ + $(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac_esp.h \ + $(PROJECT_PATH)/components/esp_eth/include/esp_eth_mac_spi.h \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_netif_glue.h \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_phy_802_3.h \ $(PROJECT_PATH)/components/esp_eth/include/esp_eth_phy.h \ diff --git a/docs/en/api-reference/network/esp_eth.rst b/docs/en/api-reference/network/esp_eth.rst index c049fcba49c..39bf96cdb0d 100644 --- a/docs/en/api-reference/network/esp_eth.rst +++ b/docs/en/api-reference/network/esp_eth.rst @@ -150,7 +150,7 @@ The Ethernet driver is composed of two parts: MAC and PHY. .. only:: esp32 .. note:: - The ``REF_CLK`` can be also configured via Project Configuration when :cpp:member:`eth_esp32_emac_config_t::clock_config::mode` of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_DEFAULT`. Choose appropriately ``CONFIG_ETH_RMII_CLK_INPUT`` or ``CONFIG_ETH_RMII_CLK_OUTPUT`` option under :ref:`CONFIG_ETH_RMII_CLK_MODE` configuration based on your design as discussed above. + The ``REF_CLK`` can be also configured via Project Configuration when :cpp:class:`eth_esp32_emac_config_t` is initialized using :c:macro:`ETH_ESP32_EMAC_DEFAULT_CONFIG` macro. In the Project Configuration, choose appropriately ``CONFIG_ETH_RMII_CLK_INPUT`` or ``CONFIG_ETH_RMII_CLK_OUTPUT`` option under :ref:`CONFIG_ETH_RMII_CLK_MODE` configuration based on your design as discussed above. .. warning:: If the RMII clock mode is configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` (or ``CONFIG_ETH_RMII_CLK_OUTPUT`` is selected), then ``GPIO0`` can be used to output the ``REF_CLK`` signal. See :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_APPL_CLK_OUT_GPIO` or :ref:`CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0` for more information. @@ -188,12 +188,12 @@ The Ethernet driver is composed of two parts: MAC and PHY. **No matter which RMII clock mode you select, you really need to take care of the signal integrity of REF_CLK in your hardware design!** Keep the trace as short as possible. Keep it away from RF devices and inductor elements. - .. only:: not SOC_EMAC_USE_IO_MUX + .. only:: not SOC_EMAC_USE_MULTI_IO_MUX .. note:: Signals used in the data plane are fixed to specific GPIOs via IO_MUX, they can not be modified to other GPIOs. Signals used in the control plane can be routed to any free GPIOs via Matrix. Please refer to :doc:`ESP32-Ethernet-Kit <../../hw-reference/esp32/get-started-ethernet-kit>` for hardware design example. - .. only:: SOC_EMAC_USE_IO_MUX + .. only:: SOC_EMAC_USE_MULTI_IO_MUX .. note:: Signals used in the data plane can be configured to predefined set of GPIOs via IO_MUX for the RMII, see below table. The data plane GPIO configuration is performed by the driver based on content of :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`. Signals used in the control plane can be routed to any free GPIOs via GPIO Matrix. @@ -250,7 +250,7 @@ Basic common configuration for MAC layer is described in :cpp:class:`eth_mac_con * :cpp:member:`eth_esp32_emac_config_t::intr_priority`: sets the priority of the MAC interrupt. If it is set to ``0`` or a negative value, the driver will allocate an interrupt with a default priority. Otherwise, the driver will use the given priority. Note that *Low* and *Medium* interrupt priorities (1 to 3) can be set since these can be handled in C. - :SOC_EMAC_USE_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers. + :SOC_EMAC_USE_MULTI_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`: configuration of EMAC MII/RMII data plane GPIO numbers. :not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`: configuration of EMAC input interface clock when ``REF_CLK`` signal is generated internally and is looped back to the EMAC externally. The mode must be always configured to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`. This option is valid only when configuration of :cpp:member:`eth_esp32_emac_config_t::clock_config` is set to :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`. @@ -549,12 +549,12 @@ Custom PHY Driver There are multiple PHY manufacturers with wide portfolios of chips available. The ESP-IDF already supports several PHY chips however one can easily get to a point where none of them satisfies the user's actual needs due to price, features, stock availability, etc. -Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task. +Luckily, a management interface between EMAC and PHY is standardized by IEEE 802.3 in Section 22.2.4 Management Functions. It defines provisions of the so-called "MII Management Interface" to control the PHY and gather status from the PHY. A set of management registers is defined to control chip behavior, link properties, auto-negotiation configuration, etc. This basic management functionality is addressed by :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` in ESP-IDF and so it makes the creation of a new custom PHY chip driver quite a simple task. .. note:: Always consult with PHY datasheet since some PHY chips may not comply with IEEE 802.3, Section 22.2.4. It does not mean you are not able to create a custom PHY driver, but it just requires more effort. You will have to define all PHY management functions. -The majority of PHY management functionality required by the ESP-IDF Ethernet driver is covered by the :component_file:`esp_eth/src/esp_eth_phy_802_3.c`. However, the following may require developing chip-specific management functions: +The majority of PHY management functionality required by the ESP-IDF Ethernet driver is covered by the :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c`. However, the following may require developing chip-specific management functions: * Link status which is almost always chip-specific * Chip initialization, even though not strictly required, should be customized to at least ensure that the expected chip is used @@ -562,11 +562,11 @@ The majority of PHY management functionality required by the ESP-IDF Ethernet dr **Steps to create a custom PHY driver:** -1. Define vendor-specific registry layout based on the PHY datasheet. See :component_file:`esp_eth/src/esp_eth_phy_ip101.c` as an example. +1. Define vendor-specific registry layout based on the PHY datasheet. See :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c` as an example. 2. Prepare derived PHY management object info structure which: * must contain at least parent IEEE 802.3 :cpp:class:`phy_802_3_t` object - * optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality. See :component_file:`esp_eth/src/esp_eth_phy_ksz80xx.c` as an example. + * optionally contain additional variables needed to support non-IEEE 802.3 or customized functionality. See :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c` as an example. 3. Define chip-specific management call-back functions. 4. Initialize parent IEEE 802.3 object and re-assign chip-specific management call-back functions. @@ -583,6 +583,8 @@ API Reference .. include-build-file:: inc/esp_eth_driver.inc .. include-build-file:: inc/esp_eth_com.inc .. include-build-file:: inc/esp_eth_mac.inc +.. include-build-file:: inc/esp_eth_mac_esp.inc +.. include-build-file:: inc/esp_eth_mac_spi.inc .. include-build-file:: inc/esp_eth_phy.inc .. include-build-file:: inc/esp_eth_phy_802_3.inc .. include-build-file:: inc/esp_eth_netif_glue.inc diff --git a/docs/zh_CN/api-reference/network/esp_eth.rst b/docs/zh_CN/api-reference/network/esp_eth.rst index 255c7ea1a45..e7d181949ef 100644 --- a/docs/zh_CN/api-reference/network/esp_eth.rst +++ b/docs/zh_CN/api-reference/network/esp_eth.rst @@ -1,6 +1,16 @@ 以太网 ========= +{IDF_TARGET_SOC_REF_CLK_IN_GPIO:default="", esp32="GPIO0", esp32p4="GPIO32, GPIO44 and GPIO50"} +{IDF_TARGET_SOC_REF_CLK_OUT_GPIO:default="", esp32="GPIO0, GPIO16 and GPIO17", esp32p4="GPIO23 and GPIO39"} +{IDF_TARGET_SOC_RMII_TX_EN:default="", esp32="GPIO21", esp32p4="GPIO33, GPIO40 and GPIO49"} +{IDF_TARGET_SOC_RMII_TXD0:default="", esp32="GPIO19", esp32p4="GPIO34 and GPIO41"} +{IDF_TARGET_SOC_RMII_TXD1:default="", esp32="GPIO22", esp32p4="GPIO35 and GPIO42"} +{IDF_TARGET_SOC_RMII_CRS_DV:default="", esp32="GPIO27", esp32p4="GPIO28, GPIO45 and GPIO51"} +{IDF_TARGET_SOC_RMII_RXD0:default="", esp32="GPIO25", esp32p4="GPIO29, GPIO46 and GPIO52"} +{IDF_TARGET_SOC_RMII_RXD1:default="", esp32="GPIO26", esp32p4="GPIO30, GPIO47 and GPIO53"} + + :link_to_translation:`en:[English]` .. -------------------------------- Overview ----------------------------------- @@ -8,7 +18,13 @@ 概述 -------- -ESP-IDF 提供一系列功能强大且兼具一致性的 API,为内部以太网 MAC (EMAC) 控制器和外部 SPI-Ethernet 模块提供支持。 +.. only:: SOC_EMAC_SUPPORTED + + ESP-IDF 提供一系列灵活度高且兼具一致性的 API,为内部以太网 MAC (EMAC) 控制器和外部 SPI-Ethernet 模块提供支持。 + +.. only:: not SOC_EMAC_SUPPORTED + + ESP-IDF 提供一系列灵活度高且兼具一致性的 API,为外部 SPI-Ethernet 模块提供支持。 本编程指南分为以下几个部分: @@ -24,7 +40,7 @@ ESP-IDF 提供一系列功能强大且兼具一致性的 API,为内部以太 以太网基本概念 ----------------------- -以太网是一种异步的带冲突检测的载波侦听多路访问 (CSMA/CD) 协议/接口。通常来说,以太网不太适用于低功率应用。然而,得益于其广泛的部署、高效的网络连接、高数据率以及范围不限的可扩展性,几乎所有的有线通信都可以通过以太网进行。 +以太网是一种异步的带冲突检测的载波侦听多路访问 (CSMA/CD) 协议/接口。通常来说,以太网不太适用于低功耗应用。然而,得益于其广泛的部署、高效的网络连接、高数据率以及范围不限的可扩展性,几乎所有的有线通信都可以通过以太网进行。 符合 IEEE 802.3 标准的正常以太网帧的长度在 64 至 1518 字节之间,由五个或六个不同的字段组成:目的地 MAC 地址 (DA)、源 MAC 地址 (SA)、类型/长度字段、数据有效载荷字段、可选的填充字段和帧校验序列字段 (CRC)。此外,在以太网上传输时,以太网数据包的开头需附加 7 字节的前导码和 1 字节的帧起始符 (SOF)。 @@ -115,36 +131,100 @@ ESP-IDF 提供一系列功能强大且兼具一致性的 API,为内部以太 MII 和 RMII 的一个明显区别在于其所需的信号数。MII 通常需要多达 18 个信号,RMII 接口则仅需要 9 个信号。 + .. only:: esp32 + + .. note:: + ESP-IDF 只支持 RMII 接口,所以请将 :cpp:member:`eth_esp32_emac_config_t::interface` 设置为 :cpp:enumerator:`eth_data_interface_t::EMAC_DATA_INTERFACE_RMII` 或在 Kconfig 选项 :ref:`CONFIG_ETH_PHY_INTERFACE` 中选择 ``CONFIG_ETH_PHY_INTERFACE_RMII``。 + + .. only:: not esp32 + + .. note:: + ESP-IDF 只支持 RMII 接口,所以请将 :cpp:member:`eth_esp32_emac_config_t::interface` 设置为 :cpp:enumerator:`eth_data_interface_t::EMAC_DATA_INTERFACE_RMII`。 + 在 RMII 模式下,接收器和发射器信号的参考时钟为 ``REF_CLK``。 **在访问 PHY 和 MAC 时,REF_CLK 必须保持稳定**。一般来说,根据设计中 PHY 设备的特征,可通过以下三种方式生成 ``REF_CLK``: - * 一些 PHY 芯片可以从其外部连接的 25 MHz 晶体振荡器中获取 ``REF_CLK`` (如图中的选项 **a** 所示)。对于此类芯片,请在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 中选择 ``CONFIG_ETH_RMII_CLK_INPUT``。 + * 一些 PHY 芯片可以从其外部连接的 25 MHz 晶体振荡器中衍生出 ``REF_CLK`` (如图中的选项 **a** 所示)。对于此类芯片,请将 :cpp:member:`eth_esp32_emac_config_t::clock_config` 中的 :cpp:member:`eth_mac_clock_config_t::clock_mode` 设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`。 + + * 一些 PHY 芯片使用外接的 50 MHz 晶体振荡器或其他时钟源作为 MAC 端的 ``REF_CLK`` (如图中的选项 **b** 所示)。对于此类芯片,请同样将 :cpp:member:`eth_esp32_emac_config_t::clock_config` 中的 :cpp:member:`eth_mac_clock_config_t::clock_mode` 设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`。 + + * 一些 EMAC 控制器可以使用其内部的高精度 PLL 生成 ``REF_CLK`` (如图中的选项 **c** 所示)。此种情况下,请将 :cpp:member:`eth_esp32_emac_config_t::clock_config` 中的 :cpp:member:`eth_mac_clock_config_t::clock_mode` 设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`。 + + .. only:: esp32 + + .. note:: + 使用 :c:macro:`ETH_ESP32_EMAC_DEFAULT_CONFIG` 宏初始化 :cpp:class:`eth_esp32_emac_config_t` 时,也可以通过项目配置来配置 ``REF_CLK``。在项目配置中,根据上述个人设计,在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 配置下选择适当的选项, ``CONFIG_ETH_RMII_CLK_INPUT`` 或是 ``CONFIG_ETH_RMII_CLK_OUTPUT``。 + + .. warning:: + 如果配置 RMII 时钟模式为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` (或是选择 ``CONFIG_ETH_RMII_CLK_OUTPUT``,那么就可以使用 ``GPIO0`` 输出 ``REF_CLK`` 信号。更多细节,请参见 :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_APPL_CLK_OUT_GPIO` 或是 :ref:`CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0`。 + + 值得一提的是,如果设计中并未使用 PSRAM,则 GPIO16 和 GPIO17 也可以用来输出参考时钟。更多细节,请参见 :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_CLK_OUT_GPIO` 和 :cpp:enumerator:`emac_rmii_clock_gpio_t::EMAC_CLK_OUT_180_GPIO`,或是 :ref:`CONFIG_ETH_RMII_CLK_OUT_GPIO`。 + + 如果配置 RMII 时钟模式为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN` (或是选择 ``CONFIG_ETH_RMII_CLK_INPUT``,那么只能选择 ``GPIO0`` 输入 ``REF_CLK`` 信号。请注意, ``GPIO0`` 同时也是 ESP32 上一个重要的 strapping GPIO 管脚。如果上电时 GPIO0 为低电平,则 ESP32 将进入下载模式,需进行手动复位重启系统。解决这个问题的方法是,在硬件中默认禁用 ``REF_CLK``,从而避免 strapping 管脚在启动阶段受到其他信号的干扰。随后,再在以太网驱动安装阶段重新启用 ``REF_CLK``。 + + 可以通过以下方法禁用 ``REF_CLK`` 信号: - * 一些 PHY 芯片使用可以作为 MAC 端 ``REF_CLK`` 的外接 50 MHz 晶体振荡器或其他时钟源(如图中的选项 **b** 所示)。对于此类芯片,请同样在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 中选择 ``CONFIG_ETH_RMII_CLK_INPUT``。 + * 禁用或关闭晶体振荡器的电源(对应图中的选项 **b**)。 - * 一些 EMAC 控制器可以使用其内部的高精度 PLL 生成 ``REF_CLK`` (如图中的选项 **c** 所示)。此种情况下,请在 :ref:`CONFIG_ETH_RMII_CLK_MODE` 中选择 ``CONFIG_ETH_RMII_CLK_OUTPUT``。 + * 强制复位 PHY 设备(对应图中的选项 **a**)。**此种方法并不适用于所有 PHY 设备** (即便处于复位状态,某些 PHY 设备仍会向 GPIO0 输出信号)。 - .. note:: - 如上所述,``REF_CLK`` 默认通过项目配置进行配置。然而,通过设置 :cpp:member:`eth_esp32_emac_config_t::interface` 和 :cpp:member:`eth_esp32_emac_config_t::clock_config`,也可以实现在用户应用代码中覆盖该时钟。更多细节,请参见 :cpp:enum:`emac_rmii_clock_mode_t` 和 :cpp:enum:`emac_rmii_clock_gpio_t`。 + .. only:: not esp32 - .. warning:: - 如果配置 RMII 时钟模式为 ``CONFIG_ETH_RMII_CLK_OUTPUT``,那么就可以使用 ``GPIO0`` 输出 ``REF_CLK`` 信号。更多细节,请参见 :ref:`CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0`。 + .. note:: + 如果 RMII 时钟模式配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`,则可以通过 IO_MUX 将 {IDF_TARGET_SOC_REF_CLK_OUT_GPIO} 选择为 ``REF_CLK`` 信号的输出管脚。 - 值得一提的是,如果设计中并未使用 PSRAM,则 GPIO16 和 GPIO17 也可以用来输出参考时钟。更多细节,请参见 :ref:`CONFIG_ETH_RMII_CLK_OUT_GPIO`。 + 如果 RMII 时钟模式配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`,则可以通过 IO_MUX 将 {IDF_TARGET_SOC_REF_CLK_IN_GPIO} 选择为 ``REF_CLK`` 信号的输入管脚。 - 如果配置 RMII 时钟模式为 ``CONFIG_ETH_RMII_CLK_INPUT``,那么有且只有 ``GPIO0`` 可以用来输入 ``REF_CLK`` 信号。请注意, ``GPIO0`` 同时也是 ESP32 上一个重要的 strapping GPIO 管脚。如果 GPIO0 在上电时采样为低电平,ESP32 将进入下载模式,需进行手动复位重启系统。解决这个问题的方法是,在硬件中默认禁用 ``REF_CLK``,从而避免 strapping 管脚在启动阶段受到其他信号的干扰。随后,再在以太网驱动安装阶段重新启用 ``REF_CLK``。 + .. only:: not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK - 可以通过以下方法禁用 ``REF_CLK`` 信号: + .. warning:: + 如果 RMII 时钟模式配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT`,则必须从外部将 ``REF_CLK`` 输出信号回环到 EMAC。请将 :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in` 中的 :cpp:member:`eth_mac_clock_config_t::clock_mode` 配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`,并选择与 ``REF_CLK`` 输入 GPIO ({IDF_TARGET_SOC_REF_CLK_IN_GPIO}) 相关联的 GPIO 编号。 - * 禁用或关闭晶体振荡器的电源(对应图中的选项 **b**)。 + .. only:: esp32p4 - * 强制复位 PHY 设备(对应图中的选项 **a**)。 **此种方法并不适用于所有 PHY 设备**,即便处于复位状态,某些 PHY 设备仍会向 GPIO0 输出信号。 + .. figure:: ../../../_static/rmii_ref_clk_esp32p4.png + :scale: 95 % + :alt: RMII REF_CKL Output Loopback + :figclass: align-center - **无论选择哪种 RMII 时钟模式,都请确保硬件设计中 REF_CLK 的信号完整性!** 信号线越短越好,并请保持信号线与 RF 设备和电感器元件的距离。 + RMII REF_CKL 输出回环 - .. note:: - ESP-IDF 只支持 RMII 接口(即在 Kconfig 选项 :ref:`CONFIG_ETH_PHY_INTERFACE` 中始终选择 ``CONFIG_ETH_PHY_INTERFACE_RMII``)。 + **无论选择哪种 RMII 时钟模式,都请确保硬件设计中 REF_CLK 的信号完整性!** 信号线越短越好,并远离 RF 设备和电感。 - 在数据平面使用的信号通过 MUX 连接至特定的 GPIO,这些信号无法配置至其他 GPIO。在控制平面使用的信号则可以通过 Matrix 矩阵路由到任何空闲 GPIO。相关的硬件设计示例,请参考 :doc:`ESP32-Ethernet-Kit <../../hw-reference/esp32/get-started-ethernet-kit>`。 + .. only:: not SOC_EMAC_USE_MULTI_IO_MUX + + .. note:: + 数据平面中使用的信号通过 IO_MUX 连接至特定的 GPIO,这些信号无法配置到其他 GPIO 上。控制平面中使用的信号可以通过矩阵路由到任何空闲的 GPIO 上。相关硬件设计示例,请参阅 :doc:`ESP32-Ethernet-Kit <../../hw-reference/esp32/get-started-ethernet-kit>`。 + + .. only:: SOC_EMAC_USE_MULTI_IO_MUX + + .. note:: + 数据平面中使用的信号可以通过 IO_MUX 配置为 RMII 预定义的 GPIO,请参阅下表。数据平面 GPIO 配置由驱动程序根据 :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio` 的内容执行。控制平面中使用的信号可以通过 GPIO 矩阵路由到任何空闲的 GPIO。 + + .. list-table:: {IDF_TARGET_NAME} RMII 数据平面 GPIO + :header-rows: 1 + :widths: 50 50 + :align: center + + * - 管脚名 + - GPIO 编号 + + * - TX_EN + - {IDF_TARGET_SOC_RMII_TX_EN} + + * - TXD0 + - {IDF_TARGET_SOC_RMII_TXD0} + + * - TXD1 + - {IDF_TARGET_SOC_RMII_TXD1} + + * - CRS_DV + - {IDF_TARGET_SOC_RMII_CRS_DV} + + * - RXD0 + - {IDF_TARGET_SOC_RMII_RXD0} + + * - RXD1 + - {IDF_TARGET_SOC_RMII_RXD1} 根据以太网板设计,需要分别为 MAC 和 PHY 配置必要的参数,通过两者完成驱动程序的安装。 @@ -156,13 +236,25 @@ MAC 的相关配置可以在 :cpp:class:`eth_mac_config_t` 中找到,具体包 * :cpp:member:`eth_mac_config_t::rx_task_stack_size` 和 :cpp:member:`eth_mac_config_t::rx_task_prio`:MAC 驱动会创建一个专门的任务来处理传入的数据包,这两个参数用于设置该任务的堆栈大小和优先级。 - * :cpp:member:`eth_mac_config_t::flags`:指定 MAC 驱动应支持的额外功能,尤其适用于某些特殊情况。这个字段的值支持与以 ``ETH_MAC_FLAG_`` 为前缀的宏进行 OR 运算。例如,如果 MAC 驱动应在禁用缓存后开始工作,那么则需要用 :c:macro:`ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE` 配置这个字段。 + * :cpp:member:`eth_mac_config_t::flags`:指定 MAC 驱动应支持的额外功能,尤其适用于某些特殊情况。这个字段的值支持与以 ``ETH_MAC_FLAG_`` 为前缀的宏进行 OR 运算。例如,如果要求 MAC 驱动程序在 cache 禁用时仍能正常工作,那么则需要用 :c:macro:`ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE` 配置这个字段。 + +.. only:: SOC_EMAC_SUPPORTED + + :cpp:class:`eth_esp32_emac_config_t` 描述了 **内部 MAC 模块** 的特定配置,其中包括: + + .. list:: + + * :cpp:member:`eth_esp32_emac_config_t::smi_mdc_gpio_num` 和 :cpp:member:`eth_esp32_emac_config_t::smi_mdio_gpio_num`:连接 SMI 信号的 GPIO 编号。 + + * :cpp:member:`eth_esp32_emac_config_t::interface`:配置到 PHY (MII/RMII) 的 MAC 数据接口。 + + * :cpp:member:`eth_esp32_emac_config_t::clock_config`:配置 EMAC 接口时钟(RMII 模式下的 ``REF_CLK`` 模式以及 GPIO 编号)。 - :SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::smi_mdc_gpio_num` 和 :cpp:member:`eth_esp32_emac_config_t::smi_mdio_gpio_num`:连接 SMI 信号的 GPIO 编号。 + * :cpp:member:`eth_esp32_emac_config_t::intr_priority`: 设置 MAC 中断的优先级。如果设置为 ``0`` 或负值,则驱动程序将分配一个具有默认优先级的中断。否则,驱动程序将使用给定的优先级。请注意,可以设置 *低*、 *中* 中断优先级(1 到 3),因为这可以在 C 中处理。 - :SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::interface`:配置到 PHY (MII/RMII) 的 MAC 数据接口。 + :SOC_EMAC_USE_MULTI_IO_MUX: * :cpp:member:`eth_esp32_emac_config_t::emac_dataif_gpio`:EMAC MII/RMII 数据平面 GPIO 编号配置。 - :SOC_EMAC_SUPPORTED: * :cpp:member:`eth_esp32_emac_config_t::clock_config`:配置 EMAC 接口时钟(RMII 模式下的 ``REF_CLK`` 模式以及 GPIO 编号)。 + :not SOC_EMAC_RMII_CLK_OUT_INTERNAL_LOOPBACK: * :cpp:member:`eth_esp32_emac_config_t::clock_config_out_in`:当 ``REF_CLK`` 信号在内部生成并从外部回环到 EMAC 时,配置 EMAC 输入接口时钟。必须始终将 EMAC 的模式配置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_EXT_IN`。此选项仅在 :cpp:member:`eth_esp32_emac_config_t::clock_config` 的配置设置为 :cpp:enumerator:`emac_rmii_clock_mode_t::EMAC_CLK_OUT` 时有效。 PHY 的相关配置可以在 :cpp:class:`eth_phy_config_t` 中找到,具体包括: @@ -172,7 +264,7 @@ PHY 的相关配置可以在 :cpp:class:`eth_phy_config_t` 中找到,具体包 * :cpp:member:`eth_phy_config_t::reset_timeout_ms`:复位超时值,单位为毫秒。通常,PHY 复位应在 100 ms 内完成。 - * :cpp:member:`eth_phy_config_t::autonego_timeout_ms`:自动协商超时值,单位为毫秒。以太网驱动程序会自动与对等的以太网节点进行协商,以确定双工和速度模式。此值通常取决于电路板上 PHY 设备的性能。 + * :cpp:member:`eth_phy_config_t::autonego_timeout_ms`:自动协商超时值,单位为毫秒。以太网驱动程序会与链路另一端的设备进行自协商,以确定连接的最佳双工模式和速率。此值通常取决于电路板上 PHY 设备的性能。 * :cpp:member:`eth_phy_config_t::reset_gpio_num`:如果开发板同时将 PHY 复位管脚连接至了任意 GPIO 管脚,请使用该字段进行配置。否则,配置为 ``-1``。 @@ -434,7 +526,7 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了 bool flow_ctrl_enable = true; esp_eth_ioctl(eth_handle, ETH_CMD_S_FLOW_CTRL, &flow_ctrl_enable); -需注意,暂停帧是在自动协商期间由 PHY 向对等端公布的。只有当链路的两边都支持暂停帧时,以太网驱动程序才会发送暂停帧。 +需注意,暂停帧是在自动协商期间由 PHY 向对等端公布的。只有当链路两端都支持暂停帧时,以太网驱动程序才会发送暂停帧。 .. -------------------------------- Examples ----------------------------------- @@ -457,14 +549,14 @@ ESP-IDF 在宏 :c:macro:`ETH_DEFAULT_CONFIG` 中为安装驱动程序提供了 自定义 PHY 驱动程序 ^^^^^^^^^^^^^^^^^^^^^^^^^ -目前市面上已有多家 PHY 制造商提供了大量的芯片组合。ESP-IDF 现已支持数种 PHY 芯片,但是由于价格、功能、库存等原因,有时用户还是无法找到一款能满足其实际需求的芯片。 +市面上有多家 PHY 芯片制造商提供各种类型的芯片。ESP-IDF 现已支持数种 PHY 芯片,但是由于价格、功能、库存等原因,有时用户还是无法找到一款能满足其实际需求的芯片。 -好在 IEEE 802.3 在其 22.2.4 管理功能部分对 EMAC 和 PHY 之间的管理接口进行了标准化。该部分定义了所谓的 ”MII 管理接口”规范,用于控制 PHY 和收集 PHY 的状态,还定义了一组管理寄存器来控制芯片行为、链接属性、自动协商配置等。在 ESP-IDF 中,这项基本的管理功能是由 :component_file:`esp_eth/src/esp_eth_phy_802_3.c` 实现的,这也大大降低了创建新的自定义 PHY 芯片驱动的难度。 +好在 IEEE 802.3 在其 22.2.4 管理功能部分对 EMAC 和 PHY 之间的管理接口进行了标准化。该部分定义了所谓的 ”MII 管理接口”规范,用于控制 PHY 和收集 PHY 的状态,还定义了一组管理寄存器来控制芯片行为、链接属性、自动协商配置等。在 ESP-IDF 中,这项基本的管理功能是由 :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` 实现的,这也大大降低了创建新的自定义 PHY 芯片驱动的难度。 .. note:: 由于一些 PHY 芯片可能不符合 IEEE 802.3 第 22.2.4 节的规定,所以请首先查看 PHY 数据手册。不过,就算芯片不符合规定,依旧可以创建自定义 PHY 驱动程序,只是由于需要自行定义所有的 PHY 管理功能,这个过程将变得较为复杂。 -ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 :component_file:`esp_eth/src/esp_eth_phy_802_3.c` 中。不过对于以下几项,可能仍需针对不同芯片开发具体的管理功能: +ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 :component_file:`esp_eth/src/phy/esp_eth_phy_802_3.c` 中。不过对于以下几项,可能仍需针对不同芯片开发具体的管理功能: * 链接状态。此项总是由使用的具体芯片决定 * 芯片初始化。即使不存在严格的限制,也应进行自定义,以确保使用的是符合预期的芯片 @@ -472,11 +564,11 @@ ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 **创建自定义 PHY 驱动程序的步骤:** -1. 请根据 PHY 数据手册,定义针对供应商的特定注册表布局。示例请参见 :component_file:`esp_eth/src/esp_eth_phy_ip101.c`。 +1. 请根据 PHY 数据手册,定义针对供应商的特定注册表布局。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ip101.c`。 2. 准备衍生的 PHY 管理对象信息结构,该结构: * 必须至少包含 IEEE 802.3 :cpp:class:`phy_802_3_t` 父对象 - * 可选包含支持非 IEEE 802.3 或自定义功能所需的额外变量。示例请参见 :component_file:`esp_eth/src/esp_eth_phy_ksz80xx.c`。 + * 可选择包含额外的变量,以支持非 IEEE 802.3 或定制功能。示例请参见 :component_file:`esp_eth/src/phy/esp_eth_phy_ksz80xx.c`。 3. 定义针对芯片的特定管理回调功能。 4. 初始化 IEEE 802.3 父对象并重新分配针对芯片的特定管理回调功能。 @@ -488,10 +580,13 @@ ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 API 参考 ------------- +.. include-build-file:: inc/eth_types.inc .. include-build-file:: inc/esp_eth.inc .. include-build-file:: inc/esp_eth_driver.inc .. include-build-file:: inc/esp_eth_com.inc .. include-build-file:: inc/esp_eth_mac.inc +.. include-build-file:: inc/esp_eth_mac_esp.inc +.. include-build-file:: inc/esp_eth_mac_spi.inc .. include-build-file:: inc/esp_eth_phy.inc .. include-build-file:: inc/esp_eth_phy_802_3.inc .. include-build-file:: inc/esp_eth_netif_glue.inc diff --git a/examples/common_components/protocol_examples_common/eth_connect.c b/examples/common_components/protocol_examples_common/eth_connect.c index 72cfa8987bd..74f3cb3b24c 100644 --- a/examples/common_components/protocol_examples_common/eth_connect.c +++ b/examples/common_components/protocol_examples_common/eth_connect.c @@ -99,8 +99,8 @@ static esp_netif_t *eth_start(void) phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO; #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); - esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; - esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; + esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config); #if CONFIG_EXAMPLE_ETH_PHY_IP101 s_phy = esp_eth_phy_new_ip101(&phy_config); diff --git a/examples/ethernet/basic/components/ethernet_init/ethernet_init.c b/examples/ethernet/basic/components/ethernet_init/ethernet_init.c index 61adee9ee21..d5f4ea34172 100644 --- a/examples/ethernet/basic/components/ethernet_init/ethernet_init.c +++ b/examples/ethernet/basic/components/ethernet_init/ethernet_init.c @@ -69,8 +69,8 @@ static esp_eth_handle_t eth_init_internal(esp_eth_mac_t **mac_out, esp_eth_phy_t // Init vendor specific MAC config to default eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG(); // Update vendor specific MAC config based on board configuration - esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; - esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; + esp32_emac_config.smi_gpio.mdc_num = CONFIG_EXAMPLE_ETH_MDC_GPIO; + esp32_emac_config.smi_gpio.mdio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO; #if CONFIG_EXAMPLE_USE_SPI_ETHERNET // The DMA is shared resource between EMAC and the SPI. Therefore, adjust // EMAC DMA burst length when SPI Ethernet is used along with EMAC. diff --git a/examples/ethernet/basic/components/ethernet_init/ethernet_init.h b/examples/ethernet/basic/components/ethernet_init/ethernet_init.h index 8fa5df6106c..6ebec50aee6 100644 --- a/examples/ethernet/basic/components/ethernet_init/ethernet_init.h +++ b/examples/ethernet/basic/components/ethernet_init/ethernet_init.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -24,6 +24,18 @@ extern "C" { */ esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt_out); +/** + * @brief De-initialize array of Ethernet drivers + * @note All Ethernet drivers in the array must be stopped prior calling this function. + * + * @param[in] eth_handles array of Ethernet drivers to be de-initialized + * @param[in] eth_cnt number of Ethernets drivers to be de-initialized + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG when passed invalid pointers + */ +esp_err_t example_eth_deinit(esp_eth_handle_t *eth_handles, uint8_t eth_cnt); + #ifdef __cplusplus } #endif diff --git a/examples/protocols/http_server/async_handlers/main/main.c b/examples/protocols/http_server/async_handlers/main/main.c index 96fb13e671f..7a1091c10d5 100644 --- a/examples/protocols/http_server/async_handlers/main/main.c +++ b/examples/protocols/http_server/async_handlers/main/main.c @@ -36,7 +36,7 @@ static const char *TAG = "example"; -// Async reqeusts are queued here while they wait to +// Async requests are queued here while they wait to // be processed by the workers static QueueHandle_t async_req_queue; diff --git a/examples/protocols/http_server/simple/main/main.c b/examples/protocols/http_server/simple/main/main.c index d3dfffe497f..e13810a4e12 100644 --- a/examples/protocols/http_server/simple/main/main.c +++ b/examples/protocols/http_server/simple/main/main.c @@ -397,9 +397,9 @@ static httpd_handle_t start_webserver(void) httpd_handle_t server = NULL; httpd_config_t config = HTTPD_DEFAULT_CONFIG(); #if CONFIG_IDF_TARGET_LINUX - // Setting port as 8001 when building for Linux. Port 80 can be used only by a priviliged user in linux. - // So when a unpriviliged user tries to run the application, it throws bind error and the server is not started. - // Port 8001 can be used by an unpriviliged user as well. So the application will not throw bind error and the + // Setting port as 8001 when building for Linux. Port 80 can be used only by a privileged user in linux. + // So when a unprivileged user tries to run the application, it throws bind error and the server is not started. + // Port 8001 can be used by an unprivileged user as well. So the application will not throw bind error and the // server will be started. config.server_port = 8001; #endif // !CONFIG_IDF_TARGET_LINUX diff --git a/examples/protocols/sockets/tcp_client_multi_net/main/tcp_client_multiple.c b/examples/protocols/sockets/tcp_client_multi_net/main/tcp_client_multiple.c index d537adf1bd3..2c911146002 100644 --- a/examples/protocols/sockets/tcp_client_multi_net/main/tcp_client_multiple.c +++ b/examples/protocols/sockets/tcp_client_multi_net/main/tcp_client_multiple.c @@ -11,7 +11,6 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_netif.h" -#include "esp_eth.h" #include "esp_event.h" #include "esp_log.h" #include "sdkconfig.h" @@ -89,13 +88,13 @@ static void app_multiple_handle(esp_ip4_addr_t *ip4_addr, esp_netif_t *esp_netif ret = send(sock, payload, strlen(payload), 0); if (ret < 0) { - ESP_LOGE(TAG, "\"%s\" Error occured during sending: errno %d", netif_name, errno); + ESP_LOGE(TAG, "\"%s\" Error occurred during sending: errno %d", netif_name, errno); goto app_multiple_handle_fail; } ret = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); if (ret < 0) { - ESP_LOGE(TAG, "\"%s\" Error occured during receiving: errno %d", netif_name, errno); + ESP_LOGE(TAG, "\"%s\" Error occurred during receiving: errno %d", netif_name, errno); } else if (ret > 0){ rx_buffer[ret] = 0; // Null-terminate whatever we received and treat like a string ESP_LOGI(TAG, "\"%s\" Received Data %d bytes", netif_name, ret); diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index d2e8394f3e1..e0fcb163efb 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -398,7 +398,6 @@ components/bt/host/bluedroid/stack/smp/smp_main.c components/bt/host/bluedroid/stack/smp/smp_utils.c components/console/linenoise/linenoise.c components/console/linenoise/linenoise.h -components/esp_eth/src/ksz8851.h components/esp_event/host_test/esp_event_unit_test/main/esp_event_test.cpp components/esp_event/host_test/fixtures.hpp components/esp_hid/include/esp_hidd.h @@ -719,7 +718,6 @@ components/soc/esp32s3/include/soc/wdev_reg.h components/soc/esp32s3/ledc_periph.c components/soc/esp32s3/uart_periph.c components/soc/include/soc/dedic_gpio_periph.h -components/soc/include/soc/emac_periph.h components/soc/include/soc/gpio_periph.h components/soc/include/soc/ledc_periph.h components/soc/lldesc.c From d6b3b8feeb00602deaf4a3a9e08c9e6c5e97e061 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Tue, 23 Apr 2024 16:49:51 +0200 Subject: [PATCH 189/548] feat(esp_eth): added example to deinit Ethernet --- .../components/ethernet_init/CMakeLists.txt | 2 +- .../components/ethernet_init/ethernet_init.c | 65 +++++++++++++++---- .../ethernet/basic/main/Kconfig.projbuild | 9 +++ .../basic/main/ethernet_example_main.c | 31 +++++++-- 4 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 examples/ethernet/basic/main/Kconfig.projbuild diff --git a/examples/ethernet/basic/components/ethernet_init/CMakeLists.txt b/examples/ethernet/basic/components/ethernet_init/CMakeLists.txt index 382893ed87f..ef299cdfd4c 100644 --- a/examples/ethernet/basic/components/ethernet_init/CMakeLists.txt +++ b/examples/ethernet/basic/components/ethernet_init/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "ethernet_init.c" - PRIV_REQUIRES driver esp_eth + PRIV_REQUIRES esp_driver_gpio esp_eth INCLUDE_DIRS ".") diff --git a/examples/ethernet/basic/components/ethernet_init/ethernet_init.c b/examples/ethernet/basic/components/ethernet_init/ethernet_init.c index d5f4ea34172..b34304e4a37 100644 --- a/examples/ethernet/basic/components/ethernet_init/ethernet_init.c +++ b/examples/ethernet/basic/components/ethernet_init/ethernet_init.c @@ -9,11 +9,9 @@ #include "esp_mac.h" #include "driver/gpio.h" #include "sdkconfig.h" -#if CONFIG_ETH_USE_SPI_ETHERNET +#if CONFIG_EXAMPLE_USE_SPI_ETHERNET #include "driver/spi_master.h" -#endif // CONFIG_ETH_USE_SPI_ETHERNET - -static const char *TAG = "example_eth_init"; +#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET #if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM #define SPI_ETHERNETS_NUM CONFIG_EXAMPLE_SPI_ETHERNETS_NUM @@ -45,6 +43,12 @@ typedef struct { uint8_t *mac_addr; }spi_eth_module_config_t; +static const char *TAG = "example_eth_init"; +#if CONFIG_EXAMPLE_USE_SPI_ETHERNET +static bool gpio_isr_svc_init_by_eth = false; // indicates that we initialized the GPIO ISR service +#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET + + #if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET /** * @brief Internal ESP32 Ethernet initialization @@ -128,17 +132,19 @@ static esp_err_t spi_bus_init(void) { esp_err_t ret = ESP_OK; +#if (CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO >= 0) || (CONFIG_EXAMPLE_ETH_SPI_INT1_GPIO > 0) // Install GPIO ISR handler to be able to service SPI Eth modules interrupts ret = gpio_install_isr_service(0); - if (ret != ESP_OK) { - if (ret == ESP_ERR_INVALID_STATE) { - ESP_LOGW(TAG, "GPIO ISR handler has been already installed"); - ret = ESP_OK; // ISR handler has been already installed so no issues - } else { - ESP_LOGE(TAG, "GPIO ISR handler install failed"); - goto err; - } + if (ret == ESP_OK) { + gpio_isr_svc_init_by_eth = true; + } else if (ret == ESP_ERR_INVALID_STATE) { + ESP_LOGW(TAG, "GPIO ISR handler has been already installed"); + ret = ESP_OK; // ISR handler has been already installed so no issues + } else { + ESP_LOGE(TAG, "GPIO ISR handler install failed"); + goto err; } +#endif // Init SPI bus spi_bus_config_t buscfg = { @@ -283,7 +289,7 @@ esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt ESP_GOTO_ON_FALSE(eth_handles[eth_cnt], ESP_FAIL, err, TAG, "SPI Ethernet init failed"); eth_cnt++; } -#endif // CONFIG_ETH_USE_SPI_ETHERNET +#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET #else ESP_LOGD(TAG, "no Ethernet device selected to init"); #endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET || CONFIG_EXAMPLE_USE_SPI_ETHERNET @@ -297,3 +303,36 @@ esp_err_t example_eth_init(esp_eth_handle_t *eth_handles_out[], uint8_t *eth_cnt return ret; #endif } + +esp_err_t example_eth_deinit(esp_eth_handle_t *eth_handles, uint8_t eth_cnt) +{ + ESP_RETURN_ON_FALSE(eth_handles != NULL, ESP_ERR_INVALID_ARG, TAG, "array of Ethernet handles cannot be NULL"); + for (int i = 0; i < eth_cnt; i++) { + esp_eth_mac_t *mac = NULL; + esp_eth_phy_t *phy = NULL; + if (eth_handles[i] != NULL) { + esp_eth_get_mac_instance(eth_handles[i], &mac); + esp_eth_get_phy_instance(eth_handles[i], &phy); + ESP_RETURN_ON_ERROR(esp_eth_driver_uninstall(eth_handles[i]), TAG, "Ethernet %p uninstall failed", eth_handles[i]); + } + if (mac != NULL) { + mac->del(mac); + } + if (phy != NULL) { + phy->del(phy); + } + } +#if CONFIG_EXAMPLE_USE_SPI_ETHERNET + spi_bus_free(CONFIG_EXAMPLE_ETH_SPI_HOST); +#if (CONFIG_EXAMPLE_ETH_SPI_INT0_GPIO >= 0) || (CONFIG_EXAMPLE_ETH_SPI_INT1_GPIO > 0) + // We installed the GPIO ISR service so let's uninstall it too. + // BE CAREFUL HERE though since the service might be used by other functionality! + if (gpio_isr_svc_init_by_eth) { + ESP_LOGW(TAG, "uninstalling GPIO ISR service!"); + gpio_uninstall_isr_service(); + } +#endif +#endif //CONFIG_EXAMPLE_USE_SPI_ETHERNET + free(eth_handles); + return ESP_OK; +} diff --git a/examples/ethernet/basic/main/Kconfig.projbuild b/examples/ethernet/basic/main/Kconfig.projbuild new file mode 100644 index 00000000000..27a8f9d7422 --- /dev/null +++ b/examples/ethernet/basic/main/Kconfig.projbuild @@ -0,0 +1,9 @@ +menu "Example Configuration" + config EXAMPLE_ETH_DEINIT_AFTER_S + int "Stop and deinit Ethernet after elapsing number of secs" + range -1 300 + default -1 + help + This option is for demonstration purposes only to demonstrate deinitialization of the Ethernet driver. + Set to -1 to not deinitialize. +endmenu diff --git a/examples/ethernet/basic/main/ethernet_example_main.c b/examples/ethernet/basic/main/ethernet_example_main.c index b3033e3329d..71f99a16877 100644 --- a/examples/ethernet/basic/main/ethernet_example_main.c +++ b/examples/ethernet/basic/main/ethernet_example_main.c @@ -75,14 +75,18 @@ void app_main(void) // Create default event loop that running in background ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_t *eth_netifs[eth_port_cnt]; + esp_eth_netif_glue_handle_t eth_netif_glues[eth_port_cnt]; + // Create instance(s) of esp-netif for Ethernet(s) if (eth_port_cnt == 1) { // Use ESP_NETIF_DEFAULT_ETH when just one Ethernet interface is used and you don't need to modify // default esp-netif configuration parameters. esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH(); - esp_netif_t *eth_netif = esp_netif_new(&cfg); + eth_netifs[0] = esp_netif_new(&cfg); + eth_netif_glues[0] = esp_eth_new_netif_glue(eth_handles[0]); // Attach Ethernet driver to TCP/IP stack - ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[0]))); + ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[0], eth_netif_glues[0])); } else { // Use ESP_NETIF_INHERENT_DEFAULT_ETH when multiple Ethernet interfaces are used and so you need to modify // esp-netif configuration parameters for each interface (name, priority, etc.). @@ -101,10 +105,10 @@ void app_main(void) esp_netif_config.if_key = if_key_str; esp_netif_config.if_desc = if_desc_str; esp_netif_config.route_prio -= i*5; - esp_netif_t *eth_netif = esp_netif_new(&cfg_spi); - + eth_netifs[i] = esp_netif_new(&cfg_spi); + eth_netif_glues[i] = esp_eth_new_netif_glue(eth_handles[0]); // Attach Ethernet driver to TCP/IP stack - ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i]))); + ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], eth_netif_glues[i])); } } @@ -116,4 +120,21 @@ void app_main(void) for (int i = 0; i < eth_port_cnt; i++) { ESP_ERROR_CHECK(esp_eth_start(eth_handles[i])); } + +#if CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S >= 0 + // For demonstration purposes, wait and then deinit Ethernet network + vTaskDelay(pdMS_TO_TICKS(CONFIG_EXAMPLE_ETH_DEINIT_AFTER_S * 1000)); + ESP_LOGI(TAG, "stop and deinitialize Ethernet network..."); + // Stop Ethernet driver state machine and destroy netif + for (int i = 0; i < eth_port_cnt; i++) { + ESP_ERROR_CHECK(esp_eth_stop(eth_handles[i])); + ESP_ERROR_CHECK(esp_eth_del_netif_glue(eth_netif_glues[i])); + esp_netif_destroy(eth_netifs[i]); + } + esp_netif_deinit(); + ESP_ERROR_CHECK(example_eth_deinit(eth_handles, eth_port_cnt)); + ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler)); + ESP_ERROR_CHECK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler)); + ESP_ERROR_CHECK(esp_event_loop_delete_default()); +#endif // EXAMPLE_ETH_DEINIT_AFTER_S > 0 } From dab7fdd6f0ccef515717b4bc0d8d27932e91e81e Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Wed, 15 May 2024 09:27:37 +0200 Subject: [PATCH 190/548] fix(esp_eth): fixing memory leak and invalid bit shift --- components/esp_eth/src/mac/esp_eth_mac_esp.c | 2 +- components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp.c b/components/esp_eth/src/mac/esp_eth_mac_esp.c index f0813bb7cac..061b8988d4d 100644 --- a/components/esp_eth/src/mac/esp_eth_mac_esp.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp.c @@ -574,8 +574,8 @@ static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_ config->rx_task_prio, &emac->rx_task_hdl, core_num); ESP_GOTO_ON_FALSE(xReturned == pdPASS, ESP_FAIL, err, TAG, "create emac_rx task failed"); - *emac_out_hdl = emac; err: + *emac_out_hdl = emac; return ret; } diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c b/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c index cb9ea5c1a21..3117832b294 100644 --- a/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp_gpio.c @@ -28,7 +28,7 @@ static uint64_t s_emac_esp_used_gpio_mask = 0x0; static esp_err_t emac_esp_gpio_matrix_init(gpio_num_t gpio_num, uint32_t signal_in_idx, uint32_t signal_out_idx, gpio_mode_t mode) { // silently skip when user don't want to connect the signal to GPIO pad - if (gpio_num == GPIO_NUM_NC) { + if (gpio_num <= GPIO_NUM_NC) { ESP_LOGD(TAG, "%s skipping signal in_idx %" PRIu32 ", out_idx %" PRIu32, __func__, signal_in_idx, signal_out_idx); return ESP_OK; } @@ -74,6 +74,11 @@ static esp_err_t emac_esp_iomux_init(gpio_num_t gpio_num, const emac_iomux_info_ ESP_LOGD(TAG, "%s skipping target undefined iomux periph function", __func__); return ESP_OK; } + // silently skip when user don't want to iomux the function to GPIO pad + if (gpio_num <= GPIO_NUM_NC) { + ESP_LOGD(TAG, "%s user defined GPIO not connected - skipping", __func__); + return ESP_OK; + } // loop over target iomux_info until reached end of list indicated by invalid GPIO num while (iomux_info->gpio_num != GPIO_NUM_MAX) { // if requested GPIO number can be IO muxed or select single pad that can be muxed on the target From 09cbbaaf7ca3cce3f65fd45db882c3aa3f5c6efd Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Wed, 5 Jun 2024 10:48:43 +0200 Subject: [PATCH 191/548] fix(esp_eth): Fixed another memory leak ESP MAC --- components/esp_eth/src/mac/esp_eth_mac_esp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp.c b/components/esp_eth/src/mac/esp_eth_mac_esp.c index 061b8988d4d..2ceb2d15b87 100644 --- a/components/esp_eth/src/mac/esp_eth_mac_esp.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp.c @@ -659,7 +659,7 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_esp32_emac_config_t *esp32_config } ret_code = emac_esp_alloc_driver_obj(config, &emac); - ESP_RETURN_ON_FALSE(ret_code == ESP_OK, NULL, TAG, "alloc driver object failed"); + ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc driver object failed"); // enable bus clock for the EMAC module, and reset the registers into default state // this must be called before HAL layer initialization From 2f0c9b3584f0a13e2ad1121e292062c6f7b4b817 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 25 Apr 2024 18:16:29 +0800 Subject: [PATCH 192/548] feat(gdma): set burst size and return alignment constraint burst size can affect the buffer alignment --- .../esp_driver_spi/src/gpspi/spi_common.c | 11 +- components/esp_hw_support/CMakeLists.txt | 5 +- .../esp_hw_support/deprecated/gdma_legacy.c | 62 ++++++++ components/esp_hw_support/dma/gdma.c | 133 +++++++----------- components/esp_hw_support/dma/gdma_crc.c | 74 ++++++++++ components/esp_hw_support/dma/gdma_priv.h | 6 +- .../dma/include/esp_private/gdma.h | 90 +++++++++--- components/hal/esp32c2/include/hal/gdma_ll.h | 1 + components/hal/esp32c3/include/hal/gdma_ll.h | 1 + components/hal/esp32c6/include/hal/gdma_ll.h | 1 + components/hal/esp32h2/include/hal/gdma_ll.h | 1 + .../hal/esp32p4/include/hal/axi_dma_ll.h | 32 ++++- components/hal/esp32s3/include/hal/gdma_ll.h | 31 ++-- components/hal/gdma_hal_ahb_v1.c | 18 +-- components/hal/gdma_hal_ahb_v2.c | 16 ++- components/hal/gdma_hal_axi.c | 22 ++- components/hal/gdma_hal_top.c | 15 +- components/hal/include/hal/gdma_hal.h | 7 +- components/hal/include/hal/gdma_hal_ahb.h | 2 +- components/hal/include/hal/gdma_hal_axi.h | 2 + .../esp_crypto_shared_gdma.c | 18 ++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 2 +- .../soc/esp32p4/include/soc/axi_dma_struct.h | 122 ++-------------- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- .../test_apps/main/test_crypto.c | 53 ++++--- .../spi_flash/spi_flash_concurrency.rst | 4 +- .../spi_flash/spi_flash_concurrency.rst | 4 +- 27 files changed, 430 insertions(+), 305 deletions(-) create mode 100644 components/esp_hw_support/deprecated/gdma_legacy.c create mode 100644 components/esp_hw_support/dma/gdma_crc.c diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 7d5b139a0c1..3e2ba4895c8 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -243,12 +243,13 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch gdma_connect(dma_ctx->rx_dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3)); } #endif - gdma_transfer_ability_t ability = { - .psram_trans_align = 0, // fall back to use the same size of the psram data cache line size - .sram_trans_align = 4, + // TODO: add support to allow SPI transfer PSRAM buffer + gdma_transfer_config_t trans_cfg = { + .max_data_burst_size = 16, + .access_ext_mem = false, }; - ESP_RETURN_ON_ERROR(gdma_set_transfer_ability(dma_ctx->tx_dma_chan, &ability), SPI_TAG, "set gdma tx transfer ability failed"); - ESP_RETURN_ON_ERROR(gdma_set_transfer_ability(dma_ctx->rx_dma_chan, &ability), SPI_TAG, "set gdma rx transfer ability failed"); + ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->tx_dma_chan, &trans_cfg), SPI_TAG, "config gdma tx transfer failed"); + ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->rx_dma_chan, &trans_cfg), SPI_TAG, "config gdma rx transfer failed"); } return ret; } diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index db2c68dadd8..e1b8875dc55 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -68,13 +68,16 @@ if(NOT BOOTLOADER_BUILD) endif() if(CONFIG_SOC_GDMA_SUPPORTED) - list(APPEND srcs "dma/gdma.c") + list(APPEND srcs "dma/gdma.c" "deprecated/gdma_legacy.c") if(CONFIG_SOC_GDMA_SUPPORT_SLEEP_RETENTION) list(APPEND srcs "dma/gdma_sleep_retention.c") endif() if(CONFIG_SOC_GDMA_SUPPORT_ETM) list(APPEND srcs "dma/gdma_etm.c") endif() + if(CONFIG_SOC_GDMA_SUPPORT_CRC) + list(APPEND srcs "dma/gdma_crc.c") + endif() endif() if(CONFIG_SOC_GP_LDO_SUPPORTED) diff --git a/components/esp_hw_support/deprecated/gdma_legacy.c b/components/esp_hw_support/deprecated/gdma_legacy.c new file mode 100644 index 00000000000..f25dd2c8ab5 --- /dev/null +++ b/components/esp_hw_support/deprecated/gdma_legacy.c @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_check.h" +#include "../dma/gdma_priv.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" + +static const char *TAG = "gdma"; + +esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability) +{ + ESP_RETURN_ON_FALSE(dma_chan && ability, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + gdma_pair_t *pair = dma_chan->pair; + gdma_group_t *group = pair->group; + gdma_hal_context_t *hal = &group->hal; + + size_t int_mem_alignment = ability->sram_trans_align; + size_t ext_mem_alignment = ability->psram_trans_align; + // alignment should be 2^n + ESP_RETURN_ON_FALSE((int_mem_alignment & (int_mem_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, + TAG, "invalid sram alignment: %zu", int_mem_alignment); + + uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); + if (ext_mem_alignment == 0) { + // fall back to use the same size of the psram data cache line size + ext_mem_alignment = ext_mem_cache_line_size; + } + if ((ext_mem_cache_line_size > 0) && (ext_mem_alignment > ext_mem_cache_line_size)) { + ESP_RETURN_ON_FALSE(((ext_mem_alignment % ext_mem_cache_line_size) == 0), ESP_ERR_INVALID_ARG, + TAG, "ext_mem_alignment(%d) should be multiple of the ext_mem_cache_line_size(%"PRIu32")", + ext_mem_alignment, ext_mem_cache_line_size); + } + + // if the DMA can't access the PSRAM, this HAL function is no-op + gdma_hal_set_burst_size(hal, pair->pair_id, dma_chan->direction, ext_mem_alignment); + + // TX channel can always enable burst mode, no matter data alignment + bool en_burst = true; + if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) { + // RX channel burst mode depends on specific data alignment + en_burst = int_mem_alignment >= 4; + } + gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_burst, en_burst); + + dma_chan->int_mem_alignment = int_mem_alignment; + dma_chan->ext_mem_alignment = ext_mem_alignment; + ESP_LOGD(TAG, "%s channel (%d,%d), (%u:%u) bytes aligned, burst %s", dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX ? "tx" : "rx", + group->group_id, pair->pair_id, int_mem_alignment, ext_mem_alignment, en_burst ? "enabled" : "disabled"); + + return ESP_OK; +} diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index c283a30bd01..d78c5cbf1b3 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "sdkconfig.h" #if CONFIG_GDMA_ENABLE_DEBUG_LOG // The local log level must be defined before including esp_log.h @@ -42,10 +43,9 @@ #include "esp_log.h" #include "esp_check.h" #include "esp_memory_utils.h" +#include "esp_flash_encrypt.h" #include "esp_private/periph_ctrl.h" #include "gdma_priv.h" -#include "hal/cache_hal.h" -#include "hal/cache_ll.h" #if CONFIG_PM_ENABLE && SOC_PM_SUPPORT_TOP_PD #include "esp_private/gdma_sleep_retention.h" @@ -354,46 +354,68 @@ esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_ return ESP_OK; } -esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability) +esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config) { - ESP_RETURN_ON_FALSE(dma_chan && ability, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + uint32_t max_data_burst_size = config->max_data_burst_size; + if (max_data_burst_size) { + // burst size must be power of 2 + ESP_RETURN_ON_FALSE((max_data_burst_size & (max_data_burst_size - 1)) == 0, ESP_ERR_INVALID_ARG, + TAG, "invalid max_data_burst_size: %"PRIu32, max_data_burst_size); + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; + size_t int_mem_alignment = 1; + size_t ext_mem_alignment = 1; - size_t sram_alignment = ability->sram_trans_align; - size_t psram_alignment = ability->psram_trans_align; - // alignment should be 2^n - ESP_RETURN_ON_FALSE((sram_alignment & (sram_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, - TAG, "invalid sram alignment: %zu", sram_alignment); - - uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); - if (psram_alignment == 0) { - // fall back to use the same size of the psram data cache line size - psram_alignment = ext_mem_cache_line_size; + // always enable descriptor burst as the descriptor is always word aligned and is in the internal SRAM + bool en_desc_burst = true; + bool en_data_burst = max_data_burst_size > 0; + gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_data_burst, en_desc_burst); + if (en_data_burst) { + gdma_hal_set_burst_size(hal, pair->pair_id, dma_chan->direction, max_data_burst_size); } - if (psram_alignment > ext_mem_cache_line_size) { - ESP_RETURN_ON_FALSE(((psram_alignment % ext_mem_cache_line_size) == 0), ESP_ERR_INVALID_ARG, - TAG, "psram_alignment(%d) should be multiple of the ext_mem_cache_line_size(%"PRIu32")", - psram_alignment, ext_mem_cache_line_size); + +#if GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT + if (en_data_burst && dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) { + int_mem_alignment = MAX(int_mem_alignment, 4); + ext_mem_alignment = MAX(ext_mem_alignment, max_data_burst_size); } +#endif - // if the DMA can't access the PSRAM, this HAL function is no-op - gdma_hal_set_ext_mem_align(hal, pair->pair_id, dma_chan->direction, psram_alignment); + // if MSPI encryption is enabled, and DMA wants to read/write external memory + if (esp_flash_encryption_enabled()) { + gdma_hal_enable_access_encrypt_mem(hal, pair->pair_id, dma_chan->direction, config->access_ext_mem); + // when DMA access the encrypted memory, extra alignment is needed, for both internal and external memory + if (config->access_ext_mem) { + ext_mem_alignment = MAX(ext_mem_alignment, GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT); + int_mem_alignment = MAX(int_mem_alignment, GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT); + } + } else { + gdma_hal_enable_access_encrypt_mem(hal, pair->pair_id, dma_chan->direction, false); + } - // TX channel can always enable burst mode, no matter data alignment - bool en_burst = true; - if (dma_chan->direction == GDMA_CHANNEL_DIRECTION_RX) { - // RX channel burst mode depends on specific data alignment - en_burst = sram_alignment >= 4; + // if the channel is not allowed to access external memory, set a super big (meaningless) alignment value + // so when the upper layer checks the alignment with an external buffer, the check should fail + if (!config->access_ext_mem) { + ext_mem_alignment = BIT(31); } - gdma_hal_enable_burst(hal, pair->pair_id, dma_chan->direction, en_burst, en_burst); - dma_chan->sram_alignment = sram_alignment; - dma_chan->psram_alignment = psram_alignment; - ESP_LOGD(TAG, "%s channel (%d,%d), (%u:%u) bytes aligned, burst %s", dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX ? "tx" : "rx", - group->group_id, pair->pair_id, sram_alignment, psram_alignment, en_burst ? "enabled" : "disabled"); + dma_chan->int_mem_alignment = int_mem_alignment; + dma_chan->ext_mem_alignment = ext_mem_alignment; + return ESP_OK; +} +esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment) +{ + ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (int_mem_alignment) { + *int_mem_alignment = dma_chan->int_mem_alignment; + } + if (ext_mem_alignment) { + *ext_mem_alignment = dma_chan->ext_mem_alignment; + } return ESP_OK; } @@ -421,57 +443,6 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority) return ESP_OK; } -#if SOC_GDMA_SUPPORT_CRC -esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config) -{ - ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - gdma_pair_t *pair = dma_chan->pair; - gdma_group_t *group = pair->group; - gdma_hal_context_t *hal = &group->hal; - switch (group->bus_id) { -#if SOC_AHB_GDMA_SUPPORTED - case SOC_GDMA_BUS_AHB: - ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AHB_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); - break; -#endif // SOC_AHB_GDMA_SUPPORTED -#if SOC_AXI_GDMA_SUPPORTED - case SOC_GDMA_BUS_AXI: - ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AXI_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); - break; -#endif // SOC_AXI_GDMA_SUPPORTED - default: - ESP_LOGE(TAG, "invalid bus id: %d", group->bus_id); - return ESP_ERR_INVALID_ARG; - } - - // clear the previous CRC result - gdma_hal_clear_crc(hal, pair->pair_id, dma_chan->direction); - - // set polynomial and initial value - gdma_hal_crc_config_t hal_config = { - .crc_bit_width = config->crc_bit_width, - .poly_hex = config->poly_hex, - .init_value = config->init_value, - .reverse_data_mask = config->reverse_data_mask, - }; - gdma_hal_set_crc_poly(hal, pair->pair_id, dma_chan->direction, &hal_config); - - return ESP_OK; -} - -esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result) -{ - ESP_RETURN_ON_FALSE(dma_chan && result, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - gdma_pair_t *pair = dma_chan->pair; - gdma_group_t *group = pair->group; - gdma_hal_context_t *hal = &group->hal; - - *result = gdma_hal_get_crc_result(hal, pair->pair_id, dma_chan->direction); - - return ESP_OK; -} -#endif // SOC_GDMA_SUPPORT_CRC - esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data) { ESP_RETURN_ON_FALSE(dma_chan && cbs && dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); diff --git a/components/esp_hw_support/dma/gdma_crc.c b/components/esp_hw_support/dma/gdma_crc.c new file mode 100644 index 00000000000..da7425d39db --- /dev/null +++ b/components/esp_hw_support/dma/gdma_crc.c @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#if CONFIG_GDMA_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "soc/soc_caps.h" +#include "soc/periph_defs.h" +#include "esp_log.h" +#include "esp_check.h" +#include "gdma_priv.h" + +static const char *TAG = "gdma"; + +esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config) +{ + ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + gdma_pair_t *pair = dma_chan->pair; + gdma_group_t *group = pair->group; + gdma_hal_context_t *hal = &group->hal; + switch (group->bus_id) { +#if SOC_AHB_GDMA_SUPPORTED + case SOC_GDMA_BUS_AHB: + ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AHB_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); + break; +#endif // SOC_AHB_GDMA_SUPPORTED +#if SOC_AXI_GDMA_SUPPORTED + case SOC_GDMA_BUS_AXI: + ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AXI_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); + break; +#endif // SOC_AXI_GDMA_SUPPORTED + default: + ESP_LOGE(TAG, "invalid bus id: %d", group->bus_id); + return ESP_ERR_INVALID_ARG; + } + + // clear the previous CRC result + gdma_hal_clear_crc(hal, pair->pair_id, dma_chan->direction); + + // set polynomial and initial value + gdma_hal_crc_config_t hal_config = { + .crc_bit_width = config->crc_bit_width, + .poly_hex = config->poly_hex, + .init_value = config->init_value, + .reverse_data_mask = config->reverse_data_mask, + }; + gdma_hal_set_crc_poly(hal, pair->pair_id, dma_chan->direction, &hal_config); + + return ESP_OK; +} + +esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result) +{ + ESP_RETURN_ON_FALSE(dma_chan && result, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + gdma_pair_t *pair = dma_chan->pair; + gdma_group_t *group = pair->group; + gdma_hal_context_t *hal = &group->hal; + + *result = gdma_hal_get_crc_result(hal, pair->pair_id, dma_chan->direction); + + return ESP_OK; +} diff --git a/components/esp_hw_support/dma/gdma_priv.h b/components/esp_hw_support/dma/gdma_priv.h index 202f3ec949c..600397be023 100644 --- a/components/esp_hw_support/dma/gdma_priv.h +++ b/components/esp_hw_support/dma/gdma_priv.h @@ -32,6 +32,8 @@ #define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED #endif +#define GDMA_ACCESS_ENCRYPTION_MEM_ALIGNMENT 16 /*!< The alignment of the memory and size when DMA accesses the encryption memory */ + #ifdef __cplusplus extern "C" { #endif @@ -67,8 +69,8 @@ struct gdma_channel_t { portMUX_TYPE spinlock; // channel level spinlock gdma_channel_direction_t direction; // channel direction int periph_id; // Peripheral instance ID, indicates which peripheral is connected to this GDMA channel - size_t sram_alignment; // alignment for memory in SRAM - size_t psram_alignment; // alignment for memory in PSRAM + size_t int_mem_alignment; // alignment for memory in internal memory + size_t ext_mem_alignment; // alignment for memory in external memory esp_err_t (*del)(gdma_channel_t *channel); // channel deletion function, it's polymorphic, see `gdma_del_tx_channel` or `gdma_del_rx_channel` struct { uint32_t start_stop_by_etm: 1; // whether the channel is started/stopped by ETM diff --git a/components/esp_hw_support/dma/include/esp_private/gdma.h b/components/esp_hw_support/dma/include/esp_private/gdma.h index 2d61d531be8..cd58cd285ba 100644 --- a/components/esp_hw_support/dma/include/esp_private/gdma.h +++ b/components/esp_hw_support/dma/include/esp_private/gdma.h @@ -4,9 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -// DO NOT USE THESE APIS IN ANY APPLICATIONS -// GDMA driver is not public for end users, but for ESP-IDF developers. - #pragma once #include @@ -37,19 +34,6 @@ typedef struct { } flags; } gdma_channel_alloc_config_t; -/** - * @brief GDMA transfer ability - * - * @note The alignment set in this structure is **not** a guarantee that gdma driver will take care of the nonalignment cases. - * Actually the GDMA driver has no knowledge about the DMA buffer (address and size) used by upper layer. - * So it's the responsibility of the **upper layer** to take care of the buffer address and size. - * - */ -typedef struct { - size_t sram_trans_align; /*!< DMA transfer alignment for memory in SRAM, in bytes. The driver enables/disables burst mode based on this value. 0 means no alignment is required */ - size_t psram_trans_align; /*!< DMA transfer alignment for memory in PSRAM, in bytes. The driver sets proper burst block size based on the alignment value. 0 means no alignment is required */ -} gdma_transfer_ability_t; - /** * @brief Type of GDMA event data */ @@ -199,16 +183,48 @@ esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_perip esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan); /** - * @brief Set DMA channel transfer ability + * @brief Channel transfer configurations + */ +typedef struct { + uint32_t max_data_burst_size; /*!< Set the max burst size when DMA read/write the data buffer. + Set to 0 means to disable the data burst. + Other value must be power of 2, e.g., 4/8/16/32/64 */ + bool access_ext_mem; /*!< Set this if the DMA transfer will access external memory */ +} gdma_transfer_config_t; + +/** + * @brief Configure transfer parameters for a DMA channel + * + * @note It's highly recommended to enable the burst mode and set proper burst size for the DMA channel, + * which can improve the performance in accessing external memory by a lot. + * + * @param[in] chan DMA channel handle, allocated by `gdma_new_channel` + * @param[in] config Transfer configurations + * @return + * - ESP_OK: Configure DMA transfer parameters successfully + * - ESP_ERR_INVALID_ARG: Configure DMA transfer parameters failed because of invalid argument + * - ESP_FAIL: Configure DMA transfer parameters failed because of other error + */ +esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config); + +/** + * @brief Get the alignment constraints for internal and external memory + * + * @note You should call this function after `gdma_config_transfer`, the later one can + * adjust the alignment constraints based on various conditions, e.g. burst size, memory encryption, etc. + * @note You can use returned alignment value to validate if a DMA buffer provided by the upper layer meets the constraints. + * @note The returned alignment doesn't take the cache line size into account, if you want to do aligned memory allocation, + * you should align the buffer size to the cache line size by yourself if the DMA buffer is behind a cache. * * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` - * @param[in] ability Transfer ability, e.g. alignment + * @param[out] int_mem_alignment Internal memory alignment + * @param[out] ext_mem_alignment External memory alignment * @return - * - ESP_OK: Set DMA channel transfer ability successfully - * - ESP_ERR_INVALID_ARG: Set DMA channel transfer ability failed because of invalid argument - * - ESP_FAIL: Set DMA channel transfer ability failed because of other error + * - ESP_OK: Get alignment constraints successfully + * - ESP_ERR_INVALID_ARG: Get alignment constraints failed because of invalid argument + * - ESP_FAIL: Get alignment constraints failed because of other error */ -esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability); +esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment); /** * @brief Apply channel strategy for GDMA channel @@ -457,6 +473,36 @@ esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_ esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result); #endif // SOC_GDMA_SUPPORT_CRC +/**************************************************************************************** + * Deprecated APIs + ****************************************************************************************/ + +/** + * @brief GDMA transfer ability + * + * @note The alignment set in this structure is **not** a guarantee that gdma driver will take care of the nonalignment cases. + * Actually the GDMA driver has no knowledge about the DMA buffer (address and size) used by upper layer. + * So it's the responsibility of the **upper layer** to take care of the buffer address and size. + * + */ +typedef struct { + size_t sram_trans_align; /*!< DMA transfer alignment for memory in SRAM, in bytes. The driver enables/disables burst mode based on this value. 0 means no alignment is required */ + size_t psram_trans_align; /*!< DMA transfer alignment for memory in PSRAM, in bytes. The driver sets proper burst block size based on the alignment value. 0 means no alignment is required */ +} gdma_transfer_ability_t; + +/** + * @brief Set DMA channel transfer ability + * + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] ability Transfer ability, e.g. alignment + * @return + * - ESP_OK: Set DMA channel transfer ability successfully + * - ESP_ERR_INVALID_ARG: Set DMA channel transfer ability failed because of invalid argument + * - ESP_FAIL: Set DMA channel transfer ability failed because of other error + */ +esp_err_t gdma_set_transfer_ability(gdma_channel_handle_t dma_chan, const gdma_transfer_ability_t *ability) +__attribute__((deprecated("please use gdma_config_transfer instead"))); + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c2/include/hal/gdma_ll.h b/components/hal/esp32c2/include/hal/gdma_ll.h index 6bf41c6a50c..37d7179c689 100644 --- a/components/hal/esp32c2/include/hal/gdma_ll.h +++ b/components/hal/esp32c2/include/hal/gdma_ll.h @@ -48,6 +48,7 @@ extern "C" { #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number #define GDMA_LL_AHB_DESC_ALIGNMENT 4 +#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 ///////////////////////////////////// Common ///////////////////////////////////////// diff --git a/components/hal/esp32c3/include/hal/gdma_ll.h b/components/hal/esp32c3/include/hal/gdma_ll.h index a6cb889b7dd..e11d1fbc49e 100644 --- a/components/hal/esp32c3/include/hal/gdma_ll.h +++ b/components/hal/esp32c3/include/hal/gdma_ll.h @@ -48,6 +48,7 @@ extern "C" { #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number #define GDMA_LL_AHB_DESC_ALIGNMENT 4 +#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 ///////////////////////////////////// Common ///////////////////////////////////////// diff --git a/components/hal/esp32c6/include/hal/gdma_ll.h b/components/hal/esp32c6/include/hal/gdma_ll.h index 78dd95c5c3a..2a168bb6924 100644 --- a/components/hal/esp32c6/include/hal/gdma_ll.h +++ b/components/hal/esp32c6/include/hal/gdma_ll.h @@ -51,6 +51,7 @@ extern "C" { #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group #define GDMA_LL_AHB_DESC_ALIGNMENT 4 +#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ diff --git a/components/hal/esp32h2/include/hal/gdma_ll.h b/components/hal/esp32h2/include/hal/gdma_ll.h index 78dd95c5c3a..2a168bb6924 100644 --- a/components/hal/esp32h2/include/hal/gdma_ll.h +++ b/components/hal/esp32h2/include/hal/gdma_ll.h @@ -51,6 +51,7 @@ extern "C" { #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group #define GDMA_LL_AHB_DESC_ALIGNMENT 4 +#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ diff --git a/components/hal/esp32p4/include/hal/axi_dma_ll.h b/components/hal/esp32p4/include/hal/axi_dma_ll.h index ddc1f5c3fba..923dcc66ac4 100644 --- a/components/hal/esp32p4/include/hal/axi_dma_ll.h +++ b/components/hal/esp32p4/include/hal/axi_dma_ll.h @@ -125,7 +125,7 @@ static inline void axi_dma_ll_rx_enable_owner_check(axi_dma_dev_t *dev, uint32_t } /** - * @brief Enable DMA RX channel burst reading data, disabled by default + * @brief Enable DMA RX channel burst reading data, always enabled */ static inline void axi_dma_ll_rx_enable_data_burst(axi_dma_dev_t *dev, uint32_t channel, bool enable) { @@ -139,6 +139,16 @@ static inline void axi_dma_ll_rx_enable_descriptor_burst(axi_dma_dev_t *dev, uin dev->in[channel].conf.in_conf0.indscr_burst_en_chn = enable; } +/** + * @brief Set the RX channel burst size + */ +static inline void axi_dma_ll_rx_set_burst_size(axi_dma_dev_t *dev, uint32_t channel, uint32_t sz) +{ + HAL_ASSERT(sz >= 8 && sz <= 128); + int ctz = __builtin_ctz(sz); + dev->in[channel].conf.in_conf0.in_burst_size_sel_chn = ctz - 3; +} + /** * @brief Reset DMA RX channel FSM and FIFO pointer */ @@ -274,11 +284,11 @@ static inline void axi_dma_ll_rx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch } /** - * @brief Whether to enable the mean access ecc or aes domain + * @brief Whether to enable access to ecc or aes memory */ static inline void axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable) { - dev->in[channel].conf.in_conf0.in_ecc_aec_en_chn = enable; + dev->in[channel].conf.in_conf0.in_ecc_aes_en_chn = enable; } ///////////////////////////////////// TX ///////////////////////////////////////// @@ -333,7 +343,7 @@ static inline void axi_dma_ll_tx_enable_owner_check(axi_dma_dev_t *dev, uint32_t } /** - * @brief Enable DMA TX channel burst sending data, disabled by default + * @brief Enable DMA TX channel burst sending data, always enabled */ static inline void axi_dma_ll_tx_enable_data_burst(axi_dma_dev_t *dev, uint32_t channel, bool enable) { @@ -347,6 +357,16 @@ static inline void axi_dma_ll_tx_enable_descriptor_burst(axi_dma_dev_t *dev, uin dev->out[channel].conf.out_conf0.outdscr_burst_en_chn = enable; } +/** + * @brief Set the TX channel burst size + */ +static inline void axi_dma_ll_tx_set_burst_size(axi_dma_dev_t *dev, uint32_t channel, uint32_t sz) +{ + HAL_ASSERT(sz >= 8 && sz <= 128); + int ctz = __builtin_ctz(sz); + dev->out[channel].conf.out_conf0.out_burst_size_sel_chn = ctz - 3; +} + /** * @brief Set TX channel EOF mode */ @@ -480,11 +500,11 @@ static inline void axi_dma_ll_tx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch } /** - * @brief Whether to enable the mean access ecc or aes domain + * @brief Whether to enable access to ecc or aes memory */ static inline void axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(axi_dma_dev_t *dev, uint32_t channel, bool enable) { - dev->out[channel].conf.out_conf0.out_ecc_aec_en_chn = enable; + dev->out[channel].conf.out_conf0.out_ecc_aes_en_chn = enable; } ///////////////////////////////////// CRC-TX ///////////////////////////////////////// diff --git a/components/hal/esp32s3/include/hal/gdma_ll.h b/components/hal/esp32s3/include/hal/gdma_ll.h index 951145e85f8..33c5c934eb5 100644 --- a/components/hal/esp32s3/include/hal/gdma_ll.h +++ b/components/hal/esp32s3/include/hal/gdma_ll.h @@ -62,6 +62,9 @@ extern "C" { #define GDMA_LL_AHB_DESC_ALIGNMENT 4 +#define GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE 1 // AHB GDMA supports adjustable burst size +#define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 + ///////////////////////////////////// Common ///////////////////////////////////////// /** @@ -177,20 +180,20 @@ static inline void gdma_ll_rx_reset_channel(gdma_dev_t *dev, uint32_t channel) } /** - * @brief Set DMA RX channel memory block size based on the alignment requirement - * @param align Supported value: 16/32/64 + * @brief Set DMA RX channel memory block size based on the burst requirement + * @param burst_sz Supported value: 16/32/64 */ -static inline void gdma_ll_rx_set_ext_mem_block_size(gdma_dev_t *dev, uint32_t channel, uint8_t align) +static inline void gdma_ll_rx_set_burst_size(gdma_dev_t *dev, uint32_t channel, uint32_t burst_sz) { uint32_t block_size = 0; - switch (align) { - case 64: // 64 Bytes alignment + switch (burst_sz) { + case 64: block_size = GDMA_LL_EXT_MEM_BK_SIZE_64B; break; - case 32: // 32 Bytes alignment + case 32: block_size = GDMA_LL_EXT_MEM_BK_SIZE_32B; break; - case 16: // 16 Bytes alignment + case 16: block_size = GDMA_LL_EXT_MEM_BK_SIZE_16B; break; default: @@ -461,20 +464,20 @@ static inline void gdma_ll_tx_reset_channel(gdma_dev_t *dev, uint32_t channel) } /** - * @brief Set DMA TX channel memory block size based on the alignment requirement - * @param align Supported value: 16/32/64 + * @brief Set DMA TX channel memory block size based on the burst requirement + * @param burst_sz Supported value: 16/32/64 */ -static inline void gdma_ll_tx_set_ext_mem_block_size(gdma_dev_t *dev, uint32_t channel, uint8_t align) +static inline void gdma_ll_tx_set_burst_size(gdma_dev_t *dev, uint32_t channel, uint32_t burst_sz) { uint32_t block_size = 0; - switch (align) { - case 64: // 64 Bytes alignment + switch (burst_sz) { + case 64: block_size = GDMA_LL_EXT_MEM_BK_SIZE_64B; break; - case 32: // 32 Bytes alignment + case 32: block_size = GDMA_LL_EXT_MEM_BK_SIZE_32B; break; - case 16: // 16 Bytes alignment + case 16: block_size = GDMA_LL_EXT_MEM_BK_SIZE_16B; break; default: diff --git a/components/hal/gdma_hal_ahb_v1.c b/components/hal/gdma_hal_ahb_v1.c index 6964b987905..08130d25ce3 100644 --- a/components/hal/gdma_hal_ahb_v1.c +++ b/components/hal/gdma_hal_ahb_v1.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,16 +91,16 @@ void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe } } -#if SOC_AHB_GDMA_SUPPORT_PSRAM -void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align) +#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE +void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz) { if (dir == GDMA_CHANNEL_DIRECTION_RX) { - gdma_ll_rx_set_ext_mem_block_size(hal->dev, chan_id, align); + gdma_ll_rx_set_burst_size(hal->dev, chan_id, burst_sz); } else { - gdma_ll_tx_set_ext_mem_block_size(hal->dev, chan_id, align); + gdma_ll_tx_set_burst_size(hal->dev, chan_id, burst_sz); } } -#endif +#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back) { @@ -193,8 +193,8 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_ahb_hal_enable_etm_task; #endif -#if SOC_AHB_GDMA_SUPPORT_PSRAM - hal->set_ext_mem_align = gdma_ahb_hal_set_ext_mem_align; -#endif // SOC_AHB_GDMA_SUPPORT_PSRAM +#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE + hal->set_burst_size = gdma_ahb_hal_set_burst_size; +#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE hal->priv_data = &gdma_ahb_hal_priv_data; } diff --git a/components/hal/gdma_hal_ahb_v2.c b/components/hal/gdma_hal_ahb_v2.c index 71385465fea..b24b39b9d5c 100644 --- a/components/hal/gdma_hal_ahb_v2.c +++ b/components/hal/gdma_hal_ahb_v2.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,6 +102,17 @@ void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channe } } +#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE +void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + ahb_dma_ll_rx_set_burst_size(hal->ahb_dma_dev, chan_id, burst_sz); + } else { + ahb_dma_ll_tx_set_burst_size(hal->ahb_dma_dev, chan_id, burst_sz); + } +} +#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE + void gdma_ahb_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis) { if (dir == GDMA_CHANNEL_DIRECTION_RX) { @@ -244,5 +255,8 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) #if SOC_GDMA_SUPPORT_ETM hal->enable_etm_task = gdma_ahb_hal_enable_etm_task; #endif // SOC_GDMA_SUPPORT_ETM +#if GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE + hal->set_burst_size = gdma_ahb_hal_set_burst_size; +#endif // GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE ahb_dma_ll_set_default_memory_range(hal->ahb_dma_dev); } diff --git a/components/hal/gdma_hal_axi.c b/components/hal/gdma_hal_axi.c index da31498cad3..9596808900b 100644 --- a/components/hal/gdma_hal_axi.c +++ b/components/hal/gdma_hal_axi.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,6 +102,15 @@ void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channe } } +void gdma_axi_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + axi_dma_ll_rx_set_burst_size(hal->axi_dma_dev, chan_id, burst_sz); + } else { + axi_dma_ll_tx_set_burst_size(hal->axi_dma_dev, chan_id, burst_sz); + } +} + void gdma_axi_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis) { if (dir == GDMA_CHANNEL_DIRECTION_RX) { @@ -151,6 +160,15 @@ uint32_t gdma_axi_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gd } } +void gdma_axi_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(hal->axi_dma_dev, chan_id, en_or_dis); + } else { + axi_dma_ll_tx_enable_ext_mem_ecc_aes_access(hal->axi_dma_dev, chan_id, en_or_dis); + } +} + #if SOC_GDMA_SUPPORT_CRC void gdma_axi_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) { @@ -236,6 +254,8 @@ void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) hal->read_intr_status = gdma_axi_hal_read_intr_status; hal->get_intr_status_reg = gdma_axi_hal_get_intr_status_reg; hal->get_eof_desc_addr = gdma_axi_hal_get_eof_desc_addr; + hal->set_burst_size = gdma_axi_hal_set_burst_size; + hal->enable_access_encrypt_mem = gdma_axi_hal_enable_access_encrypt_mem; #if SOC_GDMA_SUPPORT_CRC hal->clear_crc = gdma_axi_hal_clear_crc; hal->set_crc_poly = gdma_axi_hal_set_crc_poly; diff --git a/components/hal/gdma_hal_top.c b/components/hal/gdma_hal_top.c index e3c882b2a23..eb0c8fb0dcc 100644 --- a/components/hal/gdma_hal_top.c +++ b/components/hal/gdma_hal_top.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,10 +53,10 @@ void gdma_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_di hal->enable_burst(hal, chan_id, dir, en_data_burst, en_desc_burst); } -void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align) +void gdma_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz) { - if (hal->set_ext_mem_align) { - hal->set_ext_mem_align(hal, chan_id, dir, align); + if (hal->set_burst_size) { + hal->set_burst_size(hal, chan_id, dir, burst_sz); } } @@ -90,6 +90,13 @@ uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_c return hal->get_eof_desc_addr(hal, chan_id, dir, is_success); } +void gdma_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis) +{ + if (hal->enable_access_encrypt_mem) { + hal->enable_access_encrypt_mem(hal, chan_id, dir, en_or_dis); + } +} + #if SOC_GDMA_SUPPORT_CRC void gdma_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) { diff --git a/components/hal/include/hal/gdma_hal.h b/components/hal/include/hal/gdma_hal.h index 1eca5ebf3c6..228d9af83e9 100644 --- a/components/hal/include/hal/gdma_hal.h +++ b/components/hal/include/hal/gdma_hal.h @@ -80,13 +80,14 @@ struct gdma_hal_context_t { void (*connect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, gdma_trigger_peripheral_t periph, int periph_sub_id); /// Connect the channel to a peripheral void (*disconnect_peri)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Disconnect the channel from a peripheral void (*enable_burst)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); /// Enable burst mode - void (*set_ext_mem_align)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); /// Set the alignment of the external memory void (*set_strategy)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); /// Set some misc strategy of the channel behaviour + void (*set_burst_size)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); /// Set burst transfer size uint32_t (*get_intr_status_reg)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); // Get the interrupt status register address void (*enable_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); /// Enable the channel interrupt void (*clear_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask); /// Clear the channel interrupt uint32_t (*read_intr_status)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool raw); /// Read the channel interrupt status uint32_t (*get_eof_desc_addr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success); /// Get the address of the descriptor with success/error EOF flag set + void (*enable_access_encrypt_mem)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis); /// Enable the access to the encrypted memory #if SOC_GDMA_SUPPORT_CRC void (*clear_crc)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Clear the CRC interim results void (*set_crc_poly)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config); /// Set the CRC polynomial @@ -115,7 +116,7 @@ void gdma_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_channel void gdma_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); -void gdma_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); +void gdma_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); void gdma_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); @@ -129,6 +130,8 @@ uint32_t gdma_hal_read_intr_status(gdma_hal_context_t *hal, int chan_id, gdma_ch uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success); +void gdma_hal_enable_access_encrypt_mem(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_or_dis); + #if SOC_GDMA_SUPPORT_CRC void gdma_hal_build_parallel_crc_matrix(int crc_width, uint32_t crc_poly_hex, int data_width, uint32_t *lfsr_transform_matrix, uint32_t *data_transform_matrix); diff --git a/components/hal/include/hal/gdma_hal_ahb.h b/components/hal/include/hal/gdma_hal_ahb.h index e2de69b9e99..03782e251ee 100644 --- a/components/hal/include/hal/gdma_hal_ahb.h +++ b/components/hal/include/hal/gdma_hal_ahb.h @@ -28,7 +28,7 @@ void gdma_ahb_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_cha void gdma_ahb_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); -void gdma_ahb_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); +void gdma_ahb_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); void gdma_ahb_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); diff --git a/components/hal/include/hal/gdma_hal_axi.h b/components/hal/include/hal/gdma_hal_axi.h index e9cb68b708c..c9f5a8f3181 100644 --- a/components/hal/include/hal/gdma_hal_axi.h +++ b/components/hal/include/hal/gdma_hal_axi.h @@ -28,6 +28,8 @@ void gdma_axi_hal_disconnect_peri(gdma_hal_context_t *hal, int chan_id, gdma_cha void gdma_axi_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_data_burst, bool en_desc_burst); +void gdma_axi_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); + void gdma_axi_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); diff --git a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c index 9f202249e99..e906b9ac6fc 100644 --- a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c +++ b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c @@ -73,12 +73,6 @@ static esp_err_t crypto_shared_gdma_init(void) .direction = GDMA_CHANNEL_DIRECTION_RX, }; - gdma_transfer_ability_t transfer_ability = { - .sram_trans_align = 1, - .psram_trans_align = 16, - }; - - ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel); if (ret != ESP_OK) { goto err; @@ -90,9 +84,13 @@ static esp_err_t crypto_shared_gdma_init(void) goto err; } - - gdma_set_transfer_ability(tx_channel, &transfer_ability); - gdma_set_transfer_ability(rx_channel, &transfer_ability); + gdma_transfer_config_t transfer_cfg = { + .max_data_burst_size = 16, + .access_ext_mem = true, // crypto peripheral may want to access PSRAM + }; + gdma_config_transfer(tx_channel, &transfer_cfg); + transfer_cfg.max_data_burst_size = 0; + gdma_config_transfer(rx_channel, &transfer_cfg); gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); @@ -223,7 +221,7 @@ bool esp_crypto_shared_gdma_done(void) { int rx_ch_id = 0; gdma_get_channel_id(rx_channel, &rx_ch_id); - while(1) { + while (1) { if ((axi_dma_ll_rx_get_interrupt_status(&AXI_DMA, rx_ch_id, true) & 1)) { break; } diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 65f5cbd260c..5da4d4ac4b8 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -455,7 +455,7 @@ config SOC_DS_KEY_CHECK_MAX_WAIT_US int default 1100 -config SOC_DMA_CAN_ACCESS_MSPI_MEM +config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32p4/include/soc/axi_dma_struct.h b/components/soc/esp32p4/include/soc/axi_dma_struct.h index dcd83b04c84..61b3de7fc8b 100644 --- a/components/soc/esp32p4/include/soc/axi_dma_struct.h +++ b/components/soc/esp32p4/include/soc/axi_dma_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -273,10 +273,10 @@ typedef union { * 1:mean disable cmd of this ch0 */ uint32_t in_cmd_disable_chn: 1; - /** in_ecc_aec_en_chn : R/W; bitpos: [8]; default: 0; + /** in_ecc_aes_en_chn : R/W; bitpos: [8]; default: 0; * 1: mean access ecc or aes domain,0: mean not */ - uint32_t in_ecc_aec_en_chn: 1; + uint32_t in_ecc_aes_en_chn: 1; /** indscr_burst_en_chn : R/W; bitpos: [9]; default: 0; * Set this bit to 1 to enable INCR burst transfer for Rx channel 0 reading link * descriptor when accessing internal SRAM. @@ -567,7 +567,7 @@ typedef union { */ uint32_t rx_ch_arb_weigh_chn: 4; /** rx_arb_weigh_opt_dir_chn : R/W; bitpos: [8]; default: 0; - * 0: mean not optimazation weight function ,1: mean optimazation + * 0: mean not optimization weight function ,1: mean optimization */ uint32_t rx_arb_weigh_opt_dir_chn: 1; uint32_t reserved_9: 23; @@ -952,10 +952,10 @@ typedef union { * 1:mean disable cmd of this chn */ uint32_t out_cmd_disable_chn: 1; - /** out_ecc_aec_en_chn : R/W; bitpos: [9]; default: 0; + /** out_ecc_aes_en_chn : R/W; bitpos: [9]; default: 0; * 1: mean access ecc or aes domain,0: mean not */ - uint32_t out_ecc_aec_en_chn: 1; + uint32_t out_ecc_aes_en_chn: 1; /** outdscr_burst_en_chn : R/W; bitpos: [10]; default: 0; * Set this bit to 1 to enable INCR burst transfer for Tx channel0 reading link * descriptor when accessing internal SRAM. @@ -1238,7 +1238,7 @@ typedef union { */ uint32_t tx_ch_arb_weigh_chn: 4; /** tx_arb_weigh_opt_dir_chn : R/W; bitpos: [8]; default: 0; - * 0: mean not optimazation weight function ,1: mean optimazation + * 0: mean not optimization weight function ,1: mean optimization */ uint32_t tx_arb_weigh_opt_dir_chn: 1; uint32_t reserved_9: 23; @@ -1374,106 +1374,6 @@ typedef union { uint32_t val; } axi_dma_tx_crc_data_en_addr_chn_reg_t; -/** Type of out_conf0_ch1 register - * Configure 0 register of Tx channel1 - */ -typedef union { - struct { - /** out_rst_ch1 : R/W; bitpos: [0]; default: 0; - * This bit is used to reset AXI_DMA channel1 Tx FSM and Tx FIFO pointer. - */ - uint32_t out_rst_ch1: 1; - /** out_loop_test_ch1 : R/W; bitpos: [1]; default: 0; - * reserved - */ - uint32_t out_loop_test_ch1: 1; - /** out_auto_wrback_ch1 : R/W; bitpos: [2]; default: 0; - * Set this bit to enable automatic outlink-writeback when all the data in tx buffer - * has been transmitted. - */ - uint32_t out_auto_wrback_ch1: 1; - /** out_eof_mode_ch1 : R/W; bitpos: [3]; default: 1; - * EOF flag generation mode when transmitting data. 1: EOF flag for Tx channel1 is - * generated when data need to transmit has been popped from FIFO in AXI_DMA - */ - uint32_t out_eof_mode_ch1: 1; - /** out_etm_en_ch1 : R/W; bitpos: [4]; default: 0; - * Set this bit to 1 to enable etm control mode, dma Tx channel1 is triggered by etm - * task. - */ - uint32_t out_etm_en_ch1: 1; - /** out_burst_size_sel_ch1 : R/W; bitpos: [7:5]; default: 0; - * 3'b000-3'b100:burst length 8byte~128byte - */ - uint32_t out_burst_size_sel_ch1: 3; - /** out_cmd_disable_ch1 : R/W; bitpos: [8]; default: 0; - * 1:mean disable cmd of this ch1 - */ - uint32_t out_cmd_disable_ch1: 1; - /** out_ecc_aec_en_ch1 : R/W; bitpos: [9]; default: 0; - * 1: mean access ecc or aes domain,0: mean not - */ - uint32_t out_ecc_aec_en_ch1: 1; - /** outdscr_burst_en_ch1 : R/W; bitpos: [10]; default: 0; - * Set this bit to 1 to enable INCR burst transfer for Tx channel1 reading link - * descriptor when accessing internal SRAM. - */ - uint32_t outdscr_burst_en_ch1: 1; - uint32_t reserved_11: 21; - }; - uint32_t val; -} axi_dma_out_conf0_ch1_reg_t; - -/** Type of out_conf0_ch2 register - * Configure 0 register of Tx channel2 - */ -typedef union { - struct { - /** out_rst_ch2 : R/W; bitpos: [0]; default: 0; - * This bit is used to reset AXI_DMA channel2 Tx FSM and Tx FIFO pointer. - */ - uint32_t out_rst_ch2: 1; - /** out_loop_test_ch2 : R/W; bitpos: [1]; default: 0; - * reserved - */ - uint32_t out_loop_test_ch2: 1; - /** out_auto_wrback_ch2 : R/W; bitpos: [2]; default: 0; - * Set this bit to enable automatic outlink-writeback when all the data in tx buffer - * has been transmitted. - */ - uint32_t out_auto_wrback_ch2: 1; - /** out_eof_mode_ch2 : R/W; bitpos: [3]; default: 1; - * EOF flag generation mode when transmitting data. 1: EOF flag for Tx channel2 is - * generated when data need to transmit has been popped from FIFO in AXI_DMA - */ - uint32_t out_eof_mode_ch2: 1; - /** out_etm_en_ch2 : R/W; bitpos: [4]; default: 0; - * Set this bit to 1 to enable etm control mode, dma Tx channel2 is triggered by etm - * task. - */ - uint32_t out_etm_en_ch2: 1; - /** out_burst_size_sel_ch2 : R/W; bitpos: [7:5]; default: 0; - * 3'b000-3'b100:burst length 8byte~128byte - */ - uint32_t out_burst_size_sel_ch2: 3; - /** out_cmd_disable_ch2 : R/W; bitpos: [8]; default: 0; - * 1:mean disable cmd of this ch2 - */ - uint32_t out_cmd_disable_ch2: 1; - /** out_ecc_aec_en_ch2 : R/W; bitpos: [9]; default: 0; - * 1: mean access ecc or aes domain,0: mean not - */ - uint32_t out_ecc_aec_en_ch2: 1; - /** outdscr_burst_en_ch2 : R/W; bitpos: [10]; default: 0; - * Set this bit to 1 to enable INCR burst transfer for Tx channel2 reading link - * descriptor when accessing internal SRAM. - */ - uint32_t outdscr_burst_en_ch2: 1; - uint32_t reserved_11: 21; - }; - uint32_t val; -} axi_dma_out_conf0_ch2_reg_t; - /** Group: Configuration Registers */ /** Type of arb_timeout register * This retister is used to config arbiter time slice @@ -1705,12 +1605,12 @@ typedef union { /** Group: Status Registers */ /** Type of wresp_cnt register - * AXI wr responce cnt register. + * AXI wr response cnt register. */ typedef union { struct { /** wresp_cnt : RO; bitpos: [3:0]; default: 0; - * axi wr responce cnt reg. + * axi wr response cnt reg. */ uint32_t wresp_cnt: 4; uint32_t reserved_4: 28; @@ -1719,12 +1619,12 @@ typedef union { } axi_dma_wresp_cnt_reg_t; /** Type of rresp_cnt register - * AXI wr responce cnt register. + * AXI wr response cnt register. */ typedef union { struct { /** rresp_cnt : RO; bitpos: [3:0]; default: 0; - * axi rd responce cnt reg. + * axi rd response cnt reg. */ uint32_t rresp_cnt: 4; uint32_t reserved_4: 28; diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index ebb35f95f0a..c3fd84a497e 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -182,7 +182,7 @@ #define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100) /*-------------------------- DMA Common CAPS ----------------------------------------*/ -#define SOC_DMA_CAN_ACCESS_MSPI_MEM 1 /*!< DMA can access MSPI memory (e.g. Flash, PSRAM) */ +#define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ /*-------------------------- GDMA CAPS -------------------------------------*/ #define SOC_AHB_GDMA_VERSION 2 diff --git a/components/wpa_supplicant/test_apps/main/test_crypto.c b/components/wpa_supplicant/test_apps/main/test_crypto.c index 42fefce8038..23f14b8da52 100644 --- a/components/wpa_supplicant/test_apps/main/test_crypto.c +++ b/components/wpa_supplicant/test_apps/main/test_crypto.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,7 +37,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") bn = crypto_bignum_init_set(buf, 32); TEST_ASSERT_NOT_NULL(bn); - TEST_ASSERT(crypto_bignum_to_bin(bn, buf2, 32, 0) == 32); TEST_ASSERT(!memcmp(buf, buf2, 32)); @@ -245,7 +244,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") uint8_t buf1[32], buf2[32]; crypto_bignum *bn1, *bn2; - buf1[0] = 0xf; buf2[0] = 0x11; @@ -277,7 +275,6 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") } } - /* * Conversion macros for embedded constants: * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 @@ -322,30 +319,29 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]") * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) * Allocate a new memory as well so that it can be freed. */ -static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +static inline void ecp_mpi_load(mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len) { X->MBEDTLS_PRIVATE(s) = 1; - X->MBEDTLS_PRIVATE(n) = len / sizeof( mbedtls_mpi_uint ); + X->MBEDTLS_PRIVATE(n) = len / sizeof(mbedtls_mpi_uint); X->MBEDTLS_PRIVATE(p) = os_zalloc(len); memcpy(X->MBEDTLS_PRIVATE(p), (void *)p, len); } - TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") { - set_leak_threshold(600); + set_leak_threshold(620); static const mbedtls_mpi_uint secp256r1_gx[] = { - BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), - BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), - BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), - BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), + BYTES_TO_T_UINT_8(0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4), + BYTES_TO_T_UINT_8(0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77), + BYTES_TO_T_UINT_8(0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8), + BYTES_TO_T_UINT_8(0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B), }; static const mbedtls_mpi_uint secp256r1_gy[] = { - BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), - BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), - BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), - BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), + BYTES_TO_T_UINT_8(0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB), + BYTES_TO_T_UINT_8(0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B), + BYTES_TO_T_UINT_8(0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E), + BYTES_TO_T_UINT_8(0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F), }; { @@ -393,8 +389,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT_NOT_NULL(q); TEST_ASSERT_NOT_NULL(r); - mbedtls_mpi_init( &num ); - mbedtls_mpi_lset( &num, 3 ); + mbedtls_mpi_init(&num); + mbedtls_mpi_lset(&num, 3); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx)); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy)); @@ -408,7 +404,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT(crypto_ec_point_cmp(e, q, r) == 0); - mbedtls_mpi_free( &num ); + mbedtls_mpi_free(&num); crypto_ec_point_deinit(p, 1); crypto_ec_point_deinit(q, 1); crypto_ec_point_deinit(r, 1); @@ -432,8 +428,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT_NOT_NULL(q); TEST_ASSERT_NOT_NULL(r); - mbedtls_mpi_init( &num ); - mbedtls_mpi_lset( &num, 100 ); + mbedtls_mpi_init(&num); + mbedtls_mpi_lset(&num, 100); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx)); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy)); @@ -448,7 +444,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r)); - mbedtls_mpi_free( &num ); + mbedtls_mpi_free(&num); crypto_ec_point_deinit(p, 1); crypto_ec_point_deinit(q, 1); crypto_ec_point_deinit(r, 1); @@ -468,8 +464,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT_NOT_NULL(p); TEST_ASSERT_NOT_NULL(q); - mbedtls_mpi_init( &num ); - mbedtls_mpi_lset( &num, 50 ); + mbedtls_mpi_init(&num); + mbedtls_mpi_lset(&num, 50); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx)); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy)); @@ -483,8 +479,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT(crypto_ec_point_mul(e, p, (crypto_bignum *) &num, q) == 0); TEST_ASSERT(crypto_ec_point_is_on_curve(e, q)); - - mbedtls_mpi_free( &num ); + mbedtls_mpi_free(&num); crypto_ec_point_deinit(p, 1); crypto_ec_point_deinit(q, 1); crypto_ec_deinit(e); @@ -506,8 +501,8 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT_NOT_NULL(q); TEST_ASSERT_NOT_NULL(r); - mbedtls_mpi_init( &num ); - mbedtls_mpi_lset( &num, 50 ); + mbedtls_mpi_init(&num); + mbedtls_mpi_lset(&num, 50); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X), secp256r1_gx, sizeof(secp256r1_gx)); ecp_mpi_load(& ((mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), secp256r1_gy, sizeof(secp256r1_gy)); @@ -532,7 +527,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]") TEST_ASSERT(crypto_ec_point_add(e, q, r, r) == 0); TEST_ASSERT(crypto_ec_point_is_at_infinity(e, r)); - mbedtls_mpi_free( &num ); + mbedtls_mpi_free(&num); crypto_ec_point_deinit(p, 1); crypto_ec_point_deinit(q, 1); crypto_ec_point_deinit(r, 1); diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index b20dc9bb82f..e8181236c6c 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,12 +77,12 @@ Non-IRAM-Safe Interrupt Handlers If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not get executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, users will not see the corresponding hardware event happening. -.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM +.. only:: SOC_DMA_CAN_ACCESS_FLASH When DMA Read Data from Flash ----------------------------- - When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM. + When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA if auto-suspend is not enabled. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM. .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index 7e45a61373e..75662fa9910 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -77,12 +77,12 @@ IRAM 安全中断处理程序 如果在注册时没有设置 ``ESP_INTR_FLAG_IRAM`` 标志,当禁用 cache 时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要禁用了 cache,就不会发生相应的硬件事件。 -.. only:: SOC_DMA_CAN_ACCESS_MSPI_MEM +.. only:: SOC_DMA_CAN_ACCESS_FLASH 当 DMA 也可以访问 Flash 中的数据时 ---------------------------------- - 当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。 + 当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,如果 Flash 的 auto-suspend 功能没有开启,将会导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。 .. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND From e8852d5c381c786250e19478095edd94ae1b4fdb Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 14 May 2024 10:55:55 +0800 Subject: [PATCH 193/548] change(async_memcpy): set DMA transfer burst size --- .../esp_hw_support/dma/async_memcpy_cp_dma.c | 18 ++---- .../esp_hw_support/dma/async_memcpy_gdma.c | 56 ++++++++----------- .../esp_hw_support/include/esp_async_memcpy.h | 12 ++-- .../test_apps/dma/main/test_async_memcpy.c | 5 +- docs/en/api-reference/system/async_memcpy.rst | 3 +- .../api-reference/system/async_memcpy.rst | 3 +- 6 files changed, 40 insertions(+), 57 deletions(-) diff --git a/components/esp_hw_support/dma/async_memcpy_cp_dma.c b/components/esp_hw_support/dma/async_memcpy_cp_dma.c index 975bb92c369..e86bf10a18e 100644 --- a/components/esp_hw_support/dma/async_memcpy_cp_dma.c +++ b/components/esp_hw_support/dma/async_memcpy_cp_dma.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -48,7 +48,6 @@ typedef struct async_memcpy_transaction_t { /// @note - Number of transaction objects are determined by the backlog parameter typedef struct { async_memcpy_context_t parent; // Parent IO interface - size_t sram_trans_align; // DMA transfer alignment (both in size and address) for SRAM memory size_t max_single_dma_buffer; // max DMA buffer size by a single descriptor cp_dma_hal_context_t hal; // CPDMA hal intr_handle_t intr; // CPDMA interrupt handle @@ -90,7 +89,7 @@ esp_err_t esp_async_memcpy_install_cpdma(const async_memcpy_config_t *config, as uint32_t trans_queue_len = config->backlog ? config->backlog : DEFAULT_TRANSACTION_QUEUE_LENGTH; // allocate memory for transaction pool, aligned to 4 because the trans->eof_node requires that alignment mcp_dma->transaction_pool = heap_caps_aligned_calloc(4, trans_queue_len, sizeof(async_memcpy_transaction_t), - MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(mcp_dma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool"); // Init hal context @@ -111,8 +110,7 @@ esp_err_t esp_async_memcpy_install_cpdma(const async_memcpy_config_t *config, as // initialize other members portMUX_INITIALIZE(&mcp_dma->spin_lock); atomic_init(&mcp_dma->fsm, MCP_FSM_IDLE); - mcp_dma->sram_trans_align = config->sram_trans_align; - size_t trans_align = config->sram_trans_align; + size_t trans_align = config->dma_burst_size; mcp_dma->max_single_dma_buffer = trans_align ? ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, trans_align) : DMA_DESCRIPTOR_BUFFER_MAX_SIZE; mcp_dma->parent.del = mcp_cpdma_del; mcp_dma->parent.memcpy = mcp_cpdma_memcpy; @@ -240,12 +238,6 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void * esp_err_t ret = ESP_OK; async_memcpy_cpdma_context_t *mcp_dma = __containerof(ctx, async_memcpy_cpdma_context_t, parent); ESP_RETURN_ON_FALSE(esp_ptr_internal(src) && esp_ptr_internal(dst), ESP_ERR_INVALID_ARG, TAG, "CP_DMA can only access SRAM"); - // alignment check - if (mcp_dma->sram_trans_align) { - ESP_RETURN_ON_FALSE((((intptr_t)dst & (mcp_dma->sram_trans_align - 1)) == 0), ESP_ERR_INVALID_ARG, TAG, "buffer address not aligned: %p -> %p", src, dst); - ESP_RETURN_ON_FALSE(((n & (mcp_dma->sram_trans_align - 1)) == 0), ESP_ERR_INVALID_ARG, TAG, - "copy size should align to %d bytes", mcp_dma->sram_trans_align); - } async_memcpy_transaction_t *trans = NULL; // pick one transaction node from idle queue trans = try_pop_trans_from_idle_queue(mcp_dma); @@ -257,12 +249,12 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void * uint32_t num_desc_per_path = (n + max_single_dma_buffer - 1) / max_single_dma_buffer; // allocate DMA descriptors, descriptors need a strict alignment trans->tx_desc_link = heap_caps_aligned_calloc(4, num_desc_per_path, sizeof(dma_descriptor_align4_t), - MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(trans->tx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors"); // don't have to allocate the EOF descriptor, we will use trans->eof_node as the RX EOF descriptor if (num_desc_per_path > 1) { trans->rx_desc_link = heap_caps_aligned_calloc(4, num_desc_per_path - 1, sizeof(dma_descriptor_align4_t), - MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(trans->rx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors"); } else { // small copy buffer, use the trans->eof_node is sufficient diff --git a/components/esp_hw_support/dma/async_memcpy_gdma.c b/components/esp_hw_support/dma/async_memcpy_gdma.c index 8b8fa19930f..7282f946fae 100644 --- a/components/esp_hw_support/dma/async_memcpy_gdma.c +++ b/components/esp_hw_support/dma/async_memcpy_gdma.c @@ -69,8 +69,10 @@ typedef struct async_memcpy_transaction_t { typedef struct { async_memcpy_context_t parent; // Parent IO interface size_t descriptor_align; // DMA descriptor alignment - size_t sram_trans_align; // DMA buffer alignment (both in size and address) for SRAM memory - size_t psram_trans_align; // DMA buffer alignment (both in size and address) for PSRAM memory + size_t rx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal RX memory + size_t rx_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external RX memory + size_t tx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal TX memory + size_t tx_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external TX memory size_t max_single_dma_buffer; // max DMA buffer size by a single descriptor int gdma_bus_id; // GDMA bus id (AHB, AXI, etc.) gdma_channel_handle_t tx_channel; // GDMA TX channel handle @@ -146,12 +148,12 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi ESP_GOTO_ON_ERROR(gdma_connect(mcp_gdma->rx_channel, m2m_trigger), err, TAG, "GDMA rx connect failed"); ESP_GOTO_ON_ERROR(gdma_connect(mcp_gdma->tx_channel, m2m_trigger), err, TAG, "GDMA tx connect failed"); - gdma_transfer_ability_t transfer_ability = { - .sram_trans_align = config->sram_trans_align, - .psram_trans_align = config->psram_trans_align, + gdma_transfer_config_t transfer_cfg = { + .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : 16, + .access_ext_mem = true, // allow to do memory copy from/to external memory }; - ESP_GOTO_ON_ERROR(gdma_set_transfer_ability(mcp_gdma->tx_channel, &transfer_ability), err, TAG, "set tx trans ability failed"); - ESP_GOTO_ON_ERROR(gdma_set_transfer_ability(mcp_gdma->rx_channel, &transfer_ability), err, TAG, "set rx trans ability failed"); + ESP_GOTO_ON_ERROR(gdma_config_transfer(mcp_gdma->tx_channel, &transfer_cfg), err, TAG, "config transfer for tx channel failed"); + ESP_GOTO_ON_ERROR(gdma_config_transfer(mcp_gdma->rx_channel, &transfer_cfg), err, TAG, "config transfer for rx channel failed"); // register rx eof callback gdma_rx_event_callbacks_t cbs = { @@ -172,15 +174,13 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi atomic_init(&mcp_gdma->fsm, MCP_FSM_IDLE); mcp_gdma->gdma_bus_id = gdma_bus_id; - uint32_t psram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); - uint32_t sram_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - // if the psram_trans_align is configured to zero, we should fall back to use the data cache line size - size_t psram_trans_align = MAX(psram_cache_line_size, config->psram_trans_align); - size_t sram_trans_align = MAX(sram_cache_line_size, config->sram_trans_align); - size_t trans_align = MAX(sram_trans_align, psram_trans_align); - mcp_gdma->max_single_dma_buffer = ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, trans_align); - mcp_gdma->psram_trans_align = psram_trans_align; - mcp_gdma->sram_trans_align = sram_trans_align; + // get the buffer alignment required by the GDMA channel + gdma_get_alignment_constraints(mcp_gdma->rx_channel, &mcp_gdma->rx_int_mem_alignment, &mcp_gdma->rx_ext_mem_alignment); + gdma_get_alignment_constraints(mcp_gdma->tx_channel, &mcp_gdma->tx_int_mem_alignment, &mcp_gdma->tx_ext_mem_alignment); + + size_t buf_align = MAX(MAX(mcp_gdma->rx_int_mem_alignment, mcp_gdma->rx_ext_mem_alignment), + MAX(mcp_gdma->tx_int_mem_alignment, mcp_gdma->tx_ext_mem_alignment)); + mcp_gdma->max_single_dma_buffer = ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align); mcp_gdma->parent.del = mcp_gdma_del; mcp_gdma->parent.memcpy = mcp_gdma_memcpy; #if SOC_GDMA_SUPPORT_ETM @@ -335,29 +335,21 @@ static async_memcpy_transaction_t *try_pop_trans_from_idle_queue(async_memcpy_gd static bool check_buffer_alignment(async_memcpy_gdma_context_t *mcp_gdma, void *src, void *dst, size_t n) { bool valid = true; - uint32_t psram_align_mask = 0; - uint32_t sram_align_mask = 0; - if (mcp_gdma->psram_trans_align) { - psram_align_mask = mcp_gdma->psram_trans_align - 1; - } - if (mcp_gdma->sram_trans_align) { - sram_align_mask = mcp_gdma->sram_trans_align - 1; - } if (esp_ptr_external_ram(dst)) { - valid = valid && (((uint32_t)dst & psram_align_mask) == 0); - valid = valid && ((n & psram_align_mask) == 0); + valid = valid && (((uint32_t)dst & (mcp_gdma->rx_ext_mem_alignment - 1)) == 0); + valid = valid && ((n & (mcp_gdma->rx_ext_mem_alignment - 1)) == 0); } else { - valid = valid && (((uint32_t)dst & sram_align_mask) == 0); - valid = valid && ((n & sram_align_mask) == 0); + valid = valid && (((uint32_t)dst & (mcp_gdma->rx_int_mem_alignment - 1)) == 0); + valid = valid && ((n & (mcp_gdma->rx_int_mem_alignment - 1)) == 0); } if (esp_ptr_external_ram(src)) { - valid = valid && (((uint32_t)src & psram_align_mask) == 0); - valid = valid && ((n & psram_align_mask) == 0); + valid = valid && (((uint32_t)src & (mcp_gdma->tx_ext_mem_alignment - 1)) == 0); + valid = valid && ((n & (mcp_gdma->tx_ext_mem_alignment - 1)) == 0); } else { - valid = valid && (((uint32_t)src & sram_align_mask) == 0); - valid = valid && ((n & sram_align_mask) == 0); + valid = valid && (((uint32_t)src & (mcp_gdma->tx_int_mem_alignment - 1)) == 0); + valid = valid && ((n & (mcp_gdma->tx_int_mem_alignment - 1)) == 0); } return valid; diff --git a/components/esp_hw_support/include/esp_async_memcpy.h b/components/esp_hw_support/include/esp_async_memcpy.h index 033bb9ed917..1b91b840930 100644 --- a/components/esp_hw_support/include/esp_async_memcpy.h +++ b/components/esp_hw_support/include/esp_async_memcpy.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -51,8 +51,11 @@ typedef bool (*async_memcpy_isr_cb_t)(async_memcpy_handle_t mcp_hdl, async_memcp */ typedef struct { uint32_t backlog; /*!< Maximum number of transactions that can be prepared in the background */ - size_t sram_trans_align; /*!< DMA transfer alignment (both in size and address) for SRAM memory */ - size_t psram_trans_align; /*!< DMA transfer alignment (both in size and address) for PSRAM memory */ + size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment (both in size and address) for SRAM memory */ + union { + size_t psram_trans_align; /*!< DMA transfer alignment (both in size and address) for PSRAM memory */ + size_t dma_burst_size; /*!< DMA transfer burst size, in bytes */ + }; uint32_t flags; /*!< Extra flags to control async memcpy feature */ } async_memcpy_config_t; @@ -62,8 +65,7 @@ typedef struct { #define ASYNC_MEMCPY_DEFAULT_CONFIG() \ { \ .backlog = 8, \ - .sram_trans_align = 0, \ - .psram_trans_align = 0, \ + .dma_burst_size = 16, \ .flags = 0, \ } diff --git a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c index 81939889d0c..79423a32053 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c +++ b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c @@ -302,8 +302,7 @@ static void memcpy_performance_test(uint32_t buffer_size) async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG(); config.backlog = (buffer_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1) * TEST_ASYNC_MEMCPY_BENCH_COUNTS; - config.sram_trans_align = 4; // at least 4 bytes aligned for SRAM transfer - config.psram_trans_align = 64; // at least 64 bytes aligned for PSRAM transfer + config.dma_burst_size = 64; // set a big burst size for performance async_memcpy_handle_t driver = NULL; int64_t elapse_us = 0; float throughput = 0.0; @@ -311,7 +310,7 @@ static void memcpy_performance_test(uint32_t buffer_size) // 1. SRAM->SRAM memcpy_testbench_context_t test_context = { - .align = config.psram_trans_align, + .align = config.dma_burst_size, .buffer_size = buffer_size, .src_in_psram = false, .dst_in_psram = false, diff --git a/docs/en/api-reference/system/async_memcpy.rst b/docs/en/api-reference/system/async_memcpy.rst index d2ff7f2030b..000e86d4a2c 100644 --- a/docs/en/api-reference/system/async_memcpy.rst +++ b/docs/en/api-reference/system/async_memcpy.rst @@ -36,8 +36,7 @@ There are several ways to install the async memcpy driver, depending on the unde Driver configuration is described in :cpp:type:`async_memcpy_config_t`: * :cpp:member:`backlog`: This is used to configure the maximum number of memory copy transactions that can be queued up before the first one is completed. If this field is set to zero, then the default value 4 will be applied. -* :cpp:member:`sram_trans_align`: Declare SRAM alignment for both data address and copy size, set to zero if the data has no restriction in alignment. If set to a quadruple value (i.e., 4X), the driver will enable the burst mode internally, which is helpful for some performance related application. -* :cpp:member:`psram_trans_align`: Declare PSRAM alignment for both data address and copy size. User has to give it a valid value (only 16, 32, 64 are supported) if the destination of memcpy is located in PSRAM. The default alignment (i.e., 16) will be applied if it is set to zero. Internally, the driver configures the size of block used by DMA to access PSRAM, according to the alignment. +* :cpp:member:`dma_burst_size`: Set the burst size in a DMA burst transfer. * :cpp:member:`flags`: This is used to enable some special driver features. .. code-block:: c diff --git a/docs/zh_CN/api-reference/system/async_memcpy.rst b/docs/zh_CN/api-reference/system/async_memcpy.rst index fdd40d6befb..af3d772b85b 100644 --- a/docs/zh_CN/api-reference/system/async_memcpy.rst +++ b/docs/zh_CN/api-reference/system/async_memcpy.rst @@ -36,8 +36,7 @@ DMA 允许多个内存复制请求在首个请求完成之前排队,即允许 在 :cpp:type:`async_memcpy_config_t` 中设置驱动配置: * :cpp:member:`backlog`:此项用于配置首个请求完成前可以排队的最大内存复制事务数量。如果将此字段设置为零,会应用默认值 4。 -* :cpp:member:`sram_trans_align`:声明 SRAM 中数据地址和复制大小的对齐方式,如果数据没有对齐限制,则设置为零。如果设置为四的倍数值(即 4X),驱动程序将内部启用突发模式,这有利于某些和性能相关的应用程序。 -* :cpp:member:`psram_trans_align`:声明 PSRAM 中数据地址和复制大小的对齐方式。如果 memcpy 的目标地址位于 PSRAM 中,用户必须给出一个有效值(只支持 16、32、64)。如果设置为零,会默认采用 16 位对齐。在内部,驱动程序会根据对齐方式来配置 DMA 访问 PSRAM 时所用的块大小。 +* :cpp:member:`dma_burst_size`:设置单次 DMA 传输中突发数据量的大小。 * :cpp:member:`flags`:此项可以启用一些特殊的驱动功能。 .. code-block:: c From b2ff20d94c63110b8260da3cc53387f0e7308ec4 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 13 May 2024 14:44:06 +0800 Subject: [PATCH 194/548] change(i80_lcd): set DMA transfer burst size --- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 48 ++++++++++--------- components/esp_lcd/include/esp_lcd_panel_io.h | 7 ++- .../api-reference/peripherals/lcd/i80_lcd.rst | 3 +- .../main/i80_controller_example_main.c | 6 +-- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index 5f2911e5737..cbaea3f63d8 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,10 +27,9 @@ #include "soc/soc_caps.h" #include "esp_clk_tree.h" #include "esp_memory_utils.h" +#include "esp_cache.h" #include "hal/dma_types.h" #include "hal/gpio_hal.h" -#include "hal/cache_hal.h" -#include "hal/cache_ll.h" #include "esp_private/gdma.h" #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" @@ -38,7 +37,6 @@ #include "soc/lcd_periph.h" #include "hal/lcd_ll.h" #include "hal/lcd_hal.h" -#include "esp_cache.h" #define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1)) #define ALIGN_DOWN(size, align) ((size) & ~((align) - 1)) @@ -52,7 +50,7 @@ typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t; static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, const void *param, size_t param_size); static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, const void *color, size_t color_size); static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io); -static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus); +static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config); static void lcd_periph_trigger_quick_trans_done_event(esp_lcd_i80_bus_handle_t bus); static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_clock_source_t clk_src); static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config); @@ -72,8 +70,8 @@ struct esp_lcd_i80_bus_t { uint8_t *format_buffer; // The driver allocates an internal buffer for DMA to do data format transformer size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source gdma_channel_handle_t dma_chan; // DMA channel handle - size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM - size_t sram_trans_align; // DMA transfer alignment for data allocated from SRAM + size_t int_mem_align; // Alignment for internal memory + size_t ext_mem_align; // Alignment for external memory lcd_i80_trans_descriptor_t *cur_trans; // Current transaction lcd_panel_io_i80_t *cur_device; // Current working device LIST_HEAD(i80_device_list, lcd_panel_io_i80_t) device_list; // Head of i80 device list @@ -175,10 +173,8 @@ esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lc lcd_ll_enable_interrupt(bus->hal.dev, LCD_LL_EVENT_TRANS_DONE, false); // disable all interrupts lcd_ll_clear_interrupt_status(bus->hal.dev, UINT32_MAX); // clear pending interrupt // install DMA service - bus->psram_trans_align = bus_config->psram_trans_align; - bus->sram_trans_align = bus_config->sram_trans_align; bus->bus_width = bus_config->bus_width; - ret = lcd_i80_init_dma_link(bus); + ret = lcd_i80_init_dma_link(bus, bus_config); ESP_GOTO_ON_ERROR(ret, err, TAG, "install DMA failed"); // disable RGB-LCD mode lcd_ll_enable_rgb_mode(bus->hal.dev, false); @@ -481,6 +477,18 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons esp_lcd_i80_bus_t *bus = i80_device->bus; lcd_i80_trans_descriptor_t *trans_desc = NULL; assert(color_size <= (bus->num_dma_nodes * DMA_DESCRIPTOR_BUFFER_MAX_SIZE) && "color bytes too long, enlarge max_transfer_bytes"); + if (esp_ptr_external_ram(color)) { + // check alignment + ESP_RETURN_ON_FALSE(((uint32_t)color & (bus->ext_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color address not aligned"); + ESP_RETURN_ON_FALSE((color_size & (bus->ext_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color size not aligned"); + // flush frame buffer from cache to the physical PSRAM + esp_cache_msync((void *)color, color_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + } else { + // check alignment + ESP_RETURN_ON_FALSE(((uint32_t)color & (bus->int_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color address not aligned"); + ESP_RETURN_ON_FALSE((color_size & (bus->int_mem_align - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "color size not aligned"); + } + // in case bus_width=16 and cmd_bits=8, we still need 1 cmd_cycle uint32_t cmd_cycles = i80_device->lcd_cmd_bits / bus->bus_width; if (cmd_cycles * bus->bus_width < i80_device->lcd_cmd_bits) { @@ -503,13 +511,6 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons trans_desc->trans_done_cb = i80_device->on_color_trans_done; trans_desc->user_ctx = i80_device->user_ctx; - if (esp_ptr_external_ram(color)) { - uint32_t dcache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); - // flush frame buffer from cache to the physical PSRAM - // note the esp_cache_msync function will check the alignment of the address and size, make sure they're aligned to current cache line size - esp_cache_msync((void *)ALIGN_DOWN((intptr_t)color, dcache_line_size), ALIGN_UP(color_size, dcache_line_size), 0); - } - // send transaction to trans_queue xQueueSend(i80_device->trans_queue, &trans_desc, portMAX_DELAY); i80_device->num_trans_inflight++; @@ -542,7 +543,7 @@ static esp_err_t lcd_i80_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c return ESP_OK; } -static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus) +static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config) { esp_err_t ret = ESP_OK; // chain DMA descriptors @@ -567,12 +568,13 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus) .owner_check = true }; gdma_apply_strategy(bus->dma_chan, &strategy_config); - // set DMA transfer ability - gdma_transfer_ability_t ability = { - .psram_trans_align = bus->psram_trans_align, - .sram_trans_align = bus->sram_trans_align, + // config DMA transfer parameters + gdma_transfer_config_t trans_cfg = { + .max_data_burst_size = bus_config->dma_burst_size ? bus_config->dma_burst_size : 16, // Enable DMA burst transfer for better performance + .access_ext_mem = true, // the LCD can carry pixel buffer from the external memory }; - gdma_set_transfer_ability(bus->dma_chan, &ability); + ESP_GOTO_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), err, TAG, "config DMA transfer failed"); + gdma_get_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align); return ESP_OK; err: if (bus->dma_chan) { diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index ffae62e6805..03f0248a89c 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -238,8 +238,11 @@ typedef struct { int data_gpio_nums[ESP_LCD_I80_BUS_WIDTH_MAX]; /*!< GPIOs used for data lines */ size_t bus_width; /*!< Number of data lines, 8 or 16 */ size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */ - size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */ - size_t sram_trans_align; /*!< DMA transfer alignment for data allocated from SRAM */ + union { + size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */ + size_t dma_burst_size; /*!< DMA burst size, in bytes */ + }; + size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */ } esp_lcd_i80_bus_config_t; /** diff --git a/docs/en/api-reference/peripherals/lcd/i80_lcd.rst b/docs/en/api-reference/peripherals/lcd/i80_lcd.rst index 69df232a935..95fd79c993c 100644 --- a/docs/en/api-reference/peripherals/lcd/i80_lcd.rst +++ b/docs/en/api-reference/peripherals/lcd/i80_lcd.rst @@ -29,8 +29,7 @@ I80 Interfaced LCD }, .bus_width = 8, .max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t), // transfer 100 lines of pixels (assume pixel is RGB565) at most in one transaction - .psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT, - .sram_trans_align = 4, + .dma_burst_size = EXAMPLE_DMA_BURST_SIZE, }; ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus)); diff --git a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c index 86e8ce2b415..146c28ea7f3 100644 --- a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c +++ b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c @@ -93,8 +93,7 @@ static const char *TAG = "example"; #define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024) #define EXAMPLE_LVGL_TASK_PRIORITY 2 -// Supported alignment: 16, 32, 64. A higher alignment can enables higher burst transfer size, thus a higher i80 bus throughput. -#define EXAMPLE_PSRAM_DATA_ALIGNMENT 64 +#define EXAMPLE_DMA_BURST_SIZE 64 // 16, 32, 64. Higher burst size can improve the performance when the DMA buffer comes from PSRAM static SemaphoreHandle_t lvgl_mux = NULL; @@ -248,8 +247,7 @@ void example_init_i80_bus(esp_lcd_panel_io_handle_t *io_handle, void *user_ctx) }, .bus_width = CONFIG_EXAMPLE_LCD_I80_BUS_WIDTH, .max_transfer_bytes = EXAMPLE_LCD_H_RES * 100 * sizeof(uint16_t), - .psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT, - .sram_trans_align = 4, + .dma_burst_size = EXAMPLE_DMA_BURST_SIZE, }; ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus)); From 5d844e57edf9a77389d9f5fee7c37ec0b9daacad Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 13 May 2024 14:52:01 +0800 Subject: [PATCH 195/548] change(rgb_lcd): set DMA transfer burst size --- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 104 ++++++++++-------- .../esp_lcd/rgb/include/esp_lcd_panel_rgb.h | 7 +- .../test_apps/rgb_lcd/main/test_rgb_panel.c | 2 +- .../rgb_lcd/main/test_yuv_rgb_conv.c | 2 +- .../api-reference/peripherals/lcd/rgb_lcd.rst | 2 +- .../lcd/rgb_panel/main/rgb_lcd_example_main.c | 2 +- 6 files changed, 70 insertions(+), 49 deletions(-) diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 03161e1a96b..a12f244229d 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -39,7 +39,8 @@ #include "soc/lcd_periph.h" #include "hal/lcd_hal.h" #include "hal/lcd_ll.h" -#include "hal/gdma_ll.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" #include "rom/cache.h" #include "esp_cache.h" @@ -77,7 +78,8 @@ static esp_err_t rgb_panel_swap_xy(esp_lcd_panel_t *panel, bool swap_axes); static esp_err_t rgb_panel_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap); static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool off); static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *panel, lcd_clock_source_t clk_src); -static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel); +static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *panel); +static void lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *panel); static esp_err_t lcd_rgb_panel_configure_gpio(esp_rgb_panel_t *panel, const esp_lcd_rgb_panel_config_t *panel_config); static void lcd_rgb_panel_start_transmission(esp_rgb_panel_t *rgb_panel); static void lcd_default_isr_handler(void *args); @@ -90,8 +92,7 @@ struct esp_rgb_panel_t { size_t fb_bits_per_pixel; // Frame buffer color depth, in bpp size_t num_fbs; // Number of frame buffers size_t output_bits_per_pixel; // Color depth seen from the output data line. Default to fb_bits_per_pixel, but can be changed by YUV-RGB conversion - size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM - size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM + size_t dma_burst_size; // DMA transfer burst size int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off" intr_handle_t intr; // LCD peripheral interrupt handle esp_pm_lock_handle_t pm_lock; // Power management lock @@ -134,10 +135,20 @@ struct esp_rgb_panel_t { static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_config_t *rgb_panel_config, esp_rgb_panel_t *rgb_panel) { bool fb_in_psram = false; - size_t psram_trans_align = rgb_panel_config->psram_trans_align ? rgb_panel_config->psram_trans_align : 64; - size_t sram_trans_align = rgb_panel_config->sram_trans_align ? rgb_panel_config->sram_trans_align : 4; - rgb_panel->psram_trans_align = psram_trans_align; - rgb_panel->sram_trans_align = sram_trans_align; + size_t ext_mem_align = 0; + size_t int_mem_align = 0; + gdma_get_alignment_constraints(rgb_panel->dma_chan, &int_mem_align, &ext_mem_align); + + // also take the cache line size into account when allocating the frame buffer + uint32_t ext_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); + uint32_t int_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + // The buffer must be aligned to the cache line size + if (ext_mem_cache_line_size) { + ext_mem_align = MAX(ext_mem_align, ext_mem_cache_line_size); + } + if (int_mem_cache_line_size) { + int_mem_align = MAX(int_mem_align, int_mem_cache_line_size); + } // alloc frame buffer if (rgb_panel->num_fbs > 0) { @@ -152,13 +163,13 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi for (int i = 0; i < rgb_panel->num_fbs; i++) { if (fb_in_psram) { // the low level malloc function will help check the validation of alignment - rgb_panel->fbs[i] = heap_caps_aligned_calloc(psram_trans_align, 1, rgb_panel->fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + rgb_panel->fbs[i] = heap_caps_aligned_calloc(ext_mem_align, 1, rgb_panel->fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer"); // calloc not only allocates but also zero's the buffer. We have to make sure this is // properly committed to the PSRAM, otherwise all sorts of visual corruption will happen. ESP_RETURN_ON_ERROR(esp_cache_msync(rgb_panel->fbs[i], rgb_panel->fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M), TAG, "cache write back failed"); } else { - rgb_panel->fbs[i] = heap_caps_aligned_calloc(sram_trans_align, 1, rgb_panel->fb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + rgb_panel->fbs[i] = heap_caps_aligned_calloc(int_mem_align, 1, rgb_panel->fb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); ESP_RETURN_ON_FALSE(rgb_panel->fbs[i], ESP_ERR_NO_MEM, TAG, "no mem for frame buffer"); } } @@ -168,7 +179,7 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(const esp_lcd_rgb_panel_confi if (rgb_panel->bb_size) { for (int i = 0; i < RGB_LCD_PANEL_BOUNCE_BUF_NUM; i++) { // bounce buffer must come from SRAM - rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(sram_trans_align, 1, rgb_panel->bb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + rgb_panel->bounce_buffer[i] = heap_caps_aligned_calloc(int_mem_align, 1, rgb_panel->bb_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); ESP_RETURN_ON_FALSE(rgb_panel->bounce_buffer[i], ESP_ERR_NO_MEM, TAG, "no mem for bounce buffer"); } } @@ -302,9 +313,6 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf } } - // allocate frame buffers + bounce buffers - ESP_GOTO_ON_ERROR(lcd_rgb_panel_alloc_frame_buffers(rgb_panel_config, rgb_panel), err, TAG, "alloc frame buffers failed"); - // initialize HAL layer, so we can call LL APIs later lcd_hal_init(&rgb_panel->hal, panel_id); // enable clock @@ -334,8 +342,13 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf // install DMA service rgb_panel->flags.stream_mode = !rgb_panel_config->flags.refresh_on_demand; rgb_panel->fb_bits_per_pixel = fb_bits_per_pixel; - ret = lcd_rgb_panel_create_trans_link(rgb_panel); - ESP_GOTO_ON_ERROR(ret, err, TAG, "install DMA failed"); + rgb_panel->dma_burst_size = rgb_panel_config->dma_burst_size ? rgb_panel_config->dma_burst_size : 64; + ESP_GOTO_ON_ERROR(lcd_rgb_create_dma_channel(rgb_panel), err, TAG, "install DMA failed"); + // allocate frame buffers + bounce buffers + ESP_GOTO_ON_ERROR(lcd_rgb_panel_alloc_frame_buffers(rgb_panel_config, rgb_panel), err, TAG, "alloc frame buffers failed"); + // initialize DMA descriptor link + lcd_rgb_panel_init_trans_link(rgb_panel); + // configure GPIO ret = lcd_rgb_panel_configure_gpio(rgb_panel, rgb_panel_config); ESP_GOTO_ON_ERROR(ret, err, TAG, "configure GPIO failed"); @@ -959,11 +972,42 @@ static IRAM_ATTR bool lcd_rgb_panel_eof_handler(gdma_channel_handle_t dma_chan, return lcd_rgb_panel_fill_bounce_buffer(panel, panel->bounce_buffer[bb]); } +static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *panel) +{ + // alloc DMA channel and connect to LCD peripheral + gdma_channel_alloc_config_t dma_chan_config = { + .direction = GDMA_CHANNEL_DIRECTION_TX, + }; +#if SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed"); +#elif SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AXI + ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed"); +#endif + gdma_connect(panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0)); + + // configure DMA transfer parameters + gdma_transfer_config_t trans_cfg = { + .max_data_burst_size = panel->dma_burst_size, + .access_ext_mem = true, // frame buffer was allocated from external memory + }; + ESP_RETURN_ON_ERROR(gdma_config_transfer(panel->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); + + // we need to refill the bounce buffer in the DMA EOF interrupt, so only register the callback for bounce buffer mode + if (panel->bb_size) { + gdma_tx_event_callbacks_t cbs = { + .on_trans_eof = lcd_rgb_panel_eof_handler, + }; + gdma_register_tx_event_callbacks(panel->dma_chan, &cbs, panel); + } + + return ESP_OK; +} + // If we restart GDMA, many pixels already have been transferred to the LCD peripheral. // Looks like that has 16 pixels of FIFO plus one holding register. #define LCD_FIFO_PRESERVE_SIZE_PX (LCD_LL_FIFO_DEPTH + 1) -static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel) +static void lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *panel) { for (int i = 0; i < RGB_LCD_PANEL_DMA_LINKS_REPLICA; i++) { panel->dma_links[i] = &panel->dma_nodes[panel->num_dma_nodes * i]; @@ -1007,32 +1051,6 @@ static esp_err_t lcd_rgb_panel_create_trans_link(esp_rgb_panel_t *panel) panel->dma_restart_node.buffer = &p[restart_skip_bytes]; panel->dma_restart_node.dw0.length -= restart_skip_bytes; panel->dma_restart_node.dw0.size -= restart_skip_bytes; - - // alloc DMA channel and connect to LCD peripheral - gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; -#if SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AHB - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed"); -#elif SOC_GDMA_TRIG_PERIPH_LCD0_BUS == SOC_GDMA_BUS_AXI - ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&dma_chan_config, &panel->dma_chan), TAG, "alloc DMA channel failed"); -#endif - gdma_connect(panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0)); - gdma_transfer_ability_t ability = { - .psram_trans_align = panel->psram_trans_align, - .sram_trans_align = panel->sram_trans_align, - }; - gdma_set_transfer_ability(panel->dma_chan, &ability); - - // we need to refill the bounce buffer in the DMA EOF interrupt, so only register the callback for bounce buffer mode - if (panel->bb_size) { - gdma_tx_event_callbacks_t cbs = { - .on_trans_eof = lcd_rgb_panel_eof_handler, - }; - gdma_register_tx_event_callbacks(panel->dma_chan, &cbs, panel); - } - - return ESP_OK; } // reset the GDMA channel every VBlank to stop permanent desyncs from happening. diff --git a/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h b/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h index 7cd4c690b7b..2e9e5a95a6e 100644 --- a/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h +++ b/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h @@ -132,8 +132,11 @@ typedef struct { size_t num_fbs; /*!< Number of screen-sized frame buffers that allocated by the driver. By default (set to either 0 or 1) only one frame buffer will be used. Maximum number of buffers are 3 */ size_t bounce_buffer_size_px; /*!< If it's non-zero, the driver allocates two DRAM bounce buffers for DMA use. DMA fetching from DRAM bounce buffer is much faster than PSRAM frame buffer. */ - size_t sram_trans_align; /*!< Alignment of buffers (frame buffer or bounce buffer) that allocated in SRAM */ - size_t psram_trans_align; /*!< Alignment of buffers (frame buffer) that allocated in PSRAM */ + size_t sram_trans_align __attribute__((deprecated)); /*!< Alignment of buffers (frame buffer or bounce buffer) that allocated in SRAM */ + union { + size_t psram_trans_align; /*!< Alignment of buffers (frame buffer) that allocated in PSRAM */ + size_t dma_burst_size; /*!< DMA burst size, in bytes */ + }; int hsync_gpio_num; /*!< GPIO used for HSYNC signal */ int vsync_gpio_num; /*!< GPIO used for VSYNC signal */ int de_gpio_num; /*!< GPIO used for DE signal, set to -1 if it's not used */ diff --git a/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c b/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c index 4e1eb3edd39..8c39c32121f 100644 --- a/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c +++ b/components/esp_lcd/test_apps/rgb_lcd/main/test_rgb_panel.c @@ -31,7 +31,7 @@ static esp_lcd_panel_handle_t test_rgb_panel_initialization(size_t data_width, s esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_panel_config_t panel_config = { .data_width = data_width, - .psram_trans_align = 64, + .dma_burst_size = 64, .bounce_buffer_size_px = bb_pixels, .bits_per_pixel = bpp, .clk_src = LCD_CLK_SRC_DEFAULT, diff --git a/components/esp_lcd/test_apps/rgb_lcd/main/test_yuv_rgb_conv.c b/components/esp_lcd/test_apps/rgb_lcd/main/test_yuv_rgb_conv.c index 4bcf65dbdc8..73ab6dede79 100644 --- a/components/esp_lcd/test_apps/rgb_lcd/main/test_yuv_rgb_conv.c +++ b/components/esp_lcd/test_apps/rgb_lcd/main/test_yuv_rgb_conv.c @@ -27,7 +27,7 @@ TEST_CASE("lcd_rgb_panel_yuv422_conversion", "[lcd]") esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_panel_config_t panel_config = { .data_width = 16, - .psram_trans_align = 64, + .dma_burst_size = 64, .bits_per_pixel = 16, // YUV422: 16bits per pixel .clk_src = LCD_CLK_SRC_DEFAULT, .disp_gpio_num = TEST_LCD_DISP_EN_GPIO, diff --git a/docs/en/api-reference/peripherals/lcd/rgb_lcd.rst b/docs/en/api-reference/peripherals/lcd/rgb_lcd.rst index 882dfb7406a..1ecb0a0646c 100644 --- a/docs/en/api-reference/peripherals/lcd/rgb_lcd.rst +++ b/docs/en/api-reference/peripherals/lcd/rgb_lcd.rst @@ -7,7 +7,7 @@ RGB LCD panel is allocated in one step: :cpp:func:`esp_lcd_new_rgb_panel`, with - :cpp:member:`esp_lcd_rgb_panel_config_t::data_width` set number of data lines used by the RGB interface. Currently, the supported value can be 8 or 16. - :cpp:member:`esp_lcd_rgb_panel_config_t::bits_per_pixel` set the number of bits per pixel. This is different from :cpp:member:`esp_lcd_rgb_panel_config_t::data_width`. By default, if you set this field to 0, the driver will automatically adjust the bpp to the :cpp:member:`esp_lcd_rgb_panel_config_t::data_width`. But in some cases, these two value must be different. For example, a Serial RGB interface LCD only needs ``8`` data lines, but the color width can reach to ``RGB888``, i.e., the :cpp:member:`esp_lcd_rgb_panel_config_t::bits_per_pixel` should be set to ``24``. - :cpp:member:`esp_lcd_rgb_panel_config_t::hsync_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::vsync_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::de_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::pclk_gpio_num`, :cpp:member:`esp_lcd_rgb_panel_config_t::disp_gpio_num` and :cpp:member:`esp_lcd_rgb_panel_config_t::data_gpio_nums` are the GPIO pins used by the RGB LCD controller. If some of them are not used, please set it to `-1`. - - :cpp:member:`esp_lcd_rgb_panel_config_t::sram_trans_align` and :cpp:member:`esp_lcd_rgb_panel_config_t::psram_trans_align` set the alignment of the allocated frame buffer. Internally, the DMA transfer ability will adjust against these alignment values. A higher alignment value can lead to a bigger DMA burst size. Please note, the alignment value must be a power of 2. + - :cpp:member:`esp_lcd_rgb_panel_config_t::dma_burst_size` set the DMA transfer burst size, the value must be a power of 2. - :cpp:member:`esp_lcd_rgb_panel_config_t::bounce_buffer_size_px` set the size of bounce buffer. This is only necessary for a so-called "bounce buffer" mode. Please refer to :ref:`bounce_buffer_with_single_psram_frame_buffer` for more information. - :cpp:member:`esp_lcd_rgb_panel_config_t::timings` sets the LCD panel specific timing parameters. All required parameters are listed in the :cpp:type:`esp_lcd_rgb_timing_t`, including the LCD resolution and blanking porches. Please fill them according to the datasheet of your LCD. - :cpp:member:`esp_lcd_rgb_panel_config_t::fb_in_psram` sets whether to allocate the frame buffer from PSRAM or not. Please refer to :ref:`single_frame_buffer_in_psram` for more information. diff --git a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c index 8c8599a3d3c..f388294a41c 100644 --- a/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c +++ b/examples/peripherals/lcd/rgb_panel/main/rgb_lcd_example_main.c @@ -166,7 +166,7 @@ void app_main(void) esp_lcd_panel_handle_t panel_handle = NULL; esp_lcd_rgb_panel_config_t panel_config = { .data_width = 16, // RGB565 in parallel mode, thus 16bit in width - .psram_trans_align = 64, + .dma_burst_size = 64, .num_fbs = EXAMPLE_LCD_NUM_FB, #if CONFIG_EXAMPLE_USE_BOUNCE_BUFFER .bounce_buffer_size_px = 10 * EXAMPLE_LCD_H_RES, From 7474a450c2292ed21646648b3117c240444709db Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 7 May 2024 05:17:16 +0800 Subject: [PATCH 196/548] refactor(usb): Rename mock class files - Rename "test_usb_mock_..." class files to "mock_..." - Fixed some codespell issues - Fixed comment spacing --- .codespellrc | 2 +- .../usb/test_apps/common/CMakeLists.txt | 4 +- .../{test_usb_mock_hid.c => mock_hid.c} | 18 +-- .../{test_usb_mock_hid.h => mock_hid.h} | 0 .../{test_usb_mock_msc.c => mock_msc.c} | 32 ++--- .../{test_usb_mock_msc.h => mock_msc.h} | 0 .../usb/test_apps/common/test_usb_common.c | 8 +- .../usb/test_apps/hcd/main/test_app_main.c | 2 +- .../usb/test_apps/hcd/main/test_hcd_bulk.c | 30 ++--- .../usb/test_apps/hcd/main/test_hcd_common.c | 92 +++++++------- .../usb/test_apps/hcd/main/test_hcd_ctrl.c | 100 +++++++-------- .../usb/test_apps/hcd/main/test_hcd_intr.c | 24 ++-- .../usb/test_apps/hcd/main/test_hcd_isoc.c | 96 +++++++------- .../usb/test_apps/hcd/main/test_hcd_port.c | 118 +++++++++--------- .../usb/test_apps/hcd/main/test_usb_helpers.c | 30 ++--- components/usb/test_apps/usb_host/README.md | 2 +- .../usb_host/main/ctrl_client_async_seq.c | 26 ++-- .../usb_host/main/msc_client_async_dconn.c | 58 ++++----- .../usb_host/main/msc_client_async_enum.c | 40 +++--- .../usb_host/main/msc_client_async_seq.c | 54 ++++---- .../test_apps/usb_host/main/test_app_main.c | 14 +-- .../usb_host/main/test_usb_host_async.c | 40 +++--- .../usb_host/main/test_usb_host_plugging.c | 24 ++-- 23 files changed, 408 insertions(+), 406 deletions(-) rename components/usb/test_apps/common/{test_usb_mock_hid.c => mock_hid.c} (75%) rename components/usb/test_apps/common/{test_usb_mock_hid.h => mock_hid.h} (100%) rename components/usb/test_apps/common/{test_usb_mock_msc.c => mock_msc.c} (90%) rename components/usb/test_apps/common/{test_usb_mock_msc.h => mock_msc.h} (100%) diff --git a/.codespellrc b/.codespellrc index 4f3b1e3beed..389e346d2a1 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,4 +1,4 @@ [codespell] skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,components/wpa_supplicant/*,components/esp_wifi/* -ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart +ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight write-changes = true diff --git a/components/usb/test_apps/common/CMakeLists.txt b/components/usb/test_apps/common/CMakeLists.txt index f03c668f9ef..ce2bfb32b3a 100644 --- a/components/usb/test_apps/common/CMakeLists.txt +++ b/components/usb/test_apps/common/CMakeLists.txt @@ -1,3 +1,5 @@ -idf_component_register(SRCS "test_usb_common.c" "test_usb_mock_msc.c" "test_usb_mock_hid.c" +idf_component_register(SRCS "mock_hid.c" + "mock_msc.c" + "test_usb_common.c" INCLUDE_DIRS "." REQUIRES usb unity) diff --git a/components/usb/test_apps/common/test_usb_mock_hid.c b/components/usb/test_apps/common/mock_hid.c similarity index 75% rename from components/usb/test_apps/common/test_usb_mock_hid.c rename to components/usb/test_apps/common/mock_hid.c index ea7dc32af9b..4f91e7b2945 100644 --- a/components/usb/test_apps/common/test_usb_mock_hid.c +++ b/components/usb/test_apps/common/mock_hid.c @@ -9,33 +9,33 @@ #include #include #include "usb/usb_types_ch9.h" -#include "test_usb_mock_hid.h" +#include "mock_hid.h" // ---------------------------------------------------- HID Mouse ------------------------------------------------------ const usb_ep_desc_t mock_hid_mouse_in_ep_desc = { .bLength = sizeof(usb_ep_desc_t), .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_HID_MOUSE_INTR_IN_EP_ADDR, //EP 1 IN + .bEndpointAddress = MOCK_HID_MOUSE_INTR_IN_EP_ADDR, // EP 1 IN .bmAttributes = USB_BM_ATTRIBUTES_XFER_INT, .wMaxPacketSize = MOCK_HID_MOUSE_INTR_IN_MPS, - .bInterval = 10, //Interval of 10ms + .bInterval = 10, // Interval of 10ms }; void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter) { static int x_pos = 0; static int y_pos = 0; - //Update X position - if (report->x_movement & 0x80) { //Positive movement + // Update X position + if (report->x_movement & 0x80) { // Positive movement x_pos += report->x_movement & 0x7F; - } else { //Negative movement + } else { // Negative movement x_pos -= report->x_movement & 0x7F; } - //Update Y position - if (report->y_movement & 0x80) { //Positive movement + // Update Y position + if (report->y_movement & 0x80) { // Positive movement y_pos += report->y_movement & 0x7F; - } else { //Negative movement + } else { // Negative movement y_pos -= report->y_movement & 0x7F; } printf("\rX:%d\tY:%d\tIter: %d\n", x_pos, y_pos, iter); diff --git a/components/usb/test_apps/common/test_usb_mock_hid.h b/components/usb/test_apps/common/mock_hid.h similarity index 100% rename from components/usb/test_apps/common/test_usb_mock_hid.h rename to components/usb/test_apps/common/mock_hid.h diff --git a/components/usb/test_apps/common/test_usb_mock_msc.c b/components/usb/test_apps/common/mock_msc.c similarity index 90% rename from components/usb/test_apps/common/test_usb_mock_msc.c rename to components/usb/test_apps/common/mock_msc.c index 6f752602366..fd276d6b5b4 100644 --- a/components/usb/test_apps/common/test_usb_mock_msc.c +++ b/components/usb/test_apps/common/mock_msc.c @@ -9,7 +9,7 @@ #include #include #include "usb/usb_types_ch9.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" // ---------------------------------------------------- MSC SCSI ------------------------------------------------------- @@ -41,7 +41,7 @@ static const usb_config_desc_t mock_msc_config_desc = { .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = 0x80, - .bMaxPower = 0x70, //224mA + .bMaxPower = 0x70, // 224mA }; static const usb_intf_desc_t mock_msc_intf_desc = { @@ -51,8 +51,8 @@ static const usb_intf_desc_t mock_msc_intf_desc = { .bAlternateSetting = MOCK_MSC_SCSI_INTF_ALT_SETTING, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = 0x06, //SCSI - .bInterfaceProtocol = 0x50, //Bulk only + .bInterfaceSubClass = 0x06, // SCSI + .bInterfaceProtocol = 0x50, // Bulk only .iInterface = 0, }; @@ -66,18 +66,18 @@ usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc; const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_fs = { .bLength = sizeof(usb_ep_desc_t), .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, //EP 1 OUT + .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, // EP 1 OUT .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, //MPS of 64 bytes + .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, // MPS of 64 bytes .bInterval = 0, }; const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_hs = { .bLength = sizeof(usb_ep_desc_t), .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, //EP 1 OUT + .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, // EP 1 OUT .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, //MPS of 512 bytes + .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, // MPS of 512 bytes .bInterval = 0, }; @@ -86,7 +86,7 @@ const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_fs = { .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, .bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR, .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, //MPS of 64 bytes + .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, // MPS of 64 bytes .bInterval = 0, }; @@ -95,20 +95,20 @@ const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_hs = { .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, .bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR, .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, //MPS of 512 bytes + .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, // MPS of 512 bytes .bInterval = 0, }; void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag) { - cbw->dCBWSignature = 0x43425355; //Fixed value - cbw->dCBWTag = tag; //Random value that is echoed back + cbw->dCBWSignature = 0x43425355; // Fixed value + cbw->dCBWTag = tag; // Random value that is echoed back cbw->dCBWDataTransferLength = num_sectors * MOCK_MSC_SCSI_SECTOR_SIZE; - cbw->bmCBWFlags = (is_read) ? (1 << 7) : 0; //If this is a read, set the direction flag + cbw->bmCBWFlags = (is_read) ? (1 << 7) : 0; // If this is a read, set the direction flag cbw->bCBWLUN = MOCK_MSC_SCSI_LUN; - cbw->bCBWCBLength = 10; //The length of the SCSI command - //Initialize SCSI CMD as READ10 or WRITE 10 - cbw->CBWCB.opcode = (is_read) ? 0x28 : 0x2A; //SCSI CMD READ10 or WRITE10 + cbw->bCBWCBLength = 10; // The length of the SCSI command + // Initialize SCSI CMD as READ10 or WRITE 10 + cbw->CBWCB.opcode = (is_read) ? 0x28 : 0x2A; // SCSI CMD READ10 or WRITE10 cbw->CBWCB.flags = 0; cbw->CBWCB.lba_3 = (offset >> 24); cbw->CBWCB.lba_2 = (offset >> 16); diff --git a/components/usb/test_apps/common/test_usb_mock_msc.h b/components/usb/test_apps/common/mock_msc.h similarity index 100% rename from components/usb/test_apps/common/test_usb_mock_msc.h rename to components/usb/test_apps/common/mock_msc.h diff --git a/components/usb/test_apps/common/test_usb_common.c b/components/usb/test_apps/common/test_usb_common.c index 2fa98b3dabb..09345017625 100644 --- a/components/usb/test_apps/common/test_usb_common.c +++ b/components/usb/test_apps/common/test_usb_common.c @@ -17,12 +17,12 @@ static usb_phy_handle_t phy_hdl = NULL; void test_usb_init_phy(void) { - //Initialize the internal USB PHY to connect to the USB OTG peripheral + // Initialize the internal USB PHY to connect to the USB OTG peripheral usb_phy_config_t phy_config = { .controller = USB_PHY_CTRL_OTG, .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_HOST, - .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device .ext_io_conf = NULL, .otg_io_conf = NULL, }; @@ -31,7 +31,7 @@ void test_usb_init_phy(void) void test_usb_deinit_phy(void) { - //Deinitialize the internal USB PHY + // Deinitialize the internal USB PHY TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_del_phy(phy_hdl), "Failed to delete PHY"); phy_hdl = NULL; } @@ -39,7 +39,7 @@ void test_usb_deinit_phy(void) void test_usb_set_phy_state(bool connected, TickType_t delay_ticks) { if (delay_ticks > 0) { - //Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. + // Delay of 0 ticks causes a yield. So skip if delay_ticks is 0. vTaskDelay(delay_ticks); } ESP_ERROR_CHECK(usb_phy_action(phy_hdl, (connected) ? USB_PHY_ACTION_HOST_ALLOW_CONN : USB_PHY_ACTION_HOST_FORCE_DISCONN)); diff --git a/components/usb/test_apps/hcd/main/test_app_main.c b/components/usb/test_apps/hcd/main/test_app_main.c index 224b068adae..d9a01d71e81 100644 --- a/components/usb/test_apps/hcd/main/test_app_main.c +++ b/components/usb/test_apps/hcd/main/test_app_main.c @@ -20,7 +20,7 @@ void setUp(void) void tearDown(void) { - //Short delay to allow task to be cleaned up + // Short delay to allow task to be cleaned up vTaskDelay(10); test_hcd_teardown(port_hdl); port_hdl = NULL; diff --git a/components/usb/test_apps/hcd/main/test_hcd_bulk.c b/components/usb/test_apps/hcd/main/test_hcd_bulk.c index 5ad852f590d..f5034dc66a4 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_bulk.c +++ b/components/usb/test_apps/hcd/main/test_hcd_bulk.c @@ -9,24 +9,24 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "unity.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "test_hcd_common.h" // --------------------------------------------------- Test Cases ------------------------------------------------------ static void mock_msc_reset_req(hcd_pipe_handle_t default_pipe) { - //Create URB + // Create URB urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_setup_packet_t)); usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)urb->transfer.data_buffer; MOCK_MSC_SCSI_REQ_INIT_RESET(setup_pkt, MOCK_MSC_SCSI_INTF_NUMBER); urb->transfer.num_bytes = sizeof(usb_setup_packet_t); - //Enqueue, wait, dequeue, and check URB + // Enqueue, wait, dequeue, and check URB TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL_PTR(urb, hcd_urb_dequeue(default_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); - //Free URB + // Free URB test_hcd_free_urb(urb); } @@ -54,19 +54,19 @@ Test HCD bulk pipe URBs TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Enumerate and reset MSC SCSI device - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Enumerate and reset MSC SCSI device + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); mock_msc_reset_req(default_pipe); test_hcd_set_mock_msc_ep_descriptor(port_speed); - //Create BULK IN and BULK OUT pipes for SCSI + // Create BULK IN and BULK OUT pipes for SCSI hcd_pipe_handle_t bulk_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_msc_scsi_bulk_out_ep_desc, dev_addr, port_speed); hcd_pipe_handle_t bulk_in_pipe = test_hcd_pipe_alloc(port_hdl, &mock_msc_scsi_bulk_in_ep_desc, dev_addr, port_speed); - //Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS + // Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS urb_t *urb_cbw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_cbw_t)); urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE); const uint16_t mps = USB_EP_DESC_GET_MPS(&mock_msc_scsi_bulk_in_ep_desc) ; @@ -76,25 +76,25 @@ TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]") urb_csw->transfer.num_bytes = sizeof(mock_msc_bulk_csw_t) + (mps - (sizeof(mock_msc_bulk_csw_t) % mps)); for (int block_num = 0; block_num < TEST_NUM_SECTORS_TOTAL; block_num += TEST_NUM_SECTORS_PER_XFER) { - //Initialize CBW URB, then send it on the BULK OUT pipe + // Initialize CBW URB, then send it on the BULK OUT pipe mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)urb_cbw->transfer.data_buffer, true, block_num, TEST_NUM_SECTORS_PER_XFER, 0xAAAAAAAA); TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_out_pipe, urb_cbw)); test_hcd_expect_pipe_event(bulk_out_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL_PTR(urb_cbw, hcd_urb_dequeue(bulk_out_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb_cbw->transfer.status, "Transfer NOT completed"); - //Read data through BULK IN pipe + // Read data through BULK IN pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_in_pipe, urb_data)); test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL_PTR(urb_data, hcd_urb_dequeue(bulk_in_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb_data->transfer.status, "Transfer NOT completed"); - //Read the CSW through BULK IN pipe + // Read the CSW through BULK IN pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_in_pipe, urb_csw)); test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL_PTR(urb_csw, hcd_urb_dequeue(bulk_in_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb_data->transfer.status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(sizeof(mock_msc_bulk_csw_t), urb_csw->transfer.actual_num_bytes); TEST_ASSERT_TRUE(mock_msc_scsi_check_csw((mock_msc_bulk_csw_t *)urb_csw->transfer.data_buffer, 0xAAAAAAAA)); - //Print the read data + // Print the read data printf("Block %d to %d:\n", block_num, block_num + TEST_NUM_SECTORS_PER_XFER); for (int i = 0; i < urb_data->transfer.actual_num_bytes; i++) { printf("0x%02x,", ((char *)urb_data->transfer.data_buffer)[i]); @@ -108,6 +108,6 @@ TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]") test_hcd_pipe_free(bulk_out_pipe); test_hcd_pipe_free(bulk_in_pipe); test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } diff --git a/components/usb/test_apps/hcd/main/test_hcd_common.c b/components/usb/test_apps/hcd/main/test_hcd_common.c index b2147b5ad16..0d69c183c18 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_common.c +++ b/components/usb/test_apps/hcd/main/test_hcd_common.c @@ -19,14 +19,14 @@ #include "usb/usb_types_ch9.h" #include "test_hcd_common.h" #include "test_usb_common.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "unity.h" #include "esp_dma_utils.h" #define PORT_NUM 1 #define EVENT_QUEUE_LEN 5 -#define ENUM_ADDR 1 //Device address to use for tests that enumerate the device -#define ENUM_CONFIG 1 //Device configuration number to use for tests that enumerate the device +#define ENUM_ADDR 1 // Device address to use for tests that enumerate the device +#define ENUM_CONFIG 1 // Device configuration number to use for tests that enumerate the device typedef struct { hcd_port_handle_t port_hdl; @@ -54,10 +54,10 @@ hcd_port_handle_t port_hdl = NULL; */ static bool port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr) { - //We store the port's queue handle in the port's context variable + // We store the port's queue handle in the port's context variable void *port_ctx = hcd_port_get_context(port_hdl); QueueHandle_t port_evt_queue = (QueueHandle_t)port_ctx; - TEST_ASSERT_TRUE(in_isr); //Current HCD implementation should never call a port callback in a task context + TEST_ASSERT_TRUE(in_isr); // Current HCD implementation should never call a port callback in a task context port_event_msg_t msg = { .port_hdl = port_hdl, .port_event = port_event, @@ -98,14 +98,14 @@ static bool pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_even void test_hcd_expect_port_event(hcd_port_handle_t port_hdl, hcd_port_event_t expected_event) { - //Get the port event queue from the port's context variable + // Get the port event queue from the port's context variable QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl); TEST_ASSERT_NOT_NULL(port_evt_queue); - //Wait for port callback to send an event message + // Wait for port callback to send an event message port_event_msg_t msg; BaseType_t ret = xQueueReceive(port_evt_queue, &msg, pdMS_TO_TICKS(5000)); TEST_ASSERT_EQUAL_MESSAGE(pdPASS, ret, "Port event not generated on time"); - //Check the contents of that event message + // Check the contents of that event message TEST_ASSERT_EQUAL(port_hdl, msg.port_hdl); TEST_ASSERT_EQUAL_MESSAGE(expected_event, msg.port_event, "Unexpected event"); printf("\t-> Port event\n"); @@ -113,21 +113,21 @@ void test_hcd_expect_port_event(hcd_port_handle_t port_hdl, hcd_port_event_t exp void test_hcd_expect_pipe_event(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t expected_event) { - //Get the pipe's event queue from the pipe's context variable + // Get the pipe's event queue from the pipe's context variable QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl); TEST_ASSERT_NOT_NULL(pipe_evt_queue); - //Wait for pipe callback to send an event message + // Wait for pipe callback to send an event message pipe_event_msg_t msg; BaseType_t ret = xQueueReceive(pipe_evt_queue, &msg, pdMS_TO_TICKS(5000)); TEST_ASSERT_EQUAL_MESSAGE(pdPASS, ret, "Pipe event not generated on time"); - //Check the contents of that event message + // Check the contents of that event message TEST_ASSERT_EQUAL(pipe_hdl, msg.pipe_hdl); TEST_ASSERT_EQUAL_MESSAGE(expected_event, msg.pipe_event, "Unexpected event"); } int test_hcd_get_num_port_events(hcd_port_handle_t port_hdl) { - //Get the port event queue from the port's context variable + // Get the port event queue from the port's context variable QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl); TEST_ASSERT_NOT_NULL(port_evt_queue); return EVENT_QUEUE_LEN - uxQueueSpacesAvailable(port_evt_queue); @@ -135,7 +135,7 @@ int test_hcd_get_num_port_events(hcd_port_handle_t port_hdl) int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl) { - //Get the pipe's event queue from the pipe's context variable + // Get the pipe's event queue from the pipe's context variable QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl); TEST_ASSERT_NOT_NULL(pipe_evt_queue); return EVENT_QUEUE_LEN - uxQueueSpacesAvailable(pipe_evt_queue); @@ -145,16 +145,16 @@ int test_hcd_get_num_pipe_events(hcd_pipe_handle_t pipe_hdl) hcd_port_handle_t test_hcd_setup(void) { - test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing - //Create a queue for port callback to queue up port events + test_usb_init_phy(); // Initialize the internal USB PHY and USB Controller for testing + // Create a queue for port callback to queue up port events QueueHandle_t port_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(port_event_msg_t)); TEST_ASSERT_NOT_NULL(port_evt_queue); - //Install HCD + // Install HCD hcd_config_t hcd_config = { .intr_flags = ESP_INTR_FLAG_LEVEL1, }; TEST_ASSERT_EQUAL(ESP_OK, hcd_install(&hcd_config)); - //Initialize a port + // Initialize a port hcd_port_config_t port_config = { .fifo_bias = HCD_PORT_FIFO_BIAS_BALANCED, .callback = port_callback, @@ -165,7 +165,7 @@ hcd_port_handle_t test_hcd_setup(void) TEST_ASSERT_EQUAL(ESP_OK, hcd_port_init(PORT_NUM, &port_config, &port_hdl)); TEST_ASSERT_NOT_NULL(port_hdl); TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl)); - test_usb_set_phy_state(false, 0); //Force disconnected state on PHY + test_usb_set_phy_state(false, 0); // Force disconnected state on PHY return port_hdl; } @@ -174,33 +174,33 @@ void test_hcd_teardown(hcd_port_handle_t port_hdl) if (!port_hdl) { return; // In case of setup stage failure, don't run tear-down stage } - //Get the queue handle from the port's context variable + // Get the queue handle from the port's context variable QueueHandle_t port_evt_queue = (QueueHandle_t)hcd_port_get_context(port_hdl); TEST_ASSERT_NOT_NULL(port_evt_queue); - //Deinitialize a port + // Deinitialize a port TEST_ASSERT_EQUAL(ESP_OK, hcd_port_deinit(port_hdl)); - //Uninstall the HCD + // Uninstall the HCD TEST_ASSERT_EQUAL(ESP_OK, hcd_uninstall()); vQueueDelete(port_evt_queue); - test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing + test_usb_deinit_phy(); // Deinitialize the internal USB PHY after testing } usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl) { - //Power ON the port + // Power ON the port TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_ON)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISCONNECTED, hcd_port_get_state(port_hdl)); - //Wait for connection event + // Wait for connection event printf("Waiting for connection\n"); - test_usb_set_phy_state(true, pdMS_TO_TICKS(100)); //Allow for connected state on PHY + test_usb_set_phy_state(true, pdMS_TO_TICKS(100)); // Allow for connected state on PHY test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_CONNECTION); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_CONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); - //Reset newly connected device + // Reset newly connected device printf("Resetting\n"); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_RESET)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_ENABLED, hcd_port_get_state(port_hdl)); - //Get speed of connected + // Get speed of connected usb_speed_t port_speed; TEST_ASSERT_EQUAL(ESP_OK, hcd_port_get_speed(port_hdl, &port_speed)); TEST_ASSERT_LESS_OR_EQUAL_MESSAGE(USB_SPEED_HIGH, port_speed, "Invalid port speed"); @@ -213,18 +213,18 @@ usb_speed_t test_hcd_wait_for_conn(hcd_port_handle_t port_hdl) void test_hcd_wait_for_disconn(hcd_port_handle_t port_hdl, bool already_disabled) { if (!already_disabled) { - //Disable the device + // Disable the device printf("Disabling\n"); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); } - //Wait for a safe disconnect + // Wait for a safe disconnect printf("Waiting for disconnection\n"); - test_usb_set_phy_state(false, pdMS_TO_TICKS(100)); //Force disconnected state on PHY + test_usb_set_phy_state(false, pdMS_TO_TICKS(100)); // Force disconnected state on PHY test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); - //Power down the port + // Power down the port TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_POWER_OFF)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl)); } @@ -233,7 +233,7 @@ void test_hcd_wait_for_disconn(hcd_port_handle_t port_hdl, bool already_disabled hcd_pipe_handle_t test_hcd_pipe_alloc(hcd_port_handle_t port_hdl, const usb_ep_desc_t *ep_desc, uint8_t dev_addr, usb_speed_t dev_speed) { - //Create a queue for pipe callback to queue up pipe events + // Create a queue for pipe callback to queue up pipe events QueueHandle_t pipe_evt_queue = xQueueCreate(EVENT_QUEUE_LEN, sizeof(pipe_event_msg_t)); TEST_ASSERT_NOT_NULL(pipe_evt_queue); hcd_pipe_config_t pipe_config = { @@ -252,17 +252,17 @@ hcd_pipe_handle_t test_hcd_pipe_alloc(hcd_port_handle_t port_hdl, const usb_ep_d void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl) { - //Get the pipe's event queue from its context variable + // Get the pipe's event queue from its context variable QueueHandle_t pipe_evt_queue = (QueueHandle_t)hcd_pipe_get_context(pipe_hdl); TEST_ASSERT_NOT_NULL(pipe_evt_queue); - //Free the pipe and queue + // Free the pipe and queue TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_free(pipe_hdl)); vQueueDelete(pipe_evt_queue); } urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size) { - //Allocate a URB and data buffer + // Allocate a URB and data buffer urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT); void *data_buffer; size_t real_size; @@ -273,7 +273,7 @@ urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size) TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB"); TEST_ASSERT_NOT_NULL_MESSAGE(data_buffer, "Failed to allocate transfer buffer"); - //Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields + // Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields usb_transfer_dummy_t *transfer_dummy = (usb_transfer_dummy_t *)&urb->transfer; transfer_dummy->data_buffer = data_buffer; transfer_dummy->data_buffer_size = real_size; @@ -283,19 +283,19 @@ urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size) void test_hcd_free_urb(urb_t *urb) { - //Free data buffer of the transfer + // Free data buffer of the transfer heap_caps_free(urb->transfer.data_buffer); - //Free the URB + // Free the URB heap_caps_free(urb); } uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe) { - //We need to create a URB for the enumeration control transfers + // We need to create a URB for the enumeration control transfers urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_setup_packet_t) + 256); usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)urb->transfer.data_buffer; - //Get the device descriptor (note that device might only return 8 bytes) + // Get the device descriptor (note that device might only return 8 bytes) USB_SETUP_PACKET_INIT_GET_DEVICE_DESC(setup_pkt); urb->transfer.num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t); TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); @@ -303,22 +303,22 @@ uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe) TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); - //Update the MPS of the default pipe + // Update the MPS of the default pipe usb_device_desc_t *device_desc = (usb_device_desc_t *)(urb->transfer.data_buffer + sizeof(usb_setup_packet_t)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_mps(default_pipe, device_desc->bMaxPacketSize0)); - //Send a set address request - USB_SETUP_PACKET_INIT_SET_ADDR(setup_pkt, ENUM_ADDR); //We only support one device for now so use address 1 + // Send a set address request + USB_SETUP_PACKET_INIT_SET_ADDR(setup_pkt, ENUM_ADDR); // We only support one device for now so use address 1 urb->transfer.num_bytes = sizeof(usb_setup_packet_t); TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); - //Update address of default pipe + // Update address of default pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_dev_addr(default_pipe, ENUM_ADDR)); - //Send a set configuration request + // Send a set configuration request USB_SETUP_PACKET_INIT_SET_CONFIG(setup_pkt, ENUM_CONFIG); urb->transfer.num_bytes = sizeof(usb_setup_packet_t); TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); @@ -326,7 +326,7 @@ uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe) TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); - //Free URB + // Free URB test_hcd_free_urb(urb); return ENUM_ADDR; } diff --git a/components/usb/test_apps/hcd/main/test_hcd_ctrl.c b/components/usb/test_apps/hcd/main/test_hcd_ctrl.c index 789d8b3c662..75190e41c86 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_ctrl.c +++ b/components/usb/test_apps/hcd/main/test_hcd_ctrl.c @@ -13,7 +13,7 @@ #define TEST_DEV_ADDR 0 #define NUM_URBS 3 #define TRANSFER_MAX_BYTES 256 -#define URB_DATA_BUFF_SIZE (sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors +#define URB_DATA_BUFF_SIZE (sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES) // 256 is worst case size for configuration descriptors /* Test HCD control pipe URBs (normal completion and early abort) @@ -35,36 +35,36 @@ Test HCD control pipe URBs (normal completion and early abort) */ TEST_CASE("Test HCD control pipe URBs", "[ctrl][low_speed][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - //Initialize with a "Get Config Descriptor request" + // Initialize with a "Get Config Descriptor request" urb_list[i]->transfer.num_bytes = sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue URBs but immediately suspend the port + // Enqueue URBs but immediately suspend the port printf("Enqueuing URBs\n"); for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } - //Wait for each done event of each URB + // Wait for each done event of each URB for (int i = 0; i < NUM_URBS; i++) { test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); } - //Dequeue URBs, check, and print + // Dequeue URBs, check, and print for (int i = 0; i < NUM_URBS; i++) { urb_t *urb = hcd_urb_dequeue(default_pipe); TEST_ASSERT_EQUAL(urb_list[i], urb); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); usb_config_desc_t *config_desc = (usb_config_desc_t *)(urb->transfer.data_buffer + sizeof(usb_setup_packet_t)); @@ -72,38 +72,38 @@ TEST_CASE("Test HCD control pipe URBs", "[ctrl][low_speed][full_speed]") printf("Config Desc wTotalLength %d\n", config_desc->wTotalLength); } - //Enqueue URBs again but abort them short after + // Enqueue URBs again but abort them short after for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_abort(urb_list[i])); } - vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for any inflight transfers to complete + vTaskDelay(pdMS_TO_TICKS(100)); // Give some time for any inflight transfers to complete - //Wait for the URBs to complete and dequeue them, then check results - //Dequeue URBs + // Wait for the URBs to complete and dequeue them, then check results + // Dequeue URBs for (int i = 0; i < NUM_URBS; i++) { urb_t *urb = hcd_urb_dequeue(default_pipe); - //No need to check for URB pointer address as they may be out of order + // No need to check for URB pointer address as they may be out of order TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_CANCELED); if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); } else { - //A failed transfer should 0 actual number of bytes transmitted + // A failed transfer should 0 actual number of bytes transmitted TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } TEST_ASSERT_EQUAL(urb->transfer.context, URB_CONTEXT_VAL); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } @@ -130,27 +130,27 @@ Test HCD control pipe STALL condition, abort, and clear */ TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - //Initialize with a "Get Config Descriptor request" + // Initialize with a "Get Config Descriptor request" urb_list[i]->transfer.num_bytes = sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Corrupt the first URB so that it triggers a STALL + // Corrupt the first URB so that it triggers a STALL ((usb_setup_packet_t *)urb_list[0]->transfer.data_buffer)->bRequest = 0xAA; - //Enqueue URBs. A STALL should occur + // Enqueue URBs. A STALL should occur int num_enqueued = 0; for (int i = 0; i < NUM_URBS; i++) { if (hcd_urb_enqueue(default_pipe, urb_list[i]) != ESP_OK) { - //STALL may occur before we are done enqueing + // STALL may occur before we are done enqueuing break; } num_enqueued++; @@ -160,7 +160,7 @@ TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]") test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_ERROR_STALL); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); - //Call the pipe abort command to retire all URBs then dequeue them all + // Call the pipe abort command to retire all URBs then dequeue them all TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_FLUSH)); test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); for (int i = 0; i < num_enqueued; i++) { @@ -168,36 +168,36 @@ TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]") TEST_ASSERT_EQUAL(urb_list[i], urb); TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_STALL || urb->transfer.status == USB_TRANSFER_STATUS_CANCELED); if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); } else { - //A failed transfer should 0 actual number of bytes transmitted + // A failed transfer should 0 actual number of bytes transmitted TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } - //Call the clear command to un-stall the pipe + // Call the clear command to un-stall the pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_CLEAR)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); printf("Retrying\n"); - //Correct first URB then requeue + // Correct first URB then requeue USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[0]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } - //Wait for each URB to be done, deequeue, and check results + // Wait for each URB to be done, deequeue, and check results for (int i = 0; i < NUM_URBS; i++) { test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); - //expect_pipe_event(pipe_evt_queue, default_pipe, HCD_PIPE_EVENT_URB_DONE); + // expect_pipe_event(pipe_evt_queue, default_pipe, HCD_PIPE_EVENT_URB_DONE); urb_t *urb = hcd_urb_dequeue(default_pipe); TEST_ASSERT_EQUAL(urb_list[i], urb); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); usb_config_desc_t *config_desc = (usb_config_desc_t *)(urb->transfer.data_buffer + sizeof(usb_setup_packet_t)); @@ -205,12 +205,12 @@ TEST_CASE("Test HCD control pipe STALL", "[ctrl][full_speed]") printf("Config Desc wTotalLength %d\n", config_desc->wTotalLength); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } @@ -234,21 +234,21 @@ Test control pipe run-time halt and clear */ TEST_CASE("Test HCD control pipe runtime halt and clear", "[ctrl][low_speed][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - //Initialize with a "Get Config Descriptor request" + // Initialize with a "Get Config Descriptor request" urb_list[i]->transfer.num_bytes = sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue URBs but immediately halt the pipe + // Enqueue URBs but immediately halt the pipe printf("Enqueuing URBs\n"); for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); @@ -258,36 +258,36 @@ TEST_CASE("Test HCD control pipe runtime halt and clear", "[ctrl][low_speed][ful TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); printf("Pipe halted\n"); - //Un-halt the pipe + // Un-halt the pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_CLEAR)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); printf("Pipe cleared\n"); - vTaskDelay(pdMS_TO_TICKS(100)); //Give some time pending for transfers to restart and complete + vTaskDelay(pdMS_TO_TICKS(100)); // Give some time pending for transfers to restart and complete - //Wait for each URB to be done, dequeue, and check results + // Wait for each URB to be done, dequeue, and check results for (int i = 0; i < NUM_URBS; i++) { urb_t *urb = hcd_urb_dequeue(default_pipe); TEST_ASSERT_EQUAL_PTR(urb_list[i], urb); TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_CANCELED); if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); usb_config_desc_t *config_desc = (usb_config_desc_t *)(urb->transfer.data_buffer + sizeof(usb_setup_packet_t)); TEST_ASSERT_EQUAL(USB_B_DESCRIPTOR_TYPE_CONFIGURATION, config_desc->bDescriptorType); printf("Config Desc wTotalLength %d\n", config_desc->wTotalLength); } else { - //A failed transfer should 0 actual number of bytes transmitted + // A failed transfer should 0 actual number of bytes transmitted TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } diff --git a/components/usb/test_apps/hcd/main/test_hcd_intr.c b/components/usb/test_apps/hcd/main/test_hcd_intr.c index cf300d26935..7c772c9ee3b 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_intr.c +++ b/components/usb/test_apps/hcd/main/test_hcd_intr.c @@ -8,8 +8,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "unity.h" -#include "test_usb_mock_msc.h" -#include "test_usb_mock_hid.h" +#include "mock_msc.h" +#include "mock_hid.h" #include "test_hcd_common.h" // --------------------------------------------------- Test Cases ------------------------------------------------------ @@ -41,14 +41,14 @@ Note: Some mice will NAK until it is moved, so try moving the mouse around if th TEST_CASE("Test HCD interrupt pipe URBs", "[intr][low_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection TEST_ASSERT_EQUAL_MESSAGE(TEST_HID_DEV_SPEED, port_speed, "Connected device is not Low Speed!"); - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); - //Allocate interrupt pipe and URBS + // Allocate interrupt pipe and URBS hcd_pipe_handle_t intr_pipe = test_hcd_pipe_alloc(port_hdl, &mock_hid_mouse_in_ep_desc, dev_addr, port_speed); urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { @@ -57,31 +57,31 @@ TEST_CASE("Test HCD interrupt pipe URBs", "[intr][low_speed]") urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue URBs + // Enqueue URBs for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(intr_pipe, urb_list[i])); } int iter_count = NUM_URB_ITERS; for (iter_count = NUM_URB_ITERS; iter_count > 0; iter_count--) { - //Wait for an URB to be done + // Wait for an URB to be done test_hcd_expect_pipe_event(intr_pipe, HCD_PIPE_EVENT_URB_DONE); - //Dequeue the URB and check results + // Dequeue the URB and check results urb_t *urb = hcd_urb_dequeue(intr_pipe); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); mock_hid_process_report((mock_hid_mouse_report_t *)urb->transfer.data_buffer, iter_count); - //Requeue URB + // Requeue URB if (iter_count > NUM_URBS) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(intr_pipe, urb)); } } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(intr_pipe); test_hcd_pipe_free(default_pipe); - //Clearnup + // Clearnup test_hcd_wait_for_disconn(port_hdl, false); } diff --git a/components/usb/test_apps/hcd/main/test_hcd_isoc.c b/components/usb/test_apps/hcd/main/test_hcd_isoc.c index aff0440b499..87364c44d1b 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_isoc.c +++ b/components/usb/test_apps/hcd/main/test_hcd_isoc.c @@ -10,7 +10,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "unity.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "test_usb_common.h" #include "test_hcd_common.h" @@ -43,57 +43,57 @@ Test HCD ISOC pipe URBs TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - //The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX)); - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Enumerate and reset device - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Enumerate and reset device + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); - //Create ISOC OUT pipe to non-existent device + // Create ISOC OUT pipe to non-existent device hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_isoc_out_ep_desc, dev_addr + 1, port_speed); - //Create URBs + // Create URBs urb_t *urb_list[NUM_URBS]; - //Initialize URBs + // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, URB_DATA_BUFF_SIZE); urb_list[urb_idx]->transfer.num_bytes = URB_DATA_BUFF_SIZE; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; - //Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) + // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * NUM_URBS) + pkt_idx, ISOC_PACKET_SIZE); } } - //Enqueue URBs + // Enqueue URBs for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(isoc_out_pipe, urb_list[i])); } - //Wait for each done event from each URB + // Wait for each done event from each URB for (int i = 0; i < NUM_URBS; i++) { test_hcd_expect_pipe_event(isoc_out_pipe, HCD_PIPE_EVENT_URB_DONE); } - //Dequeue URBs + // Dequeue URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_t *urb = hcd_urb_dequeue(isoc_out_pipe); TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - //Overall URB status and overall number of bytes + // Overall URB status and overall number of bytes TEST_ASSERT_EQUAL(URB_DATA_BUFF_SIZE, urb->transfer.actual_num_bytes); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.isoc_packet_desc[pkt_idx].status, "Transfer NOT completed"); } } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(isoc_out_pipe); test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } @@ -116,13 +116,13 @@ Test HCD ISOC pipe URBs with all channels and intervals combinations */ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - //The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX)); - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Enumerate and reset device - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Enumerate and reset device + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); urb_t *urb_list[NUM_URBS]; @@ -141,20 +141,20 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") vTaskDelay(5); unsigned num_packets_per_urb = 32; // This is maximum number of packets if interval = 1. This is limited by FRAME_LIST_LEN num_packets_per_urb >>= (interval - 1); - //Create ISOC OUT pipe + // Create ISOC OUT pipe usb_ep_desc_t isoc_out_ep = mock_isoc_out_ep_desc; // Implicit copy isoc_out_ep.bInterval = interval; isoc_out_ep.bEndpointAddress = interval; // So you can see the bInterval value in trace hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &isoc_out_ep, channel + 1, port_speed); // Channel number represented in dev_num, so you can see it in trace - //Initialize URBs + // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_list[urb_idx] = test_hcd_alloc_urb(num_packets_per_urb, num_packets_per_urb * ISOC_PACKET_SIZE); urb_list[urb_idx]->transfer.num_bytes = num_packets_per_urb * ISOC_PACKET_SIZE; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < num_packets_per_urb; pkt_idx++) { urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; - //Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) + // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * num_packets_per_urb) + pkt_idx, ISOC_PACKET_SIZE); } } @@ -162,27 +162,27 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") // Add a delay so we start scheduling the transactions at different time in USB frame esp_rom_delay_us(ENQUEUE_DELAY * interval + ENQUEUE_DELAY * channel); - //Enqueue URBs + // Enqueue URBs for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(isoc_out_pipe, urb_list[i])); } - //Wait for each done event from each URB + // Wait for each done event from each URB for (int i = 0; i < NUM_URBS; i++) { test_hcd_expect_pipe_event(isoc_out_pipe, HCD_PIPE_EVENT_URB_DONE); } - //Dequeue URBs + // Dequeue URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_t *urb = hcd_urb_dequeue(isoc_out_pipe); TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - //Overall URB status and overall number of bytes + // Overall URB status and overall number of bytes TEST_ASSERT_EQUAL(num_packets_per_urb * ISOC_PACKET_SIZE, urb->transfer.actual_num_bytes); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); for (int pkt_idx = 0; pkt_idx < num_packets_per_urb; pkt_idx++) { TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.isoc_packet_desc[pkt_idx].status, "Transfer NOT completed"); } } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } @@ -195,7 +195,7 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") } } test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } @@ -225,65 +225,65 @@ Purpose: Test that when sudden disconnection happens on an HCD port, the ISOC pi */ TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - //The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + // The MPS of the ISOC OUT pipe is quite large, so we need to bias the FIFO sizing TEST_ASSERT_EQUAL(ESP_OK, hcd_port_set_fifo_bias(port_hdl, HCD_PORT_FIFO_BIAS_PTX)); - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Enumerate and reset device - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Enumerate and reset device + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); - //Create ISOC OUT pipe to non-existent device + // Create ISOC OUT pipe to non-existent device hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_isoc_out_ep_desc, dev_addr + 1, port_speed); - //Create URBs + // Create URBs urb_t *urb_list[NUM_URBS]; - //Initialize URBs + // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, URB_DATA_BUFF_SIZE); urb_list[urb_idx]->transfer.num_bytes = URB_DATA_BUFF_SIZE; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; - //Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) + // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * NUM_URBS) + pkt_idx, ISOC_PACKET_SIZE); } } - //Enqueue URBs + // Enqueue URBs for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(isoc_out_pipe, urb_list[i])); } - //Add a short delay to let the transfers run for a bit + // Add a short delay to let the transfers run for a bit esp_rom_delay_us(POST_ENQUEUE_DELAY_US); test_usb_set_phy_state(false, 0); - //Disconnect event should have occurred. Handle the port event + // Disconnect event should have occurred. Handle the port event test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); printf("Sudden disconnect\n"); - //Both pipes should still be active + // Both pipes should still be active TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(isoc_out_pipe)); - //Halt both pipes + // Halt both pipes TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_HALT)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(isoc_out_pipe, HCD_PIPE_CMD_HALT)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(isoc_out_pipe)); - //Flush both pipes. ISOC pipe should return completed URBs + // Flush both pipes. ISOC pipe should return completed URBs TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_FLUSH)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(isoc_out_pipe, HCD_PIPE_CMD_FLUSH)); - //Dequeue ISOC URBs + // Dequeue ISOC URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { urb_t *urb = hcd_urb_dequeue(isoc_out_pipe); TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - //The URB has either completed entirely or is marked as no_device + // The URB has either completed entirely or is marked as no_device TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } diff --git a/components/usb/test_apps/hcd/main/test_hcd_port.c b/components/usb/test_apps/hcd/main/test_hcd_port.c index 3b44623cba7..67f502335b0 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_port.c +++ b/components/usb/test_apps/hcd/main/test_hcd_port.c @@ -15,7 +15,7 @@ #define TEST_DEV_ADDR 0 #define NUM_URBS 3 #define TRANSFER_MAX_BYTES 256 -#define URB_DATA_BUFF_SIZE (sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors +#define URB_DATA_BUFF_SIZE (sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES) // 256 is worst case size for configuration descriptors #define POST_ENQUEUE_DELAY_US 10 /* @@ -43,35 +43,35 @@ Purpose: Test that when sudden disconnection happens on an HCD port, the port wi TEST_CASE("Test HCD port sudden disconnect", "[port][low_speed][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - //Initialize with a "Get Config Descriptor request" + // Initialize with a "Get Config Descriptor request" urb_list[i]->transfer.num_bytes = sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); urb_list[i]->transfer.context = (void *)0xDEADBEEF; } - //Enqueue URBs but immediately trigger a disconnect + // Enqueue URBs but immediately trigger a disconnect printf("Enqueuing URBs\n"); for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } - //Add a short delay to let the transfers run for a bit + // Add a short delay to let the transfers run for a bit esp_rom_delay_us(POST_ENQUEUE_DELAY_US); test_usb_set_phy_state(false, 0); - //Disconnect event should have occurred. Handle the port event + // Disconnect event should have occurred. Handle the port event test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); printf("Sudden disconnect\n"); - //We should be able to halt then flush the pipe + // We should be able to halt then flush the pipe TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_HALT)); printf("Pipe halted\n"); @@ -80,32 +80,32 @@ TEST_CASE("Test HCD port sudden disconnect", "[port][low_speed][full_speed]") test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); printf("Pipe flushed\n"); - //Dequeue URBs + // Dequeue URBs for (int i = 0; i < NUM_URBS; i++) { urb_t *urb = hcd_urb_dequeue(default_pipe); TEST_ASSERT_EQUAL(urb_list[i], urb); TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); } else { - //A failed transfer should 0 actual number of bytes transmitted + // A failed transfer should 0 actual number of bytes transmitted TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } TEST_ASSERT_EQUAL(0xDEADBEEF, urb->transfer.context); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); - //Recover the port should return to the to NOT POWERED state + // Recover the port should return to the to NOT POWERED state TEST_ASSERT_EQUAL(ESP_OK, hcd_port_recover(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_NOT_POWERED, hcd_port_get_state(port_hdl)); - //Recovered port should be able to connect and disconnect again + // Recovered port should be able to connect and disconnect again test_hcd_wait_for_conn(port_hdl); test_hcd_wait_for_disconn(port_hdl, false); } @@ -132,38 +132,38 @@ Test port suspend and resume with active pipes */ TEST_CASE("Test HCD port suspend and resume", "[port][low_speed][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) - //Test that suspending the port now fails as there is an active pipe + // Test that suspending the port now fails as there is an active pipe TEST_ASSERT_NOT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_SUSPEND)); - //Halt the default pipe before suspending + // Halt the default pipe before suspending TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_HALT)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); - //Suspend the port + // Suspend the port TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_SUSPEND)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_SUSPENDED, hcd_port_get_state(port_hdl)); printf("Suspended\n"); - vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for bus to remain suspended + vTaskDelay(pdMS_TO_TICKS(100)); // Give some time for bus to remain suspended - //Resume the port + // Resume the port TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_RESUME)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_ENABLED, hcd_port_get_state(port_hdl)); printf("Resumed\n"); - //Clear the default pipe's halt + // Clear the default pipe's halt TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_CLEAR)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); - vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for resumed URBs to complete + vTaskDelay(pdMS_TO_TICKS(100)); // Give some time for resumed URBs to complete test_hcd_pipe_free(default_pipe); - //Cleanup + // Cleanup test_hcd_wait_for_disconn(port_hdl, false); } @@ -186,65 +186,65 @@ Test HCD port disable and disconnection */ TEST_CASE("Test HCD port disable", "[port][low_speed][full_speed]") { - usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some URBs and initialize their data buffers with control transfers - hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) + // Allocate some URBs and initialize their data buffers with control transfers + hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); // Create a default pipe (using a NULL EP descriptor) urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - //Initialize with a "Get Config Descriptor request" + // Initialize with a "Get Config Descriptor request" urb_list[i]->transfer.num_bytes = sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); urb_list[i]->transfer.context = (void *)0xDEADBEEF; } - //Enqueue URBs but immediately disable the port + // Enqueue URBs but immediately disable the port printf("Enqueuing URBs\n"); for (int i = 0; i < NUM_URBS; i++) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); - //Add a short delay to let the transfers run for a bit + // Add a short delay to let the transfers run for a bit esp_rom_delay_us(POST_ENQUEUE_DELAY_US); } - //Halt the default pipe before suspending + // Halt the default pipe before suspending TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_HALT)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); - //Check that port can be disabled + // Check that port can be disabled TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); printf("Disabled\n"); - //Flush pipe + // Flush pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_FLUSH)); - //Dequeue URBs + // Dequeue URBs for (int i = 0; i < NUM_URBS; i++) { urb_t *urb = hcd_urb_dequeue(default_pipe); TEST_ASSERT_EQUAL(urb_list[i], urb); - TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || //The transfer completed before the pipe halted - urb->transfer.status == USB_TRANSFER_STATUS_CANCELED || //The transfer was stopped mid-way by the halt - urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); //The transfer was never started + TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || // The transfer completed before the pipe halted + urb->transfer.status == USB_TRANSFER_STATUS_CANCELED || // The transfer was stopped mid-way by the halt + urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); // The transfer was never started if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { - //We must have transmitted at least the setup packet, but device may return less than bytes requested + // We must have transmitted at least the setup packet, but device may return less than bytes requested TEST_ASSERT_GREATER_OR_EQUAL(sizeof(usb_setup_packet_t), urb->transfer.actual_num_bytes); TEST_ASSERT_LESS_OR_EQUAL(urb->transfer.num_bytes, urb->transfer.actual_num_bytes); } else { - //A failed transfer should 0 actual number of bytes transmitted + // A failed transfer should 0 actual number of bytes transmitted TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } TEST_ASSERT_EQUAL(0xDEADBEEF, urb->transfer.context); } - //Free URB list and pipe + // Free URB list and pipe for (int i = 0; i < NUM_URBS; i++) { test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); - //Trigger a disconnection and cleanup + // Trigger a disconnection and cleanup test_hcd_wait_for_disconn(port_hdl, true); } @@ -266,40 +266,40 @@ static void concurrent_task(void *arg) { SemaphoreHandle_t sync_sem = (SemaphoreHandle_t) arg; xSemaphoreTake(sync_sem, portMAX_DELAY); - vTaskDelay(pdMS_TO_TICKS(10)); //Give a short delay let reset command start in main thread - //Force a disconnection + vTaskDelay(pdMS_TO_TICKS(10)); // Give a short delay let reset command start in main thread + // Force a disconnection test_usb_set_phy_state(false, 0); - vTaskDelay(portMAX_DELAY); //Block forever and wait to be deleted + vTaskDelay(portMAX_DELAY); // Block forever and wait to be deleted } TEST_CASE("Test HCD port command bailout", "[port][low_speed][full_speed]") { - test_hcd_wait_for_conn(port_hdl); //Trigger a connection - vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) + test_hcd_wait_for_conn(port_hdl); // Trigger a connection + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) - //Create task to run port commands concurrently + // Create task to run port commands concurrently SemaphoreHandle_t sync_sem = xSemaphoreCreateBinary(); TaskHandle_t task_handle; TEST_ASSERT_NOT_NULL(sync_sem); TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(concurrent_task, "tsk", 4096, (void *) sync_sem, uxTaskPriorityGet(NULL) + 1, &task_handle, 0)); - //Suspend the device + // Suspend the device printf("Suspending\n"); TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_SUSPEND)); - vTaskDelay(pdMS_TO_TICKS(20)); //Short delay for device to enter suspend state + vTaskDelay(pdMS_TO_TICKS(20)); // Short delay for device to enter suspend state - //Attempt to resume the port. But the concurrent task should override this with a disconnection event + // Attempt to resume the port. But the concurrent task should override this with a disconnection event printf("Attempting to resume\n"); - xSemaphoreGive(sync_sem); //Trigger concurrent task + xSemaphoreGive(sync_sem); // Trigger concurrent task TEST_ASSERT_EQUAL(ESP_ERR_INVALID_RESPONSE, hcd_port_command(port_hdl, HCD_PORT_CMD_RESUME)); - //Check that concurrent task triggered a sudden disconnection + // Check that concurrent task triggered a sudden disconnection test_hcd_expect_port_event(port_hdl, HCD_PORT_EVENT_DISCONNECTION); TEST_ASSERT_EQUAL(HCD_PORT_EVENT_DISCONNECTION, hcd_port_handle_event(port_hdl)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); - //Cleanup task and semaphore - vTaskDelay(pdMS_TO_TICKS(10)); //Short delay for concurrent task finish running + // Cleanup task and semaphore + vTaskDelay(pdMS_TO_TICKS(10)); // Short delay for concurrent task finish running vTaskDelete(task_handle); vSemaphoreDelete(sync_sem); } diff --git a/components/usb/test_apps/hcd/main/test_usb_helpers.c b/components/usb/test_apps/hcd/main/test_usb_helpers.c index fafe81c0329..742ae56125a 100644 --- a/components/usb/test_apps/hcd/main/test_usb_helpers.c +++ b/components/usb/test_apps/hcd/main/test_usb_helpers.c @@ -333,7 +333,7 @@ static uint8_t config_desc_bytes [] = { }; _Static_assert(sizeof(config_desc_bytes) == 0x0185, "Configuration Descriptor size does not match"); -#define TEST_NUM_INTF_DESC 3 //Total number of interface descriptors (including alternate) +#define TEST_NUM_INTF_DESC 3 // Total number of interface descriptors (including alternate) // --------------------- Sub-Test 1 ------------------------ @@ -348,7 +348,7 @@ static void test_walk_desc(const usb_config_desc_t *config_desc) cur_desc = usb_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset); TEST_ASSERT_NOT_NULL(cur_desc); } - //Attempting to look for another interface descriptor should result in NULL + // Attempting to look for another interface descriptor should result in NULL cur_desc = usb_parse_next_descriptor_of_type(cur_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset); TEST_ASSERT_NULL(cur_desc); } @@ -358,11 +358,11 @@ Test if the count of number of alternate descriptors is correct */ static void test_alt_intf_desc_count(const usb_config_desc_t *config_desc) { - //bInterface 0 has no alternate interfaces + // bInterface 0 has no alternate interfaces TEST_ASSERT_EQUAL(0, usb_parse_interface_number_of_alternate(config_desc, 0)); - //bInterface 1 has 1 alternate interface + // bInterface 1 has 1 alternate interface TEST_ASSERT_EQUAL(1, usb_parse_interface_number_of_alternate(config_desc, 1)); - //Non existent bInterface 2 should return -1 + // Non existent bInterface 2 should return -1 TEST_ASSERT_EQUAL(-1, usb_parse_interface_number_of_alternate(config_desc, 2)); } @@ -370,10 +370,10 @@ static void test_parse_intf_and_ep(const usb_config_desc_t *config_desc) { int offset_intf = 0; - //Get bInterfaceNumber 0 (index 0) + // Get bInterfaceNumber 0 (index 0) const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, 0, 0, &offset_intf); TEST_ASSERT_NOT_NULL(intf_desc); - //Should only have one endpoint + // Should only have one endpoint int offset_ep = offset_intf; const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep); TEST_ASSERT_NOT_NULL(ep_desc); @@ -382,20 +382,20 @@ static void test_parse_intf_and_ep(const usb_config_desc_t *config_desc) ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 1, config_desc->wTotalLength, &offset_ep); TEST_ASSERT_NULL(ep_desc); - //Get bInterfaceNumber 1 alternate setting 0 + // Get bInterfaceNumber 1 alternate setting 0 offset_intf = 0; intf_desc = usb_parse_interface_descriptor(config_desc, 1, 0, &offset_intf); TEST_ASSERT_NOT_NULL(intf_desc); - //Should have no endpoints + // Should have no endpoints offset_ep = offset_intf; ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep); TEST_ASSERT_NULL(ep_desc); - //Get bInterfaceNumber 1 alternate setting 1 + // Get bInterfaceNumber 1 alternate setting 1 offset_intf = 0; intf_desc = usb_parse_interface_descriptor(config_desc, 1, 1, &offset_intf); TEST_ASSERT_NOT_NULL(intf_desc); - //Should only have one endpoint + // Should only have one endpoint offset_ep = offset_intf; ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, 0, config_desc->wTotalLength, &offset_ep); TEST_ASSERT_NOT_NULL(ep_desc); @@ -408,21 +408,21 @@ static void test_parse_intf_and_ep(const usb_config_desc_t *config_desc) static void test_parse_ep_by_address(const usb_config_desc_t *config_desc) { int offset_ep = 0; - //Get bInterface 0 bAlternateSetting 0 EP 0x83 + // Get bInterface 0 bAlternateSetting 0 EP 0x83 const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 0, 0, 0x83, &offset_ep); TEST_ASSERT_NOT_NULL(ep_desc); TEST_ASSERT_EQUAL(0x83, ep_desc->bEndpointAddress); - //Getting same EP address under different interface should return NULL + // Getting same EP address under different interface should return NULL offset_ep = 0; ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 0, 0x83, &offset_ep); TEST_ASSERT_NULL(ep_desc); - //Get bInterface 1 bAlternateSetting 1 EP 0x81 + // Get bInterface 1 bAlternateSetting 1 EP 0x81 offset_ep = 0; ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 1, 0x81, &offset_ep); TEST_ASSERT_NOT_NULL(ep_desc); TEST_ASSERT_EQUAL(0x81, ep_desc->bEndpointAddress); - //Getting same EP address under different interface should return NULL + // Getting same EP address under different interface should return NULL offset_ep = 0; ep_desc = usb_parse_endpoint_descriptor_by_address(config_desc, 1, 0, 0x81, &offset_ep); TEST_ASSERT_NULL(ep_desc); diff --git a/components/usb/test_apps/usb_host/README.md b/components/usb/test_apps/usb_host/README.md index afe40d8da3b..c76482cea32 100644 --- a/components/usb/test_apps/usb_host/README.md +++ b/components/usb/test_apps/usb_host/README.md @@ -7,5 +7,5 @@ There are two sets of tests in this application: 1. Low-speed: Expects low-speed USB mouse with interrupt endpoint to be connected 2. Full-speed: Expects full-speed USB flash disk with 2 bulk endpoints to be connected -For running these tests locally, you will have to update device definitions (VID, PID, ...) in [test_usb_mock_msc.h](../common/test_usb_mock_msc.h) and [test_usb_mock_hid.h](../common/test_usb_mock_hid.h). +For running these tests locally, you will have to update device definitions (VID, PID, ...) in [mock_msc.h](../common/mock_msc.h) and [mock_hid.h](../common/mock_hid.h). diff --git a/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c b/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c index b163dc20fbc..48b0937739f 100644 --- a/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c +++ b/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c @@ -61,7 +61,7 @@ typedef struct { static void ctrl_transfer_cb(usb_transfer_t *transfer) { ctrl_client_obj_t *ctrl_obj = (ctrl_client_obj_t *)transfer->context; - //Check the completed control transfer + // Check the completed control transfer TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(ctrl_obj->config_desc_cached->wTotalLength, transfer->actual_num_bytes - sizeof(usb_setup_packet_t)); ctrl_obj->num_xfer_done++; @@ -82,7 +82,7 @@ static void ctrl_client_event_cb(const usb_host_client_event_msg_t *event_msg, v ctrl_obj->dev_addr_to_open = event_msg->new_dev.address; break; default: - abort(); //Should never occur in this test + abort(); // Should never occur in this test break; } } @@ -94,7 +94,7 @@ void ctrl_client_async_seq_task(void *arg) ctrl_obj.cur_stage = TEST_STAGE_WAIT_CONN; ctrl_obj.next_stage = TEST_STAGE_WAIT_CONN; - //Register client + // Register client usb_host_client_config_t client_config = { .is_synchronous = false, .max_num_event_msg = CTRL_CLIENT_MAX_EVENT_MSGS, @@ -105,7 +105,7 @@ void ctrl_client_async_seq_task(void *arg) }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &ctrl_obj.client_hdl)); - //Allocate transfers + // Allocate transfers usb_transfer_t *ctrl_xfer[NUM_TRANSFER_OBJ] = {NULL}; for (int i = 0; i < NUM_TRANSFER_OBJ; i++) { TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(sizeof(usb_setup_packet_t) + MAX_TRANSFER_BYTES, 0, &ctrl_xfer[i])); @@ -113,7 +113,7 @@ void ctrl_client_async_seq_task(void *arg) ctrl_xfer[i]->context = (void *)&ctrl_obj; } - //Wait to be started by main thread + // Wait to be started by main thread ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(CTRL_CLIENT_TAG, "Starting"); @@ -132,18 +132,18 @@ void ctrl_client_async_seq_task(void *arg) switch (ctrl_obj.next_stage) { case TEST_STAGE_DEV_OPEN: { ESP_LOGD(CTRL_CLIENT_TAG, "Open"); - //Open the device + // Open the device TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_host_device_open(ctrl_obj.client_hdl, ctrl_obj.dev_addr_to_open, &ctrl_obj.dev_hdl), "Failed to open the device"); - //Target our transfers to the device + // Target our transfers to the device for (int i = 0; i < NUM_TRANSFER_OBJ; i++) { ctrl_xfer[i]->device_handle = ctrl_obj.dev_hdl; } - //Check the VID/PID of the opened device + // Check the VID/PID of the opened device const usb_device_desc_t *device_desc; TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(ctrl_obj.dev_hdl, &device_desc)); TEST_ASSERT_EQUAL(ctrl_obj.test_param.idVendor, device_desc->idVendor); TEST_ASSERT_EQUAL(ctrl_obj.test_param.idProduct, device_desc->idProduct); - //Cache the active configuration descriptor for later comparison + // Cache the active configuration descriptor for later comparison TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(ctrl_obj.dev_hdl, &ctrl_obj.config_desc_cached)); ctrl_obj.next_stage = TEST_STAGE_CTRL_XFER; skip_event_handling = true; @@ -151,7 +151,7 @@ void ctrl_client_async_seq_task(void *arg) } case TEST_STAGE_CTRL_XFER: { ESP_LOGD(CTRL_CLIENT_TAG, "Transfer"); - //Send a control transfer to get the device's configuration descriptor + // Send a control transfer to get the device's configuration descriptor usb_transfer_t *transfer = ctrl_xfer[ctrl_obj.num_xfer_sent % NUM_TRANSFER_OBJ]; USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, 0, MAX_TRANSFER_BYTES); transfer->num_bytes = sizeof(usb_setup_packet_t) + MAX_TRANSFER_BYTES; @@ -163,12 +163,12 @@ void ctrl_client_async_seq_task(void *arg) break; } case TEST_STAGE_CTRL_XFER_WAIT: { - //Nothing to do but wait + // Nothing to do but wait break; } case TEST_STAGE_DEV_CLOSE: { ESP_LOGD(CTRL_CLIENT_TAG, "Close"); - vTaskDelay(10); // Give USB Host Lib some time to process all trnsfers + vTaskDelay(10); // Give USB Host Lib some time to process all transfers TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(ctrl_obj.client_hdl, ctrl_obj.dev_hdl)); exit_loop = true; break; @@ -178,7 +178,7 @@ void ctrl_client_async_seq_task(void *arg) break; } } - //Free transfers and deregister client + // Free transfers and deregister client for (int i = 0; i < NUM_TRANSFER_OBJ; i++) { TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(ctrl_xfer[i])); } diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c b/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c index af6bc5435be..b1b43649062 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c @@ -12,7 +12,7 @@ #include "freertos/task.h" #include "esp_err.h" #include "esp_log.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "test_usb_common.h" #include "msc_client.h" #include "usb/usb_host.h" @@ -61,7 +61,7 @@ typedef struct { static void msc_reset_cbw_transfer_cb(usb_transfer_t *transfer) { msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context; - //We expect the reset and CBW transfers to complete with no issues + // We expect the reset and CBW transfers to complete with no issues TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes); switch (msc_obj->cur_stage) { @@ -79,7 +79,7 @@ static void msc_reset_cbw_transfer_cb(usb_transfer_t *transfer) static void msc_data_transfer_cb(usb_transfer_t *transfer) { - //The data stage should have either completed, or failed due to the disconnection. + // The data stage should have either completed, or failed due to the disconnection. TEST_ASSERT(transfer->status == USB_TRANSFER_STATUS_COMPLETED || transfer->status == USB_TRANSFER_STATUS_NO_DEVICE); if (transfer->status == USB_TRANSFER_STATUS_COMPLETED) { TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes); @@ -88,7 +88,7 @@ static void msc_data_transfer_cb(usb_transfer_t *transfer) } msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context; msc_obj->event_count++; - //If all transfers dequeued and device gone event occurred. Go to next stage + // If all transfers dequeued and device gone event occurred. Go to next stage if (msc_obj->event_count >= msc_obj->num_data_transfers + 1) { msc_obj->next_stage = TEST_STAGE_DEV_CLOSE; } @@ -105,13 +105,13 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo break; case USB_HOST_CLIENT_EVENT_DEV_GONE: msc_obj->event_count++; - //If all transfers dequeued and device gone event occurred. Go to next stage + // If all transfers dequeued and device gone event occurred. Go to next stage if (msc_obj->event_count >= msc_obj->num_data_transfers + 1) { msc_obj->next_stage = TEST_STAGE_DEV_CLOSE; } break; default: - abort(); //Should never occur in this test + abort(); // Should never occur in this test break; } } @@ -128,7 +128,7 @@ void msc_client_async_dconn_task(void *arg) msc_obj.num_data_transfers = msc_obj.test_param.num_sectors_per_xfer / MOCK_MSC_SCSI_SECTOR_SIZE; msc_obj.event_count = 0; - //Register client + // Register client usb_host_client_config_t client_config = { .is_synchronous = false, .max_num_event_msg = MSC_ASYNC_CLIENT_MAX_EVENT_MSGS, @@ -139,9 +139,9 @@ void msc_client_async_dconn_task(void *arg) }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl)); - //Allocate transfers - usb_transfer_t *xfer_out; //Must be large enough to contain CBW and MSC reset control transfer - usb_transfer_t *xfer_in[msc_obj.num_data_transfers]; //We manually split the data stage into multiple transfers + // Allocate transfers + usb_transfer_t *xfer_out; // Must be large enough to contain CBW and MSC reset control transfer + usb_transfer_t *xfer_in[msc_obj.num_data_transfers]; // We manually split the data stage into multiple transfers size_t xfer_out_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t)); size_t xfer_in_size = MOCK_MSC_SCSI_SECTOR_SIZE; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(xfer_out_size, 0, &xfer_out)); @@ -151,7 +151,7 @@ void msc_client_async_dconn_task(void *arg) xfer_in[i]->context = (void *)&msc_obj; } - //Wait to be started by main thread + // Wait to be started by main thread ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); @@ -170,43 +170,43 @@ void msc_client_async_dconn_task(void *arg) switch (msc_obj.cur_stage) { case TEST_STAGE_WAIT_CONN: { - //Nothing to do while waiting for connection + // Nothing to do while waiting for connection break; } case TEST_STAGE_DEV_OPEN: { ESP_LOGD(MSC_CLIENT_TAG, "Open"); - //Open the device + // Open the device TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl)); - //Target our transfers to the device + // Target our transfers to the device xfer_out->device_handle = msc_obj.dev_hdl; xfer_out->callback = msc_reset_cbw_transfer_cb; for (int i = 0; i < msc_obj.num_data_transfers; i++) { xfer_in[i]->device_handle = msc_obj.dev_hdl; xfer_in[i]->callback = msc_data_transfer_cb; } - //Check the VID/PID of the opened device + // Check the VID/PID of the opened device const usb_device_desc_t *device_desc; TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); TEST_ASSERT_EQUAL(msc_obj.test_param.idVendor, device_desc->idVendor); TEST_ASSERT_EQUAL(msc_obj.test_param.idProduct, device_desc->idProduct); - //Get device info to get device speed + // Get device info to get device speed usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; - //Claim the MSC interface + // Claim the MSC interface TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); msc_obj.next_stage = TEST_STAGE_MSC_RESET; - skip_event_handling = true; //Need to execute TEST_STAGE_MSC_RESET + skip_event_handling = true; // Need to execute TEST_STAGE_MSC_RESET break; } case TEST_STAGE_MSC_RESET: { ESP_LOGD(MSC_CLIENT_TAG, "MSC Reset"); - //Send an MSC SCSI interface reset + // Send an MSC SCSI interface reset MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, MOCK_MSC_SCSI_INTF_NUMBER); xfer_out->num_bytes = sizeof(usb_setup_packet_t); xfer_out->bEndpointAddress = 0; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_MSC_CBW: { @@ -215,12 +215,12 @@ void msc_client_async_dconn_task(void *arg) xfer_out->num_bytes = sizeof(mock_msc_bulk_cbw_t); xfer_out->bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_out)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_MSC_DATA_DCONN: { ESP_LOGD(MSC_CLIENT_TAG, "Data and disconnect"); - //Setup the Data IN transfers + // Setup the Data IN transfers const int bulk_ep_mps = (msc_obj.dev_speed == USB_SPEED_HIGH) ? MOCK_MSC_SCSI_BULK_EP_MPS_HS : MOCK_MSC_SCSI_BULK_EP_MPS_FS; @@ -228,13 +228,13 @@ void msc_client_async_dconn_task(void *arg) xfer_in[i]->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE, bulk_ep_mps); xfer_in[i]->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; } - //Submit those transfers + // Submit those transfers for (int i = 0; i < msc_obj.num_data_transfers; i++) { TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in[i])); } - //Trigger a disconnect + // Trigger a disconnect test_usb_set_phy_state(false, 0); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_DEV_CLOSE: { @@ -243,9 +243,9 @@ void msc_client_async_dconn_task(void *arg) TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); dconn_iter++; if (dconn_iter < TEST_DCONN_ITERATIONS) { - //Start the next test iteration by going back to TEST_STAGE_WAIT_CONN and reenabling connections + // Start the next test iteration by going back to TEST_STAGE_WAIT_CONN and reenabling connections msc_obj.next_stage = TEST_STAGE_WAIT_CONN; - skip_event_handling = true; //Need to execute TEST_STAGE_WAIT_CONN + skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN test_usb_set_phy_state(true, 0); } else { exit_loop = true; @@ -257,12 +257,12 @@ void msc_client_async_dconn_task(void *arg) break; } } - //Free transfers + // Free transfers TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_out)); for (int i = 0; i < msc_obj.num_data_transfers; i++) { TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_in[i])); } - //Deregister the client + // Deregister the client TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl)); ESP_LOGD(MSC_CLIENT_TAG, "Done"); vTaskDelete(NULL); diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c index 38da2aee239..2d4135515fb 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c @@ -12,7 +12,7 @@ #include "freertos/task.h" #include "esp_err.h" #include "esp_log.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "test_usb_common.h" #include "msc_client.h" #include "usb/usb_host.h" @@ -61,7 +61,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo msc_obj->dev_addr_to_open = event_msg->new_dev.address; break; default: - abort(); //Should never occur in this test + abort(); // Should never occur in this test break; } @@ -94,7 +94,7 @@ void msc_client_async_enum_task(void *arg) msc_obj.dev_addr_to_open = 0; msc_obj.dev_hdl = NULL; - //Register client + // Register client usb_host_client_config_t client_config = { .is_synchronous = false, .max_num_event_msg = MSC_ASYNC_CLIENT_MAX_EVENT_MSGS, @@ -105,7 +105,7 @@ void msc_client_async_enum_task(void *arg) }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl)); - //Wait to be started by main thread + // Wait to be started by main thread ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); @@ -124,49 +124,49 @@ void msc_client_async_enum_task(void *arg) switch (msc_obj.cur_stage) { case TEST_STAGE_WAIT_CONN: { - //Wait for connection, nothing to do + // Wait for connection, nothing to do break; } case TEST_STAGE_DEV_OPEN: { ESP_LOGD(MSC_CLIENT_TAG, "Open"); - //Open the device + // Open the device TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl)); msc_obj.next_stage = TEST_STAGE_CHECK_DEV_DESC; - //Get device info to get device speed + // Get device info to get device speed usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; mock_msc_scsi_init_reference_ep_descriptors(&msc_obj); - skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_DEV_DESC + skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_DEV_DESC break; } case TEST_STAGE_CHECK_DEV_DESC: { - //Check the device descriptor + // Check the device descriptor const usb_device_desc_t *device_desc; const usb_device_desc_t *device_desc_ref = &mock_msc_scsi_dev_desc; TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, device_desc_ref->bLength, "Device descriptors do not match."); msc_obj.next_stage = TEST_STAGE_CHECK_CONFIG_DESC; - skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_CONFIG_DESC + skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_CONFIG_DESC break; } case TEST_STAGE_CHECK_CONFIG_DESC: { - //Check the configuration descriptor + // Check the configuration descriptor const usb_config_desc_t *config_desc; const usb_config_desc_t *config_desc_ref = (const usb_config_desc_t *)mock_msc_scsi_config_desc; TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(msc_obj.dev_hdl, &config_desc)); - TEST_ASSERT_EQUAL_MESSAGE(config_desc_ref->wTotalLength, config_desc->wTotalLength, "Incorrent length of CFG descriptor"); + TEST_ASSERT_EQUAL_MESSAGE(config_desc_ref->wTotalLength, config_desc->wTotalLength, "Incorrect length of CFG descriptor"); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(config_desc_ref, config_desc, config_desc_ref->wTotalLength, "Configuration descriptors do not match"); msc_obj.next_stage = TEST_STAGE_CHECK_STR_DESC; - skip_event_handling = true; //Need to execute TEST_STAGE_CHECK_STR_DESC + skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_STR_DESC break; } case TEST_STAGE_CHECK_STR_DESC: { usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); - //Check manufacturer string descriptors + // Check manufacturer string descriptors const usb_str_desc_t *manu_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_manu; const usb_str_desc_t *product_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_prod; const usb_str_desc_t *ser_num_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_ser_num; @@ -175,10 +175,10 @@ void msc_client_async_enum_task(void *arg) TEST_ASSERT_EQUAL(ser_num_str_desc_ref->bLength, dev_info.str_desc_serial_num->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(manu_str_desc_ref, dev_info.str_desc_manufacturer, manu_str_desc_ref->bLength, "Manufacturer string descriptors do not match."); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(product_str_desc_ref, dev_info.str_desc_product, manu_str_desc_ref->bLength, "Product string descriptors do not match."); - //TEST_ASSERT_EQUAL_MEMORY_MESSAGE(ser_num_str_desc_ref, dev_info.str_desc_serial_num , manu_str_desc_ref->bLength, "Serial number string descriptors do not match."); - //Get dev info and compare + // TEST_ASSERT_EQUAL_MEMORY_MESSAGE(ser_num_str_desc_ref, dev_info.str_desc_serial_num , manu_str_desc_ref->bLength, "Serial number string descriptors do not match."); + // Get dev info and compare msc_obj.next_stage = TEST_STAGE_DEV_CLOSE; - skip_event_handling = true; //Need to execute TEST_STAGE_DEV_CLOSE + skip_event_handling = true; // Need to execute TEST_STAGE_DEV_CLOSE break; } @@ -187,11 +187,11 @@ void msc_client_async_enum_task(void *arg) TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); enum_iter++; if (enum_iter < TEST_ENUM_ITERATIONS) { - //Start the next test iteration by disconnecting the device, then going back to TEST_STAGE_WAIT_CONN stage + // Start the next test iteration by disconnecting the device, then going back to TEST_STAGE_WAIT_CONN stage test_usb_set_phy_state(false, 0); test_usb_set_phy_state(true, 0); msc_obj.next_stage = TEST_STAGE_WAIT_CONN; - skip_event_handling = true; //Need to execute TEST_STAGE_WAIT_CONN + skip_event_handling = true; // Need to execute TEST_STAGE_WAIT_CONN } else { exit_loop = true; } @@ -202,7 +202,7 @@ void msc_client_async_enum_task(void *arg) break; } } - //Free transfers and deregister the client + // Free transfers and deregister the client TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl)); ESP_LOGD(MSC_CLIENT_TAG, "Done"); vTaskDelete(NULL); diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_seq.c b/components/usb/test_apps/usb_host/main/msc_client_async_seq.c index 69187ea583f..7bb41f3919b 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_seq.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_seq.c @@ -13,7 +13,7 @@ #include "esp_err.h" #include "esp_log.h" #include "test_usb_common.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "msc_client.h" #include "usb/usb_host.h" #include "unity.h" @@ -61,28 +61,28 @@ static void msc_transfer_cb(usb_transfer_t *transfer) msc_client_obj_t *msc_obj = (msc_client_obj_t *)transfer->context; switch (msc_obj->cur_stage) { case TEST_STAGE_MSC_RESET: { - //Check MSC SCSI interface reset + // Check MSC SCSI interface reset TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(transfer->num_bytes, transfer->actual_num_bytes); msc_obj->next_stage = TEST_STAGE_MSC_CBW; break; } case TEST_STAGE_MSC_CBW: { - //Check MSC SCSI CBW transfer + // Check MSC SCSI CBW transfer TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(sizeof(mock_msc_bulk_cbw_t), transfer->actual_num_bytes); msc_obj->next_stage = TEST_STAGE_MSC_DATA; break; } case TEST_STAGE_MSC_DATA: { - //Check MSC SCSI data IN transfer + // Check MSC SCSI data IN transfer TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj->test_param.num_sectors_per_xfer, transfer->actual_num_bytes); msc_obj->next_stage = TEST_STAGE_MSC_CSW; break; } case TEST_STAGE_MSC_CSW: { - //Check MSC SCSI CSW transfer + // Check MSC SCSI CSW transfer TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); TEST_ASSERT_TRUE(mock_msc_scsi_check_csw((mock_msc_bulk_csw_t *)transfer->data_buffer, msc_obj->test_param.msc_scsi_xfer_tag)); msc_obj->num_sectors_read += msc_obj->test_param.num_sectors_per_xfer; @@ -110,7 +110,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo msc_obj->dev_addr_to_open = event_msg->new_dev.address; break; default: - abort(); //Should never occur in this test + abort(); // Should never occur in this test break; } @@ -127,7 +127,7 @@ void msc_client_async_seq_task(void *arg) msc_obj.dev_hdl = NULL; msc_obj.num_sectors_read = 0; - //Register client + // Register client usb_host_client_config_t client_config = { .is_synchronous = false, .max_num_event_msg = MSC_ASYNC_CLIENT_MAX_EVENT_MSGS, @@ -138,9 +138,9 @@ void msc_client_async_seq_task(void *arg) }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl)); - //Allocate transfers - usb_transfer_t *xfer_out = NULL; //Must be large enough to contain CBW and MSC reset control transfer - usb_transfer_t *xfer_in = NULL; //Must be large enough to contain CSW and Data + // Allocate transfers + usb_transfer_t *xfer_out = NULL; // Must be large enough to contain CBW and MSC reset control transfer + usb_transfer_t *xfer_in = NULL; // Must be large enough to contain CSW and Data size_t out_worst_case_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t)); size_t in_worst_case_size = usb_round_up_to_mps(MAX(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, sizeof(mock_msc_bulk_csw_t)), MOCK_MSC_SCSI_BULK_EP_MPS_HS); TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(out_worst_case_size, 0, &xfer_out)); @@ -150,7 +150,7 @@ void msc_client_async_seq_task(void *arg) xfer_out->context = (void *)&msc_obj; xfer_in->context = (void *)&msc_obj; - //Wait to be started by main thread + // Wait to be started by main thread ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ESP_LOGD(MSC_CLIENT_TAG, "Starting"); @@ -169,36 +169,36 @@ void msc_client_async_seq_task(void *arg) switch (msc_obj.cur_stage) { case TEST_STAGE_DEV_OPEN: { ESP_LOGD(MSC_CLIENT_TAG, "Open"); - //Open the device + // Open the device TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl)); - //Target our transfers to the device + // Target our transfers to the device xfer_out->device_handle = msc_obj.dev_hdl; xfer_in->device_handle = msc_obj.dev_hdl; - //Check the VID/PID of the opened device + // Check the VID/PID of the opened device const usb_device_desc_t *device_desc; TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); TEST_ASSERT_EQUAL(msc_obj.test_param.idVendor, device_desc->idVendor); TEST_ASSERT_EQUAL(msc_obj.test_param.idProduct, device_desc->idProduct); - //Get device info to get device speed + // Get device info to get device speed usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; - //Claim the MSC interface + // Claim the MSC interface TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); msc_obj.next_stage = TEST_STAGE_MSC_RESET; - skip_event_handling = true; //Need to execute TEST_STAGE_MSC_RESET + skip_event_handling = true; // Need to execute TEST_STAGE_MSC_RESET break; } case TEST_STAGE_MSC_RESET: { ESP_LOGD(MSC_CLIENT_TAG, "MSC Reset"); - //Send an MSC SCSI interface reset + // Send an MSC SCSI interface reset MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, MOCK_MSC_SCSI_INTF_NUMBER); xfer_out->num_bytes = sizeof(usb_setup_packet_t); xfer_out->bEndpointAddress = 0; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out)); - //Test that an inflight control transfer cannot be resubmitted + // Test that an inflight control transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_MSC_CBW: { @@ -207,9 +207,9 @@ void msc_client_async_seq_task(void *arg) xfer_out->num_bytes = sizeof(mock_msc_bulk_cbw_t); xfer_out->bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_out)); - //Test that an inflight transfer cannot be resubmitted + // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_out)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_MSC_DATA: { @@ -220,9 +220,9 @@ void msc_client_async_seq_task(void *arg) xfer_in->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, bulk_ep_mps); xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in)); - //Test that an inflight transfer cannot be resubmitted + // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_in)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_MSC_CSW: { @@ -233,9 +233,9 @@ void msc_client_async_seq_task(void *arg) xfer_in->num_bytes = usb_round_up_to_mps(sizeof(mock_msc_bulk_csw_t), bulk_ep_mps); xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in)); - //Test that an inflight transfer cannot be resubmitted + // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_in)); - //Next stage set from transfer callback + // Next stage set from transfer callback break; } case TEST_STAGE_DEV_CLOSE: { @@ -250,7 +250,7 @@ void msc_client_async_seq_task(void *arg) break; } } - //Free transfers and deregister the client + // Free transfers and deregister the client TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_out)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_free(xfer_in)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(msc_obj.client_hdl)); diff --git a/components/usb/test_apps/usb_host/main/test_app_main.c b/components/usb/test_apps/usb_host/main/test_app_main.c index 6a236335954..3301425ab1e 100644 --- a/components/usb/test_apps/usb_host/main/test_app_main.c +++ b/components/usb/test_apps/usb_host/main/test_app_main.c @@ -11,17 +11,17 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "test_usb_common.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "usb/usb_host.h" void setUp(void) { mock_msc_scsi_init_reference_descriptors(); unity_utils_record_free_mem(); - test_usb_init_phy(); //Initialize the internal USB PHY and USB Controller for testing - //Install USB Host + test_usb_init_phy(); // Initialize the internal USB PHY and USB Controller for testing + // Install USB Host usb_host_config_t host_config = { - .skip_phy_setup = true, //test_usb_init_phy() will already have setup the internal USB PHY for us + .skip_phy_setup = true, // test_usb_init_phy() will already have setup the internal USB PHY for us .intr_flags = ESP_INTR_FLAG_LEVEL1, }; ESP_ERROR_CHECK(usb_host_install(&host_config)); @@ -30,11 +30,11 @@ void setUp(void) void tearDown(void) { - //Short delay to allow task to be cleaned up + // Short delay to allow task to be cleaned up vTaskDelay(10); - //Clean up USB Host + // Clean up USB Host ESP_ERROR_CHECK(usb_host_uninstall()); - test_usb_deinit_phy(); //Deinitialize the internal USB PHY after testing + test_usb_deinit_phy(); // Deinitialize the internal USB PHY after testing unity_utils_evaluate_leaks(); } diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_async.c b/components/usb/test_apps/usb_host/main/test_usb_host_async.c index 98b978acf9d..b132bcfc84b 100644 --- a/components/usb/test_apps/usb_host/main/test_usb_host_async.c +++ b/components/usb/test_apps/usb_host/main/test_usb_host_async.c @@ -11,7 +11,7 @@ #include "esp_err.h" #include "esp_intr_alloc.h" #include "test_usb_common.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "msc_client.h" #include "ctrl_client.h" #include "usb/usb_host.h" @@ -46,7 +46,7 @@ Requires: This test requires an MSC SCSI device to be attached (see the MSC mock TEST_CASE("Test USB Host async client (single client)", "[usb_host][full_speed][high_speed]") { - //Create task to run client that communicates with MSC SCSI interface + // Create task to run client that communicates with MSC SCSI interface msc_client_test_param_t params = { .num_sectors_to_read = TEST_MSC_NUM_SECTORS_TOTAL, .num_sectors_per_xfer = TEST_MSC_NUM_SECTORS_PER_XFER, @@ -57,11 +57,11 @@ TEST_CASE("Test USB Host async client (single client)", "[usb_host][full_speed][ TaskHandle_t task_hdl; xTaskCreatePinnedToCore(msc_client_async_seq_task, "async", 4096, (void *)¶ms, 2, &task_hdl, 0); TEST_ASSERT_NOT_NULL_MESSAGE(task_hdl, "Failed to create async task"); - //Start the task + // Start the task xTaskNotifyGive(task_hdl); while (1) { - //Start handling system events + // Start handling system events uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { @@ -96,7 +96,7 @@ Requires: This test requires an MSC SCSI device to be attached (see the MSC mock */ TEST_CASE("Test USB Host async client (multi client)", "[usb_host][full_speed][high_speed]") { - //Create task to run the MSC client + // Create task to run the MSC client msc_client_test_param_t msc_params = { .num_sectors_to_read = TEST_MSC_NUM_SECTORS_TOTAL, .num_sectors_per_xfer = TEST_MSC_NUM_SECTORS_PER_XFER, @@ -108,7 +108,7 @@ TEST_CASE("Test USB Host async client (multi client)", "[usb_host][full_speed][h xTaskCreatePinnedToCore(msc_client_async_seq_task, "msc", 4096, (void *)&msc_params, 2, &msc_task_hdl, 0); TEST_ASSERT_NOT_NULL_MESSAGE(msc_task_hdl, "Failed to create MSC task"); - //Create task a control transfer client + // Create task a control transfer client ctrl_client_test_param_t ctrl_params = { .num_ctrl_xfer_to_send = TEST_CTRL_NUM_TRANSFERS, .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, @@ -118,12 +118,12 @@ TEST_CASE("Test USB Host async client (multi client)", "[usb_host][full_speed][h xTaskCreatePinnedToCore(ctrl_client_async_seq_task, "ctrl", 4096, (void *)&ctrl_params, 2, &ctrl_task_hdl, 0); TEST_ASSERT_NOT_NULL_MESSAGE(ctrl_task_hdl, "Failed to create CTRL task"); - //Start both tasks + // Start both tasks xTaskNotifyGive(msc_task_hdl); xTaskNotifyGive(ctrl_task_hdl); while (1) { - //Start handling system events + // Start handling system events uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { @@ -188,7 +188,7 @@ static void test_async_client_cb(const usb_host_client_event_msg_t *event_msg, v TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") { - //Register two clients + // Register two clients client_test_stage_t client0_stage = CLIENT_TEST_STAGE_NONE; client_test_stage_t client1_stage = CLIENT_TEST_STAGE_NONE; @@ -206,7 +206,7 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") client_config.async.callback_arg = (void *)&client1_stage; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &client1_hdl)); - //Wait until the device connects and the clients receive the event + // Wait until the device connects and the clients receive the event while (!(client0_stage == CLIENT_TEST_STAGE_CONN && client1_stage == CLIENT_TEST_STAGE_CONN)) { usb_host_lib_handle_events(0, NULL); usb_host_client_handle_events(client0_hdl, 0); @@ -214,35 +214,35 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") vTaskDelay(pdMS_TO_TICKS(10)); } - //Check that both clients can open the device + // Check that both clients can open the device TEST_ASSERT_NOT_EQUAL(0, dev_addr); usb_device_handle_t client0_dev_hdl; usb_device_handle_t client1_dev_hdl; printf("Opening device\n"); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, dev_addr, &client0_dev_hdl)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(client1_hdl, dev_addr, &client1_dev_hdl)); - TEST_ASSERT_EQUAL_PTR(client0_dev_hdl, client1_dev_hdl); //Check that its the same device - //Check that a client cannot open a non-existent device + TEST_ASSERT_EQUAL_PTR(client0_dev_hdl, client1_dev_hdl); // Check that its the same device + // Check that a client cannot open a non-existent device TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, 0, &client0_dev_hdl)); - //Check that the device cannot be opened again by the same client + // Check that the device cannot be opened again by the same client usb_device_handle_t dummy_dev_hdl; TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, dev_addr, &dummy_dev_hdl)); TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client1_hdl, dev_addr, &dummy_dev_hdl)); printf("Claiming interface\n"); - //Check that both clients cannot claim the same interface + // Check that both clients cannot claim the same interface TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client1_hdl, client1_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); - //Check that client0 cannot claim the same interface multiple times + // Check that client0 cannot claim the same interface multiple times TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); printf("Releasing interface\n"); - //Check that client0 can release the interface + // Check that client0 can release the interface TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); - //Check that client0 cannot release interface it has not claimed + // Check that client0 cannot release interface it has not claimed TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); - //Wait until the device disconnects and the clients receive the event + // Wait until the device disconnects and the clients receive the event test_usb_set_phy_state(false, 0); while (!(client0_stage == CLIENT_TEST_STAGE_DCONN && client1_stage == CLIENT_TEST_STAGE_DCONN)) { usb_host_lib_handle_events(0, NULL); @@ -254,7 +254,7 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(client0_hdl, client0_dev_hdl)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(client1_hdl, client1_dev_hdl)); - //Deregister the clients + // Deregister the clients TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(client0_hdl)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(client1_hdl)); diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c b/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c index 5851988f421..6be17aa848a 100644 --- a/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c +++ b/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c @@ -10,7 +10,7 @@ #include "esp_err.h" #include "esp_intr_alloc.h" #include "test_usb_common.h" -#include "test_usb_mock_msc.h" +#include "mock_msc.h" #include "msc_client.h" #include "ctrl_client.h" #include "usb/usb_host.h" @@ -38,24 +38,24 @@ TEST_CASE("Test USB Host sudden disconnection (no client)", "[usb_host][full_spe bool connected = false; int dconn_iter = 0; while (1) { - //Start handling system events + // Start handling system events uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); if (!connected) { usb_host_lib_info_t lib_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_lib_info(&lib_info)); if (lib_info.num_devices == 1) { - //We've just connected. Trigger a disconnect + // We've just connected. Trigger a disconnect connected = true; printf("Forcing Sudden Disconnect\n"); test_usb_set_phy_state(false, 0); } } if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { - //The device has disconnected and it's disconnection has been handled + // The device has disconnected and it's disconnection has been handled printf("Dconn iter %d done\n", dconn_iter); if (++dconn_iter < TEST_DCONN_NO_CLIENT_ITERATIONS) { - //Start next iteration + // Start next iteration connected = false; test_usb_set_phy_state(true, 0); } else { @@ -83,9 +83,9 @@ Test USB Host Library Sudden Disconnection Handling (with client) TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][full_speed]") { - //Create task to run client that communicates with MSC SCSI interface + // Create task to run client that communicates with MSC SCSI interface msc_client_test_param_t params = { - .num_sectors_to_read = 1, //Unused by disconnect MSC client + .num_sectors_to_read = 1, // Unused by disconnect MSC client .num_sectors_per_xfer = TEST_FORCE_DCONN_NUM_TRANSFERS * MOCK_MSC_SCSI_SECTOR_SIZE, .msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG, .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, @@ -93,13 +93,13 @@ TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][full }; TaskHandle_t task_hdl; xTaskCreatePinnedToCore(msc_client_async_dconn_task, "async", 4096, (void *)¶ms, 2, &task_hdl, 0); - //Start the task + // Start the task xTaskNotifyGive(task_hdl); bool all_clients_gone = false; bool all_dev_free = false; while (!all_clients_gone || !all_dev_free) { - //Start handling system events + // Start handling system events uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { @@ -133,16 +133,16 @@ Test USB Host Library Enumeration TEST_CASE("Test USB Host enumeration", "[usb_host][full_speed]") { - //Create task to run client that checks the enumeration of the device + // Create task to run client that checks the enumeration of the device TaskHandle_t task_hdl; xTaskCreatePinnedToCore(msc_client_async_enum_task, "async", 6144, NULL, 2, &task_hdl, 0); - //Start the task + // Start the task xTaskNotifyGive(task_hdl); bool all_clients_gone = false; bool all_dev_free = false; while (!all_clients_gone || !all_dev_free) { - //Start handling system events + // Start handling system events uint32_t event_flags; usb_host_lib_handle_events(portMAX_DELAY, &event_flags); if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { From 7f61f74aa0ea0c4ae8a79bcaa1727a591ad142eb Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 8 May 2024 02:56:16 +0800 Subject: [PATCH 197/548] refactor(usb): Split test device descriptors from mock class files Previously, descriptors of the test devices were stored direclty in the mock device files (e.g., "mock_[hid|msc].[h|c]"). This commit splits out the device descriptors to separate files (e.g., "dev_[hid|msc].c") along with getter functions. Users that want to run the tests locally on a different device simply need to update the "dev_[hid|msc].c" file for their device. --- .../usb/test_apps/common/CMakeLists.txt | 4 +- components/usb/test_apps/common/dev_hid.c | 232 ++++++++++++ components/usb/test_apps/common/dev_hid.h | 80 ++++ components/usb/test_apps/common/dev_isoc.c | 27 ++ components/usb/test_apps/common/dev_isoc.h | 36 ++ components/usb/test_apps/common/dev_msc.c | 354 ++++++++++++++++++ components/usb/test_apps/common/dev_msc.h | 118 ++++++ components/usb/test_apps/common/mock_hid.c | 42 --- components/usb/test_apps/common/mock_hid.h | 112 ------ components/usb/test_apps/common/mock_msc.c | 131 +------ components/usb/test_apps/common/mock_msc.h | 140 +------ .../usb/test_apps/hcd/main/test_app_main.c | 5 +- .../usb/test_apps/hcd/main/test_hcd_bulk.c | 28 +- .../usb/test_apps/hcd/main/test_hcd_common.c | 11 - .../usb/test_apps/hcd/main/test_hcd_intr.c | 17 +- .../usb/test_apps/hcd/main/test_hcd_isoc.c | 48 +-- .../usb/test_apps/usb_host/main/ctrl_client.h | 2 - .../usb_host/main/ctrl_client_async_seq.c | 29 +- .../usb/test_apps/usb_host/main/msc_client.h | 2 - .../usb_host/main/msc_client_async_dconn.c | 71 ++-- .../usb_host/main/msc_client_async_enum.c | 36 +- .../usb_host/main/msc_client_async_seq.c | 114 +++--- .../test_apps/usb_host/main/test_app_main.c | 7 +- .../usb_host/main/test_usb_host_async.c | 34 +- .../usb_host/main/test_usb_host_plugging.c | 8 +- 25 files changed, 1107 insertions(+), 581 deletions(-) create mode 100644 components/usb/test_apps/common/dev_hid.c create mode 100644 components/usb/test_apps/common/dev_hid.h create mode 100644 components/usb/test_apps/common/dev_isoc.c create mode 100644 components/usb/test_apps/common/dev_isoc.h create mode 100644 components/usb/test_apps/common/dev_msc.c create mode 100644 components/usb/test_apps/common/dev_msc.h delete mode 100644 components/usb/test_apps/common/mock_hid.c delete mode 100644 components/usb/test_apps/common/mock_hid.h diff --git a/components/usb/test_apps/common/CMakeLists.txt b/components/usb/test_apps/common/CMakeLists.txt index ce2bfb32b3a..047989446da 100644 --- a/components/usb/test_apps/common/CMakeLists.txt +++ b/components/usb/test_apps/common/CMakeLists.txt @@ -1,4 +1,6 @@ -idf_component_register(SRCS "mock_hid.c" +idf_component_register(SRCS "dev_hid.c" + "dev_isoc.c" + "dev_msc.c" "mock_msc.c" "test_usb_common.c" INCLUDE_DIRS "." diff --git a/components/usb/test_apps/common/dev_hid.c b/components/usb/test_apps/common/dev_hid.c new file mode 100644 index 00000000000..91d52a67b7c --- /dev/null +++ b/components/usb/test_apps/common/dev_hid.c @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_types_ch9.h" +#include "usb/usb_types_stack.h" +#include "dev_hid.h" + +/* +Some tests where the ESP (acting as host) will require that a particular test +device acting as an HID mouse be connected. That test device's information and descriptors are defined in this file. + +If you are connecting a different HID mouse, please update the descriptor and +getter functions accordingly. + +------------------------------ Device Descriptor ------------------------------- +bLength : 0x12 (18 bytes) +bDescriptorType : 0x01 (Device Descriptor) +bcdUSB : 0x0210 (2.00) +bDeviceClass : 0x00 +bDeviceSubClass : 0x00 +bDeviceProtocol : 0x00 +bMaxPacketSize0 : 0x08 (8 bytes) +idVendor : 0x413C (Dell Computer Corp) +idProduct : 0x301A (Dell MS116 Optical Mouse) +bcdDevice : 0x0100 (1.00) +iManufacturer : 1 +iProduct : 2 +iSerial : 0 +bNumConfigurations : 1 + +--------------------------- Configuration Descriptor --------------------------- +bLength : 0x09 (9 bytes) +bDescriptorType : 0x02 (Configuration Descriptor) +wTotalLength : 0x0022 (34 bytes) +bNumInterfaces : 0x01 (1 Interface) +bConfigurationValue : 0x01 (Configuration 1) +iConfiguration : 0x00 (No String Descriptor) +bmAttributes : 0xA0 + D7: Reserved, set 1 : 0x01 + D6: Self Powered : 0x00 (no) + D5: Remote Wakeup : 0x01 (yes) + D4..0: Reserved, set 0 : 0x00 +MaxPower : 0x32 (100 mA) + +Data (HexDump) : 09 02 3B 00 02 01 00 A0 32 09 04 00 00 01 03 01 + 02 00 09 21 00 02 00 01 22 4D 00 07 05 81 03 08 + 00 0A 09 04 01 00 01 03 01 01 00 09 21 00 02 00 + 01 22 31 00 07 05 82 03 08 00 0A + +----------------------------- Interface Descriptor ----------------------------- +bLength : 0x09 (9 bytes) +bDescriptorType : 0x04 (Interface Descriptor) +bInterfaceNumber : 0x00 +bAlternateSetting : 0x00 +bNumEndpoints : 0x01 (1 Endpoint) +bInterfaceClass : 0x03 (HID - Human Interface Device) +bInterfaceSubClass : 0x01 (Boot Interface) +bInterfaceProtocol : 0x02 (Mouse) +iInterface : 0x00 (No String Descriptor) + +-------------------------------- HID Descriptor -------------------------------- +bLength : 0x09 (9 bytes) +bDescriptorType : 0x21 (HID Descriptor) +bcdHID : 0x0200 (HID Version 2.00) +bCountryCode : 0x00 (00 = not localized) +bNumDescriptors : 0x01 +Descriptor 1: +bDescriptorType : 0x22 (Class=Report) +wDescriptorLength : 0x004D (77 bytes) + +------------------------------ Endpoint Descriptor ----------------------------- +bLength : 0x07 (7 bytes) +bDescriptorType : 0x05 (Endpoint Descriptor) +bEndpointAddress : 0x81 (Direction=IN EndpointID=1) +bmAttributes : 0x03 (TransferType=Interrupt) +wMaxPacketSize : 0x0008 +bInterval : 0x0A (10 ms) + +---------------------------- String Descriptor Manu ---------------------------- +bLength : 0x0E (14 bytes) +bDescriptorType : 0x03 (String Descriptor) +wData : "PixArt" + +---------------------------- String Descriptor Prod ---------------------------- +bLength : 0x3A (58 bytes) +bDescriptorType : 0x03 (String Descriptor) +wData : "Dell MS116 USB Optical Mouse" +*/ + +// ------------------------------- Descriptors --------------------------------- + +static const usb_device_desc_t dev_desc = { + .bLength = USB_DEVICE_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_DEVICE, + .bcdUSB = 0x0210, // 2.10 + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x413C, // Dell Computer Corp + .idProduct = 0x301A, // Dell MS116 Optical Mouse + .bcdDevice = 0x0100, // 1.00 + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 0, + .bNumConfigurations = 1, +}; + +static const usb_config_desc_t config_desc = { + .bLength = USB_CONFIG_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = 0x0022, // 34 bytes + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0xA0, + .bMaxPower = 0x32, // 100 mA +}; + +static const usb_intf_desc_t intf_desc = { + .bLength = USB_INTF_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 0x01, // Boot Interface + .bInterfaceProtocol = 0x02, // Mouse + .iInterface = 0, // (No String Descriptor) +}; + +const usb_ep_desc_t in_ep_desc = { + .bLength = USB_EP_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x81, // EP 1 IN + .bmAttributes = USB_BM_ATTRIBUTES_XFER_INT, + .wMaxPacketSize = 0x0008, + .bInterval = 0x0A, // 10 ms +}; + +/* +String descriptors are dynamically initialized due to issues with static +initialization of variable length array members. See IDF-9886. +*/ + +static const usb_str_desc_t str_desc_manu_base = { + .bLength = sizeof(usb_str_desc_t) + (6 * sizeof(uint16_t)), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_STRING, +}; +static const uint16_t str_desc_manu_data[] = { + 0x0050, // 'P' + 0x0069, // 'i' + 0x0078, // 'x' + 0x0041, // 'A' + 0x0072, // 'r' + 0x0074, // 't' +}; +static uint8_t *str_desc_manu[sizeof(str_desc_manu_base) + sizeof(str_desc_manu_data)]; + +static const usb_str_desc_t str_desc_prod_base = { + .bLength = sizeof(usb_str_desc_t) + (28 * sizeof(uint16_t)), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_STRING, +}; +static const uint16_t str_desc_prod_data[] = { + /* + The following string encoded in UTF-16LE + + "Dell MS116 USB Optical Mouse" + */ + 0x0044, 0x0065, 0x006c, 0x006c, 0x0020, 0x004d, 0x0053, 0x0031, 0x0031, + 0x0036, 0x0020, 0x0055, 0x0053, 0x0042, 0x0020, 0x004f, 0x0070, 0x0074, + 0x0069, 0x0063, 0x0061, 0x006c, 0x0020, 0x004d, 0x006f, 0x0075, 0x0073, + 0x0065, +}; +static uint8_t *str_desc_prod[sizeof(str_desc_prod_base) + sizeof(str_desc_prod_data)]; + +// -------------------------------- Functions ---------------------------------- + +void dev_hid_init(void) +{ + // Dynamically initialize string descriptors due to compiler limitations (see IDF-9886) + uint8_t *ptr; + + // Initialize manufacturer string descriptor + ptr = (uint8_t *)str_desc_manu; + memcpy(ptr, &str_desc_manu_base, sizeof(str_desc_manu_base)); + ptr += sizeof(str_desc_manu_base); + memcpy(ptr, &str_desc_manu_data, sizeof(str_desc_manu_data)); + + // Initialize product string descriptor + ptr = (uint8_t *)str_desc_prod; + memcpy(ptr, &str_desc_prod_base, sizeof(str_desc_prod_base)); + ptr += sizeof(str_desc_prod_base); + memcpy(ptr, &str_desc_prod_data, sizeof(str_desc_prod_data)); + + // No serial string descriptor +} + +const usb_device_desc_t *dev_hid_get_dev_desc(usb_speed_t speed) +{ + return &dev_desc; +} + +const usb_config_desc_t *dev_hid_get_config_desc(usb_speed_t speed) +{ + return &config_desc; +} + +const usb_intf_desc_t *dev_hid_get_intf_desc(usb_speed_t speed) +{ + return &intf_desc; +} + +const usb_ep_desc_t *dev_hid_get_in_ep_desc(usb_speed_t speed) +{ + return &in_ep_desc; +} + +const usb_str_desc_t *dev_hid_get_str_desc_manu(void) +{ + return (const usb_str_desc_t *)str_desc_manu; +} + +const usb_str_desc_t *dev_hid_get_str_desc_prod(void) +{ + return (const usb_str_desc_t *)str_desc_prod; +} diff --git a/components/usb/test_apps/common/dev_hid.h b/components/usb/test_apps/common/dev_hid.h new file mode 100644 index 00000000000..a0eb581e3d2 --- /dev/null +++ b/components/usb/test_apps/common/dev_hid.h @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "usb/usb_types_ch9.h" +#include "usb/usb_types_stack.h" + +/* +Some tests where the ESP (acting as host) will require that a particular test +device acting as an HID mouse be connected. That test device's information and descriptors are defined in this file. + +If you are connecting a different device, please update the descriptors in +dev_hid.c accordingly. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the test device + * + * @note Call this before running tests. This is necessary due to IDF-9886 + */ +void dev_hid_init(void); + +/** + * @brief Get the test device's descriptor + * + * @param[in] speed Test device's current speed + * @return Device descriptor + */ +const usb_device_desc_t *dev_hid_get_dev_desc(usb_speed_t speed); + +/** + * @brief Get the test device's configuration descriptor + * + * @param[in] speed Test device's current speed + * @return Configuration descriptor + */ +const usb_config_desc_t *dev_hid_get_config_desc(usb_speed_t speed); + +/** + * @brief Get the test device's HID interface descriptor + * + * @param[in] speed Test device's current speed + * @return HID interface descriptor + */ +const usb_intf_desc_t *dev_hid_get_intf_desc(usb_speed_t speed); + +/** + * @brief Get the test device's HID interrupt IN endpoint descriptor + * + * @param[in] speed Test device's current speed + * @return Interrupt IN endpoint descriptor + */ +const usb_ep_desc_t *dev_hid_get_in_ep_desc(usb_speed_t speed); + +/** + * @brief Get the test device's manufacturer string descriptor + * + * @return Manufacturer string descriptor + */ +const usb_str_desc_t *dev_hid_get_str_desc_manu(void); + +/** + * @brief Get the test device's product string descriptor + * + * @return Product string descriptor + */ +const usb_str_desc_t *dev_hid_get_str_desc_prod(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/usb/test_apps/common/dev_isoc.c b/components/usb/test_apps/common/dev_isoc.c new file mode 100644 index 00000000000..6cf1eb52f6d --- /dev/null +++ b/components/usb/test_apps/common/dev_isoc.c @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "usb/usb_types_ch9.h" +#include "usb/usb_types_stack.h" +#include "dev_isoc.h" + +// ------------------------------- Descriptors --------------------------------- + +static const usb_ep_desc_t isoc_out_ep_desc = { + .bLength = sizeof(usb_ep_desc_t), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x02, // EP 2 OUT + .bmAttributes = USB_BM_ATTRIBUTES_XFER_ISOC, + .wMaxPacketSize = 512, + .bInterval = 1, // Isoc interval is (2 ^ (bInterval - 1)) which means an interval of 1ms +}; + +// -------------------------------- Functions ---------------------------------- + +const usb_ep_desc_t *dev_isoc_get_out_ep_desc(usb_speed_t speed) +{ + return &isoc_out_ep_desc; +} diff --git a/components/usb/test_apps/common/dev_isoc.h b/components/usb/test_apps/common/dev_isoc.h new file mode 100644 index 00000000000..9096179ac37 --- /dev/null +++ b/components/usb/test_apps/common/dev_isoc.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "usb/usb_types_ch9.h" +#include "usb/usb_types_stack.h" + +/* +Some tests where the ESP (acting as host) will require that a particular test +device containing an ISOC endpoint be connected. This header contains +functions to get information and descriptors about that test device. + +If you are connecting a different device, please update the descriptors in +dev_isoc.c accordingly. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get the test device's ISOC OUT endpoint descriptor + * + * @param[in] speed Test device's current speed + * @return ISOC OUT endpoint descriptor + */ +const usb_ep_desc_t *dev_isoc_get_out_ep_desc(usb_speed_t speed); + +#ifdef __cplusplus +} +#endif diff --git a/components/usb/test_apps/common/dev_msc.c b/components/usb/test_apps/common/dev_msc.c new file mode 100644 index 00000000000..6d5d93d2246 --- /dev/null +++ b/components/usb/test_apps/common/dev_msc.c @@ -0,0 +1,354 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "usb/usb_types_ch9.h" +#include "dev_msc.h" + +/* +Some tests where the ESP (acting as host) will require that a particular test +device acting as a MSC SCSI flash drive be connected. That test device's +information and descriptors are defined in this file. + +If you are connecting a different MSC SCSI flash drive, please update +the descriptor and getter functions accordingly. + +------------------------------ Device Descriptor ------------------------------- +bLength : 0x12 (18 bytes) +bDescriptorType : 0x01 (Device Descriptor) +bcdUSB : 0x0210 (2.10) +bDeviceClass : 0x00 +bDeviceSubClass : 0x00 +bDeviceProtocol : 0x00 +bMaxPacketSize0 : 0x40 (64 bytes) +idVendor : 0x0781 (SanDisk Corp) +idProduct : 0x5595 +bcdDevice : 0x0100 (1.00) +iManufacturer : 1 +iProduct : 2 +iSerial : 3 +bNumConfigurations : 1 + +--------------------------- Configuration Descriptor --------------------------- +bLength : 0x09 (9 bytes) +bDescriptorType : 0x02 (Configuration Descriptor) +wTotalLength : 0x0020 (32 bytes) +bNumInterfaces : 0x01 (1 Interface) +bConfigurationValue : 0x01 (Configuration 1) +iConfiguration : 0x00 (No String Descriptor) +bmAttributes : 0x80 + D7: Reserved, set 1 : 0x01 + D6: Self Powered : 0x00 (no) + D5: Remote Wakeup : 0x00 (no) + D4..0: Reserved, set 0 : 0x00 +MaxPower : 0x70 (224 mA) + +Data (HexDump) : 09 02 20 00 01 01 00 80 70 09 04 00 00 02 08 06 + 50 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00 + +----------------------------- Interface Descriptor ----------------------------- +bLength : 0x09 (9 bytes) +bDescriptorType : 0x04 (Interface Descriptor) +bInterfaceNumber : 0x00 +bAlternateSetting : 0x00 +bNumEndpoints : 0x02 (2 Endpoints) +bInterfaceClass : 0x08 (Mass Storage) +bInterfaceSubClass : 0x06 (SCSI transparent command set) +bInterfaceProtocol : 0x50 (Bulk-Only Transport) +iInterface : 0x00 (No String Descriptor) + +------------------------------ Endpoint Descriptor ----------------------------- +bLength : 0x07 (7 bytes) +bDescriptorType : 0x05 (Endpoint Descriptor) +bEndpointAddress : 0x81 (Direction=IN EndpointID=1) +bmAttributes : 0x02 (TransferType=Bulk) +wMaxPacketSize : 0x0040 (max 64 bytes for FS, 512 bytes for HS) +bInterval : 0x00 (never NAKs) + +------------------------------ Endpoint Descriptor ----------------------------- +bLength : 0x07 (7 bytes) +bDescriptorType : 0x05 (Endpoint Descriptor) +bEndpointAddress : 0x02 (Direction=OUT EndpointID=2) +bmAttributes : 0x02 (TransferType=Bulk) +wMaxPacketSize : 0x0040 (max 64 bytes for FS, 512 bytes for HS) +bInterval : 0x00 (never NAKs) + +---------------------------- String Descriptor Manu ---------------------------- +bLength : 0x0A (10 bytes) +bDescriptorType : 0x03 (String Descriptor) +wData : " USB" + +---------------------------- String Descriptor Prod ---------------------------- +bLength : 0x22 (34 bytes) +bDescriptorType : 0x03 (String Descriptor) +wData : " SanDisk 3.2Gen1" + +----------------------------- String Descriptor Ser ---------------------------- +bLength : 0xF2 (242 bytes) +bDescriptorType : 0x03 (String Descriptor) +wData : "0101cdd1e856b427bbb796f870561a4b2b817af9da9872c8d75217cccdd5d5eccb3a0000000000000000000096abe1a3ff83610095558107aea948b4" +*/ + +// --------------------------- Device Information ------------------------------ + +static const dev_msc_info_t dev_info = { + .bInterfaceNumber = 0x00, + .bAlternateSetting = 0x00, + .in_ep_addr = 0x81, + .out_up_addr = 0x02, + .scsi_sector_size = 512, +}; + +// ------------------------------- Descriptors --------------------------------- + +static const usb_device_desc_t dev_desc = { + .bLength = USB_DEVICE_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_DEVICE, + .bcdUSB = 0x0210, // 2.10 + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0781, // SanDisk Corp + .idProduct = 0x5595, + .bcdDevice = 0x0100, // 1.00 + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +static const usb_config_desc_t config_desc = { + .bLength = USB_CONFIG_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_CONFIGURATION, + .wTotalLength = 0x0020, // 32 bytes + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x70, // 224 mA +}; + +static const usb_intf_desc_t intf_desc = { + .bLength = USB_INTF_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = 0x06, //SCSI + .bInterfaceProtocol = 0x50, //Bulk only + .iInterface = 0, +}; + +static const usb_ep_desc_t in_ep_desc_fs = { + .bLength = USB_EP_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x81, // EP 1 IN + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = 64, + .bInterval = 0, +}; + +static const usb_ep_desc_t in_ep_desc_hs = { + .bLength = USB_EP_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x81, // EP 1 IN + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = 512, + .bInterval = 0, +}; + +static const usb_ep_desc_t out_ep_desc_fs = { + .bLength = USB_EP_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x02, // EP 2 OUT + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = 64, + .bInterval = 0, +}; + +static const usb_ep_desc_t out_ep_desc_hs = { + .bLength = USB_EP_DESC_SIZE, + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, + .bEndpointAddress = 0x02, // EP 2 OUT + .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, + .wMaxPacketSize = 512, + .bInterval = 0, +}; + +/* +String descriptors are dynamically initialized due to issues with static +initialization of variable length array members. See IDF-9886. +*/ + +static const usb_str_desc_t str_desc_manu_base = { + .bLength = sizeof(usb_str_desc_t) + (4 * sizeof(uint16_t)), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_STRING, +}; +static const uint16_t str_desc_manu_data[] = { + 0x0020, // ' ' + 0x0055, // 'U' + 0x0053, // 'S' + 0x0042, // 'B' +}; +static uint8_t *str_desc_manu[sizeof(str_desc_manu_base) + sizeof(str_desc_manu_data)]; + +static const usb_str_desc_t str_desc_prod_base = { + .bLength = sizeof(usb_str_desc_t) + (16 * sizeof(uint16_t)), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_STRING, +}; +static const uint16_t str_desc_prod_data[] = { + 0x0020, // ' ' + 0x0053, // 'S' + 0x0061, // 'a' + 0x006e, // 'n' + 0x0044, // 'D' + 0x0069, // 'i' + 0x0073, // 's' + 0x006b, // 'k' + 0x0020, // ' ' + 0x0033, // '3' + 0x002e, // '.' + 0x0032, // '2' + 0x0047, // 'G' + 0x0065, // 'e' + 0x006e, // 'n' + 0x0031, // '1' +}; +static uint8_t *str_desc_prod[sizeof(str_desc_prod_base) + sizeof(str_desc_prod_data)]; + +static const usb_str_desc_t str_desc_ser_base = { + .bLength = sizeof(usb_str_desc_t) + (120 * sizeof(uint16_t)), + .bDescriptorType = USB_B_DESCRIPTOR_TYPE_STRING, +}; +static const uint16_t str_desc_ser_data[] = { + /* + The following string encoded in UTF-16LE + + "0101cdd1e856b427bbb796f870561a4b2b817af9da9872c8d75217cccdd5d5eccb3a0000000 + 000000000000096abe1a3ff83610095558107aea948b4" + */ + 0x0030, 0x0031, 0x0030, 0x0031, 0x0063, 0x0064, 0x0064, 0x0031, 0x0065, + 0x0038, 0x0035, 0x0036, 0x0062, 0x0034, 0x0032, 0x0037, 0x0062, 0x0062, + 0x0062, 0x0037, 0x0039, 0x0036, 0x0066, 0x0038, 0x0037, 0x0030, 0x0035, + 0x0036, 0x0031, 0x0061, 0x0034, 0x0062, 0x0032, 0x0062, 0x0038, 0x0031, + 0x0037, 0x0061, 0x0066, 0x0039, 0x0064, 0x0061, 0x0039, 0x0038, 0x0037, + 0x0032, 0x0063, 0x0038, 0x0064, 0x0037, 0x0035, 0x0032, 0x0031, 0x0037, + 0x0063, 0x0063, 0x0063, 0x0064, 0x0064, 0x0035, 0x0064, 0x0035, 0x0065, + 0x0063, 0x0063, 0x0062, 0x0033, 0x0061, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0039, 0x0036, + 0x0061, 0x0062, 0x0065, 0x0031, 0x0061, 0x0033, 0x0066, 0x0066, 0x0038, + 0x0033, 0x0036, 0x0031, 0x0030, 0x0030, 0x0039, 0x0035, 0x0035, 0x0035, + 0x0038, 0x0031, 0x0030, 0x0037, 0x0061, 0x0065, 0x0061, 0x0039, 0x0034, + 0x0038, 0x0062, 0x0034, +}; +static uint8_t *str_desc_ser[sizeof(str_desc_ser_base) + sizeof(str_desc_ser_data)]; + +// -------------------------------- Functions ---------------------------------- + +void dev_msc_init(void) +{ + // Dynamically initialize string descriptors due to compiler limitations (see IDF-9886) + uint8_t *ptr; + + // Initialize manufacturer string descriptor + ptr = (uint8_t *)str_desc_manu; + memcpy(ptr, &str_desc_manu_base, sizeof(str_desc_manu_base)); + ptr += sizeof(str_desc_manu_base); + memcpy(ptr, &str_desc_manu_data, sizeof(str_desc_manu_data)); + + // Initialize product string descriptor + ptr = (uint8_t *)str_desc_prod; + memcpy(ptr, &str_desc_prod_base, sizeof(str_desc_prod_base)); + ptr += sizeof(str_desc_prod_base); + memcpy(ptr, &str_desc_prod_data, sizeof(str_desc_prod_data)); + + // Initialize serial string descriptor + ptr = (uint8_t *)str_desc_ser; + memcpy(ptr, &str_desc_ser_base, sizeof(str_desc_ser_base)); + ptr += sizeof(str_desc_ser_base); + memcpy(ptr, &str_desc_ser_data, sizeof(str_desc_ser_data)); +} + +const dev_msc_info_t *dev_msc_get_info(void) +{ + return &dev_info; +} + +const usb_device_desc_t *dev_msc_get_dev_desc(usb_speed_t speed) +{ + return &dev_desc; +} + +const usb_config_desc_t *dev_msc_get_config_desc(usb_speed_t speed) +{ + return &config_desc; +} + +const usb_intf_desc_t *dev_msc_get_intf_desc(usb_speed_t speed) +{ + return &intf_desc; +} + +const usb_ep_desc_t *dev_msc_get_in_ep_desc(usb_speed_t speed) +{ + const usb_ep_desc_t *ret; + + // EP descriptor differs by speed due to MPS + switch (speed) { + case USB_SPEED_FULL: + ret = &in_ep_desc_fs; + break; + case USB_SPEED_HIGH: + ret = &in_ep_desc_hs; + break; + default: + ret = NULL; + abort(); // Should never occur + break; + } + + return ret; +} + +const usb_ep_desc_t *dev_msc_get_out_ep_desc(usb_speed_t speed) +{ + const usb_ep_desc_t *ret; + + // EP descriptor differs by speed due to MPS + switch (speed) { + case USB_SPEED_FULL: + ret = &out_ep_desc_fs; + break; + case USB_SPEED_HIGH: + ret = &out_ep_desc_hs; + break; + default: + ret = NULL; + abort(); // Should never occur + break; + } + + return ret; +} + +const usb_str_desc_t *dev_msc_get_str_desc_manu(void) +{ + return (const usb_str_desc_t *)str_desc_manu; +} + +const usb_str_desc_t *dev_msc_get_str_desc_prod(void) +{ + return (const usb_str_desc_t *)str_desc_prod; +} + +const usb_str_desc_t *dev_msc_get_str_desc_ser(void) +{ + return (const usb_str_desc_t *)str_desc_ser; +} diff --git a/components/usb/test_apps/common/dev_msc.h b/components/usb/test_apps/common/dev_msc.h new file mode 100644 index 00000000000..ac21ca952e2 --- /dev/null +++ b/components/usb/test_apps/common/dev_msc.h @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "usb/usb_types_ch9.h" +#include "usb/usb_types_stack.h" + +/* +Some tests where the ESP (acting as host) will require that a particular test +device acting as a MSC SCSI flash drive be connected. This header contains +functions to get information and descriptors about that test device. + +If you are connecting a different MSC SCSI flash drive, please update +the descriptors in dev_msc.c accordingly. +*/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @brief MSC SCSI test device information + * + * Structure containing basic information about the the MSC SCSI interface on + * the test device. + */ +typedef struct { + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t in_ep_addr; + uint8_t out_up_addr; + unsigned int scsi_sector_size; +} dev_msc_info_t; + +/** + * @brief Initialize the test device + * + * @note Call this before running tests. This is necessary due to IDF-9886 + */ +void dev_msc_init(void); + +/** + * @brief Get information about the test device's MSC SCSI interface + * + * @return Information object + */ +const dev_msc_info_t *dev_msc_get_info(void); + +/** + * @brief Get the test device's descriptor + * + * @param[in] speed Test device's current speed + * @return Device descriptor + */ +const usb_device_desc_t *dev_msc_get_dev_desc(usb_speed_t speed); + +/** + * @brief Get the test device's configuration descriptor + * + * @param[in] speed Test device's current speed + * @return Configuration descriptor + */ +const usb_config_desc_t *dev_msc_get_config_desc(usb_speed_t speed); + +/** + * @brief Get the test device's MSC interface descriptor + * + * @param[in] speed Test device's current speed + * @return MSC interface descriptor + */ +const usb_intf_desc_t *dev_msc_get_intf_desc(usb_speed_t speed); + +/** + * @brief Get the test device's MSC IN endpoint descriptor + * + * @param[in] speed Test device's current speed + * @return MSC IN endpoint descriptor + */ +const usb_ep_desc_t *dev_msc_get_in_ep_desc(usb_speed_t speed); + +/** + * @brief Get the test device's MSC OUT endpoint descriptor + * + * @param[in] speed Test device's current speed + * @return MSC OUT endpoint descriptor + */ +const usb_ep_desc_t *dev_msc_get_out_ep_desc(usb_speed_t speed); + +/** + * @brief Get the test device's manufacturer string descriptor + * + * @return Manufacturer string descriptor + */ +const usb_str_desc_t *dev_msc_get_str_desc_manu(void); + +/** + * @brief Get the test device's product string descriptor + * + * @return Product string descriptor + */ +const usb_str_desc_t *dev_msc_get_str_desc_prod(void); + +/** + * @brief Get the test device's serial number string descriptor + * + * @return Serial number string descriptor + */ +const usb_str_desc_t *dev_msc_get_str_desc_ser(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/usb/test_apps/common/mock_hid.c b/components/usb/test_apps/common/mock_hid.c deleted file mode 100644 index 4f91e7b2945..00000000000 --- a/components/usb/test_apps/common/mock_hid.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include -#include -#include "usb/usb_types_ch9.h" -#include "mock_hid.h" - -// ---------------------------------------------------- HID Mouse ------------------------------------------------------ - -const usb_ep_desc_t mock_hid_mouse_in_ep_desc = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_HID_MOUSE_INTR_IN_EP_ADDR, // EP 1 IN - .bmAttributes = USB_BM_ATTRIBUTES_XFER_INT, - .wMaxPacketSize = MOCK_HID_MOUSE_INTR_IN_MPS, - .bInterval = 10, // Interval of 10ms -}; - -void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter) -{ - static int x_pos = 0; - static int y_pos = 0; - // Update X position - if (report->x_movement & 0x80) { // Positive movement - x_pos += report->x_movement & 0x7F; - } else { // Negative movement - x_pos -= report->x_movement & 0x7F; - } - // Update Y position - if (report->y_movement & 0x80) { // Positive movement - y_pos += report->y_movement & 0x7F; - } else { // Negative movement - y_pos -= report->y_movement & 0x7F; - } - printf("\rX:%d\tY:%d\tIter: %d\n", x_pos, y_pos, iter); -} diff --git a/components/usb/test_apps/common/mock_hid.h b/components/usb/test_apps/common/mock_hid.h deleted file mode 100644 index a9a145fbdfc..00000000000 --- a/components/usb/test_apps/common/mock_hid.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/* -This header contains bare-bone mock implementations of some device classes in order to test various layers of the USB -Host stack. -*/ - -#pragma once - -#include -#include -#include "esp_assert.h" -#include "usb/usb_types_ch9.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// ---------------------------------------------------- HID Mouse ------------------------------------------------------ - -/* -Note: The mock HID mouse tests require that USB low speed mouse be connected. The mouse should... - -- Be implement the HID with standard report format used by mice -- It's configuration 1 should have the following endpoint - - ------------------ Configuration Descriptor ------------------- -bLength : 0x09 (9 bytes) -bDescriptorType : 0x02 (Configuration Descriptor) -wTotalLength : 0x003B (59 bytes) -bNumInterfaces : 0x02 (2 Interfaces) -bConfigurationValue : 0x01 (Configuration 1) -iConfiguration : 0x00 (No String Descriptor) -bmAttributes : 0xA0 - D7: Reserved, set 1 : 0x01 - D6: Self Powered : 0x00 (no) - D5: Remote Wakeup : 0x01 (yes) - D4..0: Reserved, set 0 : 0x00 -MaxPower : 0x32 (100 mA) -Data (HexDump) : 09 02 3B 00 02 01 00 A0 32 09 04 00 00 01 03 01 - 02 00 09 21 00 02 00 01 22 4D 00 07 05 81 03 08 - 00 0A 09 04 01 00 01 03 01 01 00 09 21 00 02 00 - 01 22 31 00 07 05 82 03 08 00 0A - - ---------------- Interface Descriptor ----------------- -bLength : 0x09 (9 bytes) -bDescriptorType : 0x04 (Interface Descriptor) -bInterfaceNumber : 0x00 -bAlternateSetting : 0x00 -bNumEndpoints : 0x01 (1 Endpoint) -bInterfaceClass : 0x03 (HID - Human Interface Device) -bInterfaceSubClass : 0x01 (Boot Interface) -bInterfaceProtocol : 0x02 (Mouse) -iInterface : 0x00 (No String Descriptor) -Data (HexDump) : 09 04 00 00 01 03 01 02 00 - - ------------------- HID Descriptor -------------------- -bLength : 0x09 (9 bytes) -bDescriptorType : 0x21 (HID Descriptor) -bcdHID : 0x0200 (HID Version 2.00) -bCountryCode : 0x00 (00 = not localized) -bNumDescriptors : 0x01 -Data (HexDump) : 09 21 00 02 00 01 22 4D 00 -Descriptor 1: -bDescriptorType : 0x22 (Class=Report) -wDescriptorLength : 0x004D (77 bytes) -Error reading descriptor : ERROR_INVALID_PARAMETER (due to a obscure limitation of the Win32 USB API, see UsbTreeView.txt) - - ----------------- Endpoint Descriptor ----------------- -bLength : 0x07 (7 bytes) -bDescriptorType : 0x05 (Endpoint Descriptor) -bEndpointAddress : 0x81 (Direction=IN EndpointID=1) -bmAttributes : 0x03 (TransferType=Interrupt) -wMaxPacketSize : 0x0008 -bInterval : 0x0A (10 ms) -Data (HexDump) : 07 05 81 03 08 00 0A - -If you're using another mice with different endpoints, modify the endpoint descriptor below -*/ - -extern const usb_ep_desc_t mock_hid_mouse_in_ep_desc; - -#define MOCK_HID_MOUSE_DEV_ID_VENDOR 0x03F0 -#define MOCK_HID_MOUSE_DEV_ID_PRODUCT 0x1198 -#define MOCK_HID_MOUSE_DEV_DFLT_EP_MPS 8 -#define MOCK_HID_MOUSE_INTF_NUMBER 0 -#define MOCK_HID_MOUSE_INTF_ALT_SETTING 0 -#define MOCK_HID_MOUSE_INTR_IN_EP_ADDR 0x81 -#define MOCK_HID_MOUSE_INTR_IN_MPS 8 - -typedef union { - struct { - uint32_t left_button: 1; - uint32_t right_button: 1; - uint32_t middle_button: 1; - uint32_t reserved5: 5; - uint8_t x_movement; - uint8_t y_movement; - } __attribute__((packed)); - uint8_t val[3]; -} mock_hid_mouse_report_t; -ESP_STATIC_ASSERT(sizeof(mock_hid_mouse_report_t) == 3, "Size of HID mouse report incorrect"); - -void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter); - -#ifdef __cplusplus -} -#endif diff --git a/components/usb/test_apps/common/mock_msc.c b/components/usb/test_apps/common/mock_msc.c index fd276d6b5b4..30538f0f7f6 100644 --- a/components/usb/test_apps/common/mock_msc.c +++ b/components/usb/test_apps/common/mock_msc.c @@ -15,97 +15,18 @@ const char *MSC_CLIENT_TAG = "MSC Client"; -const usb_device_desc_t mock_msc_scsi_dev_desc = { - .bLength = USB_DEVICE_DESC_SIZE, - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_DEVICE, - .bcdUSB = MOCK_MSC_SCSI_USB_VERSION, - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = MOCK_MSC_SCSI_DEV_DFLT_EP_MPS, - .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, - .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, - .bcdDevice = MOCK_MSC_SCSI_DEV_VERSION, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, -}; - -#define MOCK_MSC_SCSI_WTOTALLENGTH (USB_CONFIG_DESC_SIZE + USB_INTF_DESC_SIZE + 2*USB_EP_DESC_SIZE) -static const usb_config_desc_t mock_msc_config_desc = { - .bLength = USB_CONFIG_DESC_SIZE, - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_CONFIGURATION, - .wTotalLength = MOCK_MSC_SCSI_WTOTALLENGTH, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x70, // 224mA -}; - -static const usb_intf_desc_t mock_msc_intf_desc = { - .bLength = USB_INTF_DESC_SIZE, - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_INTERFACE, - .bInterfaceNumber = MOCK_MSC_SCSI_INTF_NUMBER, - .bAlternateSetting = MOCK_MSC_SCSI_INTF_ALT_SETTING, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = 0x06, // SCSI - .bInterfaceProtocol = 0x50, // Bulk only - .iInterface = 0, -}; - -uint8_t mock_msc_scsi_config_desc[255]; -uint16_t mock_msc_scsi_str_desc_manu[128]; -uint16_t mock_msc_scsi_str_desc_prod[128]; -uint16_t mock_msc_scsi_str_desc_ser_num[128]; -usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc; -usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc; - -const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_fs = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, // EP 1 OUT - .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, // MPS of 64 bytes - .bInterval = 0, -}; - -const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_hs = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR, // EP 1 OUT - .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, // MPS of 512 bytes - .bInterval = 0, -}; - -const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_fs = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR, - .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_FS, // MPS of 64 bytes - .bInterval = 0, -}; - -const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_hs = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR, - .bmAttributes = USB_BM_ATTRIBUTES_XFER_BULK, - .wMaxPacketSize = MOCK_MSC_SCSI_BULK_EP_MPS_HS, // MPS of 512 bytes - .bInterval = 0, -}; - -void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag) +void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, + bool is_read, + unsigned int offset, + unsigned int num_sectors, + unsigned int sector_size, + uint32_t tag) { cbw->dCBWSignature = 0x43425355; // Fixed value cbw->dCBWTag = tag; // Random value that is echoed back - cbw->dCBWDataTransferLength = num_sectors * MOCK_MSC_SCSI_SECTOR_SIZE; + cbw->dCBWDataTransferLength = num_sectors * sector_size; cbw->bmCBWFlags = (is_read) ? (1 << 7) : 0; // If this is a read, set the direction flag - cbw->bCBWLUN = MOCK_MSC_SCSI_LUN; + cbw->bCBWLUN = 0; cbw->bCBWCBLength = 10; // The length of the SCSI command // Initialize SCSI CMD as READ10 or WRITE 10 cbw->CBWCB.opcode = (is_read) ? 0x28 : 0x2A; // SCSI CMD READ10 or WRITE10 @@ -141,39 +62,3 @@ bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expect) } return no_issues; } - -void mock_msc_scsi_init_reference_descriptors(void) -{ - // Configuration descriptor - uint8_t *dest_ptr = mock_msc_scsi_config_desc; - memcpy(dest_ptr, (void*)&mock_msc_config_desc, sizeof(mock_msc_config_desc)); - dest_ptr += USB_CONFIG_DESC_SIZE; - memcpy(dest_ptr, (void*)&mock_msc_intf_desc, sizeof(mock_msc_intf_desc)); - dest_ptr += USB_INTF_DESC_SIZE; - // Set endpoint descriptors with zeroes, FS or HS device has not been connected - memset(dest_ptr, 0, sizeof(usb_ep_desc_t)); - dest_ptr += USB_EP_DESC_SIZE; - memset(dest_ptr, 0, sizeof(usb_ep_desc_t)); - - // String descriptors - const char *str = MOCK_MSC_SCSI_STRING_1; - uint8_t chr_count = strlen(str); - mock_msc_scsi_str_desc_manu[0] = (USB_B_DESCRIPTOR_TYPE_STRING << 8) | (2 * chr_count + 2); // first byte is length (including header), second byte is string type - for (uint8_t i = 0; i < chr_count; i++) { - mock_msc_scsi_str_desc_manu[1 + i] = str[i]; - } - - str = MOCK_MSC_SCSI_STRING_2; - chr_count = strlen(str); - mock_msc_scsi_str_desc_prod[0] = (USB_B_DESCRIPTOR_TYPE_STRING << 8) | (2 * chr_count + 2); // first byte is length (including header), second byte is string type - for (uint8_t i = 0; i < chr_count; i++) { - mock_msc_scsi_str_desc_prod[1 + i] = str[i]; - } - - str = MOCK_MSC_SCSI_STRING_3; - chr_count = strlen(str); - mock_msc_scsi_str_desc_ser_num[0] = (USB_B_DESCRIPTOR_TYPE_STRING << 8) | (2 * chr_count + 2); // first byte is length (including header), second byte is string type - for (uint8_t i = 0; i < chr_count; i++) { - mock_msc_scsi_str_desc_ser_num[1 + i] = str[i]; - } -} diff --git a/components/usb/test_apps/common/mock_msc.h b/components/usb/test_apps/common/mock_msc.h index 466decf2be2..17e347d49ab 100644 --- a/components/usb/test_apps/common/mock_msc.h +++ b/components/usb/test_apps/common/mock_msc.h @@ -4,11 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* -This header contains bare-bone mock implementations of some device classes in order to test various layers of the USB -Host stack. -*/ - #pragma once #include @@ -16,99 +11,16 @@ Host stack. #include "esp_assert.h" #include "usb/usb_types_ch9.h" +/* +This header contains bare-bone mock implementations of the MSC SCSI class +*/ + #ifdef __cplusplus extern "C" { #endif -// ---------------------------------------------------- MSC SCSI ------------------------------------------------------- - extern const char *MSC_CLIENT_TAG; -/* -Note: The mock MSC SCSI tests requires that USB flash drive be connected. The flash drive should... - -- Be implement the Mass Storage class supporting BULK only transfers using SCSI commands -- It's configuration 1 should have the following endpoints - - ------------------ Configuration Descriptor ------------------- -bLength : 0x09 (9 bytes) -bDescriptorType : 0x02 (Configuration Descriptor) -wTotalLength : 0x0020 (32 bytes) -bNumInterfaces : 0x01 (1 Interface) -bConfigurationValue : 0x01 (Configuration 1) -iConfiguration : 0x00 (No String Descriptor) -bmAttributes : 0x80 - D7: Reserved, set 1 : 0x01 - D6: Self Powered : 0x00 (no) - D5: Remote Wakeup : 0x00 (no) - D4..0: Reserved, set 0 : 0x00 -MaxPower : 0x70 (224 mA) -Data (HexDump) : 09 02 20 00 01 01 00 80 70 09 04 00 00 02 08 06 - 50 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00 - - ---------------- Interface Descriptor ----------------- -bLength : 0x09 (9 bytes) -bDescriptorType : 0x04 (Interface Descriptor) -bInterfaceNumber : 0x00 -bAlternateSetting : 0x00 -bNumEndpoints : 0x02 (2 Endpoints) -bInterfaceClass : 0x08 (Mass Storage) -bInterfaceSubClass : 0x06 (SCSI transparent command set) -bInterfaceProtocol : 0x50 (Bulk-Only Transport) -iInterface : 0x00 (No String Descriptor) -Data (HexDump) : 09 04 00 00 02 08 06 50 00 - - ----------------- Endpoint Descriptor ----------------- -bLength : 0x07 (7 bytes) -bDescriptorType : 0x05 (Endpoint Descriptor) -bEndpointAddress : 0x81 (Direction=IN EndpointID=1) -bmAttributes : 0x02 (TransferType=Bulk) -wMaxPacketSize : 0x0040 (max 64 bytes for FS, 512 bytes for HS) -bInterval : 0x00 (never NAKs) -Data (HexDump) : 07 05 81 02 40 00 00 - - ----------------- Endpoint Descriptor ----------------- -bLength : 0x07 (7 bytes) -bDescriptorType : 0x05 (Endpoint Descriptor) -bEndpointAddress : 0x02 (Direction=OUT EndpointID=2) -bmAttributes : 0x02 (TransferType=Bulk) -wMaxPacketSize : 0x0040 (max 64 bytes for FS, 512 bytest for HS) -bInterval : 0x00 (never NAKs) -Data (HexDump) : 07 05 02 02 40 00 00 - -If you're using a flash driver with different endpoints, modify the endpoint descriptors below. -*/ - -//Constant descriptors -extern const usb_device_desc_t mock_msc_scsi_dev_desc; -extern uint8_t mock_msc_scsi_config_desc[255]; -extern uint16_t mock_msc_scsi_str_desc_manu[128]; -extern uint16_t mock_msc_scsi_str_desc_prod[128]; -extern uint16_t mock_msc_scsi_str_desc_ser_num[128]; -extern usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc; -extern usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc; -extern const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_fs; -extern const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_fs; -extern const usb_ep_desc_t mock_msc_scsi_bulk_out_ep_desc_hs; -extern const usb_ep_desc_t mock_msc_scsi_bulk_in_ep_desc_hs; - -#define MOCK_MSC_SCSI_DEV_ID_VENDOR 0x0781 // Western Digital, Sandisk -#define MOCK_MSC_SCSI_DEV_ID_PRODUCT 0x5595 -#define MOCK_MSC_SCSI_DEV_VERSION 0x0100 //1.00 -#define MOCK_MSC_SCSI_USB_VERSION 0x0210 //2.10 -#define MOCK_MSC_SCSI_DEV_DFLT_EP_MPS 64 -#define MOCK_MSC_SCSI_SECTOR_SIZE 512 -#define MOCK_MSC_SCSI_LUN 0 -#define MOCK_MSC_SCSI_INTF_NUMBER 0 -#define MOCK_MSC_SCSI_INTF_ALT_SETTING 0 -#define MOCK_MSC_SCSI_BULK_OUT_EP_ADDR 0x02 -#define MOCK_MSC_SCSI_BULK_IN_EP_ADDR 0x81 -#define MOCK_MSC_SCSI_BULK_EP_MPS_FS 64 // FS wMaxPacketSize -#define MOCK_MSC_SCSI_BULK_EP_MPS_HS 512 // HS wMaxPacketSize -#define MOCK_MSC_SCSI_STRING_1 (" USB") -#define MOCK_MSC_SCSI_STRING_2 (" SanDisk 3.2Gen1") -#define MOCK_MSC_SCSI_STRING_3 ("0101cdd1e856b427bbb796f870561a4b2b817af9da9872c8d75217cccdd5d5eccb3a0000000000000000000096abe1a3ff83610095558107aea948b4") // This string is NOT checked by the enum test - #define MOCK_MSC_SCSI_REQ_INIT_RESET(setup_pkt_ptr, intf_num) ({ \ (setup_pkt_ptr)->bmRequestType = USB_BM_REQUEST_TYPE_DIR_OUT | USB_BM_REQUEST_TYPE_TYPE_CLASS | USB_BM_REQUEST_TYPE_RECIP_INTERFACE; \ (setup_pkt_ptr)->bRequest = 0xFF; \ @@ -155,21 +67,26 @@ typedef struct __attribute__((packed)) /** * @brief Initialize a MSC Command Block Wrapper (CBW) as an SCSI command * - * @param cbw CBW structure - * @param is_read Is a read command - * @param offset Block offset - * @param num_sectors Number of sectors to read - * @param tag Tag (this is simply echoed back + * @param[in] cbw CBW structure + * @param[in] is_read Is a read command + * @param[in] offset Block offset + * @param[in] num_sectors Number of sectors to read + * @param[in] sector_size Size of each sector in bytes + * @param[in] tag Tag (this is simply echoed back */ -void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag); +void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, + bool is_read, + unsigned int offset, + unsigned int num_sectors, + unsigned int sector_size, + uint32_t tag); /** * @brief Check that returned Command Status Wrapper (CSW) is valid * - * @param csw CSW structure - * @param tag_expect Expected tag - * @return true CSW is valid - * @return false CSW is not valid + * @param[in] csw CSW structure + * @param[in] tag_expect Expected tag + * @return True if CSW is valid, false otherwise */ bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expect); @@ -178,25 +95,6 @@ bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expect); */ void mock_msc_scsi_init_reference_descriptors(void); -// ---------------------------------------------------- Mock ISOC ------------------------------------------------------ - -/* -Note: ISOC test rely on communicating with a non existent endpoint using ISOC OUT transfers. Since no ACK is given for -ISOC, transferring to a non-existent endpoint should work. The non-existent endpoint descriptor is described below: -*/ - -#define MOCK_ISOC_EP_NUM 2 -#define MOCK_ISOC_EP_MPS 512 - -static const usb_ep_desc_t mock_isoc_out_ep_desc = { - .bLength = sizeof(usb_ep_desc_t), - .bDescriptorType = USB_B_DESCRIPTOR_TYPE_ENDPOINT, - .bEndpointAddress = MOCK_ISOC_EP_NUM, - .bmAttributes = USB_BM_ATTRIBUTES_XFER_ISOC, - .wMaxPacketSize = MOCK_ISOC_EP_MPS, //MPS of 512 bytes - .bInterval = 1, //Isoc interval is (2 ^ (bInterval - 1)) which means an interval of 1ms -}; - #ifdef __cplusplus } #endif diff --git a/components/usb/test_apps/hcd/main/test_app_main.c b/components/usb/test_apps/hcd/main/test_app_main.c index d9a01d71e81..9137bfe4698 100644 --- a/components/usb/test_apps/hcd/main/test_app_main.c +++ b/components/usb/test_apps/hcd/main/test_app_main.c @@ -7,14 +7,17 @@ #include "unity.h" #include "unity_test_runner.h" #include "unity_test_utils_memory.h" - #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "dev_msc.h" +#include "dev_hid.h" #include "test_hcd_common.h" void setUp(void) { unity_utils_record_free_mem(); + dev_msc_init(); + dev_hid_init(); port_hdl = test_hcd_setup(); } diff --git a/components/usb/test_apps/hcd/main/test_hcd_bulk.c b/components/usb/test_apps/hcd/main/test_hcd_bulk.c index f5034dc66a4..8d720200122 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_bulk.c +++ b/components/usb/test_apps/hcd/main/test_hcd_bulk.c @@ -10,16 +10,17 @@ #include "freertos/semphr.h" #include "unity.h" #include "mock_msc.h" +#include "dev_msc.h" #include "test_hcd_common.h" // --------------------------------------------------- Test Cases ------------------------------------------------------ -static void mock_msc_reset_req(hcd_pipe_handle_t default_pipe) +static void mock_msc_reset_req(hcd_pipe_handle_t default_pipe, uint8_t bInterfaceNumber) { // Create URB urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_setup_packet_t)); usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)urb->transfer.data_buffer; - MOCK_MSC_SCSI_REQ_INIT_RESET(setup_pkt, MOCK_MSC_SCSI_INTF_NUMBER); + MOCK_MSC_SCSI_REQ_INIT_RESET(setup_pkt, bInterfaceNumber); urb->transfer.num_bytes = sizeof(usb_setup_packet_t); // Enqueue, wait, dequeue, and check URB TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); @@ -60,24 +61,31 @@ TEST_CASE("Test HCD bulk pipe URBs", "[bulk][full_speed]") // Enumerate and reset MSC SCSI device hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); // Create a default pipe (using a NULL EP descriptor) uint8_t dev_addr = test_hcd_enum_device(default_pipe); - mock_msc_reset_req(default_pipe); - test_hcd_set_mock_msc_ep_descriptor(port_speed); + const dev_msc_info_t *dev_info = dev_msc_get_info(); + mock_msc_reset_req(default_pipe, dev_info->bInterfaceNumber); // Create BULK IN and BULK OUT pipes for SCSI - hcd_pipe_handle_t bulk_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_msc_scsi_bulk_out_ep_desc, dev_addr, port_speed); - hcd_pipe_handle_t bulk_in_pipe = test_hcd_pipe_alloc(port_hdl, &mock_msc_scsi_bulk_in_ep_desc, dev_addr, port_speed); + const usb_ep_desc_t *out_ep_desc = dev_msc_get_out_ep_desc(port_speed); + const usb_ep_desc_t *in_ep_desc = dev_msc_get_in_ep_desc(port_speed); + const uint16_t mps = USB_EP_DESC_GET_MPS(in_ep_desc) ; + hcd_pipe_handle_t bulk_out_pipe = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr, port_speed); + hcd_pipe_handle_t bulk_in_pipe = test_hcd_pipe_alloc(port_hdl, in_ep_desc, dev_addr, port_speed); // Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS urb_t *urb_cbw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_cbw_t)); - urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE); - const uint16_t mps = USB_EP_DESC_GET_MPS(&mock_msc_scsi_bulk_in_ep_desc) ; + urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * dev_info->scsi_sector_size); urb_t *urb_csw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_csw_t) + (mps - (sizeof(mock_msc_bulk_csw_t) % mps))); urb_cbw->transfer.num_bytes = sizeof(mock_msc_bulk_cbw_t); - urb_data->transfer.num_bytes = TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE; + urb_data->transfer.num_bytes = TEST_NUM_SECTORS_PER_XFER * dev_info->scsi_sector_size; urb_csw->transfer.num_bytes = sizeof(mock_msc_bulk_csw_t) + (mps - (sizeof(mock_msc_bulk_csw_t) % mps)); for (int block_num = 0; block_num < TEST_NUM_SECTORS_TOTAL; block_num += TEST_NUM_SECTORS_PER_XFER) { // Initialize CBW URB, then send it on the BULK OUT pipe - mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)urb_cbw->transfer.data_buffer, true, block_num, TEST_NUM_SECTORS_PER_XFER, 0xAAAAAAAA); + mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)urb_cbw->transfer.data_buffer, + true, + block_num, + TEST_NUM_SECTORS_PER_XFER, + dev_info->scsi_sector_size, + 0xAAAAAAAA); TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_out_pipe, urb_cbw)); test_hcd_expect_pipe_event(bulk_out_pipe, HCD_PIPE_EVENT_URB_DONE); TEST_ASSERT_EQUAL_PTR(urb_cbw, hcd_urb_dequeue(bulk_out_pipe)); diff --git a/components/usb/test_apps/hcd/main/test_hcd_common.c b/components/usb/test_apps/hcd/main/test_hcd_common.c index 0d69c183c18..293f6ca21fb 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_common.c +++ b/components/usb/test_apps/hcd/main/test_hcd_common.c @@ -330,14 +330,3 @@ uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe) test_hcd_free_urb(urb); return ENUM_ADDR; } - -void test_hcd_set_mock_msc_ep_descriptor(usb_speed_t port_speed) -{ - if (port_speed == USB_SPEED_HIGH) { - mock_msc_scsi_bulk_out_ep_desc = mock_msc_scsi_bulk_out_ep_desc_hs; // HS wMaxPacketSize = 512 - mock_msc_scsi_bulk_in_ep_desc = mock_msc_scsi_bulk_in_ep_desc_hs; - } else { - mock_msc_scsi_bulk_out_ep_desc = mock_msc_scsi_bulk_out_ep_desc_fs; // FS wMaxPacketSize = 64 - mock_msc_scsi_bulk_in_ep_desc = mock_msc_scsi_bulk_in_ep_desc_fs; - } -} diff --git a/components/usb/test_apps/hcd/main/test_hcd_intr.c b/components/usb/test_apps/hcd/main/test_hcd_intr.c index 7c772c9ee3b..4416967c1bd 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_intr.c +++ b/components/usb/test_apps/hcd/main/test_hcd_intr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,8 +8,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "unity.h" -#include "mock_msc.h" -#include "mock_hid.h" +#include "dev_hid.h" #include "test_hcd_common.h" // --------------------------------------------------- Test Cases ------------------------------------------------------ @@ -36,7 +35,6 @@ Note: Some mice will NAK until it is moved, so try moving the mouse around if th #define TEST_HID_DEV_SPEED USB_SPEED_LOW #define NUM_URBS 3 -#define URB_DATA_BUFF_SIZE MOCK_HID_MOUSE_INTR_IN_MPS #define NUM_URB_ITERS (NUM_URBS * 100) TEST_CASE("Test HCD interrupt pipe URBs", "[intr][low_speed]") @@ -49,11 +47,13 @@ TEST_CASE("Test HCD interrupt pipe URBs", "[intr][low_speed]") uint8_t dev_addr = test_hcd_enum_device(default_pipe); // Allocate interrupt pipe and URBS - hcd_pipe_handle_t intr_pipe = test_hcd_pipe_alloc(port_hdl, &mock_hid_mouse_in_ep_desc, dev_addr, port_speed); + const usb_ep_desc_t *in_ep_desc = dev_hid_get_in_ep_desc(port_speed); + const int data_buff_size = USB_EP_DESC_GET_MPS(in_ep_desc); + hcd_pipe_handle_t intr_pipe = test_hcd_pipe_alloc(port_hdl, in_ep_desc, dev_addr, port_speed); urb_t *urb_list[NUM_URBS]; for (int i = 0; i < NUM_URBS; i++) { - urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); - urb_list[i]->transfer.num_bytes = URB_DATA_BUFF_SIZE; + urb_list[i] = test_hcd_alloc_urb(0, data_buff_size); + urb_list[i]->transfer.num_bytes = data_buff_size; urb_list[i]->transfer.context = URB_CONTEXT_VAL; } @@ -69,7 +69,8 @@ TEST_CASE("Test HCD interrupt pipe URBs", "[intr][low_speed]") urb_t *urb = hcd_urb_dequeue(intr_pipe); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); - mock_hid_process_report((mock_hid_mouse_report_t *)urb->transfer.data_buffer, iter_count); + // Byte 1 and 2 contains x and y movement respectively + printf("X mov %d, Y mov %d\n", urb->transfer.data_buffer[1], urb->transfer.data_buffer[2]); // Requeue URB if (iter_count > NUM_URBS) { TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(intr_pipe, urb)); diff --git a/components/usb/test_apps/hcd/main/test_hcd_isoc.c b/components/usb/test_apps/hcd/main/test_hcd_isoc.c index 87364c44d1b..20c4c63ab58 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_isoc.c +++ b/components/usb/test_apps/hcd/main/test_hcd_isoc.c @@ -10,14 +10,13 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "unity.h" -#include "mock_msc.h" +#include "dev_isoc.h" +#include "usb/usb_types_ch9.h" #include "test_usb_common.h" #include "test_hcd_common.h" #define NUM_URBS 3 #define NUM_PACKETS_PER_URB 3 -#define ISOC_PACKET_SIZE MOCK_ISOC_EP_MPS -#define URB_DATA_BUFF_SIZE (NUM_PACKETS_PER_URB * ISOC_PACKET_SIZE) #define POST_ENQUEUE_DELAY_US 20 #define ENQUEUE_DELAY (OTG_HSPHY_INTERFACE ? 100 : 500) // With this delay we want to enqueue the URBs at different times @@ -53,18 +52,20 @@ TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed]") uint8_t dev_addr = test_hcd_enum_device(default_pipe); // Create ISOC OUT pipe to non-existent device - hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_isoc_out_ep_desc, dev_addr + 1, port_speed); + const usb_ep_desc_t *out_ep_desc = dev_isoc_get_out_ep_desc(port_speed); + const int isoc_packet_size = USB_EP_DESC_GET_MPS(out_ep_desc); + hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr + 1, port_speed); // Create URBs urb_t *urb_list[NUM_URBS]; // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { - urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, URB_DATA_BUFF_SIZE); - urb_list[urb_idx]->transfer.num_bytes = URB_DATA_BUFF_SIZE; + urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, NUM_PACKETS_PER_URB * isoc_packet_size); + urb_list[urb_idx]->transfer.num_bytes = NUM_PACKETS_PER_URB * isoc_packet_size; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { - urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; + urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = isoc_packet_size; // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) - memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * NUM_URBS) + pkt_idx, ISOC_PACKET_SIZE); + memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * isoc_packet_size], (urb_idx * NUM_URBS) + pkt_idx, isoc_packet_size); } } // Enqueue URBs @@ -81,7 +82,7 @@ TEST_CASE("Test HCD isochronous pipe URBs", "[isoc][full_speed]") TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); // Overall URB status and overall number of bytes - TEST_ASSERT_EQUAL(URB_DATA_BUFF_SIZE, urb->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(NUM_PACKETS_PER_URB * isoc_packet_size, urb->transfer.actual_num_bytes); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.isoc_packet_desc[pkt_idx].status, "Transfer NOT completed"); @@ -127,12 +128,14 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") urb_t *urb_list[NUM_URBS]; hcd_pipe_handle_t unused_pipes[OTG_NUM_HOST_CHAN]; + const usb_ep_desc_t *out_ep_desc = dev_isoc_get_out_ep_desc(port_speed); + const int isoc_packet_size = USB_EP_DESC_GET_MPS(out_ep_desc); // For all channels for (int channel = 0; channel < OTG_NUM_HOST_CHAN - 1; channel++) { // Allocate unused pipes, so the active isoc_out_pipe uses different channel index for (int ch = 0; ch < channel; ch++) { - unused_pipes[ch] = test_hcd_pipe_alloc(port_hdl, &mock_isoc_out_ep_desc, dev_addr + 1, port_speed); + unused_pipes[ch] = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr + 1, port_speed); } // For all intervals @@ -142,20 +145,21 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") unsigned num_packets_per_urb = 32; // This is maximum number of packets if interval = 1. This is limited by FRAME_LIST_LEN num_packets_per_urb >>= (interval - 1); // Create ISOC OUT pipe - usb_ep_desc_t isoc_out_ep = mock_isoc_out_ep_desc; // Implicit copy + usb_ep_desc_t isoc_out_ep; + memcpy(&isoc_out_ep, out_ep_desc, sizeof(usb_ep_desc_t)); isoc_out_ep.bInterval = interval; isoc_out_ep.bEndpointAddress = interval; // So you can see the bInterval value in trace hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &isoc_out_ep, channel + 1, port_speed); // Channel number represented in dev_num, so you can see it in trace // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { - urb_list[urb_idx] = test_hcd_alloc_urb(num_packets_per_urb, num_packets_per_urb * ISOC_PACKET_SIZE); - urb_list[urb_idx]->transfer.num_bytes = num_packets_per_urb * ISOC_PACKET_SIZE; + urb_list[urb_idx] = test_hcd_alloc_urb(num_packets_per_urb, num_packets_per_urb * isoc_packet_size); + urb_list[urb_idx]->transfer.num_bytes = num_packets_per_urb * isoc_packet_size; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < num_packets_per_urb; pkt_idx++) { - urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; + urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = isoc_packet_size; // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) - memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * num_packets_per_urb) + pkt_idx, ISOC_PACKET_SIZE); + memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * isoc_packet_size], (urb_idx * num_packets_per_urb) + pkt_idx, isoc_packet_size); } } @@ -176,7 +180,7 @@ TEST_CASE("Test HCD isochronous pipe URBs all", "[isoc][full_speed]") TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); // Overall URB status and overall number of bytes - TEST_ASSERT_EQUAL(num_packets_per_urb * ISOC_PACKET_SIZE, urb->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(num_packets_per_urb * isoc_packet_size, urb->transfer.actual_num_bytes); TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status, "Transfer NOT completed"); for (int pkt_idx = 0; pkt_idx < num_packets_per_urb; pkt_idx++) { TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.isoc_packet_desc[pkt_idx].status, "Transfer NOT completed"); @@ -235,18 +239,20 @@ TEST_CASE("Test HCD isochronous pipe sudden disconnect", "[isoc][full_speed]") uint8_t dev_addr = test_hcd_enum_device(default_pipe); // Create ISOC OUT pipe to non-existent device - hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &mock_isoc_out_ep_desc, dev_addr + 1, port_speed); + const usb_ep_desc_t *out_ep_desc = dev_isoc_get_out_ep_desc(port_speed); + const int isoc_packet_size = USB_EP_DESC_GET_MPS(out_ep_desc); + hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, out_ep_desc, dev_addr + 1, port_speed); // Create URBs urb_t *urb_list[NUM_URBS]; // Initialize URBs for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { - urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, URB_DATA_BUFF_SIZE); - urb_list[urb_idx]->transfer.num_bytes = URB_DATA_BUFF_SIZE; + urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, NUM_PACKETS_PER_URB * isoc_packet_size); + urb_list[urb_idx]->transfer.num_bytes = NUM_PACKETS_PER_URB * isoc_packet_size; urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { - urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; + urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = isoc_packet_size; // Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) - memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * NUM_URBS) + pkt_idx, ISOC_PACKET_SIZE); + memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * isoc_packet_size], (urb_idx * NUM_URBS) + pkt_idx, isoc_packet_size); } } // Enqueue URBs diff --git a/components/usb/test_apps/usb_host/main/ctrl_client.h b/components/usb/test_apps/usb_host/main/ctrl_client.h index 4cfeccc53d7..b780571f6b9 100644 --- a/components/usb/test_apps/usb_host/main/ctrl_client.h +++ b/components/usb/test_apps/usb_host/main/ctrl_client.h @@ -8,8 +8,6 @@ typedef struct { int num_ctrl_xfer_to_send; - uint16_t idVendor; - uint16_t idProduct; } ctrl_client_test_param_t; void ctrl_client_async_seq_task(void *arg); diff --git a/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c b/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c index 48b0937739f..657cf875950 100644 --- a/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c +++ b/components/usb/test_apps/usb_host/main/ctrl_client_async_seq.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "esp_err.h" #include "esp_log.h" #include "test_usb_common.h" +#include "dev_msc.h" #include "ctrl_client.h" #include "usb/usb_host.h" #include "unity.h" @@ -47,14 +48,19 @@ typedef enum { } test_stage_t; typedef struct { + // Test parameters ctrl_client_test_param_t test_param; + // MSC device info + uint8_t dev_addr; + usb_speed_t dev_speed; + // Client variables + usb_host_client_handle_t client_hdl; + usb_device_handle_t dev_hdl; + // Test state test_stage_t cur_stage; test_stage_t next_stage; uint8_t num_xfer_done; uint8_t num_xfer_sent; - uint8_t dev_addr_to_open; - usb_host_client_handle_t client_hdl; - usb_device_handle_t dev_hdl; const usb_config_desc_t *config_desc_cached; } ctrl_client_obj_t; @@ -79,7 +85,7 @@ static void ctrl_client_event_cb(const usb_host_client_event_msg_t *event_msg, v case USB_HOST_CLIENT_EVENT_NEW_DEV: TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, ctrl_obj->cur_stage); ctrl_obj->next_stage = TEST_STAGE_DEV_OPEN; - ctrl_obj->dev_addr_to_open = event_msg->new_dev.address; + ctrl_obj->dev_addr = event_msg->new_dev.address; break; default: abort(); // Should never occur in this test @@ -133,16 +139,21 @@ void ctrl_client_async_seq_task(void *arg) case TEST_STAGE_DEV_OPEN: { ESP_LOGD(CTRL_CLIENT_TAG, "Open"); // Open the device - TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_host_device_open(ctrl_obj.client_hdl, ctrl_obj.dev_addr_to_open, &ctrl_obj.dev_hdl), "Failed to open the device"); + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_host_device_open(ctrl_obj.client_hdl, ctrl_obj.dev_addr, &ctrl_obj.dev_hdl), "Failed to open the device"); + // Get device info to get device speed + usb_device_info_t dev_info; + TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(ctrl_obj.dev_hdl, &dev_info)); + ctrl_obj.dev_speed = dev_info.speed; // Target our transfers to the device for (int i = 0; i < NUM_TRANSFER_OBJ; i++) { ctrl_xfer[i]->device_handle = ctrl_obj.dev_hdl; } - // Check the VID/PID of the opened device + // Check that the device descriptor matches our expected MSC device const usb_device_desc_t *device_desc; + const usb_device_desc_t *device_desc_ref = dev_msc_get_dev_desc(ctrl_obj.dev_speed); TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(ctrl_obj.dev_hdl, &device_desc)); - TEST_ASSERT_EQUAL(ctrl_obj.test_param.idVendor, device_desc->idVendor); - TEST_ASSERT_EQUAL(ctrl_obj.test_param.idProduct, device_desc->idProduct); + TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, sizeof(usb_device_desc_t), "Device descriptors do not match."); // Cache the active configuration descriptor for later comparison TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(ctrl_obj.dev_hdl, &ctrl_obj.config_desc_cached)); ctrl_obj.next_stage = TEST_STAGE_CTRL_XFER; diff --git a/components/usb/test_apps/usb_host/main/msc_client.h b/components/usb/test_apps/usb_host/main/msc_client.h index c3bf2063f27..6a816547bdd 100644 --- a/components/usb/test_apps/usb_host/main/msc_client.h +++ b/components/usb/test_apps/usb_host/main/msc_client.h @@ -12,8 +12,6 @@ typedef struct { int num_sectors_to_read; int num_sectors_per_xfer; uint32_t msc_scsi_xfer_tag; - uint16_t idVendor; - uint16_t idProduct; } msc_client_test_param_t; void msc_client_async_seq_task(void *arg); diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c b/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c index b1b43649062..5f1df1cf151 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_dconn.c @@ -13,8 +13,10 @@ #include "esp_err.h" #include "esp_log.h" #include "mock_msc.h" +#include "dev_msc.h" #include "test_usb_common.h" #include "msc_client.h" +#include "usb/usb_types_ch9.h" #include "usb/usb_host.h" #include "unity.h" @@ -47,15 +49,20 @@ typedef enum { } test_stage_t; typedef struct { + // Test parameters msc_client_test_param_t test_param; - test_stage_t cur_stage; - test_stage_t next_stage; - uint8_t dev_addr_to_open; + // MSC device info + const dev_msc_info_t *dev_info; + usb_speed_t dev_speed; + uint8_t dev_addr; + // Client variables usb_host_client_handle_t client_hdl; usb_device_handle_t dev_hdl; + // Test state + test_stage_t cur_stage; + test_stage_t next_stage; int num_data_transfers; int event_count; - usb_speed_t dev_speed; } msc_client_obj_t; static void msc_reset_cbw_transfer_cb(usb_transfer_t *transfer) @@ -101,7 +108,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo case USB_HOST_CLIENT_EVENT_NEW_DEV: TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage); msc_obj->next_stage = TEST_STAGE_DEV_OPEN; - msc_obj->dev_addr_to_open = event_msg->new_dev.address; + msc_obj->dev_addr = event_msg->new_dev.address; break; case USB_HOST_CLIENT_EVENT_DEV_GONE: msc_obj->event_count++; @@ -119,13 +126,17 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo void msc_client_async_dconn_task(void *arg) { msc_client_obj_t msc_obj; + // Initialize test params memcpy(&msc_obj.test_param, arg, sizeof(msc_client_test_param_t)); - msc_obj.cur_stage = TEST_STAGE_WAIT_CONN; - msc_obj.next_stage = TEST_STAGE_WAIT_CONN; - msc_obj.dev_addr_to_open = 0; + // Initialize MSC device info + msc_obj.dev_info = dev_msc_get_info(); + // Initialize client variables msc_obj.client_hdl = NULL; msc_obj.dev_hdl = NULL; - msc_obj.num_data_transfers = msc_obj.test_param.num_sectors_per_xfer / MOCK_MSC_SCSI_SECTOR_SIZE; + // Initialize test state + msc_obj.cur_stage = TEST_STAGE_WAIT_CONN; + msc_obj.next_stage = TEST_STAGE_WAIT_CONN; + msc_obj.num_data_transfers = msc_obj.test_param.num_sectors_per_xfer / msc_obj.dev_info->scsi_sector_size; msc_obj.event_count = 0; // Register client @@ -143,7 +154,7 @@ void msc_client_async_dconn_task(void *arg) usb_transfer_t *xfer_out; // Must be large enough to contain CBW and MSC reset control transfer usb_transfer_t *xfer_in[msc_obj.num_data_transfers]; // We manually split the data stage into multiple transfers size_t xfer_out_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t)); - size_t xfer_in_size = MOCK_MSC_SCSI_SECTOR_SIZE; + size_t xfer_in_size = msc_obj.dev_info->scsi_sector_size; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(xfer_out_size, 0, &xfer_out)); xfer_out->context = (void *)&msc_obj; for (int i = 0; i < msc_obj.num_data_transfers; i++) { @@ -176,7 +187,7 @@ void msc_client_async_dconn_task(void *arg) case TEST_STAGE_DEV_OPEN: { ESP_LOGD(MSC_CLIENT_TAG, "Open"); // Open the device - TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr, &msc_obj.dev_hdl)); // Target our transfers to the device xfer_out->device_handle = msc_obj.dev_hdl; xfer_out->callback = msc_reset_cbw_transfer_cb; @@ -184,17 +195,21 @@ void msc_client_async_dconn_task(void *arg) xfer_in[i]->device_handle = msc_obj.dev_hdl; xfer_in[i]->callback = msc_data_transfer_cb; } - // Check the VID/PID of the opened device - const usb_device_desc_t *device_desc; - TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); - TEST_ASSERT_EQUAL(msc_obj.test_param.idVendor, device_desc->idVendor); - TEST_ASSERT_EQUAL(msc_obj.test_param.idProduct, device_desc->idProduct); // Get device info to get device speed usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; + // Check the device descriptor of the opened device + const usb_device_desc_t *device_desc; + const usb_device_desc_t *device_desc_ref = dev_msc_get_dev_desc(msc_obj.dev_speed); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); + TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, device_desc_ref->bLength, "Device descriptors do not match."); // Claim the MSC interface - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, + msc_obj.dev_hdl, + msc_obj.dev_info->bInterfaceNumber, + msc_obj.dev_info->bAlternateSetting)); msc_obj.next_stage = TEST_STAGE_MSC_RESET; skip_event_handling = true; // Need to execute TEST_STAGE_MSC_RESET break; @@ -202,7 +217,7 @@ void msc_client_async_dconn_task(void *arg) case TEST_STAGE_MSC_RESET: { ESP_LOGD(MSC_CLIENT_TAG, "MSC Reset"); // Send an MSC SCSI interface reset - MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, MOCK_MSC_SCSI_INTF_NUMBER); + MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, msc_obj.dev_info->bInterfaceNumber); xfer_out->num_bytes = sizeof(usb_setup_packet_t); xfer_out->bEndpointAddress = 0; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out)); @@ -211,9 +226,14 @@ void msc_client_async_dconn_task(void *arg) } case TEST_STAGE_MSC_CBW: { ESP_LOGD(MSC_CLIENT_TAG, "CBW"); - mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)xfer_out->data_buffer, true, 0, msc_obj.test_param.num_sectors_per_xfer, msc_obj.test_param.msc_scsi_xfer_tag); + mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)xfer_out->data_buffer, + true, + 0, + msc_obj.test_param.num_sectors_per_xfer, + msc_obj.dev_info->scsi_sector_size, + msc_obj.test_param.msc_scsi_xfer_tag); xfer_out->num_bytes = sizeof(mock_msc_bulk_cbw_t); - xfer_out->bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR; + xfer_out->bEndpointAddress = msc_obj.dev_info->out_up_addr; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_out)); // Next stage set from transfer callback break; @@ -221,12 +241,11 @@ void msc_client_async_dconn_task(void *arg) case TEST_STAGE_MSC_DATA_DCONN: { ESP_LOGD(MSC_CLIENT_TAG, "Data and disconnect"); // Setup the Data IN transfers - const int bulk_ep_mps = (msc_obj.dev_speed == USB_SPEED_HIGH) - ? MOCK_MSC_SCSI_BULK_EP_MPS_HS - : MOCK_MSC_SCSI_BULK_EP_MPS_FS; + const usb_ep_desc_t *in_ep_desc = dev_msc_get_in_ep_desc(msc_obj.dev_speed); + const int bulk_ep_mps = USB_EP_DESC_GET_MPS(in_ep_desc); for (int i = 0; i < msc_obj.num_data_transfers; i++) { - xfer_in[i]->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE, bulk_ep_mps); - xfer_in[i]->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; + xfer_in[i]->num_bytes = usb_round_up_to_mps(msc_obj.dev_info->scsi_sector_size, bulk_ep_mps); + xfer_in[i]->bEndpointAddress = msc_obj.dev_info->in_ep_addr; } // Submit those transfers for (int i = 0; i < msc_obj.num_data_transfers; i++) { @@ -239,7 +258,7 @@ void msc_client_async_dconn_task(void *arg) } case TEST_STAGE_DEV_CLOSE: { ESP_LOGD(MSC_CLIENT_TAG, "Close"); - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, msc_obj.dev_info->bInterfaceNumber)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); dconn_iter++; if (dconn_iter < TEST_DCONN_ITERATIONS) { diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c index 2d4135515fb..e33ad0ad367 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c @@ -12,6 +12,7 @@ #include "freertos/task.h" #include "esp_err.h" #include "esp_log.h" +#include "dev_msc.h" #include "mock_msc.h" #include "test_usb_common.h" #include "msc_client.h" @@ -67,24 +68,6 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo } } -static void mock_msc_scsi_init_reference_ep_descriptors(const msc_client_obj_t *msc_obj) -{ - uint8_t *dest_ptr = mock_msc_scsi_config_desc; - dest_ptr += USB_CONFIG_DESC_SIZE; - dest_ptr += USB_INTF_DESC_SIZE; - - const usb_ep_desc_t en_desc_in = (msc_obj->dev_speed == USB_SPEED_HIGH) - ? mock_msc_scsi_bulk_in_ep_desc_hs - : mock_msc_scsi_bulk_in_ep_desc_fs; - const usb_ep_desc_t en_desc_out = (msc_obj->dev_speed == USB_SPEED_HIGH) - ? mock_msc_scsi_bulk_out_ep_desc_hs - : mock_msc_scsi_bulk_out_ep_desc_fs; - - memcpy(dest_ptr, (void*)&en_desc_in, sizeof(en_desc_in)); - dest_ptr += USB_EP_DESC_SIZE; - memcpy(dest_ptr, (void*)&en_desc_out, sizeof(en_desc_out)); -} - void msc_client_async_enum_task(void *arg) { msc_client_obj_t msc_obj; @@ -136,17 +119,16 @@ void msc_client_async_enum_task(void *arg) usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; - mock_msc_scsi_init_reference_ep_descriptors(&msc_obj); skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_DEV_DESC break; } case TEST_STAGE_CHECK_DEV_DESC: { // Check the device descriptor const usb_device_desc_t *device_desc; - const usb_device_desc_t *device_desc_ref = &mock_msc_scsi_dev_desc; + const usb_device_desc_t *device_desc_ref = dev_msc_get_dev_desc(msc_obj.dev_speed); TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength); - TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, device_desc_ref->bLength, "Device descriptors do not match."); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, sizeof(usb_device_desc_t), "Device descriptors do not match."); msc_obj.next_stage = TEST_STAGE_CHECK_CONFIG_DESC; skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_CONFIG_DESC break; @@ -155,10 +137,10 @@ void msc_client_async_enum_task(void *arg) case TEST_STAGE_CHECK_CONFIG_DESC: { // Check the configuration descriptor const usb_config_desc_t *config_desc; - const usb_config_desc_t *config_desc_ref = (const usb_config_desc_t *)mock_msc_scsi_config_desc; + const usb_config_desc_t *config_desc_ref = dev_msc_get_config_desc(msc_obj.dev_speed); TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_active_config_descriptor(msc_obj.dev_hdl, &config_desc)); TEST_ASSERT_EQUAL_MESSAGE(config_desc_ref->wTotalLength, config_desc->wTotalLength, "Incorrect length of CFG descriptor"); - TEST_ASSERT_EQUAL_MEMORY_MESSAGE(config_desc_ref, config_desc, config_desc_ref->wTotalLength, "Configuration descriptors do not match"); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(config_desc_ref, config_desc, sizeof(usb_config_desc_t), "Configuration descriptors do not match"); msc_obj.next_stage = TEST_STAGE_CHECK_STR_DESC; skip_event_handling = true; // Need to execute TEST_STAGE_CHECK_STR_DESC break; @@ -167,15 +149,15 @@ void msc_client_async_enum_task(void *arg) usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); // Check manufacturer string descriptors - const usb_str_desc_t *manu_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_manu; - const usb_str_desc_t *product_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_prod; - const usb_str_desc_t *ser_num_str_desc_ref = (const usb_str_desc_t *)mock_msc_scsi_str_desc_ser_num; + const usb_str_desc_t *manu_str_desc_ref = dev_msc_get_str_desc_manu(); + const usb_str_desc_t *product_str_desc_ref = dev_msc_get_str_desc_prod(); + const usb_str_desc_t *ser_num_str_desc_ref = dev_msc_get_str_desc_ser(); TEST_ASSERT_EQUAL(manu_str_desc_ref->bLength, dev_info.str_desc_manufacturer->bLength); TEST_ASSERT_EQUAL(product_str_desc_ref->bLength, dev_info.str_desc_product->bLength); TEST_ASSERT_EQUAL(ser_num_str_desc_ref->bLength, dev_info.str_desc_serial_num->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(manu_str_desc_ref, dev_info.str_desc_manufacturer, manu_str_desc_ref->bLength, "Manufacturer string descriptors do not match."); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(product_str_desc_ref, dev_info.str_desc_product, manu_str_desc_ref->bLength, "Product string descriptors do not match."); - // TEST_ASSERT_EQUAL_MEMORY_MESSAGE(ser_num_str_desc_ref, dev_info.str_desc_serial_num , manu_str_desc_ref->bLength, "Serial number string descriptors do not match."); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(ser_num_str_desc_ref, dev_info.str_desc_serial_num, manu_str_desc_ref->bLength, "Serial number string descriptors do not match."); // Get dev info and compare msc_obj.next_stage = TEST_STAGE_DEV_CLOSE; skip_event_handling = true; // Need to execute TEST_STAGE_DEV_CLOSE diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_seq.c b/components/usb/test_apps/usb_host/main/msc_client_async_seq.c index 7bb41f3919b..192012fb342 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_seq.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_seq.c @@ -14,6 +14,7 @@ #include "esp_log.h" #include "test_usb_common.h" #include "mock_msc.h" +#include "dev_msc.h" #include "msc_client.h" #include "usb/usb_host.h" #include "unity.h" @@ -46,14 +47,19 @@ typedef enum { } test_stage_t; typedef struct { + // Test parameters msc_client_test_param_t test_param; - test_stage_t cur_stage; - test_stage_t next_stage; - uint8_t dev_addr_to_open; + // MSC device info + const dev_msc_info_t *dev_info; + usb_speed_t dev_speed; + uint8_t dev_addr; + // Client variables usb_host_client_handle_t client_hdl; usb_device_handle_t dev_hdl; + // Test state + test_stage_t cur_stage; + test_stage_t next_stage; int num_sectors_read; - usb_speed_t dev_speed; } msc_client_obj_t; static void msc_transfer_cb(usb_transfer_t *transfer) @@ -77,7 +83,7 @@ static void msc_transfer_cb(usb_transfer_t *transfer) case TEST_STAGE_MSC_DATA: { // Check MSC SCSI data IN transfer TEST_ASSERT_EQUAL_MESSAGE(USB_TRANSFER_STATUS_COMPLETED, transfer->status, "Transfer NOT completed"); - TEST_ASSERT_EQUAL(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj->test_param.num_sectors_per_xfer, transfer->actual_num_bytes); + TEST_ASSERT_EQUAL(msc_obj->dev_info->scsi_sector_size * msc_obj->test_param.num_sectors_per_xfer, transfer->actual_num_bytes); msc_obj->next_stage = TEST_STAGE_MSC_CSW; break; } @@ -107,7 +113,7 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo case USB_HOST_CLIENT_EVENT_NEW_DEV: TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, msc_obj->cur_stage); msc_obj->next_stage = TEST_STAGE_DEV_OPEN; - msc_obj->dev_addr_to_open = event_msg->new_dev.address; + msc_obj->dev_addr = event_msg->new_dev.address; break; default: abort(); // Should never occur in this test @@ -119,12 +125,17 @@ static void msc_client_event_cb(const usb_host_client_event_msg_t *event_msg, vo void msc_client_async_seq_task(void *arg) { msc_client_obj_t msc_obj; + // Initialize test params memcpy(&msc_obj.test_param, arg, sizeof(msc_client_test_param_t)); - msc_obj.cur_stage = TEST_STAGE_WAIT_CONN; - msc_obj.next_stage = TEST_STAGE_WAIT_CONN; + // Initialize MSC device info + msc_obj.dev_info = dev_msc_get_info(); + // Initialize client variables msc_obj.client_hdl = NULL; - msc_obj.dev_addr_to_open = 0; msc_obj.dev_hdl = NULL; + // Initialize test state + msc_obj.cur_stage = TEST_STAGE_WAIT_CONN; + msc_obj.next_stage = TEST_STAGE_WAIT_CONN; + msc_obj.dev_addr = 0; msc_obj.num_sectors_read = 0; // Register client @@ -138,17 +149,10 @@ void msc_client_async_seq_task(void *arg) }; TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &msc_obj.client_hdl)); - // Allocate transfers - usb_transfer_t *xfer_out = NULL; // Must be large enough to contain CBW and MSC reset control transfer - usb_transfer_t *xfer_in = NULL; // Must be large enough to contain CSW and Data - size_t out_worst_case_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t)); - size_t in_worst_case_size = usb_round_up_to_mps(MAX(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, sizeof(mock_msc_bulk_csw_t)), MOCK_MSC_SCSI_BULK_EP_MPS_HS); - TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(out_worst_case_size, 0, &xfer_out)); - TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(in_worst_case_size, 0, &xfer_in)); - xfer_out->callback = msc_transfer_cb; - xfer_in->callback = msc_transfer_cb; - xfer_out->context = (void *)&msc_obj; - xfer_in->context = (void *)&msc_obj; + // IN MPS and transfers to be set/allocated later (after device connects and MPS is determined) + int in_ep_mps = 0; + usb_transfer_t *xfer_in = NULL; + usb_transfer_t *xfer_out = NULL; // Wait to be started by main thread ulTaskNotifyTake(pdTRUE, portMAX_DELAY); @@ -170,21 +174,44 @@ void msc_client_async_seq_task(void *arg) case TEST_STAGE_DEV_OPEN: { ESP_LOGD(MSC_CLIENT_TAG, "Open"); // Open the device - TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr_to_open, &msc_obj.dev_hdl)); - // Target our transfers to the device - xfer_out->device_handle = msc_obj.dev_hdl; - xfer_in->device_handle = msc_obj.dev_hdl; - // Check the VID/PID of the opened device - const usb_device_desc_t *device_desc; - TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); - TEST_ASSERT_EQUAL(msc_obj.test_param.idVendor, device_desc->idVendor); - TEST_ASSERT_EQUAL(msc_obj.test_param.idProduct, device_desc->idProduct); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_open(msc_obj.client_hdl, msc_obj.dev_addr, &msc_obj.dev_hdl)); // Get device info to get device speed usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); msc_obj.dev_speed = dev_info.speed; + // Check that the device descriptor matches our expected MSC device + const usb_device_desc_t *device_desc; + const usb_device_desc_t *device_desc_ref = dev_msc_get_dev_desc(msc_obj.dev_speed); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_device_descriptor(msc_obj.dev_hdl, &device_desc)); + TEST_ASSERT_EQUAL(device_desc_ref->bLength, device_desc->bLength); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(device_desc_ref, device_desc, sizeof(usb_device_desc_t), "Device descriptors do not match."); // Claim the MSC interface - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(msc_obj.client_hdl, + msc_obj.dev_hdl, + msc_obj.dev_info->bInterfaceNumber, + msc_obj.dev_info->bAlternateSetting)); + /* + Allocate transfers + + IN transfer must be large enough to contain CSW and Data + OUT transfer must be large enough to contain CBW and MSC reset control transfer + */ + const usb_ep_desc_t *in_ep_desc = dev_msc_get_in_ep_desc(msc_obj.dev_speed); + in_ep_mps = USB_EP_DESC_GET_MPS(in_ep_desc); + const size_t in_worst_case_size = usb_round_up_to_mps(MAX(msc_obj.dev_info->scsi_sector_size * msc_obj.test_param.num_sectors_per_xfer, + sizeof(mock_msc_bulk_csw_t)), + in_ep_mps); + const size_t out_worst_case_size = MAX(sizeof(mock_msc_bulk_cbw_t), sizeof(usb_setup_packet_t)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(out_worst_case_size, 0, &xfer_out)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_alloc(in_worst_case_size, 0, &xfer_in)); + xfer_out->callback = msc_transfer_cb; + xfer_in->callback = msc_transfer_cb; + xfer_out->context = (void *)&msc_obj; + xfer_in->context = (void *)&msc_obj; + // Target our transfers to the device + xfer_out->device_handle = msc_obj.dev_hdl; + xfer_in->device_handle = msc_obj.dev_hdl; + // Set next stage msc_obj.next_stage = TEST_STAGE_MSC_RESET; skip_event_handling = true; // Need to execute TEST_STAGE_MSC_RESET break; @@ -192,7 +219,7 @@ void msc_client_async_seq_task(void *arg) case TEST_STAGE_MSC_RESET: { ESP_LOGD(MSC_CLIENT_TAG, "MSC Reset"); // Send an MSC SCSI interface reset - MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, MOCK_MSC_SCSI_INTF_NUMBER); + MOCK_MSC_SCSI_REQ_INIT_RESET((usb_setup_packet_t *)xfer_out->data_buffer, msc_obj.dev_info->bInterfaceNumber); xfer_out->num_bytes = sizeof(usb_setup_packet_t); xfer_out->bEndpointAddress = 0; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit_control(msc_obj.client_hdl, xfer_out)); @@ -203,9 +230,14 @@ void msc_client_async_seq_task(void *arg) } case TEST_STAGE_MSC_CBW: { ESP_LOGD(MSC_CLIENT_TAG, "CBW"); - mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)xfer_out->data_buffer, true, msc_obj.next_stage, msc_obj.test_param.num_sectors_per_xfer, msc_obj.test_param.msc_scsi_xfer_tag); + mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)xfer_out->data_buffer, + true, + msc_obj.next_stage, + msc_obj.test_param.num_sectors_per_xfer, + msc_obj.dev_info->scsi_sector_size, + msc_obj.test_param.msc_scsi_xfer_tag); xfer_out->num_bytes = sizeof(mock_msc_bulk_cbw_t); - xfer_out->bEndpointAddress = MOCK_MSC_SCSI_BULK_OUT_EP_ADDR; + xfer_out->bEndpointAddress = msc_obj.dev_info->out_up_addr; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_out)); // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_out)); @@ -214,11 +246,8 @@ void msc_client_async_seq_task(void *arg) } case TEST_STAGE_MSC_DATA: { ESP_LOGD(MSC_CLIENT_TAG, "Data"); - const int bulk_ep_mps = (msc_obj.dev_speed == USB_SPEED_HIGH) - ? MOCK_MSC_SCSI_BULK_EP_MPS_HS - : MOCK_MSC_SCSI_BULK_EP_MPS_FS; - xfer_in->num_bytes = usb_round_up_to_mps(MOCK_MSC_SCSI_SECTOR_SIZE * msc_obj.test_param.num_sectors_per_xfer, bulk_ep_mps); - xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; + xfer_in->num_bytes = usb_round_up_to_mps(msc_obj.dev_info->scsi_sector_size * msc_obj.test_param.num_sectors_per_xfer, in_ep_mps); + xfer_in->bEndpointAddress = msc_obj.dev_info->in_ep_addr; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in)); // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_in)); @@ -227,11 +256,8 @@ void msc_client_async_seq_task(void *arg) } case TEST_STAGE_MSC_CSW: { ESP_LOGD(MSC_CLIENT_TAG, "CSW"); - const int bulk_ep_mps = (msc_obj.dev_speed == USB_SPEED_HIGH) - ? MOCK_MSC_SCSI_BULK_EP_MPS_HS - : MOCK_MSC_SCSI_BULK_EP_MPS_FS; - xfer_in->num_bytes = usb_round_up_to_mps(sizeof(mock_msc_bulk_csw_t), bulk_ep_mps); - xfer_in->bEndpointAddress = MOCK_MSC_SCSI_BULK_IN_EP_ADDR; + xfer_in->num_bytes = usb_round_up_to_mps(sizeof(mock_msc_bulk_csw_t), in_ep_mps); + xfer_in->bEndpointAddress = msc_obj.dev_info->in_ep_addr; TEST_ASSERT_EQUAL(ESP_OK, usb_host_transfer_submit(xfer_in)); // Test that an inflight transfer cannot be resubmitted TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_transfer_submit(xfer_in)); @@ -240,7 +266,7 @@ void msc_client_async_seq_task(void *arg) } case TEST_STAGE_DEV_CLOSE: { ESP_LOGD(MSC_CLIENT_TAG, "Close"); - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(msc_obj.client_hdl, msc_obj.dev_hdl, msc_obj.dev_info->bInterfaceNumber)); TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(msc_obj.client_hdl, msc_obj.dev_hdl)); exit_loop = true; break; diff --git a/components/usb/test_apps/usb_host/main/test_app_main.c b/components/usb/test_apps/usb_host/main/test_app_main.c index 3301425ab1e..93e2510374c 100644 --- a/components/usb/test_apps/usb_host/main/test_app_main.c +++ b/components/usb/test_apps/usb_host/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -7,17 +7,16 @@ #include "unity.h" #include "unity_test_runner.h" #include "unity_test_utils_memory.h" - #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "test_usb_common.h" -#include "mock_msc.h" +#include "dev_msc.h" #include "usb/usb_host.h" void setUp(void) { - mock_msc_scsi_init_reference_descriptors(); unity_utils_record_free_mem(); + dev_msc_init(); test_usb_init_phy(); // Initialize the internal USB PHY and USB Controller for testing // Install USB Host usb_host_config_t host_config = { diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_async.c b/components/usb/test_apps/usb_host/main/test_usb_host_async.c index b132bcfc84b..c7329d91fa1 100644 --- a/components/usb/test_apps/usb_host/main/test_usb_host_async.c +++ b/components/usb/test_apps/usb_host/main/test_usb_host_async.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,7 +11,7 @@ #include "esp_err.h" #include "esp_intr_alloc.h" #include "test_usb_common.h" -#include "mock_msc.h" +#include "dev_msc.h" #include "msc_client.h" #include "ctrl_client.h" #include "usb/usb_host.h" @@ -51,8 +51,6 @@ TEST_CASE("Test USB Host async client (single client)", "[usb_host][full_speed][ .num_sectors_to_read = TEST_MSC_NUM_SECTORS_TOTAL, .num_sectors_per_xfer = TEST_MSC_NUM_SECTORS_PER_XFER, .msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG, - .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, - .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, }; TaskHandle_t task_hdl; xTaskCreatePinnedToCore(msc_client_async_seq_task, "async", 4096, (void *)¶ms, 2, &task_hdl, 0); @@ -101,8 +99,6 @@ TEST_CASE("Test USB Host async client (multi client)", "[usb_host][full_speed][h .num_sectors_to_read = TEST_MSC_NUM_SECTORS_TOTAL, .num_sectors_per_xfer = TEST_MSC_NUM_SECTORS_PER_XFER, .msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG, - .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, - .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, }; TaskHandle_t msc_task_hdl; xTaskCreatePinnedToCore(msc_client_async_seq_task, "msc", 4096, (void *)&msc_params, 2, &msc_task_hdl, 0); @@ -111,8 +107,6 @@ TEST_CASE("Test USB Host async client (multi client)", "[usb_host][full_speed][h // Create task a control transfer client ctrl_client_test_param_t ctrl_params = { .num_ctrl_xfer_to_send = TEST_CTRL_NUM_TRANSFERS, - .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, - .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, }; TaskHandle_t ctrl_task_hdl; xTaskCreatePinnedToCore(ctrl_client_async_seq_task, "ctrl", 4096, (void *)&ctrl_params, 2, &ctrl_task_hdl, 0); @@ -226,21 +220,35 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, 0, &client0_dev_hdl)); // Check that the device cannot be opened again by the same client + const dev_msc_info_t *dev_info = dev_msc_get_info(); usb_device_handle_t dummy_dev_hdl; TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client0_hdl, dev_addr, &dummy_dev_hdl)); TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_device_open(client1_hdl, dev_addr, &dummy_dev_hdl)); printf("Claiming interface\n"); // Check that both clients cannot claim the same interface - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); - TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client1_hdl, client1_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, + client0_dev_hdl, + dev_info->bInterfaceNumber, + dev_info->bAlternateSetting)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client1_hdl, + client1_dev_hdl, + dev_info->bInterfaceNumber, + dev_info->bAlternateSetting)); // Check that client0 cannot claim the same interface multiple times - TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER, MOCK_MSC_SCSI_INTF_ALT_SETTING)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_claim(client0_hdl, + client0_dev_hdl, + dev_info->bInterfaceNumber, + dev_info->bAlternateSetting)); printf("Releasing interface\n"); // Check that client0 can release the interface - TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, + client0_dev_hdl, + dev_info->bInterfaceNumber)); // Check that client0 cannot release interface it has not claimed - TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, client0_dev_hdl, MOCK_MSC_SCSI_INTF_NUMBER)); + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_host_interface_release(client0_hdl, + client0_dev_hdl, + dev_info->bInterfaceNumber)); // Wait until the device disconnects and the clients receive the event test_usb_set_phy_state(false, 0); diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c b/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c index 6be17aa848a..263898c0de9 100644 --- a/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c +++ b/components/usb/test_apps/usb_host/main/test_usb_host_plugging.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "esp_intr_alloc.h" #include "test_usb_common.h" #include "mock_msc.h" +#include "dev_msc.h" #include "msc_client.h" #include "ctrl_client.h" #include "usb/usb_host.h" @@ -84,12 +85,11 @@ Test USB Host Library Sudden Disconnection Handling (with client) TEST_CASE("Test USB Host sudden disconnection (single client)", "[usb_host][full_speed]") { // Create task to run client that communicates with MSC SCSI interface + const dev_msc_info_t *dev_info = dev_msc_get_info(); msc_client_test_param_t params = { .num_sectors_to_read = 1, // Unused by disconnect MSC client - .num_sectors_per_xfer = TEST_FORCE_DCONN_NUM_TRANSFERS * MOCK_MSC_SCSI_SECTOR_SIZE, + .num_sectors_per_xfer = TEST_FORCE_DCONN_NUM_TRANSFERS * dev_info->scsi_sector_size, .msc_scsi_xfer_tag = TEST_MSC_SCSI_TAG, - .idVendor = MOCK_MSC_SCSI_DEV_ID_VENDOR, - .idProduct = MOCK_MSC_SCSI_DEV_ID_PRODUCT, }; TaskHandle_t task_hdl; xTaskCreatePinnedToCore(msc_client_async_dconn_task, "async", 4096, (void *)¶ms, 2, &task_hdl, 0); From 6192507987831957b5863116c2d0fee4be0c743c Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 30 May 2024 19:25:18 +0800 Subject: [PATCH 198/548] fix(usb): Make string descriptor checks in unit tests optional Checking for an exact match for product or serial and string descriptors can lead to test failures if the USB devices connected to the runner is changed. This commit adds some kconfig options to make the string descriptor checks optional, with the product and serial string checks being disabled by default. --- .../test_apps/usb_host/main/Kconfig.projbuild | 24 +++++++++++++++++++ .../usb_host/main/msc_client_async_enum.c | 17 +++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 components/usb/test_apps/usb_host/main/Kconfig.projbuild diff --git a/components/usb/test_apps/usb_host/main/Kconfig.projbuild b/components/usb/test_apps/usb_host/main/Kconfig.projbuild new file mode 100644 index 00000000000..8706cdd15da --- /dev/null +++ b/components/usb/test_apps/usb_host/main/Kconfig.projbuild @@ -0,0 +1,24 @@ +menu "USB Host Library Test" + + config USB_HOST_TEST_CHECK_MANU_STR + bool "Check manufacturer string descriptor" + default y + help + USB Host tests that check string descriptors will check the manufacturer string + descriptor of the connected device. + + config USB_HOST_TEST_CHECK_PROD_STR + bool "Check product string descriptor" + default n + help + USB Host tests that check string descriptors will check the product string descriptor + of the connected device. + + config USB_HOST_TEST_CHECK_SERIAL_STR + bool "Check serial string descriptor" + default n + help + USB Host tests that check string descriptors will check the serial string descriptor + of the connected device. + +endmenu diff --git a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c index e33ad0ad367..68c78386476 100644 --- a/components/usb/test_apps/usb_host/main/msc_client_async_enum.c +++ b/components/usb/test_apps/usb_host/main/msc_client_async_enum.c @@ -146,19 +146,26 @@ void msc_client_async_enum_task(void *arg) break; } case TEST_STAGE_CHECK_STR_DESC: { + // Get dev info and compare usb_device_info_t dev_info; TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(msc_obj.dev_hdl, &dev_info)); +#if CONFIG_USB_HOST_TEST_CHECK_MANU_STR // Check manufacturer string descriptors const usb_str_desc_t *manu_str_desc_ref = dev_msc_get_str_desc_manu(); - const usb_str_desc_t *product_str_desc_ref = dev_msc_get_str_desc_prod(); - const usb_str_desc_t *ser_num_str_desc_ref = dev_msc_get_str_desc_ser(); TEST_ASSERT_EQUAL(manu_str_desc_ref->bLength, dev_info.str_desc_manufacturer->bLength); - TEST_ASSERT_EQUAL(product_str_desc_ref->bLength, dev_info.str_desc_product->bLength); - TEST_ASSERT_EQUAL(ser_num_str_desc_ref->bLength, dev_info.str_desc_serial_num->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(manu_str_desc_ref, dev_info.str_desc_manufacturer, manu_str_desc_ref->bLength, "Manufacturer string descriptors do not match."); +#endif // CONFIG_USB_HOST_TEST_CHECK_MANU_STR +#if CONFIG_USB_HOST_TEST_CHECK_PROD_STR + const usb_str_desc_t *product_str_desc_ref = dev_msc_get_str_desc_prod(); + TEST_ASSERT_EQUAL(product_str_desc_ref->bLength, dev_info.str_desc_product->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(product_str_desc_ref, dev_info.str_desc_product, manu_str_desc_ref->bLength, "Product string descriptors do not match."); +#endif // CONFIG_USB_HOST_TEST_CHECK_PROD_STR +#if CONFIG_USB_HOST_TEST_CHECK_SERIAL_STR + const usb_str_desc_t *ser_num_str_desc_ref = dev_msc_get_str_desc_ser(); + TEST_ASSERT_EQUAL(ser_num_str_desc_ref->bLength, dev_info.str_desc_serial_num->bLength); TEST_ASSERT_EQUAL_MEMORY_MESSAGE(ser_num_str_desc_ref, dev_info.str_desc_serial_num, manu_str_desc_ref->bLength, "Serial number string descriptors do not match."); - // Get dev info and compare +#endif // CONFIG_USB_HOST_TEST_CHECK_SERIAL_STR + (void) dev_info; // Unused if all string descriptor checks are disabled msc_obj.next_stage = TEST_STAGE_DEV_CLOSE; skip_event_handling = true; // Need to execute TEST_STAGE_DEV_CLOSE break; From fccc309499c405836073c847c35311f5590e6382 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 10 Jun 2024 03:28:52 +0800 Subject: [PATCH 199/548] fix(jpeg): Modify jpeg deocde/encode error handling logic (backport v5.3) --- components/esp_driver_jpeg/jpeg_decode.c | 27 ++++++++++++++--------- components/esp_driver_jpeg/jpeg_encode.c | 28 +++++++++++++++--------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_jpeg/jpeg_decode.c b/components/esp_driver_jpeg/jpeg_decode.c index 6ab993c616f..90b1632e415 100644 --- a/components/esp_driver_jpeg/jpeg_decode.c +++ b/components/esp_driver_jpeg/jpeg_decode.c @@ -217,12 +217,12 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_ decoder_engine->conv_std = decode_cfg->conv_std; decoder_engine->decoded_buf = decode_outbuf; - ESP_GOTO_ON_ERROR(jpeg_parse_marker(decoder_engine, bit_stream, stream_size), err, TAG, "jpeg parse marker failed"); - ESP_GOTO_ON_ERROR(jpeg_parse_header_info_to_hw(decoder_engine), err, TAG, "write header info to hw failed"); - ESP_GOTO_ON_ERROR(jpeg_dec_config_dma_descriptor(decoder_engine), err, TAG, "config dma descriptor failed"); + ESP_GOTO_ON_ERROR(jpeg_parse_marker(decoder_engine, bit_stream, stream_size), err2, TAG, "jpeg parse marker failed"); + ESP_GOTO_ON_ERROR(jpeg_parse_header_info_to_hw(decoder_engine), err2, TAG, "write header info to hw failed"); + ESP_GOTO_ON_ERROR(jpeg_dec_config_dma_descriptor(decoder_engine), err2, TAG, "config dma descriptor failed"); *out_size = decoder_engine->header_info->process_h * decoder_engine->header_info->process_v * decoder_engine->bit_per_pixel / 8; - ESP_GOTO_ON_FALSE((*out_size <= outbuf_size), ESP_ERR_INVALID_ARG, err, TAG, "Given buffer size % " PRId32 " is smaller than actual jpeg decode output size % " PRId32 "the height and width of output picture size will be adjusted to 16 bytes aligned automatically", outbuf_size, *out_size); + ESP_GOTO_ON_FALSE((*out_size <= outbuf_size), ESP_ERR_INVALID_ARG, err2, TAG, "Given buffer size % " PRId32 " is smaller than actual jpeg decode output size % " PRId32 "the height and width of output picture size will be adjusted to 16 bytes aligned automatically", outbuf_size, *out_size); dma2d_trans_config_t trans_desc = { .tx_channel_num = 1, @@ -236,21 +236,20 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_ ret = esp_cache_msync((void*)decoder_engine->header_info->buffer_offset, decoder_engine->header_info->buffer_left, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); assert(ret == ESP_OK); - ESP_GOTO_ON_ERROR(dma2d_enqueue(decoder_engine->dma2d_group_handle, &trans_desc, decoder_engine->trans_desc), err, TAG, "enqueue dma2d failed"); + ESP_GOTO_ON_ERROR(dma2d_enqueue(decoder_engine->dma2d_group_handle, &trans_desc, decoder_engine->trans_desc), err2, TAG, "enqueue dma2d failed"); bool need_yield; // Blocking for JPEG decode transaction finishes. while (1) { jpeg_dma2d_dec_evt_t jpeg_dma2d_event; BaseType_t ret_val = xQueueReceive(decoder_engine->evt_queue, &jpeg_dma2d_event, decoder_engine->timeout_tick); - ESP_GOTO_ON_FALSE(ret_val == pdTRUE, ESP_ERR_TIMEOUT, err, TAG, "jpeg-dma2d handle jpeg decode timeout, please check `timeout_ms` "); + ESP_GOTO_ON_FALSE(ret_val == pdTRUE, ESP_ERR_TIMEOUT, err1, TAG, "jpeg-dma2d handle jpeg decode timeout, please check image accuracy and `timeout_ms` "); // Dealing with JPEG event if (jpeg_dma2d_event.jpgd_status != 0) { uint32_t status = jpeg_dma2d_event.jpgd_status; s_decoder_error_log_print(status); - dma2d_force_end(decoder_engine->trans_desc, &need_yield); - xSemaphoreGive(decoder_engine->codec_base->codec_mutex); - return ESP_ERR_INVALID_STATE; + ret = ESP_ERR_INVALID_STATE; + goto err1; } if (jpeg_dma2d_event.dma_evt & JPEG_DMA2D_RX_EOF) { @@ -260,11 +259,19 @@ esp_err_t jpeg_decoder_process(jpeg_decoder_handle_t decoder_engine, const jpeg_ } } -err: xSemaphoreGive(decoder_engine->codec_base->codec_mutex); if (decoder_engine->codec_base->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_release(decoder_engine->codec_base->pm_lock), TAG, "release pm_lock failed"); } + return ESP_OK; + +err1: + dma2d_force_end(decoder_engine->trans_desc, &need_yield); +err2: + xSemaphoreGive(decoder_engine->codec_base->codec_mutex); + if (decoder_engine->codec_base->pm_lock) { + esp_pm_lock_release(decoder_engine->codec_base->pm_lock); + } return ret; } diff --git a/components/esp_driver_jpeg/jpeg_encode.c b/components/esp_driver_jpeg/jpeg_encode.c index e0b959691bf..9a6cb6f364f 100644 --- a/components/esp_driver_jpeg/jpeg_encode.c +++ b/components/esp_driver_jpeg/jpeg_encode.c @@ -186,7 +186,7 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ default: ESP_LOGE(TAG, "wrong, we don't support encode from such format."); ret = ESP_ERR_NOT_SUPPORTED; - goto err; + goto err2; } encoder_engine->header_info->sub_sample = encode_cfg->sub_sample; encoder_engine->header_info->quality = encode_cfg->image_quality; @@ -202,7 +202,7 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ jpeg_ll_add_tail(hal->dev, true); jpeg_ll_enable_ff_check(hal->dev, true); jpeg_ll_set_qnr_presition(hal->dev, 0); - ESP_GOTO_ON_ERROR(s_jpeg_set_header_info(encoder_engine), err, TAG, "set header failed"); + ESP_GOTO_ON_ERROR(s_jpeg_set_header_info(encoder_engine), err2, TAG, "set header failed"); jpeg_hal_set_quantization_coefficient(hal, encoder_engine->header_info->m_quantization_tables[0], encoder_engine->header_info->m_quantization_tables[1]); uint8_t sample_method_idx = 0; @@ -227,7 +227,7 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ uint32_t dma_hb = enc_hb_tbl[best_hb_idx][sample_method_idx]; uint32_t dma_vb = encoder_engine->mcuy; - ESP_GOTO_ON_FALSE((encoder_engine->header_info->header_len % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_STATE, err, TAG, "The header is not cache line aligned, please check"); + ESP_GOTO_ON_FALSE((encoder_engine->header_info->header_len % cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)) == 0, ESP_ERR_INVALID_STATE, err2, TAG, "The header is not cache line aligned, please check"); // 1D direction memset(encoder_engine->rxlink, 0, sizeof(dma2d_descriptor_t)); @@ -248,24 +248,24 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ .on_job_picked = s_jpeg_enc_transaction_on_job_picked, }; - ESP_GOTO_ON_ERROR(dma2d_enqueue(encoder_engine->dma2d_group_handle, &trans_desc, encoder_engine->trans_desc), err, TAG, "DMA2D enqueue failed"); - + ESP_GOTO_ON_ERROR(dma2d_enqueue(encoder_engine->dma2d_group_handle, &trans_desc, encoder_engine->trans_desc), err2, TAG, "DMA2D enqueue failed"); + bool need_yield; while (1) { jpeg_enc_dma2d_evt_t s_rcv_event; BaseType_t ret_val = xQueueReceive(encoder_engine->evt_queue, &s_rcv_event, encoder_engine->timeout_tick); - ESP_GOTO_ON_FALSE(ret_val == pdTRUE, ESP_ERR_TIMEOUT, err, TAG, "jpeg-dma2d handle jpeg decode timeout, please check `timeout_ms`"); + ESP_GOTO_ON_FALSE(ret_val == pdTRUE, ESP_ERR_TIMEOUT, err1, TAG, "jpeg-dma2d handle jpeg decode timeout, please check image accuracy and `timeout_ms`"); if (s_rcv_event.encoder_status != 0) { s_encoder_error_log_print(s_rcv_event.encoder_status); ret = ESP_ERR_INVALID_STATE; - goto err; + goto err1; } if (s_rcv_event.dma_evt & JPEG_DMA2D_RX_EOF) { - ESP_GOTO_ON_ERROR(esp_cache_msync((void*)encoder_engine->rxlink, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "sync memory to cache failed"); + ESP_GOTO_ON_ERROR(esp_cache_msync((void*)encoder_engine->rxlink, encoder_engine->dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err1, TAG, "sync memory to cache failed"); compressed_size = s_dma_desc_get_len(encoder_engine->rxlink); uint32_t _compressed_size = JPEG_ALIGN_UP(compressed_size, cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA)); - ESP_GOTO_ON_ERROR(esp_cache_msync((void*)(bit_stream + encoder_engine->header_info->header_len), _compressed_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "sync memory to cache failed"); + ESP_GOTO_ON_ERROR(esp_cache_msync((void*)(bit_stream + encoder_engine->header_info->header_len), _compressed_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err1, TAG, "sync memory to cache failed"); break; } } @@ -273,11 +273,19 @@ esp_err_t jpeg_encoder_process(jpeg_encoder_handle_t encoder_engine, const jpeg_ compressed_size += encoder_engine->header_info->header_len; *out_size = compressed_size; -err: xSemaphoreGive(encoder_engine->codec_base->codec_mutex); if (encoder_engine->codec_base->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_release(encoder_engine->codec_base->pm_lock), TAG, "release pm_lock failed"); } + return ESP_OK; + +err1: + dma2d_force_end(encoder_engine->trans_desc, &need_yield); +err2: + xSemaphoreGive(encoder_engine->codec_base->codec_mutex); + if (encoder_engine->codec_base->pm_lock) { + esp_pm_lock_release(encoder_engine->codec_base->pm_lock); + } return ret; } From c23dbefd455cea5c764b61c62af4410a29d3960e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Fri, 24 May 2024 12:17:00 +0200 Subject: [PATCH 200/548] fix(storage/vfs_console): remove possible infinite recursion --- components/esp_vfs_console/vfs_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_vfs_console/vfs_console.c b/components/esp_vfs_console/vfs_console.c index b071d521ad8..980514c1d46 100644 --- a/components/esp_vfs_console/vfs_console.c +++ b/components/esp_vfs_console/vfs_console.c @@ -73,7 +73,7 @@ ssize_t console_write(int fd, const void *data, size_t size) int console_fstat(int fd, struct stat * st) { - return fstat(fd, st); + return fstat(vfs_console.fd_primary, st); } int console_close(int fd) From 05f44bddf04bfb3d282a7910fefe2093fb721e41 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 15 May 2024 18:53:04 +0800 Subject: [PATCH 201/548] feat(isp): added isp dvp driver --- components/esp_driver_cam/CMakeLists.txt | 26 +- components/esp_driver_cam/Kconfig | 20 +- .../csi/include/esp_cam_ctlr_csi.h | 9 +- .../esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 7 +- components/esp_driver_cam/dvp_share_ctrl.c | 36 ++ components/esp_driver_cam/dvp_share_ctrl.h | 28 + .../include/esp_cam_ctlr_types.h | 5 + .../isp_dvp/include/esp_cam_ctlr_isp_dvp.h | 59 ++ .../isp_dvp/src/esp_cam_ctlr_isp_dvp.c | 568 ++++++++++++++++++ .../test_apps/csi/main/test_csi_driver.c | 8 +- .../test_apps/isp_dvp/sdkconfig.defaults | 6 + components/esp_driver_isp/CMakeLists.txt | 13 +- .../esp_driver_isp/include/driver/isp_af.h | 22 +- .../esp_driver_isp/include/driver/isp_types.h | 2 +- .../esp_private/isp_private.h} | 27 +- components/esp_driver_isp/src/isp_af.c | 32 +- components/esp_driver_isp/src/isp_bf.c | 2 +- components/esp_driver_isp/src/isp_core.c | 9 +- .../test_apps/isp/main/CMakeLists.txt | 1 + .../test_apps/isp/main/test_isp_driver.c | 45 +- .../test_apps/isp/sdkconfig.defaults | 3 + .../port/esp32p4/esp_clk_tree.c | 2 +- components/hal/esp32p4/include/hal/isp_ll.h | 131 ++++ components/hal/include/hal/cam_ctlr_types.h | 42 ++ components/hal/include/hal/isp_types.h | 9 + components/hal/include/hal/mipi_csi_types.h | 15 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 + components/soc/esp32p4/include/soc/soc_caps.h | 3 + components/soc/esp32p4/isp_periph.c | 26 + components/soc/include/soc/isp_periph.h | 8 + .../peripherals/camera_driver.rst | 8 +- docs/en/api-reference/peripherals/isp.rst | 8 +- .../components/dsi_init/CMakeLists.txt | 2 +- .../components/dsi_init/Kconfig.projbuild | 25 + .../components/dsi_init/example_dsi_init.c | 5 +- .../components/dsi_init/idf_component.yml | 2 +- .../dsi_init/include}/example_dsi_init.h | 13 +- .../include/example_dsi_init_config.h | 22 + .../camera/camera_dsi/main/CMakeLists.txt | 2 +- .../camera/camera_dsi/main/camera_dsi_main.c | 9 +- .../camera/camera_dsi/main/idf_component.yml | 2 +- .../isp_af_schemes/include/isp_af_scheme_sa.h | 2 +- .../isp_af_schemes/src/isp_af_scheme_sa.c | 4 +- .../isp/auto_focus/main/idf_component.yml | 2 +- .../isp/auto_focus/main/isp_af_dsi_main.c | 13 +- 45 files changed, 1176 insertions(+), 119 deletions(-) create mode 100644 components/esp_driver_cam/dvp_share_ctrl.c create mode 100644 components/esp_driver_cam/dvp_share_ctrl.h create mode 100644 components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h create mode 100644 components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults rename components/esp_driver_isp/{src/isp_internal.h => include/esp_private/isp_private.h} (70%) create mode 100644 components/hal/include/hal/cam_ctlr_types.h rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/CMakeLists.txt (71%) create mode 100644 examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/example_dsi_init.c (94%) rename examples/peripherals/camera/{ => camera_dsi}/components/dsi_init/idf_component.yml (53%) rename examples/peripherals/camera/{components/dsi_init => camera_dsi/components/dsi_init/include}/example_dsi_init.h (68%) create mode 100644 examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h diff --git a/components/esp_driver_cam/CMakeLists.txt b/components/esp_driver_cam/CMakeLists.txt index b6a0c4dee40..17ac846f644 100644 --- a/components/esp_driver_cam/CMakeLists.txt +++ b/components/esp_driver_cam/CMakeLists.txt @@ -1,13 +1,29 @@ -set(srcs "esp_cam_ctlr.c") +idf_build_get_property(target IDF_TARGET) -set(include "include" "interface") +set(srcs "esp_cam_ctlr.c" "dvp_share_ctrl.c") + +set(includes "include" "interface") + +set(requires "esp_driver_isp") + +set(priv_requires "esp_driver_gpio") if(CONFIG_SOC_MIPI_CSI_SUPPORTED) list(APPEND srcs "csi/src/esp_cam_ctlr_csi.c") - list(APPEND include "csi/include") + list(APPEND includes "csi/include") +endif() + +if(CONFIG_SOC_ISP_DVP_SUPPORTED) + list(APPEND srcs "isp_dvp/src/esp_cam_ctlr_isp_dvp.c") + list(APPEND includes "isp_dvp/include") +endif() + +if(NOT ${target} STREQUAL "linux") + list(APPEND requires esp_mm) endif() idf_component_register(SRCS ${srcs} - INCLUDE_DIRS ${include} - PRIV_REQUIRES esp_mm + INCLUDE_DIRS ${includes} + REQUIRES ${requires} + PRIV_REQUIRES ${priv_requires} ) diff --git a/components/esp_driver_cam/Kconfig b/components/esp_driver_cam/Kconfig index f7b3ceaa6b8..771fd0e6aba 100644 --- a/components/esp_driver_cam/Kconfig +++ b/components/esp_driver_cam/Kconfig @@ -1,11 +1,27 @@ -menu "ESP Camera Controller Configurations" +menu "ESP-Driver:Camera Controller Configurations" + depends on SOC_MIPI_CSI_SUPPORTED - config MIPI_CSI_ISR_IRAM_SAFE + config CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE bool "CSI ISR IRAM-Safe" default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM help Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler will be available when the cache is disabled. + config CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE + bool "ISP_DVP ISR IRAM-Safe" + default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM + help + Ensure the ISP_DVP driver ISR is IRAM-Safe. When enabled, the ISR handler + will be available when the cache is disabled. + endmenu # ESP Camera Controller Configurations diff --git a/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h b/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h index fa63b5fc048..18eed2e00cc 100644 --- a/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h +++ b/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h @@ -15,11 +15,6 @@ extern "C" { #endif -/** - * @brief ESP CAM controller max timeout value - */ -#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX - /** * @brief ESP CAM CSI controller configurations */ @@ -30,8 +25,8 @@ typedef struct { uint32_t v_res; ///< Input vertical resolution, i.e. the number of lines in a frame uint8_t data_lane_num; ///< Data lane num int lane_bit_rate_mbps; ///< Lane bit rate in Mbps - mipi_csi_color_t input_data_color_type; ///< Input color type - mipi_csi_color_t output_data_color_type; ///< Output color type + cam_ctlr_color_t input_data_color_type; ///< Input color type + cam_ctlr_color_t output_data_color_type; ///< Output color type int queue_items; ///< Queue items struct { uint32_t byte_swap_en : 1; ///< Enable byte swap diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 6c297f1b9c5..6c7951ace35 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -24,7 +24,7 @@ #include "esp_private/esp_cache_private.h" #include "esp_cache.h" -#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE #define CSI_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else #define CSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT @@ -66,7 +66,6 @@ static esp_err_t s_csi_claim_controller(csi_controller_t *controller) mipi_csi_ll_enable_host_bus_clock(i, 1); mipi_csi_ll_reset_host_clock(i); } - _lock_release(&s_platform.mutex); break; } } @@ -295,7 +294,7 @@ static esp_err_t s_csi_ctlr_get_buffer_length(esp_cam_ctlr_handle_t handle, size return ESP_OK; } -static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) +IRAM_ATTR static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) { bool need_yield = false; BaseType_t high_task_woken = pdFALSE; @@ -381,7 +380,7 @@ esp_err_t s_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base); ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "driver starts already, not allow cbs register"); -#if CONFIG_MIPI_CSI_ISR_IRAM_SAFE +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE if (cbs->on_get_new_trans) { ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM"); } diff --git a/components/esp_driver_cam/dvp_share_ctrl.c b/components/esp_driver_cam/dvp_share_ctrl.c new file mode 100644 index 00000000000..60d080e6d40 --- /dev/null +++ b/components/esp_driver_cam/dvp_share_ctrl.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" + +bool dvp_signal_used; +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; + +esp_err_t dvp_shared_ctrl_claim_io_signals(void) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + portENTER_CRITICAL(&s_spinlock); + if (!dvp_signal_used) { + dvp_signal_used = true; + ret = ESP_OK; + } + portEXIT_CRITICAL(&s_spinlock); + + return ret; +} + +esp_err_t dvp_shared_ctrl_declaim_io_signals(void) +{ + portENTER_CRITICAL(&s_spinlock); + dvp_signal_used = false; + portEXIT_CRITICAL(&s_spinlock); + + return ESP_OK; +} diff --git a/components/esp_driver_cam/dvp_share_ctrl.h b/components/esp_driver_cam/dvp_share_ctrl.h new file mode 100644 index 00000000000..3f321fc7eba --- /dev/null +++ b/components/esp_driver_cam/dvp_share_ctrl.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Claim DVP IO signal usage + */ +esp_err_t dvp_shared_ctrl_claim_io_signals(void); + +/** + * @brief Declaim DVP IO signal usage + */ +esp_err_t dvp_shared_ctrl_declaim_io_signals(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/include/esp_cam_ctlr_types.h b/components/esp_driver_cam/include/esp_cam_ctlr_types.h index c215d219966..5dae1bc5db0 100644 --- a/components/esp_driver_cam/include/esp_cam_ctlr_types.h +++ b/components/esp_driver_cam/include/esp_cam_ctlr_types.h @@ -14,6 +14,11 @@ extern "C" { #endif +/** + * @brief ESP CAM controller max timeout value + */ +#define ESP_CAM_CTLR_MAX_DELAY UINT32_MAX + /** * @brief ESP CAM controller handle */ diff --git a/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h b/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h new file mode 100644 index 00000000000..a0cbbc9ca7d --- /dev/null +++ b/components/esp_driver_cam/isp_dvp/include/esp_cam_ctlr_isp_dvp.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "driver/isp_types.h" +#include "hal/cam_ctlr_types.h" +#include "esp_cam_ctlr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ESP CAM ISP DVP controller configurations + */ +typedef struct { + cam_ctlr_data_width_t data_width; ///< Number of data lines + int data_io[ISP_DVP_DATA_SIG_NUM]; ///< ISP DVP data-in IO numbers + int pclk_io; ///< ISP DVP pclk IO numbers + int hsync_io; ///< ISP DVP hsync IO numbers + int vsync_io; ///< ISP DVP vsync IO numbers + int de_io; ///< ISP DVP de IO numbers + struct { + uint32_t pclk_invert: 1; ///< The pclk is inverted + uint32_t hsync_invert: 1; ///< The hsync signal is inverted + uint32_t vsync_invert: 1; ///< The vsync signal is inverted + uint32_t de_invert: 1; ///< The de signal is inverted + } io_flags; ///< ISP DVP IO flags + int queue_items; ///< Queue items + struct { + uint32_t byte_swap_en : 1; ///< Enable byte swap + uint32_t bk_buffer_dis : 1; ///< Disable backup buffer + }; +} esp_cam_ctlr_isp_dvp_cfg_t; + +/** + * @brief New ESP CAM ISP DVP controller + * + * @param[in] ctlr_config ISP DVP controller configurations + * @param[out] ret_handle Returned ESP CAM controller handle + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: Out of memory + * - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types + * - ESP_ERR_NOT_FOUND: ISP DVP is registered already + */ +esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c new file mode 100644 index 00000000000..852b35aba1f --- /dev/null +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -0,0 +1,568 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "freertos/idf_additions.h" +#include "driver/isp_types.h" +#include "driver/gpio.h" +#include "hal/isp_hal.h" +#include "hal/gpio_hal.h" +#include "hal/isp_ll.h" +#include "hal/mipi_csi_brg_ll.h" +#include "hal/mipi_csi_ll.h" +#include "hal/color_hal.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/isp_private.h" +#include "esp_private/esp_cache_private.h" +#include "esp_private/mipi_csi_share_hw_ctrl.h" +#include "esp_private/dw_gdma.h" +#include "esp_cam_ctlr_types.h" +#include "esp_cam_ctlr_interface.h" +#include "esp_cache.h" +#include "esp_cam_ctlr_isp_dvp.h" +#include "../../dvp_share_ctrl.h" + +#if CONFIG_CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE +#define ISP_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define ISP_DVP_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif + +typedef struct isp_dvp_controller_t { + int id; //dvp id + isp_fsm_t fsm; //finite state machine + portMUX_TYPE spinlock; //spinlock + isp_processor_t *isp_proc; //isp processor + int in_bpp; //input data type, bit per pixel + int out_bpp; //output data type, bit per pixel + size_t fb_size_in_bytes; //Frame buffer size, in bytes + esp_cam_ctlr_trans_t trans; //Saved done transaction to be given out to callers + void *backup_buffer; //backup buffer to make csi bridge can work to avoid wrong state + bool bk_buffer_exposed; //status of if back_buffer is exposed to users + bool bk_buffer_dis; //allow to not malloc backup_buffer + QueueHandle_t trans_que; //transaction queue + esp_cam_ctlr_evt_cbs_t cbs; //user callbacks + void *cbs_user_data; //callback userdata + dw_gdma_channel_handle_t dma_chan; //dwgdma channel handle + size_t dvp_transfer_size; //csi transfer size for dwgdma + bool isr_installed; //is isr installed + esp_cam_ctlr_t base; +} isp_dvp_controller_t; + +typedef struct isp_dvp_ctx_t { + _lock_t mutex; + isp_dvp_controller_t *dvp_ctlr[SOC_ISP_DVP_CTLR_NUMS]; +} isp_dvp_ctx_t; + +static const char *TAG = "ISP_DVP"; +static isp_dvp_ctx_t s_ctx; + +static esp_err_t s_isp_io_init(isp_dvp_controller_t *dvp_ctlr, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config); +static esp_err_t s_isp_claim_dvp_controller(isp_proc_handle_t isp_proc, isp_dvp_controller_t *dvp_ctlr); +static esp_err_t s_isp_declaim_dvp_controller(isp_dvp_controller_t *dvp_ctlr); +static esp_err_t s_isp_del_dvp_controller(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...); +static esp_err_t s_isp_dvp_get_frame_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len); +static esp_err_t s_isp_dvp_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data); +static esp_err_t s_isp_dvp_enable(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_disable(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_stop(esp_cam_ctlr_handle_t handle); +static esp_err_t s_isp_dvp_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms); +static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data); + +esp_err_t esp_cam_new_isp_dvp_ctlr(isp_proc_handle_t isp_proc, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config, esp_cam_ctlr_handle_t *ret_handle) +{ + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE(isp_proc && ctlr_config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + isp_dvp_controller_t *dvp_ctlr = heap_caps_calloc(1, sizeof(isp_dvp_controller_t), ISP_DVP_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(dvp_ctlr, ESP_ERR_NO_MEM, TAG, "no mem for isp dvp controller"); + + dvp_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + dvp_ctlr->isp_proc = isp_proc; + +#if SOC_ISP_SHARE_CSI_BRG + ESP_GOTO_ON_ERROR(mipi_csi_brg_claim(MIPI_CSI_BRG_USER_ISP_DVP, &isp_proc->csi_brg_id), err, TAG, "csi bridge is in use already"); +#endif + //claim an DVP controller + ESP_GOTO_ON_ERROR(s_isp_claim_dvp_controller(isp_proc, dvp_ctlr), err, TAG, "no available controller"); + ESP_GOTO_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), err, TAG, "failed to claim io signals"); + ESP_GOTO_ON_ERROR(s_isp_io_init(dvp_ctlr, ctlr_config), err, TAG, "io init fail"); + + dvp_ctlr->trans_que = xQueueCreateWithCaps(ctlr_config->queue_items, sizeof(esp_cam_ctlr_trans_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(dvp_ctlr->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue"); + //in color type + int in_bits_per_pixel = color_hal_pixel_format_get_bit_depth(isp_proc->in_color_format); + dvp_ctlr->in_bpp = in_bits_per_pixel; + ESP_LOGD(TAG, "dvp_ctlr->in_bpp: 0d %d", dvp_ctlr->in_bpp); + + //out color type + int out_bits_per_pixel = color_hal_pixel_format_get_bit_depth(isp_proc->out_color_format); + dvp_ctlr->out_bpp = out_bits_per_pixel; + ESP_LOGD(TAG, "dvp_ctlr->out_bpp: 0d %d", dvp_ctlr->out_bpp); + + // Note: Width * Height * BitsPerPixel must be divisible by 8 + int fb_size_in_bits = isp_proc->v_res * isp_proc->h_res * out_bits_per_pixel; + ESP_GOTO_ON_FALSE((fb_size_in_bits % 8 == 0), ESP_ERR_INVALID_ARG, err, TAG, "framesize not 8bit aligned"); + dvp_ctlr->fb_size_in_bytes = fb_size_in_bits / 8; + ESP_LOGD(TAG, "dvp_ctlr->fb_size_in_bytes=%d", dvp_ctlr->fb_size_in_bytes); + + dvp_ctlr->bk_buffer_dis = ctlr_config->bk_buffer_dis; + if (!dvp_ctlr->bk_buffer_dis) { + size_t dma_alignment = 4; + size_t cache_alignment = 1; + ESP_GOTO_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &cache_alignment), err, TAG, "failed to get cache alignment"); + size_t alignment = MAX(cache_alignment, dma_alignment); + ESP_LOGD(TAG, "alignment: 0x%x\n", alignment); + + dvp_ctlr->backup_buffer = heap_caps_aligned_alloc(alignment, dvp_ctlr->fb_size_in_bytes, MALLOC_CAP_SPIRAM); + ESP_GOTO_ON_FALSE(dvp_ctlr->backup_buffer, ESP_ERR_NO_MEM, err, TAG, "no mem for backup buffer"); + ESP_LOGD(TAG, "dvp_ctlr->backup_buffer: %p\n", dvp_ctlr->backup_buffer); + esp_cache_msync((void *)(dvp_ctlr->backup_buffer), dvp_ctlr->fb_size_in_bytes, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } + + bool valid_format = isp_ll_dvp_set_data_type(isp_proc->hal.hw, isp_proc->in_color_format); + ESP_GOTO_ON_FALSE(valid_format, ESP_ERR_INVALID_ARG, err, TAG, "invalid dvp color space config"); + if (ctlr_config->io_flags.pclk_invert) { + isp_ll_cam_enable_pclk_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.hsync_invert) { + isp_ll_cam_enable_hsync_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.vsync_invert) { + isp_ll_cam_enable_vsync_invert(isp_proc->hal.hw, true); + } + if (ctlr_config->io_flags.de_invert) { + isp_ll_cam_enable_de_invert(isp_proc->hal.hw, true); + } + isp_ll_dvp_cam_reset(isp_proc->hal.hw); + + // configure DW_GDMA for ISP DVP + dw_gdma_channel_alloc_config_t dvp_dma_alloc_config = { + .src = { + .block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS, +#if SOC_ISP_SHARE_CSI_BRG + .role = DW_GDMA_ROLE_PERIPH_CSI, //CSI bridge +#endif + .handshake_type = DW_GDMA_HANDSHAKE_HW, + .num_outstanding_requests = 5, + .status_fetch_addr = MIPI_CSI_BRG_MEM_BASE, + }, + .dst = { + .block_transfer_type = DW_GDMA_BLOCK_TRANSFER_CONTIGUOUS, + .role = DW_GDMA_ROLE_MEM, + .handshake_type = DW_GDMA_HANDSHAKE_HW, + .num_outstanding_requests = 5, + }, + .flow_controller = DW_GDMA_FLOW_CTRL_SRC, + .chan_priority = 1, + }; + ESP_ERROR_CHECK(dw_gdma_new_channel(&dvp_dma_alloc_config, &dvp_ctlr->dma_chan)); + + size_t dvp_transfer_size = isp_proc->h_res * isp_proc->v_res * dvp_ctlr->in_bpp / 64; + dvp_ctlr->dvp_transfer_size = dvp_transfer_size; + ESP_LOGD(TAG, "dvp_transfer_size: 0d %d", dvp_transfer_size); + + dvp_ctlr->fsm = ISP_FSM_INIT; + isp_proc->csi_brg_hw = MIPI_CSI_BRG_LL_GET_HW(isp_proc->csi_brg_id); + mipi_csi_brg_ll_set_intput_data_h_pixel_num(isp_proc->csi_brg_hw, isp_proc->h_res); + mipi_csi_brg_ll_set_intput_data_v_row_num(isp_proc->csi_brg_hw, isp_proc->v_res); + mipi_csi_brg_ll_set_burst_len(isp_proc->csi_brg_hw, 512); + + esp_cam_ctlr_t *cam_ctlr = &(dvp_ctlr->base); + cam_ctlr->del = s_isp_del_dvp_controller; + cam_ctlr->enable = s_isp_dvp_enable; + cam_ctlr->start = s_isp_dvp_start; + cam_ctlr->stop = s_isp_dvp_stop; + cam_ctlr->disable = s_isp_dvp_disable; + cam_ctlr->receive = s_isp_dvp_receive; + cam_ctlr->register_event_callbacks = s_isp_dvp_register_event_callbacks; + cam_ctlr->get_internal_buffer = s_isp_dvp_get_frame_buffer; + cam_ctlr->get_buffer_len = s_isp_dvp_get_frame_buffer_length; + *ret_handle = cam_ctlr; + + return ESP_OK; + +err: + if (dvp_ctlr) { + s_isp_del_dvp_controller(&(dvp_ctlr->base)); + } + + return ret; +} + +esp_err_t s_isp_del_dvp_controller(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + if (dvp_ctlr->dma_chan) { + ESP_RETURN_ON_ERROR(dw_gdma_del_channel(dvp_ctlr->dma_chan), TAG, "failed to delete dwgdma channel"); + } +#if SOC_ISP_SHARE_CSI_BRG + ESP_RETURN_ON_ERROR(mipi_csi_brg_declaim(dvp_ctlr->isp_proc->csi_brg_id), TAG, "declaim csi bridge fail"); +#endif + ESP_RETURN_ON_ERROR(s_isp_declaim_dvp_controller(dvp_ctlr), TAG, "controller isn't in use"); + ESP_RETURN_ON_ERROR(dvp_shared_ctrl_declaim_io_signals(), TAG, "failed to declaim io signals"); + if (!dvp_ctlr->bk_buffer_dis) { + free(dvp_ctlr->backup_buffer); + } + if (dvp_ctlr->trans_que) { + vQueueDeleteWithCaps(dvp_ctlr->trans_que); + } + free(dvp_ctlr); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_get_frame_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...) +{ + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE((dvp_ctlr->fsm >= ISP_FSM_INIT) && (dvp_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver isn't initialized or back_buffer isn't available"); + ESP_RETURN_ON_FALSE(fb_num && fb_num <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number"); + + dvp_ctlr->bk_buffer_exposed = true; + const void **fb_itor = fb0; + va_list args; + va_start(args, fb0); + for (uint32_t i = 0; i < fb_num; i++) { + if (fb_itor) { + *fb_itor = dvp_ctlr->backup_buffer; + fb_itor = va_arg(args, const void **); + } + } + va_end(args); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_get_frame_buffer_length(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len) +{ + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE((dvp_ctlr->fsm >= ISP_FSM_INIT) && (dvp_ctlr->backup_buffer), ESP_ERR_INVALID_STATE, TAG, "driver isn't initialized or back_buffer isn't available"); + + *ret_fb_len = dvp_ctlr->fb_size_in_bytes; + return ESP_OK; +} + +static esp_err_t s_isp_dvp_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data) +{ + ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + +#if CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE + if (cbs->on_get_new_trans) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM"); + } + if (cbs->on_trans_finished) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_finished), ESP_ERR_INVALID_ARG, TAG, "on_trans_finished callback not in IRAM"); + } +#endif + + if (!dvp_ctlr->isr_installed) { + dw_gdma_event_callbacks_t csi_dma_cbs = { + .on_full_trans_done = s_dvp_dma_trans_done_callback, + }; + ESP_RETURN_ON_ERROR(dw_gdma_channel_register_event_callbacks(dvp_ctlr->dma_chan, &csi_dma_cbs, dvp_ctlr), TAG, "failed to register dma callbacks"); + dvp_ctlr->isr_installed = true; + } + + dvp_ctlr->cbs.on_get_new_trans = cbs->on_get_new_trans; + dvp_ctlr->cbs.on_trans_finished = cbs->on_trans_finished; + dvp_ctlr->cbs_user_data = user_data; + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_enable(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_ENABLE; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_disable(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_INIT; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + ESP_RETURN_ON_FALSE(dvp_ctlr->isp_proc->isp_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "ISP processor isn't in enable state"); + ESP_RETURN_ON_FALSE(dvp_ctlr->cbs.on_trans_finished, ESP_ERR_INVALID_STATE, TAG, "no on_trans_finished callback registered"); + + mipi_csi_brg_ll_enable(dvp_ctlr->isp_proc->csi_brg_hw, true); + isp_ll_cam_enable(dvp_ctlr->isp_proc->hal.hw, true); + + esp_cam_ctlr_trans_t trans = {}; + bool has_new_trans = false; + + if (dvp_ctlr->cbs.on_get_new_trans) { + dvp_ctlr->cbs.on_get_new_trans(handle, &trans, dvp_ctlr->cbs_user_data); + if (trans.buffer) { + has_new_trans = true; + } + } + + if (!has_new_trans) { + if (!dvp_ctlr->bk_buffer_dis) { + trans.buffer = dvp_ctlr->backup_buffer; + trans.buflen = dvp_ctlr->fb_size_in_bytes; + } else { + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "no ready transaction, and no backup buffer"); + } + } + + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); + dvp_ctlr->trans = trans; + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_START; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + dw_gdma_block_transfer_config_t dvp_dma_transfer_config = {}; + dvp_dma_transfer_config = (dw_gdma_block_transfer_config_t) { + .src = { + .addr = MIPI_CSI_BRG_MEM_BASE, + .burst_mode = DW_GDMA_BURST_MODE_FIXED, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .dst = { + .addr = (uint32_t)(trans.buffer), + .burst_mode = DW_GDMA_BURST_MODE_INCREMENT, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .size = dvp_ctlr->dvp_transfer_size, + }; + ESP_RETURN_ON_ERROR(dw_gdma_channel_config_transfer(dvp_ctlr->dma_chan, &dvp_dma_transfer_config), TAG, "failed to configure dwgdma transfer"); + ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(dvp_ctlr->dma_chan, true), TAG, "failed to enable dwgdma"); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_stop(esp_cam_ctlr_handle_t handle) +{ + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + ESP_RETURN_ON_FALSE(dvp_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "driver isn't started"); + + isp_ll_cam_enable(dvp_ctlr->isp_proc->hal.hw, false); + mipi_csi_brg_ll_enable(dvp_ctlr->isp_proc->csi_brg_hw, false); + ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(dvp_ctlr->dma_chan, false), TAG, "failed to disable dwgdma"); + + portENTER_CRITICAL(&dvp_ctlr->spinlock); + dvp_ctlr->fsm = ISP_FSM_INIT; + portEXIT_CRITICAL(&dvp_ctlr->spinlock); + + return ESP_OK; +} + +static esp_err_t s_isp_dvp_receive(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, uint32_t timeout_ms) +{ + esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + isp_dvp_controller_t *dvp_ctlr = __containerof(handle, isp_dvp_controller_t, base); + + ESP_RETURN_ON_FALSE(trans->buffer, ESP_ERR_INVALID_ARG, TAG, "invalid argument: no trans buffer"); + ESP_RETURN_ON_FALSE((trans->buflen >= dvp_ctlr->fb_size_in_bytes), ESP_ERR_INVALID_ARG, TAG, "invalid argument: trans buffer smaller than framebuffer size"); + + TickType_t ticks_to_wait = timeout_ms / portTICK_PERIOD_MS; + if (timeout_ms == ESP_CAM_CTLR_MAX_DELAY) { + ticks_to_wait = portMAX_DELAY; + } + + BaseType_t r = xQueueSend(dvp_ctlr->trans_que, trans, ticks_to_wait); + if (r != pdTRUE) { + ret = ESP_ERR_TIMEOUT; + ESP_LOGW(TAG, "csi recv API, transaction queue is full, failed to send transaction to the queue"); + return ret; + } + + return ESP_OK; +} + +IRAM_ATTR static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t chan, const dw_gdma_trans_done_event_data_t *event_data, void *user_data) +{ + bool need_yield = false; + BaseType_t high_task_woken = pdFALSE; + isp_dvp_controller_t *dvp_ctlr = (isp_dvp_controller_t *)user_data; + bool has_new_trans = false; + + dw_gdma_block_transfer_config_t dvp_dma_transfer_config = {}; + dvp_dma_transfer_config = (dw_gdma_block_transfer_config_t) { + .src = { + .addr = MIPI_CSI_BRG_MEM_BASE, + .burst_mode = DW_GDMA_BURST_MODE_FIXED, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .dst = { + .addr = 0, + .burst_mode = DW_GDMA_BURST_MODE_INCREMENT, + .burst_items = DW_GDMA_BURST_ITEMS_512, + .burst_len = 16, + .width = DW_GDMA_TRANS_WIDTH_64, + }, + .size = dvp_ctlr->dvp_transfer_size, + }; + esp_cam_ctlr_trans_t new_trans = {}; + + if (dvp_ctlr->cbs.on_get_new_trans) { + need_yield = dvp_ctlr->cbs.on_get_new_trans(&(dvp_ctlr->base), &new_trans, dvp_ctlr->cbs_user_data); + if (new_trans.buffer && new_trans.buflen >= dvp_ctlr->fb_size_in_bytes) { + dvp_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; + } + } else if (xQueueReceiveFromISR(dvp_ctlr->trans_que, &new_trans, &high_task_woken) == pdTRUE) { + if (new_trans.buffer && new_trans.buflen >= dvp_ctlr->fb_size_in_bytes) { + dvp_dma_transfer_config.dst.addr = (uint32_t)(new_trans.buffer); + has_new_trans = true; + } + } + + if (!has_new_trans) { + if (!dvp_ctlr->bk_buffer_dis) { + new_trans.buffer = dvp_ctlr->backup_buffer; + new_trans.buflen = dvp_ctlr->fb_size_in_bytes; + ESP_EARLY_LOGD(TAG, "no new buffer or no long enough new buffer, use driver internal buffer"); + dvp_dma_transfer_config.dst.addr = (uint32_t)dvp_ctlr->backup_buffer; + } else { + assert(false && "no new buffer, and no driver internal buffer"); + } + } + + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); + dw_gdma_channel_config_transfer(chan, &dvp_dma_transfer_config); + dw_gdma_channel_enable_ctrl(chan, true); + + if ((dvp_ctlr->trans.buffer != dvp_ctlr->backup_buffer) || dvp_ctlr->bk_buffer_exposed) { + esp_err_t ret = esp_cache_msync((void *)(dvp_ctlr->trans.buffer), dvp_ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); + assert(ret == ESP_OK); + assert(dvp_ctlr->cbs.on_trans_finished); + if (dvp_ctlr->cbs.on_trans_finished) { + dvp_ctlr->trans.received_size = dvp_ctlr->fb_size_in_bytes; + need_yield |= dvp_ctlr->cbs.on_trans_finished(&(dvp_ctlr->base), &dvp_ctlr->trans, dvp_ctlr->cbs_user_data); + } + } + + //dvp_ctlr->trans is the transaction saved before dma starts + memset(&dvp_ctlr->trans, 0x0, sizeof(esp_cam_ctlr_trans_t)); + dvp_ctlr->trans = new_trans; + + need_yield |= high_task_woken == pdTRUE; + return need_yield; +} + +static esp_err_t s_isp_io_init(isp_dvp_controller_t *dvp_ctlr, const esp_cam_ctlr_isp_dvp_cfg_t *ctlr_config) +{ + gpio_config_t gpio_conf = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_INPUT, + .pull_down_en = false, + .pull_up_en = true, + }; + + if (ctlr_config->pclk_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->pclk_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure pclk gpio"); + ESP_LOGD(TAG, "pclk_io: %d, dvp_pclk_sig: %"PRId32, ctlr_config->pclk_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_pclk_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->pclk_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_pclk_sig, false); + } + + if (ctlr_config->hsync_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->hsync_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure hsync gpio"); + ESP_LOGD(TAG, "hsync_io: %d, dvp_hsync_sig: %"PRId32, ctlr_config->hsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_hsync_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->hsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_hsync_sig, false); + } + + if (ctlr_config->vsync_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->vsync_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure vsync gpio"); + ESP_LOGD(TAG, "vsync_io: %d, dvp_vsync_sig: %"PRId32, ctlr_config->vsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_vsync_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->vsync_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_vsync_sig, false); + } + + if (ctlr_config->de_io) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->de_io; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure de gpio"); + ESP_LOGD(TAG, "de_io: %d, dvp_de_sig: %"PRId32, ctlr_config->de_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_de_sig); + esp_rom_gpio_connect_in_signal(ctlr_config->de_io, isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_de_sig, false); + } + + for (size_t i = 0; i < ctlr_config->data_width; i++) { + gpio_conf.pin_bit_mask = 1ULL << ctlr_config->data_io[i]; + ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "failed to configure data gpio"); + ESP_LOGD(TAG, "data_io: %d, dvp_data_sig: %"PRId32, ctlr_config->data_io[i], isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_data_sig[i]); + esp_rom_gpio_connect_in_signal(ctlr_config->data_io[i], isp_hw_info.dvp_ctlr[dvp_ctlr->id].dvp_data_sig[i], false); + } + + return ESP_OK; +} + +static esp_err_t s_isp_claim_dvp_controller(isp_proc_handle_t isp_proc, isp_dvp_controller_t *dvp_ctlr) +{ + assert(isp_proc && dvp_ctlr); + + _lock_acquire(&s_ctx.mutex); + bool found = false; + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + found = !s_ctx.dvp_ctlr[i]; + if (found) { + s_ctx.dvp_ctlr[i] = dvp_ctlr; + dvp_ctlr->id = i; + + break; + } + } + _lock_release(&s_ctx.mutex); + + if (!found) { + return ESP_ERR_NOT_FOUND; + } + return ESP_OK; +} + +static esp_err_t s_isp_declaim_dvp_controller(isp_dvp_controller_t *dvp_ctlr) +{ + assert(dvp_ctlr); + + _lock_acquire(&s_ctx.mutex); + s_ctx.dvp_ctlr[dvp_ctlr->id] = NULL; + _lock_release(&s_ctx.mutex); + + return ESP_OK; +} diff --git a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c index f9890e9c21b..28a995d1b1f 100644 --- a/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c +++ b/components/esp_driver_cam/test_apps/csi/main/test_csi_driver.c @@ -16,8 +16,8 @@ TEST_CASE("TEST CSI driver allocation", "[csi]") .h_res = 800, .v_res = 640, .lane_bit_rate_mbps = 200, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, @@ -42,8 +42,8 @@ TEST_CASE("TEST CSI driver no backup buffer usage", "[csi]") .h_res = 800, .v_res = 640, .lane_bit_rate_mbps = 200, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, diff --git a/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults b/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults new file mode 100644 index 00000000000..3f0207c5d6e --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/sdkconfig.defaults @@ -0,0 +1,6 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n + +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index ac99867c005..2a6b0371154 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -1,7 +1,13 @@ +idf_build_get_property(target IDF_TARGET) + set(srcs) set(public_include "include") +set(priv_requires "esp_driver_gpio") + +set(requires) + if(CONFIG_SOC_ISP_SUPPORTED) list(APPEND srcs "src/isp_core.c" "src/isp_af.c") @@ -11,7 +17,12 @@ if(CONFIG_SOC_ISP_BF_SUPPORTED) list(APPEND srcs "src/isp_bf.c") endif() +if(NOT ${target} STREQUAL "linux") + list(APPEND requires esp_mm) +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${public_include} - PRIV_REQUIRES esp_driver_gpio + REQUIRES ${requires} + PRIV_REQUIRES ${priv_requires} ) diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 23348117d5d..9058ea7445f 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -38,7 +38,7 @@ typedef struct { * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags * - ESP_ERR_NO_MEM If out of memory */ -esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl); +esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctlr_t *ret_hdl); /** * @brief Delete an ISP AF controller @@ -50,7 +50,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_del_af_controller(isp_af_ctlr_t af_ctrlr); /** * @brief Enable an ISP AF controller @@ -62,7 +62,7 @@ esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_enable(isp_af_ctlr_t af_ctrlr); /** * @brief Disable an ISP AF controller @@ -74,7 +74,7 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_disable(isp_af_ctlr_t af_ctrlr); /** * @brief Trigger AF luminance and definition statistics for one time and get the result @@ -97,7 +97,7 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctrlr); * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res); +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res); /** @cond */ #define esp_isp_af_controller_get_oneshot_result(af_ctrlr, out_res) \ @@ -116,7 +116,7 @@ esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, * - ESP_ERR_INVALID_ARG Null pointer * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctrlr); /** * @brief Stop AF continuous statistics of the luminance and definition in the windows @@ -127,7 +127,7 @@ esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ct * - ESP_ERR_INVALID_ARG Null pointer * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr); +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr); /*--------------------------------------------- AF Env Monitor @@ -152,7 +152,7 @@ typedef struct { * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config); +esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config); /** * @brief Set ISP AF environment detector detecting threshold @@ -166,7 +166,7 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. * - ESP_ERR_INVALID_STATE Driver state is invalid. */ -esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh); +esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctrlr, int definition_thresh, int luminance_thresh); /** * @brief Event data structure @@ -184,7 +184,7 @@ typedef struct { * * @return Whether a high priority task is woken up by this function */ -typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data); +typedef bool (*esp_isp_af_env_detector_callback_t)(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data); /** * @brief Group of ISP AF Env detector callbacks @@ -215,7 +215,7 @@ typedef struct { * - ESP_ERR_INVALID_ARG: Invalid arguments * - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment */ -esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data); +esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data); #ifdef __cplusplus } diff --git a/components/esp_driver_isp/include/driver/isp_types.h b/components/esp_driver_isp/include/driver/isp_types.h index 14e0f6568fe..f374793d2cd 100644 --- a/components/esp_driver_isp/include/driver/isp_types.h +++ b/components/esp_driver_isp/include/driver/isp_types.h @@ -20,7 +20,7 @@ typedef struct isp_processor_t *isp_proc_handle_t; /** * @brief Type of ISP AF controller handle */ -typedef struct isp_af_controller_t *isp_af_ctrlr_t; +typedef struct isp_af_controller_t *isp_af_ctlr_t; #ifdef __cplusplus } diff --git a/components/esp_driver_isp/src/isp_internal.h b/components/esp_driver_isp/include/esp_private/isp_private.h similarity index 70% rename from components/esp_driver_isp/src/isp_internal.h rename to components/esp_driver_isp/include/esp_private/isp_private.h index 3d388386773..7b25b298828 100644 --- a/components/esp_driver_isp/src/isp_internal.h +++ b/components/esp_driver_isp/include/esp_private/isp_private.h @@ -19,11 +19,13 @@ #include "freertos/queue.h" #include "freertos/idf_additions.h" #include "driver/isp_types.h" +#include "soc/soc_caps.h" +#if SOC_ISP_SUPPORTED #include "hal/isp_hal.h" #include "hal/isp_ll.h" #include "hal/isp_types.h" #include "soc/isp_periph.h" -#include "soc/soc_caps.h" +#endif #ifdef __cplusplus extern "C" { @@ -43,23 +45,28 @@ typedef enum { ISP_FSM_START, } isp_fsm_t; +#if SOC_ISP_SUPPORTED /*--------------------------------------------------------------- Driver Context ---------------------------------------------------------------*/ typedef struct isp_processor_t { - int proc_id; - isp_hal_context_t hal; + int proc_id; + isp_hal_context_t hal; #if SOC_ISP_SHARE_CSI_BRG - int csi_brg_id; - void *csi_brg_hw; + int csi_brg_id; + void *csi_brg_hw; #endif - isp_fsm_t isp_fsm; - portMUX_TYPE spinlock; - + isp_fsm_t isp_fsm; + portMUX_TYPE spinlock; + color_space_pixel_format_t in_color_format; + color_space_pixel_format_t out_color_format; + uint32_t h_res; + uint32_t v_res; /* sub module contexts */ - isp_af_ctrlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; - isp_fsm_t bf_fsm; + isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; + isp_fsm_t bf_fsm; } isp_processor_t; +#endif #ifdef __cplusplus } diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index c534b785cf8..02f289a4417 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -12,7 +12,7 @@ #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" #include "driver/isp_af.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" static const char *TAG = "ISP_AF"; @@ -33,7 +33,7 @@ static void s_isp_af_default_isr(void *arg); /*--------------------------------------------- AF ----------------------------------------------*/ -static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ctrlr_t af_ctlr) +static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ctlr_t af_ctlr) { assert(isp_proc && af_ctlr); @@ -56,7 +56,7 @@ static esp_err_t s_isp_claim_af_controller(isp_proc_handle_t isp_proc, isp_af_ct return ESP_OK; } -static void s_isp_declaim_af_controller(isp_af_ctrlr_t af_ctlr) +static void s_isp_declaim_af_controller(isp_af_ctlr_t af_ctlr) { assert(af_ctlr && af_ctlr->isp_proc); @@ -65,7 +65,7 @@ static void s_isp_declaim_af_controller(isp_af_ctrlr_t af_ctlr) portEXIT_CRITICAL(&af_ctlr->isp_proc->spinlock); } -static void s_isp_af_free_controller(isp_af_ctrlr_t af_ctlr) +static void s_isp_af_free_controller(isp_af_ctlr_t af_ctlr) { if (af_ctlr) { if (af_ctlr->intr_handle) { @@ -78,7 +78,7 @@ static void s_isp_af_free_controller(isp_af_ctrlr_t af_ctlr) } } -esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctrlr_t *ret_hdl) +esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af_config_t *af_config, isp_af_ctlr_t *ret_hdl) { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(isp_proc && af_config && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); @@ -102,7 +102,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af } ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0"); - isp_af_ctrlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); + isp_af_ctlr_t af_ctlr = heap_caps_calloc(1, sizeof(isp_af_controller_t), ISP_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(af_ctlr, ESP_ERR_NO_MEM, TAG, "no mem"); af_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_af_result_t), ISP_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(af_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for af event queue"); @@ -141,7 +141,7 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af return ret; } -esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_del_af_controller(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); @@ -159,7 +159,7 @@ esp_err_t esp_isp_del_af_controller(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_af_controller_enable(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); @@ -173,7 +173,7 @@ esp_err_t esp_isp_af_controller_enable(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr) +esp_err_t esp_isp_af_controller_disable(isp_af_ctlr_t af_ctlr) { ESP_RETURN_ON_FALSE(af_ctlr && af_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); @@ -187,7 +187,7 @@ esp_err_t esp_isp_af_controller_disable(isp_af_ctrlr_t af_ctlr) return ESP_OK; } -esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res) +esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctlr_t af_ctrlr, int timeout_ms, isp_af_result_t *out_res) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't enabled or continuous statistics has started"); @@ -206,7 +206,7 @@ esp_err_t esp_isp_af_controller_get_oneshot_statistics(isp_af_ctrlr_t af_ctrlr, return ret; } -esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctlr_t af_ctrlr) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); @@ -217,7 +217,7 @@ esp_err_t esp_isp_af_controller_start_continuous_statistics(isp_af_ctrlr_t af_ct return ESP_OK; } -esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctrlr) +esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctlr_t af_ctrlr) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); @@ -231,7 +231,7 @@ esp_err_t esp_isp_af_controller_stop_continuous_statistics(isp_af_ctrlr_t af_ctr /*--------------------------------------------- AF Env Monitor ----------------------------------------------*/ -esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config) +esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_config_t *env_config) { ESP_RETURN_ON_FALSE(af_ctrlr && env_config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "invalid fsm, should be called when in init state"); @@ -248,7 +248,7 @@ esp_err_t esp_isp_af_controller_set_env_detector(isp_af_ctrlr_t af_ctrlr, const return ESP_OK; } -esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data) +esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_cbs_t *cbs, void *user_data) { ESP_RETURN_ON_FALSE(af_ctrlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(af_ctrlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state"); @@ -271,7 +271,7 @@ esp_err_t esp_isp_af_env_detector_register_event_callbacks(isp_af_ctrlr_t af_ctr return ESP_OK; } -esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctrlr, int definition_thresh, int luminance_thresh) +esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctlr_t af_ctrlr, int definition_thresh, int luminance_thresh) { ESP_RETURN_ON_FALSE_ISR(af_ctrlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE_ISR(af_ctrlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "detector isn't in enable state"); @@ -286,7 +286,7 @@ esp_err_t esp_isp_af_controller_set_env_detector_threshold(isp_af_ctrlr_t af_ctr ---------------------------------------------------------------*/ static void IRAM_ATTR s_isp_af_default_isr(void *arg) { - isp_af_ctrlr_t af_ctrlr = (isp_af_ctrlr_t)arg; + isp_af_ctlr_t af_ctrlr = (isp_af_ctlr_t)arg; isp_proc_handle_t proc = af_ctrlr->isp_proc; uint32_t af_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AF_MASK); diff --git a/components/esp_driver_isp/src/isp_bf.c b/components/esp_driver_isp/src/isp_bf.c index 00bf4d1902e..e2258216f40 100644 --- a/components/esp_driver_isp/src/isp_bf.c +++ b/components/esp_driver_isp/src/isp_bf.c @@ -19,7 +19,7 @@ #include "hal/hal_utils.h" #include "soc/mipi_csi_bridge_struct.h" #include "soc/isp_periph.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" static const char *TAG = "ISP_BF"; diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index b34057f9ab7..d1aa78784ca 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -19,7 +19,7 @@ #include "hal/hal_utils.h" #include "soc/mipi_csi_bridge_struct.h" #include "soc/isp_periph.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" typedef struct isp_platform_t { _lock_t mutex; @@ -73,7 +73,7 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE(proc_config->input_data_source == ISP_INPUT_DATA_SOURCE_CSI, ESP_ERR_NOT_SUPPORTED, TAG, "only support CSI as input source at this moment"); + ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet"); ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == ISP_COLOR_RAW8, ESP_ERR_NOT_SUPPORTED, TAG, "input data type not supported"); isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS); @@ -143,6 +143,11 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ isp_ll_set_intput_data_h_pixel_num(proc->hal.hw, proc_config->h_res); isp_ll_set_intput_data_v_row_num(proc->hal.hw, proc_config->v_res); + proc->in_color_format = in_color_format; + proc->out_color_format = out_color_format; + proc->h_res = proc_config->h_res; + proc->v_res = proc_config->v_res; + *ret_proc = proc; return ESP_OK; diff --git a/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt b/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt index 49f618de17d..941c781eaf7 100644 --- a/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt +++ b/components/esp_driver_isp/test_apps/isp/main/CMakeLists.txt @@ -8,6 +8,7 @@ endif() set(priv_requires unity esp_driver_isp + esp_psram ) idf_component_register(SRCS ${srcs} diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index 310124e0e22..ff4f9762462 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -7,8 +7,8 @@ #include "sdkconfig.h" #include "unity.h" #include "driver/isp.h" - -#include "esp_rom_sys.h" +#include "esp_private/isp_dvp_private.h" +#include "soc/soc_caps.h" TEST_CASE("ISP processor exhausted allocation", "[isp]") { @@ -31,6 +31,45 @@ TEST_CASE("ISP processor exhausted allocation", "[isp]") } } +#if SOC_ISP_DVP_SUPPORTED +TEST_CASE("ISP DVP controller exhausted allocation", "[isp]") +{ + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 120 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_DVP, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + .has_line_start_packet = false, + .has_line_end_packet = false, + .h_res = 800, + .v_res = 640, + }; + isp_proc_handle_t isp_proc = NULL; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + + esp_cam_ctlr_isp_dvp_cfg_t dvp_ctlr_config = { + .data_width = 8, + .data_io = {53, 54, 52, 0, 1, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, + .pclk_io = 21, + .hsync_io = 5, + .vsync_io = 23, + .de_io = 22, + .io_flags.vsync_invert = 1, + }; + esp_cam_ctlr_handle_t dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS + 1] = {}; + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[i])); + } + + TEST_ASSERT(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS]) == ESP_ERR_NOT_FOUND); + + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_isp_del_dvp_controller(dvp_ctrlr[i])); + } + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); +} +#endif + TEST_CASE("ISP AF controller exhausted allocation", "[isp]") { esp_isp_processor_cfg_t isp_config = { @@ -45,7 +84,7 @@ TEST_CASE("ISP AF controller exhausted allocation", "[isp]") esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr[SOC_ISP_AF_CTLR_NUMS + 1] = {}; + isp_af_ctlr_t af_ctrlr[SOC_ISP_AF_CTLR_NUMS + 1] = {}; for (int i = 0; i < SOC_ISP_AF_CTLR_NUMS; i++) { TEST_ESP_OK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr[i])); } diff --git a/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults b/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults index fa8ac618b94..5bce69ad381 100644 --- a/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults +++ b/components/esp_driver_isp/test_apps/isp/sdkconfig.defaults @@ -1,2 +1,5 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_ESP_TASK_WDT_EN=n +CONFIG_SPIRAM=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c index 835f427078c..788ddfcfac7 100644 --- a/components/esp_hw_support/port/esp32p4/esp_clk_tree.c +++ b/components/esp_hw_support/port/esp32p4/esp_clk_tree.c @@ -16,7 +16,7 @@ static const char *TAG = "esp_clk_tree"; esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_src_freq_precision_t precision, -uint32_t *freq_value) + uint32_t *freq_value) { ESP_RETURN_ON_FALSE(clk_src > 0 && clk_src < SOC_MOD_CLK_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown clk src"); ESP_RETURN_ON_FALSE(precision < ESP_CLK_TREE_SRC_FREQ_PRECISION_INVALID, ESP_ERR_INVALID_ARG, TAG, "unknown precision"); diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index c91c8efb255..eaf0760e1a0 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -76,6 +76,13 @@ extern "C" { ---------------------------------------------------------------*/ #define ISP_LL_BF_DEFAULT_TEMPLATE_VAL 15 +/*--------------------------------------------------------------- + DVP +---------------------------------------------------------------*/ +#define ISP_LL_DVP_DATA_TYPE_RAW8 0x2A +#define ISP_LL_DVP_DATA_TYPE_RAW10 0x2B +#define ISP_LL_DVP_DATA_TYPE_RAW12 0x2C + /** * @brief Env monitor mode */ @@ -791,6 +798,130 @@ static inline void isp_ll_color_enable(isp_dev_t *hw, bool enable) hw->cntl.color_en = enable; } +/*--------------------------------------------------------------- + DVP Camera +---------------------------------------------------------------*/ +/** + * @brief Set dvp data color format + * + * @param[in] hw Hardware instance address + * @param[in] format color format, see `color_space_pixel_format_t` + * + * @return true for valid format, false for invalid format + */ +static inline bool isp_ll_dvp_set_data_type(isp_dev_t *hw, color_space_pixel_format_t format) +{ + bool valid = false; + + if (format.color_space == COLOR_SPACE_RAW) { + switch(format.pixel_format) { + case COLOR_PIXEL_RAW8: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW8; + valid = true; + break; + case COLOR_PIXEL_RAW10: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW10; + valid = true; + break; + case COLOR_PIXEL_RAW12: + hw->cam_conf.cam_data_type = ISP_LL_DVP_DATA_TYPE_RAW12; + valid = true; + break; + default: + break; + } + } + + return valid; +} + +/** + * @brief Enable / Disable 2B mode + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_dvp_enable_2byte_mode(isp_dev_t *hw, bool enable) +{ + if (enable) { + HAL_ASSERT(hw->cam_conf.cam_data_type == ISP_LL_DVP_DATA_TYPE_RAW8); + hw->cam_conf.cam_2byte_mode = 1; + } else { + hw->cam_conf.cam_2byte_mode = 0; + } +} + +/** + * @brief Reset DVP CAM module + * + * @param[in] hw Hardware instance address + */ +static inline void isp_ll_dvp_cam_reset(isp_dev_t *hw) +{ + hw->cam_cntl.cam_reset = 1; + hw->cam_cntl.cam_reset = 0; +} + +/** + * @brief Enable DVP CAM pclk invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_pclk_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_cntl.cam_clk_inv = enable; +} + +/** + * @brief Enable DVP CAM de invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_de_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_de_inv = enable; +} + +/** + * @brief Enable DVP CAM hsync invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_hsync_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_hsync_inv = enable; +} + +/** + * @brief Enable DVP CAM vsync invert + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable_vsync_invert(isp_dev_t *hw, bool enable) +{ + hw->cam_conf.cam_vsync_inv = enable; +} + +/** + * @brief Enable DVP CAM + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_cam_enable(isp_dev_t *hw, bool enable) +{ + if (enable) { + hw->cam_cntl.cam_update_reg = 1; + hw->cam_cntl.cam_en = 1; + while (hw->cam_cntl.cam_update_reg); + } else { + hw->cam_cntl.cam_en = 0; + } +} /*--------------------------------------------------------------- INTR ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/cam_ctlr_types.h b/components/hal/include/hal/cam_ctlr_types.h new file mode 100644 index 00000000000..58307238213 --- /dev/null +++ b/components/hal/include/hal/cam_ctlr_types.h @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "hal/color_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Camera Controller Color Type + */ +typedef enum { + CAM_CTLR_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8 + CAM_CTLR_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10 + CAM_CTLR_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12 + CAM_CTLR_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565 + CAM_CTLR_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666 + CAM_CTLR_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 + CAM_CTLR_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 + CAM_CTLR_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 +} cam_ctlr_color_t; + +/** + * @brief Camera Controller Data Width + */ +typedef enum { + CAM_CTLR_DATA_WIDTH_8 = 8, ///< 8-bit data width + CAM_CTLR_DATA_WIDTH_10 = 10, ///< 10-bit data width + CAM_CTLR_DATA_WIDTH_12 = 12, ////< 12-bit data width + CAM_CTLR_DATA_WIDTH_16 = 16, ///< 16-bit data width +} cam_ctlr_data_width_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 0d5bc4be3fe..baa74ea90d6 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -45,6 +45,15 @@ typedef enum { ISP_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 } isp_color_t; +/*--------------------------------------------------------------- + DVP +---------------------------------------------------------------*/ +#if SOC_ISP_DVP_DATA_WIDTH_MAX +#define ISP_DVP_DATA_SIG_NUM SOC_ISP_DVP_DATA_WIDTH_MAX // The ISP DVP data signal number +#else +#define ISP_DVP_DATA_SIG_NUM 0 +#endif + /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/mipi_csi_types.h b/components/hal/include/hal/mipi_csi_types.h index 5614a43b21a..9458bc6ddb7 100644 --- a/components/hal/include/hal/mipi_csi_types.h +++ b/components/hal/include/hal/mipi_csi_types.h @@ -10,6 +10,7 @@ #include "soc/soc_caps.h" #include "soc/clk_tree_defs.h" #include "hal/color_types.h" +#include "hal/cam_ctlr_types.h" #ifdef __cplusplus extern "C" { @@ -24,20 +25,6 @@ typedef soc_periph_mipi_csi_phy_clk_src_t mipi_csi_phy_clock_source_t; typedef int mipi_csi_phy_clock_source_t; #endif // SOC_MIPI_CSI_SUPPORTED -/** - * @brief MIPI CSI Color Type - */ -typedef enum { - MIPI_CSI_COLOR_RAW8 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW8), ///< RAW8 - MIPI_CSI_COLOR_RAW10 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW10), ///< RAW10 - MIPI_CSI_COLOR_RAW12 = COLOR_TYPE_ID(COLOR_SPACE_RAW, COLOR_PIXEL_RAW12), ///< RAW12 - MIPI_CSI_COLOR_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), ///< RGB565 - MIPI_CSI_COLOR_RGB666 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB666), ///< RGB666 - MIPI_CSI_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 - MIPI_CSI_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 - MIPI_CSI_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 -} mipi_csi_color_t; - #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 6f6566e6c48..7b18e847191 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -751,10 +751,18 @@ config SOC_ISP_BF_SUPPORTED bool default y +config SOC_ISP_DVP_SUPPORTED + bool + default y + config SOC_ISP_NUMS int default 1 +config SOC_ISP_DVP_CTLR_NUMS + int + default 1 + config SOC_ISP_AF_CTLR_NUMS int default 1 @@ -775,6 +783,10 @@ config SOC_ISP_BF_TEMPLATE_Y_NUMS int default 3 +config SOC_ISP_DVP_DATA_WIDTH_MAX + int + default 16 + config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index d2a55eea8b5..cfe95b3e68f 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -312,13 +312,16 @@ /*-------------------------- ISP CAPS ----------------------------------------*/ #define SOC_ISP_BF_SUPPORTED 1 +#define SOC_ISP_DVP_SUPPORTED 1 #define SOC_ISP_NUMS 1U +#define SOC_ISP_DVP_CTLR_NUMS 1U #define SOC_ISP_AF_CTLR_NUMS 1U #define SOC_ISP_AF_WINDOW_NUMS 3 #define SOC_ISP_SHARE_CSI_BRG 1 #define SOC_ISP_BF_TEMPLATE_X_NUMS 3 #define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 +#define SOC_ISP_DVP_DATA_WIDTH_MAX 16 /*-------------------------- LEDC CAPS ---------------------------------------*/ #define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1) diff --git a/components/soc/esp32p4/isp_periph.c b/components/soc/esp32p4/isp_periph.c index e46c183356a..7ecdb372fc1 100644 --- a/components/soc/esp32p4/isp_periph.c +++ b/components/soc/esp32p4/isp_periph.c @@ -16,6 +16,32 @@ const isp_info_t isp_hw_info = { [0] = { .irq = ETS_ISP_INTR_SOURCE, } + }, + .dvp_ctlr = { + [0] = { + .dvp_pclk_sig = CAM_PCLK_PAD_IN_IDX, + .dvp_hsync_sig = CAM_H_SYNC_PAD_IN_IDX, + .dvp_vsync_sig = CAM_V_SYNC_PAD_IN_IDX, + .dvp_de_sig = CAM_H_ENABLE_PAD_IN_IDX, + .dvp_data_sig = { + CAM_DATA_IN_PAD_IN0_IDX, + CAM_DATA_IN_PAD_IN1_IDX, + CAM_DATA_IN_PAD_IN2_IDX, + CAM_DATA_IN_PAD_IN3_IDX, + CAM_DATA_IN_PAD_IN4_IDX, + CAM_DATA_IN_PAD_IN5_IDX, + CAM_DATA_IN_PAD_IN6_IDX, + CAM_DATA_IN_PAD_IN7_IDX, + CAM_DATA_IN_PAD_IN8_IDX, + CAM_DATA_IN_PAD_IN9_IDX, + CAM_DATA_IN_PAD_IN10_IDX, + CAM_DATA_IN_PAD_IN11_IDX, + CAM_DATA_IN_PAD_IN12_IDX, + CAM_DATA_IN_PAD_IN13_IDX, + CAM_DATA_IN_PAD_IN14_IDX, + CAM_DATA_IN_PAD_IN15_IDX + }, + }, } }; diff --git a/components/soc/include/soc/isp_periph.h b/components/soc/include/soc/isp_periph.h index 54185323d6e..288ed884c68 100644 --- a/components/soc/include/soc/isp_periph.h +++ b/components/soc/include/soc/isp_periph.h @@ -9,6 +9,7 @@ #include #include "soc/soc_caps.h" #include "soc/periph_defs.h" +#include "soc/gpio_sig_map.h" #ifdef __cplusplus extern "C" { @@ -19,6 +20,13 @@ typedef struct { struct { const uint32_t irq; } instances[SOC_ISP_NUMS]; + struct { + const uint32_t dvp_pclk_sig; + const uint32_t dvp_hsync_sig; + const uint32_t dvp_vsync_sig; + const uint32_t dvp_de_sig; + const uint32_t dvp_data_sig[SOC_ISP_DVP_DATA_WIDTH_MAX]; + } dvp_ctlr[SOC_ISP_DVP_CTLR_NUMS]; } isp_info_t; extern const isp_info_t isp_hw_info; diff --git a/docs/en/api-reference/peripherals/camera_driver.rst b/docs/en/api-reference/peripherals/camera_driver.rst index 18bb537b8b4..bc9bec1c574 100644 --- a/docs/en/api-reference/peripherals/camera_driver.rst +++ b/docs/en/api-reference/peripherals/camera_driver.rst @@ -48,8 +48,8 @@ Resource Allocation .h_res = MIPI_CSI_DISP_HSIZE, .v_res = MIPI_CSI_DISP_VSIZE_640P, .lane_bit_rate_mbps = MIPI_CSI_LANE_BITRATE_MBPS, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, @@ -134,7 +134,7 @@ The factory function :cpp:func:`esp_cam_new_csi_ctlr` and :cpp:func:`esp_cam_ctl Kconfig Options ^^^^^^^^^^^^^^^ -- :ref:`CONFIG_MIPI_CSI_ISR_IRAM_SAFE` controls whether the default ISR handler should be masked when the cache is disabled +- :ref:`CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE` controls whether the default ISR handler should be masked when the cache is disabled .. _cam-iram-safe: @@ -144,7 +144,7 @@ IRAM Safe By default, the CSI interrupt will be deferred when the cache is disabled because of writing or erasing the flash. -There is a Kconfig option :ref:`CONFIG_MIPI_CSI_ISR_IRAM_SAFE` that: +There is a Kconfig option :ref:`CONFIG_CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE` that: - Enables the interrupt being serviced even when the cache is disabled - Places all functions that used by the ISR into IRAM diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 1a2ff494d29..41887198090 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -71,7 +71,7 @@ If the configurations in :cpp:type:`esp_isp_af_config_t` is specified, users can esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); You can use the created handle to do driver enable / disable the ISP AF driver and ISP AF Env module installation. @@ -122,7 +122,7 @@ Calling :cpp:func:`esp_isp_af_controller_get_oneshot_statistics` to get oneshot esp_isp_af_config_t af_config = { .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); isp_af_result_t result = {}; @@ -140,7 +140,7 @@ Note that if you want to use the continuous statistics, you need to register the .. code:: c - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; esp_isp_af_config_t af_config = { .edge_thresh = 128, }; @@ -171,7 +171,7 @@ Calling :cpp:func:`esp_isp_af_controller_set_env_detector` to set an ISP AF envi esp_isp_af_env_config_t env_config = { .interval = 10, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config)); diff --git a/examples/peripherals/camera/components/dsi_init/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt similarity index 71% rename from examples/peripherals/camera/components/dsi_init/CMakeLists.txt rename to examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt index 348bb317260..f8432fc1e70 100644 --- a/examples/peripherals/camera/components/dsi_init/CMakeLists.txt +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "example_dsi_init.c" - INCLUDE_DIRS "." + INCLUDE_DIRS "include" REQUIRES esp_lcd ) diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild b/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild new file mode 100644 index 00000000000..c67e3516ad9 --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/Kconfig.projbuild @@ -0,0 +1,25 @@ +menu "Example DSI Configuration" + choice EXAMPLE_MIPI_DSI_DISP_HRES + bool "Set MIPI CSI horizontal resolution" + default EXAMPLE_MIPI_DSI_DISP_HRES_800 + + config EXAMPLE_MIPI_DSI_DISP_HRES_800 + bool "800" + endchoice + + config EXAMPLE_MIPI_DSI_DISP_HRES + int + default 800 if EXAMPLE_MIPI_DSI_DISP_HRES_800 + + choice EXAMPLE_MIPI_DSI_DISP_VRES + bool "Set MIPI CSI vertical resolution" + default EXAMPLE_MIPI_DSI_DISP_VRES_1280 + + config EXAMPLE_MIPI_DSI_DISP_VRES_1280 + bool "1280" + endchoice + + config EXAMPLE_MIPI_DSI_DISP_VRES + int + default 1280 if EXAMPLE_MIPI_DSI_DISP_VRES_1280 +endmenu diff --git a/examples/peripherals/camera/components/dsi_init/example_dsi_init.c b/examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c similarity index 94% rename from examples/peripherals/camera/components/dsi_init/example_dsi_init.c rename to examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c index 1cf9f3768a2..15790143194 100644 --- a/examples/peripherals/camera/components/dsi_init/example_dsi_init.c +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/example_dsi_init.c @@ -10,6 +10,7 @@ #include "esp_lcd_panel_ops.h" #include "esp_lcd_ili9881c.h" #include "example_dsi_init.h" +#include "example_dsi_init_config.h" void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer) { @@ -45,8 +46,8 @@ void example_dsi_resource_alloc(esp_lcd_panel_handle_t *ili9881c_ctrl_panel, esp .virtual_channel = 0, .pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565, .video_timing = { - .h_size = EXAMPLE_MIPI_DSI_IMAGE_HSIZE, - .v_size = EXAMPLE_MIPI_DSI_IMAGE_VSIZE, + .h_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, + .v_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, .hsync_back_porch = EXAMPLE_MIPI_DSI_IMAGE_HBP, .hsync_pulse_width = EXAMPLE_MIPI_DSI_IMAGE_HSYNC, .hsync_front_porch = EXAMPLE_MIPI_DSI_IMAGE_HFP, diff --git a/examples/peripherals/camera/components/dsi_init/idf_component.yml b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml similarity index 53% rename from examples/peripherals/camera/components/dsi_init/idf_component.yml rename to examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml index 6e0028e6a5e..d43fae96574 100644 --- a/examples/peripherals/camera/components/dsi_init/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml @@ -1,4 +1,4 @@ dependencies: - espressif/esp_lcd_ili9881c: "^0.2.0" + esp_lcd_ili9881c: ">=0.1.0" idf: version: ">=5.3.0" diff --git a/examples/peripherals/camera/components/dsi_init/example_dsi_init.h b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h similarity index 68% rename from examples/peripherals/camera/components/dsi_init/example_dsi_init.h rename to examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h index 5cffbc3cdfa..df04c79eb15 100644 --- a/examples/peripherals/camera/components/dsi_init/example_dsi_init.h +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init.h @@ -6,19 +6,14 @@ #pragma once +#include "esp_lcd_mipi_dsi.h" +#include "esp_lcd_panel_ops.h" +#include "esp_lcd_ili9881c.h" + #ifdef __cplusplus extern "C" { #endif -#define EXAMPLE_MIPI_DSI_IMAGE_HSIZE 800 -#define EXAMPLE_MIPI_DSI_IMAGE_VSIZE 1280 -#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 -#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 -#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40 -#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4 -#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 -#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 - /** * @brief DSI init function * diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h new file mode 100644 index 00000000000..c804154298a --- /dev/null +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/include/example_dsi_init_config.h @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXAMPLE_MIPI_DSI_IMAGE_HSYNC 40 +#define EXAMPLE_MIPI_DSI_IMAGE_HBP 140 +#define EXAMPLE_MIPI_DSI_IMAGE_HFP 40 +#define EXAMPLE_MIPI_DSI_IMAGE_VSYNC 4 +#define EXAMPLE_MIPI_DSI_IMAGE_VBP 16 +#define EXAMPLE_MIPI_DSI_IMAGE_VFP 16 + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt index 8910b7da400..e760975a481 100644 --- a/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt +++ b/examples/peripherals/camera/camera_dsi/main/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "camera_dsi_main.c" INCLUDE_DIRS "." - REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c esp_lcd dsi_init + REQUIRES esp_mm esp_driver_isp esp_driver_cam esp_driver_i2c dsi_init ) diff --git a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c index 9087aa28fb5..a5c5c2dcb70 100644 --- a/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c +++ b/examples/peripherals/camera/camera_dsi/main/camera_dsi_main.c @@ -23,6 +23,7 @@ #include "esp_cam_sensor.h" #include "ov5647.h" #include "example_dsi_init.h" +#include "example_dsi_init_config.h" #include "example_config.h" static const char *TAG = "cam_dsi"; @@ -55,9 +56,9 @@ void app_main(void) example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); + ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); @@ -92,8 +93,8 @@ void app_main(void) .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, diff --git a/examples/peripherals/camera/camera_dsi/main/idf_component.yml b/examples/peripherals/camera/camera_dsi/main/idf_component.yml index f7121dc8c58..47d0275f00d 100644 --- a/examples/peripherals/camera/camera_dsi/main/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/main/idf_component.yml @@ -4,4 +4,4 @@ dependencies: idf: version: ">=5.3.0" dsi_init: - path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init + path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h index dd70f17d0ce..b01ab5db662 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/include/isp_af_scheme_sa.h @@ -52,7 +52,7 @@ typedef struct { * - ESP_ERR_INVALID_STATE Invalid state * - ESP_ERR_NO_MEM If out of memory */ -esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctrlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme); +esp_err_t isp_af_create_sa_scheme(isp_af_ctlr_t af_ctrlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme); /** * @brief Delete an AF step approximation scheme diff --git a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c index b7b5502d520..9e8830b00d3 100644 --- a/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c +++ b/examples/peripherals/isp/auto_focus/components/isp_af_schemes/src/isp_af_scheme_sa.c @@ -21,7 +21,7 @@ static const char *TAG = "AF_SCHEME"; typedef struct { - isp_af_ctrlr_t af_ctlr; + isp_af_ctlr_t af_ctlr; int first_step_val; int first_approx_cycles; int second_step_val; @@ -36,7 +36,7 @@ typedef struct { static esp_err_t s_af_process(void *arg, int *out_definition_thresh, int *out_luminance_thresh); /* ------------------------- Public API ------------------------------------- */ -esp_err_t isp_af_create_sa_scheme(isp_af_ctrlr_t af_ctlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme) +esp_err_t isp_af_create_sa_scheme(isp_af_ctlr_t af_ctlr, const isp_af_sa_scheme_config_t *config, isp_af_scheme_handle_t *ret_scheme) { esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(af_ctlr && config && ret_scheme, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); diff --git a/examples/peripherals/isp/auto_focus/main/idf_component.yml b/examples/peripherals/isp/auto_focus/main/idf_component.yml index 803bff156a7..e424be9e274 100644 --- a/examples/peripherals/isp/auto_focus/main/idf_component.yml +++ b/examples/peripherals/isp/auto_focus/main/idf_component.yml @@ -6,4 +6,4 @@ dependencies: isp_af_schemes: path: ${IDF_PATH}/examples/peripherals/isp/auto_focus/components/isp_af_schemes dsi_init: - path: ${IDF_PATH}/examples/peripherals/camera/components/dsi_init + path: ${IDF_PATH}/examples/peripherals/camera/camera_dsi/components/dsi_init diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c index 4ff9f323efe..0d8be2f9bbf 100644 --- a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -25,6 +25,7 @@ #include "esp_cam_sensor.h" #include "ov5647.h" #include "example_dsi_init.h" +#include "example_dsi_init_config.h" #include "example_config.h" static const char *TAG = "isp_dsi"; @@ -46,7 +47,7 @@ typedef union { uint16_t val; } dw9714_reg_t; -static bool IRAM_ATTR s_env_change_cb(isp_af_ctrlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data) +static bool IRAM_ATTR s_env_change_cb(isp_af_ctlr_t af_ctrlr, const esp_isp_af_env_detector_evt_data_t *edata, void *user_data) { BaseType_t mustYield = pdFALSE; TaskHandle_t task_handle = (TaskHandle_t)user_data; @@ -119,7 +120,7 @@ static void af_task(void *arg) .edge_thresh = 128, }; - isp_af_ctrlr_t af_ctrlr = NULL; + isp_af_ctlr_t af_ctrlr = NULL; ESP_ERROR_CHECK(esp_isp_new_af_controller(af_task_param.isp_proc, &af_config, &af_ctrlr)); esp_isp_af_env_config_t env_config = { @@ -185,9 +186,9 @@ void app_main(void) example_dsi_resource_alloc(&ili9881c_ctrl_panel, &mipi_dpi_panel, &frame_buffer); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * EXAMPLE_MIPI_DSI_IMAGE_VSIZE * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; - ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, EXAMPLE_MIPI_DSI_IMAGE_VSIZE: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, EXAMPLE_MIPI_DSI_IMAGE_VSIZE, 8); + ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); @@ -226,8 +227,8 @@ void app_main(void) .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, - .input_data_color_type = MIPI_CSI_COLOR_RAW8, - .output_data_color_type = MIPI_CSI_COLOR_RGB565, + .input_data_color_type = CAM_CTLR_COLOR_RAW8, + .output_data_color_type = CAM_CTLR_COLOR_RGB565, .data_lane_num = 2, .byte_swap_en = false, .queue_items = 1, From 9713bd63a43cfecf6cb812e8b2c5859ee3b56f7e Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 23 May 2024 13:13:19 +0800 Subject: [PATCH 202/548] fix(csi): fixed csi wrong state machine settings --- components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 6c7951ace35..00156d49830 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -413,7 +413,7 @@ esp_err_t s_csi_ctlr_disable(esp_cam_ctlr_handle_t handle) { ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); csi_controller_t *ctlr = __containerof(handle, csi_controller_t, base); - ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_ENABLED, ESP_ERR_INVALID_STATE, TAG, "processor isn't in init state"); + ESP_RETURN_ON_FALSE(ctlr->csi_fsm == CSI_FSM_ENABLED, ESP_ERR_INVALID_STATE, TAG, "processor isn't in enable state"); portENTER_CRITICAL(&ctlr->spinlock); ctlr->csi_fsm = CSI_FSM_INIT; @@ -485,7 +485,7 @@ esp_err_t s_ctlr_csi_stop(esp_cam_ctlr_handle_t handle) ESP_RETURN_ON_ERROR(dw_gdma_channel_enable_ctrl(ctlr->dma_chan, false), TAG, "failed to disable dwgdma"); portENTER_CRITICAL(&ctlr->spinlock); - ctlr->csi_fsm = CSI_FSM_INIT; + ctlr->csi_fsm = CSI_FSM_ENABLED; portEXIT_CRITICAL(&ctlr->spinlock); return ESP_OK; From f58b63d31e9b422c2e586fe6b849fbb4a19b0058 Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 23 May 2024 13:36:15 +0800 Subject: [PATCH 203/548] test(isp_dvp): added isp_dvp test --- .../test_apps/.build-test-rules.yml | 6 +++ .../test_apps/isp_dvp/CMakeLists.txt | 6 +++ .../test_apps/isp_dvp/README.md | 2 + .../test_apps/isp_dvp/main/CMakeLists.txt | 16 ++++++ .../test_apps/isp_dvp/main/test_app_main.c | 27 ++++++++++ .../isp_dvp/main/test_isp_dvp_driver.c | 49 +++++++++++++++++++ .../test_apps/isp_dvp/pytest_isp_dvp.py | 10 ++++ .../test_apps/isp/main/test_isp_driver.c | 40 --------------- 8 files changed, 116 insertions(+), 40 deletions(-) create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/CMakeLists.txt create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/README.md create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/main/CMakeLists.txt create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/main/test_app_main.c create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/main/test_isp_dvp_driver.c create mode 100644 components/esp_driver_cam/test_apps/isp_dvp/pytest_isp_dvp.py diff --git a/components/esp_driver_cam/test_apps/.build-test-rules.yml b/components/esp_driver_cam/test_apps/.build-test-rules.yml index 025201a69d1..62f5e1aef94 100644 --- a/components/esp_driver_cam/test_apps/.build-test-rules.yml +++ b/components/esp_driver_cam/test_apps/.build-test-rules.yml @@ -3,3 +3,9 @@ components/esp_driver_cam/test_apps/csi: - if: SOC_MIPI_CSI_SUPPORTED != 1 depends_components: - esp_driver_cam + +components/esp_driver_cam/test_apps/isp_dvp: + disable: + - if: SOC_ISP_DVP_SUPPORTED != 1 + depends_components: + - esp_driver_cam diff --git a/components/esp_driver_cam/test_apps/isp_dvp/CMakeLists.txt b/components/esp_driver_cam/test_apps/isp_dvp/CMakeLists.txt new file mode 100644 index 00000000000..89ec188d05c --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.16) + +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_isp_dvp) diff --git a/components/esp_driver_cam/test_apps/isp_dvp/README.md b/components/esp_driver_cam/test_apps/isp_dvp/README.md new file mode 100644 index 00000000000..909282018f2 --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | diff --git a/components/esp_driver_cam/test_apps/isp_dvp/main/CMakeLists.txt b/components/esp_driver_cam/test_apps/isp_dvp/main/CMakeLists.txt new file mode 100644 index 00000000000..382e87b8ca3 --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/main/CMakeLists.txt @@ -0,0 +1,16 @@ +set(srcs "test_app_main.c") + +if(CONFIG_SOC_ISP_DVP_SUPPORTED) + list(APPEND srcs "test_isp_dvp_driver.c") +endif() + +set(priv_requires + unity + esp_driver_cam + esp_psram +) + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES ${priv_requires} + WHOLE_ARCHIVE TRUE) diff --git a/components/esp_driver_cam/test_apps/isp_dvp/main/test_app_main.c b/components/esp_driver_cam/test_apps/isp_dvp/main/test_app_main.c new file mode 100644 index 00000000000..a47ab1a130d --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/main/test_app_main.c @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_heap_caps.h" +#include "sdkconfig.h" + +#define TEST_MEMORY_LEAK_THRESHOLD (400) + +void setUp(void) +{ + unity_utils_record_free_mem(); +} + +void tearDown(void) +{ + unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); +} + +void app_main(void) +{ + unity_run_menu(); +} diff --git a/components/esp_driver_cam/test_apps/isp_dvp/main/test_isp_dvp_driver.c b/components/esp_driver_cam/test_apps/isp_dvp/main/test_isp_dvp_driver.c new file mode 100644 index 00000000000..5d0fa2f64d9 --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/main/test_isp_dvp_driver.c @@ -0,0 +1,49 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "sdkconfig.h" +#include "unity.h" +#include "esp_cam_ctlr_isp_dvp.h" +#include "esp_cam_ctlr.h" +#include "driver/isp.h" + +TEST_CASE("ISP DVP controller exhausted allocation", "[isp]") +{ + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 120 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_DVP, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + .has_line_start_packet = false, + .has_line_end_packet = false, + .h_res = 800, + .v_res = 640, + }; + isp_proc_handle_t isp_proc = NULL; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + + esp_cam_ctlr_isp_dvp_cfg_t dvp_ctlr_config = { + .data_width = 8, + .data_io = {53, 54, 52, 0, 1, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, + .pclk_io = 21, + .hsync_io = 5, + .vsync_io = 23, + .de_io = 22, + .io_flags.vsync_invert = 1, + .queue_items = 10, + }; + esp_cam_ctlr_handle_t dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS + 1] = {}; + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_cam_new_isp_dvp_ctlr(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[i])); + } + + TEST_ASSERT(esp_cam_new_isp_dvp_ctlr(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS]) == ESP_ERR_NOT_FOUND); + + for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { + TEST_ESP_OK(esp_cam_ctlr_del(dvp_ctrlr[i])); + } + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); +} diff --git a/components/esp_driver_cam/test_apps/isp_dvp/pytest_isp_dvp.py b/components/esp_driver_cam/test_apps/isp_dvp/pytest_isp_dvp.py new file mode 100644 index 00000000000..a9922987c5a --- /dev/null +++ b/components/esp_driver_cam/test_apps/isp_dvp/pytest_isp_dvp.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_isp_dvp(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index ff4f9762462..c6a3abcbe96 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -7,7 +7,6 @@ #include "sdkconfig.h" #include "unity.h" #include "driver/isp.h" -#include "esp_private/isp_dvp_private.h" #include "soc/soc_caps.h" TEST_CASE("ISP processor exhausted allocation", "[isp]") @@ -31,45 +30,6 @@ TEST_CASE("ISP processor exhausted allocation", "[isp]") } } -#if SOC_ISP_DVP_SUPPORTED -TEST_CASE("ISP DVP controller exhausted allocation", "[isp]") -{ - esp_isp_processor_cfg_t isp_config = { - .clk_hz = 120 * 1000 * 1000, - .input_data_source = ISP_INPUT_DATA_SOURCE_DVP, - .input_data_color_type = ISP_COLOR_RAW8, - .output_data_color_type = ISP_COLOR_RGB565, - .has_line_start_packet = false, - .has_line_end_packet = false, - .h_res = 800, - .v_res = 640, - }; - isp_proc_handle_t isp_proc = NULL; - TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); - - esp_cam_ctlr_isp_dvp_cfg_t dvp_ctlr_config = { - .data_width = 8, - .data_io = {53, 54, 52, 0, 1, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, -1}, - .pclk_io = 21, - .hsync_io = 5, - .vsync_io = 23, - .de_io = 22, - .io_flags.vsync_invert = 1, - }; - esp_cam_ctlr_handle_t dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS + 1] = {}; - for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { - TEST_ESP_OK(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[i])); - } - - TEST_ASSERT(esp_isp_new_dvp_controller(isp_proc, &dvp_ctlr_config, &dvp_ctrlr[SOC_ISP_DVP_CTLR_NUMS]) == ESP_ERR_NOT_FOUND); - - for (int i = 0; i < SOC_ISP_DVP_CTLR_NUMS; i++) { - TEST_ESP_OK(esp_isp_del_dvp_controller(dvp_ctrlr[i])); - } - TEST_ESP_OK(esp_isp_del_processor(isp_proc)); -} -#endif - TEST_CASE("ISP AF controller exhausted allocation", "[isp]") { esp_isp_processor_cfg_t isp_config = { From de1d006ba31c736bade528dd949cfe8032e19032 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 4 Jun 2024 14:58:51 +0800 Subject: [PATCH 204/548] change(isp): change isp_af_window_t to isp_window_t --- .../esp_driver_isp/include/driver/isp_af.h | 2 +- components/esp_driver_isp/src/isp_af.c | 22 ++++++------ components/hal/include/hal/isp_hal.h | 2 +- components/hal/include/hal/isp_types.h | 28 +++++++++------ components/hal/isp_hal.c | 4 +-- .../isp/auto_focus/main/isp_af_dsi_main.c | 36 ++++++++++++------- 6 files changed, 57 insertions(+), 37 deletions(-) diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 9058ea7445f..d3d9522d79b 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -19,7 +19,7 @@ extern "C" { * @brief AF controller config */ typedef struct { - isp_af_window_t window[ISP_AF_WINDOW_NUM]; ///< The sampling windows of AF + isp_window_t window[ISP_AF_WINDOW_NUM]; ///< The sampling windows of AF int edge_thresh; ///< Edge threshold, definition higher than this value will be counted as a valid pixel for calculating AF result int intr_priority; ///< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) otherwise the larger the higher, 7 is NMI } esp_isp_af_config_t; diff --git a/components/esp_driver_isp/src/isp_af.c b/components/esp_driver_isp/src/isp_af.c index 02f289a4417..dd7ad8d4f3e 100644 --- a/components/esp_driver_isp/src/isp_af.c +++ b/components/esp_driver_isp/src/isp_af.c @@ -88,17 +88,17 @@ esp_err_t esp_isp_new_af_controller(isp_proc_handle_t isp_proc, const esp_isp_af ESP_RETURN_ON_FALSE(demosaic_en && rgb2yuv_en, ESP_ERR_INVALID_STATE, TAG, "RGB2YUV not enabled, please update the output_data_color_type"); for (int i = 0; i < SOC_ISP_AF_WINDOW_NUMS; i++) { - ESP_LOGV(TAG, "af_config->window[%d].top_left_x: %"PRId32, i, af_config->window[i].top_left_x); - ESP_LOGV(TAG, "af_config->window[%d].bottom_right_x: %"PRId32, i, af_config->window[i].bottom_right_x); - ESP_LOGV(TAG, "af_config->window[%d].bottom_right_y: %"PRId32, i, af_config->window[i].bottom_right_y); - ESP_LOGV(TAG, "af_config->window[%d].top_left_y: %"PRId32, i, af_config->window[i].top_left_y); - - ESP_RETURN_ON_FALSE(((af_config->window[i].top_left_x < ISP_LL_AF_WINDOW_MAX_RANGE) && - (af_config->window[i].bottom_right_x >= af_config->window[i].top_left_x) && - (af_config->window[i].bottom_right_x < ISP_LL_AF_WINDOW_MAX_RANGE) && - (af_config->window[i].top_left_y < ISP_LL_AF_WINDOW_MAX_RANGE) && - (af_config->window[i].bottom_right_y >= af_config->window[i].top_left_y) && - (af_config->window[i].bottom_right_y < ISP_LL_AF_WINDOW_MAX_RANGE)), ESP_ERR_INVALID_ARG, TAG, "invalid window"); + ESP_LOGV(TAG, "af_config->window[%d].top_left.x: %"PRId32, i, af_config->window[i].top_left.x); + ESP_LOGV(TAG, "af_config->window[%d].btm_right.x: %"PRId32, i, af_config->window[i].btm_right.x); + ESP_LOGV(TAG, "af_config->window[%d].btm_right.y: %"PRId32, i, af_config->window[i].btm_right.y); + ESP_LOGV(TAG, "af_config->window[%d].top_left.y: %"PRId32, i, af_config->window[i].top_left.y); + + ESP_RETURN_ON_FALSE(((af_config->window[i].top_left.x < ISP_LL_AF_WINDOW_MAX_RANGE) && + (af_config->window[i].btm_right.x >= af_config->window[i].top_left.x) && + (af_config->window[i].btm_right.x < ISP_LL_AF_WINDOW_MAX_RANGE) && + (af_config->window[i].top_left.y < ISP_LL_AF_WINDOW_MAX_RANGE) && + (af_config->window[i].btm_right.y >= af_config->window[i].top_left.y) && + (af_config->window[i].btm_right.y < ISP_LL_AF_WINDOW_MAX_RANGE)), ESP_ERR_INVALID_ARG, TAG, "invalid window"); } ESP_RETURN_ON_FALSE(af_config->edge_thresh > 0, ESP_ERR_INVALID_ARG, TAG, "edge threshold should be larger than 0"); diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index 9aacd179d8b..c239fa43184 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -62,7 +62,7 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id); * @param[in] window_id Window ID * @param[in] window Window info, see `isp_af_window_t` */ -void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_af_window_t *window); +void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_window_t *window); /*--------------------------------------------------------------- INTR diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index baa74ea90d6..2d02ae3cd81 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -23,6 +23,24 @@ typedef soc_periph_isp_clk_src_t isp_clk_src_t; ///< Clock source type of typedef int isp_clk_src_t; ///< Default type #endif +/** + * @brief ISP coordinate type + * + */ +typedef struct { + uint32_t x; ///< X coordinate of the point + uint32_t y; ///< Y coordinate of the point +} isp_coordinate_t; + +/** + * @brief ISP window type + * + */ +typedef struct { + isp_coordinate_t top_left; ///< The top left point coordinate + isp_coordinate_t btm_right; ///< The bottom right point coordinate +} isp_window_t; + /** * @brief ISP Input Source */ @@ -63,16 +81,6 @@ typedef enum { #define ISP_AF_WINDOW_NUM 0 #endif -/** - * @brief ISP AF window - */ -typedef struct { - uint32_t top_left_x; ///< Top left x axis value - uint32_t top_left_y; ///< Top left y axis value - uint32_t bottom_right_x; ///< Bottom right x axis value - uint32_t bottom_right_y; ///< Bottom right y axis value -} isp_af_window_t; - /** * @brief ISP AF result */ diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index 3bb38906939..16b496a3af9 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -27,9 +27,9 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id) /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ -void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_af_window_t *window) +void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_window_t *window) { - isp_ll_af_set_window_range(hal->hw, window_id, window->top_left_x, window->top_left_y, window->bottom_right_x, window->bottom_right_y); + isp_ll_af_set_window_range(hal->hw, window_id, window->top_left.x, window->top_left.y, window->btm_right.x, window->btm_right.y); } /*--------------------------------------------------------------- diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c index 0d8be2f9bbf..d8f84c2b0c1 100644 --- a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -99,22 +99,34 @@ static void af_task(void *arg) esp_isp_af_config_t af_config = { .window = { [0] = { - .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, - .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, - .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, - .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + .top_left = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + }, + .btm_right = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, }, [1] = { - .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, - .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, - .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, - .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + .top_left = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + }, + .btm_right = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, }, [2] = { - .top_left_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, - .bottom_right_x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, - .top_left_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, - .bottom_right_y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + .top_left = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) - 100, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) - 100, + }, + .btm_right = { + .x = (CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES / 2) + 99, + .y = (CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES / 2) + 99, + }, }, }, .edge_thresh = 128, From be9c4ebf44eed6b17dba054b06ee92d144baefdf Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 4 Jun 2024 15:00:07 +0800 Subject: [PATCH 205/548] fix(isp): reverted only raw8 input limits --- components/esp_driver_isp/src/isp_core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index d1aa78784ca..a2586bd105f 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -74,7 +74,6 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ esp_err_t ret = ESP_FAIL; ESP_RETURN_ON_FALSE(proc_config && ret_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(proc_config->input_data_source != ISP_INPUT_DATA_SOURCE_DWGDMA, ESP_ERR_NOT_SUPPORTED, TAG, "input source not supported yet"); - ESP_RETURN_ON_FALSE(proc_config->input_data_color_type == ISP_COLOR_RAW8, ESP_ERR_NOT_SUPPORTED, TAG, "input data type not supported"); isp_processor_t *proc = heap_caps_calloc(1, sizeof(isp_processor_t), ISP_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(proc, ESP_ERR_NO_MEM, TAG, "no mem"); From dbccfbb2e713ec0da3b629143e516d11869c37c9 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 5 Jun 2024 11:08:17 +0800 Subject: [PATCH 206/548] change(isp): don't init unnecessary isp pipeline items when doing isp_new_processor --- components/esp_driver_isp/src/isp_bf.c | 2 ++ components/esp_driver_isp/src/isp_core.c | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/components/esp_driver_isp/src/isp_bf.c b/components/esp_driver_isp/src/isp_bf.c index e2258216f40..b8b7cf39867 100644 --- a/components/esp_driver_isp/src/isp_bf.c +++ b/components/esp_driver_isp/src/isp_bf.c @@ -56,6 +56,7 @@ esp_err_t esp_isp_bf_enable(isp_proc_handle_t proc) ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(proc->bf_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "bf is enabled already"); + isp_ll_bf_clk_enable(proc->hal.hw, true); isp_ll_bf_enable(proc->hal.hw, true); proc->bf_fsm = ISP_FSM_ENABLE; @@ -68,6 +69,7 @@ esp_err_t esp_isp_bf_disable(isp_proc_handle_t proc) ESP_RETURN_ON_FALSE(proc->bf_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "bf isn't enabled yet"); isp_ll_bf_enable(proc->hal.hw, false); + isp_ll_bf_clk_enable(proc->hal.hw, false); proc->bf_fsm = ISP_FSM_INIT; return ESP_OK; diff --git a/components/esp_driver_isp/src/isp_core.c b/components/esp_driver_isp/src/isp_core.c index a2586bd105f..8fbf9e5f66a 100644 --- a/components/esp_driver_isp/src/isp_core.c +++ b/components/esp_driver_isp/src/isp_core.c @@ -104,13 +104,6 @@ esp_err_t esp_isp_new_processor(const esp_isp_processor_cfg_t *proc_config, isp_ } isp_hal_init(&proc->hal, proc->proc_id); - //necessary ISP submodules that needs basic initialisation - isp_ll_bf_clk_enable(proc->hal.hw, true); - isp_ll_bf_enable(proc->hal.hw, true); - isp_ll_ccm_clk_enable(proc->hal.hw, true); - isp_ll_ccm_enable(proc->hal.hw, true); - isp_ll_color_clk_enable(proc->hal.hw, true); - isp_ll_color_enable(proc->hal.hw, true); PERIPH_RCC_ATOMIC() { isp_ll_select_clk_source(proc->hal.hw, clk_src); isp_ll_set_clock_div(proc->hal.hw, &clk_div); From ab818887057a284400b0ea92b61638d9dc9c6df9 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 22 May 2024 16:21:15 +0800 Subject: [PATCH 207/548] fix(i2s): add check to gdma callback register --- components/esp_driver_i2s/i2s_common.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 7bd6cddd6d7..43a69580174 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -696,6 +696,7 @@ static void IRAM_ATTR i2s_dma_tx_callback(void *arg) */ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) { + esp_err_t ret = ESP_OK; i2s_port_t port_id = handle->controller->id; ESP_RETURN_ON_FALSE((port_id >= 0) && (port_id < SOC_I2S_NUM), ESP_ERR_INVALID_ARG, TAG, "invalid handle"); #if SOC_GDMA_SUPPORTED @@ -719,18 +720,18 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX; /* Register a new GDMA tx channel */ ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register tx dma channel error"); - ESP_RETURN_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), TAG, "Connect tx dma channel error"); + ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect tx dma channel error"); gdma_tx_event_callbacks_t cb = {.on_trans_eof = i2s_dma_tx_callback}; /* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */ - gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle); + ESP_GOTO_ON_ERROR(gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register tx callback failed"); } else { dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX; /* Register a new GDMA rx channel */ ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register rx dma channel error"); - ESP_RETURN_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), TAG, "Connect rx dma channel error"); + ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect rx dma channel error"); gdma_rx_event_callbacks_t cb = {.on_recv_eof = i2s_dma_rx_callback}; /* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */ - gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle); + ESP_GOTO_ON_ERROR(gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register rx callback failed"); } #else intr_flag |= handle->intr_prio_flags; @@ -747,7 +748,15 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) /* Start DMA */ i2s_ll_enable_dma(handle->controller->hal.dev, true); #endif // SOC_GDMA_SUPPORTED - return ESP_OK; + return ret; +#if SOC_GDMA_SUPPORTED +err2: + gdma_disconnect(handle->dma.dma_chan); +err1: + gdma_del_channel(handle->dma.dma_chan); + handle->dma.dma_chan = NULL; + return ret; +#endif } static uint64_t s_i2s_get_pair_chan_gpio_mask(i2s_chan_handle_t handle) From cd4c71e20f7d676ba22c320d546f64ee18635f75 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 22 May 2024 16:23:06 +0800 Subject: [PATCH 208/548] fix(i2s): add the missed port2 for p4 --- components/driver/deprecated/i2s_legacy.c | 10 +++++++++- components/esp_driver_i2s/i2s_common.c | 10 +++++++++- .../esp_driver_i2s/include/driver/i2s_types.h | 3 +++ .../test_apps/i2s/main/test_i2s.c | 18 ++++++++++++++++-- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index d36b2e2945c..a7d26760a78 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -348,14 +348,22 @@ static esp_err_t i2s_dma_intr_init(i2s_port_t i2s_num, int intr_flag) gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S}; switch (i2s_num) { +#if SOC_I2S_NUM > 2 + case I2S_NUM_2: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S2; + break; +#endif #if SOC_I2S_NUM > 1 case I2S_NUM_1: trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1; break; #endif - default: + case I2S_NUM_0: trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0; break; + default: + ESP_LOGE(TAG, "Unsupported I2S port number"); + return ESP_ERR_NOT_SUPPORTED; } /* Set GDMA config */ diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 43a69580174..7520bb23cca 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -704,14 +704,22 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S}; switch (port_id) { +#if SOC_I2S_NUM > 2 + case I2S_NUM_2: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S2; + break; +#endif #if SOC_I2S_NUM > 1 case I2S_NUM_1: trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1; break; #endif - default: + case I2S_NUM_0: trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0; break; + default: + ESP_LOGE(TAG, "Unsupported I2S port number"); + return ESP_ERR_NOT_SUPPORTED; } /* Set GDMA config */ diff --git a/components/esp_driver_i2s/include/driver/i2s_types.h b/components/esp_driver_i2s/include/driver/i2s_types.h index 2135124389c..9f103f0718c 100644 --- a/components/esp_driver_i2s/include/driver/i2s_types.h +++ b/components/esp_driver_i2s/include/driver/i2s_types.h @@ -22,6 +22,9 @@ typedef enum { I2S_NUM_0 = 0, /*!< I2S controller port 0 */ #if SOC_I2S_NUM > 1 I2S_NUM_1 = 1, /*!< I2S controller port 1 */ +#endif +#if SOC_I2S_NUM > 2 + I2S_NUM_2 = 2, /*!< I2S controller port 2 */ #endif I2S_NUM_AUTO, /*!< Select whichever port is available */ } i2s_port_t; diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c index 5cb9489b5dc..93aca31233a 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c @@ -190,7 +190,21 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]") TEST_ESP_OK(i2s_channel_enable(tx_handle)); TEST_ESP_OK(i2s_channel_disable(tx_handle)); TEST_ESP_OK(i2s_del_channel(tx_handle)); - TEST_ASSERT(i2s_channel_get_info(tx_handle, &chan_info) == ESP_ERR_NOT_FOUND); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_channel_get_info(tx_handle, &chan_info)); + + /* Exhaust test */ + std_cfg.gpio_cfg.mclk = -1; + i2s_chan_handle_t tx_ex[SOC_I2S_NUM] = {}; + for (int i = 0; i < SOC_I2S_NUM; i++) { + TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_ex[i], NULL)); + TEST_ESP_OK(i2s_channel_init_std_mode(tx_ex[i], &std_cfg)); + TEST_ESP_OK(i2s_channel_enable(tx_ex[i])); + } + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, NULL)); + for (int i = 0; i < SOC_I2S_NUM; i++) { + TEST_ESP_OK(i2s_channel_disable(tx_ex[i])); + TEST_ESP_OK(i2s_del_channel(tx_ex[i])); + } /* Duplex channel basic test */ chan_cfg.id = I2S_NUM_0; // Specify port id to I2S port 0 @@ -208,7 +222,7 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]") /* Hold the occupation */ TEST_ESP_OK(i2s_platform_acquire_occupation(I2S_NUM_0, "test_i2s")); - TEST_ASSERT(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle) == ESP_ERR_NOT_FOUND); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); TEST_ESP_OK(i2s_platform_release_occupation(I2S_NUM_0)); TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle)); TEST_ESP_OK(i2s_del_channel(tx_handle)); From 33ac88cd319047aecca99d50cd215d673de2f3d7 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 29 May 2024 22:16:50 +0800 Subject: [PATCH 209/548] change(esp_lcd): split header files by different IO interface --- components/esp_lcd/CMakeLists.txt | 4 +- components/esp_lcd/include/esp_lcd_io_i2c.h | 87 +++++++ components/esp_lcd/include/esp_lcd_io_i80.h | 107 +++++++++ components/esp_lcd/include/esp_lcd_io_spi.h | 59 +++++ components/esp_lcd/include/esp_lcd_panel_io.h | 224 +----------------- components/esp_lcd/include/esp_lcd_types.h | 24 ++ docs/doxygen/Doxyfile | 3 + .../api-reference/peripherals/lcd/i2c_lcd.rst | 5 + .../api-reference/peripherals/lcd/i80_lcd.rst | 5 + .../api-reference/peripherals/lcd/spi_lcd.rst | 5 + 10 files changed, 300 insertions(+), 223 deletions(-) create mode 100644 components/esp_lcd/include/esp_lcd_io_i2c.h create mode 100644 components/esp_lcd/include/esp_lcd_io_i80.h create mode 100644 components/esp_lcd/include/esp_lcd_io_spi.h diff --git a/components/esp_lcd/CMakeLists.txt b/components/esp_lcd/CMakeLists.txt index b35a4becd51..3365a205ce5 100644 --- a/components/esp_lcd/CMakeLists.txt +++ b/components/esp_lcd/CMakeLists.txt @@ -11,8 +11,8 @@ set(srcs "src/esp_lcd_common.c" "src/esp_lcd_panel_st7789.c" "src/esp_lcd_panel_ops.c") set(includes "include" "interface") -set(priv_requires "esp_mm" "esp_psram" "esp_pm" "esp_driver_spi" "esp_driver_i2s") -set(public_requires "driver" "esp_driver_gpio" "esp_driver_i2c") +set(priv_requires "esp_mm" "esp_psram" "esp_pm" "esp_driver_i2s") +set(public_requires "driver" "esp_driver_gpio" "esp_driver_i2c" "esp_driver_spi") if(CONFIG_SOC_DMA2D_SUPPORTED) list(APPEND srcs "src/esp_async_fbcpy.c") diff --git a/components/esp_lcd/include/esp_lcd_io_i2c.h b/components/esp_lcd/include/esp_lcd_io_i2c.h new file mode 100644 index 00000000000..73ee69e55e0 --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_io_i2c.h @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_types.h" +#include "driver/i2c_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t esp_lcd_i2c_bus_handle_t; /*!< Type of LCD I2C bus handle */ + +/** + * @brief Panel IO configuration structure, for I2C interface + * + */ +typedef struct { + uint32_t dev_addr; /*!< I2C device address */ + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ + void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ + size_t control_phase_bytes; /*!< I2C LCD panel will encode control information (e.g. D/C selection) into control phase, in several bytes */ + unsigned int dc_bit_offset; /*!< Offset of the D/C selection bit in control phase */ + int lcd_cmd_bits; /*!< Bit-width of LCD command */ + int lcd_param_bits; /*!< Bit-width of LCD parameter */ + struct { + unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */ + unsigned int disable_control_phase: 1; /*!< If this flag is enabled, the control phase isn't used */ + } flags; /*!< Extra flags to fine-tune the I2C device */ + uint32_t scl_speed_hz; /*!< I2C LCD SCL frequency (hz) */ +} esp_lcd_panel_io_i2c_config_t; + +/** + * @brief Create LCD panel IO handle, for I2C interface in legacy implementation + * + * @param[in] bus I2C bus handle, (in uint32_t) + * @param[in] io_config IO configuration, for I2C interface + * @param[out] ret_io Returned IO handle + * + * @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead. + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); + +/** + * @brief Create LCD panel IO handle, for I2C interface in new implementation + * + * @param[in] bus I2C bus handle, (in i2c_master_dev_handle_t) + * @param[in] io_config IO configuration, for I2C interface + * @param[out] ret_io Returned IO handle + * + * @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead. + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); + +/** + * @brief Create LCD panel IO handle + * + * @param[in] bus I2C bus handle + * @param[in] io_config IO configuration, for I2C interface + * @param[out] ret_io Returned IO handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +#define esp_lcd_new_panel_io_i2c(bus, io_config, ret_io) _Generic((bus), \ + i2c_master_bus_handle_t : esp_lcd_new_panel_io_i2c_v2, \ + default : esp_lcd_new_panel_io_i2c_v1) (bus, io_config, ret_io) \ + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_io_i80.h b/components/esp_lcd/include/esp_lcd_io_i80.h new file mode 100644 index 00000000000..664afc0000a --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_io_i80.h @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_types.h" +#include "soc/soc_caps.h" + +#define ESP_LCD_I80_BUS_WIDTH_MAX 16 /*!< Maximum width of I80 bus */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct esp_lcd_i80_bus_t *esp_lcd_i80_bus_handle_t; /*!< Type of LCD intel 8080 bus handle */ + +#if SOC_LCD_I80_SUPPORTED +/** + * @brief LCD Intel 8080 bus configuration structure + */ +typedef struct { + int dc_gpio_num; /*!< GPIO used for D/C line */ + int wr_gpio_num; /*!< GPIO used for WR line */ + lcd_clock_source_t clk_src; /*!< Clock source for the I80 LCD peripheral */ + int data_gpio_nums[ESP_LCD_I80_BUS_WIDTH_MAX]; /*!< GPIOs used for data lines */ + size_t bus_width; /*!< Number of data lines, 8 or 16 */ + size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */ + union { + size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */ + size_t dma_burst_size; /*!< DMA burst size, in bytes */ + }; + size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */ +} esp_lcd_i80_bus_config_t; + +/** + * @brief Create Intel 8080 bus handle + * + * @param[in] bus_config Bus configuration + * @param[out] ret_bus Returned bus handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_ERR_NOT_FOUND if no free bus is available + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lcd_i80_bus_handle_t *ret_bus); + +/** + * @brief Destroy Intel 8080 bus handle + * + * @param[in] bus Intel 8080 bus handle, created by `esp_lcd_new_i80_bus()` + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_STATE if there still be some device attached to the bus + * - ESP_OK on success + */ +esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus); + +/** + * @brief Panel IO configuration structure, for intel 8080 interface + */ +typedef struct { + int cs_gpio_num; /*!< GPIO used for CS line, set to -1 will declaim exclusively use of I80 bus */ + uint32_t pclk_hz; /*!< Frequency of pixel clock */ + size_t trans_queue_depth; /*!< Transaction queue size, larger queue, higher throughput */ + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data was transferred done */ + void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ + int lcd_cmd_bits; /*!< Bit-width of LCD command */ + int lcd_param_bits; /*!< Bit-width of LCD parameter */ + struct { + unsigned int dc_idle_level: 1; /*!< Level of DC line in IDLE phase */ + unsigned int dc_cmd_level: 1; /*!< Level of DC line in CMD phase */ + unsigned int dc_dummy_level: 1; /*!< Level of DC line in DUMMY phase */ + unsigned int dc_data_level: 1; /*!< Level of DC line in DATA phase */ + } dc_levels; /*!< Each i80 device might have its own D/C control logic */ + struct { + unsigned int cs_active_high: 1; /*!< If set, a high level of CS line will select the device, otherwise, CS line is low level active */ + unsigned int reverse_color_bits: 1; /*!< Reverse the data bits, D[N:0] -> D[0:N] */ + unsigned int swap_color_bytes: 1; /*!< Swap adjacent two color bytes */ + unsigned int pclk_active_neg: 1; /*!< The display will write data lines when there's a falling edge on WR signal (a.k.a the PCLK) */ + unsigned int pclk_idle_low: 1; /*!< The WR signal (a.k.a the PCLK) stays at low level in IDLE phase */ + } flags; /*!< Panel IO config flags */ +} esp_lcd_panel_io_i80_config_t; + +/** + * @brief Create LCD panel IO, for Intel 8080 interface + * + * @param[in] bus Intel 8080 bus handle, created by `esp_lcd_new_i80_bus()` + * @param[in] io_config IO configuration, for i80 interface + * @param[out] ret_io Returned panel IO handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NOT_SUPPORTED if some configuration can't be satisfied, e.g. pixel clock out of the range + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_panel_io_i80_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); + +#endif // SOC_LCD_I80_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_io_spi.h b/components/esp_lcd/include/esp_lcd_io_spi.h new file mode 100644 index 00000000000..43e1f571295 --- /dev/null +++ b/components/esp_lcd/include/esp_lcd_io_spi.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "esp_lcd_types.h" +#include "driver/spi_master.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int esp_lcd_spi_bus_handle_t; /*!< Type of LCD SPI bus handle */ + +/** + * @brief Panel IO configuration structure, for SPI interface + */ +typedef struct { + int cs_gpio_num; /*!< GPIO used for CS line */ + int dc_gpio_num; /*!< GPIO used to select the D/C line, set this to -1 if the D/C line is not used */ + int spi_mode; /*!< Traditional SPI mode (0~3) */ + unsigned int pclk_hz; /*!< Frequency of pixel clock */ + size_t trans_queue_depth; /*!< Size of internal transaction queue */ + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ + void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ + int lcd_cmd_bits; /*!< Bit-width of LCD command */ + int lcd_param_bits; /*!< Bit-width of LCD parameter */ + struct { + unsigned int dc_high_on_cmd: 1; /*!< If enabled, DC level = 1 indicates command transfer */ + unsigned int dc_low_on_data: 1; /*!< If enabled, DC level = 0 indicates color data transfer */ + unsigned int dc_low_on_param: 1; /*!< If enabled, DC level = 0 indicates parameter transfer */ + unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */ + unsigned int quad_mode: 1; /*!< transmit with quad mode (4 data lines), this mode is useful when transmitting LCD parameters (Only use one line for command) */ + unsigned int sio_mode: 1; /*!< Read and write through a single data line (MOSI) */ + unsigned int lsb_first: 1; /*!< transmit LSB bit first */ + unsigned int cs_high_active: 1; /*!< CS line is high active */ + } flags; /*!< Extra flags to fine-tune the SPI device */ +} esp_lcd_panel_io_spi_config_t; + +/** + * @brief Create LCD panel IO handle, for SPI interface + * + * @param[in] bus SPI bus handle + * @param[in] io_config IO configuration, for SPI interface + * @param[out] ret_io Returned IO handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_panel_io_spi_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_lcd/include/esp_lcd_panel_io.h b/components/esp_lcd/include/esp_lcd_panel_io.h index 03f0248a89c..ee2707f4eaa 100644 --- a/components/esp_lcd/include/esp_lcd_panel_io.h +++ b/components/esp_lcd/include/esp_lcd_panel_io.h @@ -8,44 +8,14 @@ #include #include "esp_err.h" #include "esp_lcd_types.h" -#include "soc/soc_caps.h" -#include "hal/lcd_types.h" -#include "hal/i2c_types.h" -#include "driver/i2c_types.h" - -#define ESP_LCD_I80_BUS_WIDTH_MAX 16 /*!< Maximum width of I80 bus */ +#include "esp_lcd_io_i80.h" +#include "esp_lcd_io_i2c.h" +#include "esp_lcd_io_spi.h" #ifdef __cplusplus extern "C" { #endif -typedef void *esp_lcd_spi_bus_handle_t; /*!< Type of LCD SPI bus handle */ -typedef uint32_t esp_lcd_i2c_bus_handle_t; /*!< Type of LCD I2C bus handle */ -typedef struct esp_lcd_i80_bus_t *esp_lcd_i80_bus_handle_t; /*!< Type of LCD intel 8080 bus handle */ - -/** - * @brief Type of LCD panel IO event data - */ -typedef struct { -} esp_lcd_panel_io_event_data_t; - -/** - * @brief Declare the prototype of the function that will be invoked when panel IO finishes transferring color data - * - * @param[in] panel_io LCD panel IO handle, which is created by factory API like `esp_lcd_new_panel_io_spi()` - * @param[in] edata Panel IO event data, fed by driver - * @param[in] user_ctx User data, passed from `esp_lcd_panel_io_xxx_config_t` - * @return Whether a high priority task has been waken up by this function - */ -typedef bool (*esp_lcd_panel_io_color_trans_done_cb_t)(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); - -/** - * @brief Type of LCD panel IO callbacks - */ -typedef struct { - esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ -} esp_lcd_panel_io_callbacks_t; - /** * @brief Transmit LCD command and receive corresponding parameters * @@ -123,194 +93,6 @@ esp_err_t esp_lcd_panel_io_del(esp_lcd_panel_io_handle_t io); */ esp_err_t esp_lcd_panel_io_register_event_callbacks(esp_lcd_panel_io_handle_t io, const esp_lcd_panel_io_callbacks_t *cbs, void *user_ctx); -/** - * @brief Panel IO configuration structure, for SPI interface - */ -typedef struct { - int cs_gpio_num; /*!< GPIO used for CS line */ - int dc_gpio_num; /*!< GPIO used to select the D/C line, set this to -1 if the D/C line is not used */ - int spi_mode; /*!< Traditional SPI mode (0~3) */ - unsigned int pclk_hz; /*!< Frequency of pixel clock */ - size_t trans_queue_depth; /*!< Size of internal transaction queue */ - esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ - void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ - int lcd_cmd_bits; /*!< Bit-width of LCD command */ - int lcd_param_bits; /*!< Bit-width of LCD parameter */ - struct { - unsigned int dc_high_on_cmd: 1; /*!< If enabled, DC level = 1 indicates command transfer */ - unsigned int dc_low_on_data: 1; /*!< If enabled, DC level = 0 indicates color data transfer */ - unsigned int dc_low_on_param: 1; /*!< If enabled, DC level = 0 indicates parameter transfer */ - unsigned int octal_mode: 1; /*!< transmit with octal mode (8 data lines), this mode is used to simulate Intel 8080 timing */ - unsigned int quad_mode: 1; /*!< transmit with quad mode (4 data lines), this mode is useful when transmitting LCD parameters (Only use one line for command) */ - unsigned int sio_mode: 1; /*!< Read and write through a single data line (MOSI) */ - unsigned int lsb_first: 1; /*!< transmit LSB bit first */ - unsigned int cs_high_active: 1; /*!< CS line is high active */ - } flags; /*!< Extra flags to fine-tune the SPI device */ -} esp_lcd_panel_io_spi_config_t; - -/** - * @brief Create LCD panel IO handle, for SPI interface - * - * @param[in] bus SPI bus handle - * @param[in] io_config IO configuration, for SPI interface - * @param[out] ret_io Returned IO handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_io_spi(esp_lcd_spi_bus_handle_t bus, const esp_lcd_panel_io_spi_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); - -/** - * @brief Panel IO configuration structure, for I2C interface - * - */ -typedef struct { - uint32_t dev_addr; /*!< I2C device address */ - esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ - void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ - size_t control_phase_bytes; /*!< I2C LCD panel will encode control information (e.g. D/C selection) into control phase, in several bytes */ - unsigned int dc_bit_offset; /*!< Offset of the D/C selection bit in control phase */ - int lcd_cmd_bits; /*!< Bit-width of LCD command */ - int lcd_param_bits; /*!< Bit-width of LCD parameter */ - struct { - unsigned int dc_low_on_data: 1; /*!< If this flag is enabled, DC line = 0 means transfer data, DC line = 1 means transfer command; vice versa */ - unsigned int disable_control_phase: 1; /*!< If this flag is enabled, the control phase isn't used */ - } flags; /*!< Extra flags to fine-tune the I2C device */ - uint32_t scl_speed_hz; /*!< I2C LCD SCL frequency (hz) */ -} esp_lcd_panel_io_i2c_config_t; - -/** - * @brief Create LCD panel IO handle, for I2C interface in legacy implementation - * - * @param[in] bus I2C bus handle, (in uint32_t) - * @param[in] io_config IO configuration, for I2C interface - * @param[out] ret_io Returned IO handle - * - * @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead. - * - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); - -/** - * @brief Create LCD panel IO handle, for I2C interface in new implementation - * - * @param[in] bus I2C bus handle, (in i2c_master_dev_handle_t) - * @param[in] io_config IO configuration, for I2C interface - * @param[out] ret_io Returned IO handle - * - * @note Please don't call this function in your project directly. Please call `esp_lcd_new_panel_to_i2c` instead. - * - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); - -/** - * @brief Create LCD panel IO handle - * - * @param[in] bus I2C bus handle - * @param[in] io_config IO configuration, for I2C interface - * @param[out] ret_io Returned IO handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -#define esp_lcd_new_panel_io_i2c(bus, io_config, ret_io) _Generic((bus), \ - i2c_master_bus_handle_t : esp_lcd_new_panel_io_i2c_v2, \ - default : esp_lcd_new_panel_io_i2c_v1) (bus, io_config, ret_io) \ - -#if SOC_LCD_I80_SUPPORTED -/** - * @brief LCD Intel 8080 bus configuration structure - */ -typedef struct { - int dc_gpio_num; /*!< GPIO used for D/C line */ - int wr_gpio_num; /*!< GPIO used for WR line */ - lcd_clock_source_t clk_src; /*!< Clock source for the I80 LCD peripheral */ - int data_gpio_nums[ESP_LCD_I80_BUS_WIDTH_MAX]; /*!< GPIOs used for data lines */ - size_t bus_width; /*!< Number of data lines, 8 or 16 */ - size_t max_transfer_bytes; /*!< Maximum transfer size, this determines the length of internal DMA link */ - union { - size_t psram_trans_align; /*!< DMA transfer alignment for data allocated from PSRAM */ - size_t dma_burst_size; /*!< DMA burst size, in bytes */ - }; - size_t sram_trans_align __attribute__((deprecated)); /*!< DMA transfer alignment for data allocated from SRAM */ -} esp_lcd_i80_bus_config_t; - -/** - * @brief Create Intel 8080 bus handle - * - * @param[in] bus_config Bus configuration - * @param[out] ret_bus Returned bus handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NO_MEM if out of memory - * - ESP_ERR_NOT_FOUND if no free bus is available - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_i80_bus(const esp_lcd_i80_bus_config_t *bus_config, esp_lcd_i80_bus_handle_t *ret_bus); - -/** - * @brief Destroy Intel 8080 bus handle - * - * @param[in] bus Intel 8080 bus handle, created by `esp_lcd_new_i80_bus()` - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_INVALID_STATE if there still be some device attached to the bus - * - ESP_OK on success - */ -esp_err_t esp_lcd_del_i80_bus(esp_lcd_i80_bus_handle_t bus); - -/** - * @brief Panel IO configuration structure, for intel 8080 interface - */ -typedef struct { - int cs_gpio_num; /*!< GPIO used for CS line, set to -1 will declaim exclusively use of I80 bus */ - uint32_t pclk_hz; /*!< Frequency of pixel clock */ - size_t trans_queue_depth; /*!< Transaction queue size, larger queue, higher throughput */ - esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data was transferred done */ - void *user_ctx; /*!< User private data, passed directly to on_color_trans_done's user_ctx */ - int lcd_cmd_bits; /*!< Bit-width of LCD command */ - int lcd_param_bits; /*!< Bit-width of LCD parameter */ - struct { - unsigned int dc_idle_level: 1; /*!< Level of DC line in IDLE phase */ - unsigned int dc_cmd_level: 1; /*!< Level of DC line in CMD phase */ - unsigned int dc_dummy_level: 1; /*!< Level of DC line in DUMMY phase */ - unsigned int dc_data_level: 1; /*!< Level of DC line in DATA phase */ - } dc_levels; /*!< Each i80 device might have its own D/C control logic */ - struct { - unsigned int cs_active_high: 1; /*!< If set, a high level of CS line will select the device, otherwise, CS line is low level active */ - unsigned int reverse_color_bits: 1; /*!< Reverse the data bits, D[N:0] -> D[0:N] */ - unsigned int swap_color_bytes: 1; /*!< Swap adjacent two color bytes */ - unsigned int pclk_active_neg: 1; /*!< The display will write data lines when there's a falling edge on WR signal (a.k.a the PCLK) */ - unsigned int pclk_idle_low: 1; /*!< The WR signal (a.k.a the PCLK) stays at low level in IDLE phase */ - } flags; /*!< Panel IO config flags */ -} esp_lcd_panel_io_i80_config_t; - -/** - * @brief Create LCD panel IO, for Intel 8080 interface - * - * @param[in] bus Intel 8080 bus handle, created by `esp_lcd_new_i80_bus()` - * @param[in] io_config IO configuration, for i80 interface - * @param[out] ret_io Returned panel IO handle - * @return - * - ESP_ERR_INVALID_ARG if parameter is invalid - * - ESP_ERR_NOT_SUPPORTED if some configuration can't be satisfied, e.g. pixel clock out of the range - * - ESP_ERR_NO_MEM if out of memory - * - ESP_OK on success - */ -esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_panel_io_i80_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); - -#endif // SOC_LCD_I80_SUPPORTED - #ifdef __cplusplus } #endif diff --git a/components/esp_lcd/include/esp_lcd_types.h b/components/esp_lcd/include/esp_lcd_types.h index 77725401079..f70858df0f6 100644 --- a/components/esp_lcd/include/esp_lcd_types.h +++ b/components/esp_lcd/include/esp_lcd_types.h @@ -5,6 +5,7 @@ */ #pragma once +#include #include "esp_assert.h" #include "hal/lcd_types.h" #include "hal/mipi_dsi_types.h" @@ -61,6 +62,29 @@ typedef lcd_rgb_element_order_t lcd_color_rgb_endian_t; #define LCD_RGB_ENDIAN_BGR LCD_RGB_ELEMENT_ORDER_BGR /** @endcond */ +/** + * @brief Type of LCD panel IO event data + */ +typedef struct { +} esp_lcd_panel_io_event_data_t; + +/** + * @brief Declare the prototype of the function that will be invoked when panel IO finishes transferring color data + * + * @param[in] panel_io LCD panel IO handle, which is created by factory API like `esp_lcd_new_panel_io_spi()` + * @param[in] edata Panel IO event data, fed by driver + * @param[in] user_ctx User data, passed from `esp_lcd_panel_io_xxx_config_t` + * @return Whether a high priority task has been waken up by this function + */ +typedef bool (*esp_lcd_panel_io_color_trans_done_cb_t)(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); + +/** + * @brief Type of LCD panel IO callbacks + */ +typedef struct { + esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; /*!< Callback invoked when color data transfer has finished */ +} esp_lcd_panel_io_callbacks_t; + #ifdef __cplusplus } #endif diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 73551440033..2b1e8286dc6 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -174,6 +174,9 @@ INPUT = \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_random.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_sleep.h \ $(PROJECT_PATH)/components/esp_hw_support/ldo/include/esp_ldo_regulator.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_io_i2c.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_io_i80.h \ + $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_io_spi.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_io.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_ops.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_vendor.h \ diff --git a/docs/en/api-reference/peripherals/lcd/i2c_lcd.rst b/docs/en/api-reference/peripherals/lcd/i2c_lcd.rst index 6f41f57d6b3..24c51f775f6 100644 --- a/docs/en/api-reference/peripherals/lcd/i2c_lcd.rst +++ b/docs/en/api-reference/peripherals/lcd/i2c_lcd.rst @@ -48,3 +48,8 @@ I2C Interfaced LCD .reset_gpio_num = EXAMPLE_PIN_NUM_RST, }; ESP_ERROR_CHECK(esp_lcd_new_panel_ssd1306(io_handle, &panel_config, &panel_handle)); + +API Reference +------------- + +.. include-build-file:: inc/esp_lcd_io_i2c.inc diff --git a/docs/en/api-reference/peripherals/lcd/i80_lcd.rst b/docs/en/api-reference/peripherals/lcd/i80_lcd.rst index 95fd79c993c..01fb707ed6f 100644 --- a/docs/en/api-reference/peripherals/lcd/i80_lcd.rst +++ b/docs/en/api-reference/peripherals/lcd/i80_lcd.rst @@ -72,3 +72,8 @@ I80 Interfaced LCD .bits_per_pixel = 16, }; ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); + +API Reference +------------- + +.. include-build-file:: inc/esp_lcd_io_i80.inc diff --git a/docs/en/api-reference/peripherals/lcd/spi_lcd.rst b/docs/en/api-reference/peripherals/lcd/spi_lcd.rst index 6731c42b8c4..5c44794c619 100644 --- a/docs/en/api-reference/peripherals/lcd/spi_lcd.rst +++ b/docs/en/api-reference/peripherals/lcd/spi_lcd.rst @@ -56,3 +56,8 @@ SPI Interfaced LCD }; // Create LCD panel handle for ST7789, with the SPI IO device handle ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle)); + +API Reference +------------- + +.. include-build-file:: inc/esp_lcd_io_spi.inc From b6bc597903f5f1acc4407c0a7dd3619bf9bb5dae Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 29 May 2024 22:45:46 +0800 Subject: [PATCH 210/548] feat(i80_lcd): add help function to allocate draw buffer with proper alignment --- components/esp_lcd/i80/esp_lcd_panel_io_i2s.c | 10 +++++++++- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 15 +++++++++++++++ components/esp_lcd/include/esp_lcd_io_i80.h | 12 ++++++++++++ .../main/i80_controller_example_main.c | 18 ++++++------------ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c index 3e4e6a1323d..68db94d8b34 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -321,6 +321,14 @@ esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_p return ret; } +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps) +{ + ESP_RETURN_ON_FALSE(io, NULL, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE((caps & MALLOC_CAP_SPIRAM) == 0, NULL, TAG, "external memory is not supported"); + // DMA can only carry internal memory + return heap_caps_aligned_calloc(4, 1, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); +} + static esp_err_t panel_io_i80_del(esp_lcd_panel_io_t *io) { lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base); diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index cbaea3f63d8..8e7e50ed6f0 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -583,6 +583,21 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l return ret; } +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps) +{ + ESP_RETURN_ON_FALSE(io, NULL, TAG, "invalid argument"); + lcd_panel_io_i80_t *i80_device = __containerof(io, lcd_panel_io_i80_t, base); + esp_lcd_i80_bus_t *bus = i80_device->bus; + void *buf = NULL; + // alloc from external memory + if (caps & MALLOC_CAP_SPIRAM) { + buf = heap_caps_aligned_calloc(bus->ext_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + } else { + buf = heap_caps_aligned_calloc(bus->int_mem_align, 1, size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + } + return buf; +} + static esp_err_t lcd_i80_bus_configure_gpio(esp_lcd_i80_bus_handle_t bus, const esp_lcd_i80_bus_config_t *bus_config) { int bus_id = bus->bus_id; diff --git a/components/esp_lcd/include/esp_lcd_io_i80.h b/components/esp_lcd/include/esp_lcd_io_i80.h index 664afc0000a..7b6bd90422f 100644 --- a/components/esp_lcd/include/esp_lcd_io_i80.h +++ b/components/esp_lcd/include/esp_lcd_io_i80.h @@ -100,6 +100,18 @@ typedef struct { */ esp_err_t esp_lcd_new_panel_io_i80(esp_lcd_i80_bus_handle_t bus, const esp_lcd_panel_io_i80_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); +/** + * @brief Allocate a draw buffer that can be used by I80 interfaced LCD panel + * + * @note This function differs from the normal 'heap_caps_*' functions in that it can also automatically handle the alignment required by DMA burst, cache line size, etc. + * + * @param[in] io Panel IO handle, created by `esp_lcd_new_panel_io_i80()` + * @param[in] size Size of memory to be allocated + * @param[in] caps Bitwise OR of MALLOC_CAP_* flags indicating the type of memory desired for the allocation + * @return Pointer to a new buffer of size 'size' with capabilities 'caps', or NULL if allocation failed + */ +void *esp_lcd_i80_alloc_draw_buffer(esp_lcd_panel_io_handle_t io, size_t size, uint32_t caps); + #endif // SOC_LCD_I80_SUPPORTED #ifdef __cplusplus diff --git a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c index 146c28ea7f3..259dd4bcb5b 100644 --- a/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c +++ b/examples/peripherals/lcd/i80_controller/main/i80_controller_example_main.c @@ -9,6 +9,7 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_timer.h" +#include "esp_heap_caps.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_panel_vendor.h" #include "esp_lcd_panel_ops.h" @@ -18,7 +19,6 @@ #include "driver/i2c.h" #include "esp_err.h" #include "esp_log.h" -#include "esp_dma_utils.h" #include "lvgl.h" #if CONFIG_EXAMPLE_LCD_TOUCH_CONTROLLER_GT911 #include "esp_lcd_touch_gt911.h" @@ -443,18 +443,12 @@ void app_main(void) lv_init(); // alloc draw buffers used by LVGL // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized - lv_color_t *buf1 = NULL; - lv_color_t *buf2 = NULL; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = 4, + uint32_t draw_buf_alloc_caps = 0; #if CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM - .extra_heap_caps = MALLOC_CAP_SPIRAM, -#else - .extra_heap_caps = MALLOC_CAP_INTERNAL, -#endif // CONFIG_EXAMPLE_LCD_I80_COLOR_IN_PSRAM - }; - ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf1, NULL)); - ESP_ERROR_CHECK(esp_dma_capable_malloc(EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), &dma_mem_info, (void *)&buf2, NULL)); + draw_buf_alloc_caps |= MALLOC_CAP_SPIRAM; +#endif + lv_color_t *buf1 = esp_lcd_i80_alloc_draw_buffer(io_handle, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), draw_buf_alloc_caps); + lv_color_t *buf2 = esp_lcd_i80_alloc_draw_buffer(io_handle, EXAMPLE_LCD_H_RES * 100 * sizeof(lv_color_t), draw_buf_alloc_caps); assert(buf1); assert(buf2); ESP_LOGI(TAG, "buf1@%p, buf2@%p", buf1, buf2); From b8122ec6b37b3f44d55656cb1724ffcb493c429d Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 30 May 2024 18:25:59 +0800 Subject: [PATCH 211/548] refactor(async_memcpy): clean up memory allocation code --- .../esp_hw_support/dma/async_memcpy_gdma.c | 14 ++---- .../test_apps/dma/main/test_async_memcpy.c | 46 +++++++------------ 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/components/esp_hw_support/dma/async_memcpy_gdma.c b/components/esp_hw_support/dma/async_memcpy_gdma.c index 7282f946fae..b2a2db7574b 100644 --- a/components/esp_hw_support/dma/async_memcpy_gdma.c +++ b/components/esp_hw_support/dma/async_memcpy_gdma.c @@ -68,7 +68,6 @@ typedef struct async_memcpy_transaction_t { /// @note - Number of transaction objects are determined by the backlog parameter typedef struct { async_memcpy_context_t parent; // Parent IO interface - size_t descriptor_align; // DMA descriptor alignment size_t rx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal RX memory size_t rx_ext_mem_alignment; // DMA buffer alignment (both in size and address) for external RX memory size_t tx_int_mem_alignment; // DMA buffer alignment (both in size and address) for internal TX memory @@ -119,13 +118,10 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi mcp_gdma = heap_caps_calloc(1, sizeof(async_memcpy_gdma_context_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(mcp_gdma, ESP_ERR_NO_MEM, err, TAG, "no mem for driver context"); uint32_t trans_queue_len = config->backlog ? config->backlog : DEFAULT_TRANSACTION_QUEUE_LENGTH; - // allocate memory for transaction pool - uint32_t data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - uint32_t alignment = MAX(data_cache_line_size, MCP_DMA_DESC_ALIGN); - mcp_gdma->transaction_pool = heap_caps_aligned_calloc(alignment, trans_queue_len, sizeof(async_memcpy_transaction_t), + // allocate memory for transaction pool from internal memory because transaction structure contains DMA descriptor + mcp_gdma->transaction_pool = heap_caps_aligned_calloc(MCP_DMA_DESC_ALIGN, trans_queue_len, sizeof(async_memcpy_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(mcp_gdma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool"); - mcp_gdma->descriptor_align = alignment; // create TX channel and RX channel, they should reside in the same DMA pair gdma_channel_alloc_config_t tx_alloc_config = { @@ -382,14 +378,14 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s // calculate how many descriptors we want size_t max_single_dma_buffer = mcp_gdma->max_single_dma_buffer; uint32_t num_desc_per_path = (n + max_single_dma_buffer - 1) / max_single_dma_buffer; - // allocate DMA descriptors, descriptors need a strict alignment - trans->tx_desc_link = heap_caps_aligned_calloc(mcp_gdma->descriptor_align, num_desc_per_path, sizeof(mcp_dma_descriptor_t), + // allocate DMA descriptors from internal memory + trans->tx_desc_link = heap_caps_aligned_calloc(MCP_DMA_DESC_ALIGN, num_desc_per_path, sizeof(mcp_dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(trans->tx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors"); trans->tx_desc_nc = (mcp_dma_descriptor_t *)MCP_GET_NON_CACHE_ADDR(trans->tx_desc_link); // don't have to allocate the EOF descriptor, we will use trans->eof_node as the RX EOF descriptor if (num_desc_per_path > 1) { - trans->rx_desc_link = heap_caps_aligned_calloc(mcp_gdma->descriptor_align, num_desc_per_path - 1, sizeof(mcp_dma_descriptor_t), + trans->rx_desc_link = heap_caps_aligned_calloc(MCP_DMA_DESC_ALIGN, num_desc_per_path - 1, sizeof(mcp_dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(trans->rx_desc_link, ESP_ERR_NO_MEM, err, TAG, "no mem for DMA descriptors"); trans->rx_desc_nc = (mcp_dma_descriptor_t *)MCP_GET_NON_CACHE_ADDR(trans->rx_desc_link); diff --git a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c index 79423a32053..7d706491e76 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c +++ b/components/esp_hw_support/test_apps/dma/main/test_async_memcpy.c @@ -18,7 +18,6 @@ #include "esp_async_memcpy.h" #include "soc/soc_caps.h" #include "hal/dma_types.h" -#include "esp_dma_utils.h" #define IDF_LOG_PERFORMANCE(item, value_fmt, value, ...) \ printf("[Performance][%s]: " value_fmt "\n", item, value, ##__VA_ARGS__) @@ -55,21 +54,13 @@ static void async_memcpy_setup_testbench(memcpy_testbench_context_t *test_contex uint8_t *from_addr = NULL; uint8_t *to_addr = NULL; - esp_dma_mem_info_t mem_info = { - .dma_alignment_bytes = test_context->align, - }; - if (test_context->src_in_psram) { - mem_info.extra_heap_caps = MALLOC_CAP_SPIRAM; - } else { - mem_info.extra_heap_caps = 0; - } - TEST_ESP_OK(esp_dma_capable_calloc(1, buffer_size, &mem_info, (void **)&src_buf, NULL)); - if (test_context->dst_in_psram) { - mem_info.extra_heap_caps = MALLOC_CAP_SPIRAM; - } else { - mem_info.extra_heap_caps = 0; - } - TEST_ESP_OK(esp_dma_capable_calloc(1, buffer_size, &mem_info, (void **)&dst_buf, NULL)); + uint32_t mem_caps = test_context->src_in_psram ? MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT : MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT ; + src_buf = heap_caps_aligned_calloc(test_context->align, 1, buffer_size, mem_caps); + TEST_ASSERT_NOT_NULL(src_buf); + + mem_caps = test_context->dst_in_psram ? MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA | MALLOC_CAP_8BIT : MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT ; + dst_buf = heap_caps_aligned_calloc(test_context->align, 1, buffer_size, mem_caps); + TEST_ASSERT_NOT_NULL(dst_buf); // adding extra offset from_addr = src_buf + test_context->offset; @@ -111,13 +102,11 @@ TEST_CASE("memory copy the same buffer with different content", "[async mcp]") async_memcpy_config_t config = ASYNC_MEMCPY_DEFAULT_CONFIG(); async_memcpy_handle_t driver = NULL; TEST_ESP_OK(esp_async_memcpy_install(&config, &driver)); - uint8_t *sbuf = NULL; - uint8_t *dbuf = NULL; - esp_dma_mem_info_t mem_info = { - .dma_alignment_bytes = 4, - }; - TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&sbuf, NULL)); - TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&dbuf, NULL)); + uint8_t *sbuf = heap_caps_aligned_calloc(4, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dbuf = heap_caps_aligned_calloc(4, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(sbuf); + TEST_ASSERT_NOT_NULL(dbuf); + for (int j = 0; j < 20; j++) { TEST_ESP_OK(esp_async_memcpy(driver, dbuf, sbuf, 256, NULL, NULL)); vTaskDelay(pdMS_TO_TICKS(10)); @@ -219,13 +208,10 @@ TEST_CASE("memory copy done callback", "[async mcp]") async_memcpy_handle_t driver = NULL; TEST_ESP_OK(esp_async_memcpy_install(&config, &driver)); - uint8_t *src_buf = NULL; - uint8_t *dst_buf = NULL; - esp_dma_mem_info_t mem_info = { - .dma_alignment_bytes = 4, - }; - TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&src_buf, NULL)); - TEST_ESP_OK(esp_dma_capable_calloc(1, 256, &mem_info, (void **)&dst_buf, NULL)); + uint8_t *src_buf = heap_caps_aligned_calloc(4, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(4, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(src_buf); + TEST_ASSERT_NOT_NULL(dst_buf); SemaphoreHandle_t sem = xSemaphoreCreateBinary(); TEST_ESP_OK(esp_async_memcpy(driver, dst_buf, src_buf, 256, test_async_memcpy_cb_v1, sem)); From 784abd1ae0fd36a9ed2884a84aeae953d58f01d3 Mon Sep 17 00:00:00 2001 From: zwx Date: Wed, 24 Apr 2024 15:45:10 +0800 Subject: [PATCH 212/548] feat(openthread): move iperf dependency into cli extension --- examples/openthread/ot_br/main/idf_component.yml | 4 +--- examples/openthread/ot_cli/main/idf_component.yml | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/openthread/ot_br/main/idf_component.yml b/examples/openthread/ot_br/main/idf_component.yml index 10a25935ff8..519cf7f89d2 100644 --- a/examples/openthread/ot_br/main/idf_component.yml +++ b/examples/openthread/ot_br/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: espressif/esp_ot_cli_extension: - version: "~1.0.0" + version: "~1.1.0" espressif/mdns: "^1.0.3" ## Required IDF version idf: @@ -10,5 +10,3 @@ dependencies: path: ${IDF_PATH}/examples/common_components/protocol_examples_common ot_led: path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led - espressif/iperf: - version: "~0.1.1" diff --git a/examples/openthread/ot_cli/main/idf_component.yml b/examples/openthread/ot_cli/main/idf_component.yml index 6b1234251fb..3f1f6778d27 100644 --- a/examples/openthread/ot_cli/main/idf_component.yml +++ b/examples/openthread/ot_cli/main/idf_component.yml @@ -1,10 +1,8 @@ ## IDF Component Manager Manifest File dependencies: espressif/esp_ot_cli_extension: - version: "~1.0.0" + version: "~1.1.0" idf: version: ">=4.1.0" ot_led: path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led - espressif/iperf: - version: "~0.1.1" From d6a3ed06372537aaf606bcd79d6fe4f6a15cec6a Mon Sep 17 00:00:00 2001 From: zwx Date: Fri, 10 May 2024 15:20:11 +0800 Subject: [PATCH 213/548] feat(openthread): remove the range for some configurations --- components/openthread/Kconfig | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 558f093f6cf..740479a940a 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -206,7 +206,6 @@ menu "OpenThread" int "The size of max commissioning joiner entries" depends on OPENTHREAD_COMMISSIONER default 2 - range 2 50 config OPENTHREAD_JOINER bool "Enable Joiner" @@ -228,7 +227,6 @@ menu "OpenThread" int "Specifies number of service entries in the SRP client service pool" depends on OPENTHREAD_SRP_CLIENT default 5 - range 2 20 help Set the max buffer size of service entries in the SRP client service pool. @@ -257,14 +255,11 @@ menu "OpenThread" int "The number of openthread message buffers" depends on OPENTHREAD_ENABLED default 65 - range 10 100 if !OPENTHREAD_PLATFORM_MSGPOOL_MANAGEMENT - range 10 8191 if OPENTHREAD_PLATFORM_MSGPOOL_MANAGEMENT config OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE int "The size of openthread spinel rx frame buffer" depends on OPENTHREAD_ENABLED || OPENTHREAD_SPINEL_ONLY - default 1024 - range 512 8192 + default 2048 config OPENTHREAD_MAC_MAX_CSMA_BACKOFFS_DIRECT int "Maximum backoffs times before declaring a channel access failure." @@ -278,13 +273,11 @@ menu "OpenThread" int "The size of max MLE children entries" depends on OPENTHREAD_ENABLED default 10 - range 5 50 config OPENTHREAD_TMF_ADDR_CACHE_ENTRIES int "The size of max TMF address cache entries" depends on OPENTHREAD_ENABLED default 20 - range 5 50 config OPENTHREAD_DNS64_CLIENT bool "Use dns64 client" @@ -303,8 +296,7 @@ menu "OpenThread" config OPENTHREAD_UART_BUFFER_SIZE int "The uart received buffer size of openthread" depends on OPENTHREAD_ENABLED - default 768 - range 128 1024 + default 2048 help Set the OpenThread UART buffer size. @@ -377,7 +369,7 @@ menu "OpenThread" default n help Select this option to enable the radio statistics feature, you can use radio command to print some radio - Statistics informations. + Statistics information. config OPENTHREAD_SPINEL_ONLY bool "Enable OpenThread External Radio Spinel feature" @@ -386,11 +378,11 @@ menu "OpenThread" Select this option to enable the OpenThread Radio Spinel for external protocol stack, such as Zigbee. config OPENTHREAD_RX_ON_WHEN_IDLE - bool "Enable OpenThread radio capibility rx on when idle" + bool "Enable OpenThread radio capability rx on when idle" default y if !ESP_COEX_SW_COEXIST_ENABLE default n if ESP_COEX_SW_COEXIST_ENABLE help - Select this option to enable OpenThread radio capibility rx on when idle. Do not support this feature when + Select this option to enable OpenThread radio capability rx on when idle. Do not support this feature when SW coexistence is enabled. menu "Thread Address Query Config" @@ -398,19 +390,16 @@ menu "OpenThread" int "Timeout value (in seconds) for a address notification response after sending an address query." depends on OPENTHREAD_FTD || OPENTHREAD_MTD default 3 - range 1 10 config OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY int "Initial retry delay for address query (in seconds)." depends on OPENTHREAD_FTD || OPENTHREAD_MTD default 15 - range 1 120 config OPENTHREAD_ADDRESS_QUERY_MAX_RETRY_DELAY int "Maximum retry delay for address query (in seconds)." depends on OPENTHREAD_FTD || OPENTHREAD_MTD default 120 - range OPENTHREAD_ADDRESS_QUERY_RETRY_DELAY 960 endmenu endmenu From 01e02aec6c7a117520ada349639f49b391a7dc62 Mon Sep 17 00:00:00 2001 From: zwx Date: Wed, 15 May 2024 10:57:08 +0800 Subject: [PATCH 214/548] fix(802.15.4): fix a risk for receive_at and ignore bit8 for the frame length --- components/ieee802154/driver/esp_ieee802154_dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 9d18f7ea6d1..131d963c59a 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -88,6 +88,8 @@ static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t * esp_rom_printf("receive buffer full, drop the current frame.\n"); } else { // Otherwise, post it to the upper layer. + // Ignore bit8 for the frame length, due to the max frame length is 127 based 802.15.4 spec. + data[0] = data[0] & 0x7f; frame_info->process = true; esp_ieee802154_receive_done(data, frame_info); } @@ -901,11 +903,11 @@ esp_err_t ieee802154_receive_at(uint32_t time) uint32_t rx_target_time = time - IEEE802154_RX_RAMPUP_TIME_US; uint32_t current_time; IEEE802154_RF_ENABLE(); + ieee802154_enter_critical(); rx_init(); IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_RX_AT); set_next_rx_buffer(); ieee802154_set_state(IEEE802154_STATE_RX); - ieee802154_enter_critical(); ieee802154_etm_set_event_task(IEEE802154_ETM_CHANNEL1, ETM_EVENT_TIMER0_OVERFLOW, ETM_TASK_RX_START); current_time = (uint32_t)esp_timer_get_time(); ieee802154_timer0_set_threshold((is_target_time_expired(rx_target_time, current_time) ? 0 : (rx_target_time - current_time))); //uint: 1us From 3efe49f26a4008ad0ca5a73f7a1859bb6c0868f2 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 10 Apr 2024 17:49:25 +0800 Subject: [PATCH 215/548] feat(openthread): support openthread ephemeral key --- .../include/esp_openthread_netif_glue.h | 13 ++++++- .../openthread/include/esp_openthread_types.h | 2 + components/openthread/lib | 2 +- components/openthread/openthread | 2 +- .../openthread-core-esp32x-ftd-config.h | 4 ++ components/openthread/sbom_openthread.yml | 2 +- .../src/esp_openthread_netif_glue.c | 37 ++++++++++++++++++- examples/openthread/pytest_otbr.py | 8 ++-- 8 files changed, 60 insertions(+), 10 deletions(-) diff --git a/components/openthread/include/esp_openthread_netif_glue.h b/components/openthread/include/esp_openthread_netif_glue.h index 404e9f1f5c7..3d70c8a7f74 100644 --- a/components/openthread/include/esp_openthread_netif_glue.h +++ b/components/openthread/include/esp_openthread_netif_glue.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,7 +16,7 @@ extern "C" { #endif /** -* @brief Default configuration reference of OT esp-netif +* @brief Default configuration reference of OpenThread esp-netif */ #define ESP_NETIF_INHERENT_DEFAULT_OPENTHREAD() \ { \ @@ -67,6 +67,15 @@ void esp_openthread_netif_glue_deinit(void); */ esp_netif_t *esp_openthread_get_netif(void); +/** + * @brief This function register a handler for meshcop-e service publish event and remove event. + * + * @param[in] handler The handler. + * @param[in] for_publish The usage of handler, true for publish event and false for remove event. + * + */ +void esp_openthread_register_meshcop_e_handler(esp_event_handler_t handler, bool for_publish); + #ifdef __cplusplus } #endif diff --git a/components/openthread/include/esp_openthread_types.h b/components/openthread/include/esp_openthread_types.h index 28595d3fa00..03095940194 100644 --- a/components/openthread/include/esp_openthread_types.h +++ b/components/openthread/include/esp_openthread_types.h @@ -44,6 +44,8 @@ typedef enum { OPENTHREAD_EVENT_TREL_REMOVE_IP6, /*!< OpenThread stack removed TREL IPv6 address */ OPENTHREAD_EVENT_TREL_MULTICAST_GROUP_JOIN, /*!< OpenThread stack joined TREL IPv6 multicast group */ OPENTHREAD_EVENT_SET_DNS_SERVER, /*!< OpenThread stack set DNS server >*/ + OPENTHREAD_EVENT_PUBLISH_MESHCOP_E, /*!< OpenThread stack start to publish meshcop-e service >*/ + OPENTHREAD_EVENT_REMOVE_MESHCOP_E, /*!< OpenThread stack start to remove meshcop-e service >*/ } esp_openthread_event_t; /** diff --git a/components/openthread/lib b/components/openthread/lib index fcee30db4b7..a0f6a77960b 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit fcee30db4b7342de4df9105bdd049a09d2d63187 +Subproject commit a0f6a77960b36ebe357cc4bee280034f8c7120f1 diff --git a/components/openthread/openthread b/components/openthread/openthread index 456c4482844..be7d36e4ff9 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit 456c448284486abe2a9118a9fdaa468fe2383fcd +Subproject commit be7d36e4ff9cf7df6dfce54e58a31163c87b93f7 diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 609c01112c4..bf61bc9094c 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -632,4 +632,8 @@ #define OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT CONFIG_OPENTHREAD_MAC_MAX_CSMA_BACKOFFS_DIRECT #endif +#ifndef OPENTHREAD_CONFIG_THREAD_VERSION +#define OPENTHREAD_CONFIG_THREAD_VERSION OT_THREAD_VERSION_1_4 +#endif + #define OPENTHREAD_FTD 1 diff --git a/components/openthread/sbom_openthread.yml b/components/openthread/sbom_openthread.yml index 0748bffc639..ae0203670fb 100644 --- a/components/openthread/sbom_openthread.yml +++ b/components/openthread/sbom_openthread.yml @@ -5,4 +5,4 @@ supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' originator: 'Organization: Google LLC' description: OpenThread released by Google is an open-source implementation of the Thread networking url: https://github.com/espressif/openthread -hash: 456c448284486abe2a9118a9fdaa468fe2383fcd +hash: be7d36e4ff9cf7df6dfce54e58a31163c87b93f7 diff --git a/components/openthread/src/esp_openthread_netif_glue.c b/components/openthread/src/esp_openthread_netif_glue.c index 608a3218fa3..8e0ff030855 100644 --- a/components/openthread/src/esp_openthread_netif_glue.c +++ b/components/openthread/src/esp_openthread_netif_glue.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -203,6 +203,33 @@ static esp_err_t openthread_netif_transmit(void *handle, void *buffer, size_t le return error; } +static esp_event_handler_t meshcop_e_publish_handler = NULL; +static void esp_openthread_meshcop_e_publish_handler(void *args, esp_event_base_t base, int32_t event_id, void *data) +{ + if (meshcop_e_publish_handler) { + meshcop_e_publish_handler(args, base, event_id, data); + } +} + +static esp_event_handler_t meshcop_e_remove_handler = NULL; +static void esp_openthread_meshcop_e_remove_handler(void *args, esp_event_base_t base, int32_t event_id, void *data) +{ + if (meshcop_e_remove_handler) { + meshcop_e_remove_handler(args, base, event_id, data); + } +} + +void esp_openthread_register_meshcop_e_handler(esp_event_handler_t handler, bool for_publish) +{ + if (for_publish) { + meshcop_e_publish_handler = handler; + } else if (!for_publish) { + meshcop_e_remove_handler = handler; + } else { + ESP_ERROR_CHECK(ESP_FAIL); + } +} + static esp_err_t register_openthread_event_handlers(esp_netif_t *esp_netif) { ESP_RETURN_ON_ERROR( @@ -229,6 +256,12 @@ static esp_err_t register_openthread_event_handlers(esp_netif_t *esp_netif) ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, esp_netif_action_leave_ip6_multicast_group, esp_netif), OT_PLAT_LOG_TAG, "OpenThread interface leave ip6 multicast group event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_PUBLISH_MESHCOP_E, + esp_openthread_meshcop_e_publish_handler, NULL), + OT_PLAT_LOG_TAG, "OpenThread publish meshcop-e service event register failed"); + ESP_RETURN_ON_ERROR(esp_event_handler_register(OPENTHREAD_EVENT, OPENTHREAD_EVENT_REMOVE_MESHCOP_E, + esp_openthread_meshcop_e_remove_handler, NULL), + OT_PLAT_LOG_TAG, "OpenThread remove meshcop-e service event register failed"); return ESP_OK; } @@ -244,6 +277,8 @@ static void unregister_openthread_event_handlers(void) esp_netif_action_join_ip6_multicast_group); esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_MULTICAST_GROUP_LEAVE, esp_netif_action_leave_ip6_multicast_group); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_PUBLISH_MESHCOP_E, esp_openthread_meshcop_e_publish_handler); + esp_event_handler_unregister(OPENTHREAD_EVENT, OPENTHREAD_EVENT_REMOVE_MESHCOP_E, esp_openthread_meshcop_e_remove_handler); } static esp_err_t openthread_netif_post_attach(esp_netif_t *esp_netif, void *args) diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index c307adc1c71..fbadbf684be 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -18,7 +18,7 @@ # This file contains the test scripts for Thread: # Case 1: Thread network formation and attaching -# A Thread Border Router forms a Thread network, Thread devices attache to it, then test ping connection between them. +# A Thread Border Router forms a Thread network, Thread devices attach to it, then test ping connection between them. # Case 2: Bidirectional IPv6 connectivity # Test IPv6 ping connection between Thread device and Linux Host (via Thread Border Router). @@ -29,10 +29,10 @@ # Case 4: Multicast forwarding from Thread to Wi-Fi network # Linux Host joins the multicast group, test group communication from Thread to Wi-Fi network. -# Case 5: discover Serice published by Thread device +# Case 5: discover Service published by Thread device # Thread device publishes the service, Linux Host discovers the service on Wi-Fi network. -# Case 6: discover Serice published by W-Fi device +# Case 6: discover Service published by W-Fi device # Linux Host device publishes the service on Wi-Fi network, Thread device discovers the service. # Case 7: ICMP communication via NAT64 @@ -728,7 +728,7 @@ def test_br_meshcop(Init_interface:bool, Init_avahi:bool, dut: Tuple[IdfDut, Idf assert 'hostname = [esp-ot-br.local]' in str(output_str) assert ('address = [' + ipv4_address + ']') in str(output_str) assert 'dn=DefaultDomain' in str(output_str) - assert 'tv=1.3.0' in str(output_str) + assert 'tv=1.4.0' in str(output_str) assert ('nn=' + networkname) in str(output_str) assert 'mn=BorderRouter' in str(output_str) assert 'vn=OpenThread' in str(output_str) From 3860cc8dac31be4faccf0adce6f99bdcadb1825e Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Sun, 28 Apr 2024 19:41:35 +0800 Subject: [PATCH 216/548] feat(openthread): update openthread br lib --- components/openthread/CMakeLists.txt | 2 ++ .../include/esp_openthread_border_router.h | 21 ++++++++++++++++--- components/openthread/lib | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index eb3d3dc3394..39cc5b78b81 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -111,7 +111,9 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/src/core/thread/mesh_forwarder_ftd.cpp" "openthread/src/core/thread/mesh_forwarder_mtd.cpp" "openthread/src/core/thread/mle.cpp" + "openthread/src/core/thread/mle_router.cpp" "openthread/src/core/thread/mle_types.cpp" + "openthread/src/core/thread/neighbor.cpp" "openthread/src/core/thread/neighbor_table.cpp" "openthread/src/core/thread/network_data.cpp" "openthread/src/core/thread/network_data_leader.cpp" diff --git a/components/openthread/include/esp_openthread_border_router.h b/components/openthread/include/esp_openthread_border_router.h index 3a6c6e96387..de4b8ee6048 100644 --- a/components/openthread/include/esp_openthread_border_router.h +++ b/components/openthread/include/esp_openthread_border_router.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -67,7 +67,7 @@ esp_netif_t *esp_openthread_get_backbone_netif(void); void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_handler handler); /** - * @brief Deinitializes the conneciton to RCP. + * @brief Deinitializes the connection to RCP. * * @return * - ESP_OK on success @@ -77,7 +77,7 @@ void esp_openthread_register_rcp_failure_handler(esp_openthread_rcp_failure_hand esp_err_t esp_openthread_rcp_deinit(void); /** - * @brief Initializes the conneciton to RCP. + * @brief Initializes the connection to RCP. * * @return * - ESP_OK on success @@ -86,6 +86,21 @@ esp_err_t esp_openthread_rcp_deinit(void); */ esp_err_t esp_openthread_rcp_init(void); +/** + * @brief Sets the meshcop(e) instance name. + * + * @note This function can only be called before `esp_openthread_border_router_init`. + * If `instance_name` is NULL, then the service will use the hostname as instance name. + * + * @param[in] instance_name The instance name, can be `NULL`. + * + * @return + * - ESP_OK on success + * - ESP_FAIL if fail to initialize RCP + * + */ +esp_err_t esp_openthread_set_meshcop_instance_name(const char *instance_name); + #ifdef __cplusplus } #endif diff --git a/components/openthread/lib b/components/openthread/lib index a0f6a77960b..5ae57e156e4 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit a0f6a77960b36ebe357cc4bee280034f8c7120f1 +Subproject commit 5ae57e156e4cd2ccd8dc51e90266b16b284e64de From 5887426badcc4fb23e6b3b5b80d9357a470d45fe Mon Sep 17 00:00:00 2001 From: zwx Date: Mon, 27 May 2024 14:43:00 +0800 Subject: [PATCH 217/548] feat(802154): log `buffer full` message in debug mode only --- .../ieee802154/driver/esp_ieee802154_debug.c | 101 +++++++++--------- .../ieee802154/driver/esp_ieee802154_dev.c | 11 +- .../ieee802154/driver/esp_ieee802154_frame.c | 25 +++-- .../ieee802154/driver/esp_ieee802154_timer.c | 9 +- .../private_include/esp_ieee802154_dev.h | 2 - .../private_include/esp_ieee802154_util.h | 2 + 6 files changed, 73 insertions(+), 77 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_debug.c b/components/ieee802154/driver/esp_ieee802154_debug.c index c8472c83159..0dbfd4bc590 100644 --- a/components/ieee802154/driver/esp_ieee802154_debug.c +++ b/components/ieee802154/driver/esp_ieee802154_debug.c @@ -12,7 +12,6 @@ #if CONFIG_IEEE802154_DEBUG ieee802154_probe_info_t g_ieee802154_probe; -#define TAG "ieee802154_debug" #if CONFIG_IEEE802154_RECORD_EVENT static char *ieee802154_get_event_string(ieee802154_ll_event_t events) @@ -176,7 +175,7 @@ static char *ieee80154_tx_abort_reason_string[] = { void ieee802154_assert_print(void) { #if CONFIG_IEEE802154_RECORD_EVENT - ESP_EARLY_LOGW(TAG, "Print the record event, current event index: %d", g_ieee802154_probe.event_index); + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record event, current event index: %d", g_ieee802154_probe.event_index); for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_EVENT_SIZE; i++) { char event_log[200] = { 0 }; char abort_log[100] = { 0 }; @@ -191,49 +190,49 @@ void ieee802154_assert_print(void) snprintf(abort_log, 100, "tx abort reason: %4x, %20s", g_ieee802154_probe.event[i].abort_reason.tx, ieee80154_tx_abort_reason_string[g_ieee802154_probe.event[i].abort_reason.tx]); } - ESP_EARLY_LOGW(TAG, "%s %s", event_log, abort_log); + ESP_EARLY_LOGW(IEEE802154_TAG, "%s %s", event_log, abort_log); } - ESP_EARLY_LOGW(TAG,"Print the record event done.\n"); + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record event done."); #endif // CONFIG_IEEE802154_RECORD_EVENT #if CONFIG_IEEE802154_RECORD_STATE - ESP_EARLY_LOGW(TAG, "Print the record state, current state index: %d", g_ieee802154_probe.state_index); + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record state, current state index: %d", g_ieee802154_probe.state_index); for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_STATE_SIZE; i++) { - ESP_EARLY_LOGW(TAG, "index %2d: line:%5s, state:%10s, timestamp: %lld", + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: line:%5s, state:%10s, timestamp: %lld", i, g_ieee802154_probe.state[i].line_str, ieee802154_state_string[g_ieee802154_probe.state[i].state], g_ieee802154_probe.state[i].timestamp); } - ESP_EARLY_LOGW(TAG,"Print the record state done.\n"); + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record state done."); #endif // CONFIG_IEEE802154_RECORD_STATE #if CONFIG_IEEE802154_RECORD_CMD - ESP_EARLY_LOGW(TAG, "Print the record cmd, current cmd index: %d", g_ieee802154_probe.cmd_index); + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record cmd, current cmd index: %d", g_ieee802154_probe.cmd_index); for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_CMD_SIZE; i++) { - ESP_EARLY_LOGW(TAG, "index %2d: line:%5s, cmd:%10s, timestamp: %lld", + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: line:%5s, cmd:%10s, timestamp: %lld", i, g_ieee802154_probe.cmd[i].line_str, ieee802154_get_cmd_string(g_ieee802154_probe.cmd[i].cmd), g_ieee802154_probe.cmd[i].timestamp); } - ESP_EARLY_LOGW(TAG,"Print the record cmd done.\n"); + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record cmd done."); #endif // CONFIG_IEEE802154_RECORD_CMD #if CONFIG_IEEE802154_RECORD_ABORT - ESP_EARLY_LOGW(TAG, "Print the record abort, current abort index: %d", g_ieee802154_probe.abort_index); + ESP_EARLY_LOGW(IEEE802154_TAG, "Print the record abort, current abort index: %d", g_ieee802154_probe.abort_index); for (uint8_t i = 0; i < IEEE802154_ASSERT_RECORD_ABORT_SIZE; i++) { if (g_ieee802154_probe.abort[i].is_tx_abort) { - ESP_EARLY_LOGW(TAG, "index %2d: tx abort: %4x, %15s, timestamp: %lld", + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: tx abort: %4x, %15s, timestamp: %lld", i, g_ieee802154_probe.abort[i].abort_reason.tx, ieee80154_tx_abort_reason_string[g_ieee802154_probe.abort[i].abort_reason.tx], g_ieee802154_probe.abort[i].timestamp); } else { - ESP_EARLY_LOGW(TAG, "index %2d: rx abort: %4x, %15s, timestamp: %lld", + ESP_EARLY_LOGW(IEEE802154_TAG, "index %2d: rx abort: %4x, %15s, timestamp: %lld", i, g_ieee802154_probe.abort[i].abort_reason.rx, ieee80154_rx_abort_reason_string[g_ieee802154_probe.abort[i].abort_reason.rx], g_ieee802154_probe.abort[i].timestamp); } } - ESP_EARLY_LOGW(TAG,"Print the record abort done.\n"); + ESP_EARLY_LOGW(IEEE802154_TAG,"Print the record abort done."); #endif // CONFIG_IEEE802154_RECORD_ABORT } #endif // CONFIG_IEEE802154_ASSERT @@ -330,43 +329,43 @@ void ieee802154_txrx_statistic_print(void) uint64_t rx_success_nums = s_ieee802154_txrx_statistic.rx.done_nums - s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums; - ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "", "Done:", s_ieee802154_txrx_statistic.tx.done_nums, tx_done_ratio*100, "Success:", tx_success_nums, tx_success_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_direct_num:", tx_direct_num, tx_direct_num_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_deferred_num:", s_ieee802154_txrx_statistic.tx.deferred_nums, tx_deferred_num_ratio*100); - ESP_LOGW(TAG, "+ +-----------------------------------+--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_coex_break:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums, tx_abort_rx_ack_coex_break_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_timeout:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums, tx_abort_rx_ack_timeout_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-5s%-15llu|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "TX:", s_ieee802154_txrx_statistic.tx.nums, "Abort", tx_abort_nums, tx_abort_ratio*100, "tx_coex_break:", s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums, tx_abort_tx_coex_break_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_security_error:", s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums, tx_abort_tx_security_error_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_failed:", s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums, tx_abort_cca_failed_ratio*100); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_busy:", s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums, tx_abort_cca_busy_ratio*100); - ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "", "Done:", s_ieee802154_txrx_statistic.rx.done_nums, "Success:", rx_success_nums); - ESP_LOGW(TAG, "+ +-----------------------------------+--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "tx_ack_coex_break:", s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "sfd_timeout:", s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "crc_error:", s_ieee802154_txrx_statistic.rx.abort.crc_error_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "RX", "Abort", rx_abort_nums, "filter_fail:", s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "no_rss:", s_ieee802154_txrx_statistic.rx.abort.no_rss_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_coex_break:", s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_restart:", s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums); - ESP_LOGW(TAG, "+ + +--------------------------------------------------+"); - ESP_LOGW(TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "ed_abort:", s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums); - ESP_LOGW(TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "", "Done:", s_ieee802154_txrx_statistic.tx.done_nums, tx_done_ratio*100, "Success:", tx_success_nums, tx_success_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_direct_num:", tx_direct_num, tx_direct_num_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_deferred_num:", s_ieee802154_txrx_statistic.tx.deferred_nums, tx_deferred_num_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ +-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_coex_break:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_coex_break_nums, tx_abort_rx_ack_coex_break_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "rx_ack_timeout:", s_ieee802154_txrx_statistic.tx.abort.rx_ack_timeout_nums, tx_abort_rx_ack_timeout_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-5s%-15llu|%-10s%-15llu%9.2f%%|%-25s%-15llu%9.2f%%|", "TX:", s_ieee802154_txrx_statistic.tx.nums, "Abort", tx_abort_nums, tx_abort_ratio*100, "tx_coex_break:", s_ieee802154_txrx_statistic.tx.abort.tx_coex_break_nums, tx_abort_tx_coex_break_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "tx_security_error:", s_ieee802154_txrx_statistic.tx.abort.tx_security_error_nums, tx_abort_tx_security_error_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_failed:", s_ieee802154_txrx_statistic.tx.abort.cca_failed_nums, tx_abort_cca_failed_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-15llu%9.2f%%|", "", "", "cca_busy:", s_ieee802154_txrx_statistic.tx.abort.cca_busy_nums, tx_abort_cca_busy_ratio*100); + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "", "Done:", s_ieee802154_txrx_statistic.rx.done_nums, "Success:", rx_success_nums); + ESP_LOGW(IEEE802154_TAG, "+ +-----------------------------------+--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "tx_ack_coex_break:", s_ieee802154_txrx_statistic.rx.abort.tx_ack_coex_break_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "sfd_timeout:", s_ieee802154_txrx_statistic.rx.abort.sfd_timeout_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "crc_error:", s_ieee802154_txrx_statistic.rx.abort.crc_error_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-10s%-25llu|%-25s%-25llu|", "RX", "Abort", rx_abort_nums, "filter_fail:", s_ieee802154_txrx_statistic.rx.abort.filter_fail_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "no_rss:", s_ieee802154_txrx_statistic.rx.abort.no_rss_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_coex_break:", s_ieee802154_txrx_statistic.rx.abort.rx_coex_break_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "rx_restart:", s_ieee802154_txrx_statistic.rx.abort.rx_restart_nums); + ESP_LOGW(IEEE802154_TAG, "+ + +--------------------------------------------------+"); + ESP_LOGW(IEEE802154_TAG, "|%-20s|%-35s|%-25s%-25llu|", "", "", "ed_abort:", s_ieee802154_txrx_statistic.rx.abort.ed_abort_nums); + ESP_LOGW(IEEE802154_TAG, "+--------------------+-----------------------------------+--------------------------------------------------+"); } #endif // CONFIG_IEEE802154_TXRX_STATISTIC diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index 131d963c59a..f94f15d6c98 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -5,6 +5,7 @@ */ #include +#include "sdkconfig.h" #include "freertos/portmacro.h" #include "soc/periph_defs.h" #include "soc/soc.h" @@ -84,9 +85,7 @@ static pending_tx_t s_pending_tx = { 0 }; static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) { // If the RX done packet is written in the stub buffer, drop it silently. - if (s_rx_index == CONFIG_IEEE802154_RX_BUFFER_SIZE) { - esp_rom_printf("receive buffer full, drop the current frame.\n"); - } else { + if (s_rx_index != CONFIG_IEEE802154_RX_BUFFER_SIZE) { // Otherwise, post it to the upper layer. // Ignore bit8 for the frame length, due to the max frame length is 127 based 802.15.4 spec. data[0] = data[0] & 0x7f; @@ -99,7 +98,6 @@ static void ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, e { if (ack && ack_frame_info) { if (s_rx_index == CONFIG_IEEE802154_RX_BUFFER_SIZE) { - esp_rom_printf("receive buffer full, drop the current ack frame.\n"); esp_ieee802154_transmit_failed(frame, ESP_IEEE802154_TX_ERR_NO_ACK); } else { ack_frame_info->process = true; @@ -165,7 +163,6 @@ IEEE802154_STATIC void set_next_rx_buffer(void) { uint8_t* next_rx_buffer = NULL; uint8_t index = 0; - if (s_rx_index != CONFIG_IEEE802154_RX_BUFFER_SIZE && s_rx_frame_info[s_rx_index].process == false) { // If buffer is not full, and current index is empty, set it to hardware. next_rx_buffer = s_rx_frame[s_rx_index]; @@ -188,8 +185,10 @@ IEEE802154_STATIC void set_next_rx_buffer(void) if (!next_rx_buffer) { s_rx_index = CONFIG_IEEE802154_RX_BUFFER_SIZE; next_rx_buffer = s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE]; +#if CONFIG_IEEE802154_DEBUG + ESP_EARLY_LOGW(IEEE802154_TAG, "Rx buffer full."); +#endif } - ieee802154_ll_set_rx_addr(next_rx_buffer); } diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index 8a6468be65b..e32e338ae0e 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,8 +9,7 @@ #include "esp_attr.h" #include "esp_ieee802154_dev.h" #include "esp_ieee802154_frame.h" - -static const char *TAG = "ieee802154 frame"; +#include "esp_ieee802154_util.h" IEEE802154_STATIC IEEE802154_INLINE bool is_security_enabled(const uint8_t *frame) { @@ -59,7 +58,7 @@ IEEE802154_STATIC bool is_dst_panid_present(const uint8_t *frame) uint8_t src_mode = src_addr_mode(frame); bool panid_compression = is_panid_compression(frame); - if (dst_mode != IEEE802154_FRAME_DST_MODE_NONE) { // dest address is present/short/extented + if (dst_mode != IEEE802154_FRAME_DST_MODE_NONE) { // dest address is present/short/extended if ((src_mode == IEEE802154_FRAME_SRC_MODE_NONE && panid_compression) || (dst_mode == IEEE802154_FRAME_DST_MODE_EXT && src_mode == IEEE802154_FRAME_SRC_MODE_EXT && panid_compression)) { dst_panid_present = false; @@ -163,12 +162,12 @@ IEEE802154_STATIC IRAM_ATTR uint8_t ieee802154_frame_address_size(const uint8_t IEEE802154_STATIC uint8_t ieee802154_frame_security_header_offset(const uint8_t *frame) { - ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, TAG, "invalid frame type"); + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type"); uint8_t offset = ieee802154_frame_address_offset(frame); uint8_t address_size = ieee802154_frame_address_size(frame); - ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, TAG, "invalid offset"); - ESP_RETURN_ON_FALSE_ISR(address_size != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, TAG, "invalid offset"); + ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset"); + ESP_RETURN_ON_FALSE_ISR(address_size != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset"); offset += address_size; @@ -177,12 +176,12 @@ IEEE802154_STATIC uint8_t ieee802154_frame_security_header_offset(const uint8_t IEEE802154_STATIC uint8_t ieee802154_frame_get_security_field_len(const uint8_t *frame) { - ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_OFFSET, TAG, "invalid frame type"); + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid frame type"); uint8_t security_field_len = 0; uint8_t offset = ieee802154_frame_security_header_offset(frame); - ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, TAG, "invalid offset"); + ESP_RETURN_ON_FALSE_ISR(offset != IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_FRAME_INVALID_OFFSET, IEEE802154_TAG, "invalid offset"); security_field_len += IEEE802154_FRAME_SE_HEAD_SIZE; uint8_t security_header = frame[offset]; @@ -315,13 +314,13 @@ bool IEEE802154_INLINE ieee802154_frame_is_ack_required(const uint8_t *frame) uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr) { - ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, TAG, "invalid frame type"); + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type"); uint8_t offset = ieee802154_frame_address_offset(frame); uint8_t dst_mode = dst_addr_mode(frame); uint8_t addr_size; - ESP_RETURN_ON_FALSE_ISR(dst_mode == IEEE802154_FRAME_DST_MODE_SHORT || dst_mode == IEEE802154_FRAME_DST_MODE_EXT, dst_mode, TAG, "invalid address mode"); + ESP_RETURN_ON_FALSE_ISR(dst_mode == IEEE802154_FRAME_DST_MODE_SHORT || dst_mode == IEEE802154_FRAME_DST_MODE_EXT, dst_mode, IEEE802154_TAG, "invalid address mode"); addr_size = (dst_mode == IEEE802154_FRAME_DST_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE; @@ -336,14 +335,14 @@ uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr) uint8_t ieee802154_frame_get_src_addr(const uint8_t *frame, uint8_t *addr) { - ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, TAG, "invalid frame type"); + ESP_RETURN_ON_FALSE_ISR(is_suported_frame_type(ieee802154_frame_get_type(frame)), IEEE802154_FRAME_INVALID_ADDR_MODE, IEEE802154_TAG, "invalid frame type"); uint8_t offset = ieee802154_frame_address_offset(frame); uint8_t dst_mode = dst_addr_mode(frame); uint8_t src_mode = src_addr_mode(frame); uint8_t addr_size; - ESP_RETURN_ON_FALSE_ISR(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT, src_mode, TAG, "invalid address mode"); + ESP_RETURN_ON_FALSE_ISR(src_mode == IEEE802154_FRAME_SRC_MODE_SHORT || src_mode == IEEE802154_FRAME_SRC_MODE_EXT, src_mode, IEEE802154_TAG, "invalid address mode"); addr_size = (src_mode == IEEE802154_FRAME_SRC_MODE_SHORT) ? IEEE802154_FRAME_SHORT_ADDR_SIZE : IEEE802154_FRAME_EXT_ADDR_SIZE; diff --git a/components/ieee802154/driver/esp_ieee802154_timer.c b/components/ieee802154/driver/esp_ieee802154_timer.c index fb564cbcb58..e2bff1a59be 100644 --- a/components/ieee802154/driver/esp_ieee802154_timer.c +++ b/components/ieee802154/driver/esp_ieee802154_timer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,8 +8,7 @@ #include "hal/ieee802154_ll.h" #include "esp_check.h" #include "esp_ieee802154_timer.h" - -static const char *TAG = "ieee802154_timer"; +#include "esp_ieee802154_util.h" void ieee802154_timer0_start(void) { @@ -23,7 +22,7 @@ void ieee802154_timer0_stop(void) esp_err_t ieee802154_timer0_set_threshold(uint32_t value) { - ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER0_THRESHOLD), ESP_ERR_INVALID_ARG, TAG, "invalid timer0 threshold\r\n"); + ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER0_THRESHOLD), ESP_ERR_INVALID_ARG, IEEE802154_TAG, "invalid timer0 threshold"); ieee802154_ll_timer0_set_threshold(value); @@ -47,7 +46,7 @@ void ieee802154_timer1_stop(void) esp_err_t ieee802154_timer1_set_threshold(uint32_t value) { - ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER1_THRESHOLD), ESP_ERR_INVALID_ARG, TAG, "invalid timer1 threshold\r\n"); + ESP_RETURN_ON_FALSE((value < IEEE802154_TIMER1_THRESHOLD), ESP_ERR_INVALID_ARG, IEEE802154_TAG, "invalid timer1 threshold"); ieee802154_ll_timer1_set_threshold(value); diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h index 6dada29c56c..ace28cd5f78 100644 --- a/components/ieee802154/private_include/esp_ieee802154_dev.h +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -19,8 +19,6 @@ extern "C" { #endif -#define IEEE802154_TAG "ieee802154" - // These three macros are in microseconds, used for transmit_at #define IEEE802154_ED_TRIG_TX_RAMPUP_TIME_US 256 #define IEEE802154_TX_RAMPUP_TIME_US 98 diff --git a/components/ieee802154/private_include/esp_ieee802154_util.h b/components/ieee802154/private_include/esp_ieee802154_util.h index 44ca5980619..7949e5286da 100644 --- a/components/ieee802154/private_include/esp_ieee802154_util.h +++ b/components/ieee802154/private_include/esp_ieee802154_util.h @@ -17,6 +17,8 @@ extern "C" { #endif +#define IEEE802154_TAG "ieee802154" + #if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE #define IEEE802154_RF_ENABLE() ieee802154_rf_enable() #define IEEE802154_RF_DISABLE() ieee802154_rf_disable() From fd0ea434963bb6672fba9d26ed8cc715059e0fd5 Mon Sep 17 00:00:00 2001 From: zwx Date: Mon, 3 Jun 2024 19:53:08 +0800 Subject: [PATCH 218/548] fix(802.15.4): fixed ieee802154 will sleep when only pm enabled --- .../ieee802154/driver/esp_ieee802154_dev.c | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index f94f15d6c98..c5371814796 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -27,7 +27,7 @@ #include "esp_attr.h" #include "esp_phy_init.h" -#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_PM_ENABLE #include "esp_pm.h" #include "esp_private/esp_clk.h" #include "esp_private/sleep_retention.h" @@ -37,7 +37,7 @@ #else #define IEEE802154_LINK_OWNER ENTRY(0) | ENTRY(2) #endif // SOC_PM_RETENTION_HAS_CLOCK_BUG -#endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#endif // CONFIG_PM_ENABLE static bool s_rf_closed = true; #define CCA_DETECTION_TIME 8 @@ -915,24 +915,27 @@ esp_err_t ieee802154_receive_at(uint32_t time) return ESP_OK; } -#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_PM_ENABLE static esp_err_t ieee802154_sleep_retention_init(void *arg) { + esp_err_t err = ESP_OK; +#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE #define N_REGS_IEEE802154() (((IEEE802154_MAC_DATE_REG - IEEE802154_REG_BASE) / 4) + 1) const static sleep_retention_entries_config_t ieee802154_mac_regs_retention[] = { [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_MODEM_IEEE802154_LINK(0x00), IEEE802154_REG_BASE, IEEE802154_REG_BASE, N_REGS_IEEE802154(), 0, 0), .owner = IEEE802154_LINK_OWNER }, }; - esp_err_t err = sleep_retention_entries_create(ieee802154_mac_regs_retention, ARRAY_SIZE(ieee802154_mac_regs_retention), REGDMA_LINK_PRI_IEEE802154, SLEEP_RETENTION_MODULE_802154_MAC); + err = sleep_retention_entries_create(ieee802154_mac_regs_retention, ARRAY_SIZE(ieee802154_mac_regs_retention), REGDMA_LINK_PRI_IEEE802154, SLEEP_RETENTION_MODULE_802154_MAC); ESP_RETURN_ON_ERROR(err, IEEE802154_TAG, "failed to allocate memory for ieee802154 mac retention"); ESP_LOGD(IEEE802154_TAG, "ieee802154 mac sleep retention initialization"); +#endif return err; } -#endif +#endif // CONFIG_PM_ENABLE static esp_err_t ieee802154_sleep_init(void) { esp_err_t err = ESP_OK; -#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_PM_ENABLE sleep_retention_module_init_param_t init_param = { .cbs = { .create = { .handle = ieee802154_sleep_retention_init, .arg = NULL } }, .depends = BIT(SLEEP_RETENTION_MODULE_BT_BB) | BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM) @@ -946,14 +949,14 @@ static esp_err_t ieee802154_sleep_init(void) sleep_modem_register_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, sleep_modem_mac_bb_power_up_prepare); #endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD -#endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#endif // CONFIG_PM_ENABLE return err; } static esp_err_t ieee802154_sleep_deinit(void) { esp_err_t err = ESP_OK; -#if SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_PM_ENABLE err = sleep_retention_module_free(SLEEP_RETENTION_MODULE_802154_MAC); if (err == ESP_OK) { err = sleep_retention_module_deinit(SLEEP_RETENTION_MODULE_802154_MAC); @@ -962,7 +965,7 @@ static esp_err_t ieee802154_sleep_deinit(void) sleep_modem_unregister_mac_bb_module_prepare_callback(sleep_modem_mac_bb_power_down_prepare, sleep_modem_mac_bb_power_up_prepare); #endif // SOC_PM_RETENTION_HAS_CLOCK_BUG && CONFIG_MAC_BB_PD -#endif // SOC_PM_MODEM_RETENTION_BY_REGDMA && CONFIG_FREERTOS_USE_TICKLESS_IDLE +#endif // CONFIG_PM_ENABLE return err; } From 15512f4170ba2ffb638cc012f017989515075435 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 29 May 2024 20:52:10 +0800 Subject: [PATCH 219/548] fix(openthread): remove the empty task for openthread tasklets --- .codespellrc | 2 +- components/openthread/src/esp_openthread.cpp | 14 +-- .../src/esp_openthread_platform.cpp | 5 +- .../src/esp_openthread_task_queue.c | 11 ++- .../openthread/src/port/esp_openthread_udp.c | 90 +++++++++---------- .../src/port/esp_spi_spinel_interface.cpp | 4 +- .../src/port/esp_uart_spinel_interface.cpp | 4 +- .../esp_radio_spinel_uart_interface.cpp | 4 +- 8 files changed, 65 insertions(+), 69 deletions(-) diff --git a/.codespellrc b/.codespellrc index 389e346d2a1..b664425f9c7 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,4 +1,4 @@ [codespell] skip = build,*.yuv,components/fatfs/src/*,alice.txt,*.rgb,components/wpa_supplicant/*,components/esp_wifi/* -ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight +ignore-words-list = ser,dout,rsource,fram,inout,shs,ans,aci,unstall,unstalling,hart,wheight,ot write-changes = true diff --git a/components/openthread/src/esp_openthread.cpp b/components/openthread/src/esp_openthread.cpp index 60eba6153df..87c7b4986ec 100644 --- a/components/openthread/src/esp_openthread.cpp +++ b/components/openthread/src/esp_openthread.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -129,7 +129,7 @@ esp_err_t esp_openthread_auto_start(otOperationalDatasetTlvs *datasetTlvs) memcpy(dataset.mMeshLocalPrefix.m8, prefix.mPrefix.mFields.m8, sizeof(dataset.mMeshLocalPrefix.m8)); dataset.mComponents.mIsMeshLocalPrefixPresent = true; } else { - ESP_LOGE("Falied to parse mesh local prefix", CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX); + ESP_LOGE("Failed to parse mesh local prefix", CONFIG_OPENTHREAD_MESH_LOCAL_PREFIX); } // Network Key @@ -213,13 +213,3 @@ esp_err_t esp_openthread_deinit(void) otInstanceFinalize(esp_openthread_get_instance()); return esp_openthread_platform_deinit(); } - -static void stub_task(void *context) -{ - // this is a empty function used for ot-task signal pending -} - -void otTaskletsSignalPending(otInstance *aInstance) -{ - esp_openthread_task_queue_post(stub_task, NULL); -} diff --git a/components/openthread/src/esp_openthread_platform.cpp b/components/openthread/src/esp_openthread_platform.cpp index f6f29e278e5..3e73ef362a5 100644 --- a/components/openthread/src/esp_openthread_platform.cpp +++ b/components/openthread/src/esp_openthread_platform.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -34,7 +34,7 @@ static esp_openthread_platform_workflow_t *s_workflow_list = NULL; esp_err_t esp_openthread_platform_workflow_register(esp_openthread_update_func update_func, esp_openthread_process_func process_func, const char *name) { - uint8_t name_len = strnlen(name, WORKFLOW_MAX_NAMELEN); + uint8_t name_len = strnlen(name, WORKFLOW_MAX_NAMELEN - 1); esp_openthread_platform_workflow_t *current_workflow = s_workflow_list; esp_openthread_platform_workflow_t *before_workflow = NULL; esp_openthread_platform_workflow_t *add_workflow = @@ -42,6 +42,7 @@ esp_err_t esp_openthread_platform_workflow_register(esp_openthread_update_func u ESP_RETURN_ON_FALSE(add_workflow != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to alloc memory for esp_openthread_workflow"); strncpy(add_workflow->name, name, name_len); + add_workflow->name[name_len] = '\0'; add_workflow->update_func = update_func; add_workflow->process_func = process_func; add_workflow->next = NULL; diff --git a/components/openthread/src/esp_openthread_task_queue.c b/components/openthread/src/esp_openthread_task_queue.c index 4acfaad722b..32bb4f20020 100644 --- a/components/openthread/src/esp_openthread_task_queue.c +++ b/components/openthread/src/esp_openthread_task_queue.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include "freertos/queue.h" +#include "openthread/tasklet.h" static QueueHandle_t s_task_queue = NULL; static int s_task_queue_event_fd = -1; @@ -37,6 +38,14 @@ esp_err_t esp_openthread_task_queue_init(const esp_openthread_platform_config_t &esp_openthread_task_queue_process, task_queue_workflow); } +void otTaskletsSignalPending(otInstance *aInstance) +{ + uint64_t val = 1; + ssize_t ret; + ret = write(s_task_queue_event_fd, &val, sizeof(val)); + assert(ret == sizeof(val)); +} + esp_err_t IRAM_ATTR esp_openthread_task_queue_post(esp_openthread_task_t task, void *arg) { task_storage_t task_storage = { diff --git a/components/openthread/src/port/esp_openthread_udp.c b/components/openthread/src/port/esp_openthread_udp.c index 852c0a920a0..fd118b2a0f7 100644 --- a/components/openthread/src/port/esp_openthread_udp.c +++ b/components/openthread/src/port/esp_openthread_udp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ #include "esp_openthread_task_queue.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "lwip/err.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/ip_addr.h" @@ -40,24 +41,19 @@ typedef struct { } udp_recv_task_t; typedef struct { - TaskHandle_t source_task; otUdpSocket *socket; struct udp_pcb *pcb_ret; } udp_new_task_t; typedef struct { - TaskHandle_t source_task; struct udp_pcb *pcb; ip_addr_t addr; uint16_t port; - err_t ret; } udp_bind_connect_task_t; typedef struct { - TaskHandle_t source_task; struct udp_pcb *pcb; uint8_t netif_index; - esp_err_t err; } udp_bind_netif_task_t; typedef struct { @@ -78,13 +74,6 @@ typedef struct { ip6_addr_t addr; } udp_multicast_join_leave_task_t; -static void wait_for_task_notification(void) -{ - esp_openthread_task_switching_lock_release(); - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - esp_openthread_task_switching_lock_acquire(portMAX_DELAY); -} - static ip_addr_t map_openthread_addr_to_lwip_addr(const otIp6Address *address) { ip_addr_t addr; @@ -185,23 +174,25 @@ static void handle_udp_recv(void *ctx, struct udp_pcb *pcb, struct pbuf *p, cons } } -static void udp_new_task(void *ctx) +static esp_err_t udp_new_task(void *ctx) { udp_new_task_t *task = (udp_new_task_t *)ctx; - task->pcb_ret = udp_new(); + ESP_RETURN_ON_FALSE(task->pcb_ret != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create a new UDP pcb"); udp_recv(task->pcb_ret, handle_udp_recv, task->socket); - xTaskNotifyGive(task->source_task); + return ESP_OK; } otError otPlatUdpSocket(otUdpSocket *udp_socket) { otError error = OT_ERROR_NONE; + esp_err_t err = ESP_OK; - udp_new_task_t task = { .source_task = xTaskGetCurrentTaskHandle(), .socket = udp_socket }; - tcpip_callback(udp_new_task, &task); - wait_for_task_notification(); - VerifyOrExit(task.pcb_ret != NULL, error = OT_ERROR_FAILED); + udp_new_task_t task = {.socket = udp_socket }; + esp_openthread_task_switching_lock_release(); + err = esp_netif_tcpip_exec(udp_new_task, &task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); + VerifyOrExit(err == ESP_OK, error = OT_ERROR_FAILED); udp_socket->mHandle = task.pcb_ret; exit: @@ -220,24 +211,25 @@ otError otPlatUdpClose(otUdpSocket *udp_socket) struct udp_pcb *pcb = (struct udp_pcb *)udp_socket->mHandle; if (pcb) { + esp_openthread_task_switching_lock_release(); tcpip_callback(udp_close_task, pcb); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); } return OT_ERROR_NONE; } -static void udp_bind_task(void *ctx) +static esp_err_t udp_bind_task(void *ctx) { udp_bind_connect_task_t *task = (udp_bind_connect_task_t *)ctx; - - task->ret = udp_bind(task->pcb, &task->addr, task->port); - xTaskNotifyGive(task->source_task); + err_t ret = udp_bind(task->pcb, &task->addr, task->port); + return (ret == ERR_OK) ? ESP_OK : ESP_FAIL; } otError otPlatUdpBind(otUdpSocket *udp_socket) { + esp_err_t err = ESP_OK; udp_bind_connect_task_t task = { - .source_task = xTaskGetCurrentTaskHandle(), .pcb = (struct udp_pcb *)udp_socket->mHandle, .port = udp_socket->mSockName.mPort, }; @@ -247,17 +239,18 @@ otError otPlatUdpBind(otUdpSocket *udp_socket) task.addr.type = IPADDR_TYPE_ANY; #endif memcpy(ip_2_ip6(&task.addr)->addr, udp_socket->mSockName.mAddress.mFields.m8, sizeof(ip_2_ip6(&task.addr)->addr)); - tcpip_callback(udp_bind_task, &task); - wait_for_task_notification(); + esp_openthread_task_switching_lock_release(); + err = esp_netif_tcpip_exec(udp_bind_task, &task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); - return task.ret == ERR_OK ? OT_ERROR_NONE : OT_ERROR_FAILED; + return err == ESP_OK ? OT_ERROR_NONE : OT_ERROR_FAILED; } -static void udp_bind_netif_task(void *ctx) +static esp_err_t udp_bind_netif_task(void *ctx) { udp_bind_netif_task_t *task = (udp_bind_netif_task_t *)ctx; udp_bind_netif(task->pcb, netif_get_by_index(task->netif_index)); - xTaskNotifyGive(task->source_task); + return ESP_OK; } static uint8_t get_netif_index(otNetifIdentifier netif_identifier) @@ -276,34 +269,30 @@ static uint8_t get_netif_index(otNetifIdentifier netif_identifier) otError otPlatUdpBindToNetif(otUdpSocket *udp_socket, otNetifIdentifier netif_identifier) { - otError err = OT_ERROR_NONE; + esp_err_t err = ESP_OK; udp_bind_netif_task_t task = { - .source_task = xTaskGetCurrentTaskHandle(), .pcb = (struct udp_pcb *)udp_socket->mHandle, .netif_index = get_netif_index(netif_identifier), - .err = ESP_OK, }; - tcpip_callback(udp_bind_netif_task, &task); - wait_for_task_notification(); - if (task.err != ESP_OK) { - err = OT_ERROR_FAILED; - } - return err; + esp_openthread_task_switching_lock_release(); + err = esp_netif_tcpip_exec(udp_bind_netif_task, &task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); + + return err == ESP_OK ? OT_ERROR_NONE : OT_ERROR_FAILED; } -static void udp_connect_task(void *ctx) +static esp_err_t udp_connect_task(void *ctx) { udp_bind_connect_task_t *task = (udp_bind_connect_task_t *)ctx; - - task->ret = udp_connect(task->pcb, &task->addr, task->port); - xTaskNotifyGive(task->source_task); + err_t ret = udp_connect(task->pcb, &task->addr, task->port); + return (ret == ERR_OK) ? ESP_OK : ESP_FAIL; } otError otPlatUdpConnect(otUdpSocket *udp_socket) { + esp_err_t err = ESP_OK; udp_bind_connect_task_t task = { - .source_task = xTaskGetCurrentTaskHandle(), .pcb = (struct udp_pcb *)udp_socket->mHandle, .port = udp_socket->mPeerName.mPort, }; @@ -312,10 +301,11 @@ otError otPlatUdpConnect(otUdpSocket *udp_socket) if (ip_addr_isany_val(task.addr) && task.port == 0) { return OT_ERROR_NONE; } - tcpip_callback(udp_connect_task, &task); - wait_for_task_notification(); + esp_openthread_task_switching_lock_release(); + err = esp_netif_tcpip_exec(udp_connect_task, &task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); - return task.ret == ERR_OK ? OT_ERROR_NONE : OT_ERROR_FAILED; + return err == ESP_OK ? OT_ERROR_NONE : OT_ERROR_FAILED; } static bool is_link_local(const otIp6Address *address) @@ -419,7 +409,9 @@ otError otPlatUdpSend(otUdpSocket *udp_socket, otMessage *message, const otMessa // If the destination address is a openthread mesh local address, set the netif OT. task->netif_index = get_netif_index(OT_NETIF_THREAD); } + esp_openthread_task_switching_lock_release(); tcpip_callback(udp_send_task, task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); exit: return error; @@ -458,7 +450,9 @@ otError otPlatUdpJoinMulticastGroup(otUdpSocket *socket, otNetifIdentifier netif task->netif_index = get_netif_index(netif_id); task->addr.zone = task->netif_index; memcpy(task->addr.addr, addr->mFields.m8, sizeof(task->addr.addr)); + esp_openthread_task_switching_lock_release(); tcpip_callback(udp_multicast_join_leave_task, task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); exit: return error; @@ -475,7 +469,9 @@ otError otPlatUdpLeaveMulticastGroup(otUdpSocket *socket, otNetifIdentifier neti task->netif_index = get_netif_index(netif_id); task->addr.zone = task->netif_index; memcpy(task->addr.addr, addr->mFields.m8, sizeof(task->addr.addr)); + esp_openthread_task_switching_lock_release(); tcpip_callback(udp_multicast_join_leave_task, task); + esp_openthread_task_switching_lock_acquire(portMAX_DELAY); exit: return error; diff --git a/components/openthread/src/port/esp_spi_spinel_interface.cpp b/components/openthread/src/port/esp_spi_spinel_interface.cpp index b89eff6779f..e19acd91527 100644 --- a/components/openthread/src/port/esp_spi_spinel_interface.cpp +++ b/components/openthread/src/port/esp_spi_spinel_interface.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -266,8 +266,8 @@ otError SpiSpinelInterface::WaitForFrame(uint64_t timeout_us) otError SpiSpinelInterface::HardwareReset(void) { if (mRcpFailureHandler) { - mRcpFailureHandler(); ConductSPITransaction(true, 0, 0); // clear + mRcpFailureHandler(); } return OT_ERROR_NONE; } diff --git a/components/openthread/src/port/esp_uart_spinel_interface.cpp b/components/openthread/src/port/esp_uart_spinel_interface.cpp index 2cfa42d5e42..6f683fdee4a 100644 --- a/components/openthread/src/port/esp_uart_spinel_interface.cpp +++ b/components/openthread/src/port/esp_uart_spinel_interface.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -295,8 +295,8 @@ esp_err_t UartSpinelInterface::TryRecoverUart(void) otError UartSpinelInterface::HardwareReset(void) { if (mRcpFailureHandler) { - mRcpFailureHandler(); TryRecoverUart(); + mRcpFailureHandler(); } return OT_ERROR_NONE; } diff --git a/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp index d07a67065b1..56806500590 100644 --- a/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -276,8 +276,8 @@ esp_err_t UartSpinelInterface::TryRecoverUart(void) otError UartSpinelInterface::HardwareReset(void) { if (mRcpFailureHandler) { - mRcpFailureHandler(); TryRecoverUart(); + mRcpFailureHandler(); } return OT_ERROR_NONE; } From 1de232fb98fc5a3d12d691afa5934f4412662b4a Mon Sep 17 00:00:00 2001 From: zwx Date: Tue, 4 Jun 2024 12:18:13 +0800 Subject: [PATCH 220/548] feat(openthread): update BR lib --- components/openthread/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openthread/lib b/components/openthread/lib index 5ae57e156e4..34d698a2749 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit 5ae57e156e4cd2ccd8dc51e90266b16b284e64de +Subproject commit 34d698a274940730901b934caa023a3281aca53e From 0b8952dc2eccd49793fc1fca9ab808160d30f78f Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 11 Jun 2024 11:42:36 +0800 Subject: [PATCH 221/548] change(dma): remove esp_dma_x usage in programming guide --- docs/doxygen/Doxyfile | 1 - docs/en/api-reference/system/mm_sync.rst | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 73551440033..0fb7b41bef0 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -159,7 +159,6 @@ INPUT = \ $(PROJECT_PATH)/components/esp_http_server/include/esp_http_server.h \ $(PROJECT_PATH)/components/esp_https_ota/include/esp_https_ota.h \ $(PROJECT_PATH)/components/esp_https_server/include/esp_https_server.h \ - $(PROJECT_PATH)/components/esp_hw_support/dma/include/esp_dma_utils.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_clk_tree.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_async_memcpy.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_chip_info.h \ diff --git a/docs/en/api-reference/system/mm_sync.rst b/docs/en/api-reference/system/mm_sync.rst index 55fb9932d1c..fafb5a26d12 100644 --- a/docs/en/api-reference/system/mm_sync.rst +++ b/docs/en/api-reference/system/mm_sync.rst @@ -101,17 +101,6 @@ There is address and size alignment requirement (in bytes) for using :cpp:func:` By default, if you specify an unaligned address region, :cpp:func:`esp_cache_msync` will return an :c:macro:`ESP_ERR_INVALID_ARG` error, together with the required alignment. -Memory Allocation Helper ------------------------- - -cache memory synchronization is usually considered when DMA is involved. ESP-IDF provides an API to do memory allocation that can meet the alignment requirement from both the cache and the DMA. - -- :cpp:func:`esp_dma_capable_malloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. -- :cpp:func:`esp_dma_capable_calloc`, this API allocates a chunk of memory that meets the alignment requirement from both the cache and the DMA. The initialized value in the memory is set to zero. - -You can also use :c:macro:`ESP_DMA_MALLOC_FLAG_PSRAM` to allocate from the PSRAM. - - Warning for Address Alignment Requirement ----------------------------------------- @@ -138,9 +127,3 @@ API Reference - ESP Msync Driver -------------------------------- .. include-build-file:: inc/esp_cache.inc - - -API Reference - ESP DMA Utils ------------------------------ - -.. include-build-file:: inc/esp_dma_utils.inc From 0868604664c7f926a1fe655a9f912a93d61f6ebb Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 31 May 2024 22:26:59 +0530 Subject: [PATCH 222/548] fix(esp_hw_support): Fix incorrect PMA configuration for ESP32-P4 - As the PMA entry that made some memory regions cacheable was assigned the highest priority, some intermediate inaccessible memory regions bypassed protection. - Added tests for the same - Verified that even after changing the priority of the PMA entry, a write operation at SOC_IRAM_LOW + 0x40 (a random RAM cached address) still needs the same number (29) of CPU cycles. --- .../port/esp32p4/cpu_region_protect.c | 49 +++++++++---------- .../system/panic/main/include/test_memprot.h | 4 ++ .../system/panic/main/test_app_main.c | 4 ++ .../system/panic/main/test_memprot.c | 18 +++++++ tools/test_apps/system/panic/pytest_panic.py | 24 +++++++++ 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/cpu_region_protect.c b/components/esp_hw_support/port/esp32p4/cpu_region_protect.c index cfed9a0f0c6..acf88eae27b 100644 --- a/components/esp_hw_support/port/esp32p4/cpu_region_protect.c +++ b/components/esp_hw_support/port/esp32p4/cpu_region_protect.c @@ -38,39 +38,38 @@ static void esp_cpu_configure_invalid_regions(void) __attribute__((unused)) const unsigned PMA_RX = PMA_L | PMA_EN | PMA_R | PMA_X; __attribute__((unused)) const unsigned PMA_RWX = PMA_L | PMA_EN | PMA_R | PMA_W | PMA_X; - // 0. Special case - This whitelists the External flash/RAM, HP ROM and HP L2MEM regions and make them cacheable. - // At the startup, this is done using PMA entry 15 by the ROM code. - // We are reconfiguring and making it the highest priority entry here. - PMA_ENTRY_SET_NAPOT(0, SOC_IROM_LOW, SOC_PERIPHERAL_LOW - SOC_IROM_LOW, PMA_NAPOT | PMA_RWX); + // 0. Gap at bottom of address space + PMA_ENTRY_SET_NAPOT(0, 0, SOC_CPU_SUBSYSTEM_LOW, PMA_NAPOT | PMA_NONE); - // 1. Gap at bottom of address space - PMA_ENTRY_SET_NAPOT(1, 0, SOC_CPU_SUBSYSTEM_LOW, PMA_NAPOT | PMA_NONE); + // 1. Gap between CPU subsystem region & HP TCM + PMA_ENTRY_SET_TOR(1, SOC_CPU_SUBSYSTEM_HIGH, PMA_NONE); + PMA_ENTRY_SET_TOR(2, SOC_TCM_LOW, PMA_TOR | PMA_NONE); - // 2. Gap between CPU subsystem region & HP TCM - PMA_ENTRY_SET_TOR(2, SOC_CPU_SUBSYSTEM_HIGH, PMA_NONE); - PMA_ENTRY_SET_TOR(3, SOC_TCM_LOW, PMA_TOR | PMA_NONE); + // 2. Gap between HP TCM and CPU Peripherals + PMA_ENTRY_SET_TOR(3, SOC_TCM_HIGH, PMA_NONE); + PMA_ENTRY_SET_TOR(4, CPU_PERIPH_LOW, PMA_TOR | PMA_NONE); - // 3. Gap between HP TCM and CPU Peripherals - PMA_ENTRY_SET_TOR(4, SOC_TCM_HIGH, PMA_NONE); - PMA_ENTRY_SET_TOR(5, CPU_PERIPH_LOW, PMA_TOR | PMA_NONE); + // 3. Gap between CPU Peripherals and I_Cache + PMA_ENTRY_SET_TOR(5, CPU_PERIPH_HIGH, PMA_NONE); + PMA_ENTRY_SET_TOR(6, SOC_IROM_LOW, PMA_TOR | PMA_NONE); - // 4. Gap between CPU Peripherals and I_Cache - PMA_ENTRY_SET_TOR(6, CPU_PERIPH_HIGH, PMA_NONE); - PMA_ENTRY_SET_TOR(7, SOC_IROM_LOW, PMA_TOR | PMA_NONE); + // 4. Gap between I_Cache and external memory range + PMA_ENTRY_SET_NAPOT(7, SOC_DROM_HIGH, SOC_EXTRAM_LOW - SOC_DROM_HIGH, PMA_NAPOT | PMA_NONE); - // 5. Gap between I_Cache and external memory range - PMA_ENTRY_SET_NAPOT(8, SOC_DROM_HIGH, SOC_EXTRAM_LOW - SOC_DROM_HIGH, PMA_NAPOT | PMA_NONE); + // 5. Gap between external memory and ROM + PMA_ENTRY_SET_TOR(8, SOC_EXTRAM_HIGH, PMA_NONE); + PMA_ENTRY_SET_TOR(9, SOC_IROM_MASK_LOW, PMA_TOR | PMA_NONE); - // 6. Gap between external memory and ROM - PMA_ENTRY_SET_TOR(9, SOC_EXTRAM_HIGH, PMA_NONE); - PMA_ENTRY_SET_TOR(10, SOC_IROM_MASK_LOW, PMA_TOR | PMA_NONE); + // 6. Gap between ROM and internal memory + PMA_ENTRY_SET_TOR(10, SOC_IROM_MASK_HIGH, PMA_NONE); + PMA_ENTRY_SET_TOR(11, SOC_IRAM_LOW, PMA_TOR | PMA_NONE); - // 7. Gap between ROM and internal memory - PMA_ENTRY_SET_TOR(11, SOC_IROM_MASK_HIGH, PMA_NONE); - PMA_ENTRY_SET_TOR(12, SOC_IRAM_LOW, PMA_TOR | PMA_NONE); + // 7. Gap between internal memory and HP peripherals + PMA_ENTRY_SET_NAPOT(12, SOC_DRAM_HIGH, SOC_PERIPHERAL_LOW - SOC_DRAM_HIGH, PMA_NAPOT | PMA_NONE); - // 8. Gap between internal memory and HP peripherals - PMA_ENTRY_SET_NAPOT(13, SOC_DRAM_HIGH, SOC_PERIPHERAL_LOW - SOC_DRAM_HIGH, PMA_NAPOT | PMA_NONE); + // 8. Special case - This whitelists the External flash/RAM, HP ROM and HP L2MEM regions and make them cacheable. + // At the startup, this is done using PMA entry 15 by the ROM code. + PMA_ENTRY_SET_NAPOT(13, SOC_IROM_LOW, SOC_PERIPHERAL_LOW - SOC_IROM_LOW, PMA_NAPOT | PMA_RWX); // 9. Gap between Uncacheable L2 Mem and end of address space PMA_ENTRY_SET_TOR(14, CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_DRAM_HIGH), PMA_NONE); diff --git a/tools/test_apps/system/panic/main/include/test_memprot.h b/tools/test_apps/system/panic/main/include/test_memprot.h index d21d795f608..6b8cfde2df9 100644 --- a/tools/test_apps/system/panic/main/include/test_memprot.h +++ b/tools/test_apps/system/panic/main/include/test_memprot.h @@ -48,6 +48,10 @@ void test_drom_reg_write_violation(void); void test_drom_reg_execute_violation(void); +void test_invalid_memory_region_write_violation(void); + +void test_invalid_memory_region_execute_violation(void); + #ifdef __cplusplus } #endif diff --git a/tools/test_apps/system/panic/main/test_app_main.c b/tools/test_apps/system/panic/main/test_app_main.c index 1a387f0018b..7fb99a273d9 100644 --- a/tools/test_apps/system/panic/main/test_app_main.c +++ b/tools/test_apps/system/panic/main/test_app_main.c @@ -155,6 +155,10 @@ void app_main(void) HANDLE_TEST(test_name, test_drom_reg_execute_violation); #endif +#ifdef CONFIG_SOC_CPU_HAS_PMA + HANDLE_TEST(test_name, test_invalid_memory_region_write_violation); + HANDLE_TEST(test_name, test_invalid_memory_region_execute_violation); +#endif #endif die("Unknown test name"); diff --git a/tools/test_apps/system/panic/main/test_memprot.c b/tools/test_apps/system/panic/main/test_memprot.c index cfefa415e69..73885f1e0cb 100644 --- a/tools/test_apps/system/panic/main/test_memprot.c +++ b/tools/test_apps/system/panic/main/test_memprot.c @@ -246,3 +246,21 @@ void test_drom_reg_execute_violation(void) func_ptr(); } #endif + +#ifdef CONFIG_SOC_CPU_HAS_PMA +void test_invalid_memory_region_write_violation(void) +{ + uint32_t *test_addr = (uint32_t *)((uint32_t)(SOC_DRAM_HIGH + 0x40)); + printf("Write operation | Address: %p\n", test_addr); + *test_addr = RND_VAL; + printf("%ld\n", *test_addr); +} + +void test_invalid_memory_region_execute_violation(void) +{ + void (*func_ptr)(void); + func_ptr = (void(*)(void))(SOC_DRAM_HIGH + 0x40); + printf("Execute operation | Address: %p\n", func_ptr); + func_ptr(); +} +#endif diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 90154a40d2e..e3193670ad3 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -588,6 +588,12 @@ def test_panic_delay(dut: PanicTestDut) -> None: pytest.param('memprot_esp32p4', marks=[pytest.mark.esp32p4]) ] +CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA = [ + pytest.param('memprot_esp32c6', marks=[pytest.mark.esp32c6]), + pytest.param('memprot_esp32h2', marks=[pytest.mark.esp32h2]), + pytest.param('memprot_esp32p4', marks=[pytest.mark.esp32p4]) +] + @pytest.mark.parametrize('config', CONFIGS_MEMPROT_DCACHE, indirect=True) @pytest.mark.generic @@ -851,6 +857,24 @@ def test_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> N dut.expect_cpu_reset() +@pytest.mark.parametrize('config', CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA, indirect=True) +@pytest.mark.generic +def test_invalid_memory_region_write_violation(dut: PanicTestDut, test_func_name: str) -> None: + dut.run_test_func(test_func_name) + dut.expect_gme('Store access fault') + dut.expect_reg_dump(0) + dut.expect_cpu_reset() + + +@pytest.mark.parametrize('config', CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA, indirect=True) +@pytest.mark.generic +def test_invalid_memory_region_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: + dut.run_test_func(test_func_name) + dut.expect_gme('Instruction access fault') + dut.expect_reg_dump(0) + dut.expect_cpu_reset() + + @pytest.mark.esp32 @pytest.mark.generic @pytest.mark.parametrize('config', ['gdbstub_coredump'], indirect=True) From 4f11dd7e217acf7679bf8aab0ec591af1bf9c14a Mon Sep 17 00:00:00 2001 From: Jakub Kocka Date: Wed, 5 Jun 2024 15:28:20 +0200 Subject: [PATCH 223/548] fix(tools): Avoid crashing when Git is used to acquire IDF version Closes https://github.com/espressif/esp-idf/issues/13345 --- tools/idf_py_actions/tools.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tools/idf_py_actions/tools.py b/tools/idf_py_actions/tools.py index 20942435691..76322ae7c66 100644 --- a/tools/idf_py_actions/tools.py +++ b/tools/idf_py_actions/tools.py @@ -80,6 +80,7 @@ def executable_exists(args: List) -> bool: def _idf_version_from_cmake() -> Optional[str]: + """Acquires version of ESP-IDF from version.cmake""" version_path = os.path.join(os.environ['IDF_PATH'], 'tools/cmake/version.cmake') regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)') ver = {} @@ -113,7 +114,7 @@ def idf_version() -> Optional[str]: '--work-tree=%s' % os.environ['IDF_PATH'], 'describe', '--tags', '--dirty', '--match', 'v*.*', ]).decode('utf-8', 'ignore').strip() - except (subprocess.CalledProcessError, UnicodeError): + except Exception: # if failed, then try to parse cmake.version file sys.stderr.write('WARNING: Git version unavailable, reading from source\n') version = _idf_version_from_cmake() @@ -148,7 +149,7 @@ def get_default_serial_port() -> Any: # function prints warning when autocompletion is not being performed # set argument stream to sys.stderr for errors and exceptions -def print_warning(message: str, stream: TextIO=None) -> None: +def print_warning(message: str, stream: Optional[TextIO]=None) -> None: if not SHELL_COMPLETE_RUN: print(message, file=stream or sys.stderr) @@ -277,8 +278,9 @@ def fit_text_in_terminal(out: str) -> str: class RunTool: - def __init__(self, tool_name: str, args: List, cwd: str, env: Dict=None, custom_error_handler: FunctionType=None, build_dir: str=None, - hints: bool=True, force_progression: bool=False, interactive: bool=False, convert_output: bool=False) -> None: + def __init__(self, tool_name: str, args: List, cwd: str, env: Optional[Dict]=None, custom_error_handler: Optional[FunctionType]=None, + build_dir: Optional[str]=None, hints: bool=True, force_progression: bool=False, interactive: bool=False, convert_output: bool=False + ) -> None: self.tool_name = tool_name self.args = args self.cwd = cwd @@ -471,7 +473,7 @@ def run_tool(*args: Any, **kwargs: Any) -> None: def run_target(target_name: str, args: 'PropertyDict', env: Optional[Dict]=None, - custom_error_handler: FunctionType=None, force_progression: bool=False, interactive: bool=False) -> None: + custom_error_handler: Optional[FunctionType]=None, force_progression: bool=False, interactive: bool=False) -> None: """Run target in build directory.""" if env is None: env = {} @@ -554,7 +556,7 @@ def _detect_cmake_generator(prog_name: str) -> Any: def ensure_build_directory(args: 'PropertyDict', prog_name: str, always_run_cmake: bool=False, - env: Dict=None) -> None: + env: Optional[Dict]=None) -> None: """Check the build directory exists and that cmake has been run there. If this isn't the case, create the build directory (if necessary) and @@ -671,7 +673,7 @@ def merge_action_lists(*action_lists: Dict) -> Dict: return merged_actions -def get_sdkconfig_filename(args: 'PropertyDict', cache_cmdl: Dict=None) -> str: +def get_sdkconfig_filename(args: 'PropertyDict', cache_cmdl: Optional[Dict]=None) -> str: """ Get project's sdkconfig file name. """ @@ -720,7 +722,7 @@ def is_target_supported(project_path: str, supported_targets: List) -> bool: def _check_idf_target(args: 'PropertyDict', prog_name: str, cache: Dict, - cache_cmdl: Dict, env: Dict=None) -> None: + cache_cmdl: Dict, env: Optional[Dict]=None) -> None: """ Cross-check the three settings (sdkconfig, CMakeCache, environment) and if there is mismatch, fail with instructions on how to fix this. From 8445486303845fce13317a762ae30a403074d5ef Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Mon, 20 May 2024 15:18:52 +0530 Subject: [PATCH 224/548] fix(soc): Cleanup inaccessible SHA registers from the header files --- .../soc/esp32c5/mp/include/soc/sha_reg.h | 144 -------------- .../soc/esp32c5/mp/include/soc/sha_struct.h | 177 +----------------- components/soc/esp32c61/include/soc/sha_reg.h | 144 -------------- .../soc/esp32c61/include/soc/sha_struct.h | 177 +----------------- 4 files changed, 2 insertions(+), 640 deletions(-) diff --git a/components/soc/esp32c5/mp/include/soc/sha_reg.h b/components/soc/esp32c5/mp/include/soc/sha_reg.h index d49c15e2671..ab9f346e774 100644 --- a/components/soc/esp32c5/mp/include/soc/sha_reg.h +++ b/components/soc/esp32c5/mp/include/soc/sha_reg.h @@ -172,150 +172,6 @@ extern "C" { #define SHA_M_MEM (DR_REG_SHA_BASE + 0x80) #define SHA_M_MEM_SIZE_BYTES 64 -/** SHA_3_MODE_REG register - * Initial configuration register 0. - */ -#define SHA_3_MODE_REG (DR_REG_SHA_BASE + 0x800) -/** SHA_3_MODE : R/W; bitpos: [2:0]; default: 0; - * Sha3 mode - */ -#define SHA_3_MODE 0x00000007U -#define SHA_3_MODE_M (SHA_3_MODE_V << SHA_3_MODE_S) -#define SHA_3_MODE_V 0x00000007U -#define SHA_3_MODE_S 0 - -/** SHA_3_CLEAN_M_REG register - * Initial configuration register 1. - */ -#define SHA_3_CLEAN_M_REG (DR_REG_SHA_BASE + 0x804) -/** SHA_3_CLEAN_M : WO; bitpos: [0]; default: 0; - * Clean Message. - */ -#define SHA_3_CLEAN_M (BIT(0)) -#define SHA_3_CLEAN_M_M (SHA_3_CLEAN_M_V << SHA_3_CLEAN_M_S) -#define SHA_3_CLEAN_M_V 0x00000001U -#define SHA_3_CLEAN_M_S 0 - -/** SHA_3_DMA_BLOCK_NUM_REG register - * DMA configuration register 0. - */ -#define SHA_3_DMA_BLOCK_NUM_REG (DR_REG_SHA_BASE + 0x80c) -/** SHA_3_DMA_BLOCK_NUM : R/W; bitpos: [5:0]; default: 0; - * DMA-SHA3 block number. - */ -#define SHA_3_DMA_BLOCK_NUM 0x0000003FU -#define SHA_3_DMA_BLOCK_NUM_M (SHA_3_DMA_BLOCK_NUM_V << SHA_3_DMA_BLOCK_NUM_S) -#define SHA_3_DMA_BLOCK_NUM_V 0x0000003FU -#define SHA_3_DMA_BLOCK_NUM_S 0 - -/** SHA_3_START_REG register - * Typical SHA3 configuration register 0. - */ -#define SHA_3_START_REG (DR_REG_SHA_BASE + 0x810) -/** SHA_3_START : WO; bitpos: [0]; default: 0; - * Start typical sha3. - */ -#define SHA_3_START (BIT(0)) -#define SHA_3_START_M (SHA_3_START_V << SHA_3_START_S) -#define SHA_3_START_V 0x00000001U -#define SHA_3_START_S 0 - -/** SHA_3_CONTINUE_REG register - * Typical SHA3 configuration register 1. - */ -#define SHA_3_CONTINUE_REG (DR_REG_SHA_BASE + 0x814) -/** SHA_3_CONTINUE : WO; bitpos: [0]; default: 0; - * Continue typical sha3. - */ -#define SHA_3_CONTINUE (BIT(0)) -#define SHA_3_CONTINUE_M (SHA_3_CONTINUE_V << SHA_3_CONTINUE_S) -#define SHA_3_CONTINUE_V 0x00000001U -#define SHA_3_CONTINUE_S 0 - -/** SHA_3_BUSY_REG register - * Busy register. - */ -#define SHA_3_BUSY_REG (DR_REG_SHA_BASE + 0x818) -/** SHA_3_BUSY_REG : RO; bitpos: [0]; default: 0; - * Sha3 busy state. 1'b0: idle. 1'b1: busy. - */ -#define SHA_3_BUSY_REG (BIT(0)) -#define SHA_3_BUSY_REG_M (SHA_3_BUSY_REG_V << SHA_3_BUSY_REG_S) -#define SHA_3_BUSY_REG_V 0x00000001U -#define SHA_3_BUSY_REG_S 0 - -/** SHA_3_DMA_START_REG register - * DMA configuration register 1. - */ -#define SHA_3_DMA_START_REG (DR_REG_SHA_BASE + 0x81c) -/** SHA_3_DMA_START : WO; bitpos: [0]; default: 0; - * Start dma-sha3. - */ -#define SHA_3_DMA_START (BIT(0)) -#define SHA_3_DMA_START_M (SHA_3_DMA_START_V << SHA_3_DMA_START_S) -#define SHA_3_DMA_START_V 0x00000001U -#define SHA_3_DMA_START_S 0 - -/** SHA_3_DMA_CONTINUE_REG register - * DMA configuration register 2. - */ -#define SHA_3_DMA_CONTINUE_REG (DR_REG_SHA_BASE + 0x820) -/** SHA_3_DMA_CONTINUE : WO; bitpos: [0]; default: 0; - * Continue dma-sha3. - */ -#define SHA_3_DMA_CONTINUE (BIT(0)) -#define SHA_3_DMA_CONTINUE_M (SHA_3_DMA_CONTINUE_V << SHA_3_DMA_CONTINUE_S) -#define SHA_3_DMA_CONTINUE_V 0x00000001U -#define SHA_3_DMA_CONTINUE_S 0 - -/** SHA_3_CLEAR_INT_REG register - * Interrupt clear register. - */ -#define SHA_3_CLEAR_INT_REG (DR_REG_SHA_BASE + 0x824) -/** SHA_3_CLEAR_INT : WO; bitpos: [0]; default: 0; - * Clear sha3 interrupt. - */ -#define SHA_3_CLEAR_INT (BIT(0)) -#define SHA_3_CLEAR_INT_M (SHA_3_CLEAR_INT_V << SHA_3_CLEAR_INT_S) -#define SHA_3_CLEAR_INT_V 0x00000001U -#define SHA_3_CLEAR_INT_S 0 - -/** SHA_3_INT_ENA_REG register - * Interrupt enable register. - */ -#define SHA_3_INT_ENA_REG (DR_REG_SHA_BASE + 0x828) -/** SHA_3_INT_ENA : R/W; bitpos: [0]; default: 0; - * Sha3 interrupt enable register. 1'b0: disable(default). 1'b1:enable - */ -#define SHA_3_INT_ENA (BIT(0)) -#define SHA_3_INT_ENA_M (SHA_3_INT_ENA_V << SHA_3_INT_ENA_S) -#define SHA_3_INT_ENA_V 0x00000001U -#define SHA_3_INT_ENA_S 0 - -/** SHA_3_SHAKE_LENGTH_REG register - * DMA configuration register 3. - */ -#define SHA_3_SHAKE_LENGTH_REG (DR_REG_SHA_BASE + 0x82c) -/** SHA_3_SHAKE_LENGTH : WO; bitpos: [10:0]; default: 50; - * SHAKE output hash word length - */ -#define SHA_3_SHAKE_LENGTH 0x000007FFU -#define SHA_3_SHAKE_LENGTH_M (SHA_3_SHAKE_LENGTH_V << SHA_3_SHAKE_LENGTH_S) -#define SHA_3_SHAKE_LENGTH_V 0x000007FFU -#define SHA_3_SHAKE_LENGTH_S 0 - -/** SHA_3_M_OUT_MEM register - * Sha3 hash reg which contains intermediate hash or finial hash. - */ -#define SHA_3_M_OUT_MEM (DR_REG_SHA_BASE + 0x900) -#define SHA_3_M_OUT_MEM_SIZE_BYTES 200 - -/** SHA_3_M_MEM register - * Sha3 message reg which contains message. - */ -#define SHA_3_M_MEM (DR_REG_SHA_BASE + 0xa00) -#define SHA_3_M_MEM_SIZE_BYTES 200 - #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/mp/include/soc/sha_struct.h b/components/soc/esp32c5/mp/include/soc/sha_struct.h index db2cb97f443..bc2cd2cef2c 100644 --- a/components/soc/esp32c5/mp/include/soc/sha_struct.h +++ b/components/soc/esp32c5/mp/include/soc/sha_struct.h @@ -127,118 +127,6 @@ typedef union { uint32_t val; } sha_t_length_reg_t; -/** Type of mode register - * Initial configuration register 0. - */ -typedef union { - struct { - /** mode : R/W; bitpos: [2:0]; default: 0; - * Sha3 mode - */ - uint32_t mode:3; - uint32_t reserved_3:29; - }; - uint32_t val; -} sha_3_mode_reg_t; - -/** Type of clean_m register - * Initial configuration register 1. - */ -typedef union { - struct { - /** clean_m : WO; bitpos: [0]; default: 0; - * Clean Message. - */ - uint32_t clean_m:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_clean_m_reg_t; - -/** Type of dma_block_num register - * DMA configuration register 0. - */ -typedef union { - struct { - /** dma_block_num : R/W; bitpos: [5:0]; default: 0; - * DMA-SHA3 block number. - */ - uint32_t dma_block_num:6; - uint32_t reserved_6:26; - }; - uint32_t val; -} sha_3_dma_block_num_reg_t; - -/** Type of start register - * Typical SHA3 configuration register 0. - */ -typedef union { - struct { - /** start : WO; bitpos: [0]; default: 0; - * Start typical sha3. - */ - uint32_t start:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_start_reg_t; - -/** Type of continue register - * Typical SHA3 configuration register 1. - */ -typedef union { - struct { - /** conti : WO; bitpos: [0]; default: 0; - * Continue typical sha3. - */ - uint32_t conti:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_continue_reg_t; - -/** Type of dma_start register - * DMA configuration register 1. - */ -typedef union { - struct { - /** dma_start : WO; bitpos: [0]; default: 0; - * Start dma-sha3. - */ - uint32_t dma_start:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_dma_start_reg_t; - -/** Type of dma_continue register - * DMA configuration register 2. - */ -typedef union { - struct { - /** dma_continue : WO; bitpos: [0]; default: 0; - * Continue dma-sha3. - */ - uint32_t dma_continue:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_dma_continue_reg_t; - -/** Type of shake_length register - * DMA configuration register 3. - */ -typedef union { - struct { - /** shake_length : WO; bitpos: [10:0]; default: 50; - * SHAKE output hash word length - */ - uint32_t shake_length:11; - uint32_t reserved_11:21; - }; - uint32_t val; -} sha_3_shake_length_reg_t; - /** Group: Status Registers */ /** Type of busy register @@ -306,52 +194,6 @@ typedef union { /** Group: memory type */ -/** Group: Status Register */ -/** Type of busy register - * Busy register. - */ -typedef union { - struct { - /** busy_reg : RO; bitpos: [0]; default: 0; - * Sha3 busy state. 1'b0: idle. 1'b1: busy. - */ - uint32_t busy_reg:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_busy_reg_t; - - -/** Group: Interrupt Register */ -/** Type of clear_int register - * Interrupt clear register. - */ -typedef union { - struct { - /** clear_int : WO; bitpos: [0]; default: 0; - * Clear sha3 interrupt. - */ - uint32_t clear_int:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_clear_int_reg_t; - -/** Type of int_ena register - * Interrupt enable register. - */ -typedef union { - struct { - /** int_ena : R/W; bitpos: [0]; default: 0; - * Sha3 interrupt enable register. 1'b0: disable(default). 1'b1:enable - */ - uint32_t int_ena:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_int_ena_reg_t; - - typedef struct { volatile sha_mode_reg_t mode; volatile sha_t_string_reg_t t_string; @@ -368,29 +210,12 @@ typedef struct { uint32_t reserved_030[4]; volatile uint32_t h[16]; volatile uint32_t m[16]; - uint32_t reserved_0c0[464]; - volatile sha_3_mode_reg_t mode_3; - volatile sha_3_clean_m_reg_t clean_m_3; - uint32_t reserved_808; - volatile sha_3_dma_block_num_reg_t dma_block_num_3; - volatile sha_3_start_reg_t start_3; - volatile sha_3_continue_reg_t continue_3; - volatile sha_3_busy_reg_t busy_3; - volatile sha_3_dma_start_reg_t dma_start_3; - volatile sha_3_dma_continue_reg_t dma_continue_3; - volatile sha_3_clear_int_reg_t clear_int_3; - volatile sha_3_int_ena_reg_t int_ena_3; - volatile sha_3_shake_length_reg_t shake_length_3; - uint32_t reserved_830[52]; - volatile uint32_t m_out_3[50]; - uint32_t reserved_9c8[14]; - volatile uint32_t m_3[50]; } sha_dev_t; extern sha_dev_t SHA; #ifndef __cplusplus -_Static_assert(sizeof(sha_dev_t) == 0xac8, "Invalid size of sha_dev_t structure"); +_Static_assert(sizeof(sha_dev_t) == 0xc0, "Invalid size of sha_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32c61/include/soc/sha_reg.h b/components/soc/esp32c61/include/soc/sha_reg.h index d49c15e2671..ab9f346e774 100644 --- a/components/soc/esp32c61/include/soc/sha_reg.h +++ b/components/soc/esp32c61/include/soc/sha_reg.h @@ -172,150 +172,6 @@ extern "C" { #define SHA_M_MEM (DR_REG_SHA_BASE + 0x80) #define SHA_M_MEM_SIZE_BYTES 64 -/** SHA_3_MODE_REG register - * Initial configuration register 0. - */ -#define SHA_3_MODE_REG (DR_REG_SHA_BASE + 0x800) -/** SHA_3_MODE : R/W; bitpos: [2:0]; default: 0; - * Sha3 mode - */ -#define SHA_3_MODE 0x00000007U -#define SHA_3_MODE_M (SHA_3_MODE_V << SHA_3_MODE_S) -#define SHA_3_MODE_V 0x00000007U -#define SHA_3_MODE_S 0 - -/** SHA_3_CLEAN_M_REG register - * Initial configuration register 1. - */ -#define SHA_3_CLEAN_M_REG (DR_REG_SHA_BASE + 0x804) -/** SHA_3_CLEAN_M : WO; bitpos: [0]; default: 0; - * Clean Message. - */ -#define SHA_3_CLEAN_M (BIT(0)) -#define SHA_3_CLEAN_M_M (SHA_3_CLEAN_M_V << SHA_3_CLEAN_M_S) -#define SHA_3_CLEAN_M_V 0x00000001U -#define SHA_3_CLEAN_M_S 0 - -/** SHA_3_DMA_BLOCK_NUM_REG register - * DMA configuration register 0. - */ -#define SHA_3_DMA_BLOCK_NUM_REG (DR_REG_SHA_BASE + 0x80c) -/** SHA_3_DMA_BLOCK_NUM : R/W; bitpos: [5:0]; default: 0; - * DMA-SHA3 block number. - */ -#define SHA_3_DMA_BLOCK_NUM 0x0000003FU -#define SHA_3_DMA_BLOCK_NUM_M (SHA_3_DMA_BLOCK_NUM_V << SHA_3_DMA_BLOCK_NUM_S) -#define SHA_3_DMA_BLOCK_NUM_V 0x0000003FU -#define SHA_3_DMA_BLOCK_NUM_S 0 - -/** SHA_3_START_REG register - * Typical SHA3 configuration register 0. - */ -#define SHA_3_START_REG (DR_REG_SHA_BASE + 0x810) -/** SHA_3_START : WO; bitpos: [0]; default: 0; - * Start typical sha3. - */ -#define SHA_3_START (BIT(0)) -#define SHA_3_START_M (SHA_3_START_V << SHA_3_START_S) -#define SHA_3_START_V 0x00000001U -#define SHA_3_START_S 0 - -/** SHA_3_CONTINUE_REG register - * Typical SHA3 configuration register 1. - */ -#define SHA_3_CONTINUE_REG (DR_REG_SHA_BASE + 0x814) -/** SHA_3_CONTINUE : WO; bitpos: [0]; default: 0; - * Continue typical sha3. - */ -#define SHA_3_CONTINUE (BIT(0)) -#define SHA_3_CONTINUE_M (SHA_3_CONTINUE_V << SHA_3_CONTINUE_S) -#define SHA_3_CONTINUE_V 0x00000001U -#define SHA_3_CONTINUE_S 0 - -/** SHA_3_BUSY_REG register - * Busy register. - */ -#define SHA_3_BUSY_REG (DR_REG_SHA_BASE + 0x818) -/** SHA_3_BUSY_REG : RO; bitpos: [0]; default: 0; - * Sha3 busy state. 1'b0: idle. 1'b1: busy. - */ -#define SHA_3_BUSY_REG (BIT(0)) -#define SHA_3_BUSY_REG_M (SHA_3_BUSY_REG_V << SHA_3_BUSY_REG_S) -#define SHA_3_BUSY_REG_V 0x00000001U -#define SHA_3_BUSY_REG_S 0 - -/** SHA_3_DMA_START_REG register - * DMA configuration register 1. - */ -#define SHA_3_DMA_START_REG (DR_REG_SHA_BASE + 0x81c) -/** SHA_3_DMA_START : WO; bitpos: [0]; default: 0; - * Start dma-sha3. - */ -#define SHA_3_DMA_START (BIT(0)) -#define SHA_3_DMA_START_M (SHA_3_DMA_START_V << SHA_3_DMA_START_S) -#define SHA_3_DMA_START_V 0x00000001U -#define SHA_3_DMA_START_S 0 - -/** SHA_3_DMA_CONTINUE_REG register - * DMA configuration register 2. - */ -#define SHA_3_DMA_CONTINUE_REG (DR_REG_SHA_BASE + 0x820) -/** SHA_3_DMA_CONTINUE : WO; bitpos: [0]; default: 0; - * Continue dma-sha3. - */ -#define SHA_3_DMA_CONTINUE (BIT(0)) -#define SHA_3_DMA_CONTINUE_M (SHA_3_DMA_CONTINUE_V << SHA_3_DMA_CONTINUE_S) -#define SHA_3_DMA_CONTINUE_V 0x00000001U -#define SHA_3_DMA_CONTINUE_S 0 - -/** SHA_3_CLEAR_INT_REG register - * Interrupt clear register. - */ -#define SHA_3_CLEAR_INT_REG (DR_REG_SHA_BASE + 0x824) -/** SHA_3_CLEAR_INT : WO; bitpos: [0]; default: 0; - * Clear sha3 interrupt. - */ -#define SHA_3_CLEAR_INT (BIT(0)) -#define SHA_3_CLEAR_INT_M (SHA_3_CLEAR_INT_V << SHA_3_CLEAR_INT_S) -#define SHA_3_CLEAR_INT_V 0x00000001U -#define SHA_3_CLEAR_INT_S 0 - -/** SHA_3_INT_ENA_REG register - * Interrupt enable register. - */ -#define SHA_3_INT_ENA_REG (DR_REG_SHA_BASE + 0x828) -/** SHA_3_INT_ENA : R/W; bitpos: [0]; default: 0; - * Sha3 interrupt enable register. 1'b0: disable(default). 1'b1:enable - */ -#define SHA_3_INT_ENA (BIT(0)) -#define SHA_3_INT_ENA_M (SHA_3_INT_ENA_V << SHA_3_INT_ENA_S) -#define SHA_3_INT_ENA_V 0x00000001U -#define SHA_3_INT_ENA_S 0 - -/** SHA_3_SHAKE_LENGTH_REG register - * DMA configuration register 3. - */ -#define SHA_3_SHAKE_LENGTH_REG (DR_REG_SHA_BASE + 0x82c) -/** SHA_3_SHAKE_LENGTH : WO; bitpos: [10:0]; default: 50; - * SHAKE output hash word length - */ -#define SHA_3_SHAKE_LENGTH 0x000007FFU -#define SHA_3_SHAKE_LENGTH_M (SHA_3_SHAKE_LENGTH_V << SHA_3_SHAKE_LENGTH_S) -#define SHA_3_SHAKE_LENGTH_V 0x000007FFU -#define SHA_3_SHAKE_LENGTH_S 0 - -/** SHA_3_M_OUT_MEM register - * Sha3 hash reg which contains intermediate hash or finial hash. - */ -#define SHA_3_M_OUT_MEM (DR_REG_SHA_BASE + 0x900) -#define SHA_3_M_OUT_MEM_SIZE_BYTES 200 - -/** SHA_3_M_MEM register - * Sha3 message reg which contains message. - */ -#define SHA_3_M_MEM (DR_REG_SHA_BASE + 0xa00) -#define SHA_3_M_MEM_SIZE_BYTES 200 - #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c61/include/soc/sha_struct.h b/components/soc/esp32c61/include/soc/sha_struct.h index a297423e8f1..058b8a88f61 100644 --- a/components/soc/esp32c61/include/soc/sha_struct.h +++ b/components/soc/esp32c61/include/soc/sha_struct.h @@ -127,118 +127,6 @@ typedef union { uint32_t val; } sha_t_length_reg_t; -/** Type of mode_3 register - * Initial configuration register 0. - */ -typedef union { - struct { - /** mode_3 : R/W; bitpos: [2:0]; default: 0; - * Sha3 mode - */ - uint32_t mode_3:3; - uint32_t reserved_3:29; - }; - uint32_t val; -} sha_3_mode_reg_t; - -/** Type of clean_m_3 register - * Initial configuration register 1. - */ -typedef union { - struct { - /** clean_m_3 : WO; bitpos: [0]; default: 0; - * Clean Message. - */ - uint32_t clean_m_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_clean_m_reg_t; - -/** Type of dma_block_num_3 register - * DMA configuration register 0. - */ -typedef union { - struct { - /** dma_block_num_3 : R/W; bitpos: [5:0]; default: 0; - * DMA-SHA3 block number. - */ - uint32_t dma_block_num_3:6; - uint32_t reserved_6:26; - }; - uint32_t val; -} sha_3_dma_block_num_reg_t; - -/** Type of start_3 register - * Typical SHA3 configuration register 0. - */ -typedef union { - struct { - /** start_3 : WO; bitpos: [0]; default: 0; - * Start typical sha3. - */ - uint32_t start_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_start_reg_t; - -/** Type of continue_3 register - * Typical SHA3 configuration register 1. - */ -typedef union { - struct { - /** continue_3 : WO; bitpos: [0]; default: 0; - * Continue typical sha3. - */ - uint32_t continue_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_continue_reg_t; - -/** Type of dma_start_3 register - * DMA configuration register 1. - */ -typedef union { - struct { - /** dma_start_3 : WO; bitpos: [0]; default: 0; - * Start dma-sha3. - */ - uint32_t dma_start_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_dma_start_reg_t; - -/** Type of dma_continue_3 register - * DMA configuration register 2. - */ -typedef union { - struct { - /** dma_continue_3 : WO; bitpos: [0]; default: 0; - * Continue dma-sha3. - */ - uint32_t dma_continue_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_dma_continue_reg_t; - -/** Type of shake_length_3 register - * DMA configuration register 3. - */ -typedef union { - struct { - /** shake_length_3 : WO; bitpos: [10:0]; default: 50; - * SHAKE output hash word length - */ - uint32_t shake_length_3:11; - uint32_t reserved_11:21; - }; - uint32_t val; -} sha_3_shake_length_reg_t; - /** Group: Status Registers */ /** Type of busy register @@ -306,52 +194,6 @@ typedef union { /** Group: memory type */ -/** Group: Status Register */ -/** Type of busy_3 register - * Busy register. - */ -typedef union { - struct { - /** busy_reg_3 : RO; bitpos: [0]; default: 0; - * Sha3 busy state. 1'b0: idle. 1'b1: busy. - */ - uint32_t busy_reg_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_busy_reg_t; - - -/** Group: Interrupt Register */ -/** Type of clear_int_3 register - * Interrupt clear register. - */ -typedef union { - struct { - /** clear_int_3 : WO; bitpos: [0]; default: 0; - * Clear sha3 interrupt. - */ - uint32_t clear_int_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_clear_int_reg_t; - -/** Type of int_ena_3 register - * Interrupt enable register. - */ -typedef union { - struct { - /** int_ena_3 : R/W; bitpos: [0]; default: 0; - * Sha3 interrupt enable register. 1'b0: disable(default). 1'b1:enable - */ - uint32_t int_ena_3:1; - uint32_t reserved_1:31; - }; - uint32_t val; -} sha_3_int_ena_reg_t; - - typedef struct { volatile sha_mode_reg_t mode; volatile sha_t_string_reg_t t_string; @@ -368,29 +210,12 @@ typedef struct { uint32_t reserved_030[4]; volatile uint32_t h[16]; volatile uint32_t m[16]; - uint32_t reserved_0c0[464]; - volatile sha_3_mode_reg_t mode_3; - volatile sha_3_clean_m_reg_t clean_m_3; - uint32_t reserved_808; - volatile sha_3_dma_block_num_reg_t dma_block_num_3; - volatile sha_3_start_reg_t start_3; - volatile sha_3_continue_reg_t continue_3; - volatile sha_3_busy_reg_t busy_3; - volatile sha_3_dma_start_reg_t dma_start_3; - volatile sha_3_dma_continue_reg_t dma_continue_3; - volatile sha_3_clear_int_reg_t clear_int_3; - volatile sha_3_int_ena_reg_t int_ena_3; - volatile sha_3_shake_length_reg_t shake_length_3; - uint32_t reserved_830[52]; - volatile uint32_t m_out_3[50]; - uint32_t reserved_9c8[14]; - volatile uint32_t m_3[50]; } sha_dev_t; extern sha_dev_t SHA; #ifndef __cplusplus -_Static_assert(sizeof(sha_dev_t) == 0xac8, "Invalid size of sha_dev_t structure"); +_Static_assert(sizeof(sha_dev_t) == 0xc0, "Invalid size of sha_dev_t structure"); #endif #ifdef __cplusplus From 32a2ddceaa421ecc8977736ebbd859668d40de83 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 11 Jun 2024 17:43:32 +0530 Subject: [PATCH 225/548] fix(nimble): Added change to handle extra memory for ext adv reattempt --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 794fb12e75b..a1f5999ee87 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 794fb12e75b91e9cc938acf834ad2abd57c31190 +Subproject commit a1f5999ee87d73c1d71e1e90991fafde4a951ec3 From 39d0f4b650d62e7ebc4a4618097c362adcfd5e44 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 31 May 2024 18:32:18 +0800 Subject: [PATCH 226/548] feat(ppa): add test cases to test PPA data correctness --- .../test_apps/main/CMakeLists.txt | 2 +- .../esp_driver_ppa/test_apps/main/test_ppa.c | 349 +++++++++++++++++- 2 files changed, 331 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_ppa/test_apps/main/CMakeLists.txt b/components/esp_driver_ppa/test_apps/main/CMakeLists.txt index 25e36806850..5988460a63c 100644 --- a/components/esp_driver_ppa/test_apps/main/CMakeLists.txt +++ b/components/esp_driver_ppa/test_apps/main/CMakeLists.txt @@ -5,5 +5,5 @@ set(srcs "test_app_main.c" # the component can be registered as WHOLE_ARCHIVE idf_component_register(SRCS ${srcs} INCLUDE_DIRS "." - PRIV_REQUIRES esp_driver_ppa esp_psram unity + PRIV_REQUIRES esp_driver_ppa esp_psram unity esp_mm WHOLE_ARCHIVE) diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c index 0dd676c6648..b1ce9891415 100644 --- a/components/esp_driver_ppa/test_apps/main/test_ppa.c +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -16,6 +16,7 @@ #include "esp_err.h" #include "ccomp_timer.h" #include "hal/color_hal.h" +#include "esp_cache.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -35,9 +36,9 @@ TEST_CASE("ppa_client_do_ppa_operation", "[PPA]") uint32_t buf_1_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8, 64); uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64); - uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *buf_1 = heap_caps_aligned_calloc(4, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); // cache alignment is implicited by MALLOC_CAP_DMA TEST_ASSERT_NOT_NULL(buf_1); - uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *buf_2 = heap_caps_aligned_calloc(4, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(buf_2); // Register different types of PPA clients @@ -167,7 +168,7 @@ TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]") const uint32_t w = 1920; const uint32_t h = 1080; const uint32_t buf_1_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); - const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888); + const uint32_t buf_2_color_type_id = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420); color_space_pixel_format_t buf_1_cm = { .color_type_id = buf_1_color_type_id, @@ -178,9 +179,9 @@ TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]") uint32_t buf_1_size = w * h * color_hal_pixel_format_get_bit_depth(buf_1_cm) / 8; uint32_t buf_2_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(buf_2_cm) / 8, 64); - uint8_t *buf_1 = heap_caps_aligned_calloc(64, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *buf_1 = heap_caps_aligned_calloc(4, buf_1_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(buf_1); - uint8_t *buf_2 = heap_caps_aligned_calloc(64, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *buf_2 = heap_caps_aligned_calloc(4, buf_2_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(buf_2); // Register two PPA SRM clients with different max_pending_trans_num @@ -261,14 +262,304 @@ TEST_CASE("ppa_pending_transactions_in_queue", "[PPA]") free(buf_2); } -TEST_CASE("ppa_srm_performance", "[PPA][ignore]") +TEST_CASE("ppa_srm_basic_data_correctness_check", "[PPA]") +{ + const uint32_t w = 4; + const uint32_t h = 4; + const uint32_t block_w = 3; + const uint32_t block_h = 3; + const uint32_t in_block_offset_x = 1; + const uint32_t in_block_offset_y = 1; + const uint32_t out_block_offset_x = 1; + const uint32_t out_block_offset_y = 0; + const ppa_srm_color_mode_t cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_90; // CCW + const float scale_x = 1.0; + const float scale_y = 1.0; + + color_space_pixel_format_t buf_cm = { + .color_type_id = cm, + }; + const uint32_t buf_len = w * h * color_hal_pixel_format_get_bit_depth(buf_cm) / 8; // 32 + uint32_t out_buf_size = ALIGN_UP(buf_len, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(out_buf); + esp_cache_msync((void *)out_buf, out_buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + const uint16_t in_buf[16] = { + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + // /*******************************/ + 0xFFFF, /**/ 0x8080, 0x8080, 0x8080, /**/ + 0xFFFF, /**/ 0x8F80, 0x8F80, 0x8F80, /**/ + 0xFFFF, /**/ 0xFF80, 0xFF80, 0xFF80, /**/ + // /*******************************/ + }; + // Expected SRM output + const uint16_t out_buf_expected[16] = { + // /*******************************/ + 0x0000, /**/ 0x8080, 0x8F80, 0xFF80, /**/ + 0x0000, /**/ 0x8080, 0x8F80, 0xFF80, /**/ + 0x0000, /**/ 0x8080, 0x8F80, 0xFF80, /**/ + // /*******************************/ + 0x0000, 0x0000, 0x0000, 0x0000 + }; + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + ppa_srm_oper_config_t oper_config = { + .in.buffer = in_buf, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = block_w, + .in.block_h = block_h, + .in.block_offset_x = in_block_offset_x, + .in.block_offset_y = in_block_offset_y, + .in.srm_cm = cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = out_block_offset_x, + .out.block_offset_y = out_block_offset_y, + .out.srm_cm = cm, + + .rotation_angle = rotation, + .scale_x = scale_x, + .scale_y = scale_y, + + .rgb_swap = 0, + .byte_swap = 0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); + + // Check result + for (int i = 0; i < buf_len; i++) { + if (i % 8 == 0) { + printf("\n"); + } + printf("0x%02X ", out_buf[i]); + } + printf("\n"); + TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, buf_len); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(out_buf); +} + +TEST_CASE("ppa_blend_basic_data_correctness_check", "[PPA]") { + const uint32_t w = 2; + const uint32_t h = 2; + const uint32_t block_w = 1; + const uint32_t block_h = 1; + const uint32_t block_offset_x = 1; + const uint32_t block_offset_y = 1; + const ppa_blend_color_mode_t in_bg_cm = PPA_BLEND_COLOR_MODE_RGB888; + const ppa_blend_color_mode_t in_fg_cm = PPA_BLEND_COLOR_MODE_ARGB8888; + const ppa_blend_color_mode_t out_cm = PPA_BLEND_COLOR_MODE_ARGB8888; + + color_space_pixel_format_t bg_buf_cm = { + .color_type_id = in_bg_cm, + }; + const uint32_t bg_buf_len __attribute__((unused)) = w * h * color_hal_pixel_format_get_bit_depth(bg_buf_cm) / 8; // 12 + color_space_pixel_format_t fg_buf_cm = { + .color_type_id = in_fg_cm, + }; + const uint32_t fg_buf_len __attribute__((unused)) = w * h * color_hal_pixel_format_get_bit_depth(fg_buf_cm) / 8; // 16 + const uint32_t out_buf_len = fg_buf_len; // 16 + // We will make the output write to the in_fg_buffer, therefore, it has cache line alignment requirement + const uint32_t out_buf_size = 64; + + // Alpha of BG will be scaled by 0.8 + // Alpha of FG will be inverted + const float bg_alpha_scale_ratio = 0.8; + const uint8_t in_bg_buf[12] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // /*************************/ + 0xFF, 0xFF, 0xFF, /**/ 0x80, 0x40, 0xA0, /**/ + // /*************************/ + }; + uint8_t in_fg_buf[64] __attribute__((aligned(64))) = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // /*******************************/ + 0xFF, 0xFF, 0xFF, 0xFF, /**/ 0x00, 0x80, 0x80, 0xC0, /**/ + // /* (B) (G) (R) (A) */ + // /*******************************/ + [16 ... 63] = 0, + }; + uint8_t *out_buf = in_fg_buf; + // Expected blend output + // Alpha Blending calculation: + // A_bg' = (255 * 0.8) / 255 = 0.8, A_fg' = (255 - 0xC0) / 255 = 0.247 + // A_out = 0.8 + 0.247 - 0.8 * 0.247 = 0.849 (216 -> 0xD8) + // C_out_b = (0x80 * 0.8 * (1 - 0.247) + 0x00 * 0.247) / 0.849 = 91 -> 0x5B + // C_out_g = (0x40 * 0.8 * (1 - 0.247) + 0x80 * 0.247) / 0.849 = 83 -> 0x53 + // C_out_g = (0xA0 * 0.8 * (1 - 0.247) + 0x80 * 0.247) / 0.849 = 150 -> 0x96 + const uint8_t out_buf_expected[16] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // /*******************************/ + 0xFF, 0xFF, 0xFF, 0xFF, /**/ 0x5B, 0x53, 0x96, 0xD8, /**/ + // /*******************************/ + }; + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_BLEND, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + ppa_blend_oper_config_t oper_config = { + .in_bg.buffer = in_bg_buf, + .in_bg.pic_w = w, + .in_bg.pic_h = h, + .in_bg.block_w = block_w, + .in_bg.block_h = block_h, + .in_bg.block_offset_x = block_offset_x, + .in_bg.block_offset_y = block_offset_y, + .in_bg.blend_cm = in_bg_cm, + + .in_fg.buffer = in_fg_buf, + .in_fg.pic_w = w, + .in_fg.pic_h = h, + .in_fg.block_w = block_w, + .in_fg.block_h = block_h, + .in_fg.block_offset_x = block_offset_x, + .in_fg.block_offset_y = block_offset_y, + .in_fg.blend_cm = in_fg_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = block_offset_x, + .out.block_offset_y = block_offset_y, + .out.blend_cm = out_cm, + + .bg_alpha_update_mode = PPA_ALPHA_SCALE, + .bg_alpha_scale_ratio = bg_alpha_scale_ratio, + + .fg_alpha_update_mode = PPA_ALPHA_INVERT, + + .bg_ck_en = false, + .fg_ck_en = false, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config)); + + // Check result + for (int i = 0; i < out_buf_len; i++) { + if (i % 8 == 0) { + printf("\n"); + } + printf("0x%02X ", out_buf[i]); + } + printf("\n"); + TEST_ASSERT_EQUAL_UINT8_ARRAY((void *)out_buf_expected, (void *)out_buf, out_buf_len); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); +} + +TEST_CASE("ppa_fill_basic_data_correctness_check", "[PPA]") +{ + const uint32_t w = 80; + const uint32_t h = 120; + const uint32_t block_w = 80; + const uint32_t block_h = 80; + const uint32_t block_offset_x = 0; + const uint32_t block_offset_y = 40; + const ppa_fill_color_mode_t out_cm = PPA_FILL_COLOR_MODE_RGB565; + const color_pixel_argb8888_data_t fill_color = {.a = 0x80, .r = 0xFF, .g = 0x55, .b = 0xAA}; + + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); // bits + uint32_t out_buf_len = w * h * out_pixel_depth / 8; + uint32_t out_buf_size = ALIGN_UP(out_buf_len, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(out_buf); + + memset(out_buf, 0xFF, out_buf_len); + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_FILL, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + ppa_fill_oper_config_t oper_config = { + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = w, + .out.pic_h = h, + .out.block_offset_x = block_offset_x, + .out.block_offset_y = block_offset_y, + .out.fill_cm = out_cm, + + .fill_block_w = block_w, + .fill_block_h = block_h, + .fill_argb_color = fill_color, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config)); + + // Check result + const color_pixel_rgb565_data_t fill_pixel_expected = {.r = fill_color.r >> 3, + .g = fill_color.g >> 2, + .b = fill_color.b >> 3, + }; + TEST_ASSERT_EACH_EQUAL_UINT16(fill_pixel_expected.val, (void *)((uint32_t)out_buf + w * block_offset_y * out_pixel_depth / 8), block_w * block_h); + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(out_buf); +} + +/* All performance tests are tested under the following situations: + * - Testing PPA speed where in_buffer(s) and out_buffer all located in PSRAM + * - Only 2D-DMA is using PSRAM + * - 2D-DMA burst length is at maximum 128B + * - Input and output color mode is ARGB8888 (maximizing 2D-DMA data transafer amount) + * + * The time spend (T) to complete a PPA transaction is proportional to the amount of pixels (x) need to be processed. + * T = k * x + b + * k = (T - b) / x + */ + +#define PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC (21000 * 1000) // k_min +#define PPA_SRM_TIME_OFFSET (-26000) // b_approx + +#define PPA_BLEND_MIN_PERFORMANCE_PX_PER_SEC (31500 * 1000) // k_min +#define PPA_BLEND_TIME_OFFSET (-37150) // b_approx + +#define PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC (150000 * 1000) // k_min +#define PPA_FILL_TIME_OFFSET (-106000) // b_approx + +TEST_CASE("ppa_srm_performance", "[PPA]") +{ + // Configurable parameters const uint32_t w = 1920; // 1920 / 1280 / 800 / 640 const uint32_t h = 1080; // 1080 / 720 / 480 const uint32_t block_w = w; const uint32_t block_h = h; const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_ARGB8888; - const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_YUV420; + const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_ARGB8888; const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0; const float scale_x = 1.0; const float scale_y = 1.0; @@ -282,9 +573,9 @@ TEST_CASE("ppa_srm_performance", "[PPA][ignore]") uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8; uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); - uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(out_buf); - uint8_t *in_buf = heap_caps_aligned_calloc(64, in_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *in_buf = heap_caps_aligned_calloc(4, in_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(in_buf); uint8_t *ptr = in_buf; @@ -333,8 +624,14 @@ TEST_CASE("ppa_srm_performance", "[PPA][ignore]") TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); - int64_t oper_time = ccomp_timer_stop(); - printf("Time passed: %lld us\n", oper_time); + int64_t oper_time = ccomp_timer_stop(); // us + printf("PPA SRM - Process Time: %lld us\n", oper_time); + + // Check performance + uint64_t num_pixels_processed = block_w * block_h; + uint64_t px_per_second = (num_pixels_processed - PPA_SRM_TIME_OFFSET) * 1000 * 1000 / oper_time; + printf("PPA SRM performance = %lld pixels/sec\n", px_per_second); + TEST_ASSERT_GREATER_THAN(PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC, px_per_second); TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); @@ -342,8 +639,9 @@ TEST_CASE("ppa_srm_performance", "[PPA][ignore]") free(out_buf); } -TEST_CASE("ppa_blend_performance", "[PPA][ignore]") +TEST_CASE("ppa_blend_performance", "[PPA]") { + // Configurable parameters const uint32_t w = 1280; const uint32_t h = 720; const uint32_t block_w = w; @@ -365,11 +663,11 @@ TEST_CASE("ppa_blend_performance", "[PPA][ignore]") uint32_t in_bg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_bg_pixel_format) / 8; uint32_t in_fg_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_fg_pixel_format) / 8; uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); - uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(out_buf); - uint8_t *in_bg_buf = heap_caps_aligned_calloc(64, in_bg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *in_bg_buf = heap_caps_aligned_calloc(4, in_bg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(in_bg_buf); - uint8_t *in_fg_buf = heap_caps_aligned_calloc(64, in_fg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *in_fg_buf = heap_caps_aligned_calloc(4, in_fg_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(in_fg_buf); uint8_t *ptr = in_bg_buf; @@ -426,7 +724,13 @@ TEST_CASE("ppa_blend_performance", "[PPA][ignore]") TEST_ESP_OK(ppa_do_blend(ppa_client_handle, &oper_config)); int64_t oper_time = ccomp_timer_stop(); - printf("Time passed: %lld us\n", oper_time); + printf("PPA Blend - Process Time: %lld us\n", oper_time); + + // Check performance + uint64_t num_pixels_processed = block_w * block_h; + uint64_t px_per_second = (num_pixels_processed - PPA_BLEND_TIME_OFFSET) * 1000 * 1000 / oper_time; + printf("PPA Blend performance = %lld pixels/sec\n", px_per_second); + TEST_ASSERT_GREATER_THAN(PPA_BLEND_MIN_PERFORMANCE_PX_PER_SEC, px_per_second); TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); @@ -435,8 +739,9 @@ TEST_CASE("ppa_blend_performance", "[PPA][ignore]") free(out_buf); } -TEST_CASE("ppa_fill_performance", "[PPA][ignore]") +TEST_CASE("ppa_fill_performance", "[PPA]") { + // Configurable parameters const uint32_t w = 1280; const uint32_t h = 720; const uint32_t block_w = 800; @@ -448,7 +753,7 @@ TEST_CASE("ppa_fill_performance", "[PPA][ignore]") }; uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); - uint8_t *out_buf = heap_caps_aligned_calloc(64, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(out_buf); ppa_client_handle_t ppa_client_handle; @@ -481,7 +786,13 @@ TEST_CASE("ppa_fill_performance", "[PPA][ignore]") TEST_ESP_OK(ppa_do_fill(ppa_client_handle, &oper_config)); int64_t oper_time = ccomp_timer_stop(); - printf("Time passed: %lld us\n", oper_time); + printf("PPA Fill - Process Time: %lld us\n", oper_time); + + // Check performance + uint64_t num_pixels_processed = block_w * block_h; + uint64_t px_per_second = (num_pixels_processed - PPA_FILL_TIME_OFFSET) * 1000 * 1000 / oper_time; + printf("PPA Blend performance = %lld pixels/sec\n", px_per_second); + TEST_ASSERT_GREATER_THAN(PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC, px_per_second); TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); From 8ae12473b5f700c927ae1c0327b611e32e91d9bd Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 3 Jun 2024 15:57:49 +0800 Subject: [PATCH 227/548] refactor(i2s): clean up DMA buffer allocation --- components/driver/deprecated/i2s_legacy.c | 14 ++++---------- components/esp_driver_i2s/i2s_common.c | 19 +++++-------------- components/esp_driver_i2s/i2s_private.h | 2 +- components/esp_driver_parlio/src/parlio_rx.c | 1 - .../test_apps/parlio/main/test_parlio_rx.c | 1 - .../esp_probe/hw_impl/esp_probe_impl_parlio.c | 1 - 6 files changed, 10 insertions(+), 28 deletions(-) diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index a7d26760a78..352e1f03f9e 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -61,7 +61,6 @@ #include "esp_pm.h" #include "esp_efuse.h" #include "esp_rom_gpio.h" -#include "esp_dma_utils.h" #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" @@ -580,22 +579,17 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) ESP_GOTO_ON_FALSE(dma_obj, ESP_ERR_INVALID_ARG, err, TAG, "I2S DMA object can't be NULL"); uint32_t buf_cnt = p_i2s[i2s_num]->dma_desc_num; - size_t desc_size = 0; for (int cnt = 0; cnt < buf_cnt; cnt++) { /* Allocate DMA buffer */ - esp_dma_mem_info_t dma_mem_info = { - .extra_heap_caps = MALLOC_CAP_INTERNAL, - .dma_alignment_bytes = 4, - }; - //TODO: IDF-9636 - esp_dma_capable_calloc(1, sizeof(char) * dma_obj->buf_size, &dma_mem_info, (void **)&dma_obj->buf[cnt], NULL); + dma_obj->buf[cnt] = heap_caps_aligned_calloc(4, 1, sizeof(char) * dma_obj->buf_size, + MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer"); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE esp_cache_msync(dma_obj->buf[cnt], dma_obj->buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); #endif /* Allocate DMA descriptor */ - esp_dma_capable_calloc(1, sizeof(lldesc_t), &dma_mem_info, (void **)&dma_obj->desc[cnt], &desc_size); + dma_obj->desc[cnt] = heap_caps_aligned_calloc(4, 1, sizeof(lldesc_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry"); } /* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */ @@ -611,7 +605,7 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) /* Link to the next descriptor */ dma_obj->desc[cnt]->empty = (uint32_t)((cnt < (buf_cnt - 1)) ? (dma_obj->desc[cnt + 1]) : dma_obj->desc[0]); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_cache_msync(dma_obj->desc[cnt], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync(dma_obj->desc[cnt], sizeof(lldesc_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); #endif } if (p_i2s[i2s_num]->dir & I2S_DIR_RX) { diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 7520bb23cca..55bb984661d 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -54,7 +54,6 @@ #include "esp_intr_alloc.h" #include "esp_check.h" #include "esp_attr.h" -#include "esp_dma_utils.h" #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" #endif @@ -69,16 +68,9 @@ static const char *TAG = "i2s_common"; __attribute__((always_inline)) -inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size, size_t *actual_size) +inline void *i2s_dma_calloc(i2s_chan_handle_t handle, size_t num, size_t size) { - void *ptr = NULL; - esp_dma_mem_info_t dma_mem_info = { - .extra_heap_caps = I2S_DMA_ALLOC_CAPS, - .dma_alignment_bytes = 4, - }; - //TODO: IDF-9636 - esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size); - return ptr; + return heap_caps_aligned_calloc(4, num, size, I2S_DMA_ALLOC_CAPS); } /*--------------------------------------------------------------------------- @@ -425,10 +417,9 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA descriptor array failed"); handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS); - size_t desc_size = 0; for (int i = 0; i < num; i++) { /* Allocate DMA descriptor */ - handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(handle, 1, sizeof(lldesc_t), &desc_size); + handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(handle, 1, sizeof(lldesc_t)); ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed"); handle->dma.desc[i]->owner = 1; handle->dma.desc[i]->eof = 1; @@ -436,7 +427,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu handle->dma.desc[i]->length = bufsize; handle->dma.desc[i]->size = bufsize; handle->dma.desc[i]->offset = 0; - handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(handle, 1, bufsize * sizeof(uint8_t), NULL); + handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(handle, 1, bufsize * sizeof(uint8_t)); ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed"); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE esp_cache_msync(handle->dma.bufs[i], bufsize * sizeof(uint8_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M); @@ -449,7 +440,7 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu /* Link to the next descriptor */ STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0]; #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_cache_msync(handle->dma.desc[i], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync(handle->dma.desc[i], sizeof(lldesc_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); #endif } if (handle->dir == I2S_DIR_RX) { diff --git a/components/esp_driver_i2s/i2s_private.h b/components/esp_driver_i2s/i2s_private.h index 0f6e388e8cd..3675d29897e 100644 --- a/components/esp_driver_i2s/i2s_private.h +++ b/components/esp_driver_i2s/i2s_private.h @@ -38,7 +38,7 @@ extern "C" { #define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED) #define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif //CONFIG_I2S_ISR_IRAM_SAFE -#define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) +#define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT) #if SOC_PERIPH_CLK_CTRL_SHARED #define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index a3390947cad..c6e3eadf885 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -33,7 +33,6 @@ #include "esp_memory_utils.h" #include "esp_clk_tree.h" #include "esp_attr.h" -#include "esp_dma_utils.h" #include "esp_private/gdma.h" #include "esp_cache.h" diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index 4f4dd596a23..60aacfd5b9e 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -23,7 +23,6 @@ #include "soc/i2s_periph.h" #include "soc/spi_periph.h" #include "soc/parlio_periph.h" -#include "esp_dma_utils.h" #include "esp_attr.h" #include "test_board.h" diff --git a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c index f317c3b39ef..41de582782c 100644 --- a/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c +++ b/examples/peripherals/parlio/parlio_rx/logic_analyzer/components/esp_probe/hw_impl/esp_probe_impl_parlio.c @@ -12,7 +12,6 @@ #include "hal/cache_ll.h" #include "esp_clk_tree.h" #include "esp_heap_caps.h" -#include "esp_dma_utils.h" #include "esp_check.h" #include "esp_probe_private.h" From f1df3eb99b8a72838bc1beeaff3651f998665ab7 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 30 May 2024 16:39:07 +0800 Subject: [PATCH 228/548] docs(core): update misc docs for C5 --- docs/docs_not_updated/esp32c5.txt | 76 ------------------- docs/en/api-guides/startup.rst | 4 +- docs/en/api-reference/system/intr_alloc.rst | 4 + docs/zh_CN/api-guides/startup.rst | 4 +- .../zh_CN/api-reference/system/intr_alloc.rst | 4 + 5 files changed, 12 insertions(+), 80 deletions(-) diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index f02c429bad6..8517a165184 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -17,10 +17,7 @@ api-guides/jtag-debugging/configure-other-jtag.rst api-guides/jtag-debugging/building-openocd-windows.rst api-guides/jtag-debugging/index.rst api-guides/jtag-debugging/configure-builtin-jtag.rst -api-guides/partition-tables.rst api-guides/app_trace.rst -api-guides/thread-local-storage.rst -api-guides/error-handling.rst api-guides/tools/idf-tools.rst api-guides/tools/idf-clang-tidy.rst api-guides/tools/idf-component-manager.rst @@ -31,29 +28,20 @@ api-guides/tools/idf-monitor.rst api-guides/tools/idf-docker-image.rst api-guides/tools/index.rst api-guides/low-power-mode.rst -api-guides/startup.rst -api-guides/hlinterrupts.rst api-guides/RF_calibration.rst -api-guides/unit-tests.rst api-guides/deep-sleep-stub.rst api-guides/blufi.rst api-guides/lwip.rst api-guides/coexist.rst api-guides/flash_psram_config.rst api-guides/usb-serial-jtag-console.rst -api-guides/linker-script-generation.rst api-guides/wifi.rst api-guides/usb-otg-console.rst api-guides/bluetooth.rst api-guides/wireshark-user-guide.rst -api-guides/bootloader.rst api-guides/esp-wifi-mesh.rst -api-guides/cplusplus.rst -api-guides/build-system.rst api-guides/core_dump.rst api-guides/inc/external-ram-esp32-notes.rst -api-guides/inc/linux-host-requirements.rst -api-guides/c.rst api-guides/dfu.rst api-guides/current-consumption-measurement-modules.rst api-guides/esp-ble-mesh/ble-mesh-index.rst @@ -62,15 +50,8 @@ api-guides/esp-ble-mesh/ble-mesh-terminology.rst api-guides/esp-ble-mesh/ble-mesh-architecture.rst api-guides/esp-ble-mesh/ble-mesh-faq.rst api-guides/external-ram.rst -api-guides/reproducible-builds.rst -api-guides/hardware-abstraction.rst api-guides/wifi-security.rst -api-guides/host-apps.rst -api-guides/index.rst api-guides/openthread.rst -api-guides/fatal-errors.rst -api-guides/memory-types.rst -api-guides/general-notes.rst third-party-tools/platformio.rst third-party-tools/clion.rst third-party-tools/visualgdb.rst @@ -79,7 +60,6 @@ libraries-and-frameworks/libs-frameworks.rst libraries-and-frameworks/index.rst libraries-and-frameworks/cloud-frameworks.rst versions.rst -api-reference/api-conventions.rst api-reference/template.rst api-reference/provisioning/protocomm.rst api-reference/provisioning/provisioning.rst @@ -142,7 +122,6 @@ api-reference/peripherals/index.rst api-reference/peripherals/sdmmc_host.rst api-reference/peripherals/ecdsa.rst api-reference/peripherals/rmt.rst -api-reference/kconfig.rst api-reference/network/esp_openthread.rst api-reference/network/esp_eth.rst api-reference/network/esp_netif_driver.rst @@ -158,41 +137,22 @@ api-reference/system/sleep_modes.rst api-reference/system/mm_sync.rst api-reference/system/ota.rst api-reference/system/app_trace.rst -api-reference/system/perfmon.rst -api-reference/system/esp_function_with_shared_stack.rst api-reference/system/efuse.rst api-reference/system/chip_revision.rst api-reference/system/async_memcpy.rst api-reference/system/random.rst api-reference/system/esp_timer.rst -api-reference/system/esp_event.rst api-reference/system/freertos.rst api-reference/system/system_time.rst -api-reference/system/log.rst -api-reference/system/soc_caps.rst -api-reference/system/internal-unstable.rst -api-reference/system/app_image_format.rst api-reference/system/freertos_additions.rst -api-reference/system/himem.rst api-reference/system/power_management.rst -api-reference/system/mem_alloc.rst -api-reference/system/wdts.rst -api-reference/system/misc_system_api.rst -api-reference/system/bootloader_image_format.rst api-reference/system/inc/show-efuse-table_ESP32-C5.rst api-reference/system/inc/revisions_ESP32-C5.rst api-reference/system/inc/espefuse_summary_ESP32-C5.rst api-reference/system/inc/power_management_esp32c5.rst -api-reference/system/heap_debug.rst api-reference/system/mm.rst -api-reference/system/ipc.rst api-reference/system/esp_https_ota.rst -api-reference/system/esp_err.rst api-reference/system/freertos_idf.rst -api-reference/system/console.rst -api-reference/system/intr_alloc.rst -api-reference/system/index.rst -api-reference/system/pthread.rst api-reference/bluetooth/esp_spp.rst api-reference/bluetooth/esp_l2cap_bt.rst api-reference/bluetooth/esp_hidd.rst @@ -219,7 +179,6 @@ api-reference/bluetooth/esp-ble-mesh.rst api-reference/bluetooth/index.rst api-reference/bluetooth/esp_gap_ble.rst api-reference/bluetooth/classic_bt.rst -api-reference/error-codes.rst api-reference/index.rst api-reference/protocols/icmp_echo.rst api-reference/protocols/esp_serial_slave_link.rst @@ -244,41 +203,6 @@ security/secure-boot-v1.rst security/index.rst about.rst resources.rst -migration-guides/release-5.x/5.2/ieee802154.rst -migration-guides/release-5.x/5.2/gcc.rst -migration-guides/release-5.x/5.2/protocols.rst -migration-guides/release-5.x/5.2/wifi.rst -migration-guides/release-5.x/5.2/storage.rst -migration-guides/release-5.x/5.2/index.rst -migration-guides/release-5.x/5.2/system.rst -migration-guides/release-5.x/5.2/peripherals.rst -migration-guides/release-5.x/5.3/security.rst -migration-guides/release-5.x/5.3/bluetooth-low-energy.rst -migration-guides/release-5.x/5.3/storage.rst -migration-guides/release-5.x/5.3/index.rst -migration-guides/release-5.x/5.3/system.rst -migration-guides/release-5.x/5.3/peripherals.rst -migration-guides/release-5.x/5.1/ieee802154.rst -migration-guides/release-5.x/5.1/gcc.rst -migration-guides/release-5.x/5.1/networking.rst -migration-guides/release-5.x/5.1/storage.rst -migration-guides/release-5.x/5.1/index.rst -migration-guides/release-5.x/5.1/system.rst -migration-guides/release-5.x/5.1/peripherals.rst -migration-guides/release-5.x/5.0/bluetooth-classic.rst -migration-guides/release-5.x/5.0/gcc.rst -migration-guides/release-5.x/5.0/bluetooth-low-energy.rst -migration-guides/release-5.x/5.0/removed-components.rst -migration-guides/release-5.x/5.0/protocols.rst -migration-guides/release-5.x/5.0/networking.rst -migration-guides/release-5.x/5.0/provisioning.rst -migration-guides/release-5.x/5.0/build-system.rst -migration-guides/release-5.x/5.0/storage.rst -migration-guides/release-5.x/5.0/index.rst -migration-guides/release-5.x/5.0/system.rst -migration-guides/release-5.x/5.0/tools.rst -migration-guides/release-5.x/5.0/peripherals.rst -migration-guides/index.rst get-started/establish-serial-connection.rst get-started/linux-macos-setup.rst get-started/linux-macos-start-project.rst diff --git a/docs/en/api-guides/startup.rst b/docs/en/api-guides/startup.rst index e0276986eac..a9196363aef 100644 --- a/docs/en/api-guides/startup.rst +++ b/docs/en/api-guides/startup.rst @@ -50,11 +50,11 @@ Startup code called from the reset vector determines the boot mode by checking ` Second stage bootloader binary image is loaded from flash starting at address {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH}. The 4 kB sector of flash before this address is unused. -.. only:: esp32p4 +.. only:: SOC_KEY_MANAGER_SUPPORTED Second stage bootloader binary image is loaded from flash starting at address {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH}. The 8 kB sector of flash before this address is reserved for the key manager for use with flash encryption (AES-XTS). -.. only:: not (esp32 or esp32s2 or esp32p4) +.. only:: not (esp32 or esp32s2 or SOC_KEY_MANAGER_SUPPORTED) Second stage bootloader binary image is loaded from the start of flash at offset {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH}. diff --git a/docs/en/api-reference/system/intr_alloc.rst b/docs/en/api-reference/system/intr_alloc.rst index 9d8743bfec7..19e56de49c0 100644 --- a/docs/en/api-reference/system/intr_alloc.rst +++ b/docs/en/api-reference/system/intr_alloc.rst @@ -26,6 +26,10 @@ Overview The {IDF_TARGET_NAME} has two cores, with 32 external asynchronous interrupts each. Each interrupt's priority is independently programmable. In addition, there are also 3 core local interrupt sources (CLINT) on each core. See **{IDF_TARGET_NAME} Technical Reference Manual** [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__] for more details. +.. only:: esp32c5 + + The {IDF_TARGET_NAME} has one core, with 32 external asynchronous interrupts. Each interrupt's priority is independently programmable. In addition, there are also 3 core local interrupt sources (CLINT). For details, see **{IDF_TARGET_NAME} Technical Reference Manual** > **High-Performance CPU** [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__]. + Because there are more interrupt sources than interrupts, sometimes it makes sense to share an interrupt in multiple drivers. The :cpp:func:`esp_intr_alloc` abstraction exists to hide all these implementation details. A driver can allocate an interrupt for a certain peripheral by calling :cpp:func:`esp_intr_alloc` (or :cpp:func:`esp_intr_alloc_intrstatus`). It can use the flags passed to this function to specify the type, priority, and trigger method of the interrupt to allocate. The interrupt allocation code will then find an applicable interrupt, use the interrupt matrix to hook it up to the peripheral, and install the given interrupt handler and ISR to it. diff --git a/docs/zh_CN/api-guides/startup.rst b/docs/zh_CN/api-guides/startup.rst index db8a0125492..db82ddc7d97 100644 --- a/docs/zh_CN/api-guides/startup.rst +++ b/docs/zh_CN/api-guides/startup.rst @@ -50,11 +50,11 @@ 二级引导程序二进制镜像会从 flash 的 {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} 偏移地址处加载。该地址前面的 flash 4 kB 扇区未使用。 -.. only:: esp32p4 +.. only:: SOC_KEY_MANAGER_SUPPORTED 二级引导程序二进制镜像会从 flash 的 {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} 偏移地址处加载。该地址前面的 flash 8 kB 扇区将为密钥管理器保留,用于与 flash 加密 (AES-XTS) 相关的操作。 - .. only:: not (esp32 or esp32s2 or esp32p4) + .. only:: not (esp32 or esp32s2 or SOC_KEY_MANAGER_SUPPORTED) 二级引导程序二进制镜像会从 flash 的 {IDF_TARGET_CONFIG_BOOTLOADER_OFFSET_IN_FLASH} 偏移地址处加载。 diff --git a/docs/zh_CN/api-reference/system/intr_alloc.rst b/docs/zh_CN/api-reference/system/intr_alloc.rst index eb4fa1dd123..ec60d86e417 100644 --- a/docs/zh_CN/api-reference/system/intr_alloc.rst +++ b/docs/zh_CN/api-reference/system/intr_alloc.rst @@ -26,6 +26,10 @@ {IDF_TARGET_NAME} 有两个核,每个核有 32 个外部异步中断。每个中断的优先级别都可独立地通过编程设置。此外,每个核还有 3 个核心本地中断源 (CLINT)。详细信息请参见 **{IDF_TARGET_NAME} 技术参考手册** [`PDF <{IDF_TARGET_TRM_CN_URL}#riscvcpu>`__]。 +.. only:: esp32c5 + + {IDF_TARGET_NAME} 有一个核,32 个外部异步中断。每个中断的优先级别都可独立地通过编程设置。此外,还有 3 个核心本地中断源 (CLINT)。详细信息请参见 **{IDF_TARGET_NAME} 技术参考手册** > **高性能处理器** [`PDF <{IDF_TARGET_TRM_CN_URL}#riscvcpu>`__]。 + 由于中断源数量多于中断,有时多个驱动程序可以共用一个中断。:cpp:func:`esp_intr_alloc` 抽象隐藏了这些实现细节。 驱动程序可以通过调用 :cpp:func:`esp_intr_alloc`,或 :cpp:func:`esp_intr_alloc_intrstatus` 为某个外设分配中断。通过向此函数传递 flag,可以指定中断类型、优先级和触发方式。然后,中断分配代码会找到适用的中断,使用中断矩阵将其连接到外设,并为其安装给定的中断处理程序和 ISR。 From de0990e58c35d1d6f19236d26884ca2b51fa335f Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 24 May 2024 15:53:11 +0800 Subject: [PATCH 229/548] feat(cam): add esp32-p4 lcd_cam dvp driver --- components/esp_driver_cam/CMakeLists.txt | 7 + components/esp_driver_cam/Kconfig | 17 +- .../dvp/include/esp_cam_ctlr_dvp.h | 70 ++ .../dvp/include/esp_private/esp_cam_dvp.h | 54 ++ .../private_include/esp_cam_ctlr_dvp_cam.h | 56 ++ .../private_include/esp_cam_ctlr_dvp_dma.h | 104 +++ .../dvp/src/esp_cam_ctlr_dvp_cam.c | 764 ++++++++++++++++++ .../dvp/src/esp_cam_ctlr_dvp_gdma.c | 202 +++++ .../test_apps/.build-test-rules.yml | 6 + .../test_apps/dvp/CMakeLists.txt | 8 + .../esp_driver_cam/test_apps/dvp/README.md | 2 + .../test_apps/dvp/main/CMakeLists.txt | 16 + .../test_apps/dvp/main/test_app_main.c | 27 + .../test_apps/dvp/main/test_dvp_driver.c | 86 ++ .../test_apps/dvp/pytest_dvp.py | 10 + .../test_apps/dvp/sdkconfig.defaults | 6 + .../test_apps/dvp/sdkconfig.defaults.esp32p4 | 3 + components/hal/CMakeLists.txt | 4 + components/hal/cam_hal.c | 121 +++ components/hal/esp32p4/include/hal/cam_ll.h | 634 +++++++++++++++ components/hal/include/hal/cam_hal.h | 73 ++ components/hal/include/hal/cam_types.h | 34 + components/soc/CMakeLists.txt | 4 + components/soc/esp32p4/cam_periph.c | 40 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 16 + .../soc/esp32p4/include/soc/clk_tree_defs.h | 17 + components/soc/esp32p4/include/soc/soc_caps.h | 10 +- components/soc/include/soc/cam_periph.h | 35 + 28 files changed, 2422 insertions(+), 4 deletions(-) create mode 100644 components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h create mode 100644 components/esp_driver_cam/dvp/include/esp_private/esp_cam_dvp.h create mode 100644 components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_cam.h create mode 100644 components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h create mode 100644 components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c create mode 100644 components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c create mode 100644 components/esp_driver_cam/test_apps/dvp/CMakeLists.txt create mode 100644 components/esp_driver_cam/test_apps/dvp/README.md create mode 100644 components/esp_driver_cam/test_apps/dvp/main/CMakeLists.txt create mode 100644 components/esp_driver_cam/test_apps/dvp/main/test_app_main.c create mode 100644 components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c create mode 100644 components/esp_driver_cam/test_apps/dvp/pytest_dvp.py create mode 100644 components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults create mode 100644 components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults.esp32p4 create mode 100644 components/hal/cam_hal.c create mode 100644 components/hal/esp32p4/include/hal/cam_ll.h create mode 100644 components/hal/include/hal/cam_hal.h create mode 100644 components/hal/include/hal/cam_types.h create mode 100644 components/soc/esp32p4/cam_periph.c create mode 100644 components/soc/include/soc/cam_periph.h diff --git a/components/esp_driver_cam/CMakeLists.txt b/components/esp_driver_cam/CMakeLists.txt index 17ac846f644..e0a06e35866 100644 --- a/components/esp_driver_cam/CMakeLists.txt +++ b/components/esp_driver_cam/CMakeLists.txt @@ -22,8 +22,15 @@ if(NOT ${target} STREQUAL "linux") list(APPEND requires esp_mm) endif() +if(CONFIG_SOC_LCDCAM_CAM_SUPPORTED) + list(APPEND srcs "dvp/src/esp_cam_ctlr_dvp_gdma.c" "dvp/src/esp_cam_ctlr_dvp_cam.c") + list(APPEND includes "dvp/include") + list(APPEND priv_include_dirs "dvp/private_include") +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${includes} + PRIV_INCLUDE_DIRS ${priv_include_dirs} REQUIRES ${requires} PRIV_REQUIRES ${priv_requires} ) diff --git a/components/esp_driver_cam/Kconfig b/components/esp_driver_cam/Kconfig index 771fd0e6aba..ca1fac319a3 100644 --- a/components/esp_driver_cam/Kconfig +++ b/components/esp_driver_cam/Kconfig @@ -1,9 +1,10 @@ menu "ESP-Driver:Camera Controller Configurations" - depends on SOC_MIPI_CSI_SUPPORTED + depends on SOC_MIPI_CSI_SUPPORTED || SOC_LCDCAM_CAM_SUPPORTED config CAM_CTLR_MIPI_CSI_ISR_IRAM_SAFE bool "CSI ISR IRAM-Safe" + depends on SOC_MIPI_CSI_SUPPORTED default n select DW_GDMA_ISR_IRAM_SAFE select DW_GDMA_CTRL_FUNC_IN_IRAM @@ -13,7 +14,7 @@ menu "ESP-Driver:Camera Controller Configurations" Ensure the CSI driver ISR is IRAM-Safe. When enabled, the ISR handler will be available when the cache is disabled. - config CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE + config CAM_CTLR_ISP_DVP_ISR_IRAM_SAFE # IDF-10093 bool "ISP_DVP ISR IRAM-Safe" default n select DW_GDMA_ISR_IRAM_SAFE @@ -24,4 +25,16 @@ menu "ESP-Driver:Camera Controller Configurations" Ensure the ISP_DVP driver ISR is IRAM-Safe. When enabled, the ISR handler will be available when the cache is disabled. + config CAM_CTLR_DVP_CAM_ISR_IRAM_SAFE + bool "DVP ISR IRAM-Safe" + depends on SOC_LCDCAM_CAM_SUPPORTED + default n + select DW_GDMA_ISR_IRAM_SAFE + select DW_GDMA_CTRL_FUNC_IN_IRAM + select DW_GDMA_SETTER_FUNC_IN_IRAM + select DW_GDMA_GETTER_FUNC_IN_IRAM + help + Ensure the DVP driver ISR is IRAM-Safe. When enabled, the ISR handler + will be available when the cache is disabled. + endmenu # ESP Camera Controller Configurations diff --git a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h new file mode 100644 index 00000000000..b235f3e8f74 --- /dev/null +++ b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "hal/cam_types.h" +#include "esp_cam_ctlr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ESP CAM DVP pins configuration + */ +typedef struct esp_cam_ctlr_dvp_pin_config { + cam_ctlr_data_width_t data_width; /*!< Number of data lines */ + int data_io[CAM_DVP_DATA_SIG_NUM]; /*!< DVP data pin number */ + int vsync_io; /*!< DVP V-Sync pin number */ + int de_io; /*!< DVP DE pin number */ + int pclk_io; /*!< DVP PCLK input pin number, clock is from camera sensor */ + int xclk_io; /*!< DVP output clock pin number */ +} esp_cam_ctlr_dvp_pin_config_t; + +/** + * @brief ESP CAM DVP controller configurations + */ +typedef struct esp_cam_ctlr_dvp_config { + int ctlr_id; /*!< DVP controller ID */ + cam_clock_source_t clk_src; /*!< DVP clock source */ + uint32_t h_res; /*!< Input horizontal resolution, i.e. the number of pixels in a line */ + uint32_t v_res; /*!< Input vertical resolution, i.e. the number of lines in a frame */ + cam_ctlr_color_t input_data_color_type; /*!< Input pixel format */ + struct { + uint32_t byte_swap_en : 1; /*!< Enable byte swap */ + uint32_t bk_buffer_dis : 1; /*!< Disable backup buffer */ + uint32_t pin_dont_init : 1; /*!< Don't initialize DVP pins if users have called "esp_cam_ctlr_dvp_init" before */ + uint32_t pic_format_jpeg : 1; /*!< Input picture format is JPEG, if set this flag and "input_data_color_type" will be ignored */ + }; /*!< Boolean Flags */ + + uint32_t dma_burst_size; /*!< DVP DMA burst transmission block size, set to 0 means to disable the data burst, + other value must be power of 2, e.g., 4/8/16/32/64/128 */ + + const esp_cam_ctlr_dvp_pin_config_t *pin; /*!< DVP pin configuration, this will be ignored by "esp_cam_new_dvp_ctlr" if "pin_dont_init" is set */ +} esp_cam_ctlr_dvp_config_t; + +/** + * @brief New ESP CAM DVP controller + * + * @param config DVP controller configurations + * @param ret_handle Returned CAM controller handle + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: Out of memory + * - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types + * - ESP_ERR_NOT_FOUND: CSI is registered already + */ +esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ctlr_handle_t *ret_handle); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/dvp/include/esp_private/esp_cam_dvp.h b/components/esp_driver_cam/dvp/include/esp_private/esp_cam_dvp.h new file mode 100644 index 00000000000..032c8161793 --- /dev/null +++ b/components/esp_driver_cam/dvp/include/esp_private/esp_cam_dvp.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_cam_ctlr_dvp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ESP CAM DVP initialzie clock and GPIO. + * + * @param ctlr_id CAM DVP controller ID + * @param clk_src CAM DVP clock source + * @param pin CAM DVP pin configuration + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const esp_cam_ctlr_dvp_pin_config_t *pin); + +/** + * @brief ESP CAM DVP output hardware clock + * + * @param ctlr_id CAM DVP controller ID + * @param clk_src CAM DVP clock source + * @param xclk_freq CAM DVP output clock frequency in HZ + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src, uint32_t xclk_freq); + +/** + * @brief ESP CAM DVP de-initialzie. + * + * @param ctlr_id DVP controller ID + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_cam.h b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_cam.h new file mode 100644 index 00000000000..5c9b311ee1a --- /dev/null +++ b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_cam.h @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "freertos/FreeRTOS.h" +#include "esp_cam_ctlr_interface.h" +#include "hal/cam_hal.h" +#include "esp_cam_ctlr_dvp_dma.h" +#include "esp_cam_ctlr_dvp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief DVP CAM finite state machine + */ +typedef enum esp_cam_ctlr_dvp_cam_fsm { + ESP_CAM_CTLR_DVP_CAM_FSM_INIT = 1, /*!< DVP CAM initialization state, and next state is "enabled" */ + ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED, /*!< DVP CAM enabled state, and next state is "init" or "started" */ + ESP_CAM_CTLR_DVP_CAM_FSM_STARTED, /*!< DVP CAM started state, and next state is "init" or "enabled" */ +} esp_cam_ctlr_dvp_cam_fsm_t; + +/** + * @brief DVP CAM object data + */ +typedef struct esp_cam_ctlr_dvp_cam { + esp_cam_ctlr_t base; /*!< Camera controller base object data */ + esp_cam_ctlr_evt_cbs_t cbs; /*!< Camera controller callback functions */ + void *cbs_user_data; /*!< Camera controller callback private data */ + + int ctlr_id; /*!< DVP CAM port ID */ + cam_ctlr_color_t input_data_color_type; /*!< DVP CAM input pixel format */ + struct { + uint32_t bk_buffer_dis : 1; /*!< Disable backup buffer */ + uint32_t pin_dont_init : 1; /*!< Don't initialize DVP pins if users have called "esp_cam_ctlr_dvp_init" before */ + uint32_t pic_format_jpeg : 1; /*!< Input picture format is JPEG, if set this flag and "input_data_color_type" will be ignored */ + }; /*!< Boolean Flags */ + + cam_hal_context_t hal; /*!< DVP CAM HAL object data */ + esp_cam_ctlr_dvp_dma_t dma; /*!< DVP CAM DMA object data */ + size_t fb_size_in_bytes; /*!< DVP CAM frame buffer maximum size in byte */ + esp_cam_ctlr_dvp_cam_fsm_t dvp_fsm; /*!< DVP CAM finite state machine */ + uint8_t *cur_buf; /*!< DVP CAM current buffer which is receiving stream */ + uint8_t *backup_buffer; /*!< DVP CAM backup buffer */ + bool bk_buffer_exposed; /*!< status of if back_buffer is exposed to users */ + portMUX_TYPE spinlock; /*!< DVP CAM spinlock */ +} esp_cam_ctlr_dvp_cam_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h new file mode 100644 index 00000000000..0846d6ccd66 --- /dev/null +++ b/components/esp_driver_cam/dvp/private_include/esp_cam_ctlr_dvp_dma.h @@ -0,0 +1,104 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "hal/dma_types.h" +#include "esp_private/gdma.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + +/** + * @brief DVP DMA description object + */ +typedef dma_descriptor_align8_t esp_cam_ctlr_dvp_dma_desc_t; + +/** + * @brief DVP DMA object + */ +typedef struct esp_cam_ctlr_dvp_dma { + gdma_channel_handle_t dma_chan; /*!< DVP DMA channel handle */ + size_t size; /*!< DVP DMA buffer size */ + esp_cam_ctlr_dvp_dma_desc_t *desc; /*!< DVP DMA description buffer */ + size_t desc_count; /*!< DVP DMA description count */ + size_t desc_size; /*!< DVP DMA description buffer size in byte */ +} esp_cam_ctlr_dvp_dma_t; + +/** + * @brief Initialize DVP DMA object + * + * @param dma DVP DMA object pointer + * @param burst_size DVP DMA burst transmission block size + * @param size DVP DMA buffer size + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_size, size_t size); + +/** + * @brief De-initialize DVP DMA object + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_deinit(esp_cam_ctlr_dvp_dma_t *dma); + +/** + * @brief Set DVP DMA descriptor address and start engine + * + * @param dma DVP DMA object pointer + * @param buffer DVP DMA buffer pointer + * @param size DVP DMA buffer size + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint8_t *buffer, size_t size); + +/** + * @brief Stop DVP DMA engine + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_stop(esp_cam_ctlr_dvp_dma_t *dma); + +/** + * @brief Reset DVP DMA FIFO and internal finite state machine + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_reset(esp_cam_ctlr_dvp_dma_t *dma); + +/** + * @brief Get DMA received data size + * + * @param dma DVP DMA object pointer + * + * @return DMA received data size + */ +size_t esp_cam_ctlr_dvp_dma_get_recv_size(esp_cam_ctlr_dvp_dma_t *dma); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c new file mode 100644 index 00000000000..04334bf7e68 --- /dev/null +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -0,0 +1,764 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "hal/gpio_ll.h" +#include "hal/cam_ll.h" +#include "driver/gpio.h" +#include "esp_cache.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_cache_private.h" +#include "esp_private/gpio.h" +#include "esp_heap_caps.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_clk_tree.h" +#include "soc/cam_periph.h" +#include "esp_cam_ctlr_dvp_cam.h" +#include "esp_private/esp_cam_dvp.h" +#include "../../dvp_share_ctrl.h" + +#ifdef CONFIG_CAM_CTLR_DVP_CAM_ISR_IRAM_SAFE +#define CAM_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define CAM_DVP_MEM_ALLOC_CAPS (MALLOC_CAP_DEFAULT) +#endif + +#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) + +#define DVP_CAM_CONFIG_INPUT_PIN(pin, sig, inv) \ +{ \ + ret = esp_cam_ctlr_dvp_config_input_gpio(pin, sig, inv); \ + if (ret != ESP_OK) { \ + ESP_LOGE(TAG, "failed to configure pin=%d sig=%d", \ + pin, sig); \ + return ret; \ + } \ +} + +typedef struct dvp_platform { + _lock_t mutex; + esp_cam_ctlr_dvp_cam_t *ctlrs[CAP_DVP_PERIPH_NUM]; +} dvp_platform_t; + +static dvp_platform_t s_platform; +static const char *TAG = "dvp_cam"; + +/** + * @brief Claim DVP controller + * + * @param ctlr_id DVP controller ID + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t s_dvp_claim_ctlr(int ctlr_id, esp_cam_ctlr_dvp_cam_t *ctlr) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + + _lock_acquire(&s_platform.mutex); + if (!s_platform.ctlrs[ctlr_id]) { + s_platform.ctlrs[ctlr_id] = ctlr; + ret = ESP_OK; + } + _lock_release(&s_platform.mutex); + + return ret; +} + +/** + * @brief Declaim DVP controller + * + * @param ctlr_id DVP controller ID + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t s_dvp_declaim_ctlr(int ctlr_id) +{ + esp_err_t ret = ESP_ERR_NOT_FOUND; + + _lock_acquire(&s_platform.mutex); + if (s_platform.ctlrs[ctlr_id]) { + s_platform.ctlrs[ctlr_id] = NULL; + ret = ESP_OK; + } + _lock_release(&s_platform.mutex); + + return ret; +} + +/** + * @brief CAM DVP initialzie input GPIO pin. + * + * @param pin DVP pin number + * @param signal DVP pin mapping signal + * @param inv true: DVP pin is inverted, false: DVP pin is not inverted + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_config_input_gpio(int pin, int signal, bool inv) +{ + esp_err_t ret; + + gpio_func_sel(pin, PIN_FUNC_GPIO); + ret = gpio_set_direction(pin, GPIO_MODE_INPUT); + if (ret != ESP_OK) { + return ret; + } + ret = gpio_set_pull_mode(pin, GPIO_FLOATING); + if (ret != ESP_OK) { + return ret; + } + esp_rom_gpio_connect_in_signal(pin, signal, inv); + + return ESP_OK; +} + +/** + * @brief CAM DVP start receiving frame. + * + * @param ctlr CAM DVP controller + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static IRAM_ATTR esp_err_t esp_cam_ctlr_dvp_start_trans(esp_cam_ctlr_dvp_cam_t *ctlr) +{ + bool buffer_ready = false; + esp_cam_ctlr_trans_t trans; + + if (ctlr->cur_buf) { + ctlr->cur_buf = NULL; + cam_hal_stop_streaming(&ctlr->hal); + ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_stop(&ctlr->dma), TAG, "failed to stop DMA"); + } + + if (ctlr->cbs.on_get_new_trans && ctlr->cbs.on_get_new_trans(&(ctlr->base), &trans, ctlr->cbs_user_data)) { + buffer_ready = true; + } else if (!ctlr->bk_buffer_dis) { + trans.buffer = ctlr->backup_buffer; + trans.buflen = ctlr->fb_size_in_bytes; + buffer_ready = true; + } + + if (!buffer_ready) { + assert(false && "no new buffer, and no driver internal buffer"); + } + + ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_reset(&ctlr->dma), TAG, "failed to reset DMA"); + ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_start(&ctlr->dma, trans.buffer, ctlr->fb_size_in_bytes), TAG, "failed to start DMA"); + + cam_hal_start_streaming(&ctlr->hal); + + ctlr->cur_buf = trans.buffer; + + return ESP_OK; +} + +/** + * @brief Check JPEG file and return JPEG frame actual size + * + * @param buffer JPEG buffer pointer + * @param size JPEG buffer size + * + * @return JPEG frame actual size if success or 0 if not JPEG header or tail TAG is found + */ +static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_jpeg_size(const uint8_t *buffer, uint32_t size) +{ + /* Check JPEG header TAG: ff:d8 */ + + if (buffer[0] != 0xff || buffer[1] != 0xd8) { + return 0; + } + + for (uint32_t off = size - 2; off > 2; off--) { + /* Check JPEG tail TAG: ff:d9 */ + + if (buffer[off] == 0xff && buffer[off + 1] == 0xd9) { + return off + 2; + } + } + + return 0; +} + +/** + * @brief CAM DVP get actually received data size in byte + * + * @param ctlr CAM DVP controller + * @param rx_buffer CAM DVP receive buffer + * @param dma_recv_size CAM DVP DMA receive buffer size + * + * @return Received data size if success or 0 if failed + */ +static uint32_t IRAM_ATTR esp_cam_ctlr_dvp_get_recved_size(esp_cam_ctlr_dvp_cam_t *ctlr, uint8_t *rx_buffer, uint32_t dma_recv_size) +{ + esp_err_t ret; + uint32_t recv_buffer_size; + + if (ctlr->pic_format_jpeg) { + recv_buffer_size = ALIGN_UP_BY(MIN(dma_recv_size, ctlr->fb_size_in_bytes), 64); + } else { + recv_buffer_size = ctlr->fb_size_in_bytes; + } + + ret = esp_cache_msync(rx_buffer, recv_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + + if (ctlr->pic_format_jpeg) { + recv_buffer_size = esp_cam_ctlr_dvp_get_jpeg_size(rx_buffer, dma_recv_size); + } + + return recv_buffer_size; +} + +/** + * @brief CAM DVP calculate frame receive buffer size. + * + * @param config CAM DVP controller configurations + * @param p_size CAM DVP frame receive buffer size buffer pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_get_frame_size(const esp_cam_ctlr_dvp_config_t *config, size_t *p_size) +{ + esp_err_t ret = ESP_OK; + + if (config->pic_format_jpeg) { + *p_size = config->h_res * config->v_res; + } else { + switch (config->input_data_color_type) { + case CAM_CTLR_COLOR_RGB565: + *p_size = config->h_res * config->v_res * 2; + break; + case CAM_CTLR_COLOR_YUV422: + *p_size = config->h_res * config->v_res * 2; + break; + case CAM_CTLR_COLOR_YUV420: + *p_size = (config->h_res * config->v_res / 2) * 3; + break; + case CAM_CTLR_COLOR_RGB888: + *p_size = config->h_res * config->v_res * 3; + break; + default: + ret = ESP_ERR_INVALID_ARG; + break; + } + } + + return ret; +} + +/** + * @brief CAM DVP receive frame done interrupt callback function. + * + * @param dma_chan DMA channel + * @param event_data DMA event data + * @param user_data DMA interrupt callback user data + * + * @return + * - true: trigger task switch + * - false: don't trigger task switch + */ +static IRAM_ATTR bool esp_cam_ctlr_recv_frame_done_isr(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + bool need_switch = false; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)user_data; + size_t dma_recv_size = esp_cam_ctlr_dvp_dma_get_recv_size(&ctlr->dma); + esp_cam_ctlr_trans_t trans = { + .buffer = ctlr->cur_buf, + }; + + esp_cam_ctlr_dvp_start_trans(ctlr); + + if ((trans.buffer != ctlr->backup_buffer) || ctlr->bk_buffer_exposed) { + trans.buflen = ctlr->fb_size_in_bytes; + trans.received_size = esp_cam_ctlr_dvp_get_recved_size(ctlr, trans.buffer, dma_recv_size); + need_switch = ctlr->cbs.on_trans_finished(&ctlr->base, &trans, ctlr->cbs_user_data); + } + + return need_switch; +} + +/** + * @brief ESP CAM DVP initialzie clock and GPIO. + * + * @param ctlr_id CAM DVP controller ID + * @param clk_src CAM DVP clock source + * @param pin CAM DVP pin configuration + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const esp_cam_ctlr_dvp_pin_config_t *pin) +{ + esp_err_t ret; + + ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM); + ESP_RETURN_ON_FALSE(pin->data_width == CAM_CTLR_DATA_WIDTH_8, ESP_ERR_INVALID_ARG, TAG, "invalid argument: data_width != CAM_CTLR_DATA_WIDTH_8"); + ESP_RETURN_ON_FALSE(pin, ESP_ERR_INVALID_ARG, TAG, "invalid argument: pin is null"); + + DVP_CAM_CONFIG_INPUT_PIN(pin->vsync_io, cam_periph_signals.buses[ctlr_id].vsync_sig, true); + DVP_CAM_CONFIG_INPUT_PIN(pin->de_io, cam_periph_signals.buses[ctlr_id].de_sig, false); + DVP_CAM_CONFIG_INPUT_PIN(pin->pclk_io, cam_periph_signals.buses[ctlr_id].pclk_sig, false); + for (int i = 0; i < pin->data_width; i++) { + DVP_CAM_CONFIG_INPUT_PIN(pin->data_io[i], cam_periph_signals.buses[ctlr_id].data_sigs[i], false); + } + + ret = gpio_set_direction(pin->xclk_io, GPIO_MODE_OUTPUT); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "failed to configure pin=%d", pin->xclk_io); + return ret; + } + esp_rom_gpio_connect_out_signal(pin->xclk_io, cam_periph_signals.buses[ctlr_id].clk_sig, false, false); + + PERIPH_RCC_ACQUIRE_ATOMIC(cam_periph_signals.buses[ctlr_id].module, ref_count) { + if (ref_count == 0) { + cam_ll_enable_bus_clock(ctlr_id, true); + cam_ll_reset_register(ctlr_id); + } + } + + PERIPH_RCC_ATOMIC() { + cam_ll_enable_clk(ctlr_id, true); + cam_ll_select_clk_src(ctlr_id, clk_src); + }; + + return ESP_OK; +} + +/** + * @brief ESP CAM DVP output hardware clock + * + * @param ctlr_id CAM DVP controller ID + * @param clk_src CAM DVP clock source + * @param xclk_freq CAM DVP output clock frequency in HZ + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_output_clock(int ctlr_id, cam_clock_source_t clk_src, uint32_t xclk_freq) +{ + esp_err_t ret = ESP_ERR_INVALID_ARG; + uint32_t src_clk_hz; + + ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM); + ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz), + TAG, "failed to get clock source frequency"); + + ESP_LOGD(TAG, "DVP clock source frequency %" PRIu32 "Hz", src_clk_hz); + + if ((src_clk_hz % xclk_freq) == 0) { + PERIPH_RCC_ATOMIC() { + cam_ll_set_group_clock_coeff(ctlr_id, src_clk_hz / xclk_freq, 0, 0); + }; + + ret = ESP_OK; + } + + return ret; +} + +/** + * @brief ESP CAM DVP de-initialzie. + * + * @param ctlr_id DVP controller ID + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_deinit(int ctlr_id) +{ + ESP_RETURN_ON_FALSE(ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM); + + PERIPH_RCC_ATOMIC() { + cam_ll_enable_clk(ctlr_id, false); + }; + + PERIPH_RCC_ACQUIRE_ATOMIC(cam_periph_signals.buses[ctlr_id].module, ref_count) { + if (ref_count == 0) { + cam_ll_reset_register(ctlr_id); + cam_ll_enable_bus_clock(ctlr_id, false); + } + } + + return ESP_OK; +} + +/** + * @brief Enable CAM DVP camera controller + * + * @param handle ESP CAM controller handle + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_enable(esp_cam_ctlr_handle_t handle) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle is null"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_INIT) { + ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief Disable CAM DVP camera controller + * + * @param handle ESP CAM controller handle + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_disable(esp_cam_ctlr_handle_t handle) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle is null"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED) { + ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_INIT; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief Start CAM DVP camera controller + * + * @param handle ESP CAM controller handle + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_start(esp_cam_ctlr_handle_t handle) +{ + bool start = false; + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle is null"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED) { + ctlr->cur_buf = NULL; + ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_STARTED; + start = true; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + if (start) { + ret = esp_cam_ctlr_dvp_start_trans(ctlr); + } + + return ret; +} + +/** + * @brief Stop CAM DVP camera controller + * + * @param handle ESP CAM controller handle + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_stop(esp_cam_ctlr_handle_t handle) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle is null"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_STARTED) { + cam_hal_stop_streaming(&ctlr->hal); + esp_cam_ctlr_dvp_dma_stop(&ctlr->dma); + ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_ENABLED; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief Delete CAM DVP camera controller + * + * @param handle ESP CAM controller handle + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_del(esp_cam_ctlr_handle_t handle) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle is null"); + + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_INIT) { + esp_cam_ctlr_dvp_dma_stop(&ctlr->dma); + cam_hal_stop_streaming(&ctlr->hal); + + esp_cam_ctlr_dvp_dma_deinit(&ctlr->dma); + + if (!ctlr->pin_dont_init) { + esp_cam_ctlr_dvp_deinit(ctlr->ctlr_id); + } + + cam_hal_deinit(&ctlr->hal); + + if (!ctlr->bk_buffer_dis) { + heap_caps_free(ctlr->backup_buffer); + } + + s_dvp_declaim_ctlr(ctlr->ctlr_id); + + heap_caps_free(ctlr); + + dvp_shared_ctrl_declaim_io_signals(); + + ret = ESP_OK; + } + + return ret; +} + +/** + * @brief Register CAM DVP camera controller event callbacks + * + * @param handle ESP CAM controller handle + * @param cbs ESP CAM controller event callbacks + * @param user_data ESP CAM controller event user data + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_register_event_callbacks(esp_cam_ctlr_handle_t handle, const esp_cam_ctlr_evt_cbs_t *cbs, void *user_data) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle or cbs is null"); + ESP_RETURN_ON_FALSE(cbs->on_trans_finished, ESP_ERR_INVALID_ARG, TAG, "invalid argument: on_trans_finished is null"); + ESP_RETURN_ON_FALSE(cbs->on_get_new_trans || !ctlr->bk_buffer_dis, ESP_ERR_INVALID_ARG, TAG, "invalid argument: on_get_new_trans is null"); + +#if CONFIG_CAM_CTLR_DVP_CAM_ISR_IRAM_SAFE + if (cbs->on_get_new_trans) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_get_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_get_new_trans callback not in IRAM"); + } + if (cbs->on_trans_finished) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_finished), ESP_ERR_INVALID_ARG, TAG, "on_trans_finished callback not in IRAM"); + } +#endif + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_INIT) { + ctlr->cbs.on_get_new_trans = cbs->on_get_new_trans; + ctlr->cbs.on_trans_finished = cbs->on_trans_finished; + ctlr->cbs_user_data = user_data; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief Get AM DVP camera controller backup buffer pointer + * + * @param handle ESP CAM controller handle + * @param fb_num Backup buffer pointer storage buffer number + * @param fb0 Backup buffer pointer storage buffer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_dvp_cam_get_internal_buffer(esp_cam_ctlr_handle_t handle, uint32_t fb_num, const void **fb0, ...) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr->backup_buffer, ESP_ERR_INVALID_STATE, TAG, "back_buffer is not available"); + ESP_RETURN_ON_FALSE(fb_num && fb_num <= 1, ESP_ERR_INVALID_ARG, TAG, "invalid frame buffer number"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_INIT) { + va_list args; + const void **fb_itor = fb0; + + va_start(args, fb0); + for (uint32_t i = 0; i < fb_num; i++) { + if (fb_itor) { + *fb_itor = ctlr->backup_buffer; + fb_itor = va_arg(args, const void **); + } + } + va_end(args); + + ctlr->bk_buffer_exposed = true; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief Get CAM DVP camera controller frame buffer length + * + * @param handle ESP CAM controller handle + * @param ret_fb_len The size of each frame buffer in bytes + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static esp_err_t esp_cam_ctlr_get_dvp_cam_frame_buffer_len(esp_cam_ctlr_handle_t handle, size_t *ret_fb_len) +{ + esp_err_t ret = ESP_ERR_INVALID_STATE; + esp_cam_ctlr_dvp_cam_t *ctlr = (esp_cam_ctlr_dvp_cam_t *)handle; + + ESP_RETURN_ON_FALSE(ctlr && ret_fb_len, ESP_ERR_INVALID_ARG, TAG, "invalid argument: handle or ret_fb_len is null"); + + portENTER_CRITICAL(&ctlr->spinlock); + if (ctlr->dvp_fsm == ESP_CAM_CTLR_DVP_CAM_FSM_INIT) { + *ret_fb_len = ctlr->fb_size_in_bytes; + ret = ESP_OK; + } + portEXIT_CRITICAL(&ctlr->spinlock); + + return ret; +} + +/** + * @brief New ESP CAM DVP controller + * + * @param config DVP controller configurations + * @param ret_handle Returned CAM controller handle + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: Out of memory + * - ESP_ERR_NOT_SUPPORTED: Currently not support modes or types + * - ESP_ERR_NOT_FOUND: CSI is registered already + */ +esp_err_t esp_cam_new_dvp_ctlr(const esp_cam_ctlr_dvp_config_t *config, esp_cam_ctlr_handle_t *ret_handle) +{ + esp_err_t ret; + size_t fb_size_in_bytes; + size_t alignment_size; + + ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: config or ret_handle is null"); + ESP_RETURN_ON_FALSE(config->ctlr_id < CAP_DVP_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ctlr_id >= %d", CAP_DVP_PERIPH_NUM); + ESP_RETURN_ON_FALSE(config->pin_dont_init || config->pin, ESP_ERR_INVALID_ARG, TAG, "invalid argument: pin_dont_init is unset and pin is null"); + ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment"); + ESP_RETURN_ON_ERROR(esp_cam_ctlr_dvp_cam_get_frame_size(config, &fb_size_in_bytes), TAG, "invalid argument: input frame pixel format is not supported"); + ESP_RETURN_ON_ERROR(dvp_shared_ctrl_claim_io_signals(), TAG, "failed to claim io signals"); + + esp_cam_ctlr_dvp_cam_t *ctlr = heap_caps_calloc(1, sizeof(esp_cam_ctlr_dvp_cam_t), CAM_DVP_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(ctlr, ESP_ERR_NO_MEM, fail0, TAG, "no mem for CAM DVP controller context"); + + ESP_GOTO_ON_ERROR(s_dvp_claim_ctlr(config->ctlr_id, ctlr), fail1, TAG, "no available DVP controller"); + + ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size); + fb_size_in_bytes = ALIGN_UP_BY(fb_size_in_bytes, alignment_size); + if (!config->bk_buffer_dis) { + ctlr->backup_buffer = heap_caps_aligned_alloc(alignment_size, fb_size_in_bytes, MALLOC_CAP_SPIRAM); + ESP_GOTO_ON_FALSE(ctlr->backup_buffer, ESP_ERR_NO_MEM, fail2, TAG, "no mem for DVP backup buffer"); + } + + ESP_GOTO_ON_ERROR(esp_cam_ctlr_dvp_dma_init(&ctlr->dma, config->dma_burst_size, fb_size_in_bytes), + fail3, TAG, "failed to initialize DVP DMA"); + + gdma_rx_event_callbacks_t cbs = { + .on_recv_eof = esp_cam_ctlr_recv_frame_done_isr + }; + + ESP_GOTO_ON_ERROR(gdma_register_rx_event_callbacks(ctlr->dma.dma_chan, &cbs, ctlr), + fail4, TAG, "failed to register DMA event callbacks"); + + /* Initialize DVP controller */ + + cam_hal_config_t cam_hal_config = { + .port = config->ctlr_id, + .byte_swap_en = config->byte_swap_en, + }; + cam_hal_init(&ctlr->hal, &cam_hal_config); + + if (!config->pin_dont_init) { + ESP_GOTO_ON_ERROR(esp_cam_ctlr_dvp_init(config->ctlr_id, config->clk_src, config->pin), + fail5, TAG, "failed to initialize clock and GPIO"); + } + + ctlr->ctlr_id = config->ctlr_id; + ctlr->fb_size_in_bytes = fb_size_in_bytes; + ctlr->dvp_fsm = ESP_CAM_CTLR_DVP_CAM_FSM_INIT; + ctlr->input_data_color_type = config->input_data_color_type; + ctlr->pic_format_jpeg = config->pic_format_jpeg; + ctlr->bk_buffer_dis = config->bk_buffer_dis; + ctlr->pin_dont_init = config->pin_dont_init; + ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + + ctlr->base.del = esp_cam_ctlr_dvp_cam_del; + ctlr->base.enable = esp_cam_ctlr_dvp_cam_enable; + ctlr->base.start = esp_cam_ctlr_dvp_cam_start; + ctlr->base.stop = esp_cam_ctlr_dvp_cam_stop; + ctlr->base.disable = esp_cam_ctlr_dvp_cam_disable; + ctlr->base.register_event_callbacks = esp_cam_ctlr_dvp_cam_register_event_callbacks; + ctlr->base.get_internal_buffer = esp_cam_ctlr_dvp_cam_get_internal_buffer; + ctlr->base.get_buffer_len = esp_cam_ctlr_get_dvp_cam_frame_buffer_len; + + *ret_handle = &ctlr->base; + + return ESP_OK; + +fail5: + cam_hal_deinit(&ctlr->hal); +fail4: + esp_cam_ctlr_dvp_dma_deinit(&ctlr->dma); +fail3: + if (!config->bk_buffer_dis) { + heap_caps_free(ctlr->backup_buffer); + } +fail2: + s_dvp_declaim_ctlr(config->ctlr_id); +fail1: + heap_caps_free(ctlr); +fail0: + dvp_shared_ctrl_declaim_io_signals(); + return ret; +} diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c new file mode 100644 index 00000000000..4e428b25052 --- /dev/null +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c @@ -0,0 +1,202 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_heap_caps.h" +#include "esp_check.h" +#include "esp_cache.h" +#include "esp_private/esp_cache_private.h" +#include "esp_cam_ctlr_dvp_dma.h" + +#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) + +static const char *TAG = "dvp_gdma"; + +/** + * @brief Configure DMA description + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +static void IRAM_ATTR esp_cam_ctlr_dvp_config_dma_desc(esp_cam_ctlr_dvp_dma_desc_t *desc, uint8_t *buffer, uint32_t size) +{ + size_t n = 0; + + while (size) { + uint32_t node_size = MIN(size, ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE); + + desc[n].dw0.size = node_size; + desc[n].dw0.length = 0; + desc[n].dw0.err_eof = 0; + desc[n].dw0.suc_eof = 0; + desc[n].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + desc[n].buffer = (uint8_t *)buffer; + desc[n].next = &desc[n + 1]; + + size -= node_size; + buffer += node_size; + n++; + } + + desc[n - 1].next = NULL; +} + +/** + * @brief Initialize DVP DMA object + * + * @param dma DVP DMA object pointer + * @param burst_size DVP DMA burst transmission block size + * @param size DVP DMA buffer size + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_size, size_t size) +{ + esp_err_t ret = ESP_OK; + size_t alignment_size; + + gdma_channel_alloc_config_t rx_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_RX, + }; + + ESP_RETURN_ON_ERROR(esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &alignment_size), TAG, "failed to get cache alignment"); + + ESP_RETURN_ON_ERROR(gdma_new_axi_channel(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed"); + + ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed"); + + gdma_strategy_config_t strategy_config = { + .auto_update_desc = false, + .owner_check = true + }; + + ESP_GOTO_ON_ERROR(gdma_apply_strategy(dma->dma_chan, &strategy_config), fail1, TAG, "apply strategy failed"); + // set DMA transfer ability + gdma_transfer_config_t transfer_config = { + .max_data_burst_size = burst_size, + .access_ext_mem = true, + }; + ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed"); + + dma->desc_count = size / ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE; + if (size % ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE) { + dma->desc_count++; + } + dma->size = size; + + ESP_LOGD(TAG, "alignment: 0x%x\n", alignment_size); + dma->desc_size = ALIGN_UP_BY(dma->desc_count * sizeof(esp_cam_ctlr_dvp_dma_desc_t), alignment_size); + + dma->desc = heap_caps_aligned_alloc(alignment_size, dma->desc_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(dma->desc, ESP_ERR_NO_MEM, fail1, TAG, "no mem for DVP DMA descriptor"); + + return ESP_OK; + +fail1: + gdma_disconnect(dma->dma_chan); +fail0: + gdma_del_channel(dma->dma_chan); + return ret; +} + +/** + * @brief De-initialize DVP DMA object + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t esp_cam_ctlr_dvp_dma_deinit(esp_cam_ctlr_dvp_dma_t *dma) +{ + ESP_RETURN_ON_ERROR(gdma_disconnect(dma->dma_chan), TAG, "disconnect dma channel failed"); + ESP_RETURN_ON_ERROR(gdma_del_channel(dma->dma_chan), TAG, "delete dma channel failed"); + + heap_caps_free(dma->desc); + + return ESP_OK; +} + +/** + * @brief Set DVP DMA descriptor address and start engine + * + * @param dma DVP DMA object pointer + * @param buffer DVP DMA buffer pointer + * @param size DVP DMA buffer size + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_start(esp_cam_ctlr_dvp_dma_t *dma, uint8_t *buffer, size_t size) +{ + esp_err_t ret; + + ESP_RETURN_ON_FALSE_ISR(dma, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(dma->size >= size, ESP_ERR_INVALID_ARG, TAG, "input buffer size is out of range"); + + esp_cam_ctlr_dvp_config_dma_desc(dma->desc, buffer, size); + + ret = esp_cache_msync(dma->desc, dma->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); + assert(ret == ESP_OK); + + return gdma_start(dma->dma_chan, (intptr_t)dma->desc); +} + +/** + * @brief Stop DVP DMA engine + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_stop(esp_cam_ctlr_dvp_dma_t *dma) +{ + return gdma_stop(dma->dma_chan); +} + +/** + * @brief Reset DVP DMA FIFO and internal finite state machine + * + * @param dma DVP DMA object pointer + * + * @return + * - ESP_OK on success + * - Others if failed + */ +esp_err_t IRAM_ATTR esp_cam_ctlr_dvp_dma_reset(esp_cam_ctlr_dvp_dma_t *dma) +{ + return gdma_reset(dma->dma_chan); +} + +/** + * @brief Get DMA received data size + * + * @param dma DVP DMA object pointer + * + * @return DMA received data size + */ +size_t IRAM_ATTR esp_cam_ctlr_dvp_dma_get_recv_size(esp_cam_ctlr_dvp_dma_t *dma) +{ + size_t recv_size = 0; + + for (int i = 0; i < dma->desc_count; i++) { + recv_size += dma->desc[i].dw0.length; + if (dma->desc[i].dw0.suc_eof) { + break; + } + } + + return recv_size; +} diff --git a/components/esp_driver_cam/test_apps/.build-test-rules.yml b/components/esp_driver_cam/test_apps/.build-test-rules.yml index 62f5e1aef94..0d419e7609c 100644 --- a/components/esp_driver_cam/test_apps/.build-test-rules.yml +++ b/components/esp_driver_cam/test_apps/.build-test-rules.yml @@ -4,6 +4,12 @@ components/esp_driver_cam/test_apps/csi: depends_components: - esp_driver_cam +components/esp_driver_cam/test_apps/dvp: + disable: + - if: SOC_LCDCAM_CAM_SUPPORTED != 1 + depends_components: + - esp_driver_cam + components/esp_driver_cam/test_apps/isp_dvp: disable: - if: SOC_ISP_DVP_SUPPORTED != 1 diff --git a/components/esp_driver_cam/test_apps/dvp/CMakeLists.txt b/components/esp_driver_cam/test_apps/dvp/CMakeLists.txt new file mode 100644 index 00000000000..d49275de910 --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.16) + +list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") + +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_dvp) diff --git a/components/esp_driver_cam/test_apps/dvp/README.md b/components/esp_driver_cam/test_apps/dvp/README.md new file mode 100644 index 00000000000..909282018f2 --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | diff --git a/components/esp_driver_cam/test_apps/dvp/main/CMakeLists.txt b/components/esp_driver_cam/test_apps/dvp/main/CMakeLists.txt new file mode 100644 index 00000000000..3ad81cd956b --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/main/CMakeLists.txt @@ -0,0 +1,16 @@ +set(srcs "test_app_main.c") + +if(CONFIG_SOC_LCDCAM_CAM_SUPPORTED) + list(APPEND srcs "test_dvp_driver.c") +endif() + +set(priv_requires + unity + esp_driver_cam + esp_psram +) + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES ${priv_requires} + WHOLE_ARCHIVE TRUE) diff --git a/components/esp_driver_cam/test_apps/dvp/main/test_app_main.c b/components/esp_driver_cam/test_apps/dvp/main/test_app_main.c new file mode 100644 index 00000000000..a47ab1a130d --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/main/test_app_main.c @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_heap_caps.h" +#include "sdkconfig.h" + +#define TEST_MEMORY_LEAK_THRESHOLD (400) + +void setUp(void) +{ + unity_utils_record_free_mem(); +} + +void tearDown(void) +{ + unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD); +} + +void app_main(void) +{ + unity_run_menu(); +} diff --git a/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c b/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c new file mode 100644 index 00000000000..4f6b7041e81 --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/main/test_dvp_driver.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "sdkconfig.h" +#include "unity.h" +#include "esp_cam_ctlr_dvp.h" +#include "esp_cam_ctlr.h" + +TEST_CASE("TEST DVP driver allocation", "[DVP]") +{ + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = 800, + .v_res = 640, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .byte_swap_en = false, + .pin_dont_init = true, + }; + esp_cam_ctlr_handle_t handle = NULL; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + + uint8_t *bk_buffer = NULL; + size_t bk_buffer_len = 0; + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer(handle, 1, (const void **)&bk_buffer)); + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); + TEST_ASSERT_NOT_NULL(bk_buffer); + TEST_ASSERT_EQUAL((dvp_config.h_res * dvp_config.v_res * 2), bk_buffer_len); // type RGB565 using 2 byte / pixel + TEST_ESP_OK(esp_cam_ctlr_del(handle)); +} + +TEST_CASE("TEST DVP driver allocation with JPEG input", "[DVP]") +{ + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = 800, + .v_res = 640, + .dma_burst_size = 128, + .byte_swap_en = false, + .pin_dont_init = true, + .pic_format_jpeg = true, + }; + esp_cam_ctlr_handle_t handle = NULL; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + + uint8_t *bk_buffer = NULL; + size_t bk_buffer_len = 0; + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer(handle, 1, (const void **)&bk_buffer)); + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); + TEST_ASSERT_NOT_NULL(bk_buffer); + TEST_ASSERT_EQUAL((dvp_config.h_res * dvp_config.v_res * 1), bk_buffer_len); // type JPEG using 1 byte / pixel + TEST_ESP_OK(esp_cam_ctlr_del(handle)); +} + +TEST_CASE("TEST DVP driver no backup buffer usage", "[DVP]") +{ + esp_cam_ctlr_dvp_config_t dvp_config = { + .ctlr_id = 0, + .clk_src = CAM_CLK_SRC_DEFAULT, + .h_res = 800, + .v_res = 640, + .input_data_color_type = CAM_CTLR_COLOR_RGB565, + .dma_burst_size = 128, + .byte_swap_en = false, + .bk_buffer_dis = true, + .pin_dont_init = true, + }; + esp_cam_ctlr_handle_t handle = NULL; + TEST_ESP_OK(esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, esp_cam_new_dvp_ctlr(&dvp_config, &handle)); + + uint8_t *bk_buffer = NULL; + size_t bk_buffer_len = 0; + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_cam_ctlr_get_frame_buffer(handle, 1, (const void **)&bk_buffer)); + TEST_ESP_OK(esp_cam_ctlr_get_frame_buffer_len(handle, &bk_buffer_len)); + TEST_ASSERT_NULL(bk_buffer); + TEST_ASSERT_EQUAL((dvp_config.h_res * dvp_config.v_res * 2), bk_buffer_len); // out type RGB565 using 2 byte / pixel + TEST_ESP_OK(esp_cam_ctlr_del(handle)); +} diff --git a/components/esp_driver_cam/test_apps/dvp/pytest_dvp.py b/components/esp_driver_cam/test_apps/dvp/pytest_dvp.py new file mode 100644 index 00000000000..139f1c0694b --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/pytest_dvp.py @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_dvp(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults b/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults new file mode 100644 index 00000000000..f02afdd3c69 --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults @@ -0,0 +1,6 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration +# +CONFIG_SPIRAM=y +CONFIG_ESP_TASK_WDT_EN=n +CONFIG_FREERTOS_HZ=1000 diff --git a/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults.esp32p4 b/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults.esp32p4 new file mode 100644 index 00000000000..5fca5fa0805 --- /dev/null +++ b/components/esp_driver_cam/test_apps/dvp/sdkconfig.defaults.esp32p4 @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="esp32p4" +CONFIG_SPIRAM_SPEED_200M=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 750fddce903..573199e54c1 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -260,6 +260,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "ds_hal.c") endif() + if(CONFIG_SOC_LCDCAM_CAM_SUPPORTED) + list(APPEND srcs "cam_hal.c") + endif() + if(CONFIG_SOC_USB_SERIAL_JTAG_SUPPORTED) list(APPEND srcs "usb_serial_jtag_hal.c") endif() diff --git a/components/hal/cam_hal.c b/components/hal/cam_hal.c new file mode 100644 index 00000000000..101cf3bfcbe --- /dev/null +++ b/components/hal/cam_hal.c @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "hal/cam_ll.h" +#include "hal/cam_hal.h" +#include "soc/soc_caps.h" +#include "soc/cam_periph.h" + +/** + * @brief Configure line number to trigger interrupt + * + * @param hal CAM object data pointer + * @param num line number + * + * @return None + */ +static void cam_hal_set_line_int_num(cam_hal_context_t *hal, uint32_t num) +{ + if (num > 0) { + cam_ll_enable_hs_line_int(hal->hw, 1); + cam_ll_set_line_int_num(hal->hw, num); + } else { + cam_ll_enable_hs_line_int(hal->hw, 0); + cam_ll_set_line_int_num(hal->hw, 0); + } +} + +/** + * @brief Configure V-SYNC filter threshold + * + * @param hal CAM object data pointer + * @param num V-SYNC filter threshold + * + * @return None + */ +static void cam_hal_set_vsync_filter_num(cam_hal_context_t *hal, uint32_t num) +{ + if (num > 0) { + cam_ll_enable_vsync_filter(hal->hw, 1); + cam_ll_set_vsync_filter_thres(hal->hw, num); + } else { + cam_ll_enable_vsync_filter(hal->hw, 0); + cam_ll_set_vsync_filter_thres(hal->hw, 0); + } +} + +/** + * @brief Initialize CAM hardware + * + * @param hal CAM object data pointer + * @param config CAM configuration + * + * @return None + */ +void cam_hal_init(cam_hal_context_t *hal, const cam_hal_config_t *config) +{ + memset(hal, 0, sizeof(cam_hal_context_t)); + + hal->hw = CAM_LL_GET_HW(0); + + cam_ll_enable_stop_signal(hal->hw, 0); + cam_ll_swap_dma_data_byte_order(hal->hw, config->byte_swap_en); + cam_ll_reverse_dma_data_bit_order(hal->hw, 0); + cam_ll_enable_vsync_generate_eof(hal->hw, 1); + + cam_hal_set_line_int_num(hal, 0); + cam_hal_set_vsync_filter_num(hal, 0); + + cam_ll_enable_invert_pclk(hal->hw, 0); + cam_ll_set_input_data_width(hal->hw, 8); + cam_ll_enable_invert_de(hal->hw, 0); + cam_ll_enable_invert_vsync(hal->hw, 0); + cam_ll_enable_invert_hsync(hal->hw, 0); + cam_ll_set_vh_de_mode(hal->hw, 0); // Disable vh_de mode default + cam_ll_enable_rgb_yuv_convert(hal->hw, 0); // bypass conv module default +} + +/** + * @brief De-initialize CAM hardware + * + * @note Stop stream before deinit + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_deinit(cam_hal_context_t *hal) +{ + cam_ll_stop(hal->hw); + cam_ll_reset(hal->hw); + cam_ll_fifo_reset(hal->hw); +} + +/** + * @brief Start CAM to receive frame data + * + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_start_streaming(cam_hal_context_t *hal) +{ + cam_ll_reset(hal->hw); + cam_ll_fifo_reset(hal->hw); + + cam_ll_start(hal->hw); +} + +/** + * @brief Stop CAM receiving frame data + * + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_stop_streaming(cam_hal_context_t *hal) +{ + cam_ll_stop(hal->hw); +} diff --git a/components/hal/esp32p4/include/hal/cam_ll.h b/components/hal/esp32p4/include/hal/cam_ll.h new file mode 100644 index 00000000000..a48dba2dc83 --- /dev/null +++ b/components/hal/esp32p4/include/hal/cam_ll.h @@ -0,0 +1,634 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/lcd_cam_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "hal/cam_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CAM_LL_GET_HW(id) (((id) == 0) ? (&LCD_CAM) : NULL) + +#define CAM_LL_CLK_FRAC_DIV_N_MAX 256 // CAM_CLK = CAM_CLK_S / (N + b/a), the N register is 8 bit-width +#define CAM_LL_CLK_FRAC_DIV_AB_MAX 64 // CAM_CLK = CAM_CLK_S / (N + b/a), the a/b register is 6 bit-width + +/** + * @brief Enable the bus clock for CAM module + * + * @param group_id Group ID + * @param enable true to enable, false to disable + */ +static inline void cam_ll_enable_bus_clock(int group_id, bool en) +{ + (void)group_id; + HP_SYS_CLKRST.soc_clk_ctrl3.reg_lcdcam_apb_clk_en = en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance +#define cam_ll_enable_bus_clock(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; cam_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the CAM module + * + * @param group_id Group ID + */ +static inline void cam_ll_reset_register(int group_id) +{ + (void)group_id; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_lcdcam = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_lcdcam = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_RC_ATOMIC_ENV variable in advance +#define cam_ll_reset_register(...) (void)__DECLARE_RCC_RC_ATOMIC_ENV; cam_ll_reset_register(__VA_ARGS__) + +/** + * @brief Enable clock gating + * + * @param group_id Group ID + * @param en True to enable, False to disable + */ +static inline void cam_ll_enable_clk(int group_id, bool en) +{ + HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_en = en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_enable_clk(...) (void)__DECLARE_RCC_ATOMIC_ENV; cam_ll_enable_clk(__VA_ARGS__) + +/** + * @brief Get the clock status for the CAM module + * + * @return True when enabled, false when disabled + */ +static inline bool cam_ll_get_clk_status(int group_id) +{ + (void)group_id; + return HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_get_clk_status(...) (void)__DECLARE_RCC_ATOMIC_ENV; cam_ll_get_clk_status(__VA_ARGS__) + +/** + * @brief Select clock source for CAM peripheral + * + * @param group_id Group ID + * @param src Clock source + */ +static inline void cam_ll_select_clk_src(int group_id, cam_clock_source_t src) +{ + switch (src) { + case CAM_CLK_SRC_XTAL: + HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_src_sel = 0; + break; + case CAM_CLK_SRC_PLL160M: + HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_src_sel = 1; + break; + case CAM_CLK_SRC_APLL: + HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_src_sel = 2; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_select_clk_src(...) (void)__DECLARE_RCC_ATOMIC_ENV; cam_ll_select_clk_src(__VA_ARGS__) + +/** + * @brief Get the CAM source clock type + * + * @param dev CAM register base address + * @param src The pointer to accept the CAM source clock type + */ +static inline void cam_ll_get_clk_src(lcd_cam_dev_t *dev, cam_clock_source_t *src) +{ + switch (HP_SYS_CLKRST.peri_clk_ctrl119.reg_cam_clk_src_sel) { + case 0: + *src = CAM_CLK_SRC_XTAL; + break; + case 1: + *src = CAM_CLK_SRC_PLL160M; + break; + case 2: + *src = CAM_CLK_SRC_APLL; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Set clock coefficient of CAM peripheral + * + * @param group_id Group ID + * @param div_num Integer part of the divider + * @param div_a denominator of the divider + * @param div_b numerator of the divider + */ +__attribute__((always_inline)) +static inline void cam_ll_set_group_clock_coeff(int group_id, int div_num, int div_a, int div_b) +{ + // cam_clk = module_clock_src / (div_num + div_b / div_a) + HAL_ASSERT(div_num >= 2 && div_num < CAM_LL_CLK_FRAC_DIV_N_MAX); + + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl120, reg_cam_clk_div_num, div_num); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl120, reg_cam_clk_div_denominator, div_a); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl120, reg_cam_clk_div_numerator, div_b); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define cam_ll_set_group_clock_coeff(...) (void)__DECLARE_RCC_ATOMIC_ENV; cam_ll_set_group_clock_coeff(__VA_ARGS__) + +/** + * @brief Enable stop signal for CAM peripheral + * + * @param dev CAM register base address + * @param en True to stop when GDMA Rx FIFO is full, False to not stop + */ +static inline void cam_ll_enable_stop_signal(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl.cam_stop_en = en; +} + +/** + * @brief Set vsync filter threshold value + * + * @param dev CAM register base address + * @param value Filter threshold value for CAM_VSYNC_SIGNAL, range [0, 7] + */ +static inline void cam_ll_set_vsync_filter_thres(lcd_cam_dev_t *dev, uint32_t value) +{ + dev->cam_ctrl.cam_vsync_filter_thres = value; +} + +/** + * @brief Enable to generate LCD_CAM_CAM_HS_INT + * + * @param dev CAM register base address + * @param en True to enable to generate LCD_CAM_CAM_HS_INT, False to disable + */ +static inline void cam_ll_enable_hs_line_int(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl.cam_line_int_en = en; +} + +/** + * @brief Enable CAM_VSYNC to generate in_suc_eof + * + * @param dev CAM register base address + * @param en True to enable CAM_VSYNC to generate in_suc_eof, False to use LCD_CAM_CAM_REC_DATA_BYTELEN to control in_suc_eof + */ +static inline void cam_ll_enable_vsync_generate_eof(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl.cam_vs_eof_en = en; +} + +/** + * @brief Enable to swap every two 8-bit input data + * + * @param dev CAM register base address + * @param en True to enable invert, False to disable invert + */ +static inline void cam_ll_enable_8bits_data_invert(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_rgb_yuv.cam_conv_8bits_data_inv = en; +} + +/** + * @brief Enable YUV-RGB converter + * + * @param dev CAM register base address + * @param en True to enable converter, False to disable converter + */ +static inline void cam_ll_enable_rgb_yuv_convert(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_rgb_yuv.cam_conv_enable = en; +} + +/** + * @brief Set convert data line width + * + * @param dev CAM register base address + * @param width data line width (8 or 16) + */ +static inline void cam_ll_set_convert_data_width(lcd_cam_dev_t *dev, uint32_t width) +{ + HAL_ASSERT(width == 8 || width == 16); + dev->cam_rgb_yuv.cam_conv_mode_8bits_on = (width == 8) ? 1 : 0; +} + +/** + * @brief Set the color range of input data + * + * @param dev CAM register base address + * @param range Color range + */ +static inline void cam_ll_set_input_color_range(lcd_cam_dev_t *dev, color_range_t range) +{ + if (range == COLOR_RANGE_LIMIT) { + dev->cam_rgb_yuv.cam_conv_data_in_mode = 0; + } else if (range == COLOR_RANGE_FULL) { + dev->cam_rgb_yuv.cam_conv_data_in_mode = 1; + } +} + +/** + * @brief Set the color range of output data + * + * @param dev CAM register base address + * @param range Color range + */ +static inline void cam_ll_set_output_color_range(lcd_cam_dev_t *dev, color_range_t range) +{ + if (range == COLOR_RANGE_LIMIT) { + dev->cam_rgb_yuv.cam_conv_data_out_mode = 0; + } else if (range == COLOR_RANGE_FULL) { + dev->cam_rgb_yuv.cam_conv_data_out_mode = 1; + } +} + +/** + * @brief Set YUV conversion standard + * + * @param dev CAM register base address + * @param std YUV conversion standard + */ +static inline void cam_ll_set_yuv_convert_std(lcd_cam_dev_t *dev, color_conv_std_rgb_yuv_t std) +{ + if (std == COLOR_CONV_STD_RGB_YUV_BT601) { + dev->cam_rgb_yuv.cam_conv_protocol_mode = 0; + } else if (std == COLOR_CONV_STD_RGB_YUV_BT709) { + dev->cam_rgb_yuv.cam_conv_protocol_mode = 1; + } +} + +/** + * @brief Set the converter mode: RGB565 to YUV + * + * @param dev CAM register base address + * @param yuv_sample YUV sample mode + */ +static inline void cam_ll_set_convert_mode_rgb_to_yuv(lcd_cam_dev_t *dev, color_pixel_yuv_format_t yuv_sample) +{ + dev->cam_rgb_yuv.cam_conv_trans_mode = 1; + dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 3; + switch (yuv_sample) { + case COLOR_PIXEL_YUV422: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 0; + break; + case COLOR_PIXEL_YUV420: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 1; + break; + case COLOR_PIXEL_YUV411: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 2; + break; + default: + abort(); + } +} + +/** + * @brief Set the converter mode: YUV to RGB565 + * + * @param dev CAM register base address + * @param yuv_sample YUV sample mode + */ +static inline void cam_ll_set_convert_mode_yuv_to_rgb(lcd_cam_dev_t *dev, color_pixel_yuv_format_t yuv_sample) +{ + dev->cam_rgb_yuv.cam_conv_trans_mode = 0; + dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 3; + switch (yuv_sample) { + case COLOR_PIXEL_YUV422: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 0; + break; + case COLOR_PIXEL_YUV420: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 1; + break; + case COLOR_PIXEL_YUV411: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 2; + break; + default: + abort(); + } +} + +/** + * @brief Set the converter mode: YUV to YUV + * + * @param dev CAM register base address + * @param src_sample Source YUV sample mode + * @param dst_sample Destination YUV sample mode + */ +static inline void cam_ll_set_convert_mode_yuv_to_yuv(lcd_cam_dev_t *dev, color_pixel_yuv_format_t src_sample, color_pixel_yuv_format_t dst_sample) +{ + HAL_ASSERT(src_sample != dst_sample); + dev->cam_rgb_yuv.cam_conv_trans_mode = 1; + switch (src_sample) { + case COLOR_PIXEL_YUV422: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 0; + break; + case COLOR_PIXEL_YUV420: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 1; + break; + case COLOR_PIXEL_YUV411: + dev->cam_rgb_yuv.cam_conv_yuv_mode = 2; + break; + default: + abort(); + } + switch (dst_sample) { + case COLOR_PIXEL_YUV422: + dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 0; + break; + case COLOR_PIXEL_YUV420: + dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 1; + break; + case COLOR_PIXEL_YUV411: + dev->cam_rgb_yuv.cam_conv_yuv2yuv_mode = 2; + break; + default: + abort(); + } +} + +/** + * @brief Set camera received data byte length + * + * @param dev CAM register base address + * @param length received data byte length, range [0, 0xFFFF] + */ +static inline void cam_ll_set_recv_data_bytelen(lcd_cam_dev_t *dev, uint32_t length) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->cam_ctrl1, cam_rec_data_bytelen, length); +} + +/** + * @brief Set line number to trigger interrupt + * + * @param dev CAM register base address + * @param number line number to trigger hs interrupt, range [0, 0x3F] + */ +static inline void cam_ll_set_line_int_num(lcd_cam_dev_t *dev, uint32_t number) +{ + dev->cam_ctrl1.cam_line_int_num = number; +} + +/** + * @brief Whether to invert the input signal CAM_PCLK + * + * @param dev CAM register base address + * @param en True to invert, False to not invert + */ +static inline void cam_ll_enable_invert_pclk(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl1.cam_clk_inv = en; +} + +/** + * @brief Enable CAM_VSYNC filter function + * + * @param dev CAM register base address + * @param en True to enable, False to bypass + */ +static inline void cam_ll_enable_vsync_filter(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl1.cam_vsync_filter_en = en; +} + +/** + * @brief Set CAM input data width + * + * @param dev CAM register base address + * @param stride 16: The bit number of input data is 9~16. 8: The bit number of input data is 0~8. + */ +static inline void cam_ll_set_input_data_width(lcd_cam_dev_t *dev, uint32_t stride) +{ + switch (stride) { + case 8: + dev->cam_ctrl1.cam_2byte_en = 0; + break; + case 16: + dev->cam_ctrl1.cam_2byte_en = 1; + break; + default: + HAL_ASSERT(false); + break; + } +} + +/** + * @brief Whether to invert CAM_DE + * + * @param dev CAM register base address + * @param en True to invert, False to not invert + */ +static inline void cam_ll_enable_invert_de(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl1.cam_de_inv = en; +} + +/** + * @brief Whether to invert CAM_HSYNC + * + * @param dev CAM register base address + * @param en True to invert, False to not invert + */ +static inline void cam_ll_enable_invert_hsync(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl1.cam_hsync_inv = en; +} + +/** + * @brief Whether to invert CAM_VSYNC + * + * @param dev CAM register base address + * @param en True to invert, False to not invert + */ +static inline void cam_ll_enable_invert_vsync(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl1.cam_vsync_inv = en; +} + +/** + * @brief Enable the mode to control the input control signals + * + * @param dev CAM register base address + * @param mode 1: Input control signals are CAM_DE, CAM_HSYNC and CAM_VSYNC; + * 0: Input control signals are CAM_DE and CAM_VSYNC. CAM_HSYNC and CAM_DE are all 1 the the same time. + */ +static inline void cam_ll_set_vh_de_mode(lcd_cam_dev_t *dev, bool enable) +{ + dev->cam_ctrl1.cam_vh_de_mode_en = enable; +} + +/** + * @brief Get the mode of input control signals + * + * @param dev CAM register base address + * @param en The pointer to accept the vh_de mode status. 1: Input control signals are CAM_DE, CAM_HSYNC and CAM_VSYNC; + * 0: Input control signals are CAM_DE and CAM_VSYNC. CAM_HSYNC and CAM_DE are all 1 the the same time. + */ +static inline void cam_ll_get_vh_de_mode(lcd_cam_dev_t *dev, bool *en) +{ + *en = dev->cam_ctrl1.cam_vh_de_mode_en; +} + +/** + * @brief Set the wire width of CAM output + * + * @param dev CAM register base address + * @param width CAM output wire width + */ +static inline void cam_ll_set_data_wire_width(lcd_cam_dev_t *dev, uint32_t width) +{ + // data line width is same as data stride that set in `cam_ll_set_input_data_width` +} + +/** + * @brief Start the CAM transaction + * + * @param dev CAM register base address + */ +__attribute__((always_inline)) +static inline void cam_ll_start(lcd_cam_dev_t *dev) +{ + dev->cam_ctrl.cam_update_reg = 1; + dev->cam_ctrl1.cam_start = 1; +} + +/** + * @brief Stop the CAM transaction + * + * @param dev CAM register base address + */ +__attribute__((always_inline)) +static inline void cam_ll_stop(lcd_cam_dev_t *dev) +{ + dev->cam_ctrl1.cam_start = 0; + dev->cam_ctrl.cam_update_reg = 1; // self clear +} + +/** + * @brief Whether to reverse the data bit order + * + * @note It acts before the YUV-RGB converter + * + * @param dev CAM register base address + * @param en True to reverse, False to not reverse + */ +__attribute__((always_inline)) +static inline void cam_ll_reverse_dma_data_bit_order(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl.cam_bit_order = en; +} + +/** + * @brief Whether to swap adjacent two bytes + * + * @note This acts before the YUV-RGB converter, mainly to change the data endian. + * {B1,B0},{B3,B2} => {B0,B1}{B2,B3} + * + * @param dev CAM register base address + * @param en True to swap the byte order, False to not swap + */ +__attribute__((always_inline)) +static inline void cam_ll_swap_dma_data_byte_order(lcd_cam_dev_t *dev, bool en) +{ + dev->cam_ctrl.cam_byte_order = en; +} + +/** + * @brief Reset camera module + * + * @param dev CAM register base address + */ +__attribute__((always_inline)) +static inline void cam_ll_reset(lcd_cam_dev_t *dev) +{ + dev->cam_ctrl1.cam_reset = 1; // self clear +} + +/** + * @brief Reset Async RX FIFO + * + * @param dev CAM register base address + */ +__attribute__((always_inline)) +static inline void cam_ll_fifo_reset(lcd_cam_dev_t *dev) +{ + dev->cam_ctrl1.cam_afifo_reset = 1; // self clear +} + +/** + * @brief Enable/disable interrupt by mask + * + * @param dev CAM register base address + * @param mask Interrupt mask + * @param en True to enable interrupt, False to disable interrupt + */ +static inline void cam_ll_enable_interrupt(lcd_cam_dev_t *dev, uint32_t mask, bool en) +{ + if (en) { + dev->lc_dma_int_ena.val |= mask & 0x0c; + } else { + dev->lc_dma_int_ena.val &= ~(mask & 0x0c); + } +} + +/** + * @brief Get interrupt status value + * + * @param dev CAM register base address + * @return Interrupt status value + */ +__attribute__((always_inline)) +static inline uint32_t cam_ll_get_interrupt_status(lcd_cam_dev_t *dev) +{ + return dev->lc_dma_int_st.val & 0x0c; +} + +/** + * @brief Clear interrupt status by mask + * + * @param dev CAM register base address + * @param mask Interrupt status mask + */ +__attribute__((always_inline)) +static inline void cam_ll_clear_interrupt_status(lcd_cam_dev_t *dev, uint32_t mask) +{ + dev->lc_dma_int_clr.val = mask & 0x0c; +} + +/** + * @brief Get address of interrupt status register address + * + * @param dev CAM register base address + * @return Interrupt status register address + */ +static inline volatile void *cam_ll_get_interrupt_status_reg(lcd_cam_dev_t *dev) +{ + return &dev->lc_dma_int_st; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/cam_hal.h b/components/hal/include/hal/cam_hal.h new file mode 100644 index 00000000000..2b1c9229b6c --- /dev/null +++ b/components/hal/include/hal/cam_hal.h @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "hal/cam_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lcd_cam_dev_t cam_dev_t; // CAM SOC layer handle + +/** + * @brief CAM hardware interface object data + */ +typedef struct cam_hal_context { + cam_dev_t *hw; /*!< Beginning address of the CAM peripheral registers. */ +} cam_hal_context_t; + +/** + * @brief CAM HAL driver configuration + */ +typedef struct cam_hal_config { + int port; /*!< CAM port */ + bool byte_swap_en; /*!< CAM enable byte swap */ +} cam_hal_config_t; + +/** + * @brief Initialize CAM hardware + * + * @param hal CAM object data pointer + * @param config CAM configuration + * + * @return None + */ +void cam_hal_init(cam_hal_context_t *hal, const cam_hal_config_t *config); + +/** + * @brief De-initialize CAM hardware + * + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_deinit(cam_hal_context_t *hal); + +/** + * @brief Start CAM to receive frame data + * + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_start_streaming(cam_hal_context_t *hal); + +/** + * @brief Stop CAM receiving frame data + * + * @param hal CAM object data pointer + * + * @return None + */ +void cam_hal_stop_streaming(cam_hal_context_t *hal); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/cam_types.h b/components/hal/include/hal/cam_types.h new file mode 100644 index 00000000000..32e22f22a69 --- /dev/null +++ b/components/hal/include/hal/cam_types.h @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" +#include "hal/color_types.h" +#include "hal/cam_ctlr_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_LCDCAM_CAM_DATA_WIDTH_MAX +#define CAP_DVP_PERIPH_NUM SOC_LCDCAM_CAM_PERIPH_NUM /*!< DVP port number */ +#define CAM_DVP_DATA_SIG_NUM SOC_LCDCAM_CAM_DATA_WIDTH_MAX /*!< DVP data bus width of CAM */ +#else +#define CAP_DVP_PERIPH_NUM 0 /*!< Default value */ +#define CAM_DVP_DATA_SIG_NUM 0 /*!< Default value */ +#endif + +#if SOC_LCDCAM_CAM_SUPPORTED +typedef soc_periph_cam_clk_src_t cam_clock_source_t; /*!< Clock source type of CAM */ +#else +typedef int cam_clock_source_t; /*!< Default type */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 0c3f4ed0bd5..b3a53fb7798 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -156,6 +156,10 @@ if(CONFIG_SOC_PAU_SUPPORTED) list(APPEND srcs "${target_folder}/system_retention_periph.c") endif() +if(CONFIG_SOC_LCDCAM_CAM_SUPPORTED) + list(APPEND srcs "${target_folder}/cam_periph.c") +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${includes} LDFRAGMENTS "linker.lf") diff --git a/components/soc/esp32p4/cam_periph.c b/components/soc/esp32p4/cam_periph.c new file mode 100644 index 00000000000..acecf882726 --- /dev/null +++ b/components/soc/esp32p4/cam_periph.c @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/gpio_sig_map.h" +#include "soc/cam_periph.h" + +const cam_signal_conn_t cam_periph_signals = { + .buses = { + [0] = { + .module = PERIPH_LCD_CAM_MODULE, + .irq_id = ETS_LCD_CAM_INTR_SOURCE, + .data_sigs = { + CAM_DATA_IN_PAD_IN0_IDX, + CAM_DATA_IN_PAD_IN1_IDX, + CAM_DATA_IN_PAD_IN2_IDX, + CAM_DATA_IN_PAD_IN3_IDX, + CAM_DATA_IN_PAD_IN4_IDX, + CAM_DATA_IN_PAD_IN5_IDX, + CAM_DATA_IN_PAD_IN6_IDX, + CAM_DATA_IN_PAD_IN7_IDX, + CAM_DATA_IN_PAD_IN8_IDX, + CAM_DATA_IN_PAD_IN9_IDX, + CAM_DATA_IN_PAD_IN10_IDX, + CAM_DATA_IN_PAD_IN11_IDX, + CAM_DATA_IN_PAD_IN12_IDX, + CAM_DATA_IN_PAD_IN13_IDX, + CAM_DATA_IN_PAD_IN14_IDX, + CAM_DATA_IN_PAD_IN15_IDX, + }, + .hsync_sig = CAM_H_SYNC_PAD_IN_IDX, + .vsync_sig = CAM_V_SYNC_PAD_IN_IDX, + .pclk_sig = CAM_PCLK_PAD_IN_IDX, + .de_sig = CAM_H_ENABLE_PAD_IN_IDX, + .clk_sig = CAM_CLK_PAD_OUT_IDX + } + } +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index ab97a343dad..a3a9280b894 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -43,6 +43,10 @@ config SOC_PCNT_SUPPORTED bool default y +config SOC_LCDCAM_CAM_SUPPORTED + bool + default y + config SOC_MIPI_CSI_SUPPORTED bool default y @@ -1642,3 +1646,15 @@ config SOC_JPEG_DECODE_SUPPORTED config SOC_JPEG_ENCODE_SUPPORTED bool default y + +config SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV + bool + default y + +config SOC_LCDCAM_CAM_PERIPH_NUM + int + default 1 + +config SOC_LCDCAM_CAM_DATA_WIDTH_MAX + int + default 16 diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 5679247b501..570239f07b7 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -373,6 +373,23 @@ typedef enum { LCD_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ } soc_periph_lcd_clk_src_t; +//////////////////////////////////////////////////LCD/////////////////////////////////////////////////////////////////// + +/** + * @brief Array initializer for all supported clock sources of CAM + */ +#define SOC_CAM_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL} + +/** + * @brief Type of CAM clock source + */ +typedef enum { + CAM_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */ + CAM_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + CAM_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */ + CAM_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default choice */ +} soc_periph_cam_clk_src_t; + /////////////////////////////////////////////////MIPI/////////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index e277bd82974..e9487cd2c5d 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -29,6 +29,7 @@ #define SOC_GPTIMER_SUPPORTED 1 #define SOC_PCNT_SUPPORTED 1 // #define SOC_LCDCAM_SUPPORTED 1 // TODO: IDF-7465 +#define SOC_LCDCAM_CAM_SUPPORTED 1 #define SOC_MIPI_CSI_SUPPORTED 1 #define SOC_MIPI_DSI_SUPPORTED 1 #define SOC_MCPWM_SUPPORTED 1 @@ -538,8 +539,8 @@ /*-------------------------- TOUCH SENSOR CAPS -------------------------------*/ #define SOC_TOUCH_SENSOR_VERSION (3) // Hardware version of touch sensor #define SOC_TOUCH_SENSOR_NUM (14) // Touch available channel number. Actually there are 15 Touch channels, but channel 14 is not pinned out, limit to 14 channels -#define SOC_TOUCH_PROXIMITY_CHANNEL_NUM (3) // Sopport touch proximity channel number. -#define SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED (1) // Sopport touch proximity channel measure done interrupt type. +#define SOC_TOUCH_PROXIMITY_CHANNEL_NUM (3) // Support touch proximity channel number. +#define SOC_TOUCH_PROXIMITY_MEAS_DONE_SUPPORTED (1) // Support touch proximity channel measure done interrupt type. #define SOC_TOUCH_SAMPLER_NUM (3) // The sampler number in total, each sampler can be used to sample on one frequency /*-------------------------- TWAI CAPS ---------------------------------------*/ @@ -657,3 +658,8 @@ #define SOC_JPEG_CODEC_SUPPORTED (1) #define SOC_JPEG_DECODE_SUPPORTED (1) #define SOC_JPEG_ENCODE_SUPPORTED (1) + +/*--------------------------- CAM ---------------------------------*/ +#define SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV (1) +#define SOC_LCDCAM_CAM_PERIPH_NUM (1U) +#define SOC_LCDCAM_CAM_DATA_WIDTH_MAX (16U) diff --git a/components/soc/include/soc/cam_periph.h b/components/soc/include/soc/cam_periph.h new file mode 100644 index 00000000000..e71f973656e --- /dev/null +++ b/components/soc/include/soc/cam_periph.h @@ -0,0 +1,35 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "soc/periph_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_LCDCAM_CAM_SUPPORTED +typedef struct { + struct { + const periph_module_t module; + const int irq_id; + const int data_sigs[SOC_LCDCAM_CAM_DATA_WIDTH_MAX]; + const int hsync_sig; + const int vsync_sig; + const int pclk_sig; + const int de_sig; + const int clk_sig; + } buses[SOC_LCDCAM_CAM_PERIPH_NUM]; +} cam_signal_conn_t; + +extern const cam_signal_conn_t cam_periph_signals; +#endif // SOC_LCDCAM_CAM_SUPPORTED + +#ifdef __cplusplus +} +#endif From c349247236a34cd8aa199c637f816e574b4e04f1 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 31 May 2024 19:08:46 +0800 Subject: [PATCH 230/548] refactor(emac): use heap component API to allocate cached aligned DMA buffer --- components/esp_eth/CMakeLists.txt | 5 +--- .../esp_eth/src/mac/esp_eth_mac_esp_dma.c | 30 +++++++------------ 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/components/esp_eth/CMakeLists.txt b/components/esp_eth/CMakeLists.txt index a3499c07465..132f01a3011 100644 --- a/components/esp_eth/CMakeLists.txt +++ b/components/esp_eth/CMakeLists.txt @@ -68,8 +68,5 @@ if(CONFIG_ETH_ENABLED) if(CONFIG_ETH_USE_SPI_ETHERNET) idf_component_optional_requires(PUBLIC esp_driver_spi) endif() - idf_component_optional_requires(PRIVATE esp_netif esp_pm) - if(CONFIG_SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE) - idf_component_optional_requires(PRIVATE esp_mm) - endif() + idf_component_optional_requires(PRIVATE esp_netif esp_pm esp_mm) endif() diff --git a/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c b/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c index d5eba402c8f..73f5ee40c7c 100644 --- a/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c +++ b/components/esp_eth/src/mac/esp_eth_mac_esp_dma.c @@ -5,13 +5,11 @@ */ #include "esp_check.h" -#include "esp_dma_utils.h" #include "sdkconfig.h" #include "soc/soc_caps.h" -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" -#endif #include "hal/emac_hal.h" +#include "esp_heap_caps.h" #include "esp_private/eth_mac_esp_dma.h" #define ETH_CRC_LENGTH (4) @@ -41,8 +39,7 @@ static const char *TAG = "esp.emac.dma"; -struct emac_esp_dma_t -{ +struct emac_esp_dma_t { emac_hal_context_t hal; uint32_t tx_desc_flags; uint32_t rx_desc_flags; @@ -58,14 +55,14 @@ typedef struct { uint32_t magic_id; #endif // NDEBUG uint32_t copy_len; -}__attribute__((packed)) emac_esp_dma_auto_buf_info_t; +} __attribute__((packed)) emac_esp_dma_auto_buf_info_t; void emac_esp_dma_reset(emac_esp_dma_handle_t emac_esp_dma) { /* reset DMA descriptors */ emac_esp_dma->rx_desc = (eth_dma_rx_descriptor_t *)(emac_esp_dma->descriptors); emac_esp_dma->tx_desc = (eth_dma_tx_descriptor_t *)(emac_esp_dma->descriptors + - sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM); + sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM); /* init rx chain */ for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { /* Set Own bit of the Rx descriptor Status: DMA */ @@ -227,7 +224,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp buffs_cnt--; ptr = *(++buffs); lastlen = *(++lengths); - /* There is only limited available space in the current descriptor, use it all */ + /* There is only limited available space in the current descriptor, use it all */ } else { /* copy data from uplayer stack buffer */ memcpy((void *)(desc_iter->Buffer1Addr + (CONFIG_ETH_DMA_BUFFER_SIZE - avail_len)), ptr, avail_len); @@ -236,7 +233,7 @@ uint32_t emac_esp_dma_transmit_multiple_buf_frame(emac_esp_dma_handle_t emac_esp /* If lastlen is not zero, input buff will be fragmented over multiple descriptors */ if (lastlen > 0) { ptr += avail_len; - /* Input buff fully fits the descriptor, move to the next input buff */ + /* Input buff fully fits the descriptor, move to the next input buff */ } else { /* Update processed input buffers info */ buffs_cnt--; @@ -386,7 +383,7 @@ uint32_t emac_esp_dma_receive_frame(emac_esp_dma_handle_t emac_esp_dma, uint8_t if (copy_len) { eth_dma_rx_descriptor_t *desc_iter = emac_esp_dma->rx_desc; - while(copy_len > CONFIG_ETH_DMA_BUFFER_SIZE) { + while (copy_len > CONFIG_ETH_DMA_BUFFER_SIZE) { DMA_CACHE_INVALIDATE(desc_iter->Buffer1Addr, CONFIG_ETH_DMA_BUFFER_SIZE); memcpy(buf, (void *)(desc_iter->Buffer1Addr), CONFIG_ETH_DMA_BUFFER_SIZE); buf += CONFIG_ETH_DMA_BUFFER_SIZE; @@ -449,7 +446,7 @@ esp_err_t emac_esp_del_dma(emac_esp_dma_handle_t emac_esp_dma) return ESP_OK; } -esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_handle_t *ret_handle) +esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t *config, emac_esp_dma_handle_t *ret_handle) { esp_err_t ret = ESP_OK; *ret_handle = NULL; @@ -459,20 +456,15 @@ esp_err_t emac_esp_new_dma(const emac_esp_dma_config_t* config, emac_esp_dma_han /* alloc memory for ethernet dma descriptor */ uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); - esp_dma_mem_info_t dma_mem_info = { - .extra_heap_caps = MALLOC_CAP_INTERNAL, - .dma_alignment_bytes = 4, - }; - esp_dma_capable_calloc(1, desc_size, &dma_mem_info, (void*)&emac_esp_dma->descriptors, NULL); - + emac_esp_dma->descriptors = heap_caps_aligned_calloc(4, 1, desc_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(emac_esp_dma->descriptors, ESP_ERR_NO_MEM, err, TAG, "no mem for descriptors"); /* alloc memory for ethernet dma buffer */ for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - esp_dma_capable_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, &dma_mem_info, (void*)&emac_esp_dma->rx_buf[i], NULL); + emac_esp_dma->rx_buf[i] = heap_caps_aligned_calloc(4, 1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(emac_esp_dma->rx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for RX DMA buffers"); } for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - esp_dma_capable_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, &dma_mem_info, (void*)&emac_esp_dma->tx_buf[i], NULL); + emac_esp_dma->tx_buf[i] = heap_caps_aligned_calloc(4, 1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(emac_esp_dma->tx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for TX DMA buffers"); } emac_hal_init(&emac_esp_dma->hal); From bbc44b486ec83c29d3a2e01efacf881f0689da7a Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Tue, 23 Apr 2024 20:11:32 +0800 Subject: [PATCH 231/548] feat(gdma): add GDMA support for ESP32C5 MP --- .../bootloader_support/src/bootloader_mem.c | 4 +- .../test_apps/dma/main/test_gdma.c | 38 +- components/hal/CMakeLists.txt | 6 + .../esp32c5/beta3/include/hal/gdma_beta3_ll.h | 630 ++++++++++++++++++ components/hal/esp32c5/include/hal/gdma_ll.h | 630 +----------------- .../hal/esp32c5/mp/include/hal/ahb_dma_ll.h | 619 +++++++++++++++++ .../hal/esp32p4/include/hal/ahb_dma_ll.h | 44 +- components/soc/esp32c5/beta3/gdma_periph.c | 2 +- components/soc/esp32c5/mp/gdma_periph.c | 143 ++++ .../mp/include/soc/Kconfig.soc_caps.in | 28 + .../esp32c5/mp/include/soc/ahb_dma_struct.h | 199 ++---- .../soc/esp32c5/mp/include/soc/gdma_channel.h | 30 + .../soc/esp32c5/mp/include/soc/reg_base.h | 1 + .../mp/include/soc/retention_periph_defs.h | 68 ++ .../soc/esp32c5/mp/include/soc/soc_caps.h | 20 +- .../soc/esp32c5/mp/ld/esp32c5.peripherals.ld | 1 + components/soc/esp32c6/gdma_periph.c | 2 +- components/soc/esp32h2/gdma_periph.c | 2 +- .../soc/esp32p4/include/soc/ahb_dma_struct.h | 10 +- components/soc/include/soc/gdma_periph.h | 2 +- 20 files changed, 1683 insertions(+), 796 deletions(-) create mode 100644 components/hal/esp32c5/beta3/include/hal/gdma_beta3_ll.h create mode 100644 components/hal/esp32c5/mp/include/hal/ahb_dma_ll.h create mode 100644 components/soc/esp32c5/mp/gdma_periph.c create mode 100644 components/soc/esp32c5/mp/include/soc/retention_periph_defs.h diff --git a/components/bootloader_support/src/bootloader_mem.c b/components/bootloader_support/src/bootloader_mem.c index e329d304050..2af61961e10 100644 --- a/components/bootloader_support/src/bootloader_mem.c +++ b/components/bootloader_support/src/bootloader_mem.c @@ -16,7 +16,7 @@ #include "hal/apm_hal.h" #endif -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION // TODO: IDF-8615 Remove the workaround when APM supported on C5! +#if CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8615 Remove the workaround when APM supported on C5! #include "soc/hp_apm_reg.h" #include "soc/lp_apm_reg.h" #include "soc/lp_apm0_reg.h" @@ -36,7 +36,7 @@ void bootloader_init_mem(void) apm_hal_apm_ctrl_filter_enable_all(false); #endif -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION // TODO: IDF-8615 Remove the workaround when APM supported on C5! +#if CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8615 Remove the workaround when APM supported on C5! // disable apm filter REG_WRITE(LP_APM_FUNC_CTRL_REG, 0); REG_WRITE(LP_APM0_FUNC_CTRL_REG, 0); diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_gdma.c index 03c46b1bbf0..d68d3a2ea0b 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma.c @@ -19,6 +19,8 @@ #include "hal/cache_ll.h" #include "hal/cache_hal.h" #include "esp_cache.h" +#include "esp_memory_utils.h" +#include "soc/soc_caps.h" TEST_CASE("GDMA channel allocation", "[GDMA]") { @@ -183,7 +185,7 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); size_t alignment = MAX(sram_alignment, 8); uint8_t *src_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + uint8_t *dst_buf = heap_caps_aligned_calloc(alignment, 1, 384, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); TEST_ASSERT_NOT_NULL(src_buf); TEST_ASSERT_NOT_NULL(dst_buf); dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; @@ -199,6 +201,19 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl // do write-back for the source data because it's in the cache TEST_ESP_OK(esp_cache_msync((void *)src_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); } +#if SOC_DMA_CAN_ACCESS_FLASH + const char *src_string = "GDMA can fetch data from MSPI Flash"; + size_t src_string_len = strlen(src_string); + TEST_ASSERT_TRUE(esp_ptr_in_drom(src_string)); + + // Only gonna copy length = src_string_len, set the character after to be 0xFF + // So that we can check if the copied length is correct + dst_data[128 + src_string_len] = 0xFF; + if (sram_alignment) { + // do write-back for the dst data because it's in the cache + TEST_ESP_OK(esp_cache_msync((void *)dst_data, 256, ESP_CACHE_MSYNC_FLAG_DIR_C2M)); + } +#endif #ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR dma_descriptor_align8_t *tx_descs_nc = (dma_descriptor_align8_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(tx_descs)); @@ -219,11 +234,23 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl tx_descs_nc[1].dw0.size = 64; tx_descs_nc[1].dw0.length = 64; tx_descs_nc[1].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; +#if !SOC_DMA_CAN_ACCESS_FLASH tx_descs_nc[1].dw0.suc_eof = 1; tx_descs_nc[1].next = NULL; +#else + tx_descs_nc[1].dw0.suc_eof = 0; + tx_descs_nc[1].next = &tx_descs[2]; + + tx_descs_nc[2].buffer = (void *)src_string; + tx_descs_nc[2].dw0.size = src_string_len + 1; // +1 for '\0' + tx_descs_nc[2].dw0.length = src_string_len; + tx_descs_nc[2].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + tx_descs_nc[2].dw0.suc_eof = 1; + tx_descs_nc[2].next = NULL; +#endif rx_descs_nc->buffer = dst_data; - rx_descs_nc->dw0.size = 128; + rx_descs_nc->dw0.size = 256; rx_descs_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; rx_descs_nc->dw0.suc_eof = 1; rx_descs_nc->next = NULL; @@ -235,7 +262,7 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl if (sram_alignment) { // the destination data are not reflected to the cache, so do an invalidate to ask the cache load new data - TEST_ESP_OK(esp_cache_msync((void *)dst_data, 128, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); + TEST_ESP_OK(esp_cache_msync((void *)dst_data, 256, ESP_CACHE_MSYNC_FLAG_DIR_M2C)); } // check the DMA descriptor write-back feature @@ -245,6 +272,11 @@ static void test_gdma_m2m_mode(gdma_channel_handle_t tx_chan, gdma_channel_handl for (int i = 0; i < 128; i++) { TEST_ASSERT_EQUAL(i, dst_data[i]); } +#if SOC_DMA_CAN_ACCESS_FLASH + TEST_ASSERT_TRUE(dst_data[128 + src_string_len] == 0xFF); + dst_data[128 + src_string_len] = '\0'; + TEST_ASSERT_TRUE(strcmp(src_string, (const char *)((uint32_t)dst_data + 128)) == 0); +#endif free((void *)src_buf); free((void *)dst_buf); vSemaphoreDelete(done_sem); diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 750fddce903..f131925f15c 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -7,6 +7,12 @@ set(includes "platform_port/include") # because of the "include_next" directive used by the efuse_hal.h if(NOT ${target} STREQUAL "linux") list(APPEND includes "${target}/include") + + if(CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION) + list(APPEND includes "${target}/beta3/include") + elseif(CONFIG_IDF_TARGET_ESP32C5_MP_VERSION) + list(APPEND includes "${target}/mp/include") + endif() endif() list(APPEND includes "include") diff --git a/components/hal/esp32c5/beta3/include/hal/gdma_beta3_ll.h b/components/hal/esp32c5/beta3/include/hal/gdma_beta3_ll.h new file mode 100644 index 00000000000..5a9260eea19 --- /dev/null +++ b/components/hal/esp32c5/beta3/include/hal/gdma_beta3_ll.h @@ -0,0 +1,630 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include /* Required for NULL constant */ +#include +#include +#include "soc/soc_caps.h" +#include "hal/gdma_types.h" +#include "soc/gdma_struct.h" +#include "soc/gdma_reg.h" +#include "soc/soc_etm_source.h" +#include "soc/pcr_struct.h" +#include "soc/retention_periph_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id) (SLEEP_RETENTION_MODULE_GDMA_CH0 << (SOC_GDMA_PAIRS_PER_GROUP_MAX * group_id) << pair_id) + +#define GDMA_LL_GET_HW(id) (((id) == 0) ? (&GDMA) : NULL) + +#define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5] + +#define GDMA_LL_RX_EVENT_MASK (0x7F) +#define GDMA_LL_TX_EVENT_MASK (0x3F) + +// any "dummy" peripheral ID can be used for M2M mode +#define GDMA_LL_M2M_FREE_PERIPH_ID_MASK (0xFC32) +#define GDMA_LL_INVALID_PERIPH_ID (0x3F) + +#define GDMA_LL_EVENT_TX_FIFO_UDF (1<<5) +#define GDMA_LL_EVENT_TX_FIFO_OVF (1<<4) +#define GDMA_LL_EVENT_RX_FIFO_UDF (1<<6) +#define GDMA_LL_EVENT_RX_FIFO_OVF (1<<5) +#define GDMA_LL_EVENT_TX_TOTAL_EOF (1<<3) +#define GDMA_LL_EVENT_RX_DESC_EMPTY (1<<4) +#define GDMA_LL_EVENT_TX_DESC_ERROR (1<<2) +#define GDMA_LL_EVENT_RX_DESC_ERROR (1<<3) +#define GDMA_LL_EVENT_TX_EOF (1<<1) +#define GDMA_LL_EVENT_TX_DONE (1<<0) +#define GDMA_LL_EVENT_RX_ERR_EOF (1<<2) +#define GDMA_LL_EVENT_RX_SUC_EOF (1<<1) +#define GDMA_LL_EVENT_RX_DONE (1<<0) + +#define GDMA_LL_AHB_GROUP_START_ID 0 // AHB GDMA group ID starts from 0 +#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups +#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group + +#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ + (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH1, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH2, \ + }}}[group][chan][event] + +#define GDMA_LL_RX_ETM_EVENT_TABLE(group, chan, event) \ + (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH0, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH1, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH2, \ + }}}[group][chan][event] + +#define GDMA_LL_TX_ETM_TASK_TABLE(group, chan, task) \ + (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH0, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH1, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH2, \ + }}}[group][chan][task] + +#define GDMA_LL_RX_ETM_TASK_TABLE(group, chan, task) \ + (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH0, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH1, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH2, \ + }}}[group][chan][task] + +// Workaround for C5-beta3 only, it can not vectorized channels into an array in gdma_struct.h +#define GDMA_LL_CHANNEL_GET_REG_ADDR(dev, ch) ((volatile gdma_chn_reg_t*[]){&dev->channel0, &dev->channel1, &dev->channel2}[(ch)]) + +#define GDMA_LL_AHB_DESC_ALIGNMENT 4 + +///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.gdma_conf.gdma_clk_en = enable; +} + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.gdma_conf.gdma_rst_en = 1; + PCR.gdma_conf.gdma_rst_en = 0; +} + +/** + * @brief Force enable register clock + */ +static inline void gdma_ll_force_enable_reg_clock(gdma_dev_t *dev, bool enable) +{ + dev->misc_conf.clk_en = enable; +} + +///////////////////////////////////// RX ///////////////////////////////////////// +/** + * @brief Get DMA RX channel interrupt status word + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_rx_get_interrupt_status(gdma_dev_t *dev, uint32_t channel, bool raw) +{ + if (raw) { + return dev->in_intr[channel].raw.val; + } else { + return dev->in_intr[channel].st.val; + } +} + +/** + * @brief Enable DMA RX channel interrupt + */ +static inline void gdma_ll_rx_enable_interrupt(gdma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) +{ + if (enable) { + dev->in_intr[channel].ena.val |= mask; + } else { + dev->in_intr[channel].ena.val &= ~mask; + } +} + +/** + * @brief Clear DMA RX channel interrupt + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_clear_interrupt_status(gdma_dev_t *dev, uint32_t channel, uint32_t mask) +{ + dev->in_intr[channel].clr.val = mask; +} + +/** + * @brief Get DMA RX channel interrupt status register address + */ +static inline volatile void *gdma_ll_rx_get_interrupt_status_reg(gdma_dev_t *dev, uint32_t channel) +{ + return (volatile void *)(&dev->in_intr[channel].st); +} + +/** + * @brief Enable DMA RX channel to check the owner bit in the descriptor, disabled by default + */ +static inline void gdma_ll_rx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_conf1.in_check_owner = enable; +} + +/** + * @brief Enable DMA RX channel burst reading data, disabled by default + */ +static inline void gdma_ll_rx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_conf0.in_data_burst_en = enable; +} + +/** + * @brief Enable DMA RX channel burst reading descriptor link, disabled by default + */ +static inline void gdma_ll_rx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_conf0.indscr_burst_en = enable; +} + +/** + * @brief Reset DMA RX channel FSM and FIFO pointer + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_reset_channel(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_conf0.in_rst = 1; + ch->in.in_conf0.in_rst = 0; +} + +/** + * @brief Check if DMA RX FIFO is full + * @param fifo_level only supports level 1 + */ +static inline bool gdma_ll_rx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.infifo_status.val & 0x01; +} + +/** + * @brief Check if DMA RX FIFO is empty + * @param fifo_level only supports level 1 + */ +static inline bool gdma_ll_rx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.infifo_status.val & 0x02; +} + +/** + * @brief Get number of bytes in RX FIFO + * @param fifo_level only supports level 1 + */ +static inline uint32_t gdma_ll_rx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.infifo_status.infifo_cnt; +} + +/** + * @brief Pop data from DMA RX FIFO + */ +static inline uint32_t gdma_ll_rx_pop_data(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_pop.infifo_pop = 1; + return ch->in.in_pop.infifo_rdata; +} + +/** + * @brief Set the descriptor link base address for RX channel + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_link.inlink_addr = addr; +} + +/** + * @brief Start dealing with RX descriptors + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_start(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_link.inlink_start = 1; +} + +/** + * @brief Stop dealing with RX descriptors + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_stop(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_link.inlink_stop = 1; +} + +/** + * @brief Restart a new inlink right after the last descriptor + */ +__attribute__((always_inline)) +static inline void gdma_ll_rx_restart(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_link.inlink_restart = 1; +} + +/** + * @brief Enable DMA RX to return the address of current descriptor when receives error + */ +static inline void gdma_ll_rx_enable_auto_return(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_link.inlink_auto_ret = enable; +} + +/** + * @brief Check if DMA RX descriptor FSM is in IDLE state + */ +static inline bool gdma_ll_rx_is_desc_fsm_idle(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.in_link.inlink_park; +} + +/** + * @brief Get RX success EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_rx_get_success_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.in_suc_eof_des_addr.val; +} + +/** + * @brief Get RX error EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_rx_get_error_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.in_err_eof_des_addr.val; +} + +/** + * @brief Get the pre-fetched RX descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_rx_get_prefetched_desc_addr(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->in.in_dscr.val; +} + +/** + * @brief Set priority for DMA RX channel + */ +static inline void gdma_ll_rx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_pri.rx_pri = prio; +} + +/** + * @brief Connect DMA RX channel to a given peripheral + */ +static inline void gdma_ll_rx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_peri_sel.peri_in_sel = periph_id; + ch->in.in_conf0.mem_trans_en = (periph == GDMA_TRIG_PERIPH_M2M); +} + +/** + * @brief Disconnect DMA RX channel from peripheral + */ +static inline void gdma_ll_rx_disconnect_from_periph(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_peri_sel.peri_in_sel = GDMA_LL_INVALID_PERIPH_ID; + ch->in.in_conf0.mem_trans_en = false; +} + +/** + * @brief Whether to enable the ETM subsystem for RX channel + * + * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. + */ +static inline void gdma_ll_rx_enable_etm_task(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->in.in_conf0.in_etm_en = enable; +} + +///////////////////////////////////// TX ///////////////////////////////////////// +/** + * @brief Get DMA TX channel interrupt status word + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_tx_get_interrupt_status(gdma_dev_t *dev, uint32_t channel, bool raw) +{ + if (raw) { + return dev->out_intr[channel].raw.val; + } else { + return dev->out_intr[channel].st.val; + } +} + +/** + * @brief Enable DMA TX channel interrupt + */ +static inline void gdma_ll_tx_enable_interrupt(gdma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) +{ + if (enable) { + dev->out_intr[channel].ena.val |= mask; + } else { + dev->out_intr[channel].ena.val &= ~mask; + } +} + +/** + * @brief Clear DMA TX channel interrupt + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_clear_interrupt_status(gdma_dev_t *dev, uint32_t channel, uint32_t mask) +{ + dev->out_intr[channel].clr.val = mask; +} + +/** + * @brief Get DMA TX channel interrupt status register address + */ +static inline volatile void *gdma_ll_tx_get_interrupt_status_reg(gdma_dev_t *dev, uint32_t channel) +{ + return (volatile void *)(&dev->out_intr[channel].st); +} + +/** + * @brief Enable DMA TX channel to check the owner bit in the descriptor, disabled by default + */ +static inline void gdma_ll_tx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf1.out_check_owner = enable; +} + +/** + * @brief Enable DMA TX channel burst sending data, disabled by default + */ +static inline void gdma_ll_tx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.out_data_burst_en = enable; +} + +/** + * @brief Enable DMA TX channel burst reading descriptor link, disabled by default + */ +static inline void gdma_ll_tx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.outdscr_burst_en = enable; +} + +/** + * @brief Set TX channel EOF mode + */ +static inline void gdma_ll_tx_set_eof_mode(gdma_dev_t *dev, uint32_t channel, uint32_t mode) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.out_eof_mode = mode; +} + +/** + * @brief Enable DMA TX channel automatic write results back to descriptor after all data has been sent out, disabled by default + */ +static inline void gdma_ll_tx_enable_auto_write_back(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.out_auto_wrback = enable; +} + +/** + * @brief Reset DMA TX channel FSM and FIFO pointer + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_reset_channel(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.out_rst = 1; + ch->out.out_conf0.out_rst = 0; +} + +/** + * @brief Check if DMA TX FIFO is full + * @param fifo_level only supports level 1 + */ +static inline bool gdma_ll_tx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.outfifo_status.val & 0x01; +} + +/** + * @brief Check if DMA TX FIFO is empty + * @param fifo_level only supports level 1 + */ +static inline bool gdma_ll_tx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.outfifo_status.val & 0x02; +} + +/** + * @brief Get number of bytes in TX FIFO + * @param fifo_level only supports level 1 + */ +static inline uint32_t gdma_ll_tx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.outfifo_status.outfifo_cnt; +} + +/** + * @brief Push data into DMA TX FIFO + */ +static inline void gdma_ll_tx_push_data(gdma_dev_t *dev, uint32_t channel, uint32_t data) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_push.outfifo_wdata = data; + ch->out.out_push.outfifo_push = 1; +} + +/** + * @brief Set the descriptor link base address for TX channel + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_link.outlink_addr = addr; +} + +/** + * @brief Start dealing with TX descriptors + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_start(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_link.outlink_start = 1; +} + +/** + * @brief Stop dealing with TX descriptors + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_stop(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_link.outlink_stop = 1; +} + +/** + * @brief Restart a new outlink right after the last descriptor + */ +__attribute__((always_inline)) +static inline void gdma_ll_tx_restart(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_link.outlink_restart = 1; +} + +/** + * @brief Check if DMA TX descriptor FSM is in IDLE state + */ +static inline bool gdma_ll_tx_is_desc_fsm_idle(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.out_link.outlink_park; +} + +/** + * @brief Get TX EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_tx_get_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.out_eof_des_addr.val; +} + +/** + * @brief Get the pre-fetched TX descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t gdma_ll_tx_get_prefetched_desc_addr(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + return ch->out.out_dscr.val; +} + +/** + * @brief Set priority for DMA TX channel + */ +static inline void gdma_ll_tx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_pri.tx_pri = prio; +} + +/** + * @brief Connect DMA TX channel to a given peripheral + */ +static inline void gdma_ll_tx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) +{ + (void)periph; + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_peri_sel.peri_out_sel = periph_id; +} + +/** + * @brief Disconnect DMA TX channel from peripheral + */ +static inline void gdma_ll_tx_disconnect_from_periph(gdma_dev_t *dev, uint32_t channel) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_peri_sel.peri_out_sel = GDMA_LL_INVALID_PERIPH_ID; +} + +/** + * @brief Whether to enable the ETM subsystem for TX channel + * + * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. + */ +static inline void gdma_ll_tx_enable_etm_task(gdma_dev_t *dev, uint32_t channel, bool enable) +{ + volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); + ch->out.out_conf0.out_etm_en = enable; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32c5/include/hal/gdma_ll.h b/components/hal/esp32c5/include/hal/gdma_ll.h index 55c89bb81f4..4acd0bf59a2 100644 --- a/components/hal/esp32c5/include/hal/gdma_ll.h +++ b/components/hal/esp32c5/include/hal/gdma_ll.h @@ -5,629 +5,9 @@ */ #pragma once -#include /* Required for NULL constant */ -#include -#include -#include "soc/soc_caps.h" -#if SOC_GDMA_SUPPORTED // TODO: [ESP32C5] IDF-8710 -#include "hal/gdma_types.h" -#include "soc/gdma_struct.h" -#include "soc/gdma_reg.h" -#include "soc/soc_etm_source.h" -#include "soc/pcr_struct.h" -#include "soc/retention_periph_defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id) (SLEEP_RETENTION_MODULE_GDMA_CH0 << (SOC_GDMA_PAIRS_PER_GROUP_MAX * group_id) << pair_id) - -#define GDMA_LL_GET_HW(id) (((id) == 0) ? (&GDMA) : NULL) - -#define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5] - -#define GDMA_LL_RX_EVENT_MASK (0x7F) -#define GDMA_LL_TX_EVENT_MASK (0x3F) - -// any "dummy" peripheral ID can be used for M2M mode -#define GDMA_LL_M2M_FREE_PERIPH_ID_MASK (0xFC32) -#define GDMA_LL_INVALID_PERIPH_ID (0x3F) - -#define GDMA_LL_EVENT_TX_FIFO_UDF (1<<5) -#define GDMA_LL_EVENT_TX_FIFO_OVF (1<<4) -#define GDMA_LL_EVENT_RX_FIFO_UDF (1<<6) -#define GDMA_LL_EVENT_RX_FIFO_OVF (1<<5) -#define GDMA_LL_EVENT_TX_TOTAL_EOF (1<<3) -#define GDMA_LL_EVENT_RX_DESC_EMPTY (1<<4) -#define GDMA_LL_EVENT_TX_DESC_ERROR (1<<2) -#define GDMA_LL_EVENT_RX_DESC_ERROR (1<<3) -#define GDMA_LL_EVENT_TX_EOF (1<<1) -#define GDMA_LL_EVENT_TX_DONE (1<<0) -#define GDMA_LL_EVENT_RX_ERR_EOF (1<<2) -#define GDMA_LL_EVENT_RX_SUC_EOF (1<<1) -#define GDMA_LL_EVENT_RX_DONE (1<<0) - -#define GDMA_LL_AHB_GROUP_START_ID 0 // AHB GDMA group ID starts from 0 -#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups -#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group - -#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ - (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ - }, \ - { \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH1, \ - }, \ - { \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH2, \ - }}}[group][chan][event] - -#define GDMA_LL_RX_ETM_EVENT_TABLE(group, chan, event) \ - (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH0, \ - }, \ - { \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH1, \ - }, \ - { \ - [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH2, \ - }}}[group][chan][event] - -#define GDMA_LL_TX_ETM_TASK_TABLE(group, chan, task) \ - (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ - [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH0, \ - }, \ - { \ - [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH1, \ - }, \ - { \ - [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH2, \ - }}}[group][chan][task] - -#define GDMA_LL_RX_ETM_TASK_TABLE(group, chan, task) \ - (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ - [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH0, \ - }, \ - { \ - [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH1, \ - }, \ - { \ - [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH2, \ - }}}[group][chan][task] - -// TODO: Workaround for C5-beta3 only. C5-mp can still vectorized channels into an array in gdma_struct.h -#define GDMA_LL_CHANNEL_GET_REG_ADDR(dev, ch) ((volatile gdma_chn_reg_t*[]){&dev->channel0, &dev->channel1, &dev->channel2}[(ch)]) - -#define GDMA_LL_AHB_DESC_ALIGNMENT 4 - -///////////////////////////////////// Common ///////////////////////////////////////// - -/** - * @brief Enable the bus clock for the DMA module - */ -static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) -{ - (void)group_id; - PCR.gdma_conf.gdma_clk_en = enable; -} - -/** - * @brief Reset the DMA module - */ -static inline void gdma_ll_reset_register(int group_id) -{ - (void)group_id; - PCR.gdma_conf.gdma_rst_en = 1; - PCR.gdma_conf.gdma_rst_en = 0; -} - -/** - * @brief Force enable register clock - */ -static inline void gdma_ll_force_enable_reg_clock(gdma_dev_t *dev, bool enable) -{ - dev->misc_conf.clk_en = enable; -} - -///////////////////////////////////// RX ///////////////////////////////////////// -/** - * @brief Get DMA RX channel interrupt status word - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_rx_get_interrupt_status(gdma_dev_t *dev, uint32_t channel, bool raw) -{ - if (raw) { - return dev->in_intr[channel].raw.val; - } else { - return dev->in_intr[channel].st.val; - } -} - -/** - * @brief Enable DMA RX channel interrupt - */ -static inline void gdma_ll_rx_enable_interrupt(gdma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) -{ - if (enable) { - dev->in_intr[channel].ena.val |= mask; - } else { - dev->in_intr[channel].ena.val &= ~mask; - } -} - -/** - * @brief Clear DMA RX channel interrupt - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_clear_interrupt_status(gdma_dev_t *dev, uint32_t channel, uint32_t mask) -{ - dev->in_intr[channel].clr.val = mask; -} - -/** - * @brief Get DMA RX channel interrupt status register address - */ -static inline volatile void *gdma_ll_rx_get_interrupt_status_reg(gdma_dev_t *dev, uint32_t channel) -{ - return (volatile void *)(&dev->in_intr[channel].st); -} - -/** - * @brief Enable DMA RX channel to check the owner bit in the descriptor, disabled by default - */ -static inline void gdma_ll_rx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_conf1.in_check_owner = enable; -} - -/** - * @brief Enable DMA RX channel burst reading data, disabled by default - */ -static inline void gdma_ll_rx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_conf0.in_data_burst_en = enable; -} - -/** - * @brief Enable DMA RX channel burst reading descriptor link, disabled by default - */ -static inline void gdma_ll_rx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_conf0.indscr_burst_en = enable; -} - -/** - * @brief Reset DMA RX channel FSM and FIFO pointer - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_reset_channel(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_conf0.in_rst = 1; - ch->in.in_conf0.in_rst = 0; -} - -/** - * @brief Check if DMA RX FIFO is full - * @param fifo_level only supports level 1 - */ -static inline bool gdma_ll_rx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.infifo_status.val & 0x01; -} - -/** - * @brief Check if DMA RX FIFO is empty - * @param fifo_level only supports level 1 - */ -static inline bool gdma_ll_rx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.infifo_status.val & 0x02; -} - -/** - * @brief Get number of bytes in RX FIFO - * @param fifo_level only supports level 1 - */ -static inline uint32_t gdma_ll_rx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.infifo_status.infifo_cnt; -} - -/** - * @brief Pop data from DMA RX FIFO - */ -static inline uint32_t gdma_ll_rx_pop_data(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_pop.infifo_pop = 1; - return ch->in.in_pop.infifo_rdata; -} - -/** - * @brief Set the descriptor link base address for RX channel - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_link.inlink_addr = addr; -} - -/** - * @brief Start dealing with RX descriptors - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_start(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_link.inlink_start = 1; -} - -/** - * @brief Stop dealing with RX descriptors - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_stop(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_link.inlink_stop = 1; -} - -/** - * @brief Restart a new inlink right after the last descriptor - */ -__attribute__((always_inline)) -static inline void gdma_ll_rx_restart(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_link.inlink_restart = 1; -} - -/** - * @brief Enable DMA RX to return the address of current descriptor when receives error - */ -static inline void gdma_ll_rx_enable_auto_return(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_link.inlink_auto_ret = enable; -} - -/** - * @brief Check if DMA RX descriptor FSM is in IDLE state - */ -static inline bool gdma_ll_rx_is_desc_fsm_idle(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.in_link.inlink_park; -} - -/** - * @brief Get RX success EOF descriptor's address - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_rx_get_success_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.in_suc_eof_des_addr.val; -} - -/** - * @brief Get RX error EOF descriptor's address - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_rx_get_error_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.in_err_eof_des_addr.val; -} - -/** - * @brief Get the pre-fetched RX descriptor's address - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_rx_get_prefetched_desc_addr(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->in.in_dscr.val; -} - -/** - * @brief Set priority for DMA RX channel - */ -static inline void gdma_ll_rx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_pri.rx_pri = prio; -} - -/** - * @brief Connect DMA RX channel to a given peripheral - */ -static inline void gdma_ll_rx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_peri_sel.peri_in_sel = periph_id; - ch->in.in_conf0.mem_trans_en = (periph == GDMA_TRIG_PERIPH_M2M); -} - -/** - * @brief Disconnect DMA RX channel from peripheral - */ -static inline void gdma_ll_rx_disconnect_from_periph(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_peri_sel.peri_in_sel = GDMA_LL_INVALID_PERIPH_ID; - ch->in.in_conf0.mem_trans_en = false; -} - -/** - * @brief Whether to enable the ETM subsystem for RX channel - * - * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. - */ -static inline void gdma_ll_rx_enable_etm_task(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->in.in_conf0.in_etm_en = enable; -} - -///////////////////////////////////// TX ///////////////////////////////////////// -/** - * @brief Get DMA TX channel interrupt status word - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_tx_get_interrupt_status(gdma_dev_t *dev, uint32_t channel, bool raw) -{ - if (raw) { - return dev->out_intr[channel].raw.val; - } else { - return dev->out_intr[channel].st.val; - } -} - -/** - * @brief Enable DMA TX channel interrupt - */ -static inline void gdma_ll_tx_enable_interrupt(gdma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) -{ - if (enable) { - dev->out_intr[channel].ena.val |= mask; - } else { - dev->out_intr[channel].ena.val &= ~mask; - } -} - -/** - * @brief Clear DMA TX channel interrupt - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_clear_interrupt_status(gdma_dev_t *dev, uint32_t channel, uint32_t mask) -{ - dev->out_intr[channel].clr.val = mask; -} - -/** - * @brief Get DMA TX channel interrupt status register address - */ -static inline volatile void *gdma_ll_tx_get_interrupt_status_reg(gdma_dev_t *dev, uint32_t channel) -{ - return (volatile void *)(&dev->out_intr[channel].st); -} - -/** - * @brief Enable DMA TX channel to check the owner bit in the descriptor, disabled by default - */ -static inline void gdma_ll_tx_enable_owner_check(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf1.out_check_owner = enable; -} - -/** - * @brief Enable DMA TX channel burst sending data, disabled by default - */ -static inline void gdma_ll_tx_enable_data_burst(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.out_data_burst_en = enable; -} - -/** - * @brief Enable DMA TX channel burst reading descriptor link, disabled by default - */ -static inline void gdma_ll_tx_enable_descriptor_burst(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.outdscr_burst_en = enable; -} - -/** - * @brief Set TX channel EOF mode - */ -static inline void gdma_ll_tx_set_eof_mode(gdma_dev_t *dev, uint32_t channel, uint32_t mode) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.out_eof_mode = mode; -} - -/** - * @brief Enable DMA TX channel automatic write results back to descriptor after all data has been sent out, disabled by default - */ -static inline void gdma_ll_tx_enable_auto_write_back(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.out_auto_wrback = enable; -} - -/** - * @brief Reset DMA TX channel FSM and FIFO pointer - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_reset_channel(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.out_rst = 1; - ch->out.out_conf0.out_rst = 0; -} - -/** - * @brief Check if DMA TX FIFO is full - * @param fifo_level only supports level 1 - */ -static inline bool gdma_ll_tx_is_fifo_full(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.outfifo_status.val & 0x01; -} - -/** - * @brief Check if DMA TX FIFO is empty - * @param fifo_level only supports level 1 - */ -static inline bool gdma_ll_tx_is_fifo_empty(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.outfifo_status.val & 0x02; -} - -/** - * @brief Get number of bytes in TX FIFO - * @param fifo_level only supports level 1 - */ -static inline uint32_t gdma_ll_tx_get_fifo_bytes(gdma_dev_t *dev, uint32_t channel, uint32_t fifo_level) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.outfifo_status.outfifo_cnt; -} - -/** - * @brief Push data into DMA TX FIFO - */ -static inline void gdma_ll_tx_push_data(gdma_dev_t *dev, uint32_t channel, uint32_t data) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_push.outfifo_wdata = data; - ch->out.out_push.outfifo_push = 1; -} - -/** - * @brief Set the descriptor link base address for TX channel - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_set_desc_addr(gdma_dev_t *dev, uint32_t channel, uint32_t addr) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_link.outlink_addr = addr; -} - -/** - * @brief Start dealing with TX descriptors - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_start(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_link.outlink_start = 1; -} - -/** - * @brief Stop dealing with TX descriptors - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_stop(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_link.outlink_stop = 1; -} - -/** - * @brief Restart a new outlink right after the last descriptor - */ -__attribute__((always_inline)) -static inline void gdma_ll_tx_restart(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_link.outlink_restart = 1; -} - -/** - * @brief Check if DMA TX descriptor FSM is in IDLE state - */ -static inline bool gdma_ll_tx_is_desc_fsm_idle(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.out_link.outlink_park; -} - -/** - * @brief Get TX EOF descriptor's address - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_tx_get_eof_desc_addr(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.out_eof_des_addr.val; -} - -/** - * @brief Get the pre-fetched TX descriptor's address - */ -__attribute__((always_inline)) -static inline uint32_t gdma_ll_tx_get_prefetched_desc_addr(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - return ch->out.out_dscr.val; -} - -/** - * @brief Set priority for DMA TX channel - */ -static inline void gdma_ll_tx_set_priority(gdma_dev_t *dev, uint32_t channel, uint32_t prio) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_pri.tx_pri = prio; -} - -/** - * @brief Connect DMA TX channel to a given peripheral - */ -static inline void gdma_ll_tx_connect_to_periph(gdma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) -{ - (void)periph; - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_peri_sel.peri_out_sel = periph_id; -} - -/** - * @brief Disconnect DMA TX channel from peripheral - */ -static inline void gdma_ll_tx_disconnect_from_periph(gdma_dev_t *dev, uint32_t channel) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_peri_sel.peri_out_sel = GDMA_LL_INVALID_PERIPH_ID; -} - -/** - * @brief Whether to enable the ETM subsystem for TX channel - * - * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. - */ -static inline void gdma_ll_tx_enable_etm_task(gdma_dev_t *dev, uint32_t channel, bool enable) -{ - volatile gdma_chn_reg_t *ch = (volatile gdma_chn_reg_t *)GDMA_LL_CHANNEL_GET_REG_ADDR(dev, channel); - ch->out.out_conf0.out_etm_en = enable; -} - -#ifdef __cplusplus -} +#include "sdkconfig.h" +#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION +#include "hal/gdma_beta3_ll.h" +#else +#include "hal/ahb_dma_ll.h" #endif - -#endif // SOC_GDMA_SUPPORTED diff --git a/components/hal/esp32c5/mp/include/hal/ahb_dma_ll.h b/components/hal/esp32c5/mp/include/hal/ahb_dma_ll.h new file mode 100644 index 00000000000..39ecb083b7e --- /dev/null +++ b/components/hal/esp32c5/mp/include/hal/ahb_dma_ll.h @@ -0,0 +1,619 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include /* Required for NULL constant */ +#include +#include +#include "soc/soc_caps.h" +#include "hal/gdma_types.h" +#include "soc/ahb_dma_struct.h" +#include "soc/ahb_dma_reg.h" +#include "soc/soc_etm_source.h" +#include "soc/pcr_struct.h" +#include "soc/retention_periph_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GDMA_CH_RETENTION_GET_MODULE_ID(group_id, pair_id) (SLEEP_RETENTION_MODULE_GDMA_CH0 << (SOC_GDMA_PAIRS_PER_GROUP_MAX * group_id) << pair_id) + +#define AHB_DMA_LL_GET_HW(id) (((id) == 0) ? (&AHB_DMA) : NULL) + +#define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5] + +#define GDMA_LL_RX_EVENT_MASK (0x7F) +#define GDMA_LL_TX_EVENT_MASK (0x3F) + +// any "dummy" peripheral ID can be used for M2M mode +#define AHB_DMA_LL_M2M_FREE_PERIPH_ID_MASK (0xFC31) +#define AHB_DMA_LL_INVALID_PERIPH_ID (0x3F) + +#define GDMA_LL_EVENT_TX_FIFO_UDF (1<<5) +#define GDMA_LL_EVENT_TX_FIFO_OVF (1<<4) +#define GDMA_LL_EVENT_RX_FIFO_UDF (1<<6) +#define GDMA_LL_EVENT_RX_FIFO_OVF (1<<5) +#define GDMA_LL_EVENT_TX_TOTAL_EOF (1<<3) +#define GDMA_LL_EVENT_RX_DESC_EMPTY (1<<4) +#define GDMA_LL_EVENT_TX_DESC_ERROR (1<<2) +#define GDMA_LL_EVENT_RX_DESC_ERROR (1<<3) +#define GDMA_LL_EVENT_TX_EOF (1<<1) +#define GDMA_LL_EVENT_TX_DONE (1<<0) +#define GDMA_LL_EVENT_RX_ERR_EOF (1<<2) +#define GDMA_LL_EVENT_RX_SUC_EOF (1<<1) +#define GDMA_LL_EVENT_RX_DONE (1<<0) + +#define GDMA_LL_AHB_GROUP_START_ID 0 // AHB GDMA group ID starts from 0 +#define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups +#define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group + +#define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ + (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH1, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH2, \ + }}}[group][chan][event] + +#define GDMA_LL_RX_ETM_EVENT_TABLE(group, chan, event) \ + (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH0, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH1, \ + }, \ + { \ + [GDMA_ETM_EVENT_EOF] = GDMA_EVT_IN_SUC_EOF_CH2, \ + }}}[group][chan][event] + +#define GDMA_LL_TX_ETM_TASK_TABLE(group, chan, task) \ + (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH0, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH1, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_OUT_START_CH2, \ + }}}[group][chan][task] + +#define GDMA_LL_RX_ETM_TASK_TABLE(group, chan, task) \ + (uint32_t[1][3][GDMA_ETM_TASK_MAX]){{{ \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH0, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH1, \ + }, \ + { \ + [GDMA_ETM_TASK_START] = GDMA_TASK_IN_START_CH2, \ + }}}[group][chan][task] + +#define GDMA_LL_AHB_DESC_ALIGNMENT 4 + +///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.gdma_conf.gdma_clk_en = enable; +} + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.gdma_conf.gdma_rst_en = 1; + PCR.gdma_conf.gdma_rst_en = 0; +} + +/** + * @brief Force enable register clock + */ +static inline void ahb_dma_ll_force_enable_reg_clock(ahb_dma_dev_t *dev, bool enable) +{ + dev->misc_conf.clk_en = enable; +} + +/** + * @brief Disable priority arbitration + * + * @param dev DMA register base address + * @param dis True to disable, false to enable + */ +static inline void ahb_dma_ll_disable_prio_arb(ahb_dma_dev_t *dev, bool dis) +{ + dev->misc_conf.arb_pri_dis = dis; +} + +/** + * @brief Reset DMA FSM + * + * @param dev DMA register base address + */ +static inline void ahb_dma_ll_reset_fsm(ahb_dma_dev_t *dev) +{ + dev->misc_conf.ahbm_rst_inter = 1; + dev->misc_conf.ahbm_rst_inter = 0; +} + +/** + * @brief Preset valid memory range for AHB-DMA + * + * @param dev DMA register base address + */ +static inline void ahb_dma_ll_set_default_memory_range(ahb_dma_dev_t *dev) +{ + // AHB-DMA can access L2MEM, L2ROM, MSPI Flash, MSPI PSRAM + dev->intr_mem_start_addr.val = 0x40800000; + dev->intr_mem_end_addr.val = 0x44000000; +} + +///////////////////////////////////// RX ///////////////////////////////////////// +/** + * @brief Get DMA RX channel interrupt status word + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_rx_get_interrupt_status(ahb_dma_dev_t *dev, uint32_t channel, bool raw) +{ + if (raw) { + return dev->in_intr[channel].raw.val; + } else { + return dev->in_intr[channel].st.val; + } +} + +/** + * @brief Enable DMA RX channel interrupt + */ +static inline void ahb_dma_ll_rx_enable_interrupt(ahb_dma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) +{ + if (enable) { + dev->in_intr[channel].ena.val |= mask; + } else { + dev->in_intr[channel].ena.val &= ~mask; + } +} + +/** + * @brief Clear DMA RX channel interrupt + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_clear_interrupt_status(ahb_dma_dev_t *dev, uint32_t channel, uint32_t mask) +{ + dev->in_intr[channel].clr.val = mask; +} + +/** + * @brief Get DMA RX channel interrupt status register address + */ +static inline volatile void *ahb_dma_ll_rx_get_interrupt_status_reg(ahb_dma_dev_t *dev, uint32_t channel) +{ + return (volatile void *)(&dev->in_intr[channel].st); +} + +/** + * @brief Enable DMA RX channel to check the owner bit in the descriptor, disabled by default + */ +static inline void ahb_dma_ll_rx_enable_owner_check(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].in.in_conf1.in_check_owner_chn = enable; +} + +/** + * @brief Enable DMA RX channel burst reading data, disabled by default + */ +static inline void ahb_dma_ll_rx_enable_data_burst(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + // dev->channel[channel].in.in_conf0.in_data_burst_mode_sel_chn = enable; // single/incr4/incr8/incr16 +} + +/** + * @brief Enable DMA RX channel burst reading descriptor link, disabled by default + */ +static inline void ahb_dma_ll_rx_enable_descriptor_burst(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].in.in_conf0.indscr_burst_en_chn = enable; +} + +/** + * @brief Reset DMA RX channel FSM and FIFO pointer + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_reset_channel(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_conf0.in_rst_chn = 1; + dev->channel[channel].in.in_conf0.in_rst_chn = 0; +} + +/** + * @brief Check if DMA RX FIFO is full + * @param fifo_level only supports level 1 + */ +static inline bool ahb_dma_ll_rx_is_fifo_full(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].in.infifo_status.val & 0x01; +} + +/** + * @brief Check if DMA RX FIFO is empty + * @param fifo_level only supports level 1 + */ +static inline bool ahb_dma_ll_rx_is_fifo_empty(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].in.infifo_status.val & 0x02; +} + +/** + * @brief Get number of bytes in RX FIFO + * @param fifo_level only supports level 1 + */ +static inline uint32_t ahb_dma_ll_rx_get_fifo_bytes(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].in.infifo_status.infifo_cnt_chn; +} + +/** + * @brief Pop data from DMA RX FIFO + */ +static inline uint32_t ahb_dma_ll_rx_pop_data(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_pop.infifo_pop_chn = 1; + return dev->channel[channel].in.in_pop.infifo_rdata_chn; +} + +/** + * @brief Set the descriptor link base address for RX channel + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_set_desc_addr(ahb_dma_dev_t *dev, uint32_t channel, uint32_t addr) +{ + dev->in_link_addr[channel].inlink_addr_chn = addr; +} + +/** + * @brief Start dealing with RX descriptors + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_start(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_link.inlink_start_chn = 1; +} + +/** + * @brief Stop dealing with RX descriptors + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_stop(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_link.inlink_stop_chn = 1; +} + +/** + * @brief Restart a new inlink right after the last descriptor + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_rx_restart(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_link.inlink_restart_chn = 1; +} + +/** + * @brief Enable DMA RX to return the address of current descriptor when receives error + */ +static inline void ahb_dma_ll_rx_enable_auto_return(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].in.in_link.inlink_auto_ret_chn = enable; +} + +/** + * @brief Check if DMA RX descriptor FSM is in IDLE state + */ +static inline bool ahb_dma_ll_rx_is_desc_fsm_idle(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].in.in_link.inlink_park_chn; +} + +/** + * @brief Get RX success EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_rx_get_success_eof_desc_addr(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].in.in_suc_eof_des_addr.val; +} + +/** + * @brief Get RX error EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_rx_get_error_eof_desc_addr(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].in.in_err_eof_des_addr.val; +} + +/** + * @brief Get the pre-fetched RX descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_rx_get_prefetched_desc_addr(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].in.in_dscr.val; +} + +/** + * @brief Set priority for DMA RX channel + */ +static inline void ahb_dma_ll_rx_set_priority(ahb_dma_dev_t *dev, uint32_t channel, uint32_t prio) +{ + dev->channel[channel].in.in_pri.rx_pri_chn = prio; +} + +/** + * @brief Connect DMA RX channel to a given peripheral + */ +static inline void ahb_dma_ll_rx_connect_to_periph(ahb_dma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) +{ + dev->channel[channel].in.in_peri_sel.peri_in_sel_chn = periph_id; + dev->channel[channel].in.in_conf0.mem_trans_en_chn = (periph == GDMA_TRIG_PERIPH_M2M); +} + +/** + * @brief Disconnect DMA RX channel from peripheral + */ +static inline void ahb_dma_ll_rx_disconnect_from_periph(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].in.in_peri_sel.peri_in_sel_chn = AHB_DMA_LL_INVALID_PERIPH_ID; + dev->channel[channel].in.in_conf0.mem_trans_en_chn = false; +} + +/** + * @brief Whether to enable the ETM subsystem for RX channel + * + * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. + */ +static inline void ahb_dma_ll_rx_enable_etm_task(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].in.in_conf0.in_etm_en_chn = enable; +} + +///////////////////////////////////// TX ///////////////////////////////////////// +/** + * @brief Get DMA TX channel interrupt status word + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_tx_get_interrupt_status(ahb_dma_dev_t *dev, uint32_t channel, bool raw) +{ + if (raw) { + return dev->out_intr[channel].raw.val; + } else { + return dev->out_intr[channel].st.val; + } +} + +/** + * @brief Enable DMA TX channel interrupt + */ +static inline void ahb_dma_ll_tx_enable_interrupt(ahb_dma_dev_t *dev, uint32_t channel, uint32_t mask, bool enable) +{ + if (enable) { + dev->out_intr[channel].ena.val |= mask; + } else { + dev->out_intr[channel].ena.val &= ~mask; + } +} + +/** + * @brief Clear DMA TX channel interrupt + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_clear_interrupt_status(ahb_dma_dev_t *dev, uint32_t channel, uint32_t mask) +{ + dev->out_intr[channel].clr.val = mask; +} + +/** + * @brief Get DMA TX channel interrupt status register address + */ +static inline volatile void *ahb_dma_ll_tx_get_interrupt_status_reg(ahb_dma_dev_t *dev, uint32_t channel) +{ + return (volatile void *)(&dev->out_intr[channel].st); +} + +/** + * @brief Enable DMA TX channel to check the owner bit in the descriptor, disabled by default + */ +static inline void ahb_dma_ll_tx_enable_owner_check(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].out.out_conf1.out_check_owner_chn = enable; +} + +/** + * @brief Enable DMA TX channel burst sending data, disabled by default + */ +static inline void ahb_dma_ll_tx_enable_data_burst(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + // dev->channel[channel].out.out_conf0.out_data_burst_mode_sel_chn = enable; +} + +/** + * @brief Enable DMA TX channel burst reading descriptor link, disabled by default + */ +static inline void ahb_dma_ll_tx_enable_descriptor_burst(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].out.out_conf0.outdscr_burst_en_chn = enable; +} + +/** + * @brief Set TX channel EOF mode + */ +static inline void ahb_dma_ll_tx_set_eof_mode(ahb_dma_dev_t *dev, uint32_t channel, uint32_t mode) +{ + dev->channel[channel].out.out_conf0.out_eof_mode_chn = mode; +} + +/** + * @brief Enable DMA TX channel automatic write results back to descriptor after all data has been sent out, disabled by default + */ +static inline void ahb_dma_ll_tx_enable_auto_write_back(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].out.out_conf0.out_auto_wrback_chn = enable; +} + +/** + * @brief Reset DMA TX channel FSM and FIFO pointer + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_reset_channel(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].out.out_conf0.out_rst_chn = 1; + dev->channel[channel].out.out_conf0.out_rst_chn = 0; +} + +/** + * @brief Check if DMA TX FIFO is full + * @param fifo_level only supports level 1 + */ +static inline bool ahb_dma_ll_tx_is_fifo_full(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].out.outfifo_status.val & 0x01; +} + +/** + * @brief Check if DMA TX FIFO is empty + * @param fifo_level only supports level 1 + */ +static inline bool ahb_dma_ll_tx_is_fifo_empty(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].out.outfifo_status.val & 0x02; +} + +/** + * @brief Get number of bytes in TX FIFO + * @param fifo_level only supports level 1 + */ +static inline uint32_t ahb_dma_ll_tx_get_fifo_bytes(ahb_dma_dev_t *dev, uint32_t channel, uint32_t fifo_level) +{ + return dev->channel[channel].out.outfifo_status.outfifo_cnt_chn; +} + +/** + * @brief Push data into DMA TX FIFO + */ +static inline void ahb_dma_ll_tx_push_data(ahb_dma_dev_t *dev, uint32_t channel, uint32_t data) +{ + dev->channel[channel].out.out_push.outfifo_wdata_chn = data; + dev->channel[channel].out.out_push.outfifo_push_chn = 1; +} + +/** + * @brief Set the descriptor link base address for TX channel + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_set_desc_addr(ahb_dma_dev_t *dev, uint32_t channel, uint32_t addr) +{ + dev->out_link_addr[channel].outlink_addr_chn = addr; +} + +/** + * @brief Start dealing with TX descriptors + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_start(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].out.out_link.outlink_start_chn = 1; +} + +/** + * @brief Stop dealing with TX descriptors + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_stop(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].out.out_link.outlink_stop_chn = 1; +} + +/** + * @brief Restart a new outlink right after the last descriptor + */ +__attribute__((always_inline)) +static inline void ahb_dma_ll_tx_restart(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].out.out_link.outlink_restart_chn = 1; +} + +/** + * @brief Check if DMA TX descriptor FSM is in IDLE state + */ +static inline bool ahb_dma_ll_tx_is_desc_fsm_idle(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].out.out_link.outlink_park_chn; +} + +/** + * @brief Get TX EOF descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_tx_get_eof_desc_addr(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].out.out_eof_des_addr.val; +} + +/** + * @brief Get the pre-fetched TX descriptor's address + */ +__attribute__((always_inline)) +static inline uint32_t ahb_dma_ll_tx_get_prefetched_desc_addr(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->channel[channel].out.out_dscr.val; +} + +/** + * @brief Set priority for DMA TX channel + */ +static inline void ahb_dma_ll_tx_set_priority(ahb_dma_dev_t *dev, uint32_t channel, uint32_t prio) +{ + dev->channel[channel].out.out_pri.tx_pri_chn = prio; +} + +/** + * @brief Connect DMA TX channel to a given peripheral + */ +static inline void ahb_dma_ll_tx_connect_to_periph(ahb_dma_dev_t *dev, uint32_t channel, gdma_trigger_peripheral_t periph, int periph_id) +{ + (void)periph; + dev->channel[channel].out.out_peri_sel.peri_out_sel_chn = periph_id; +} + +/** + * @brief Disconnect DMA TX channel from peripheral + */ +static inline void ahb_dma_ll_tx_disconnect_from_periph(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->channel[channel].out.out_peri_sel.peri_out_sel_chn = AHB_DMA_LL_INVALID_PERIPH_ID; +} + +/** + * @brief Whether to enable the ETM subsystem for TX channel + * + * @note When ETM_EN is 1, only ETM tasks can be used to configure the transfer direction and enable the channel. + */ +static inline void ahb_dma_ll_tx_enable_etm_task(ahb_dma_dev_t *dev, uint32_t channel, bool enable) +{ + dev->channel[channel].out.out_conf0.out_etm_en_chn = enable; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/ahb_dma_ll.h b/components/hal/esp32p4/include/hal/ahb_dma_ll.h index acf76923e04..383062c995c 100644 --- a/components/hal/esp32p4/include/hal/ahb_dma_ll.h +++ b/components/hal/esp32p4/include/hal/ahb_dma_ll.h @@ -530,8 +530,8 @@ static inline void ahb_dma_ll_tx_enable_etm_task(ahb_dma_dev_t *dev, uint32_t ch */ static inline void ahb_dma_ll_tx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) { - dev->out_crc[channel].crc_clear.out_crc_clear_chn_reg = 1; - dev->out_crc[channel].crc_clear.out_crc_clear_chn_reg = 0; + dev->out_crc_arb[channel].crc_clear.out_crc_clear_chn_reg = 1; + dev->out_crc_arb[channel].crc_clear.out_crc_clear_chn_reg = 0; } /** @@ -540,7 +540,7 @@ static inline void ahb_dma_ll_tx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) static inline void ahb_dma_ll_tx_crc_set_width(ahb_dma_dev_t *dev, uint32_t channel, uint32_t width) { HAL_ASSERT(width <= 32); - dev->out_crc[channel].crc_width.tx_crc_width_chn = (width - 1) / 8; + dev->out_crc_arb[channel].crc_width.tx_crc_width_chn = (width - 1) / 8; } /** @@ -548,7 +548,7 @@ static inline void ahb_dma_ll_tx_crc_set_width(ahb_dma_dev_t *dev, uint32_t chan */ static inline void ahb_dma_ll_tx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t channel, uint32_t value) { - dev->out_crc[channel].crc_init_data.out_crc_init_data_chn = value; + dev->out_crc_arb[channel].crc_init_data.out_crc_init_data_chn = value; } /** @@ -556,7 +556,7 @@ static inline void ahb_dma_ll_tx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t */ static inline uint32_t ahb_dma_ll_tx_crc_get_result(ahb_dma_dev_t *dev, uint32_t channel) { - return dev->out_crc[channel].crc_final_result.out_crc_final_result_chn; + return dev->out_crc_arb[channel].crc_final_result.out_crc_final_result_chn; } /** @@ -564,8 +564,8 @@ static inline uint32_t ahb_dma_ll_tx_crc_get_result(ahb_dma_dev_t *dev, uint32_t */ static inline void ahb_dma_ll_tx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t channel) { - dev->out_crc[channel].crc_width.tx_crc_latch_flag_chn = 1; - dev->out_crc[channel].crc_width.tx_crc_latch_flag_chn = 0; + dev->out_crc_arb[channel].crc_width.tx_crc_latch_flag_chn = 1; + dev->out_crc_arb[channel].crc_width.tx_crc_latch_flag_chn = 0; } /** @@ -574,14 +574,14 @@ static inline void ahb_dma_ll_tx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t c static inline void ahb_dma_ll_tx_crc_set_lfsr_data_mask(ahb_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) { - dev->out_crc[channel].crc_en_addr.tx_crc_en_addr_chn = crc_bit; - dev->out_crc[channel].crc_en_wr_data.tx_crc_en_wr_data_chn = lfsr_mask; - dev->out_crc[channel].crc_data_en_addr.tx_crc_data_en_addr_chn = crc_bit; + dev->out_crc_arb[channel].crc_en_addr.tx_crc_en_addr_chn = crc_bit; + dev->out_crc_arb[channel].crc_en_wr_data.tx_crc_en_wr_data_chn = lfsr_mask; + dev->out_crc_arb[channel].crc_data_en_addr.tx_crc_data_en_addr_chn = crc_bit; if (reverse_data_mask) { // "& 0xff" because the hardware only support 8-bit data data_mask = hal_utils_bitwise_reverse8(data_mask & 0xFF); } - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->out_crc[channel].crc_data_en_wr_data, tx_crc_data_en_wr_data_chn, data_mask); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->out_crc_arb[channel].crc_data_en_wr_data, tx_crc_data_en_wr_data_chn, data_mask); } ///////////////////////////////////// CRC-RX ///////////////////////////////////////// @@ -591,8 +591,8 @@ static inline void ahb_dma_ll_tx_crc_set_lfsr_data_mask(ahb_dma_dev_t *dev, uint */ static inline void ahb_dma_ll_rx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) { - dev->in_crc[channel].crc_clear.in_crc_clear_chn_reg = 1; - dev->in_crc[channel].crc_clear.in_crc_clear_chn_reg = 0; + dev->in_crc_arb[channel].crc_clear.in_crc_clear_chn_reg = 1; + dev->in_crc_arb[channel].crc_clear.in_crc_clear_chn_reg = 0; } /** @@ -601,7 +601,7 @@ static inline void ahb_dma_ll_rx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) static inline void ahb_dma_ll_rx_crc_set_width(ahb_dma_dev_t *dev, uint32_t channel, uint32_t width) { HAL_ASSERT(width <= 32); - dev->in_crc[channel].crc_width.rx_crc_width_chn = (width - 1) / 8; + dev->in_crc_arb[channel].crc_width.rx_crc_width_chn = (width - 1) / 8; } /** @@ -609,7 +609,7 @@ static inline void ahb_dma_ll_rx_crc_set_width(ahb_dma_dev_t *dev, uint32_t chan */ static inline void ahb_dma_ll_rx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t channel, uint32_t value) { - dev->in_crc[channel].crc_init_data.in_crc_init_data_chn = value; + dev->in_crc_arb[channel].crc_init_data.in_crc_init_data_chn = value; } /** @@ -617,7 +617,7 @@ static inline void ahb_dma_ll_rx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t */ static inline uint32_t ahb_dma_ll_rx_crc_get_result(ahb_dma_dev_t *dev, uint32_t channel) { - return dev->in_crc[channel].crc_final_result.in_crc_final_result_chn; + return dev->in_crc_arb[channel].crc_final_result.in_crc_final_result_chn; } /** @@ -625,8 +625,8 @@ static inline uint32_t ahb_dma_ll_rx_crc_get_result(ahb_dma_dev_t *dev, uint32_t */ static inline void ahb_dma_ll_rx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t channel) { - dev->in_crc[channel].crc_width.rx_crc_latch_flag_chn = 1; - dev->in_crc[channel].crc_width.rx_crc_latch_flag_chn = 0; + dev->in_crc_arb[channel].crc_width.rx_crc_latch_flag_chn = 1; + dev->in_crc_arb[channel].crc_width.rx_crc_latch_flag_chn = 0; } /** @@ -635,14 +635,14 @@ static inline void ahb_dma_ll_rx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t c static inline void ahb_dma_ll_rx_crc_set_lfsr_data_mask(ahb_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) { - dev->in_crc[channel].crc_en_addr.rx_crc_en_addr_chn = crc_bit; - dev->in_crc[channel].crc_en_wr_data.rx_crc_en_wr_data_chn = lfsr_mask; - dev->in_crc[channel].crc_data_en_addr.rx_crc_data_en_addr_chn = crc_bit; + dev->in_crc_arb[channel].crc_en_addr.rx_crc_en_addr_chn = crc_bit; + dev->in_crc_arb[channel].crc_en_wr_data.rx_crc_en_wr_data_chn = lfsr_mask; + dev->in_crc_arb[channel].crc_data_en_addr.rx_crc_data_en_addr_chn = crc_bit; if (reverse_data_mask) { // "& 0xff" because the hardware only support 8-bit data data_mask = hal_utils_bitwise_reverse8(data_mask & 0xFF); } - HAL_FORCE_MODIFY_U32_REG_FIELD(dev->in_crc[channel].crc_data_en_wr_data, rx_crc_data_en_wr_data_chn, data_mask); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->in_crc_arb[channel].crc_data_en_wr_data, rx_crc_data_en_wr_data_chn, data_mask); } #ifdef __cplusplus diff --git a/components/soc/esp32c5/beta3/gdma_periph.c b/components/soc/esp32c5/beta3/gdma_periph.c index 943e9bad3d2..f17b916be20 100644 --- a/components/soc/esp32c5/beta3/gdma_periph.c +++ b/components/soc/esp32c5/beta3/gdma_periph.c @@ -111,7 +111,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { .owner = ENTRY(0) | ENTRY(2) }, }; -const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_PAIRS_PER_GROUP_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { +const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_NUM_GROUPS_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { [0] = { [0] = {gdma_g0p0_regs_retention, ARRAY_SIZE(gdma_g0p0_regs_retention)}, [1] = {gdma_g0p1_regs_retention, ARRAY_SIZE(gdma_g0p1_regs_retention)}, diff --git a/components/soc/esp32c5/mp/gdma_periph.c b/components/soc/esp32c5/mp/gdma_periph.c new file mode 100644 index 00000000000..3217ef607cf --- /dev/null +++ b/components/soc/esp32c5/mp/gdma_periph.c @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/gdma_periph.h" +#include "soc/ahb_dma_reg.h" + +const gdma_signal_conn_t gdma_periph_signals = { + .groups = { + [0] = { + .module = PERIPH_GDMA_MODULE, + .pairs = { + [0] = { + .rx_irq_id = ETS_DMA_IN_CH0_INTR_SOURCE, + .tx_irq_id = ETS_DMA_OUT_CH0_INTR_SOURCE, + }, + [1] = { + .rx_irq_id = ETS_DMA_IN_CH1_INTR_SOURCE, + .tx_irq_id = ETS_DMA_OUT_CH1_INTR_SOURCE, + }, + [2] = { + .rx_irq_id = ETS_DMA_IN_CH2_INTR_SOURCE, + .tx_irq_id = ETS_DMA_OUT_CH2_INTR_SOURCE, + } + } + } + } +}; + +#if SOC_GDMA_SUPPORT_SLEEP_RETENTION +/* GDMA Channel (Group0, Pair0) Registers Context + Include: GDMA_MISC_CONF_REG + GDMA_IN_INT_ENA_CH0_REG / GDMA_OUT_INT_ENA_CH0_REG / GDMA_IN_PERI_SEL_CH0_REG / GDMA_OUT_PERI_SEL_CH0_REG + GDMA_IN_CONF0_CH0_REG / GDMA_IN_CONF1_CH0_REG / GDMA_IN_LINK_CH0_REG / GDMA_IN_PRI_CH0_REG + GDMA_OUT_CONF0_CH0_REG / GDMA_OUT_CONF1_CH0_REG / GDMA_OUT_LINK_CH0_REG /GDMA_OUT_PRI_CH0_REG + + AHB_DMA_TX_CH_ARB_WEIGH_CH0_REG / AHB_DMA_TX_ARB_WEIGH_OPT_DIR_CH0_REG + AHB_DMA_RX_CH_ARB_WEIGH_CH0_REG / AHB_DMA_RX_ARB_WEIGH_OPT_DIR_CH0_REG + AHB_DMA_IN_LINK_ADDR_CH0_REG / AHB_DMA_OUT_LINK_ADDR_CH0_REG + AHB_DMA_INTR_MEM_START_ADDR_REG / AHB_DMA_INTR_MEM_END_ADDR_REG + AHB_DMA_ARB_TIMEOUT_TX_REG / AHB_DMA_ARB_TIMEOUT_RX_REG + AHB_DMA_WEIGHT_EN_TX_REG / AHB_DMA_WEIGHT_EN_RX_REG +*/ +#define G0P0_RETENTION_REGS_CNT_0 13 +#define G0P0_RETENTION_MAP_BASE_0 (REG_AHB_DMA_BASE + 0x8) +#define G0P0_RETENTION_REGS_CNT_1 12 +#define G0P0_RETENTION_MAP_BASE_1 (REG_AHB_DMA_BASE + 0x2dc) +static const uint32_t g0p0_regs_map0[4] = {0x4c801001, 0x604c0060, 0x0, 0x0}; +static const uint32_t g0p0_regs_map1[4] = {0xc0000003, 0xfc900000, 0x0, 0x0}; +static const regdma_entries_config_t gdma_g0p0_regs_retention[] = { + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P0_RETENTION_MAP_BASE_0, G0P0_RETENTION_MAP_BASE_0, \ + G0P0_RETENTION_REGS_CNT_0, 0, 0, \ + g0p0_regs_map0[0], g0p0_regs_map0[1], \ + g0p0_regs_map0[2], g0p0_regs_map0[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P0_RETENTION_MAP_BASE_1, G0P0_RETENTION_MAP_BASE_1, \ + G0P0_RETENTION_REGS_CNT_1, 0, 0, \ + g0p0_regs_map1[0], g0p0_regs_map1[1], \ + g0p0_regs_map1[2], g0p0_regs_map1[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, +}; + +/* GDMA Channel (Group0, Pair1) Registers Context + Include: GDMA_MISC_CONF_REG + GDMA_IN_INT_ENA_CH1_REG / GDMA_OUT_INT_ENA_CH1_REG / GDMA_IN_PERI_SEL_CH1_REG / GDMA_OUT_PERI_SEL_CH1_REG + GDMA_IN_CONF0_CH1_REG / GDMA_IN_CONF1_CH1_REG / GDMA_IN_LINK_CH1_REG / GDMA_IN_PRI_CH1_REG + GDMA_OUT_CONF0_CH1_REG / GDMA_OUT_CONF1_CH1_REG / GDMA_OUT_LINK_CH1_REG /GDMA_OUT_PRI_CH1_REG + + AHB_DMA_TX_CH_ARB_WEIGH_CH1_REG / AHB_DMA_TX_ARB_WEIGH_OPT_DIR_CH1_REG + AHB_DMA_RX_CH_ARB_WEIGH_CH1_REG / AHB_DMA_RX_ARB_WEIGH_OPT_DIR_CH1_REG + AHB_DMA_IN_LINK_ADDR_CH1_REG / AHB_DMA_OUT_LINK_ADDR_CH1_REG + AHB_DMA_INTR_MEM_START_ADDR_REG / AHB_DMA_INTR_MEM_END_ADDR_REG + AHB_DMA_ARB_TIMEOUT_TX_REG / AHB_DMA_ARB_TIMEOUT_RX_REG + AHB_DMA_WEIGHT_EN_TX_REG / AHB_DMA_WEIGHT_EN_RX_REG +*/ +#define G0P1_RETENTION_REGS_CNT_0 13 +#define G0P1_RETENTION_MAP_BASE_0 (REG_AHB_DMA_BASE + 0x18) +#define G0P1_RETENTION_REGS_CNT_1 12 +#define G0P1_RETENTION_MAP_BASE_1 (REG_AHB_DMA_BASE + 0x304) +static const uint32_t g0p1_regs_map0[4] = {0x81001, 0x0, 0xc00604c0, 0x604}; +static const uint32_t g0p1_regs_map1[4] = {0xc0000003, 0x3f4800, 0x0, 0x0}; +static const regdma_entries_config_t gdma_g0p1_regs_retention[] = { + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P1_RETENTION_MAP_BASE_0, G0P1_RETENTION_MAP_BASE_0, \ + G0P1_RETENTION_REGS_CNT_0, 0, 0, \ + g0p1_regs_map0[0], g0p1_regs_map0[1], \ + g0p1_regs_map0[2], g0p1_regs_map0[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P1_RETENTION_MAP_BASE_1, G0P1_RETENTION_MAP_BASE_1, \ + G0P1_RETENTION_REGS_CNT_1, 0, 0, \ + g0p1_regs_map1[0], g0p1_regs_map1[1], \ + g0p1_regs_map1[2], g0p1_regs_map1[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, +}; + +/* GDMA Channel (Group0, Pair2) Registers Context + Include: GDMA_MISC_CONF_REG + GDMA_IN_INT_ENA_CH2_REG / GDMA_OUT_INT_ENA_CH2_REG + + GDMA_IN_PERI_SEL_CH2_REG / GDMA_OUT_PERI_SEL_CH2_REG + GDMA_IN_CONF0_CH2_REG / GDMA_IN_CONF1_CH2_REG / GDMA_IN_LINK_CH2_REG / GDMA_IN_PRI_CH2_REG + GDMA_OUT_CONF0_CH2_REG / GDMA_OUT_CONF1_CH2_REG / GDMA_OUT_LINK_CH2_REG /GDMA_OUT_PRI_CH2_REG + AHB_DMA_TX_CH_ARB_WEIGH_CH2_REG / AHB_DMA_TX_ARB_WEIGH_OPT_DIR_CH2_REG + AHB_DMA_RX_CH_ARB_WEIGH_CH2_REG / AHB_DMA_RX_ARB_WEIGH_OPT_DIR_CH2_REG + AHB_DMA_IN_LINK_ADDR_CH2_REG / AHB_DMA_OUT_LINK_ADDR_CH2_REG + AHB_DMA_INTR_MEM_START_ADDR_REG / AHB_DMA_INTR_MEM_END_ADDR_REG + AHB_DMA_ARB_TIMEOUT_TX_REG / AHB_DMA_ARB_TIMEOUT_RX_REG + AHB_DMA_WEIGHT_EN_TX_REG / AHB_DMA_WEIGHT_EN_RX_REG +*/ +#define G0P2_RETENTION_REGS_CNT_0 3 +#define G0P2_RETENTION_MAP_BASE_0 (REG_AHB_DMA_BASE + 0x28) +#define G0P2_RETENTION_REGS_CNT_1 22 +#define G0P2_RETENTION_MAP_BASE_1 (REG_AHB_DMA_BASE + 0x1f0) +static const uint32_t g0p2_regs_map0[4] = {0x9001, 0x0, 0x0, 0x0}; +static const uint32_t g0p2_regs_map1[4] = {0x13001813, 0x18, 0x18000, 0x7f26000}; +static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { + [0] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P2_RETENTION_MAP_BASE_0, G0P2_RETENTION_MAP_BASE_0, \ + G0P2_RETENTION_REGS_CNT_0, 0, 0, \ + g0p2_regs_map0[0], g0p2_regs_map0[1], \ + g0p2_regs_map0[2], g0p2_regs_map0[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ + G0P2_RETENTION_REGS_CNT_1, 0, 0, \ + g0p2_regs_map1[0], g0p2_regs_map1[1], \ + g0p2_regs_map1[2], g0p2_regs_map1[3]), \ + .owner = ENTRY(0) | ENTRY(2) }, +}; + +const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_NUM_GROUPS_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { + [0] = { + [0] = {gdma_g0p0_regs_retention, ARRAY_SIZE(gdma_g0p0_regs_retention)}, + [1] = {gdma_g0p1_regs_retention, ARRAY_SIZE(gdma_g0p1_regs_retention)}, + [2] = {gdma_g0p2_regs_retention, ARRAY_SIZE(gdma_g0p2_regs_retention)} + } +}; +#endif diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index cb12a7c2fd5..a6749ecc213 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -7,10 +7,22 @@ config SOC_UART_SUPPORTED bool default y +config SOC_GDMA_SUPPORTED + bool + default y + +config SOC_AHB_GDMA_SUPPORTED + bool + default y + config SOC_GPTIMER_SUPPORTED bool default y +config SOC_ASYNC_MEMCPY_SUPPORTED + bool + default y + config SOC_SUPPORTS_SECURE_DL_MODE bool default y @@ -111,6 +123,22 @@ config SOC_CPU_IDRAM_SPLIT_USING_PMP bool default y +config SOC_DMA_CAN_ACCESS_FLASH + bool + default y + +config SOC_AHB_GDMA_VERSION + int + default 2 + +config SOC_GDMA_NUM_GROUPS_MAX + int + default 1 + +config SOC_GDMA_PAIRS_PER_GROUP_MAX + int + default 3 + config SOC_GPIO_PORT int default 1 diff --git a/components/soc/esp32c5/mp/include/soc/ahb_dma_struct.h b/components/soc/esp32c5/mp/include/soc/ahb_dma_struct.h index 3da3d5fee3f..dce94fc8501 100644 --- a/components/soc/esp32c5/mp/include/soc/ahb_dma_struct.h +++ b/components/soc/esp32c5/mp/include/soc/ahb_dma_struct.h @@ -1132,139 +1132,84 @@ typedef union { uint32_t val; } ahb_dma_out_peri_sel_chn_reg_t; +typedef struct { + volatile ahb_dma_in_int_raw_chn_reg_t raw; + volatile ahb_dma_in_int_st_chn_reg_t st; + volatile ahb_dma_in_int_ena_chn_reg_t ena; + volatile ahb_dma_in_int_clr_chn_reg_t clr; +} ahb_dma_in_int_chn_reg_t; + +typedef struct { + volatile ahb_dma_out_int_raw_chn_reg_t raw; + volatile ahb_dma_out_int_st_chn_reg_t st; + volatile ahb_dma_out_int_ena_chn_reg_t ena; + volatile ahb_dma_out_int_clr_chn_reg_t clr; +} ahb_dma_out_int_chn_reg_t; + +typedef struct { + volatile ahb_dma_in_conf0_chn_reg_t in_conf0; + volatile ahb_dma_in_conf1_chn_reg_t in_conf1; + volatile ahb_dma_infifo_status_chn_reg_t infifo_status; + volatile ahb_dma_in_pop_chn_reg_t in_pop; + volatile ahb_dma_in_link_chn_reg_t in_link; + volatile ahb_dma_in_state_chn_reg_t in_state; + volatile ahb_dma_in_suc_eof_des_addr_chn_reg_t in_suc_eof_des_addr; + volatile ahb_dma_in_err_eof_des_addr_chn_reg_t in_err_eof_des_addr; + volatile ahb_dma_in_dscr_chn_reg_t in_dscr; + volatile ahb_dma_in_dscr_bf0_chn_reg_t in_dscr_bf0; + volatile ahb_dma_in_dscr_bf1_chn_reg_t in_dscr_bf1; + volatile ahb_dma_in_pri_chn_reg_t in_pri; + volatile ahb_dma_in_peri_sel_chn_reg_t in_peri_sel; +} ahb_dma_in_chn_reg_t; + +typedef struct { + volatile ahb_dma_out_conf0_chn_reg_t out_conf0; + volatile ahb_dma_out_conf1_chn_reg_t out_conf1; + volatile ahb_dma_outfifo_status_chn_reg_t outfifo_status; + volatile ahb_dma_out_push_chn_reg_t out_push; + volatile ahb_dma_out_link_chn_reg_t out_link; + volatile ahb_dma_out_state_chn_reg_t out_state; + volatile ahb_dma_out_eof_des_addr_chn_reg_t out_eof_des_addr; + volatile ahb_dma_out_eof_bfr_des_addr_chn_reg_t out_eof_bfr_des_addr; + volatile ahb_dma_out_dscr_chn_reg_t out_dscr; + volatile ahb_dma_out_dscr_bf0_chn_reg_t out_dscr_bf0; + volatile ahb_dma_out_dscr_bf1_chn_reg_t out_dscr_bf1; + volatile ahb_dma_out_pri_chn_reg_t out_pri; + volatile ahb_dma_out_peri_sel_chn_reg_t out_peri_sel; +} ahb_dma_out_chn_reg_t; + +typedef struct { + volatile ahb_dma_in_chn_reg_t in; + uint32_t reserved_in[11]; + volatile ahb_dma_out_chn_reg_t out; + uint32_t reserved_out[11]; +} ahb_dma_chn_reg_t; + +typedef struct { + uint32_t reserved[8]; + ahb_dma_rx_ch_arb_weigh_chn_reg_t ch_arb_weigh; + ahb_dma_rx_arb_weigh_opt_dir_chn_reg_t arb_weigh_opt; +} ahb_dma_in_crc_arb_chn_reg_t; + +typedef struct { + uint32_t reserved[8]; + ahb_dma_tx_ch_arb_weigh_chn_reg_t ch_arb_weigh; + ahb_dma_tx_arb_weigh_opt_dir_chn_reg_t arb_weigh_opt; +} ahb_dma_out_crc_arb_chn_reg_t; typedef struct { - volatile ahb_dma_in_int_raw_chn_reg_t in_int_raw_ch0; - volatile ahb_dma_in_int_st_chn_reg_t in_int_st_ch0; - volatile ahb_dma_in_int_ena_chn_reg_t in_int_ena_ch0; - volatile ahb_dma_in_int_clr_chn_reg_t in_int_clr_ch0; - volatile ahb_dma_in_int_raw_chn_reg_t in_int_raw_ch1; - volatile ahb_dma_in_int_st_chn_reg_t in_int_st_ch1; - volatile ahb_dma_in_int_ena_chn_reg_t in_int_ena_ch1; - volatile ahb_dma_in_int_clr_chn_reg_t in_int_clr_ch1; - volatile ahb_dma_in_int_raw_chn_reg_t in_int_raw_ch2; - volatile ahb_dma_in_int_st_chn_reg_t in_int_st_ch2; - volatile ahb_dma_in_int_ena_chn_reg_t in_int_ena_ch2; - volatile ahb_dma_in_int_clr_chn_reg_t in_int_clr_ch2; - volatile ahb_dma_out_int_raw_chn_reg_t out_int_raw_ch0; - volatile ahb_dma_out_int_st_chn_reg_t out_int_st_ch0; - volatile ahb_dma_out_int_ena_chn_reg_t out_int_ena_ch0; - volatile ahb_dma_out_int_clr_chn_reg_t out_int_clr_ch0; - volatile ahb_dma_out_int_raw_chn_reg_t out_int_raw_ch1; - volatile ahb_dma_out_int_st_chn_reg_t out_int_st_ch1; - volatile ahb_dma_out_int_ena_chn_reg_t out_int_ena_ch1; - volatile ahb_dma_out_int_clr_chn_reg_t out_int_clr_ch1; - volatile ahb_dma_out_int_raw_chn_reg_t out_int_raw_ch2; - volatile ahb_dma_out_int_st_chn_reg_t out_int_st_ch2; - volatile ahb_dma_out_int_ena_chn_reg_t out_int_ena_ch2; - volatile ahb_dma_out_int_clr_chn_reg_t out_int_clr_ch2; + volatile ahb_dma_in_int_chn_reg_t in_intr[3]; + volatile ahb_dma_out_int_chn_reg_t out_intr[3]; volatile ahb_dma_ahb_test_reg_t ahb_test; volatile ahb_dma_misc_conf_reg_t misc_conf; volatile ahb_dma_date_reg_t date; uint32_t reserved_06c; - volatile ahb_dma_in_conf0_chn_reg_t in_conf0_ch0; - volatile ahb_dma_in_conf1_chn_reg_t in_conf1_ch0; - volatile ahb_dma_infifo_status_chn_reg_t infifo_status_ch0; - volatile ahb_dma_in_pop_chn_reg_t in_pop_ch0; - volatile ahb_dma_in_link_chn_reg_t in_link_ch0; - volatile ahb_dma_in_state_chn_reg_t in_state_ch0; - volatile ahb_dma_in_suc_eof_des_addr_chn_reg_t in_suc_eof_des_addr_ch0; - volatile ahb_dma_in_err_eof_des_addr_chn_reg_t in_err_eof_des_addr_ch0; - volatile ahb_dma_in_dscr_chn_reg_t in_dscr_ch0; - volatile ahb_dma_in_dscr_bf0_chn_reg_t in_dscr_bf0_ch0; - volatile ahb_dma_in_dscr_bf1_chn_reg_t in_dscr_bf1_ch0; - volatile ahb_dma_in_pri_chn_reg_t in_pri_ch0; - volatile ahb_dma_in_peri_sel_chn_reg_t in_peri_sel_ch0; - uint32_t reserved_0a4[11]; - volatile ahb_dma_out_conf0_ch0_reg_t out_conf0_ch0; - volatile ahb_dma_out_conf1_chn_reg_t out_conf1_ch0; - volatile ahb_dma_outfifo_status_chn_reg_t outfifo_status_ch0; - volatile ahb_dma_out_push_chn_reg_t out_push_ch0; - volatile ahb_dma_out_link_chn_reg_t out_link_ch0; - volatile ahb_dma_out_state_chn_reg_t out_state_ch0; - volatile ahb_dma_out_eof_des_addr_chn_reg_t out_eof_des_addr_ch0; - volatile ahb_dma_out_eof_bfr_des_addr_chn_reg_t out_eof_bfr_des_addr_ch0; - volatile ahb_dma_out_dscr_chn_reg_t out_dscr_ch0; - volatile ahb_dma_out_dscr_bf0_chn_reg_t out_dscr_bf0_ch0; - volatile ahb_dma_out_dscr_bf1_chn_reg_t out_dscr_bf1_ch0; - volatile ahb_dma_out_pri_chn_reg_t out_pri_ch0; - volatile ahb_dma_out_peri_sel_chn_reg_t out_peri_sel_ch0; - uint32_t reserved_104[11]; - volatile ahb_dma_in_conf0_chn_reg_t in_conf0_ch1; - volatile ahb_dma_in_conf1_chn_reg_t in_conf1_ch1; - volatile ahb_dma_infifo_status_chn_reg_t infifo_status_ch1; - volatile ahb_dma_in_pop_chn_reg_t in_pop_ch1; - volatile ahb_dma_in_link_chn_reg_t in_link_ch1; - volatile ahb_dma_in_state_chn_reg_t in_state_ch1; - volatile ahb_dma_in_suc_eof_des_addr_chn_reg_t in_suc_eof_des_addr_ch1; - volatile ahb_dma_in_err_eof_des_addr_chn_reg_t in_err_eof_des_addr_ch1; - volatile ahb_dma_in_dscr_chn_reg_t in_dscr_ch1; - volatile ahb_dma_in_dscr_bf0_chn_reg_t in_dscr_bf0_ch1; - volatile ahb_dma_in_dscr_bf1_chn_reg_t in_dscr_bf1_ch1; - volatile ahb_dma_in_pri_chn_reg_t in_pri_ch1; - volatile ahb_dma_in_peri_sel_chn_reg_t in_peri_sel_ch1; - uint32_t reserved_164[11]; - volatile ahb_dma_out_conf0_chn_reg_t out_conf0_ch1; - volatile ahb_dma_out_conf1_chn_reg_t out_conf1_ch1; - volatile ahb_dma_outfifo_status_chn_reg_t outfifo_status_ch1; - volatile ahb_dma_out_push_chn_reg_t out_push_ch1; - volatile ahb_dma_out_link_chn_reg_t out_link_ch1; - volatile ahb_dma_out_state_chn_reg_t out_state_ch1; - volatile ahb_dma_out_eof_des_addr_chn_reg_t out_eof_des_addr_ch1; - volatile ahb_dma_out_eof_bfr_des_addr_chn_reg_t out_eof_bfr_des_addr_ch1; - volatile ahb_dma_out_dscr_chn_reg_t out_dscr_ch1; - volatile ahb_dma_out_dscr_bf0_chn_reg_t out_dscr_bf0_ch1; - volatile ahb_dma_out_dscr_bf1_chn_reg_t out_dscr_bf1_ch1; - volatile ahb_dma_out_pri_chn_reg_t out_pri_ch1; - volatile ahb_dma_out_peri_sel_chn_reg_t out_peri_sel_ch1; - uint32_t reserved_1c4[11]; - volatile ahb_dma_in_conf0_chn_reg_t in_conf0_ch2; - volatile ahb_dma_in_conf1_chn_reg_t in_conf1_ch2; - volatile ahb_dma_infifo_status_chn_reg_t infifo_status_ch2; - volatile ahb_dma_in_pop_chn_reg_t in_pop_ch2; - volatile ahb_dma_in_link_chn_reg_t in_link_ch2; - volatile ahb_dma_in_state_chn_reg_t in_state_ch2; - volatile ahb_dma_in_suc_eof_des_addr_chn_reg_t in_suc_eof_des_addr_ch2; - volatile ahb_dma_in_err_eof_des_addr_chn_reg_t in_err_eof_des_addr_ch2; - volatile ahb_dma_in_dscr_chn_reg_t in_dscr_ch2; - volatile ahb_dma_in_dscr_bf0_chn_reg_t in_dscr_bf0_ch2; - volatile ahb_dma_in_dscr_bf1_chn_reg_t in_dscr_bf1_ch2; - volatile ahb_dma_in_pri_chn_reg_t in_pri_ch2; - volatile ahb_dma_in_peri_sel_chn_reg_t in_peri_sel_ch2; - uint32_t reserved_224[11]; - volatile ahb_dma_out_conf0_chn_reg_t out_conf0_ch2; - volatile ahb_dma_out_conf1_chn_reg_t out_conf1_ch2; - volatile ahb_dma_outfifo_status_chn_reg_t outfifo_status_ch2; - volatile ahb_dma_out_push_chn_reg_t out_push_ch2; - volatile ahb_dma_out_link_chn_reg_t out_link_ch2; - volatile ahb_dma_out_state_chn_reg_t out_state_ch2; - volatile ahb_dma_out_eof_des_addr_chn_reg_t out_eof_des_addr_ch2; - volatile ahb_dma_out_eof_bfr_des_addr_chn_reg_t out_eof_bfr_des_addr_ch2; - volatile ahb_dma_out_dscr_chn_reg_t out_dscr_ch2; - volatile ahb_dma_out_dscr_bf0_chn_reg_t out_dscr_bf0_ch2; - volatile ahb_dma_out_dscr_bf1_chn_reg_t out_dscr_bf1_ch2; - volatile ahb_dma_out_pri_chn_reg_t out_pri_ch2; - volatile ahb_dma_out_peri_sel_chn_reg_t out_peri_sel_ch2; - uint32_t reserved_284[22]; - volatile ahb_dma_tx_ch_arb_weigh_chn_reg_t tx_ch_arb_weigh_ch0; - volatile ahb_dma_tx_arb_weigh_opt_dir_chn_reg_t tx_arb_weigh_opt_dir_ch0; - uint32_t reserved_2e4[8]; - volatile ahb_dma_tx_ch_arb_weigh_chn_reg_t tx_ch_arb_weigh_ch1; - volatile ahb_dma_tx_arb_weigh_opt_dir_chn_reg_t tx_arb_weigh_opt_dir_ch1; - uint32_t reserved_30c[8]; - volatile ahb_dma_tx_ch_arb_weigh_chn_reg_t tx_ch_arb_weigh_ch2; - volatile ahb_dma_tx_arb_weigh_opt_dir_chn_reg_t tx_arb_weigh_opt_dir_ch2; - uint32_t reserved_334[8]; - volatile ahb_dma_rx_ch_arb_weigh_chn_reg_t rx_ch_arb_weigh_ch0; - volatile ahb_dma_rx_arb_weigh_opt_dir_chn_reg_t rx_arb_weigh_opt_dir_ch0; - uint32_t reserved_35c[8]; - volatile ahb_dma_rx_ch_arb_weigh_chn_reg_t rx_ch_arb_weigh_ch1; - volatile ahb_dma_rx_arb_weigh_opt_dir_chn_reg_t rx_arb_weigh_opt_dir_ch1; - uint32_t reserved_384[8]; - volatile ahb_dma_rx_ch_arb_weigh_chn_reg_t rx_ch_arb_weigh_ch2; - volatile ahb_dma_rx_arb_weigh_opt_dir_chn_reg_t rx_arb_weigh_opt_dir_ch2; - volatile ahb_dma_in_link_addr_chn_reg_t in_link_addr_chn[3]; - volatile ahb_dma_out_link_addr_chn_reg_t out_link_addr_chn[3]; + volatile ahb_dma_chn_reg_t channel[3]; + uint32_t reserved_2b0[3]; + volatile ahb_dma_out_crc_arb_chn_reg_t out_crc_arb[3]; + volatile ahb_dma_in_crc_arb_chn_reg_t in_crc_arb[3]; + volatile ahb_dma_in_link_addr_chn_reg_t in_link_addr[3]; + volatile ahb_dma_out_link_addr_chn_reg_t out_link_addr[3]; volatile ahb_dma_intr_mem_start_addr_reg_t intr_mem_start_addr; volatile ahb_dma_intr_mem_end_addr_reg_t intr_mem_end_addr; volatile ahb_dma_arb_timeout_tx_reg_t arb_timeout_tx; diff --git a/components/soc/esp32c5/mp/include/soc/gdma_channel.h b/components/soc/esp32c5/mp/include/soc/gdma_channel.h index e69de29bb2d..7322d9ffe79 100644 --- a/components/soc/esp32c5/mp/include/soc/gdma_channel.h +++ b/components/soc/esp32c5/mp/include/soc/gdma_channel.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +// The following macros have a format SOC_[periph][instance_id] to make it work with `GDMA_MAKE_TRIGGER` +#define SOC_GDMA_TRIG_PERIPH_M2M0 (-1) +#define SOC_GDMA_TRIG_PERIPH_SPI2 (1) +#define SOC_GDMA_TRIG_PERIPH_UHCI0 (2) +#define SOC_GDMA_TRIG_PERIPH_I2S0 (3) +#define SOC_GDMA_TRIG_PERIPH_AES0 (6) +#define SOC_GDMA_TRIG_PERIPH_SHA0 (7) +#define SOC_GDMA_TRIG_PERIPH_ADC0 (8) +#define SOC_GDMA_TRIG_PERIPH_PARLIO0 (9) + +// On which system bus is the DMA instance of the peripheral connection mounted +#define SOC_GDMA_BUS_ANY (-1) +#define SOC_GDMA_BUS_AHB (0) + +#define SOC_GDMA_TRIG_PERIPH_M2M0_BUS SOC_GDMA_BUS_ANY +#define SOC_GDMA_TRIG_PERIPH_SPI2_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_UHCI0_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_I2S0_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_AES0_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_SHA0_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_ADC0_BUS SOC_GDMA_BUS_AHB +#define SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS SOC_GDMA_BUS_AHB diff --git a/components/soc/esp32c5/mp/include/soc/reg_base.h b/components/soc/esp32c5/mp/include/soc/reg_base.h index bfd38466861..a7b52e5797d 100644 --- a/components/soc/esp32c5/mp/include/soc/reg_base.h +++ b/components/soc/esp32c5/mp/include/soc/reg_base.h @@ -63,6 +63,7 @@ #define DR_REG_PCR_BASE 0x60096000 #define DR_REG_TEE_BASE 0x60098000 #define DR_REG_HP_APM_BASE 0x60099000 +#define DR_REG_LP_APM0_BASE 0x60099800 #define DR_REG_MISC_BASE 0x6009F000 /** diff --git a/components/soc/esp32c5/mp/include/soc/retention_periph_defs.h b/components/soc/esp32c5/mp/include/soc/retention_periph_defs.h new file mode 100644 index 00000000000..2ef044eb402 --- /dev/null +++ b/components/soc/esp32c5/mp/include/soc/retention_periph_defs.h @@ -0,0 +1,68 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_bit_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum periph_retention_module { + SLEEP_RETENTION_MODULE_MIN = 0, + /* clock module, which includes system and modem */ + SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1, + SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2, + + /* modem module, which includes WiFi, BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_WIFI_MAC = 10, + SLEEP_RETENTION_MODULE_WIFI_BB = 11, + SLEEP_RETENTION_MODULE_BLE_MAC = 12, + SLEEP_RETENTION_MODULE_BT_BB = 13, + SLEEP_RETENTION_MODULE_802154_MAC = 14, + + /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, + * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_SYS_PERIPH = 16, + + SLEEP_RETENTION_MODULE_ADC = 17, + + SLEEP_RETENTION_MODULE_GDMA_CH0 = 24, + SLEEP_RETENTION_MODULE_GDMA_CH1 = 25, + SLEEP_RETENTION_MODULE_GDMA_CH2 = 26, + + SLEEP_RETENTION_MODULE_MAX = 31 +} periph_retention_module_t; + +typedef enum periph_retention_module_bitmap { + /* clock module, which includes system and modem */ + SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), + SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM), + + /* modem module, which includes WiFi, BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), + SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), + SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), + SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), + SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), + + /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, + * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), + + SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), + + SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), + SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), + SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), + SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 +} periph_retention_module_bitmap_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index cd358d4b902..dc5e4d5f769 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -20,15 +20,15 @@ // #define SOC_ADC_SUPPORTED 1 // TODO: [ESP32C5] IDF-8701 // #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: [ESP32C5] IDF-8725 #define SOC_UART_SUPPORTED 1 // TODO: [ESP32C5] IDF-8722 -// #define SOC_GDMA_SUPPORTED 1 // TODO: [ESP32C5] IDF-8710 -// #define SOC_AHB_GDMA_SUPPORTED 1 // TODO: [ESP32C5] IDF-8710 +#define SOC_GDMA_SUPPORTED 1 +#define SOC_AHB_GDMA_SUPPORTED 1 #define SOC_GPTIMER_SUPPORTED 1 // #define SOC_PCNT_SUPPORTED 1 // TODO: [ESP32C5] IDF-8683 // #define SOC_MCPWM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8709 // #define SOC_TWAI_SUPPORTED 1 // TODO: [ESP32C5] IDF-8691 // #define SOC_ETM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8693 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32C5] IDF-8685, IDF-8686 -// #define SOC_ASYNC_MEMCPY_SUPPORTED 1 // TODO: [ESP32C5] IDF-8716 +#define SOC_ASYNC_MEMCPY_SUPPORTED 1 // #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32C5] IDF-8721 // #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32C5] IDF-8727 // #define SOC_WIFI_SUPPORTED 1 // TODO: [ESP32C5] IDF-8851 @@ -55,7 +55,7 @@ #define SOC_FLASH_ENC_SUPPORTED 1 // TODO: [ESP32C5] IDF-8622 // #define SOC_SECURE_BOOT_SUPPORTED 1 // TODO: [ESP32C5] IDF-8623 // #define SOC_BOD_SUPPORTED 1 // TODO: [ESP32C5] IDF-8647 -// #define SOC_APM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8614 +// #define SOC_APM_SUPPORTED 1 // TODO: [ESP32C5] IDF-8614, IDF-8615 // #define SOC_PMU_SUPPORTED 1 // TODO: [ESP32C5] IDF-8667 // #define SOC_PAU_SUPPORTED 1 // TODO: [ESP32C5] IDF-8638 // #define SOC_LP_TIMER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8636 @@ -164,11 +164,15 @@ See TRM DS chapter for more details */ // #define SOC_DS_KEY_CHECK_MAX_WAIT_US (1100) +/*-------------------------- DMA Common CAPS ----------------------------------------*/ +#define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ + /*-------------------------- GDMA CAPS -------------------------------------*/ -// #define SOC_AHB_GDMA_VERSION 1U -// #define SOC_GDMA_NUM_GROUPS_MAX 1U -// #define SOC_GDMA_PAIRS_PER_GROUP_MAX 3 -// #define SOC_GDMA_SUPPORT_ETM 1 // Support ETM submodule +#define SOC_AHB_GDMA_VERSION 2 +#define SOC_GDMA_NUM_GROUPS_MAX 1U +#define SOC_GDMA_PAIRS_PER_GROUP_MAX 3 +// #define SOC_GDMA_SUPPORT_ETM 1 // Support ETM submodule TODO: IDF-9224 +// #define SOC_GDMA_SUPPORT_SLEEP_RETENTION 1 // TODO: IDF-9225 /*-------------------------- ETM CAPS --------------------------------------*/ // #define SOC_ETM_GROUPS 1U // Number of ETM groups diff --git a/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld b/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld index 7a60c63b9a5..b7b8e4da405 100644 --- a/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld +++ b/components/soc/esp32c5/mp/ld/esp32c5.peripherals.ld @@ -48,6 +48,7 @@ PROVIDE ( HP_SYSTEM = 0x60095000 ); PROVIDE ( PCR = 0x60096000 ); PROVIDE ( TEE = 0x60098000 ); PROVIDE ( HP_APM = 0x60099000 ); +PROVIDE ( LP_APM0 = 0x60099800 ); PROVIDE ( MISC = 0x6009F000 ); /* TODO: [ESP32C5] IDF-8845 Check the address */ diff --git a/components/soc/esp32c6/gdma_periph.c b/components/soc/esp32c6/gdma_periph.c index 40d421a6e7d..c5795713ea1 100644 --- a/components/soc/esp32c6/gdma_periph.c +++ b/components/soc/esp32c6/gdma_periph.c @@ -92,7 +92,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { .owner = ENTRY(0) | ENTRY(2) }, }; -const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_PAIRS_PER_GROUP_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { +const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_NUM_GROUPS_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { [0] = { [0] = {gdma_g0p0_regs_retention, ARRAY_SIZE(gdma_g0p0_regs_retention)}, [1] = {gdma_g0p1_regs_retention, ARRAY_SIZE(gdma_g0p1_regs_retention)}, diff --git a/components/soc/esp32h2/gdma_periph.c b/components/soc/esp32h2/gdma_periph.c index 40d421a6e7d..c5795713ea1 100644 --- a/components/soc/esp32h2/gdma_periph.c +++ b/components/soc/esp32h2/gdma_periph.c @@ -92,7 +92,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { .owner = ENTRY(0) | ENTRY(2) }, }; -const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_PAIRS_PER_GROUP_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { +const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_NUM_GROUPS_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX] = { [0] = { [0] = {gdma_g0p0_regs_retention, ARRAY_SIZE(gdma_g0p0_regs_retention)}, [1] = {gdma_g0p1_regs_retention, ARRAY_SIZE(gdma_g0p1_regs_retention)}, diff --git a/components/soc/esp32p4/include/soc/ahb_dma_struct.h b/components/soc/esp32p4/include/soc/ahb_dma_struct.h index 5679071117e..6cc20f36df1 100644 --- a/components/soc/esp32p4/include/soc/ahb_dma_struct.h +++ b/components/soc/esp32p4/include/soc/ahb_dma_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1357,7 +1357,7 @@ typedef struct { ahb_dma_rx_crc_data_en_addr_chn_reg_t crc_data_en_addr; ahb_dma_rx_ch_arb_weigh_chn_reg_t ch_arb_weigh; ahb_dma_rx_arb_weigh_opt_dir_chn_reg_t arb_weigh_opt; -} ahb_dma_in_crc_chn_reg_t; +} ahb_dma_in_crc_arb_chn_reg_t; typedef struct { ahb_dma_out_crc_init_data_chn_reg_t crc_init_data; @@ -1370,7 +1370,7 @@ typedef struct { ahb_dma_tx_crc_data_en_addr_chn_reg_t crc_data_en_addr; ahb_dma_tx_ch_arb_weigh_chn_reg_t ch_arb_weigh; ahb_dma_tx_arb_weigh_opt_dir_chn_reg_t arb_weigh_opt; -} ahb_dma_out_crc_chn_reg_t; +} ahb_dma_out_crc_arb_chn_reg_t; typedef struct { volatile ahb_dma_in_chn_reg_t in; @@ -1388,8 +1388,8 @@ typedef struct { uint32_t reserved_06c; volatile ahb_dma_chn_reg_t channel[3]; uint32_t reserved_2b0[3]; - volatile ahb_dma_out_crc_chn_reg_t out_crc[3]; - volatile ahb_dma_in_crc_chn_reg_t in_crc[3]; + volatile ahb_dma_out_crc_arb_chn_reg_t out_crc_arb[3]; + volatile ahb_dma_in_crc_arb_chn_reg_t in_crc_arb[3]; volatile ahb_dma_in_link_addr_chn_reg_t in_link_addr[3]; volatile ahb_dma_out_link_addr_chn_reg_t out_link_addr[3]; volatile ahb_dma_intr_mem_start_addr_reg_t intr_mem_start_addr; diff --git a/components/soc/include/soc/gdma_periph.h b/components/soc/include/soc/gdma_periph.h index 2d445980800..3376e4d8817 100644 --- a/components/soc/include/soc/gdma_periph.h +++ b/components/soc/include/soc/gdma_periph.h @@ -36,7 +36,7 @@ typedef struct { uint32_t link_num; } gdma_chx_reg_ctx_link_t; -extern const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_PAIRS_PER_GROUP_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX]; +extern const gdma_chx_reg_ctx_link_t gdma_chx_regs_retention[SOC_GDMA_NUM_GROUPS_MAX][SOC_GDMA_PAIRS_PER_GROUP_MAX]; #endif #endif From cf123b36264cc666dede39cf09c97037190d61bd Mon Sep 17 00:00:00 2001 From: gaoxu Date: Wed, 12 Jun 2024 15:29:16 +0800 Subject: [PATCH 232/548] feat(uart): support HP/LP uart on ESP32C5 MP v5.3 --- components/hal/esp32c5/include/hal/uart_ll.h | 20 ++++------------ .../esp32c5/beta3/include/soc/clk_tree_defs.h | 8 +++---- .../mp/include/soc/Kconfig.soc_caps.in | 20 ++++++++++++++++ .../esp32c5/mp/include/soc/clk_tree_defs.h | 24 +++++++++++++++---- .../esp32c5/mp/include/soc/lp_uart_struct.h | 17 ++++++++++++- .../soc/esp32c5/mp/include/soc/soc_caps.h | 13 +++++----- .../soc/esp32c5/mp/include/soc/uart_channel.h | 14 +++++------ .../soc/esp32c5/mp/include/soc/uart_pins.h | 2 -- .../soc/esp32c5/mp/include/soc/uart_struct.h | 20 +++++++++++++--- examples/protocols/.build-test-rules.yml | 2 +- 10 files changed, 96 insertions(+), 44 deletions(-) diff --git a/components/hal/esp32c5/include/hal/uart_ll.h b/components/hal/esp32c5/include/hal/uart_ll.h index ea56ae3e2e9..45abdf70154 100644 --- a/components/hal/esp32c5/include/hal/uart_ll.h +++ b/components/hal/esp32c5/include/hal/uart_ll.h @@ -112,7 +112,7 @@ FORCE_INLINE_ATTR void lp_uart_ll_get_sclk(uart_dev_t *hw, soc_module_clk_t *sou switch (LP_CLKRST.lpperi.lp_uart_clk_sel) { default: case 0: - *source_clk = (soc_module_clk_t)LP_UART_SCLK_LP_FAST; + *source_clk = (soc_module_clk_t)LP_UART_SCLK_RC_FAST; break; case 1: *source_clk = (soc_module_clk_t)LP_UART_SCLK_XTAL_D2; @@ -130,7 +130,7 @@ static inline void lp_uart_ll_set_source_clk(uart_dev_t *hw, soc_periph_lp_uart_ { (void)hw; switch (src_clk) { - case LP_UART_SCLK_LP_FAST: + case LP_UART_SCLK_RC_FAST: LP_CLKRST.lpperi.lp_uart_clk_sel = 0; break; case LP_UART_SCLK_XTAL_D2: @@ -167,12 +167,7 @@ FORCE_INLINE_ATTR void lp_uart_ll_set_baudrate(uart_dev_t *hw, uint32_t baud, ui // an integer part and a fractional part. hw->clkdiv_sync.clkdiv_int = clk_div >> 4; hw->clkdiv_sync.clkdiv_frag = clk_div & 0xf; -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clk_conf, sclk_div_num, sclk_div - 1); -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // TODO: [ESP32c5] IDF-8633 Not found sclk_div_num for LP_UART - abort(); -#endif uart_ll_update(hw); } @@ -437,12 +432,7 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_baudrate(uart_dev_t *hw, uint32_t sclk_fr div_reg.val = hw->clkdiv_sync.val; int sclk_div; if ((hw) == &LP_UART) { -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION sclk_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clk_conf, sclk_div_num) + 1; -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - // TODO: [ESP32c5] IDF-8633 Not found sclk_div_num for LP_UART - abort(); -#endif } else { sclk_div = UART_LL_PCR_REG_U32_GET(hw, sclk_conf, sclk_div_num) + 1; } @@ -734,7 +724,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -801,7 +791,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -1132,7 +1122,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/soc/esp32c5/beta3/include/soc/clk_tree_defs.h b/components/soc/esp32c5/beta3/include/soc/clk_tree_defs.h index 42e7115ba34..d65e8583d22 100644 --- a/components/soc/esp32c5/beta3/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/beta3/include/soc/clk_tree_defs.h @@ -19,7 +19,7 @@ extern "C" { * * 2) External 40/48MHz Crystal Clock: XTAL * - * 3) Internal 136kHz RC Oscillator: RC_SLOW (may also referrred as SOSC in TRM or reg. description) + * 3) Internal 136kHz RC Oscillator: RC_SLOW (may also referred as SOSC in TRM or reg. description) * * This RC oscillator generates a ~136kHz clock signal output as the RC_SLOW_CLK. The exact frequency of this clock * can be computed in runtime through calibration. @@ -250,15 +250,15 @@ typedef enum { /** * @brief Array initializer for all supported clock sources of LP_UART */ -#define SOC_LP_UART_CLKS {SOC_MOD_CLK_RTC_FAST, SOC_MOD_CLK_XTAL_D2} +#define SOC_LP_UART_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_D2} /** * @brief Type of LP_UART clock source */ typedef enum { - LP_UART_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock is LP(RTC)_FAST */ + LP_UART_SCLK_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< LP_UART source clock is RC_FAST */ LP_UART_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock is XTAL_D2 */ - LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock default choice is LP(RTC)_FAST */ + LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock default choice is RC_FAST */ } soc_periph_lp_uart_clk_src_t; //////////////////////////////////////////////////MCPWM///////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index a6749ecc213..e51199cc96d 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -51,6 +51,10 @@ config SOC_FLASH_ENC_SUPPORTED bool default y +config SOC_LP_PERIPHERALS_SUPPORTED + bool + default y + config SOC_SPI_FLASH_SUPPORTED bool default y @@ -383,10 +387,26 @@ config SOC_LP_UART_FIFO_LEN int default 16 +config SOC_UART_BITRATE_MAX + int + default 5000000 + config SOC_UART_SUPPORT_XTAL_CLK bool default y +config SOC_UART_SUPPORT_WAKEUP_INT + bool + default y + +config SOC_UART_HAS_LP_UART + bool + default y + +config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND + bool + default y + config SOC_PM_SUPPORT_MODEM_PD bool default y diff --git a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h index 1872aedd81d..a1ff0423166 100644 --- a/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h +++ b/components/soc/esp32c5/mp/include/soc/clk_tree_defs.h @@ -247,23 +247,39 @@ typedef enum { // TODO: [ESP32C5] IDF-8727 (inherit from C6) ///////////////////////////////////////////////////UART///////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of UART + */ +#define SOC_UART_CLKS {SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_XTAL, SOC_MOD_CLK_RC_FAST} + /** * @brief Type of UART clock source, reserved for the legacy UART driver */ -typedef enum { // TODO: [ESP32C5] IDF-8722 (inherit from C6) +typedef enum { UART_SCLK_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock is PLL_F80M */ UART_SCLK_RTC = SOC_MOD_CLK_RC_FAST, /*!< UART source clock is RC_FAST */ UART_SCLK_XTAL = SOC_MOD_CLK_XTAL, /*!< UART source clock is XTAL */ +#if SOC_CLK_TREE_SUPPORTED UART_SCLK_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< UART source clock default choice is PLL_F80M */ +#else + UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL, /*!< UART source clock default choice is XTAL for FPGA environment*/ +#endif } soc_periph_uart_clk_src_legacy_t; +/** + * @brief Array initializer for all supported clock sources of LP_UART + */ +#define SOC_LP_UART_CLKS {SOC_MOD_CLK_RC_FAST, SOC_MOD_CLK_XTAL_D2} + /** * @brief Type of LP_UART clock source */ -typedef enum { // TODO: [ESP32C5] IDF-8633 (inherit from C6) - LP_UART_SCLK_LP_FAST = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock is LP(RTC)_FAST */ +typedef enum { + LP_UART_SCLK_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< LP_UART source clock is RC_FAST */ LP_UART_SCLK_XTAL_D2 = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock is XTAL_D2 */ - LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_RTC_FAST, /*!< LP_UART source clock default choice is LP(RTC)_FAST */ + + //TODO: IDF-10034 + LP_UART_SCLK_DEFAULT = SOC_MOD_CLK_XTAL_D2, /*!< LP_UART source clock default choice is XTAL_D2 */ } soc_periph_lp_uart_clk_src_t; //////////////////////////////////////////////////MCPWM///////////////////////////////////////////////////////////////// diff --git a/components/soc/esp32c5/mp/include/soc/lp_uart_struct.h b/components/soc/esp32c5/mp/include/soc/lp_uart_struct.h index ad53ed0d9d8..316b3bc1b3f 100644 --- a/components/soc/esp32c5/mp/include/soc/lp_uart_struct.h +++ b/components/soc/esp32c5/mp/include/soc/lp_uart_struct.h @@ -844,7 +844,22 @@ typedef union { */ typedef union { struct { - uint32_t reserved_0:24; + /** sclk_div_b : R/W; bitpos: [5:0]; default: 0; + * The denominator of the frequency divider factor. + * Only available to LP UART instance + */ + uint32_t sclk_div_b:6; + /** sclk_div_a : R/W; bitpos: [11:6]; default: 0; + * The numerator of the frequency divider factor. + * Only available to LP UART instance + */ + uint32_t sclk_div_a:6; + /** sclk_div_num : R/W; bitpos: [19:12]; default: 1; + * The integral part of the frequency divider factor. + * Only available to LP UART instance + */ + uint32_t sclk_div_num:8; + uint32_t reserved_20:4; /** tx_sclk_en : R/W; bitpos: [24]; default: 1; * Configures whether or not to enable LP UART TX clock.\\ * 0: Disable\\ diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index dc5e4d5f769..e4c023f71fd 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -19,7 +19,7 @@ /*-------------------------- COMMON CAPS ---------------------------------------*/ // #define SOC_ADC_SUPPORTED 1 // TODO: [ESP32C5] IDF-8701 // #define SOC_DEDICATED_GPIO_SUPPORTED 1 // TODO: [ESP32C5] IDF-8725 -#define SOC_UART_SUPPORTED 1 // TODO: [ESP32C5] IDF-8722 +#define SOC_UART_SUPPORTED 1 #define SOC_GDMA_SUPPORTED 1 #define SOC_AHB_GDMA_SUPPORTED 1 #define SOC_GPTIMER_SUPPORTED 1 @@ -60,7 +60,7 @@ // #define SOC_PAU_SUPPORTED 1 // TODO: [ESP32C5] IDF-8638 // #define SOC_LP_TIMER_SUPPORTED 1 // TODO: [ESP32C5] IDF-8636 // #define SOC_LP_AON_SUPPORTED 1 // TODO: [ESP32C5] IDF-8638 -// #define SOC_LP_PERIPHERALS_SUPPORTED 1 // TODO: [ESP32C5] IDF-8695, IDF-8723, IDF-8719 +#define SOC_LP_PERIPHERALS_SUPPORTED 1 // #define SOC_LP_I2C_SUPPORTED 1 // TODO: [ESP32C5] IDF-8634 // #define SOC_ULP_LP_UART_SUPPORTED 1 // TODO: [ESP32C5] IDF-8633 // #define SOC_CLK_TREE_SUPPORTED 1 // TODO: [ESP32C5] IDF-8642 @@ -481,14 +481,15 @@ #define SOC_UART_LP_NUM (1U) #define SOC_UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ #define SOC_LP_UART_FIFO_LEN (16) /*!< The LP UART hardware FIFO length */ -// #define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ +#define SOC_UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ // #define SOC_UART_SUPPORT_PLL_F80M_CLK (1) /*!< Support PLL_F80M as the clock source */ -// #define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */ +// #define SOC_UART_SUPPORT_RTC_CLK (1) /*!< Support RTC clock as the clock source */ // TODO: [ESP32C5] IDF-8642 #define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */ -// #define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ +#define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ +#define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled -// #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) +#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) /*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/ // #define SOC_COEX_HW_PTI (1) diff --git a/components/soc/esp32c5/mp/include/soc/uart_channel.h b/components/soc/esp32c5/mp/include/soc/uart_channel.h index 86e8cd6e745..36cad83af11 100644 --- a/components/soc/esp32c5/mp/include/soc/uart_channel.h +++ b/components/soc/esp32c5/mp/include/soc/uart_channel.h @@ -8,13 +8,11 @@ #pragma once -// TODO: [ESP32C5] IDF-8722 - //UART channels -#define UART_GPIO16_DIRECT_CHANNEL UART_NUM_0 -#define UART_NUM_0_TXD_DIRECT_GPIO_NUM 16 -#define UART_GPIO17_DIRECT_CHANNEL UART_NUM_0 -#define UART_NUM_0_RXD_DIRECT_GPIO_NUM 17 +#define UART_GPIO11_DIRECT_CHANNEL UART_NUM_0 +#define UART_NUM_0_TXD_DIRECT_GPIO_NUM 11 +#define UART_GPIO12_DIRECT_CHANNEL UART_NUM_0 +#define UART_NUM_0_RXD_DIRECT_GPIO_NUM 12 -#define UART_TXD_GPIO16_DIRECT_CHANNEL UART_GPIO16_DIRECT_CHANNEL -#define UART_RXD_GPIO17_DIRECT_CHANNEL UART_GPIO17_DIRECT_CHANNEL +#define UART_TXD_GPIO11_DIRECT_CHANNEL UART_GPIO11_DIRECT_CHANNEL +#define UART_RXD_GPIO12_DIRECT_CHANNEL UART_GPIO12_DIRECT_CHANNEL diff --git a/components/soc/esp32c5/mp/include/soc/uart_pins.h b/components/soc/esp32c5/mp/include/soc/uart_pins.h index a5520009d03..6a5c8028703 100644 --- a/components/soc/esp32c5/mp/include/soc/uart_pins.h +++ b/components/soc/esp32c5/mp/include/soc/uart_pins.h @@ -8,8 +8,6 @@ #include "soc/io_mux_reg.h" -// TODO: [ESP32C5] IDF-8722 - /* Specify the number of pins for UART */ #define SOC_UART_PINS_COUNT (4) diff --git a/components/soc/esp32c5/mp/include/soc/uart_struct.h b/components/soc/esp32c5/mp/include/soc/uart_struct.h index 3de1fcc804d..1cc6ed2d323 100644 --- a/components/soc/esp32c5/mp/include/soc/uart_struct.h +++ b/components/soc/esp32c5/mp/include/soc/uart_struct.h @@ -20,8 +20,7 @@ typedef union { * Represents the data UART $n read from FIFO.\\ * Measurement unit: byte. */ - uint32_t rxfifo_rd_byte:8; - uint32_t reserved_8:24; + uint32_t rxfifo_rd_byte:32; }; uint32_t val; } uart_fifo_reg_t; @@ -947,7 +946,22 @@ typedef union { */ typedef union { struct { - uint32_t reserved_0:24; + /** sclk_div_b : R/W; bitpos: [5:0]; default: 0; + * The denominator of the frequency divider factor.' + * Only available to LP UART instance + */ + uint32_t sclk_div_b:6; + /** sclk_div_a : R/W; bitpos: [11:6]; default: 0; + * The numerator of the frequency divider factor. + * Only available to LP UART instance + */ + uint32_t sclk_div_a:6; + /** sclk_div_num : R/W; bitpos: [19:12]; default: 1; + * The integral part of the frequency divider factor. + * Only available to LP UART instance + */ + uint32_t sclk_div_num:8; + uint32_t reserved_20:4; /** tx_sclk_en : R/W; bitpos: [24]; default: 1; * Configures whether or not to enable UART TX clock.\\ * 0: Disable\\ diff --git a/examples/protocols/.build-test-rules.yml b/examples/protocols/.build-test-rules.yml index 76a30e26323..26f38fb99ca 100644 --- a/examples/protocols/.build-test-rules.yml +++ b/examples/protocols/.build-test-rules.yml @@ -184,7 +184,7 @@ examples/protocols/modbus: disable: - if: IDF_TARGET == "esp32c5" temporary: true - reason: not supported yet # TODO: [ESP32C5] IDF-8722, IDF-8697 + reason: not supported yet # TODO: [ESP32C5] IDF-8697 depends_filepatterns: - examples/common_components/protocol_examples_common/**/* - examples/protocols/modbus/mb_example_common/**/* From 3f5037866be698bbef83805c41ac7c7a8960cf7b Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 28 Mar 2024 15:16:12 +0800 Subject: [PATCH 233/548] fix(dma): feat(adc): support ADC oneshot mod on ESP32P4 --- components/driver/deprecated/adc_legacy.c | 6 +- .../deprecated/driver/adc_types_legacy.h | 25 +- .../test_apps/legacy_adc_driver/README.md | 4 +- .../legacy_adc_driver/main/test_legacy_adc.c | 9 +- .../legacy_adc_driver/pytest_legacy_adc.py | 2 +- components/esp_adc/adc_oneshot.c | 13 +- components/esp_adc/test_apps/adc/README.md | 4 +- .../test_apps/adc/main/test_common_adc.c | 3 +- .../test_apps/adc/main/test_common_adc.h | 10 +- .../port/esp32p4/CMakeLists.txt | 3 +- .../port/esp32p4/sar_periph_ctrl.c | 116 ++++ components/esp_hw_support/sleep_modes.c | 6 +- components/esp_pm/linker.lf | 2 - components/hal/esp32/include/hal/adc_ll.h | 3 +- components/hal/esp32p4/include/hal/adc_ll.h | 588 ++++++++++++++++++ .../hal/esp32p4/include/hal/sar_ctrl_ll.h | 27 +- components/hal/esp32s2/include/hal/adc_ll.h | 1 + components/hal/esp32s3/include/hal/adc_ll.h | 3 +- components/hal/include/hal/adc_types.h | 2 +- components/soc/esp32p4/adc_periph.c | 15 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 18 +- .../soc/esp32p4/include/soc/adc_channel.h | 44 +- .../soc/esp32p4/include/soc/adc_struct.h | 1 + .../soc/esp32p4/include/soc/clk_tree_defs.h | 30 + .../soc/{rtcadc_reg.h => lp_adc_reg.h} | 0 .../soc/{rtcadc_struct.h => lp_adc_struct.h} | 25 +- .../soc/esp32p4/include/soc/regi2c_saradc.h | 41 ++ components/soc/esp32p4/include/soc/soc_caps.h | 14 +- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 1 + components/soc/include/soc/rtc_io_periph.h | 3 +- .../peripherals/adc/oneshot_read/README.md | 4 +- .../adc/oneshot_read/pytest_adc_oneshot.py | 1 - 32 files changed, 970 insertions(+), 54 deletions(-) create mode 100644 components/esp_hw_support/port/esp32p4/sar_periph_ctrl.c create mode 100644 components/hal/esp32p4/include/hal/adc_ll.h rename components/soc/esp32p4/include/soc/{rtcadc_reg.h => lp_adc_reg.h} (100%) rename components/soc/esp32p4/include/soc/{rtcadc_struct.h => lp_adc_struct.h} (96%) diff --git a/components/driver/deprecated/adc_legacy.c b/components/driver/deprecated/adc_legacy.c index 87e66e56a8d..75eda25031e 100644 --- a/components/driver/deprecated/adc_legacy.c +++ b/components/driver/deprecated/adc_legacy.c @@ -70,7 +70,7 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define FSM_ENTER() RTC_ENTER_CRITICAL() #define FSM_EXIT() RTC_EXIT_CRITICAL() -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 //prevent ADC1 being used by I2S dma and other tasks at the same time. static _lock_t adc1_dma_lock; #define SARADC1_ACQUIRE() _lock_acquire( &adc1_dma_lock ) @@ -172,7 +172,7 @@ static void adc_rtc_chan_init(adc_unit_t adc_unit) esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) { ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(adc_unit), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel"); - +#if ADC_LL_RTC_GPIO_SUPPORTED gpio_num_t gpio_num = 0; //If called with `ADC_UNIT_BOTH (ADC_UNIT_1 | ADC_UNIT_2)`, both if blocks will be run if (adc_unit == ADC_UNIT_1) { @@ -188,7 +188,7 @@ esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel) ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(gpio_num, RTC_GPIO_MODE_DISABLED), ADC_TAG, "rtc_gpio_set_direction fail"); ESP_RETURN_ON_ERROR(rtc_gpio_pulldown_dis(gpio_num), ADC_TAG, "rtc_gpio_pulldown_dis fail"); ESP_RETURN_ON_ERROR(rtc_gpio_pullup_dis(gpio_num), ADC_TAG, "rtc_gpio_pullup_dis fail"); - +#endif return ESP_OK; } diff --git a/components/driver/deprecated/driver/adc_types_legacy.h b/components/driver/deprecated/driver/adc_types_legacy.h index 8ea32f9d47c..9186b9c2457 100644 --- a/components/driver/deprecated/driver/adc_types_legacy.h +++ b/components/driver/deprecated/driver/adc_types_legacy.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -81,6 +81,18 @@ typedef enum { ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO6 */ ADC1_CHANNEL_MAX, } adc1_channel_t; +#elif CONFIG_IDF_TARGET_ESP32P4 +typedef enum { + ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO16 */ + ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO17 */ + ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO18 */ + ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO19 */ + ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO20 */ + ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO21 */ + ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO22 */ + ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO23 */ + ADC1_CHANNEL_MAX, +} adc1_channel_t; #endif // CONFIG_IDF_TARGET_* #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 @@ -103,6 +115,17 @@ typedef enum { ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO5 */ ADC2_CHANNEL_MAX, } adc2_channel_t; + +#elif CONFIG_IDF_TARGET_ESP32P4 +typedef enum { + ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO49 */ + ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO50 */ + ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO51 */ + ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO52 */ + ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO53 */ + ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO54 */ + ADC2_CHANNEL_MAX, +} adc2_channel_t; #endif #if SOC_ADC_DMA_SUPPORTED diff --git a/components/driver/test_apps/legacy_adc_driver/README.md b/components/driver/test_apps/legacy_adc_driver/README.md index a8b7833fa30..bf47d80ec64 100644 --- a/components/driver/test_apps/legacy_adc_driver/README.md +++ b/components/driver/test_apps/legacy_adc_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c index 196c56764a2..e09a741b185 100644 --- a/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c +++ b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -67,6 +67,13 @@ #define ADC_TEST_HIGH_VAL 3390 #define ADC_TEST_HIGH_THRESH 200 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ADC_TEST_LOW_VAL 3100 +#define ADC_TEST_LOW_THRESH 200 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_THRESH 200 + #endif //ADC Channels diff --git a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py index 6bc3b838d66..7f23428f5e9 100644 --- a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py +++ b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @@ -11,6 +10,7 @@ @pytest.mark.esp32c3 @pytest.mark.esp32c6 @pytest.mark.esp32h2 +@pytest.mark.esp32p4 @pytest.mark.adc @pytest.mark.parametrize( 'config', diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index 80f2711489f..d2929ea405b 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -125,10 +125,17 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a _lock_release(&s_ctx.mutex); #endif +//TODO: refactor clock enable/reset functions, add adc_digi_clk_enable/reset and adc_rtc_clk_enable/reset +#if CONFIG_IDF_TARGET_ESP32P4 + adc_ll_rtc_reset(); +#endif + if (init_config->ulp_mode == ADC_ULP_MODE_DISABLE) { sar_periph_ctrl_adc_oneshot_power_acquire(); } else { +#if !CONFIG_IDF_TARGET_ESP32P4 // # TODO: IDF-7528, IDF-7529 esp_sleep_enable_adc_tsens_monitor(true); +#endif } ESP_LOGD(TAG, "new adc unit%"PRId32" is created", unit->unit_id); @@ -229,7 +236,9 @@ esp_err_t adc_oneshot_del_unit(adc_oneshot_unit_handle_t handle) if (ulp_mode == ADC_ULP_MODE_DISABLE) { sar_periph_ctrl_adc_oneshot_power_release(); } else { +#if !CONFIG_IDF_TARGET_ESP32P4 // # TODO: IDF-7528, IDF-7529 esp_sleep_enable_adc_tsens_monitor(false); +#endif } #if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED @@ -262,7 +271,7 @@ static esp_err_t s_adc_io_init(adc_unit_t unit, adc_channel_t channel) { ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(unit), ESP_ERR_INVALID_ARG, TAG, "invalid channel"); -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED +#if !ADC_LL_RTC_GPIO_SUPPORTED uint32_t io_num = ADC_GET_IO_NUM(unit, channel); gpio_config_t cfg = { diff --git a/components/esp_adc/test_apps/adc/README.md b/components/esp_adc/test_apps/adc/README.md index a8b7833fa30..bf47d80ec64 100644 --- a/components/esp_adc/test_apps/adc/README.md +++ b/components/esp_adc/test_apps/adc/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_adc/test_apps/adc/main/test_common_adc.c b/components/esp_adc/test_apps/adc/main/test_common_adc.c index 7cf974c43f5..2636803588d 100644 --- a/components/esp_adc/test_apps/adc/main/test_common_adc.c +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.c @@ -13,6 +13,7 @@ #include "driver/rtc_io.h" #include "soc/adc_periph.h" #include "test_common_adc.h" +#include "hal/adc_ll.h" __attribute__((unused)) static const char *TAG = "TEST_ADC"; @@ -98,7 +99,7 @@ void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level) { TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel"); -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED +#if !ADC_LL_RTC_GPIO_SUPPORTED uint32_t io_num = ADC_GET_IO_NUM(unit, channel); TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY))); #else diff --git a/components/esp_adc/test_apps/adc/main/test_common_adc.h b/components/esp_adc/test_apps/adc/main/test_common_adc.h index 5228713af93..1d28c66e4ee 100644 --- a/components/esp_adc/test_apps/adc/main/test_common_adc.h +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -86,6 +86,14 @@ extern "C" { #define ADC_TEST_HIGH_VAL 3390 #define ADC_TEST_HIGH_VAL_DMA 4081 #define ADC_TEST_HIGH_THRESH 200 + +#elif CONFIG_IDF_TARGET_ESP32P4 +#define ADC_TEST_LOW_VAL 3100 +#define ADC_TEST_LOW_THRESH 200 + +#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL_DMA 4095 +#define ADC_TEST_HIGH_THRESH 200 #endif /*--------------------------------------------------------------- diff --git a/components/esp_hw_support/port/esp32p4/CMakeLists.txt b/components/esp_hw_support/port/esp32p4/CMakeLists.txt index f81f017081a..2965e1746d3 100644 --- a/components/esp_hw_support/port/esp32p4/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32p4/CMakeLists.txt @@ -10,7 +10,8 @@ set(srcs "rtc_clk_init.c" ) if(NOT BOOTLOADER_BUILD) - list(APPEND srcs "esp_crypto_lock.c") + list(APPEND srcs "sar_periph_ctrl.c" + "esp_crypto_lock.c") if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) list(APPEND srcs "mspi_timing_config.c") diff --git a/components/esp_hw_support/port/esp32p4/sar_periph_ctrl.c b/components/esp_hw_support/port/esp32p4/sar_periph_ctrl.c new file mode 100644 index 00000000000..90a4b986aed --- /dev/null +++ b/components/esp_hw_support/port/esp32p4/sar_periph_ctrl.c @@ -0,0 +1,116 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * SAR related peripherals are interdependent. This file + * provides a united control to these registers, as multiple + * components require these controls. + * + * Related peripherals are: + * - ADC + * - PWDET + */ + +#include "sdkconfig.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "esp_private/sar_periph_ctrl.h" +#include "esp_private/esp_modem_clock.h" +#include "hal/sar_ctrl_ll.h" + +static const char *TAG = "sar_periph_ctrl"; +extern portMUX_TYPE rtc_spinlock; + + +void sar_periph_ctrl_init(void) +{ + //Put SAR control mux to FSM state + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM); +} + +void sar_periph_ctrl_power_enable(void) +{ + portENTER_CRITICAL_SAFE(&rtc_spinlock); + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM); + portEXIT_CRITICAL_SAFE(&rtc_spinlock); +} + +void sar_periph_ctrl_power_disable(void) +{ + portENTER_CRITICAL_SAFE(&rtc_spinlock); + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_OFF); + portEXIT_CRITICAL_SAFE(&rtc_spinlock); +} + +/** + * This gets incremented when s_sar_power_acquire() is called, + * and decremented when s_sar_power_release() is called. + * PWDET is powered down when the value reaches zero. + * Should be modified within critical section. + */ +static int s_sar_power_on_cnt; + +static void s_sar_power_acquire(void) +{ + portENTER_CRITICAL_SAFE(&rtc_spinlock); + s_sar_power_on_cnt++; + if (s_sar_power_on_cnt == 1) { + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_ON); + } + portEXIT_CRITICAL_SAFE(&rtc_spinlock); +} + +static void s_sar_power_release(void) +{ + portENTER_CRITICAL_SAFE(&rtc_spinlock); + s_sar_power_on_cnt--; + if (s_sar_power_on_cnt < 0) { + portEXIT_CRITICAL(&rtc_spinlock); + ESP_LOGE(TAG, "%s called, but s_sar_power_on_cnt == 0", __func__); + abort(); + } else if (s_sar_power_on_cnt == 0) { + sar_ctrl_ll_set_power_mode(SAR_CTRL_LL_POWER_FSM); + } + portEXIT_CRITICAL_SAFE(&rtc_spinlock); +} + + +/*------------------------------------------------------------------------------ +* PWDET Power +*----------------------------------------------------------------------------*/ +void sar_periph_ctrl_pwdet_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_pwdet_power_release(void) +{ + s_sar_power_release(); +} + + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +void sar_periph_ctrl_adc_oneshot_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_adc_oneshot_power_release(void) +{ + s_sar_power_release(); +} + +void sar_periph_ctrl_adc_continuous_power_acquire(void) +{ + s_sar_power_acquire(); +} + +void sar_periph_ctrl_adc_continuous_power_release(void) +{ + s_sar_power_release(); +} diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 90827e94d81..39e7af37089 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -663,7 +663,7 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) #endif } -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-6496 +#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-7370 if (!(deep_sleep && s_adc_tsen_enabled)){ sar_periph_ctrl_power_disable(); @@ -679,11 +679,7 @@ FORCE_INLINE_ATTR void misc_modules_wake_prepare(void) #if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP sleep_console_usj_pad_restore(); #endif - -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-6496 sar_periph_ctrl_power_enable(); -#endif - #if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP && SOC_PM_CPU_RETENTION_BY_RTCCNTL sleep_disable_cpu_retention(); #endif diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index 8216d8a8607..29cb76425d2 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -36,8 +36,6 @@ entries: sleep_system_peripheral:peripheral_domain_pd_allowed (noflash) sleep_modem:modem_domain_pd_allowed (noflash) sleep_modem:periph_inform_out_light_sleep_overhead (noflash) - if IDF_TARGET_ESP32P4 = n: # TODO: IDF-6496 - sar_periph_ctrl:sar_periph_ctrl_power_disable (noflash) [mapping:esp_system_pm] archive: libesp_system.a diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index 08e93a0c6d0..ea9f8ef8bba 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -31,6 +31,7 @@ extern "C" { #define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (1) #define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1) #define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0) +#define ADC_LL_RTC_GPIO_SUPPORTED (1) /*--------------------------------------------------------------- DMA @@ -229,7 +230,7 @@ static inline void adc_ll_digi_set_pattern_table_len(adc_unit_t adc_n, uint32_t } /** - * Set pattern table lenth for digital controller. + * Set pattern table length for digital controller. * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h new file mode 100644 index 00000000000..8d3ed7318e5 --- /dev/null +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -0,0 +1,588 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_attr.h" + +#include "soc/adc_periph.h" +// #include "soc/ADC_struct.h" +// #include "soc/ADC_reg.h" +#include "soc/pmu_reg.h" +#include "soc/clk_tree_defs.h" +// #include "soc/pcr_struct.h" +#include "hal/misc.h" +#include "hal/assert.h" +#include "hal/adc_types.h" +#include "hal/adc_types_private.h" +#include "hal/regi2c_ctrl.h" +#include "hal/sar_ctrl_ll.h" + +#include "soc/regi2c_saradc.h" + +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/adc_struct.h" +#include "soc/lp_adc_struct.h" +#include "soc/lpperi_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) +#define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) + +/*--------------------------------------------------------------- + Oneshot +---------------------------------------------------------------*/ +#define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0) +#define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1) +#define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0) + +/*--------------------------------------------------------------- + DMA +---------------------------------------------------------------*/ + +/*--------------------------------------------------------------- + PWDET (Power Detect) +---------------------------------------------------------------*/ +#define ADC_LL_PWDET_CCT_DEFAULT (4) + +typedef enum { + ADC_LL_CTRL_RTC = 0, ///< For ADC1 and ADC2. Select RTC controller. + ADC_LL_CTRL_ULP = 1, ///< For ADC1 and ADC2. Select ULP controller. + ADC_LL_CTRL_DIG = 2, ///< For ADC1 and ADC2. Select DIG controller. + ADC_LL_CTRL_PWDET = 3, ///< ??? + ADC_LL_CTRL_ARB = 4, ///< ??? +} adc_ll_controller_t; + +typedef enum { + ADC_LL_POWER_BY_FSM = SAR_CTRL_LL_POWER_FSM, /*!< ADC XPD controlled by FSM. Used for polling mode */ + ADC_LL_POWER_SW_ON = SAR_CTRL_LL_POWER_ON, /*!< ADC XPD controlled by SW. power on. Used for DMA mode */ + ADC_LL_POWER_SW_OFF = SAR_CTRL_LL_POWER_OFF, /*!< ADC XPD controlled by SW. power off. */ +} adc_ll_power_t; + +/** + * @brief ADC digital controller (DMA mode) work mode. + * + * @note The conversion mode affects the sampling frequency: + * SINGLE_UNIT_1: When the measurement is triggered, only ADC1 is sampled once. + * SINGLE_UNIT_2: When the measurement is triggered, only ADC2 is sampled once. + * BOTH_UNIT : When the measurement is triggered, ADC1 and ADC2 are sampled at the same time. + * ALTER_UNIT : When the measurement is triggered, ADC1 or ADC2 samples alternately. + */ +typedef enum { + ADC_LL_DIGI_CONV_ONLY_ADC1 = 0, // Only use ADC1 for conversion + ADC_LL_DIGI_CONV_ONLY_ADC2 = 1, // Only use ADC2 for conversion + ADC_LL_DIGI_CONV_BOTH_UNIT = 2, // Use Both ADC1 and ADC2 for conversion simultaneously + ADC_LL_DIGI_CONV_ALTER_UNIT = 3 // Use both ADC1 and ADC2 for conversion by turn. e.g. ADC1 -> ADC2 -> ADC1 -> ADC2 ..... +} adc_ll_digi_convert_mode_t; + +typedef struct { + union { + struct { + uint8_t atten: 2; + uint8_t channel: 3; + uint8_t unit: 1; + uint8_t reserved: 2; + }; + uint8_t val; + }; +} __attribute__((packed)) adc_ll_digi_pattern_table_t; + +/** + * @brief Analyze whether the obtained raw data is correct. + * ADC2 use arbiter by default. The arbitration result can be judged by the flag bit in the original data. + * + */ +typedef struct { + union { + struct { + uint16_t data: 13; /*! 0), The data is invalid. */ + }; + uint16_t val; + }; +} adc_ll_rtc_output_data_t; + +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ + +/** + * Set SAR ADC module clock division factor. + * SAR ADC clock divided from digital controller clock. + * + * @param div Division factor. + */ +static inline void adc_ll_digi_set_clk_div(uint32_t div) +{ + /* ADC clock divided from digital controller clock clk */ + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.ctrl_reg, sar_clk_div, div); +} + +/** + * Set ADC digital controller clock division factor. The clock divided from `APLL` or `APB` clock. + * Expression: controller_clk = (APLL or APB) / (div_num + div_a / div_b + 1). + * + * @param div_num Division factor. Range: 0 ~ 255. + * @param div_b Division factor. Range: 1 ~ 63. + * @param div_a Division factor. Range: 0 ~ 63. + */ +static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div_b, uint32_t div_a) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl23, reg_adc_clk_div_num, div_num); + HP_SYS_CLKRST.root_clk_ctrl0.reg_cpu_clk_div_numerator = div_b; + HP_SYS_CLKRST.root_clk_ctrl0.reg_cpu_clk_div_denominator = div_a; +} + +/** + * Enable clock and select clock source for ADC digital controller. + * + * @param clk_src clock source for ADC digital controller. + */ +static inline void adc_ll_digi_clk_sel(adc_continuous_clk_src_t clk_src) +{ + switch (clk_src) { + case ADC_DIGI_CLK_SRC_XTAL: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_adc_clk_src_sel = 0; + break; + case ADC_DIGI_CLK_SRC_RC_FAST: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_adc_clk_src_sel = 1; + break; + case ADC_DIGI_CLK_SRC_PLL_F80M: + HP_SYS_CLKRST.peri_clk_ctrl22.reg_adc_clk_src_sel = 2; + break; + default: + HAL_ASSERT(false && "unsupported clock"); + } + // Enable ADC_CTRL_CLK (i.e. digital domain clock) + ADC.ctrl_reg.sar_clk_gated = 1; +} + +/*--------------------------------------------------------------- + PWDET(Power detect) controller setting +---------------------------------------------------------------*/ + +/** + * Set adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @param cct Range: 0 ~ 7. + */ +static inline void adc_ll_pwdet_set_cct(uint32_t cct) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + LP_ADC.meas2_mux.sar2_pwdet_cct = cct; +} + +/** + * Get adc cct for PWDET controller. + * + * @note Capacitor tuning of the PA power monitor. cct set to the same value with PHY. + * @return cct Range: 0 ~ 7. + */ +static inline uint32_t adc_ll_pwdet_get_cct(void) +{ + /* Capacitor tuning of the PA power monitor. cct set to the same value with PHY. */ + return LP_ADC.meas2_mux.sar2_pwdet_cct; +} + +/*--------------------------------------------------------------- + Common setting +---------------------------------------------------------------*/ + +/** + * Set ADC module controller. + * There are five SAR ADC controllers: + * Two digital controller: Continuous conversion mode (DMA). High performance with multiple channel scan modes; + * Two RTC controller: Single conversion modes (Polling). For low power purpose working during deep sleep; + * the other is dedicated for Power detect (PWDET / PKDET), Only support ADC2. + * + * @param adc_n ADC unit. + * @param ctrl ADC controller. + */ +__attribute__((always_inline)) +static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t ctrl) +{ + if (adc_n == ADC_UNIT_1) { + switch (ctrl) { + case ADC_LL_CTRL_RTC: + LP_ADC.meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas1_ctrl2.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas1_ctrl2.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_LL_CTRL_ULP: + LP_ADC.meas1_mux.sar1_dig_force = 0; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas1_ctrl2.meas1_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas1_ctrl2.sar1_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_LL_CTRL_DIG: + LP_ADC.meas1_mux.sar1_dig_force = 1; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas1_ctrl2.meas1_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas1_ctrl2.sar1_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + default: + break; + } + } else { // adc_n == ADC_UNIT_2 + switch (ctrl) { + case ADC_LL_CTRL_RTC: + LP_ADC.meas2_mux.sar2_rtc_force = 1; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_LL_CTRL_ULP: + LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas2_ctrl2.meas2_start_force = 0; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas2_ctrl2.sar2_en_pad_force = 0; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + case ADC_LL_CTRL_DIG: + LP_ADC.meas2_mux.sar2_rtc_force = 0; // 1: Select digital control; 0: Select RTC control. + LP_ADC.meas2_ctrl2.meas2_start_force = 1; // 1: SW control RTC ADC start; 0: ULP control RTC ADC start. + LP_ADC.meas2_ctrl2.sar2_en_pad_force = 1; // 1: SW control RTC ADC bit map; 0: ULP control RTC ADC bit map; + break; + default: + break; + } + } +} + +// /** +// * Set ADC2 module arbiter work mode. +// * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, +// * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. +// * +// * @note Only ADC2 support arbiter. +// * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. +// * +// * @param mode Refer to ``adc_arbiter_mode_t``. +// */ +// __attribute__((always_inline)) +// static inline void adc_ll_set_arbiter_work_mode(adc_arbiter_mode_t mode) +// { +// LP_ADC.meas2_mux.sar2_rtc_force = 0; // Enable arbiter in wakeup mode +// if (mode == ADC_ARB_MODE_FIX) { +// ADC.arb_ctrl.arb_grant_force = 0; +// ADC.arb_ctrl.arb_fix_priority = 1; +// } else if (mode == ADC_ARB_MODE_LOOP) { +// ADC.arb_ctrl.arb_grant_force = 0; +// ADC.arb_ctrl.arb_fix_priority = 0; +// } else { +// ADC.arb_ctrl.arb_grant_force = 1; // Shield arbiter. +// } +// } + +/** + * Set ADC2 module controller priority in arbiter. + * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, + * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. + * + * @note Only ADC2 support arbiter. + * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. + * @note Default priority: Wi-Fi(2) > RTC(1) > Digital(0); + * + * @param pri_rtc RTC controller priority. Range: 0 ~ 2. + * @param pri_dig Digital controller priority. Range: 0 ~ 2. + * @param pri_pwdet Wi-Fi controller priority. Range: 0 ~ 2. + */ +__attribute__((always_inline)) +static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, uint8_t pri_pwdet) +{ + if (pri_rtc != pri_dig && pri_rtc != pri_pwdet && pri_dig != pri_pwdet) { + ADC.arb_ctrl.arb_rtc_priority = pri_rtc; + ADC.arb_ctrl.arb_apb_priority = pri_dig; + ADC.arb_ctrl.arb_wifi_priority = pri_pwdet; + } + /* Should select highest priority controller. */ + if (pri_rtc > pri_dig) { + ADC.arb_ctrl.arb_apb_force = 0; + ADC.arb_ctrl.arb_rtc_force = 1; + ADC.arb_ctrl.arb_wifi_force = 0; + } else { + ADC.arb_ctrl.arb_apb_force = 1; + ADC.arb_ctrl.arb_rtc_force = 0; + ADC.arb_ctrl.arb_wifi_force = 0; + } +} + +/*--------------------------------------------------------------- + Oneshot Read +---------------------------------------------------------------*/ + +static inline void adc_ll_vref_output(adc_unit_t adc, adc_channel_t channel, bool en) +{ + abort(); +} + +/** + * Set adc output data format for RTC controller. + * + * @note ESP32P4 RTC controller only support 12bit. + * @param adc_n ADC unit. + * @param bits Output data bits width option. + */ +static inline void adc_oneshot_ll_set_output_bits(adc_unit_t adc_n, adc_bitwidth_t bits) +{ + //ESP32P4 only supports 12bit, leave here for compatibility + HAL_ASSERT(bits == ADC_BITWIDTH_12 || bits == ADC_BITWIDTH_DEFAULT); +} + +/** + * Enable adc channel to start convert. + * + * @note Only one channel can be selected for once measurement. + * + * @param adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_oneshot_ll_set_channel(adc_unit_t adc_n, adc_channel_t channel) +{ + if (adc_n == ADC_UNIT_1) { + LP_ADC.meas1_ctrl2.sar1_en_pad = (1 << channel); //only one channel is selected. + } else { // adc_n == ADC_UNIT_2 + LP_ADC.meas2_ctrl2.sar2_en_pad = (1 << ((channel + 2))); //only one channel is selected. + } +} + +/** + * Disable adc channel to start convert. + * + * @note Only one channel can be selected in once measurement. + * + * @param adc_n ADC unit. + * @param channel ADC channel number for each ADCn. + */ +static inline void adc_oneshot_ll_disable_channel(adc_unit_t adc_n) +{ + if (adc_n == ADC_UNIT_1) { + LP_ADC.meas1_ctrl2.sar1_en_pad = 0; //only one channel is selected. + } else { // adc_n == ADC_UNIT_2 + LP_ADC.meas2_ctrl2.sar2_en_pad = 0; //only one channel is selected. + } +} + +/** + * Start conversion once by software for RTC controller. + * + * @note It may be block to wait conversion idle for ADC1. + * + * @param adc_n ADC unit. + */ +static inline void adc_oneshot_ll_start(adc_unit_t adc_n) +{ + if (adc_n == ADC_UNIT_1) { + LP_ADC.meas1_ctrl2.meas1_start_sar = 0; + LP_ADC.meas1_ctrl2.meas1_start_sar = 1; + } else { // adc_n == ADC_UNIT_2 + LP_ADC.meas2_ctrl2.meas2_start_sar = 0; + LP_ADC.meas2_ctrl2.meas2_start_sar = 1; + } +} + +/** + * Clear the event for each ADCn for Oneshot mode + * + * @param event ADC event + */ +static inline void adc_oneshot_ll_clear_event(uint32_t event_mask) +{ + // ADC.int_clr.val |= event_mask; +} + +/** + * Check the event for each ADCn for Oneshot mode + * + * @param event ADC event + * + * @return + * -true : The conversion process is finish. + * -false : The conversion process is not finish. + */ +static inline bool adc_oneshot_ll_get_event(uint32_t event) +{ + bool ret = true; + if (event == ADC_LL_EVENT_ADC1_ONESHOT_DONE) { + ret = (bool)LP_ADC.meas1_ctrl2.meas1_done_sar; + } else if (event == ADC_LL_EVENT_ADC2_ONESHOT_DONE) { + ret = (bool)LP_ADC.meas2_ctrl2.meas2_done_sar; + } else { + HAL_ASSERT(false); + } + return ret; +} + +/** + * Get the converted value for each ADCn for RTC controller. + * + * @param adc_n ADC unit. + * @return + * - Converted value. + */ +static inline uint32_t adc_oneshot_ll_get_raw_result(adc_unit_t adc_n) +{ + uint32_t ret_val = 0; + if (adc_n == ADC_UNIT_1) { + ret_val = HAL_FORCE_READ_U32_REG_FIELD(LP_ADC.meas1_ctrl2, meas1_data_sar); + } else { // adc_n == ADC_UNIT_2 + ret_val = HAL_FORCE_READ_U32_REG_FIELD(LP_ADC.meas2_ctrl2, meas2_data_sar); + } + return ret_val; +} + +/** + * Analyze whether the obtained raw data is correct. + * ADC2 can use arbiter. The arbitration result can be judged by the flag bit in the original data. + * + * @param adc_n ADC unit. + * @param raw ADC raw data input (convert value). + * @return + * - true: raw data is valid + * - false: raw data is invalid + */ +static inline bool adc_oneshot_ll_raw_check_valid(adc_unit_t adc_n, uint32_t raw) +{ + if (adc_n == ADC_UNIT_1) { + return true; + } + adc_ll_rtc_output_data_t *temp = (adc_ll_rtc_output_data_t *)&raw; + if (temp->flag == 0) { + return true; + } else { + //Could be ADC_LL_RTC_CTRL_UNSELECTED, ADC_LL_RTC_CTRL_BREAK or ADC_LL_RTC_DATA_FAIL + return false; + } +} + +/** + * ADC module RTC output data invert or not. + * + * @param adc_n ADC unit. + * @param inv_en data invert or not. + */ +static inline void adc_oneshot_ll_output_invert(adc_unit_t adc_n, bool inv_en) +{ + if (adc_n == ADC_UNIT_1) { + LP_ADC.reader1_ctrl.sar1_data_inv = inv_en; // Enable / Disable ADC data invert + } else { // adc_n == ADC_UNIT_2 + LP_ADC.reader2_ctrl.sar2_data_inv = inv_en; // Enable / Disable ADC data invert + } +} + +/** + * Enable oneshot conversion trigger + * + * @param adc_n ADC unit + */ +static inline void adc_oneshot_ll_enable(adc_unit_t adc_n) +{ + (void)adc_n; + HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = 1; + HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_en = 1; +} + +/** + * Disable oneshot conversion trigger for all the ADC units + */ +static inline void adc_oneshot_ll_disable_all_unit(void) +{ + HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = 0; + HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_en = 0; +} + +/*--------------------------------------------------------------- + RTC controller setting +---------------------------------------------------------------*/ +/** + * ADC SAR clock division factor setting. ADC SAR clock divided from `RTC_FAST_CLK`. + * + * @param div Division factor. + */ +static inline void adc_ll_set_sar_clk_div(adc_unit_t adc_n, uint32_t div) +{ + if (adc_n == ADC_UNIT_1) { + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ADC.reader1_ctrl, sar1_clk_div, div); + } else { // adc_n == ADC_UNIT_2 + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ADC.reader2_ctrl, sar2_clk_div, div); + } +} + +/** + * Reset RTC controller FSM. + */ +static inline void adc_ll_rtc_reset(void) +{ + LPPERI.reset_en.rst_en_lp_adc = 1; + LPPERI.reset_en.rst_en_lp_adc = 0; +} + + +/** + * Set the attenuation of a particular channel on ADCn. + * + * @note For any given channel, this function must be called before the first time conversion. + * + * The default ADC full-scale voltage is 1.1V. To read higher voltages (up to the pin maximum voltage, + * usually 3.3V) requires setting >0dB signal attenuation for that ADC channel. + * + * When VDD_A is 3.3V: + * + * - 0dB attenuation (ADC_ATTEN_DB_0) gives full-scale voltage 1.1V + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) gives full-scale voltage 1.5V + * - 6dB attenuation (ADC_ATTEN_DB_6) gives full-scale voltage 2.2V + * - 11dB attenuation (ADC_ATTEN_DB_12) gives full-scale voltage 3.9V (see note below) + * + * @note The full-scale voltage is the voltage corresponding to a maximum reading (depending on ADC1 configured + * bit width, this value is: 4095 for 12-bits, 2047 for 11-bits, 1023 for 10-bits, 511 for 9 bits.) + * + * @note At 11dB attenuation the maximum voltage is limited by VDD_A, not the full scale voltage. + * + * Due to ADC characteristics, most accurate results are obtained within the following approximate voltage ranges: + * + * - 0dB attenuation (ADC_ATTEN_DB_0) between 100 and 950mV + * - 2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV + * - 6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV + * - 11dB attenuation (ADC_ATTEN_DB_12) between 150 to 2450mV + * + * For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges. + * + * @param adc_n ADC unit. + * @param channel ADCn channel number. + * @param atten The attenuation option. + */ +static inline void adc_oneshot_ll_set_atten(adc_unit_t adc_n, adc_channel_t channel, adc_atten_t atten) +{ + if (adc_n == ADC_UNIT_1) { + LP_ADC.atten1.sar1_atten = ( LP_ADC.atten1.sar1_atten & ~(0x3 << (channel * 2)) ) | ((atten & 0x3) << (channel * 2)); + } else { // adc_n == ADC_UNIT_2 + LP_ADC.atten2.sar2_atten = ( LP_ADC.atten2.sar2_atten & ~(0x3 << ((channel + 2) * 2)) ) | ((atten & 0x3) << ((channel + 2) * 2)); + } +} + +/** + * Get the attenuation of a particular channel on ADCn. + * + * @param adc_n ADC unit. + * @param channel ADCn channel number. + * @return atten The attenuation option. + */ +__attribute__((always_inline)) +static inline adc_atten_t adc_ll_get_atten(adc_unit_t adc_n, adc_channel_t channel) +{ + if (adc_n == ADC_UNIT_1) { + return (adc_atten_t)((LP_ADC.atten1.sar1_atten >> (channel * 2)) & 0x3); + } else { + return (adc_atten_t)((LP_ADC.atten2.sar2_atten >> ((channel + 2) * 2)) & 0x3); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/sar_ctrl_ll.h b/components/hal/esp32p4/include/hal/sar_ctrl_ll.h index 60f26337cdb..3a8eff42935 100644 --- a/components/hal/esp32p4/include/hal/sar_ctrl_ll.h +++ b/components/hal/esp32p4/include/hal/sar_ctrl_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,6 +20,7 @@ #include #include #include "soc/soc.h" +#include "soc/lp_adc_struct.h" #ifdef __cplusplus extern "C" { @@ -39,6 +40,30 @@ typedef enum { /*--------------------------------------------------------------- SAR power control ---------------------------------------------------------------*/ + +/** + * Set SAR power mode + * + * @param mode See `sar_ctrl_ll_power_t` + */ +__attribute__((always_inline)) +static inline void sar_ctrl_ll_set_power_mode(sar_ctrl_ll_power_t mode) +{ + if (mode == SAR_CTRL_LL_POWER_FSM) { + // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 1; + LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x0; + LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x0; + } else if (mode == SAR_CTRL_LL_POWER_ON) { + // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 1; + LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x3; + LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x3; + } else { + // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 0; + LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x2; + LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x2; + } +} + /** * @brief Set SAR power mode when controlled by PWDET * diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index 1344a64970d..ef6712a53f6 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -40,6 +40,7 @@ extern "C" { #define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0) #define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1) #define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0) +#define ADC_LL_RTC_GPIO_SUPPORTED (1) /*--------------------------------------------------------------- DMA diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index 7e0f405e1fc..7c5e3b4121c 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,6 +43,7 @@ extern "C" { #define ADC_LL_DATA_INVERT_DEFAULT(PERIPH_NUM) (0) #define ADC_LL_SAR_CLK_DIV_DEFAULT(PERIPH_NUM) (1) #define ADC_LL_DELAY_CYCLE_AFTER_DONE_SIGNAL (0) +#define ADC_LL_RTC_GPIO_SUPPORTED (1) /*--------------------------------------------------------------- DMA diff --git a/components/hal/include/hal/adc_types.h b/components/hal/include/hal/adc_types.h index 063e3ab3c42..b37689afe88 100644 --- a/components/hal/include/hal/adc_types.h +++ b/components/hal/include/hal/adc_types.h @@ -191,7 +191,7 @@ typedef struct { }; } adc_digi_output_data_t; -#elif CONFIG_IDF_TARGET_ESP32S3 +#elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4 /** * @brief ADC digital controller (DMA mode) output data format. * Used to analyze the acquired ADC (DMA) data. diff --git a/components/soc/esp32p4/adc_periph.c b/components/soc/esp32p4/adc_periph.c index 47081cfc689..fe4445b44eb 100644 --- a/components/soc/esp32p4/adc_periph.c +++ b/components/soc/esp32p4/adc_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,4 +7,15 @@ #include "soc/adc_periph.h" /* Store IO number corresponding to the ADC channel number. */ -const int adc_channel_io_map[SOC_ADC_PERIPH_NUM][SOC_ADC_MAX_CHANNEL_NUM] = {}; +const int adc_channel_io_map[SOC_ADC_PERIPH_NUM][SOC_ADC_MAX_CHANNEL_NUM] = { + /* ADC1 */ + { + ADC1_CHANNEL_0_GPIO_NUM, ADC1_CHANNEL_1_GPIO_NUM, ADC1_CHANNEL_2_GPIO_NUM, ADC1_CHANNEL_3_GPIO_NUM, + ADC1_CHANNEL_4_GPIO_NUM, ADC1_CHANNEL_5_GPIO_NUM, ADC1_CHANNEL_6_GPIO_NUM, ADC1_CHANNEL_7_GPIO_NUM + }, + /* ADC2 */ + { + ADC2_CHANNEL_0_GPIO_NUM, ADC2_CHANNEL_1_GPIO_NUM, ADC2_CHANNEL_2_GPIO_NUM, + ADC2_CHANNEL_3_GPIO_NUM, ADC2_CHANNEL_4_GPIO_NUM, ADC2_CHANNEL_5_GPIO_NUM + } +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index ab97a343dad..1c91223f790 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -3,6 +3,10 @@ # using gen_soc_caps_kconfig.py, do not edit manually ##################################################### +config SOC_ADC_SUPPORTED + bool + default y + config SOC_ANA_CMPR_SUPPORTED bool default y @@ -307,13 +311,21 @@ config SOC_AES_SUPPORT_AES_256 bool default y +config SOC_ADC_RTC_CTRL_SUPPORTED + bool + default y + +config SOC_ADC_DIG_CTRL_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int - default 1 + default 2 config SOC_ADC_MAX_CHANNEL_NUM int - default 7 + default 8 config SOC_ADC_ATTEN_NUM int @@ -321,7 +333,7 @@ config SOC_ADC_ATTEN_NUM config SOC_ADC_DIGI_CONTROLLER_NUM int - default 1 + default 2 config SOC_ADC_PATT_LEN_MAX int diff --git a/components/soc/esp32p4/include/soc/adc_channel.h b/components/soc/esp32p4/include/soc/adc_channel.h index d2aa55b41e9..1d95c0d19ac 100644 --- a/components/soc/esp32p4/include/soc/adc_channel.h +++ b/components/soc/esp32p4/include/soc/adc_channel.h @@ -1,7 +1,49 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once + +#define ADC1_GPIO16_CHANNEL 0 +#define ADC1_CHANNEL_0_GPIO_NUM 16 + +#define ADC1_GPIO17_CHANNEL 1 +#define ADC1_CHANNEL_1_GPIO_NUM 17 + +#define ADC1_GPIO18_CHANNEL 2 +#define ADC1_CHANNEL_2_GPIO_NUM 18 + +#define ADC1_GPIO19_CHANNEL 3 +#define ADC1_CHANNEL_3_GPIO_NUM 19 + +#define ADC1_GPIO20_CHANNEL 4 +#define ADC1_CHANNEL_4_GPIO_NUM 20 + +#define ADC1_GPIO21_CHANNEL 5 +#define ADC1_CHANNEL_5_GPIO_NUM 21 + +#define ADC1_GPIO22_CHANNEL 6 +#define ADC1_CHANNEL_6_GPIO_NUM 22 + +#define ADC1_GPIO23_CHANNEL 7 +#define ADC1_CHANNEL_7_GPIO_NUM 23 + +#define ADC2_GPIO49_CHANNEL 0 +#define ADC2_CHANNEL_0_GPIO_NUM 49 + +#define ADC2_GPIO50_CHANNEL 1 +#define ADC2_CHANNEL_1_GPIO_NUM 50 + +#define ADC2_GPIO51_CHANNEL 2 +#define ADC2_CHANNEL_2_GPIO_NUM 51 + +#define ADC2_GPIO52_CHANNEL 3 +#define ADC2_CHANNEL_3_GPIO_NUM 52 + +#define ADC2_GPIO53_CHANNEL 4 +#define ADC2_CHANNEL_4_GPIO_NUM 53 + +#define ADC2_GPIO54_CHANNEL 5 +#define ADC2_CHANNEL_5_GPIO_NUM 54 diff --git a/components/soc/esp32p4/include/soc/adc_struct.h b/components/soc/esp32p4/include/soc/adc_struct.h index 54f7a7af026..efaade0acb6 100644 --- a/components/soc/esp32p4/include/soc/adc_struct.h +++ b/components/soc/esp32p4/include/soc/adc_struct.h @@ -684,6 +684,7 @@ typedef struct { volatile adc_ctrl_date_reg_t ctrl_date; } adc_dev_t; +extern adc_dev_t ADC; #ifndef __cplusplus _Static_assert(sizeof(adc_dev_t) == 0x400, "Invalid size of adc_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index 5679247b501..d500fe63fdb 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -589,6 +589,36 @@ typedef enum { //////////////////////////////////////////////////ADC/////////////////////////////////////////////////////////////////// +/** + * @brief Array initializer for all supported clock sources of ADC digital controller + */ +#define SOC_ADC_DIGI_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_PLL_F80M, SOC_MOD_CLK_RC_FAST} + +/** + * @brief ADC digital controller clock source + */ +typedef enum { + ADC_DIGI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ + ADC_DIGI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + ADC_DIGI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ + + ADC_DIGI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default clock choice */ +} soc_periph_adc_digi_clk_src_t; + +/** + * @brief Array initializer for all supported clock sources of ADC RTC controller + */ +#define SOC_ADC_RTC_CLKS {SOC_MOD_CLK_RC_FAST} + +/** + * @brief ADC RTC controller clock source + */ +typedef enum { + ADC_RTC_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ + + ADC_RTC_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default clock choice */ +} soc_periph_adc_rtc_clk_src_t; + //////////////////////////////////////////////////MWDT///////////////////////////////////////////////////////////////// /** diff --git a/components/soc/esp32p4/include/soc/rtcadc_reg.h b/components/soc/esp32p4/include/soc/lp_adc_reg.h similarity index 100% rename from components/soc/esp32p4/include/soc/rtcadc_reg.h rename to components/soc/esp32p4/include/soc/lp_adc_reg.h diff --git a/components/soc/esp32p4/include/soc/rtcadc_struct.h b/components/soc/esp32p4/include/soc/lp_adc_struct.h similarity index 96% rename from components/soc/esp32p4/include/soc/rtcadc_struct.h rename to components/soc/esp32p4/include/soc/lp_adc_struct.h index be919a948b8..0886d6ba2a0 100644 --- a/components/soc/esp32p4/include/soc/rtcadc_struct.h +++ b/components/soc/esp32p4/include/soc/lp_adc_struct.h @@ -259,11 +259,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_raw:1; /** cocpu_saradc1_error_int_raw : R/WTC/SS; bitpos: [2]; default: 0; - * An errro occurs from ADC1, int raw. + * An error occurs from ADC1, int raw. */ uint32_t cocpu_saradc1_error_int_raw:1; /** cocpu_saradc2_error_int_raw : R/WTC/SS; bitpos: [3]; default: 0; - * An errro occurs from ADC2, int raw. + * An error occurs from ADC2, int raw. */ uint32_t cocpu_saradc2_error_int_raw:1; /** cocpu_saradc1_wake_int_raw : R/WTC/SS; bitpos: [4]; default: 0; @@ -293,11 +293,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_ena:1; /** cocpu_saradc1_error_int_ena : R/WTC; bitpos: [2]; default: 0; - * An errro occurs from ADC1, int enable. + * An error occurs from ADC1, int enable. */ uint32_t cocpu_saradc1_error_int_ena:1; /** cocpu_saradc2_error_int_ena : R/WTC; bitpos: [3]; default: 0; - * An errro occurs from ADC2, int enable. + * An error occurs from ADC2, int enable. */ uint32_t cocpu_saradc2_error_int_ena:1; /** cocpu_saradc1_wake_int_ena : R/WTC; bitpos: [4]; default: 0; @@ -327,11 +327,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_st:1; /** cocpu_saradc1_error_int_st : RO; bitpos: [2]; default: 0; - * An errro occurs from ADC1, int status. + * An error occurs from ADC1, int status. */ uint32_t cocpu_saradc1_error_int_st:1; /** cocpu_saradc2_error_int_st : RO; bitpos: [3]; default: 0; - * An errro occurs from ADC2, int status. + * An error occurs from ADC2, int status. */ uint32_t cocpu_saradc2_error_int_st:1; /** cocpu_saradc1_wake_int_st : RO; bitpos: [4]; default: 0; @@ -361,11 +361,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_clr:1; /** cocpu_saradc1_error_int_clr : WT; bitpos: [2]; default: 0; - * An errro occurs from ADC1, int clear. + * An error occurs from ADC1, int clear. */ uint32_t cocpu_saradc1_error_int_clr:1; /** cocpu_saradc2_error_int_clr : WT; bitpos: [3]; default: 0; - * An errro occurs from ADC2, int clear. + * An error occurs from ADC2, int clear. */ uint32_t cocpu_saradc2_error_int_clr:1; /** cocpu_saradc1_wake_int_clr : WT; bitpos: [4]; default: 0; @@ -395,11 +395,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_ena_w1ts:1; /** cocpu_saradc1_error_int_ena_w1ts : WT; bitpos: [2]; default: 0; - * An errro occurs from ADC1, write 1 to assert int enable. + * An error occurs from ADC1, write 1 to assert int enable. */ uint32_t cocpu_saradc1_error_int_ena_w1ts:1; /** cocpu_saradc2_error_int_ena_w1ts : WT; bitpos: [3]; default: 0; - * An errro occurs from ADC2, write 1 to assert int enable. + * An error occurs from ADC2, write 1 to assert int enable. */ uint32_t cocpu_saradc2_error_int_ena_w1ts:1; /** cocpu_saradc1_wake_int_ena_w1ts : WT; bitpos: [4]; default: 0; @@ -429,11 +429,11 @@ typedef union { */ uint32_t cocpu_saradc2_int_ena_w1tc:1; /** cocpu_saradc1_error_int_ena_w1tc : WT; bitpos: [2]; default: 0; - * An errro occurs from ADC1, write 1 to deassert int enable. + * An error occurs from ADC1, write 1 to deassert int enable. */ uint32_t cocpu_saradc1_error_int_ena_w1tc:1; /** cocpu_saradc2_error_int_ena_w1tc : WT; bitpos: [3]; default: 0; - * An errro occurs from ADC2, write 1 to deassert int enable. + * An error occurs from ADC2, write 1 to deassert int enable. */ uint32_t cocpu_saradc2_error_int_ena_w1tc:1; /** cocpu_saradc1_wake_int_ena_w1tc : WT; bitpos: [4]; default: 0; @@ -592,6 +592,7 @@ typedef struct { volatile rtcadc_sar2_hw_wakeup_reg_t sar2_hw_wakeup; } rtcadc_dev_t; +extern rtcadc_dev_t LP_ADC; #ifndef __cplusplus _Static_assert(sizeof(rtcadc_dev_t) == 0x74, "Invalid size of rtcadc_dev_t structure"); diff --git a/components/soc/esp32p4/include/soc/regi2c_saradc.h b/components/soc/esp32p4/include/soc/regi2c_saradc.h index b784a26a3ea..88fa3640bcd 100644 --- a/components/soc/esp32p4/include/soc/regi2c_saradc.h +++ b/components/soc/esp32p4/include/soc/regi2c_saradc.h @@ -37,3 +37,44 @@ #define I2C_SAR_ADC_DTEST_VDD_GRP1 9 #define I2C_SAR_ADC_DTEST_VDD_GRP1_MSB 3 #define I2C_SAR_ADC_DTEST_VDD_GRP1_LSB 0 + +#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0 + +#define ADC_SAR1_DREF_ADDR 0x2 +#define ADC_SAR1_DREF_ADDR_MSB 0x6 +#define ADC_SAR1_DREF_ADDR_LSB 0x4 + +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0 + +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0 + + +#define ADC_SAR2_SAMPLE_CYCLE_ADDR 0x5 +#define ADC_SAR2_SAMPLE_CYCLE_ADDR_MSB 0x2 +#define ADC_SAR2_SAMPLE_CYCLE_ADDR_LSB 0x0 + +#define ADC_SAR2_DREF_ADDR 0x5 +#define ADC_SAR2_DREF_ADDR_MSB 0x6 +#define ADC_SAR2_DREF_ADDR_LSB 0x4 + +#define ADC_SAR1_ENCAL_REF_ADDR 0x7 +#define ADC_SAR1_ENCAL_REF_ADDR_MSB 4 +#define ADC_SAR1_ENCAL_REF_ADDR_LSB 4 + +#define ADC_SAR1_ENCAL_GND_ADDR 0x7 +#define ADC_SAR1_ENCAL_GND_ADDR_MSB 5 +#define ADC_SAR1_ENCAL_GND_ADDR_LSB 5 + +#define ADC_SAR2_ENCAL_REF_ADDR 0x7 +#define ADC_SAR2_ENCAL_REF_ADDR_MSB 6 +#define ADC_SAR2_ENCAL_REF_ADDR_LSB 6 + +#define ADC_SAR2_ENCAL_GND_ADDR 0x7 +#define ADC_SAR2_ENCAL_GND_ADDR_MSB 7 +#define ADC_SAR2_ENCAL_GND_ADDR_LSB 7 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index e277bd82974..b57a0c39cc0 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -17,7 +17,7 @@ #pragma once /*-------------------------- COMMON CAPS ---------------------------------------*/ -// #define SOC_ADC_SUPPORTED 1 //TODO: IDF-6496 +#define SOC_ADC_SUPPORTED 1 #define SOC_ANA_CMPR_SUPPORTED 1 #define SOC_DEDICATED_GPIO_SUPPORTED 1 #define SOC_UART_SUPPORTED 1 @@ -108,18 +108,20 @@ /*-------------------------- ADC CAPS -------------------------------*/ /*!< SAR ADC Module*/ -// #define SOC_ADC_DIG_CTRL_SUPPORTED 1 //TODO: IDF-6496, TODO: IDF-6497 +#define SOC_ADC_RTC_CTRL_SUPPORTED 1 +#define SOC_ADC_DIG_CTRL_SUPPORTED 1 +// #define SOC_ADC_ARBITER_SUPPORTED 1 // #define SOC_ADC_DIG_IIR_FILTER_SUPPORTED 1 // #define SOC_ADC_MONITOR_SUPPORTED 1 #define SOC_ADC_DIG_SUPPORTED_UNIT(UNIT) 1 //Digital controller supported ADC unit // #define SOC_ADC_DMA_SUPPORTED 1 -#define SOC_ADC_PERIPH_NUM (1U) -#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (7) -#define SOC_ADC_MAX_CHANNEL_NUM (7) +#define SOC_ADC_PERIPH_NUM (2) +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (14) +#define SOC_ADC_MAX_CHANNEL_NUM (8) #define SOC_ADC_ATTEN_NUM (4) /*!< Digital */ -#define SOC_ADC_DIGI_CONTROLLER_NUM (1U) +#define SOC_ADC_DIGI_CONTROLLER_NUM (2) #define SOC_ADC_PATT_LEN_MAX (8) /*!< Two pattern tables, each contains 4 items. Each item takes 1 byte */ #define SOC_ADC_DIGI_MAX_BITWIDTH (12) #define SOC_ADC_DIGI_MIN_BITWIDTH (12) diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index f937560b0aa..0b293ba89e7 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -82,6 +82,7 @@ PROVIDE ( LP_I2C = 0x50122000 ); PROVIDE ( LP_SPI = 0x50123000 ); PROVIDE ( LP_WDT = 0x50116000 ); PROVIDE ( LP_I2S = 0x50125000 ); +PROVIDE ( LP_ADC = 0x50127000 ); PROVIDE ( LP_TOUCH = 0x50128000 ); PROVIDE ( LP_GPIO = 0x5012A000 ); PROVIDE ( LP_PERI_PMS = 0x5012E000 ); diff --git a/components/soc/include/soc/rtc_io_periph.h b/components/soc/include/soc/rtc_io_periph.h index 19c4959a57c..935bd07f716 100644 --- a/components/soc/include/soc/rtc_io_periph.h +++ b/components/soc/include/soc/rtc_io_periph.h @@ -9,12 +9,13 @@ #include //include soc related (generated) definitions #include "soc/soc_caps.h" +#include "sdkconfig.h" #if SOC_RTCIO_PIN_COUNT > 0 #include "soc/rtc_io_channel.h" #endif -#if SOC_ADC_RTC_CTRL_SUPPORTED +#if SOC_ADC_RTC_CTRL_SUPPORTED && !CONFIG_IDF_TARGET_ESP32P4 #include "soc/sens_struct.h" #endif diff --git a/examples/peripherals/adc/oneshot_read/README.md b/examples/peripherals/adc/oneshot_read/README.md index cc872ff214a..15404c47ee1 100644 --- a/examples/peripherals/adc/oneshot_read/README.md +++ b/examples/peripherals/adc/oneshot_read/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # ADC Single Read Example diff --git a/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py b/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py index 9d5ad5058ac..8bb86e3c00b 100644 --- a/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py +++ b/examples/peripherals/adc/oneshot_read/pytest_adc_oneshot.py @@ -1,6 +1,5 @@ # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded.dut import Dut From e63d6582ccfeed2fd9c094b9be59b99f66818ea2 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 28 Mar 2024 15:19:45 +0800 Subject: [PATCH 234/548] feat(adc): move adc periph enable/reset functions to ll layer --- components/driver/deprecated/adc_dma_legacy.c | 5 +- components/esp_adc/adc_continuous.c | 4 +- components/esp_adc/adc_oneshot.c | 7 --- .../test_apps/adc/main/test_adc_performance.c | 3 ++ components/esp_hw_support/adc_share_hw_ctrl.c | 14 +++--- .../include/esp_private/adc_share_hw_ctrl.h | 8 +++- components/hal/esp32/include/hal/adc_ll.h | 22 ++++++++- components/hal/esp32c2/include/hal/adc_ll.h | 26 +++++++++- components/hal/esp32c3/include/hal/adc_ll.h | 24 ++++++++++ components/hal/esp32c6/include/hal/adc_ll.h | 21 ++++++++- components/hal/esp32h2/include/hal/adc_ll.h | 20 +++++++- components/hal/esp32p4/include/hal/adc_ll.h | 47 +++++++++---------- components/hal/esp32s2/include/hal/adc_ll.h | 30 +++++++++++- components/hal/esp32s3/include/hal/adc_ll.h | 24 ++++++++++ 14 files changed, 209 insertions(+), 46 deletions(-) diff --git a/components/driver/deprecated/adc_dma_legacy.c b/components/driver/deprecated/adc_dma_legacy.c index dd3e9f3a727..ca95596cd05 100644 --- a/components/driver/deprecated/adc_dma_legacy.c +++ b/components/driver/deprecated/adc_dma_legacy.c @@ -434,7 +434,10 @@ esp_err_t adc_digi_start(void) return ESP_ERR_INVALID_STATE; } //reset ADC digital part to reset ADC sampling EOF counter - periph_module_reset(PERIPH_SARADC_MODULE); + ADC_BUS_CLK_ATOMIC() { + adc_ll_reset_register(); + } + sar_periph_ctrl_adc_continuous_power_acquire(); //reset flags s_adc_digi_ctx->ringbuf_overflow_flag = 0; diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index 6a13fb2911b..fd748b8e24c 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -245,7 +245,9 @@ esp_err_t adc_continuous_start(adc_continuous_handle_t handle) ESP_RETURN_ON_FALSE(handle->fsm == ADC_FSM_INIT, ESP_ERR_INVALID_STATE, ADC_TAG, "ADC continuous mode isn't in the init state, it's started already"); //reset ADC digital part to reset ADC sampling EOF counter - periph_module_reset(PERIPH_SARADC_MODULE); + ADC_BUS_CLK_ATOMIC() { + adc_ll_reset_register(); + } if (handle->pm_lock) { ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(handle->pm_lock), ADC_TAG, "acquire pm_lock failed"); diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index d2929ea405b..0691e22f1ad 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -115,7 +115,6 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a }; adc_oneshot_hal_init(&(unit->hal), &config); -#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED //To enable the APB_SARADC periph if needed _lock_acquire(&s_ctx.mutex); s_ctx.apb_periph_ref_cnts++; @@ -123,12 +122,6 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a adc_apb_periph_claim(); } _lock_release(&s_ctx.mutex); -#endif - -//TODO: refactor clock enable/reset functions, add adc_digi_clk_enable/reset and adc_rtc_clk_enable/reset -#if CONFIG_IDF_TARGET_ESP32P4 - adc_ll_rtc_reset(); -#endif if (init_config->ulp_mode == ADC_ULP_MODE_DISABLE) { sar_periph_ctrl_adc_oneshot_power_acquire(); diff --git a/components/esp_adc/test_apps/adc/main/test_adc_performance.c b/components/esp_adc/test_apps/adc/main/test_adc_performance.c index 82ef8dde078..f6f15e6dbc3 100644 --- a/components/esp_adc/test_apps/adc/main/test_adc_performance.c +++ b/components/esp_adc/test_apps/adc/main/test_adc_performance.c @@ -28,6 +28,7 @@ __attribute__((unused)) static const char *TAG = "TEST_ADC"; #define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_2 #endif +#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-6497 static int s_adc_count_size; static int *s_p_adc_count; static int s_adc_offset = -1; @@ -131,6 +132,8 @@ static float s_print_summary(bool figure) return sqrt(variation_square / count); } +#endif + #if SOC_ADC_DMA_SUPPORTED /*--------------------------------------------------------------- ADC Continuous Average / STD_Deviation Test diff --git a/components/esp_hw_support/adc_share_hw_ctrl.c b/components/esp_hw_support/adc_share_hw_ctrl.c index 86d3738d5e0..32f3c67b79b 100644 --- a/components/esp_hw_support/adc_share_hw_ctrl.c +++ b/components/esp_hw_support/adc_share_hw_ctrl.c @@ -12,7 +12,7 @@ * * However, usages of above components are different. * Therefore, we put the common used parts into `esp_hw_support`, including: - * - adc power maintainance + * - adc power maintenance * - adc hw calibration settings * - adc locks, to prevent concurrently using adc hw */ @@ -205,10 +205,10 @@ void adc_apb_periph_claim(void) portENTER_CRITICAL(&s_spinlock); s_adc_digi_ctrlr_cnt++; if (s_adc_digi_ctrlr_cnt == 1) { - //enable ADC digital part - periph_module_enable(PERIPH_SARADC_MODULE); - //reset ADC digital part - periph_module_reset(PERIPH_SARADC_MODULE); + ADC_BUS_CLK_ATOMIC() { + adc_ll_enable_bus_clock(true); + adc_ll_reset_register(); + } } portEXIT_CRITICAL(&s_spinlock); @@ -219,7 +219,9 @@ void adc_apb_periph_free(void) portENTER_CRITICAL(&s_spinlock); s_adc_digi_ctrlr_cnt--; if (s_adc_digi_ctrlr_cnt == 0) { - periph_module_disable(PERIPH_SARADC_MODULE); + ADC_BUS_CLK_ATOMIC() { + adc_ll_enable_bus_clock(false); + } } else if (s_adc_digi_ctrlr_cnt < 0) { portEXIT_CRITICAL(&s_spinlock); ESP_LOGE(TAG, "%s called, but `s_adc_digi_ctrlr_cnt == 0`", __func__); diff --git a/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h b/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h index 5bf1084730f..a0c82e394bc 100644 --- a/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h +++ b/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h @@ -12,7 +12,7 @@ * * However, usages of above components are different. * Therefore, we put the common used parts into `esp_hw_support`, including: - * - adc power maintainance + * - adc power maintenance * - adc hw calibration settings * - adc locks, to prevent concurrently using adc hw */ @@ -26,6 +26,12 @@ extern "C" { #endif +#if SOC_RCC_IS_INDEPENDENT || CONFIG_IDF_TARGET_ESP32 +#define ADC_BUS_CLK_ATOMIC() +#else +#define ADC_BUS_CLK_ATOMIC() PERIPH_RCC_ATOMIC() +#endif + #if SOC_ADC_CALIBRATION_V1_SUPPORTED /*--------------------------------------------------------------- ADC Hardware Calibration diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index ea9f8ef8bba..2f50ea6e5a7 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "soc/syscon_struct.h" #include "soc/rtc_cntl_struct.h" #include "soc/clk_tree_defs.h" +#include "soc/dport_reg.h" #ifdef __cplusplus extern "C" { @@ -565,6 +566,25 @@ static inline void adc_oneshot_ll_disable_all_unit(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + (void)enable; + //For compatibility +} + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + //For compatibility +} + /** * Set ADC module controller. * There are five SAR ADC controllers: diff --git a/components/hal/esp32c2/include/hal/adc_ll.h b/components/hal/esp32c2/include/hal/adc_ll.h index 9427b0e4c42..2e234d740c0 100644 --- a/components/hal/esp32c2/include/hal/adc_ll.h +++ b/components/hal/esp32c2/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "soc/rtc_cntl_struct.h" #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" +#include "soc/system_struct.h" #include "hal/misc.h" #include "hal/assert.h" #include "hal/adc_types.h" @@ -286,6 +287,29 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + SYSTEM.perip_clk_en0.apb_saradc_clk_en = enable; +} +// SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + SYSTEM.perip_rst_en0.apb_saradc_rst = 1; + SYSTEM.perip_rst_en0.apb_saradc_rst = 0; +} +// SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + /** * Set ADC module power management. * diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index b780bcebd5b..779312f4fa9 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -15,6 +15,7 @@ #include "soc/rtc_cntl_struct.h" #include "soc/rtc_cntl_reg.h" #include "soc/clk_tree_defs.h" +#include "soc/system_struct.h" #include "hal/misc.h" #include "hal/assert.h" #include "hal/adc_types.h" @@ -560,6 +561,29 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + SYSTEM.perip_clk_en0.reg_apb_saradc_clk_en = enable; +} +// SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + SYSTEM.perip_rst_en0.reg_apb_saradc_rst = 1; + SYSTEM.perip_rst_en0.reg_apb_saradc_rst = 0; +} +// SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + /** * Set ADC module power management. * diff --git a/components/hal/esp32c6/include/hal/adc_ll.h b/components/hal/esp32c6/include/hal/adc_ll.h index d7d689e74a6..1761021322c 100644 --- a/components/hal/esp32c6/include/hal/adc_ll.h +++ b/components/hal/esp32c6/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -554,6 +554,25 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + PCR.saradc_conf.saradc_reg_clk_en = enable; +} + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + PCR.saradc_conf.saradc_reg_rst_en = 1; + PCR.saradc_conf.saradc_reg_rst_en = 0; +} + /** * Set ADC module power management. * diff --git a/components/hal/esp32h2/include/hal/adc_ll.h b/components/hal/esp32h2/include/hal/adc_ll.h index dd9c8113798..315b77de15f 100644 --- a/components/hal/esp32h2/include/hal/adc_ll.h +++ b/components/hal/esp32h2/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -555,6 +555,24 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + PCR.saradc_conf.saradc_reg_clk_en = enable; +} + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + PCR.saradc_conf.saradc_reg_rst_en = 1; + PCR.saradc_conf.saradc_reg_rst_en = 0; +} /** * Set ADC module power management. * diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h index 8d3ed7318e5..ca81a3dad41 100644 --- a/components/hal/esp32p4/include/hal/adc_ll.h +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -199,6 +199,28 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) Common setting ---------------------------------------------------------------*/ +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = enable; +} +// HP_SYS_CLKRST.soc_clk_ctrl2 are shared registers, so this function must be used in an atomic way +#define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_adc = 1; + HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_adc = 0; +} +// HP_SYS_CLKRST.hp_rst_en2 is a shared register, so this function must be used in an atomic way +#define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + /** * Set ADC module controller. * There are five SAR ADC controllers: @@ -255,31 +277,6 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c } } -// /** -// * Set ADC2 module arbiter work mode. -// * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, -// * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. -// * -// * @note Only ADC2 support arbiter. -// * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. -// * -// * @param mode Refer to ``adc_arbiter_mode_t``. -// */ -// __attribute__((always_inline)) -// static inline void adc_ll_set_arbiter_work_mode(adc_arbiter_mode_t mode) -// { -// LP_ADC.meas2_mux.sar2_rtc_force = 0; // Enable arbiter in wakeup mode -// if (mode == ADC_ARB_MODE_FIX) { -// ADC.arb_ctrl.arb_grant_force = 0; -// ADC.arb_ctrl.arb_fix_priority = 1; -// } else if (mode == ADC_ARB_MODE_LOOP) { -// ADC.arb_ctrl.arb_grant_force = 0; -// ADC.arb_ctrl.arb_fix_priority = 0; -// } else { -// ADC.arb_ctrl.arb_grant_force = 1; // Shield arbiter. -// } -// } - /** * Set ADC2 module controller priority in arbiter. * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index ef6712a53f6..f68a85dc381 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,8 @@ #include "soc/clk_tree_defs.h" #include "hal/regi2c_ctrl.h" #include "soc/regi2c_saradc.h" +#include "soc/system_reg.h" +#include "soc/dport_reg.h" #ifdef __cplusplus extern "C" { @@ -918,6 +920,32 @@ static inline void adc_oneshot_ll_disable_all_unit(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + uint32_t reg_val = READ_PERI_REG(DPORT_PERIP_CLK_EN0_REG); + reg_val = reg_val & (~DPORT_APB_SARADC_CLK_EN); + reg_val = reg_val | (enable << DPORT_APB_SARADC_CLK_EN_S); + WRITE_PERI_REG(DPORT_PERIP_CLK_EN0_REG, reg_val); +} +// SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); +} +// SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + /** * Set ADC module power management. * diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index 7c5e3b4121c..ec8180c0486 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -20,6 +20,7 @@ #include "soc/rtc_cntl_reg.h" #include "soc/regi2c_defs.h" #include "soc/clk_tree_defs.h" +#include "soc/system_struct.h" #include "hal/regi2c_ctrl.h" #include "soc/regi2c_saradc.h" @@ -612,6 +613,29 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) /*--------------------------------------------------------------- Common setting ---------------------------------------------------------------*/ + +/** + * @brief Enable the ADC clock + * @param enable true to enable, false to disable + */ +static inline void adc_ll_enable_bus_clock(bool enable) +{ + SYSTEM.perip_clk_en0.apb_saradc_clk_en = enable; +} +// SYSTEM.perip_clk_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset ADC module + */ +static inline void adc_ll_reset_register(void) +{ + SYSTEM.perip_rst_en0.apb_saradc_rst = 1; + SYSTEM.perip_rst_en0.apb_saradc_rst = 0; +} +// SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way +#define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + /** * Set ADC module power management. * From cfc5da167d317a11677b92ebe431e0c7efa8cff3 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 28 Mar 2024 15:20:28 +0800 Subject: [PATCH 235/548] feat(soc): rename lp_adc and ahb_dma reg base on p4 --- components/bootloader_support/src/bootloader_random_esp32p4.c | 2 +- components/soc/esp32p4/include/soc/reg_base.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/src/bootloader_random_esp32p4.c b/components/bootloader_support/src/bootloader_random_esp32p4.c index 4d0552f16a2..df88e8d7b22 100644 --- a/components/bootloader_support/src/bootloader_random_esp32p4.c +++ b/components/bootloader_support/src/bootloader_random_esp32p4.c @@ -9,7 +9,7 @@ #include "soc/pmu_reg.h" #include "soc/regi2c_saradc.h" #include "soc/hp_sys_clkrst_reg.h" -#include "soc/rtcadc_reg.h" +#include "soc/lp_adc_reg.h" #include "esp_private/regi2c_ctrl.h" #include "esp_rom_regi2c.h" diff --git a/components/soc/esp32p4/include/soc/reg_base.h b/components/soc/esp32p4/include/soc/reg_base.h index f6a845a421a..f851cb5c742 100644 --- a/components/soc/esp32p4/include/soc/reg_base.h +++ b/components/soc/esp32p4/include/soc/reg_base.h @@ -43,7 +43,7 @@ #define DR_REG_REGDMA_BASE (DR_REG_HPPERIPH0_BASE + 0x82000) #define DR_REG_SDMMC_BASE (DR_REG_HPPERIPH0_BASE + 0x83000) #define DR_REG_H264_CORE_BASE (DR_REG_HPPERIPH0_BASE + 0x84000) -#define DR_REG_AHB_PDMA_BASE (DR_REG_HPPERIPH0_BASE + 0x85000) +#define DR_REG_AHB_DMA_BASE (DR_REG_HPPERIPH0_BASE + 0x85000) #define DR_REG_JPEG_BASE (DR_REG_HPPERIPH0_BASE + 0x86000) #define DR_REG_PPA_BASE (DR_REG_HPPERIPH0_BASE + 0x87000) #define DR_REG_DMA2D_BASE (DR_REG_HPPERIPH0_BASE + 0x88000) From a326f1512007b8568ee7901e4c42bf8427dd5a60 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Tue, 21 May 2024 19:47:55 +0800 Subject: [PATCH 236/548] feat(adc): support ADC continuous mode on ESP32P4 --- components/driver/deprecated/adc_dma_legacy.c | 2 +- components/driver/deprecated/adc_legacy.c | 2 +- .../driver/test_apps/.build-test-rules.yml | 4 + .../legacy_adc_driver/pytest_legacy_adc.py | 1 - components/esp_adc/CMakeLists.txt | 2 +- components/esp_adc/adc_continuous.c | 28 +- components/esp_adc/adc_continuous_internal.h | 1 + .../esp_adc/test_apps/.build-test-rules.yml | 4 + .../test_apps/adc/main/test_adc_performance.c | 3 - components/esp_pm/linker.lf | 2 + components/hal/adc_hal.c | 13 + components/hal/adc_oneshot_hal.c | 2 +- components/hal/esp32/include/hal/adc_ll.h | 1 - components/hal/esp32c6/include/hal/adc_ll.h | 4 +- components/hal/esp32h2/include/hal/adc_ll.h | 4 +- components/hal/esp32p4/include/hal/adc_ll.h | 490 +++++++++++++++--- .../hal/esp32p4/include/hal/sar_ctrl_ll.h | 3 - components/hal/esp32s2/include/hal/adc_ll.h | 4 +- .../hal/esp32s3/include/hal/rtc_io_ll.h | 3 +- .../include/esp32p4/idf_performance_target.h | 8 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 10 +- components/soc/esp32p4/include/soc/adc_reg.h | 22 +- .../soc/esp32p4/include/soc/adc_struct.h | 114 +--- .../soc/esp32p4/include/soc/clk_tree_defs.h | 2 - components/soc/esp32p4/include/soc/soc_caps.h | 10 +- components/soc/include/soc/rtc_io_periph.h | 8 +- examples/peripherals/.build-test-rules.yml | 8 + .../peripherals/adc/continuous_read/README.md | 4 +- 28 files changed, 546 insertions(+), 213 deletions(-) diff --git a/components/driver/deprecated/adc_dma_legacy.c b/components/driver/deprecated/adc_dma_legacy.c index ca95596cd05..04eb8c9024f 100644 --- a/components/driver/deprecated/adc_dma_legacy.c +++ b/components/driver/deprecated/adc_dma_legacy.c @@ -57,7 +57,7 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi #define INTERNAL_BUF_NUM 5 -#if SOC_AHB_GDMA_VERSION == 1 +#if SOC_AHB_GDMA_SUPPORTED #define ADC_GDMA_HOST 0 #define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF #define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF diff --git a/components/driver/deprecated/adc_legacy.c b/components/driver/deprecated/adc_legacy.c index 75eda25031e..76277ac5e5f 100644 --- a/components/driver/deprecated/adc_legacy.c +++ b/components/driver/deprecated/adc_legacy.c @@ -571,7 +571,7 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * #endif adc_oneshot_ll_set_output_bits(ADC_UNIT_2, bitwidth); -#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4 adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_RTC);// set controller #else adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_ARB);// set controller diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index 4e30f5c6eca..996eacf13c8 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -17,6 +17,10 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_driver: components/driver/test_apps/legacy_adc_driver: disable: - if: SOC_ADC_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners, TODO IDF-9573 depends_components: - efuse - esp_driver_i2s diff --git a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py index 7f23428f5e9..dd7ce7097fc 100644 --- a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py +++ b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py @@ -10,7 +10,6 @@ @pytest.mark.esp32c3 @pytest.mark.esp32c6 @pytest.mark.esp32h2 -@pytest.mark.esp32p4 @pytest.mark.adc @pytest.mark.parametrize( 'config', diff --git a/components/esp_adc/CMakeLists.txt b/components/esp_adc/CMakeLists.txt index 633c9549597..92a4d9304a9 100644 --- a/components/esp_adc/CMakeLists.txt +++ b/components/esp_adc/CMakeLists.txt @@ -53,5 +53,5 @@ endif() idf_component_register(SRCS ${srcs} INCLUDE_DIRS ${includes} - PRIV_REQUIRES driver esp_driver_gpio efuse esp_pm esp_ringbuf + PRIV_REQUIRES driver esp_driver_gpio efuse esp_pm esp_ringbuf esp_mm LDFRAGMENTS linker.lf) diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index fd748b8e24c..7fb2f68dcac 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -37,6 +37,11 @@ #include "adc_continuous_internal.h" #include "esp_private/adc_dma.h" #include "adc_dma_internal.h" +#include "esp_dma_utils.h" +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE +#include "esp_cache.h" +#include "esp_private/esp_cache_private.h" +#endif static const char *ADC_TAG = "adc_continuous"; @@ -66,6 +71,12 @@ static IRAM_ATTR bool adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx) if (status != ADC_HAL_DMA_DESC_VALID) { break; } +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + else { + esp_err_t msync_ret = esp_cache_msync((void *)finished_buffer, finished_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(msync_ret == ESP_OK); + } +#endif ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken); need_yield |= (taskAwoken == pdTRUE); @@ -108,7 +119,10 @@ static IRAM_ATTR bool adc_dma_intr(adc_continuous_ctx_t *adc_digi_ctx) } } } - +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_err_t msync_ret = esp_cache_msync((void *)(adc_digi_ctx->hal.rx_desc), adc_digi_ctx->adc_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(msync_ret == ESP_OK); +#endif return need_yield; } @@ -178,7 +192,11 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi } //malloc internal buffer used by DMA - adc_ctx->rx_dma_buf = heap_caps_calloc(1, hdl_config->conv_frame_size * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + esp_dma_mem_info_t dma_mem_info = { + .extra_heap_caps = (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA), + .dma_alignment_bytes = 4, + }; + esp_dma_capable_calloc(1, hdl_config->conv_frame_size * INTERNAL_BUF_NUM, &dma_mem_info, (void **)&adc_ctx->rx_dma_buf, NULL); if (!adc_ctx->rx_dma_buf) { ret = ESP_ERR_NO_MEM; goto cleanup; @@ -187,7 +205,7 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi //malloc dma descriptor uint32_t dma_desc_num_per_frame = (hdl_config->conv_frame_size + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; uint32_t dma_desc_max_num = dma_desc_num_per_frame * INTERNAL_BUF_NUM; - adc_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * dma_desc_max_num, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + esp_dma_capable_calloc(1, (sizeof(dma_descriptor_t)) * dma_desc_max_num, &dma_mem_info, (void **)&adc_ctx->hal.rx_desc, &adc_ctx->adc_desc_size); if (!adc_ctx->hal.rx_desc) { ret = ESP_ERR_NO_MEM; goto cleanup; @@ -297,6 +315,10 @@ esp_err_t adc_continuous_start(adc_continuous_handle_t handle) adc_dma_reset(handle->adc_dma); adc_hal_digi_reset(); adc_hal_digi_dma_link(&handle->hal, handle->rx_dma_buf); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + esp_err_t ret = esp_cache_msync(handle->hal.rx_desc, handle->adc_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + assert(ret == ESP_OK); +#endif adc_dma_start(handle->adc_dma, handle->hal.rx_desc); adc_hal_digi_connect(true); diff --git a/components/esp_adc/adc_continuous_internal.h b/components/esp_adc/adc_continuous_internal.h index 03ae5d970a2..a2fb28dfac6 100644 --- a/components/esp_adc/adc_continuous_internal.h +++ b/components/esp_adc/adc_continuous_internal.h @@ -99,6 +99,7 @@ struct adc_continuous_ctx_t { #if SOC_ADC_MONITOR_SUPPORTED adc_monitor_t *adc_monitor[SOC_ADC_DIGI_MONITOR_NUM]; // adc monitor context #endif + size_t adc_desc_size; adc_dma_t adc_dma; adc_dma_intr_func_t adc_intr_func; }; diff --git a/components/esp_adc/test_apps/.build-test-rules.yml b/components/esp_adc/test_apps/.build-test-rules.yml index aa97546c7d4..6a284fa6d2c 100644 --- a/components/esp_adc/test_apps/.build-test-rules.yml +++ b/components/esp_adc/test_apps/.build-test-rules.yml @@ -4,6 +4,10 @@ components/esp_adc/test_apps/adc: disable: - if: SOC_ADC_SUPPORTED != 1 - if: CONFIG_NAME == "gdma_iram_safe" and IDF_TARGET in ["esp32", "esp32s2", "esp32c2"] + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: not runners for ESP32P4 ADC # TODO: IDF-9573 depends_components: - esp_adc - esp_driver_gpio diff --git a/components/esp_adc/test_apps/adc/main/test_adc_performance.c b/components/esp_adc/test_apps/adc/main/test_adc_performance.c index f6f15e6dbc3..82ef8dde078 100644 --- a/components/esp_adc/test_apps/adc/main/test_adc_performance.c +++ b/components/esp_adc/test_apps/adc/main/test_adc_performance.c @@ -28,7 +28,6 @@ __attribute__((unused)) static const char *TAG = "TEST_ADC"; #define TEST_STD_ADC1_CHANNEL0 ADC_CHANNEL_2 #endif -#if !CONFIG_IDF_TARGET_ESP32P4 // TODO: IDF-6497 static int s_adc_count_size; static int *s_p_adc_count; static int s_adc_offset = -1; @@ -132,8 +131,6 @@ static float s_print_summary(bool figure) return sqrt(variation_square / count); } -#endif - #if SOC_ADC_DMA_SUPPORTED /*--------------------------------------------------------------- ADC Continuous Average / STD_Deviation Test diff --git a/components/esp_pm/linker.lf b/components/esp_pm/linker.lf index 29cb76425d2..8216d8a8607 100644 --- a/components/esp_pm/linker.lf +++ b/components/esp_pm/linker.lf @@ -36,6 +36,8 @@ entries: sleep_system_peripheral:peripheral_domain_pd_allowed (noflash) sleep_modem:modem_domain_pd_allowed (noflash) sleep_modem:periph_inform_out_light_sleep_overhead (noflash) + if IDF_TARGET_ESP32P4 = n: # TODO: IDF-6496 + sar_periph_ctrl:sar_periph_ctrl_power_disable (noflash) [mapping:esp_system_pm] archive: libesp_system.a diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index bb62c05de93..1688491f2db 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -74,6 +74,10 @@ void adc_hal_digi_init(adc_hal_dma_ctx_t *hal) void adc_hal_digi_deinit() { +#if ADC_LL_POWER_MANAGE_SUPPORTED + adc_ll_set_power_manage(ADC_UNIT_1, ADC_LL_POWER_SW_OFF); + adc_ll_set_power_manage(ADC_UNIT_2, ADC_LL_POWER_SW_OFF); +#endif adc_ll_digi_trigger_disable(); adc_ll_digi_dma_disable(); adc_ll_digi_clear_pattern_table(ADC_UNIT_1); @@ -144,6 +148,9 @@ void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_c for (int i = 0; i < cfg->adc_pattern_len; i++) { adc_ll_digi_set_pattern_table(pattern_both, i, cfg->adc_pattern[i]); } +#if ADC_LL_POWER_MANAGE_SUPPORTED + adc_ll_set_power_manage(0, ADC_LL_POWER_SW_ON); +#endif #elif (SOC_ADC_DIGI_CONTROLLER_NUM >= 2) uint32_t adc1_pattern_idx = 0; @@ -154,9 +161,15 @@ void adc_hal_digi_controller_config(adc_hal_dma_ctx_t *hal, const adc_hal_digi_c for (int i = 0; i < cfg->adc_pattern_len; i++) { if (cfg->adc_pattern[i].unit == ADC_UNIT_1) { +#if ADC_LL_POWER_MANAGE_SUPPORTED + adc_ll_set_power_manage(ADC_UNIT_1, ADC_LL_POWER_SW_ON); +#endif adc_ll_digi_set_pattern_table(ADC_UNIT_1, adc1_pattern_idx, cfg->adc_pattern[i]); adc1_pattern_idx++; } else if (cfg->adc_pattern[i].unit == ADC_UNIT_2) { +#if ADC_LL_POWER_MANAGE_SUPPORTED + adc_ll_set_power_manage(ADC_UNIT_2, ADC_LL_POWER_SW_ON); +#endif adc_ll_digi_set_pattern_table(ADC_UNIT_2, adc2_pattern_idx, cfg->adc_pattern[i]); adc2_pattern_idx++; } else { diff --git a/components/hal/adc_oneshot_hal.c b/components/hal/adc_oneshot_hal.c index 1a5b56da4eb..c74079d464e 100644 --- a/components/hal/adc_oneshot_hal.c +++ b/components/hal/adc_oneshot_hal.c @@ -142,7 +142,7 @@ bool adc_oneshot_hal_convert(adc_oneshot_hal_ctx_t *hal, int *out_raw) } esp_rom_delay_us(read_delay_us); *out_raw = adc_oneshot_ll_get_raw_result(hal->unit); -#if (SOC_ADC_PERIPH_NUM == 2) +#if SOC_ADC_ARBITER_SUPPORTED if (hal->unit == ADC_UNIT_2) { valid = adc_oneshot_ll_raw_check_valid(ADC_UNIT_2, *out_raw); if (!valid) { diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index 2f50ea6e5a7..8f412ea3d6e 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -17,7 +17,6 @@ #include "soc/syscon_struct.h" #include "soc/rtc_cntl_struct.h" #include "soc/clk_tree_defs.h" -#include "soc/dport_reg.h" #ifdef __cplusplus extern "C" { diff --git a/components/hal/esp32c6/include/hal/adc_ll.h b/components/hal/esp32c6/include/hal/adc_ll.h index 1761021322c..db51a869daa 100644 --- a/components/hal/esp32c6/include/hal/adc_ll.h +++ b/components/hal/esp32c6/include/hal/adc_ll.h @@ -59,6 +59,7 @@ extern "C" { #define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 #define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 +#define ADC_LL_POWER_MANAGE_SUPPORTED 1 //ESP32C6 supported to manage power mode /*--------------------------------------------------------------- PWDET (Power Detect) ---------------------------------------------------------------*/ @@ -578,8 +579,9 @@ static inline void adc_ll_reset_register(void) * * @param manage Set ADC power status. */ -static inline void adc_ll_set_power_manage(adc_ll_power_t manage) +static inline void adc_ll_set_power_manage(adc_unit_t adc_n, adc_ll_power_t manage) { + (void) adc_n; /* Bit1 0:Fsm 1: SW mode Bit0 0:SW mode power down 1: SW mode power on */ if (manage == ADC_LL_POWER_SW_ON) { diff --git a/components/hal/esp32h2/include/hal/adc_ll.h b/components/hal/esp32h2/include/hal/adc_ll.h index 315b77de15f..8c02ddd191d 100644 --- a/components/hal/esp32h2/include/hal/adc_ll.h +++ b/components/hal/esp32h2/include/hal/adc_ll.h @@ -60,6 +60,7 @@ extern "C" { #define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 #define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 +#define ADC_LL_POWER_MANAGE_SUPPORTED 1 //ESP32H2 supported to manage power mode /*--------------------------------------------------------------- PWDET (Power Detect) ---------------------------------------------------------------*/ @@ -578,8 +579,9 @@ static inline void adc_ll_reset_register(void) * * @param manage Set ADC power status. */ -static inline void adc_ll_set_power_manage(adc_ll_power_t manage) +static inline void adc_ll_set_power_manage(adc_unit_t adc_n, adc_ll_power_t manage) { + (void) adc_n; /* Bit1 0:Fsm 1: SW mode Bit0 0:SW mode power down 1: SW mode power on */ if (manage == ADC_LL_POWER_SW_ON) { diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h index ca81a3dad41..881cfd0c635 100644 --- a/components/hal/esp32p4/include/hal/adc_ll.h +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -10,24 +10,18 @@ #include "esp_attr.h" #include "soc/adc_periph.h" -// #include "soc/ADC_struct.h" -// #include "soc/ADC_reg.h" -#include "soc/pmu_reg.h" +#include "soc/adc_struct.h" #include "soc/clk_tree_defs.h" -// #include "soc/pcr_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/lpperi_struct.h" +#include "soc/regi2c_saradc.h" #include "hal/misc.h" #include "hal/assert.h" #include "hal/adc_types.h" #include "hal/adc_types_private.h" #include "hal/regi2c_ctrl.h" #include "hal/sar_ctrl_ll.h" - -#include "soc/regi2c_saradc.h" - -#include "soc/hp_sys_clkrst_struct.h" -#include "soc/adc_struct.h" #include "soc/lp_adc_struct.h" -#include "soc/lpperi_struct.h" #ifdef __cplusplus extern "C" { @@ -36,6 +30,10 @@ extern "C" { #define ADC_LL_EVENT_ADC1_ONESHOT_DONE BIT(31) #define ADC_LL_EVENT_ADC2_ONESHOT_DONE BIT(30) +#define LP_ADC_FORCE_XPD_SAR_FSM 0 // Use FSM to control power down +#define LP_ADC_FORCE_XPD_SAR_PD 2 // Force power down +#define LP_ADC_FORCE_XPD_SAR_PU 3 // Force power up + /*--------------------------------------------------------------- Oneshot ---------------------------------------------------------------*/ @@ -46,7 +44,20 @@ extern "C" { /*--------------------------------------------------------------- DMA ---------------------------------------------------------------*/ - +#define ADC_LL_DIGI_DATA_INVERT_DEFAULT(PERIPH_NUM) (0) +#define ADC_LL_FSM_RSTB_WAIT_DEFAULT (8) +#define ADC_LL_FSM_START_WAIT_DEFAULT (5) +#define ADC_LL_FSM_STANDBY_WAIT_DEFAULT (100) +#define ADC_LL_SAMPLE_CYCLE_DEFAULT (2) +#define ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT (1) + +#define ADC_LL_CLKM_DIV_NUM_DEFAULT 15 +#define ADC_LL_CLKM_DIV_B_DEFAULT 1 +#define ADC_LL_CLKM_DIV_A_DEFAULT 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_EN 0 +#define ADC_LL_DEFAULT_CONV_LIMIT_NUM 10 + +#define ADC_LL_POWER_MANAGE_SUPPORTED 1 //ESP32P4 supported to manage power mode /*--------------------------------------------------------------- PWDET (Power Detect) ---------------------------------------------------------------*/ @@ -56,8 +67,7 @@ typedef enum { ADC_LL_CTRL_RTC = 0, ///< For ADC1 and ADC2. Select RTC controller. ADC_LL_CTRL_ULP = 1, ///< For ADC1 and ADC2. Select ULP controller. ADC_LL_CTRL_DIG = 2, ///< For ADC1 and ADC2. Select DIG controller. - ADC_LL_CTRL_PWDET = 3, ///< ??? - ADC_LL_CTRL_ARB = 4, ///< ??? + ADC_LL_CTRL_PWDET = 3, ///< For ADC2. Select PWDET controller. } adc_ll_controller_t; typedef enum { @@ -94,27 +104,39 @@ typedef struct { }; } __attribute__((packed)) adc_ll_digi_pattern_table_t; +/*--------------------------------------------------------------- + Digital controller setting +---------------------------------------------------------------*/ + /** - * @brief Analyze whether the obtained raw data is correct. - * ADC2 use arbiter by default. The arbitration result can be judged by the flag bit in the original data. + * Set adc fsm interval parameter for digital controller. These values are fixed for same platforms. * + * @param rst_wait cycles between DIG ADC controller reset ADC sensor and start ADC sensor. + * @param start_wait Delay time after open xpd. + * @param standby_wait Delay time to close xpd. */ -typedef struct { - union { - struct { - uint16_t data: 13; /*! 0), The data is invalid. */ - }; - uint16_t val; - }; -} adc_ll_rtc_output_data_t; +static inline void adc_ll_digi_set_fsm_time(uint32_t rst_wait, uint32_t start_wait, uint32_t standby_wait) +{ + // Internal FSM reset wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.fsm_wait, rstb_wait, rst_wait); + // Internal FSM start wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.fsm_wait, xpd_wait, start_wait); + // Internal FSM standby wait time + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.fsm_wait, standby_wait, standby_wait); +} -/*--------------------------------------------------------------- - Digital controller setting ----------------------------------------------------------------*/ +/** + * Set adc sample cycle for digital controller. + * + * @note Normally, please use default value. + * @param sample_cycle Cycles between DIG ADC controller start ADC sensor and beginning to receive data from sensor. + * Range: 2 ~ 0xFF. + */ +static inline void adc_ll_set_sample_cycle(uint32_t sample_cycle) +{ + /* Peripheral reg i2c has powered up in rtc_init, write directly */ + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_SAMPLE_CYCLE_ADDR, sample_cycle); +} /** * Set SAR ADC module clock division factor. @@ -128,6 +150,49 @@ static inline void adc_ll_digi_set_clk_div(uint32_t div) HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.ctrl_reg, sar_clk_div, div); } +/** + * Set adc max conversion number for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param meas_num Max conversion number. Range: 0 ~ 255. + */ +static inline void adc_ll_digi_set_convert_limit_num(uint32_t meas_num) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.ctrl2, max_meas_num, meas_num); +} + +/** + * Enable max conversion number detection for digital controller. + * If the number of ADC conversion is equal to the maximum, the conversion is stopped. + * + * @param enable true: enable; false: disable + */ +static inline void adc_ll_digi_convert_limit_enable(bool enable) +{ + ADC.ctrl2.meas_num_limit = enable; +} + +/** + * Set adc conversion mode for digital controller. + * + * @param mode Conversion mode select. + */ +static inline void adc_ll_digi_set_convert_mode(adc_ll_digi_convert_mode_t mode) +{ + if (mode == ADC_LL_DIGI_CONV_ONLY_ADC1) { + ADC.ctrl_reg.work_mode = 0; + ADC.ctrl_reg.sar_sel = 0; + } else if (mode == ADC_LL_DIGI_CONV_ONLY_ADC2) { + ADC.ctrl_reg.work_mode = 0; + ADC.ctrl_reg.sar_sel = 1; + } else if (mode == ADC_LL_DIGI_CONV_BOTH_UNIT) { + ADC.ctrl_reg.work_mode = 1; + } else if (mode == ADC_LL_DIGI_CONV_ALTER_UNIT) { + ADC.ctrl_reg.work_mode = 2; + } + ADC.ctrl_reg.data_sar_sel = 1; +} + /** * Set ADC digital controller clock division factor. The clock divided from `APLL` or `APB` clock. * Expression: controller_clk = (APLL or APB) / (div_num + div_a / div_b + 1). @@ -139,8 +204,8 @@ static inline void adc_ll_digi_set_clk_div(uint32_t div) static inline void adc_ll_digi_controller_clk_div(uint32_t div_num, uint32_t div_b, uint32_t div_a) { HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl23, reg_adc_clk_div_num, div_num); - HP_SYS_CLKRST.root_clk_ctrl0.reg_cpu_clk_div_numerator = div_b; - HP_SYS_CLKRST.root_clk_ctrl0.reg_cpu_clk_div_denominator = div_a; + HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_div_numerator = div_a; + HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_div_denominator = div_b; } /** @@ -167,6 +232,235 @@ static inline void adc_ll_digi_clk_sel(adc_continuous_clk_src_t clk_src) ADC.ctrl_reg.sar_clk_gated = 1; } +/** + * Disable clock for ADC digital controller. + */ +static inline void adc_ll_digi_controller_clk_disable(void) +{ + ADC.ctrl_reg.sar_clk_gated = 0; +} + +/** + * Reset adc digital controller filter. + * + * @param idx Filter index + * @param adc_n ADC unit. + */ +static inline void adc_ll_digi_filter_reset(adc_digi_iir_filter_t idx, adc_unit_t adc_n) +{ + (void)adc_n; + ADC.filter_ctrl0.filter_reset = 1; + ADC.filter_ctrl0.filter_reset = 0; +} + +/** + * Set adc digital controller filter coeff. + * + * @param idx filter index + * @param adc_n adc unit + * @param channel adc channel + * @param coeff filter coeff + */ +static inline void adc_ll_digi_filter_set_factor(adc_digi_iir_filter_t idx, adc_unit_t adc_n, adc_channel_t channel, adc_digi_iir_filter_coeff_t coeff) +{ + uint32_t factor_reg_val = 0; + switch (coeff) { + case ADC_DIGI_IIR_FILTER_COEFF_2: + factor_reg_val = 1; + break; + case ADC_DIGI_IIR_FILTER_COEFF_4: + factor_reg_val = 2; + break; + case ADC_DIGI_IIR_FILTER_COEFF_8: + factor_reg_val = 3; + break; + case ADC_DIGI_IIR_FILTER_COEFF_16: + factor_reg_val = 4; + break; + case ADC_DIGI_IIR_FILTER_COEFF_64: + factor_reg_val = 6; + break; + default: + HAL_ASSERT(false); + } + + if (idx == ADC_DIGI_IIR_FILTER_0) { + ADC.filter_ctrl0.filter_channel0 = ((adc_n + 1) << 3) | (channel & 0x7); + ADC.filter_ctrl1.filter_factor0 = factor_reg_val; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + ADC.filter_ctrl0.filter_channel1 = ((adc_n + 1) << 3) | (channel & 0x7); + ADC.filter_ctrl1.filter_factor1 = factor_reg_val; + } +} + +/** + * Enable adc digital controller filter. + * Filtering the ADC data to obtain smooth data at higher sampling rates. + * + * @param idx filter index + * @param adc_n ADC unit + * @param enable Enable / Disable + */ +static inline void adc_ll_digi_filter_enable(adc_digi_iir_filter_t idx, adc_unit_t adc_n, bool enable) +{ + (void)adc_n; + if (!enable) { + if (idx == ADC_DIGI_IIR_FILTER_0) { + ADC.filter_ctrl0.filter_channel0 = 0xF; + ADC.filter_ctrl1.filter_factor0 = 0; + } else if (idx == ADC_DIGI_IIR_FILTER_1) { + ADC.filter_ctrl0.filter_channel1 = 0xF; + ADC.filter_ctrl1.filter_factor1 = 0; + } + } + //nothing to do to enable, after adc_ll_digi_filter_set_factor, it's enabled. +} + +/** + * Set pattern table length for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. + * + * @param adc_n ADC unit. + * @param patt_len Items range: 1 ~ 16. + */ +static inline void adc_ll_digi_set_pattern_table_len(adc_unit_t adc_n, uint32_t patt_len) +{ + if (adc_n == ADC_UNIT_1) { + ADC.ctrl_reg.sar1_patt_len = patt_len - 1; + } else { // adc_n == ADC_UNIT_2 + ADC.ctrl_reg.sar2_patt_len = patt_len - 1; + } +} + +/** + * Set pattern table for digital controller. + * The pattern table that defines the conversion rules for each SAR ADC. Each table has 12 items, in which channel selection, + * resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the + * pattern table one by one. For each controller the scan sequence has at most 12 different rules before repeating itself. + * + * @param adc_n ADC unit. + * @param pattern_index Items index. Range: 0 ~ 11. + * @param pattern Stored conversion rules. + */ +static inline void adc_ll_digi_set_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_config_t table) +{ + uint32_t tab; + uint8_t index = pattern_index / 4; + uint8_t offset = (pattern_index % 4) * 6; + adc_ll_digi_pattern_table_t pattern = {0}; + + pattern.val = (table.atten & 0x3) | ((table.channel & 0xF) << 2); + if (table.unit == ADC_UNIT_1){ + tab = ADC.sar1_patt_tab[index].sar1_patt_tab; //Read old register value + tab &= (~(0xFC0000 >> offset)); //Clear old data + tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; //Fill in the new data + ADC.sar1_patt_tab[index].sar1_patt_tab = tab; //Write back + } else { + tab = ADC.sar2_patt_tab[index].sar2_patt_tab; //Read old register value + tab &= (~(0xFC0000 >> offset)); //clear old data + tab |= ((uint32_t)(pattern.val & 0x3F) << 18) >> offset; //Fill in the new data + ADC.sar2_patt_tab[index].sar2_patt_tab = tab; //Write back + } +} + +/** + * Reset the pattern table pointer, then take the measurement rule from table header in next measurement. + * + * @param adc_n ADC unit. + */ +static inline void adc_ll_digi_clear_pattern_table(adc_unit_t adc_n) +{ + if (adc_n == ADC_UNIT_1) { + ADC.ctrl_reg.sar1_patt_p_clear = 1; + ADC.ctrl_reg.sar1_patt_p_clear = 0; + } else { // adc_n == ADC_UNIT_2 + ADC.ctrl_reg.sar2_patt_p_clear = 1; + ADC.ctrl_reg.sar2_patt_p_clear = 0; + } +} + +/** + * ADC Digital controller output data invert or not. + * + * @param adc_n ADC unit. + * @param inv_en data invert or not. + */ +static inline void adc_ll_digi_output_invert(adc_unit_t adc_n, bool inv_en) +{ + if (adc_n == ADC_UNIT_1) { + ADC.ctrl2.sar1_inv = inv_en; // Enable / Disable ADC data invert + } else { // adc_n == ADC_UNIT_2 + ADC.ctrl2.sar2_inv = inv_en; // Enable / Disable ADC data invert + } +} + +/** + * Set the interval clock cycle for the digital controller to trigger the measurement. + * Expression: `trigger_meas_freq` = `controller_clk` / 2 / interval. + * + * @note The trigger interval should not be smaller than the sampling time of the SAR ADC. + * @param cycle The clock cycle (trigger interval) of the measurement. Range: 30 ~ 4095. + */ +static inline void adc_ll_digi_set_trigger_interval(uint32_t cycle) +{ + ADC.ctrl2.timer_target = cycle; +} + +/** + * Set DMA eof num of adc digital controller. + * If the number of measurements reaches `dma_eof_num`, then `dma_in_suc_eof` signal is generated. + * + * @param num eof num of DMA. + */ +static inline void adc_ll_digi_dma_set_eof_num(uint32_t num) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(ADC.dma_conf, apb_adc_eof_num, num); +} + +/** + * Enable output data to DMA from adc digital controller. + */ +static inline void adc_ll_digi_dma_enable(void) +{ + ADC.dma_conf.apb_adc_trans = 1; +} + +/** + * Disable output data to DMA from adc digital controller. + */ +static inline void adc_ll_digi_dma_disable(void) +{ + ADC.dma_conf.apb_adc_trans = 0; +} + +/** + * Reset adc digital controller. + */ +static inline void adc_ll_digi_reset(void) +{ + ADC.dma_conf.apb_adc_reset_fsm = 1; + ADC.dma_conf.apb_adc_reset_fsm = 0; +} + +/** + * Enable digital controller timer to trigger the measurement. + */ +static inline void adc_ll_digi_trigger_enable(void) +{ + ADC.ctrl2.timer_sel = 1; + ADC.ctrl2.timer_en = 1; +} + +/** + * Disable digital controller timer to trigger the measurement. + */ +static inline void adc_ll_digi_trigger_disable(void) +{ + ADC.ctrl2.timer_en = 0; +} + /*--------------------------------------------------------------- PWDET(Power detect) controller setting ---------------------------------------------------------------*/ @@ -206,6 +500,7 @@ static inline uint32_t adc_ll_pwdet_get_cct(void) static inline void adc_ll_enable_bus_clock(bool enable) { HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = enable; + HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_en = enable; } // HP_SYS_CLKRST.soc_clk_ctrl2 are shared registers, so this function must be used in an atomic way #define adc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_enable_bus_clock(__VA_ARGS__) @@ -221,6 +516,84 @@ static inline void adc_ll_reset_register(void) // HP_SYS_CLKRST.hp_rst_en2 is a shared register, so this function must be used in an atomic way #define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) + + +/** + * Set ADC digital controller power management. + * + * @param adc_n ADC unit. + * @param manage Set ADC power status. + */ +static inline void adc_ll_digi_set_power_manage(adc_unit_t adc_n, adc_ll_power_t manage) +{ + if (adc_n == ADC_UNIT_1) { + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_LL_POWER_SW_ON) { + ADC.ctrl_reg.sar_clk_gated = 1; + ADC.ctrl_reg.xpd_sar1_force = LP_ADC_FORCE_XPD_SAR_PU; + } else if (manage == ADC_LL_POWER_BY_FSM) { + ADC.ctrl_reg.sar_clk_gated = 1; + ADC.ctrl_reg.xpd_sar1_force = LP_ADC_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_LL_POWER_SW_OFF) { + ADC.ctrl_reg.sar_clk_gated = 0; + ADC.ctrl_reg.xpd_sar1_force = LP_ADC_FORCE_XPD_SAR_PD; + } + } else { + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_LL_POWER_SW_ON) { + ADC.ctrl_reg.sar_clk_gated = 1; + ADC.ctrl_reg.xpd_sar2_force = LP_ADC_FORCE_XPD_SAR_PU; + } else if (manage == ADC_LL_POWER_BY_FSM) { + ADC.ctrl_reg.sar_clk_gated = 1; + ADC.ctrl_reg.xpd_sar2_force = LP_ADC_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_LL_POWER_SW_OFF) { + ADC.ctrl_reg.sar_clk_gated = 0; + ADC.ctrl_reg.xpd_sar2_force = LP_ADC_FORCE_XPD_SAR_PD; + } + } +} + +/** + * Set ADC module power management. + * + * @param adc_n ADC unit. + * @param manage Set ADC power status. + */ +static inline void adc_ll_set_power_manage(adc_unit_t adc_n, adc_ll_power_t manage) +{ + adc_ll_digi_set_power_manage(adc_n, manage); + if (adc_n == ADC_UNIT_1) { + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_LL_POWER_SW_ON) { + LPPERI.clk_en.ck_en_lp_adc = 1; + LP_ADC.force_wpd_sar.force_xpd_sar1 = LP_ADC_FORCE_XPD_SAR_PU; + } else if (manage == ADC_LL_POWER_BY_FSM) { + LPPERI.clk_en.ck_en_lp_adc = 1; + LP_ADC.force_wpd_sar.force_xpd_sar1 = LP_ADC_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_LL_POWER_SW_OFF) { + LP_ADC.force_wpd_sar.force_xpd_sar1 = LP_ADC_FORCE_XPD_SAR_PD; + LPPERI.clk_en.ck_en_lp_adc = 0; + } + } else { + /* Bit1 0:Fsm 1: SW mode + Bit0 0:SW mode power down 1: SW mode power on */ + if (manage == ADC_LL_POWER_SW_ON) { + LPPERI.clk_en.ck_en_lp_adc = 1; + LP_ADC.force_wpd_sar.force_xpd_sar2 = LP_ADC_FORCE_XPD_SAR_PU; + } else if (manage == ADC_LL_POWER_BY_FSM) { + LPPERI.clk_en.ck_en_lp_adc = 1; + LP_ADC.force_wpd_sar.force_xpd_sar2 = LP_ADC_FORCE_XPD_SAR_FSM; + } else if (manage == ADC_LL_POWER_SW_OFF) { + LP_ADC.force_wpd_sar.force_xpd_sar2 = LP_ADC_FORCE_XPD_SAR_PD; + LPPERI.clk_en.ck_en_lp_adc = 0; + } + } +} + + /** * Set ADC module controller. * There are five SAR ADC controllers: @@ -277,39 +650,6 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c } } -/** - * Set ADC2 module controller priority in arbiter. - * The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority, - * the low priority controller will read the invalid ADC data, and the validity of the data can be judged by the flag bit in the data. - * - * @note Only ADC2 support arbiter. - * @note The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode. - * @note Default priority: Wi-Fi(2) > RTC(1) > Digital(0); - * - * @param pri_rtc RTC controller priority. Range: 0 ~ 2. - * @param pri_dig Digital controller priority. Range: 0 ~ 2. - * @param pri_pwdet Wi-Fi controller priority. Range: 0 ~ 2. - */ -__attribute__((always_inline)) -static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, uint8_t pri_pwdet) -{ - if (pri_rtc != pri_dig && pri_rtc != pri_pwdet && pri_dig != pri_pwdet) { - ADC.arb_ctrl.arb_rtc_priority = pri_rtc; - ADC.arb_ctrl.arb_apb_priority = pri_dig; - ADC.arb_ctrl.arb_wifi_priority = pri_pwdet; - } - /* Should select highest priority controller. */ - if (pri_rtc > pri_dig) { - ADC.arb_ctrl.arb_apb_force = 0; - ADC.arb_ctrl.arb_rtc_force = 1; - ADC.arb_ctrl.arb_wifi_force = 0; - } else { - ADC.arb_ctrl.arb_apb_force = 1; - ADC.arb_ctrl.arb_rtc_force = 0; - ADC.arb_ctrl.arb_wifi_force = 0; - } -} - /*--------------------------------------------------------------- Oneshot Read ---------------------------------------------------------------*/ @@ -436,26 +776,16 @@ static inline uint32_t adc_oneshot_ll_get_raw_result(adc_unit_t adc_n) /** * Analyze whether the obtained raw data is correct. - * ADC2 can use arbiter. The arbitration result can be judged by the flag bit in the original data. * * @param adc_n ADC unit. * @param raw ADC raw data input (convert value). * @return * - true: raw data is valid - * - false: raw data is invalid */ static inline bool adc_oneshot_ll_raw_check_valid(adc_unit_t adc_n, uint32_t raw) { - if (adc_n == ADC_UNIT_1) { - return true; - } - adc_ll_rtc_output_data_t *temp = (adc_ll_rtc_output_data_t *)&raw; - if (temp->flag == 0) { - return true; - } else { - //Could be ADC_LL_RTC_CTRL_UNSELECTED, ADC_LL_RTC_CTRL_BREAK or ADC_LL_RTC_DATA_FAIL - return false; - } + /* No arbiter, don't need check data */ + return true; } /** @@ -481,8 +811,7 @@ static inline void adc_oneshot_ll_output_invert(adc_unit_t adc_n, bool inv_en) static inline void adc_oneshot_ll_enable(adc_unit_t adc_n) { (void)adc_n; - HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = 1; - HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_en = 1; + //For compatibility } /** @@ -490,8 +819,7 @@ static inline void adc_oneshot_ll_enable(adc_unit_t adc_n) */ static inline void adc_oneshot_ll_disable_all_unit(void) { - HP_SYS_CLKRST.soc_clk_ctrl2.reg_adc_apb_clk_en = 0; - HP_SYS_CLKRST.peri_clk_ctrl23.reg_adc_clk_en = 0; + //For compatibility } /*--------------------------------------------------------------- diff --git a/components/hal/esp32p4/include/hal/sar_ctrl_ll.h b/components/hal/esp32p4/include/hal/sar_ctrl_ll.h index 3a8eff42935..8c0b02bc6d2 100644 --- a/components/hal/esp32p4/include/hal/sar_ctrl_ll.h +++ b/components/hal/esp32p4/include/hal/sar_ctrl_ll.h @@ -50,15 +50,12 @@ __attribute__((always_inline)) static inline void sar_ctrl_ll_set_power_mode(sar_ctrl_ll_power_t mode) { if (mode == SAR_CTRL_LL_POWER_FSM) { - // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 1; LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x0; LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x0; } else if (mode == SAR_CTRL_LL_POWER_ON) { - // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 1; LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x3; LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x3; } else { - // LP_ADC.sar_peri_clk_gate_conf.saradc_clk_en = 0; LP_ADC.force_wpd_sar.force_xpd_sar1 = 0x2; LP_ADC.force_wpd_sar.force_xpd_sar2 = 0x2; } diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index f68a85dc381..d0b558cc619 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -940,8 +940,8 @@ static inline void adc_ll_enable_bus_clock(bool enable) */ static inline void adc_ll_reset_register(void) { - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); + SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); + CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_APB_SARADC_RST); } // SYSTEM.perip_rst_en0 is a shared register, so this function must be used in an atomic way #define adc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; adc_ll_reset_register(__VA_ARGS__) diff --git a/components/hal/esp32s3/include/hal/rtc_io_ll.h b/components/hal/esp32s3/include/hal/rtc_io_ll.h index 1a988c000cb..86d483b217a 100644 --- a/components/hal/esp32s3/include/hal/rtc_io_ll.h +++ b/components/hal/esp32s3/include/hal/rtc_io_ll.h @@ -19,6 +19,7 @@ #include "soc/io_mux_reg.h" #include "soc/usb_serial_jtag_reg.h" #include "soc/usb_serial_jtag_struct.h" +#include "soc/sens_struct.h" #ifdef __cplusplus extern "C" { @@ -27,7 +28,7 @@ extern "C" { #define RTCIO_LL_PIN_FUNC 0 typedef enum { - RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controled by RTC module. */ + RTCIO_LL_FUNC_RTC = 0x0, /*!< The pin controlled by RTC module. */ RTCIO_LL_FUNC_DIGITAL = 0x1, /*!< The pin controlled by DIGITAL module. */ } rtcio_ll_func_t; diff --git a/components/idf_test/include/esp32p4/idf_performance_target.h b/components/idf_test/include/esp32p4/idf_performance_target.h index a312d550f97..90ad9b1e3a5 100644 --- a/components/idf_test/include/esp32p4/idf_performance_target.h +++ b/components/idf_test/include/esp32p4/idf_performance_target.h @@ -10,3 +10,11 @@ /* Solicited yields (portYIELD() or taskYIELD()) take longer on esp32p4. TODO: IDF-2809 */ #define IDF_PERFORMANCE_MAX_SCHEDULING_TIME 3200 + +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER 10 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_2 10 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_4 10 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 10 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 10 +#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 10 +#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 10 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 1c91223f790..ebee09a5d92 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -319,6 +319,10 @@ config SOC_ADC_DIG_CTRL_SUPPORTED bool default y +config SOC_ADC_DMA_SUPPORTED + bool + default y + config SOC_ADC_PERIPH_NUM int default 2 @@ -337,7 +341,7 @@ config SOC_ADC_DIGI_CONTROLLER_NUM config SOC_ADC_PATT_LEN_MAX int - default 8 + default 16 config SOC_ADC_DIGI_MAX_BITWIDTH int @@ -383,6 +387,10 @@ config SOC_ADC_CALIBRATION_V1_SUPPORTED bool default n +config SOC_ADC_SHARED_POWER + bool + default y + config SOC_APB_BACKUP_DMA bool default n diff --git a/components/soc/esp32p4/include/soc/adc_reg.h b/components/soc/esp32p4/include/soc/adc_reg.h index 1247201710f..c495c57bf64 100644 --- a/components/soc/esp32p4/include/soc/adc_reg.h +++ b/components/soc/esp32p4/include/soc/adc_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -195,6 +195,26 @@ extern "C" { #define ADC_FILTER_FACTOR0_V 0x00000007U #define ADC_FILTER_FACTOR0_S 29 +#define ADC_FSM_WAIT_REG (DR_REG_ADC_BASE + 0xC) +/* ADC_STANDBY_WAIT : R/W ;bitpos:[23:16] ;default: 8'd255 ; */ +/*description: need_des.*/ +#define ADC_STANDBY_WAIT 0x000000FF +#define ADC_STANDBY_WAIT_M ((ADC_STANDBY_WAIT_V)<<(ADC_STANDBY_WAIT_S)) +#define ADC_STANDBY_WAIT_V 0xFF +#define ADC_STANDBY_WAIT_S 16 +/* ADC_RSTB_WAIT : R/W ;bitpos:[15:8] ;default: 8'd8 ; */ +/*description: need_des.*/ +#define ADC_RSTB_WAIT 0x000000FF +#define ADC_RSTB_WAIT_M ((ADC_RSTB_WAIT_V)<<(ADC_RSTB_WAIT_S)) +#define ADC_RSTB_WAIT_V 0xFF +#define ADC_RSTB_WAIT_S 8 +/* ADC_XPD_WAIT : R/W ;bitpos:[7:0] ;default: 8'd8 ; */ +/*description: need_des.*/ +#define ADC_XPD_WAIT 0x000000FF +#define ADC_XPD_WAIT_M ((ADC_XPD_WAIT_V)<<(ADC_XPD_WAIT_S)) +#define ADC_XPD_WAIT_V 0xFF +#define ADC_XPD_WAIT_S 0 + /** ADC_SAR1_PATT_TAB1_REG register * Register */ diff --git a/components/soc/esp32p4/include/soc/adc_struct.h b/components/soc/esp32p4/include/soc/adc_struct.h index efaade0acb6..c534937c36c 100644 --- a/components/soc/esp32p4/include/soc/adc_struct.h +++ b/components/soc/esp32p4/include/soc/adc_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -137,117 +137,46 @@ typedef union { uint32_t val; } adc_filter_ctrl1_reg_t; -/** Type of sar1_patt_tab1 register - * Register - */ -typedef union { - struct { - /** sar1_patt_tab1 : R/W; bitpos: [23:0]; default: 0; - * item 0 ~ 3 for pattern table 1 (each item one byte) - */ - uint32_t sar1_patt_tab1:24; - uint32_t reserved_24:8; - }; - uint32_t val; -} adc_sar1_patt_tab1_reg_t; - -/** Type of sar1_patt_tab2 register - * Register - */ -typedef union { - struct { - /** sar1_patt_tab2 : R/W; bitpos: [23:0]; default: 0; - * Item 4 ~ 7 for pattern table 1 (each item one byte) - */ - uint32_t sar1_patt_tab2:24; - uint32_t reserved_24:8; - }; - uint32_t val; -} adc_sar1_patt_tab2_reg_t; - -/** Type of sar1_patt_tab3 register +/** Type of filter_ctrl1 register * Register */ typedef union { struct { - /** sar1_patt_tab3 : R/W; bitpos: [23:0]; default: 0; - * Item 8 ~ 11 for pattern table 1 (each item one byte) - */ - uint32_t sar1_patt_tab3:24; - uint32_t reserved_24:8; + uint32_t xpd_wait:8; + uint32_t rstb_wait:8; + uint32_t standby_wait:8; + uint32_t reserved24:8; }; uint32_t val; -} adc_sar1_patt_tab3_reg_t; +} adc_fsm_wait_reg_t; -/** Type of sar1_patt_tab4 register +/** Type of sar1_patt_tab register * Register */ typedef union { struct { - /** sar1_patt_tab4 : R/W; bitpos: [23:0]; default: 0; - * Item 12 ~ 15 for pattern table 1 (each item one byte) + /** sar1_patt_tab : R/W; bitpos: [23:0]; default: 0; + * item 0 ~ 3 for pattern table 1 (each item one byte) */ - uint32_t sar1_patt_tab4:24; + uint32_t sar1_patt_tab:24; uint32_t reserved_24:8; }; uint32_t val; -} adc_sar1_patt_tab4_reg_t; +} adc_sar1_patt_tab_reg_t; /** Type of sar2_patt_tab1 register * Register */ typedef union { struct { - /** sar2_patt_tab1 : R/W; bitpos: [23:0]; default: 0; + /** sar2_patt_tab : R/W; bitpos: [23:0]; default: 0; * item 0 ~ 3 for pattern table 2 (each item one byte) */ - uint32_t sar2_patt_tab1:24; - uint32_t reserved_24:8; - }; - uint32_t val; -} adc_sar2_patt_tab1_reg_t; - -/** Type of sar2_patt_tab2 register - * Register - */ -typedef union { - struct { - /** sar2_patt_tab2 : R/W; bitpos: [23:0]; default: 0; - * Item 4 ~ 7 for pattern table 2 (each item one byte) - */ - uint32_t sar2_patt_tab2:24; - uint32_t reserved_24:8; - }; - uint32_t val; -} adc_sar2_patt_tab2_reg_t; - -/** Type of sar2_patt_tab3 register - * Register - */ -typedef union { - struct { - /** sar2_patt_tab3 : R/W; bitpos: [23:0]; default: 0; - * Item 8 ~ 11 for pattern table 2 (each item one byte) - */ - uint32_t sar2_patt_tab3:24; - uint32_t reserved_24:8; - }; - uint32_t val; -} adc_sar2_patt_tab3_reg_t; - -/** Type of sar2_patt_tab4 register - * Register - */ -typedef union { - struct { - /** sar2_patt_tab4 : R/W; bitpos: [23:0]; default: 0; - * Item 12 ~ 15 for pattern table 2 (each item one byte) - */ - uint32_t sar2_patt_tab4:24; + uint32_t sar2_patt_tab:24; uint32_t reserved_24:8; }; uint32_t val; -} adc_sar2_patt_tab4_reg_t; +} adc_sar2_patt_tab_reg_t; /** Type of arb_ctrl register * Register @@ -655,15 +584,10 @@ typedef struct { volatile adc_ctrl_reg_reg_t ctrl_reg; volatile adc_ctrl2_reg_t ctrl2; volatile adc_filter_ctrl1_reg_t filter_ctrl1; - uint32_t reserved_00c[3]; - volatile adc_sar1_patt_tab1_reg_t sar1_patt_tab1; - volatile adc_sar1_patt_tab2_reg_t sar1_patt_tab2; - volatile adc_sar1_patt_tab3_reg_t sar1_patt_tab3; - volatile adc_sar1_patt_tab4_reg_t sar1_patt_tab4; - volatile adc_sar2_patt_tab1_reg_t sar2_patt_tab1; - volatile adc_sar2_patt_tab2_reg_t sar2_patt_tab2; - volatile adc_sar2_patt_tab3_reg_t sar2_patt_tab3; - volatile adc_sar2_patt_tab4_reg_t sar2_patt_tab4; + volatile adc_fsm_wait_reg_t fsm_wait; + uint32_t reserved_00c[2]; + volatile adc_sar1_patt_tab_reg_t sar1_patt_tab[4]; + volatile adc_sar2_patt_tab_reg_t sar2_patt_tab[4]; volatile adc_arb_ctrl_reg_t arb_ctrl; volatile adc_filter_ctrl0_reg_t filter_ctrl0; volatile adc_sar1_data_status_reg_t sar1_data_status; diff --git a/components/soc/esp32p4/include/soc/clk_tree_defs.h b/components/soc/esp32p4/include/soc/clk_tree_defs.h index d500fe63fdb..59da431669b 100644 --- a/components/soc/esp32p4/include/soc/clk_tree_defs.h +++ b/components/soc/esp32p4/include/soc/clk_tree_defs.h @@ -601,7 +601,6 @@ typedef enum { ADC_DIGI_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */ ADC_DIGI_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ ADC_DIGI_CLK_SRC_PLL_F80M = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the source clock */ - ADC_DIGI_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F80M, /*!< Select PLL_F80M as the default clock choice */ } soc_periph_adc_digi_clk_src_t; @@ -615,7 +614,6 @@ typedef enum { */ typedef enum { ADC_RTC_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */ - ADC_RTC_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the default clock choice */ } soc_periph_adc_rtc_clk_src_t; diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index b57a0c39cc0..a9e6c7b67af 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -110,19 +110,18 @@ /*!< SAR ADC Module*/ #define SOC_ADC_RTC_CTRL_SUPPORTED 1 #define SOC_ADC_DIG_CTRL_SUPPORTED 1 -// #define SOC_ADC_ARBITER_SUPPORTED 1 // #define SOC_ADC_DIG_IIR_FILTER_SUPPORTED 1 // #define SOC_ADC_MONITOR_SUPPORTED 1 #define SOC_ADC_DIG_SUPPORTED_UNIT(UNIT) 1 //Digital controller supported ADC unit -// #define SOC_ADC_DMA_SUPPORTED 1 +#define SOC_ADC_DMA_SUPPORTED 1 #define SOC_ADC_PERIPH_NUM (2) -#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (14) +#define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) ((PERIPH_NUM==0)? 6: 8) #define SOC_ADC_MAX_CHANNEL_NUM (8) #define SOC_ADC_ATTEN_NUM (4) /*!< Digital */ #define SOC_ADC_DIGI_CONTROLLER_NUM (2) -#define SOC_ADC_PATT_LEN_MAX (8) /*!< Two pattern tables, each contains 4 items. Each item takes 1 byte */ +#define SOC_ADC_PATT_LEN_MAX (16) /*!< Four pattern tables, each contains 4 items. Each item takes 1 byte */ #define SOC_ADC_DIGI_MAX_BITWIDTH (12) #define SOC_ADC_DIGI_MIN_BITWIDTH (12) #define SOC_ADC_DIGI_IIR_FILTER_NUM (2) @@ -140,6 +139,9 @@ /*!< Calibration */ #define SOC_ADC_CALIBRATION_V1_SUPPORTED (0) /*!< support HW offset calibration version 1*/ +/*!< ADC power control is shared by PWDET, TempSensor */ +#define SOC_ADC_SHARED_POWER 1 + // ESP32P4-TODO: Copy from esp32c6, need check /*-------------------------- APB BACKUP DMA CAPS -------------------------------*/ #define SOC_APB_BACKUP_DMA (0) diff --git a/components/soc/include/soc/rtc_io_periph.h b/components/soc/include/soc/rtc_io_periph.h index 935bd07f716..b8c23f0e06d 100644 --- a/components/soc/include/soc/rtc_io_periph.h +++ b/components/soc/include/soc/rtc_io_periph.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,16 +9,10 @@ #include //include soc related (generated) definitions #include "soc/soc_caps.h" -#include "sdkconfig.h" #if SOC_RTCIO_PIN_COUNT > 0 #include "soc/rtc_io_channel.h" #endif - -#if SOC_ADC_RTC_CTRL_SUPPORTED && !CONFIG_IDF_TARGET_ESP32P4 -#include "soc/sens_struct.h" -#endif - #include "soc/io_mux_reg.h" #ifdef __cplusplus diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 59a9dadd8e9..7397280ae0a 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -10,11 +10,19 @@ examples/peripherals/adc/continuous_read: disable: - if: SOC_ADC_DMA_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runners, TODO IDF-9573 <<: *adc_dependencies examples/peripherals/adc/oneshot_read: disable: - if: SOC_ADC_SUPPORTED != 1 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: lack of runner, TODO IDF-9573 <<: *adc_dependencies examples/peripherals/analog_comparator: diff --git a/examples/peripherals/adc/continuous_read/README.md b/examples/peripherals/adc/continuous_read/README.md index 94ecfd9889b..e02022f3c10 100644 --- a/examples/peripherals/adc/continuous_read/README.md +++ b/examples/peripherals/adc/continuous_read/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | # ADC DMA Example From 679df9ec6fc093fafda16463028cc52528fcfc78 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Tue, 14 May 2024 11:13:54 +0800 Subject: [PATCH 237/548] feat(bt/nimble): support hci log for nimble --- components/bt/common/hci_log/bt_hci_log.c | 20 ++++++------- .../bt/host/bluedroid/api/esp_bluedroid_hci.c | 2 +- components/bt/host/bluedroid/hci/hci_hal_h4.c | 30 ++++++++++++++----- .../host/nimble/esp-hci/src/esp_nimble_hci.c | 26 ---------------- 4 files changed, 33 insertions(+), 45 deletions(-) diff --git a/components/bt/common/hci_log/bt_hci_log.c b/components/bt/common/hci_log/bt_hci_log.c index 1cc95a46ce2..e35bf1a7a68 100644 --- a/components/bt/common/hci_log/bt_hci_log.c +++ b/components/bt/common/hci_log/bt_hci_log.c @@ -31,8 +31,8 @@ static const char s_hex_to_char_mapping[16] = { '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; -bt_hci_log_t g_bt_hci_log_data_ctl = {0}; -bt_hci_log_t g_bt_hci_log_adv_ctl = {0}; +static bt_hci_log_t g_bt_hci_log_data_ctl = {0}; +static bt_hci_log_t g_bt_hci_log_adv_ctl = {0}; esp_err_t bt_hci_log_init(void) { @@ -98,35 +98,35 @@ static char IRAM_ATTR *bt_data_type_to_str(uint8_t data_type) { case HCI_LOG_DATA_TYPE_COMMAND: // hci cmd data - tag = "CMD"; + tag = "C"; break; case HCI_LOG_DATA_TYPE_H2C_ACL: // host to controller hci acl data - tag = "HAL"; + tag = "H"; break; case HCI_LOG_DATA_TYPE_SCO: // hci sco data - tag = "SCO"; + tag = "S"; break; case HCI_LOG_DATA_TYPE_EVENT: // hci event - tag = "EVT"; + tag = "E"; break; case HCI_LOG_DATA_TYPE_ADV: // controller adv report data - tag = "ADV"; + tag = NULL; break; case HCI_LOG_DATA_TYPE_C2H_ACL: // controller to host hci acl data - tag = "CAL"; + tag = "D"; break; case HCI_LOG_DATA_TYPE_SELF_DEFINE: // self-defining data - tag = "ST"; + tag = "S"; break; default: // unknown data type - tag = "UK"; + tag = "U"; break; } diff --git a/components/bt/host/bluedroid/api/esp_bluedroid_hci.c b/components/bt/host/bluedroid/api/esp_bluedroid_hci.c index d17ab91494e..1676ae88243 100644 --- a/components/bt/host/bluedroid/api/esp_bluedroid_hci.c +++ b/components/bt/host/bluedroid/api/esp_bluedroid_hci.c @@ -61,7 +61,7 @@ bool hci_host_check_send_available(void) void hci_host_send_packet(uint8_t *data, uint16_t len) { #if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_data(data[0], data, len); + bt_hci_log_record_hci_data(data[0], &data[1], len - 1); #endif #if (BT_CONTROLLER_INCLUDED == TRUE) esp_vhci_host_send_packet(data, len); diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 8f312e60a2d..a2ee1d1121b 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -541,6 +541,26 @@ static void host_send_pkt_available_cb(void) hci_downstream_data_post(OSI_THREAD_MAX_TIMEOUT); } + +void bt_record_hci_data(uint8_t *data, uint16_t len) +{ +#if (BT_HCI_LOG_INCLUDED == TRUE) + if ((data[0] == DATA_TYPE_EVENT) && (data[1] == HCI_BLE_EVENT) && ((data[3] == HCI_BLE_ADV_PKT_RPT_EVT) || (data[3] == HCI_BLE_DIRECT_ADV_EVT) +#if (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + || (data[3] == HCI_BLE_ADV_DISCARD_REPORT_EVT) +#endif // (BLE_ADV_REPORT_FLOW_CONTROL == TRUE) + #if (BLE_50_FEATURE_SUPPORT == TRUE) + || (data[3] == HCI_BLE_EXT_ADV_REPORT_EVT) || (data[3] == HCI_BLE_PERIOD_ADV_REPORT_EVT) +#endif // (BLE_50_FEATURE_SUPPORT == TRUE) + )) { + bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2); + } else { + uint8_t data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]); + bt_hci_log_record_hci_data(data_type, &data[1], len - 1); + } +#endif // (BT_HCI_LOG_INCLUDED == TRUE) +} + static int host_recv_pkt_cb(uint8_t *data, uint16_t len) { //Target has packet to host, malloc new buffer for packet @@ -552,13 +572,11 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) return 0; } + bt_record_hci_data(data, len); + bool is_adv_rpt = host_recv_adv_packet(data); if (!is_adv_rpt) { -#if (BT_HCI_LOG_INCLUDED == TRUE) - uint8_t data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]); - bt_hci_log_record_hci_data(data_type, data, len); -#endif // (BT_HCI_LOG_INCLUDED == TRUE) pkt_size = BT_HDR_SIZE + len; pkt = (BT_HDR *) osi_calloc(pkt_size); if (!pkt) { @@ -572,10 +590,6 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) memcpy(pkt->data, data, len); fixed_queue_enqueue(hci_hal_env.rx_q, pkt, FIXED_QUEUE_MAX_TIMEOUT); } else { -#if (BT_HCI_LOG_INCLUDED == TRUE) - // data type is adv report - bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, data, len); -#endif // (BT_HCI_LOG_INCLUDED == TRUE) #if !BLE_ADV_REPORT_FLOW_CONTROL // drop the packets if pkt_queue length goes beyond upper limit if (pkt_queue_length(hci_hal_env.adv_rpt_q) > HCI_HAL_BLE_ADV_RPT_QUEUE_LEN_MAX) { diff --git a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c index 8dbe78c36ae..605b831211c 100644 --- a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c +++ b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -21,8 +21,6 @@ #include "freertos/semphr.h" #include "esp_compiler.h" #include "soc/soc_caps.h" -#include "bt_common.h" -#include "hci_log/bt_hci_log.h" #define NIMBLE_VHCI_TIMEOUT_MS 2000 #define BLE_HCI_EVENT_HDR_LEN (2) @@ -77,9 +75,6 @@ int ble_hci_trans_hs_cmd_tx(uint8_t *cmd) } if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_data(cmd[0], cmd, len); -#endif esp_vhci_host_send_packet(cmd, len); } else { rc = BLE_HS_ETIMEOUT_HCI; @@ -117,9 +112,6 @@ int ble_hci_trans_hs_acl_tx(struct os_mbuf *om) len += OS_MBUF_PKTLEN(om); if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_data(data[0], data, len); -#endif esp_vhci_host_send_packet(data, len); } else { rc = BLE_HS_ETIMEOUT_HCI; @@ -178,7 +170,6 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len) OS_EXIT_CRITICAL(sr); } - /* * @brief: BT controller callback function, used to notify the upper layer that * controller is ready to receive command @@ -223,18 +214,12 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len) /* Allocate LE Advertising Report Event from lo pool only */ if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT || data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, data, len); -#endif evbuf = ble_transport_alloc_evt(1); /* Skip advertising report if we're out of memory */ if (!evbuf) { return 0; } } else { -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_data(data[0], data, len); -#endif evbuf = ble_transport_alloc_evt(0); assert(evbuf != NULL); } @@ -245,9 +230,6 @@ static int host_rcv_pkt(uint8_t *data, uint16_t len) rc = ble_hci_trans_ll_evt_tx(evbuf); assert(rc == 0); } else if (data[0] == BLE_HCI_UART_H4_ACL) { -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_record_hci_data(HCI_LOG_DATA_TYPE_C2H_ACL, data, len); -#endif ble_hci_rx_acl(data + 1, len - 1); } return 0; @@ -282,10 +264,6 @@ esp_err_t esp_nimble_hci_init(void) goto err; } -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_init(); -#endif // (BT_HCI_LOG_INCLUDED == TRUE) - xSemaphoreGive(vhci_send_sem); #if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) @@ -313,10 +291,6 @@ esp_err_t esp_nimble_hci_deinit(void) ble_buf_free(); -#if (BT_HCI_LOG_INCLUDED == TRUE) - bt_hci_log_deinit(); -#endif // (BT_HCI_LOG_INCLUDED == TRUE) - #if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK) ble_adv_list_deinit(); #endif From d83e7ea5056733ac797951db5b025045d97676b9 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 12 Jun 2024 10:55:51 +0800 Subject: [PATCH 238/548] fix(esp_system): fixed not necessary public require to bootloader_support --- components/esp_psram/CMakeLists.txt | 1 + components/esp_system/CMakeLists.txt | 3 +-- components/esp_system/port/image_process.c | 18 ++++++++++++++++++ .../private/esp_private/image_process.h | 19 ------------------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index 9083aca4440..a9693334d41 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -8,6 +8,7 @@ set(includes "include") set(priv_requires heap spi_flash esp_mm) if(${target} STREQUAL "esp32") + list(APPEND priv_requires bootloader_support) # [refactor-todo]: requires "driver" for `spicommon_periph_claim` list(APPEND priv_requires driver) endif() diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 80dca0e81d1..eac1a98ced6 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -67,8 +67,7 @@ else() # [refactor-todo] requirements due to init code, # should be removable once using component init functions # link-time registration is used. - esp_pm - REQUIRES bootloader_support + bootloader_support esp_pm LDFRAGMENTS "linker.lf" "app.lf") add_subdirectory(port) diff --git a/components/esp_system/port/image_process.c b/components/esp_system/port/image_process.c index d4ff4ed8d08..2f795bf7657 100644 --- a/components/esp_system/port/image_process.c +++ b/components/esp_system/port/image_process.c @@ -44,6 +44,24 @@ #define MMU_FLASH_MASK (~(CONFIG_MMU_PAGE_SIZE - 1)) +/** + * @brief Image process driver + */ +struct image_process_driver_s { + + /** + * @brief Process segments + * + * @param[in] data image meta data + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: invalid argument + * - ESP_ERR_INVALID_STATE: invalid state + */ + esp_err_t (*process_segments)(esp_image_metadata_t *data); +}; + const static char *TAG = "image_process"; static uint32_t s_current_read_mapping = UINT32_MAX; diff --git a/components/esp_system/port/include/private/esp_private/image_process.h b/components/esp_system/port/include/private/esp_private/image_process.h index 809055a6822..e68bd82899f 100644 --- a/components/esp_system/port/include/private/esp_private/image_process.h +++ b/components/esp_system/port/include/private/esp_private/image_process.h @@ -10,7 +10,6 @@ #include #include #include "esp_err.h" -#include "esp_image_format.h" #ifdef __cplusplus extern "C" { @@ -21,24 +20,6 @@ extern "C" { */ typedef struct image_process_driver_s image_process_driver_t; -/** - * @brief Image process driver - */ -struct image_process_driver_s { - - /** - * @brief Process segments - * - * @param[in] data image meta data - * - * @return - * - ESP_OK - * - ESP_ERR_INVALID_ARG: invalid argument - * - ESP_ERR_INVALID_STATE: invalid state - */ - esp_err_t (*process_segments)(esp_image_metadata_t *data); -}; - /** * @brief Image process flow * @note This API first reads the image header, then process the segments from the image header. From cb8670e2bc3deb919458014f0b8fcd95e501cfdf Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 13 Jun 2024 11:25:52 +0800 Subject: [PATCH 239/548] ci(flash): temp disable SOC_SPI_MEM_SUPPORT_WRAP --- components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ---- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index ab97a343dad..4c6bdc0f9ca 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1239,10 +1239,6 @@ config SOC_SPI_MEM_SUPPORT_CHECK_SUS bool default y -config SOC_SPI_MEM_SUPPORT_WRAP - bool - default y - config SOC_SPI_MEM_SUPPORT_TIMING_TUNING bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index e277bd82974..a4be4cf23e5 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -500,7 +500,7 @@ #define SOC_SPI_MEM_SUPPORT_IDLE_INTR (1) #define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1) #define SOC_SPI_MEM_SUPPORT_CHECK_SUS (1) -#define SOC_SPI_MEM_SUPPORT_WRAP (1) +// #define SOC_SPI_MEM_SUPPORT_WRAP (1) //TODO: IDFCI-2073 #define SOC_SPI_MEM_SUPPORT_TIMING_TUNING (1) #define SOC_MEMSPI_TIMING_TUNING_BY_DQS (1) From bbf0d76ac39ba68deccfe1d05eccaee700ad05be Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Fri, 31 May 2024 18:20:31 +0800 Subject: [PATCH 240/548] fix(wifi):fix data len not correct in he actions --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index fff3460aafd..cb49ddb64b9 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit fff3460aafdcfef2d1890caa80c1855eb5fac327 +Subproject commit cb49ddb64b9fd10f0b0bb62445611e903e275eef From 3b0e048f0ed3159294dfffbccc8f333a8c2311e4 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Fri, 31 May 2024 14:35:55 +0800 Subject: [PATCH 241/548] fix(wifi): fixed disable gcmp choose pairwise cipher wrong issue --- components/esp_wifi/include/esp_wifi.h | 10 +++++++++- components/esp_wifi/lib | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index f56beb6c6e0..1ec09eb11e3 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -242,6 +242,12 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define WIFI_FTM_RESPONDER 0 #endif +#if CONFIG_GCMP +#define WIFI_ENABLE_GCMP (1<<4) +#else +#define WIFI_ENABLE_GCMP 0 +#endif + #if CONFIG_ESP_WIFI_ENABLE_DUMP_HESIGB && !WIFI_CSI_ENABLED #define WIFI_DUMP_HESIGB_ENABLED true #else @@ -258,12 +264,14 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define CONFIG_FEATURE_CACHE_TX_BUF_BIT (1<<1) #define CONFIG_FEATURE_FTM_INITIATOR_BIT (1<<2) #define CONFIG_FEATURE_FTM_RESPONDER_BIT (1<<3) +#define CONFIG_FEATURE_GCMP_BIT (1<<4) /* Set additional WiFi features and capabilities */ #define WIFI_FEATURE_CAPS (WIFI_ENABLE_WPA3_SAE | \ WIFI_ENABLE_SPIRAM | \ WIFI_FTM_INITIATOR | \ - WIFI_FTM_RESPONDER) + WIFI_FTM_RESPONDER | \ + WIFI_ENABLE_GCMP) #define WIFI_INIT_CONFIG_DEFAULT() { \ .osi_funcs = &g_wifi_osi_funcs, \ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index cb49ddb64b9..e16a9ee1b2c 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit cb49ddb64b9fd10f0b0bb62445611e903e275eef +Subproject commit e16a9ee1b2c72c423e497ea62b34ae87761f7fd6 From 687a40df4ee0d90cb573d6056acadc29504bcf51 Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 6 Jun 2024 10:40:36 +0800 Subject: [PATCH 242/548] fix(wifi): do not send null data when scan start/done for mesh Closes https://github.com/espressif/esp-idf/issues/13786 --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index e16a9ee1b2c..12fad1ea40d 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit e16a9ee1b2c72c423e497ea62b34ae87761f7fd6 +Subproject commit 12fad1ea40d5ce4b1da7a1866f7bdd9b11a355bc From c3a47bf36561153f9e473ef3d758809d1a891e4f Mon Sep 17 00:00:00 2001 From: muhaidong Date: Tue, 4 Jun 2024 17:27:18 +0800 Subject: [PATCH 243/548] fix(wifi): fix configure gcmp failure issue --- components/esp_wifi/Kconfig | 2 +- components/esp_wifi/include/esp_wifi.h | 12 ++++++++++-- components/esp_wifi/lib | 2 +- components/wpa_supplicant/src/crypto/crypto_ops.c | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/components/esp_wifi/Kconfig b/components/esp_wifi/Kconfig index 1a69b8d6bd9..67f268c8fd7 100644 --- a/components/esp_wifi/Kconfig +++ b/components/esp_wifi/Kconfig @@ -406,7 +406,7 @@ menu "Wi-Fi" config ESP_WIFI_GMAC_SUPPORT bool "WiFi GMAC Support(GMAC128 and GMAC256)" - default n + default y help Select this option to enable GMAC support. GMAC support is compulsory for WiFi 192 bit certification. diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index 1ec09eb11e3..b9589ad70d0 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -242,12 +242,18 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define WIFI_FTM_RESPONDER 0 #endif -#if CONFIG_GCMP +#if CONFIG_ESP_WIFI_GCMP_SUPPORT #define WIFI_ENABLE_GCMP (1<<4) #else #define WIFI_ENABLE_GCMP 0 #endif +#if CONFIG_ESP_WIFI_GMAC_SUPPORT +#define WIFI_ENABLE_GMAC (1<<5) +#else +#define WIFI_ENABLE_GMAC 0 +#endif + #if CONFIG_ESP_WIFI_ENABLE_DUMP_HESIGB && !WIFI_CSI_ENABLED #define WIFI_DUMP_HESIGB_ENABLED true #else @@ -265,13 +271,15 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define CONFIG_FEATURE_FTM_INITIATOR_BIT (1<<2) #define CONFIG_FEATURE_FTM_RESPONDER_BIT (1<<3) #define CONFIG_FEATURE_GCMP_BIT (1<<4) +#define CONFIG_FEATURE_GMAC_BIT (1<<5) /* Set additional WiFi features and capabilities */ #define WIFI_FEATURE_CAPS (WIFI_ENABLE_WPA3_SAE | \ WIFI_ENABLE_SPIRAM | \ WIFI_FTM_INITIATOR | \ WIFI_FTM_RESPONDER | \ - WIFI_ENABLE_GCMP) + WIFI_ENABLE_GCMP | \ + WIFI_ENABLE_GMAC) #define WIFI_INIT_CONFIG_DEFAULT() { \ .osi_funcs = &g_wifi_osi_funcs, \ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 12fad1ea40d..21d34cbbf1a 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 12fad1ea40d5ce4b1da7a1866f7bdd9b11a355bc +Subproject commit 21d34cbbf1a9e7d0f6907483012d7e390b393a77 diff --git a/components/wpa_supplicant/src/crypto/crypto_ops.c b/components/wpa_supplicant/src/crypto/crypto_ops.c index 17c052c986b..7b3f31a148b 100644 --- a/components/wpa_supplicant/src/crypto/crypto_ops.c +++ b/components/wpa_supplicant/src/crypto/crypto_ops.c @@ -43,7 +43,7 @@ static int esp_aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_l #if CONFIG_GMAC return aes_gmac(key, key_len, iv, iv_len, aad, aad_len, tag); #else - return 0; + return -1; #endif } From c4bda59c319339faaf573d466f213bea77e191e4 Mon Sep 17 00:00:00 2001 From: "wangtao@espressif.com" Date: Tue, 11 Jun 2024 16:25:51 +0800 Subject: [PATCH 244/548] fix(wifi): fix sta scan when connected cause bcn timeout loop issue --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 21d34cbbf1a..7f676ffedd5 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 21d34cbbf1a9e7d0f6907483012d7e390b393a77 +Subproject commit 7f676ffedd56d64d418ca5dfa13847a2dbe07b4c From 3ccffd46f129d8a1af506515dda2f0f577456c36 Mon Sep 17 00:00:00 2001 From: aditi_lonkar Date: Mon, 8 Apr 2024 17:38:27 +0530 Subject: [PATCH 245/548] fix(esp_wifi): Fix for issue in changing opmode when wps is enabled --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 7f676ffedd5..70c2d7f46d6 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 7f676ffedd56d64d418ca5dfa13847a2dbe07b4c +Subproject commit 70c2d7f46d65a1b7904ce968e6b63a51acfc0745 From ea142bb6d1b5eaf4e2ed15e137470cb09f6a0af2 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 23 May 2024 10:42:52 +0800 Subject: [PATCH 246/548] change(esp_hw_support): do timergroup watchdogs retention by needs --- components/esp_hw_support/sleep_modes.c | 15 +++- .../esp_hw_support/sleep_system_peripheral.c | 14 +--- components/esp_pm/Kconfig | 2 +- components/esp_system/int_wdt.c | 41 ++++++++++ .../task_wdt/task_wdt_impl_timergroup.c | 57 ++++++++++++- .../beta3/include/soc/retention_periph_defs.h | 78 +++++++++++------- .../soc/esp32c5/beta3/include/soc/soc_caps.h | 1 + .../esp32c5/beta3/system_retention_periph.c | 15 ---- components/soc/esp32c5/beta3/timer_periph.c | 31 ++++++- .../soc/esp32c5/mp/include/soc/soc_caps.h | 1 + components/soc/esp32c5/mp/timer_periph.c | 31 ++++++- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 80 ++++++++++++------- components/soc/esp32c6/include/soc/soc_caps.h | 1 + .../soc/esp32c6/system_retention_periph.c | 15 ---- components/soc/esp32c6/timer_periph.c | 29 ++++++- .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 78 +++++++++++------- components/soc/esp32h2/include/soc/soc_caps.h | 1 + .../soc/esp32h2/system_retention_periph.c | 15 ---- components/soc/esp32h2/timer_periph.c | 29 ++++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 23 +++++- components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../soc/esp32p4/system_retention_periph.c | 15 ---- components/soc/esp32p4/timer_periph.c | 29 ++++++- components/soc/include/soc/regdma.h | 23 +++--- components/soc/include/soc/timer_periph.h | 12 ++- 28 files changed, 469 insertions(+), 180 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 39e7af37089..481095366a5 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -674,8 +674,19 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(bool deep_sleep) /** * These save-restore workaround should be moved to lower layer */ -FORCE_INLINE_ATTR void misc_modules_wake_prepare(void) +FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t pd_flags) { +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + if (pd_flags & PMU_SLEEP_PD_TOP) { + // There is no driver to manage the flashboot watchdog, and it is definitely be in off state when + // the system is running, after waking up from pd_top sleep, shut it down by software here. + wdt_hal_context_t mwdt_ctx = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&mwdt_ctx); + wdt_hal_set_flashboot_en(&mwdt_ctx, false); + wdt_hal_write_protect_enable(&mwdt_ctx); + } +#endif + #if SOC_USB_SERIAL_JTAG_SUPPORTED && !SOC_USB_SERIAL_JTAG_SUPPORT_LIGHT_SLEEP sleep_console_usj_pad_restore(); #endif @@ -1043,7 +1054,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m sleep_retention_do_system_retention(false); } #endif - misc_modules_wake_prepare(); + misc_modules_wake_prepare(pd_flags); } #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 3ba63ffafff..531f3dd6706 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -57,14 +57,6 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_uart0_retention_init(v return ESP_OK; } -static __attribute__((unused)) esp_err_t sleep_sys_periph_tg0_retention_init(void *arg) -{ - esp_err_t err = sleep_retention_entries_create(tg_regs_retention, ARRAY_SIZE(tg_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); - ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "Timer Group"); - ESP_LOGD(TAG, "Timer Group sleep retention initialization"); - return ESP_OK; -} - static __attribute__((unused)) esp_err_t sleep_sys_periph_iomux_retention_init(void *arg) { esp_err_t err = sleep_retention_entries_create(iomux_regs_retention, ARRAY_SIZE(iomux_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); @@ -126,8 +118,6 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_retention_init(void *a #endif err = sleep_sys_periph_uart0_retention_init(arg); if(err) goto error; - err = sleep_sys_periph_tg0_retention_init(arg); - if(err) goto error; err = sleep_sys_periph_iomux_retention_init(arg); if(err) goto error; err = sleep_sys_periph_spimem_retention_init(arg); @@ -147,9 +137,7 @@ bool peripheral_domain_pd_allowed(void) #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP const uint32_t inited_modules = sleep_retention_get_inited_modules(); const uint32_t created_modules = sleep_retention_get_created_modules(); - const uint32_t mask = (const uint32_t) (BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH)); - - return ((inited_modules & mask) == (created_modules & mask)); + return (((inited_modules ^ created_modules) & TOP_DOMAIN_PERIPHERALS_BM) == 0); #else return false; #endif diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 8e5cc131584..d7f0ee7d3b8 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -142,7 +142,7 @@ menu "Power Management" config PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP bool "Power down Digital Peripheral in light sleep (EXPERIMENTAL)" - depends on SOC_PM_SUPPORT_TOP_PD + depends on SOC_PM_SUPPORT_TOP_PD && SOC_PAU_SUPPORTED select PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP if !SOC_CPU_IN_TOP_DOMAIN default n #TODO: enable by default if periph init/deinit management supported (WIFI-5252) help diff --git a/components/esp_system/int_wdt.c b/components/esp_system/int_wdt.c index e4936f0a667..68d031d5337 100644 --- a/components/esp_system/int_wdt.c +++ b/components/esp_system/int_wdt.c @@ -14,6 +14,7 @@ #include "hal/timer_ll.h" #include "freertos/FreeRTOS.h" #include "esp_cpu.h" +#include "esp_check.h" #include "esp_err.h" #include "esp_attr.h" #include "esp_log.h" @@ -23,6 +24,10 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/esp_int_wdt.h" +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +#include "esp_private/sleep_retention.h" +#endif + #if SOC_TIMER_GROUPS > 1 /* If we have two hardware timer groups, use the second one for interrupt watchdog. */ @@ -47,6 +52,38 @@ #endif // SOC_TIMER_GROUPS > 1 #if CONFIG_ESP_INT_WDT +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +static const char* TAG = "int_wdt"; +static esp_err_t sleep_int_wdt_retention_init(void *arg) +{ + uint32_t group_id = *(uint32_t *)arg; + esp_err_t err = sleep_retention_entries_create(tg_wdt_regs_retention[group_id].link_list, + tg_wdt_regs_retention[group_id].link_num, + REGDMA_LINK_PRI_6, + (group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + if (err == ESP_OK) { + ESP_LOGD(TAG, "Interrupt watchdog timer retention initialization"); + } + ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for interrupt watchdog timer"); + return err; +} + +static esp_err_t esp_int_wdt_retention_enable(uint32_t group_id) +{ + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = sleep_int_wdt_retention_init, .arg = &group_id } }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) + }; + esp_err_t err = sleep_retention_module_init((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT, &init_param); + if (err == ESP_OK) { + err = sleep_retention_module_allocate((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for interrupt watchdog timer retention"); + } + } + return err; +} +#endif static wdt_hal_context_t iwdt_context; @@ -122,6 +159,10 @@ void esp_int_wdt_init(void) wdt_hal_enable(&iwdt_context); wdt_hal_write_protect_enable(&iwdt_context); +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION + esp_int_wdt_retention_enable(IWDT_TIMER_GROUP); +#endif + #if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI) #define APB_DCRSET (0x200c) #define APB_ITCTRL (0x3f00) diff --git a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c index 5d0fef7234c..533a4f24616 100644 --- a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c +++ b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c @@ -11,13 +11,19 @@ #include "hal/wdt_hal.h" #include "hal/mwdt_ll.h" #include "hal/timer_ll.h" +#include "esp_check.h" #include "esp_err.h" #include "esp_attr.h" #include "esp_intr_alloc.h" +#include "esp_log.h" #include "esp_private/system_internal.h" #include "esp_private/periph_ctrl.h" #include "esp_private/esp_task_wdt_impl.h" +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +#include "esp_private/sleep_retention.h" +#endif + #define TWDT_INSTANCE WDT_MWDT0 #define TWDT_TICKS_PER_US 500 #define TWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz @@ -39,6 +45,48 @@ typedef struct { * init function. */ static twdt_ctx_hard_t init_context; +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +static const char* TAG = "task_wdt"; +static esp_err_t sleep_task_wdt_retention_init(void *arg) +{ + uint32_t group_id = *(uint32_t *)arg; + esp_err_t err = sleep_retention_entries_create(tg_wdt_regs_retention[group_id].link_list, + tg_wdt_regs_retention[group_id].link_num, + REGDMA_LINK_PRI_6, + (group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + if (err == ESP_OK) { + ESP_LOGD(TAG, "Task watchdog timer retention initialization"); + } + ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for task watchdog timer"); + return err; +} + +static esp_err_t esp_task_wdt_retention_enable(uint32_t group_id) +{ + sleep_retention_module_init_param_t init_param = { + .cbs = { .create = { .handle = sleep_task_wdt_retention_init, .arg = &group_id } }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) + }; + esp_err_t err = sleep_retention_module_init((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT, &init_param); + if (err == ESP_OK) { + err = sleep_retention_module_allocate((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for task watchdog timer retention"); + } + } + return err; +} + +static esp_err_t esp_task_wdt_retention_disable(uint32_t group_id) +{ + esp_err_t err = sleep_retention_module_free((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + if (err == ESP_OK) { + err = sleep_retention_module_deinit((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); + } + return err; +} +#endif + esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config, twdt_isr_callback callback, twdt_ctx_t *obj) @@ -74,8 +122,11 @@ esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config, /* Return the implementation context to the caller */ *obj = (twdt_ctx_t) ctx; - } +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION + esp_task_wdt_retention_enable(TWDT_TIMER_GROUP); +#endif + } return ret; } @@ -118,6 +169,10 @@ void esp_task_wdt_impl_timer_free(twdt_ctx_t obj) /* Deregister interrupt */ ESP_ERROR_CHECK(esp_intr_free(ctx->intr_handle)); + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION + ESP_ERROR_CHECK(esp_task_wdt_retention_disable(TWDT_TIMER_GROUP)); +#endif } } diff --git a/components/soc/esp32c5/beta3/include/soc/retention_periph_defs.h b/components/soc/esp32c5/beta3/include/soc/retention_periph_defs.h index 2ef044eb402..47b33960179 100644 --- a/components/soc/esp32c5/beta3/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c5/beta3/include/soc/retention_periph_defs.h @@ -18,24 +18,29 @@ typedef enum periph_retention_module { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1, SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2, - - /* modem module, which includes WiFi, BLE and 802.15.4 */ - SLEEP_RETENTION_MODULE_WIFI_MAC = 10, - SLEEP_RETENTION_MODULE_WIFI_BB = 11, - SLEEP_RETENTION_MODULE_BLE_MAC = 12, - SLEEP_RETENTION_MODULE_BT_BB = 13, - SLEEP_RETENTION_MODULE_802154_MAC = 14, - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ - SLEEP_RETENTION_MODULE_SYS_PERIPH = 16, - - SLEEP_RETENTION_MODULE_ADC = 17, - - SLEEP_RETENTION_MODULE_GDMA_CH0 = 24, - SLEEP_RETENTION_MODULE_GDMA_CH1 = 25, - SLEEP_RETENTION_MODULE_GDMA_CH2 = 26, + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_SYS_PERIPH = 3, + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_TG0_WDT = 4, + SLEEP_RETENTION_MODULE_TG1_WDT = 5, + SLEEP_RETENTION_MODULE_TG0_TIMER = 6, + SLEEP_RETENTION_MODULE_TG1_TIMER = 7, + /* GDMA by channel */ + SLEEP_RETENTION_MODULE_GDMA_CH0 = 8, + SLEEP_RETENTION_MODULE_GDMA_CH1 = 9, + SLEEP_RETENTION_MODULE_GDMA_CH2 = 10, + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_ADC = 11, + SLEEP_RETENTION_MODULE_I2C0 = 12, + SLEEP_RETENTION_MODULE_RMT0 = 13, + /* Modem module, which includes WiFi, BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_WIFI_MAC = 26, + SLEEP_RETENTION_MODULE_WIFI_BB = 27, + SLEEP_RETENTION_MODULE_BLE_MAC = 28, + SLEEP_RETENTION_MODULE_BT_BB = 29, + SLEEP_RETENTION_MODULE_802154_MAC = 30, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -43,26 +48,45 @@ typedef enum periph_retention_module_bitmap { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM), - + /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_BM_TASK_WDT = BIT(SLEEP_RETENTION_MODULE_TG0_WDT), + SLEEP_RETENTION_MODULE_BM_INT_WDT = BIT(SLEEP_RETENTION_MODULE_TG1_WDT), + SLEEP_RETENTION_MODULE_BM_TG0_TIMER = BIT(SLEEP_RETENTION_MODULE_TG0_TIMER), + SLEEP_RETENTION_MODULE_BM_TG1_TIMER = BIT(SLEEP_RETENTION_MODULE_TG1_TIMER), + /* GDMA by channel */ + SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), + SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), + SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), + SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), + SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), - - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ - SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), - - SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), - - SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), - SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), - SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; +#define TOP_DOMAIN_PERIPHERALS_BM (SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM \ + | SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM \ + | SLEEP_RETENTION_MODULE_BM_SYS_PERIPH \ + | SLEEP_RETENTION_MODULE_BM_TASK_WDT \ + | SLEEP_RETENTION_MODULE_BM_INT_WDT \ + | SLEEP_RETENTION_MODULE_BM_TG0_TIMER \ + | SLEEP_RETENTION_MODULE_BM_TG1_TIMER \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH0 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH1 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH2 \ + | SLEEP_RETENTION_MODULE_BM_ADC \ + | SLEEP_RETENTION_MODULE_BM_I2C0 \ + | SLEEP_RETENTION_MODULE_BM_RMT0) + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index fa64ffd022f..de656045300 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -444,6 +444,7 @@ // #define SOC_TIMER_GROUP_SUPPORT_RC_FAST (1) #define SOC_TIMER_GROUP_TOTAL_TIMERS (2) // #define SOC_TIMER_SUPPORT_ETM (1) +// #define SOC_TIMER_SUPPORT_SLEEP_RETENTION (1) /*--------------------------- WATCHDOG CAPS ---------------------------------------*/ // #define SOC_MWDT_SUPPORT_XTAL (1) diff --git a/components/soc/esp32c5/beta3/system_retention_periph.c b/components/soc/esp32c5/beta3/system_retention_periph.c index 08848b4c757..d2a9863ca6c 100644 --- a/components/soc/esp32c5/beta3/system_retention_periph.c +++ b/components/soc/esp32c5/beta3/system_retention_periph.c @@ -54,21 +54,6 @@ const regdma_entries_config_t uart_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); -/* Timergroup Registers Context */ -#define N_REGS_TG() (((TIMG_REGCLK_REG(0) - REG_TIMG_BASE(0)) / 4) + 1) -const regdma_entries_config_t tg_regs_retention[] = { - /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, /* TG0 */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x01), REG_TIMG_BASE(0), REG_TIMG_BASE(0), N_REGS_TG(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x02), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x04), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_TIMG_LINK(0x05), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x06), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x07), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO26_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC30_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32c5/beta3/timer_periph.c b/components/soc/esp32c5/beta3/timer_periph.c index 4273eec72e6..4ab27c7fdf2 100644 --- a/components/soc/esp32c5/beta3/timer_periph.c +++ b/components/soc/esp32c5/beta3/timer_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,3 +22,32 @@ const timer_group_signal_conn_t timer_group_periph_signals = { } } }; + +#if SOC_TIMER_SUPPORT_SLEEP_RETENTION +#define N_REGS_TGWDT 6 // TIMG_WDTCONFIG0_REG ... TIMG_WDTCONFIG5_REG & TIMG_INT_ENA_TIMERS_REG + +static const regdma_entries_config_t tg0_wdt_regs_retention[] = { + /*Timer group backup. should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(0), TIMG_WDTCONFIG0_REG(0), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(0), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(0),TIMG_INT_ENA_TIMERS_REG(0), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(0), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +static const regdma_entries_config_t tg1_wdt_regs_retention[] = { + /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(1), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(1),TIMG_INT_ENA_TIMERS_REG(1), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(1), TIMG_WDTCONFIG0_REG(1), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(1), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(1), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, + [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, +}; +#endif diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index dc5e4d5f769..e4eb5013679 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -439,6 +439,7 @@ // #define SOC_TIMER_GROUP_SUPPORT_RC_FAST (1) #define SOC_TIMER_GROUP_TOTAL_TIMERS (2) // #define SOC_TIMER_SUPPORT_ETM (1) +// #define SOC_TIMER_SUPPORT_SLEEP_RETENTION (1) /*--------------------------- WATCHDOG CAPS ---------------------------------------*/ // #define SOC_MWDT_SUPPORT_XTAL (1) diff --git a/components/soc/esp32c5/mp/timer_periph.c b/components/soc/esp32c5/mp/timer_periph.c index 4273eec72e6..4ab27c7fdf2 100644 --- a/components/soc/esp32c5/mp/timer_periph.c +++ b/components/soc/esp32c5/mp/timer_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,3 +22,32 @@ const timer_group_signal_conn_t timer_group_periph_signals = { } } }; + +#if SOC_TIMER_SUPPORT_SLEEP_RETENTION +#define N_REGS_TGWDT 6 // TIMG_WDTCONFIG0_REG ... TIMG_WDTCONFIG5_REG & TIMG_INT_ENA_TIMERS_REG + +static const regdma_entries_config_t tg0_wdt_regs_retention[] = { + /*Timer group backup. should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(0), TIMG_WDTCONFIG0_REG(0), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(0), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(0),TIMG_INT_ENA_TIMERS_REG(0), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(0), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +static const regdma_entries_config_t tg1_wdt_regs_retention[] = { + /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(1), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(1),TIMG_INT_ENA_TIMERS_REG(1), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(1), TIMG_WDTCONFIG0_REG(1), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(1), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(1), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, + [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, +}; +#endif diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 85387866e88..f3f3df1034b 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1111,6 +1111,10 @@ config SOC_TIMER_SUPPORT_ETM bool default y +config SOC_TIMER_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MWDT_SUPPORT_XTAL bool default y diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index bd798e19038..47b33960179 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -18,25 +18,29 @@ typedef enum periph_retention_module { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1, SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2, - - /* modem module, which includes WiFi, BLE and 802.15.4 */ - SLEEP_RETENTION_MODULE_WIFI_MAC = 10, - SLEEP_RETENTION_MODULE_WIFI_BB = 11, - SLEEP_RETENTION_MODULE_BLE_MAC = 12, - SLEEP_RETENTION_MODULE_BT_BB = 13, - SLEEP_RETENTION_MODULE_802154_MAC = 14, - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ - SLEEP_RETENTION_MODULE_SYS_PERIPH = 16, - - SLEEP_RETENTION_MODULE_ADC = 17, - - SLEEP_RETENTION_MODULE_GDMA_CH0 = 24, - SLEEP_RETENTION_MODULE_GDMA_CH1 = 25, - SLEEP_RETENTION_MODULE_GDMA_CH2 = 26, - SLEEP_RETENTION_MODULE_I2C0 = 27, + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_SYS_PERIPH = 3, + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_TG0_WDT = 4, + SLEEP_RETENTION_MODULE_TG1_WDT = 5, + SLEEP_RETENTION_MODULE_TG0_TIMER = 6, + SLEEP_RETENTION_MODULE_TG1_TIMER = 7, + /* GDMA by channel */ + SLEEP_RETENTION_MODULE_GDMA_CH0 = 8, + SLEEP_RETENTION_MODULE_GDMA_CH1 = 9, + SLEEP_RETENTION_MODULE_GDMA_CH2 = 10, + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_ADC = 11, + SLEEP_RETENTION_MODULE_I2C0 = 12, + SLEEP_RETENTION_MODULE_RMT0 = 13, + /* Modem module, which includes WiFi, BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_WIFI_MAC = 26, + SLEEP_RETENTION_MODULE_WIFI_BB = 27, + SLEEP_RETENTION_MODULE_BLE_MAC = 28, + SLEEP_RETENTION_MODULE_BT_BB = 29, + SLEEP_RETENTION_MODULE_802154_MAC = 30, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -44,27 +48,45 @@ typedef enum periph_retention_module_bitmap { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM), - - /* modem module, which includes WiFi, BLE and 802.15.4 */ - SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), - SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), - SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), - SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), - SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), - - SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), - + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_BM_TASK_WDT = BIT(SLEEP_RETENTION_MODULE_TG0_WDT), + SLEEP_RETENTION_MODULE_BM_INT_WDT = BIT(SLEEP_RETENTION_MODULE_TG1_WDT), + SLEEP_RETENTION_MODULE_BM_TG0_TIMER = BIT(SLEEP_RETENTION_MODULE_TG0_TIMER), + SLEEP_RETENTION_MODULE_BM_TG1_TIMER = BIT(SLEEP_RETENTION_MODULE_TG1_TIMER), + /* GDMA by channel */ SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), + SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), + /* modem module, which includes WiFi, BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), + SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), + SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), + SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), + SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; +#define TOP_DOMAIN_PERIPHERALS_BM (SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM \ + | SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM \ + | SLEEP_RETENTION_MODULE_BM_SYS_PERIPH \ + | SLEEP_RETENTION_MODULE_BM_TASK_WDT \ + | SLEEP_RETENTION_MODULE_BM_INT_WDT \ + | SLEEP_RETENTION_MODULE_BM_TG0_TIMER \ + | SLEEP_RETENTION_MODULE_BM_TG1_TIMER \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH0 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH1 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH2 \ + | SLEEP_RETENTION_MODULE_BM_ADC \ + | SLEEP_RETENTION_MODULE_BM_I2C0 \ + | SLEEP_RETENTION_MODULE_BM_RMT0) + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 4ad24e4d172..c16ebceee48 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -440,6 +440,7 @@ #define SOC_TIMER_GROUP_SUPPORT_RC_FAST (1) #define SOC_TIMER_GROUP_TOTAL_TIMERS (2) #define SOC_TIMER_SUPPORT_ETM (1) +#define SOC_TIMER_SUPPORT_SLEEP_RETENTION (1) /*--------------------------- WATCHDOG CAPS ---------------------------------------*/ #define SOC_MWDT_SUPPORT_XTAL (1) diff --git a/components/soc/esp32c6/system_retention_periph.c b/components/soc/esp32c6/system_retention_periph.c index 8e65e7c355a..b9645c39a43 100644 --- a/components/soc/esp32c6/system_retention_periph.c +++ b/components/soc/esp32c6/system_retention_periph.c @@ -54,21 +54,6 @@ const regdma_entries_config_t uart_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); -/* Timergroup Registers Context */ -#define N_REGS_TG() (((TIMG_REGCLK_REG(0) - REG_TIMG_BASE(0)) / 4) + 1) -const regdma_entries_config_t tg_regs_retention[] = { - /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, /* TG0 */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x01), REG_TIMG_BASE(0), REG_TIMG_BASE(0), N_REGS_TG(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x02), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x04), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_TIMG_LINK(0x05), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x06), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x07), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO30_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC34_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32c6/timer_periph.c b/components/soc/esp32c6/timer_periph.c index 089c80958fb..7d338258deb 100644 --- a/components/soc/esp32c6/timer_periph.c +++ b/components/soc/esp32c6/timer_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,3 +22,30 @@ const timer_group_signal_conn_t timer_group_periph_signals = { } } }; + +#define N_REGS_TGWDT 6 // TIMG_WDTCONFIG0_REG ... TIMG_WDTCONFIG5_REG & TIMG_INT_ENA_TIMERS_REG + +static const regdma_entries_config_t tg0_wdt_regs_retention[] = { + /*Timer group backup. should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(0), TIMG_WDTCONFIG0_REG(0), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(0), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(0),TIMG_INT_ENA_TIMERS_REG(0), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(0), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +static const regdma_entries_config_t tg1_wdt_regs_retention[] = { + /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(1), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(1),TIMG_INT_ENA_TIMERS_REG(1), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(1), TIMG_WDTCONFIG0_REG(1), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(1), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(1), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, + [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, +}; diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 5bc1cc44953..9ebdecb32cd 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1115,6 +1115,10 @@ config SOC_TIMER_SUPPORT_ETM bool default y +config SOC_TIMER_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MWDT_SUPPORT_XTAL bool default y diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index 5ac1e90c2a8..353bc1c2bc9 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -18,24 +18,28 @@ typedef enum periph_retention_module { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1, SLEEP_RETENTION_MODULE_CLOCK_MODEM = 2, - - /* modem module, which includes BLE and 802.15.4 */ - SLEEP_RETENTION_MODULE_BLE_MAC = 12, - SLEEP_RETENTION_MODULE_BT_BB = 13, - SLEEP_RETENTION_MODULE_802154_MAC = 14, - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ - SLEEP_RETENTION_MODULE_SYS_PERIPH = 16, - - SLEEP_RETENTION_MODULE_ADC = 17, - - SLEEP_RETENTION_MODULE_GDMA_CH0 = 24, - SLEEP_RETENTION_MODULE_GDMA_CH1 = 25, - SLEEP_RETENTION_MODULE_GDMA_CH2 = 26, - SLEEP_RETENTION_MODULE_I2C0 = 27, - SLEEP_RETENTION_MODULE_I2C1 = 28, - + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_SYS_PERIPH = 3, + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_TG0_WDT = 4, + SLEEP_RETENTION_MODULE_TG1_WDT = 5, + SLEEP_RETENTION_MODULE_TG0_TIMER = 6, + SLEEP_RETENTION_MODULE_TG1_TIMER = 7, + /* GDMA by channel */ + SLEEP_RETENTION_MODULE_GDMA_CH0 = 8, + SLEEP_RETENTION_MODULE_GDMA_CH1 = 9, + SLEEP_RETENTION_MODULE_GDMA_CH2 = 10, + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_ADC = 11, + SLEEP_RETENTION_MODULE_I2C0 = 12, + SLEEP_RETENTION_MODULE_I2C1 = 13, + SLEEP_RETENTION_MODULE_RMT0 = 14, + + /* Modem module, which includes BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_BLE_MAC = 28, + SLEEP_RETENTION_MODULE_BT_BB = 29, + SLEEP_RETENTION_MODULE_802154_MAC = 30, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -43,27 +47,45 @@ typedef enum periph_retention_module_bitmap { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_MODEM), - - /* modem module, which includes BLE and 802.15.4 */ - SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), - SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), - SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), - - SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), - + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_BM_TASK_WDT = BIT(SLEEP_RETENTION_MODULE_TG0_WDT), + SLEEP_RETENTION_MODULE_BM_INT_WDT = BIT(SLEEP_RETENTION_MODULE_TG1_WDT), + SLEEP_RETENTION_MODULE_BM_TG0_TIMER = BIT(SLEEP_RETENTION_MODULE_TG0_TIMER), + SLEEP_RETENTION_MODULE_BM_TG1_TIMER = BIT(SLEEP_RETENTION_MODULE_TG1_TIMER), + /* GDMA by channel */ SLEEP_RETENTION_MODULE_BM_GDMA_CH0 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH0), SLEEP_RETENTION_MODULE_BM_GDMA_CH1 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH1), SLEEP_RETENTION_MODULE_BM_GDMA_CH2 = BIT(SLEEP_RETENTION_MODULE_GDMA_CH2), + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), SLEEP_RETENTION_MODULE_BM_I2C1 = BIT(SLEEP_RETENTION_MODULE_I2C1), - - SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 + SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), + /* modem module, which includes BLE and 802.15.4 */ + SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), + SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), + SLEEP_RETENTION_MODULE_BM_802154_MAC = BIT(SLEEP_RETENTION_MODULE_802154_MAC), + SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t) -1 } periph_retention_module_bitmap_t; +#define TOP_DOMAIN_PERIPHERALS_BM (SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM \ + | SLEEP_RETENTION_MODULE_BM_CLOCK_MODEM \ + | SLEEP_RETENTION_MODULE_BM_SYS_PERIPH \ + | SLEEP_RETENTION_MODULE_BM_TASK_WDT \ + | SLEEP_RETENTION_MODULE_BM_INT_WDT \ + | SLEEP_RETENTION_MODULE_BM_TG0_TIMER \ + | SLEEP_RETENTION_MODULE_BM_TG1_TIMER \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH0 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH1 \ + | SLEEP_RETENTION_MODULE_BM_GDMA_CH2 \ + | SLEEP_RETENTION_MODULE_BM_ADC \ + | SLEEP_RETENTION_MODULE_BM_I2C0 \ + | SLEEP_RETENTION_MODULE_BM_I2C1 \ + | SLEEP_RETENTION_MODULE_BM_RMT0) + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 29599f99f75..8728e3f730d 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -438,6 +438,7 @@ #define SOC_TIMER_GROUP_SUPPORT_RC_FAST (1) #define SOC_TIMER_GROUP_TOTAL_TIMERS (2) #define SOC_TIMER_SUPPORT_ETM (1) +#define SOC_TIMER_SUPPORT_SLEEP_RETENTION (1) /*--------------------------- WATCHDOG CAPS ---------------------------------------*/ #define SOC_MWDT_SUPPORT_XTAL (1) diff --git a/components/soc/esp32h2/system_retention_periph.c b/components/soc/esp32h2/system_retention_periph.c index fead39b1238..da52fbe53fc 100644 --- a/components/soc/esp32h2/system_retention_periph.c +++ b/components/soc/esp32h2/system_retention_periph.c @@ -54,21 +54,6 @@ const regdma_entries_config_t uart_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); -/* Timergroup Registers Context */ -#define N_REGS_TG() (((TIMG_REGCLK_REG(0) - REG_TIMG_BASE(0)) / 4) + 1) -const regdma_entries_config_t tg_regs_retention[] = { - /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, /* TG0 */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x01), REG_TIMG_BASE(0), REG_TIMG_BASE(0), N_REGS_TG(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x02), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x04), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_TIMG_LINK(0x05), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x06), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, - [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x07), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO27_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC31_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32h2/timer_periph.c b/components/soc/esp32h2/timer_periph.c index e2be270b18e..7d338258deb 100644 --- a/components/soc/esp32h2/timer_periph.c +++ b/components/soc/esp32h2/timer_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,3 +22,30 @@ const timer_group_signal_conn_t timer_group_periph_signals = { } } }; + +#define N_REGS_TGWDT 6 // TIMG_WDTCONFIG0_REG ... TIMG_WDTCONFIG5_REG & TIMG_INT_ENA_TIMERS_REG + +static const regdma_entries_config_t tg0_wdt_regs_retention[] = { + /*Timer group backup. should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(0), TIMG_WDTCONFIG0_REG(0), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(0), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(0),TIMG_INT_ENA_TIMERS_REG(0), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(0), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +static const regdma_entries_config_t tg1_wdt_regs_retention[] = { + /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(1), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(1),TIMG_INT_ENA_TIMERS_REG(1), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(1), TIMG_WDTCONFIG0_REG(1), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(1), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(1), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, + [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index d58925194ea..dd76fce1aa1 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1359,6 +1359,10 @@ config SOC_TIMER_SUPPORT_ETM bool default y +config SOC_TIMER_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_MWDT_SUPPORT_XTAL bool default y diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index fde9c3e6876..34219a85e0b 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -17,10 +17,14 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_MIN = 0, /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_CLOCK_SYSTEM = 1, - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, - * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ - SLEEP_RETENTION_MODULE_SYS_PERIPH = 16, + * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ + SLEEP_RETENTION_MODULE_SYS_PERIPH = 2, + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_TG0_WDT = 3, + SLEEP_RETENTION_MODULE_TG1_WDT = 4, + SLEEP_RETENTION_MODULE_TG0_TIMER = 5, + SLEEP_RETENTION_MODULE_TG1_TIMER = 6, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -28,14 +32,25 @@ typedef enum periph_retention_module { typedef enum periph_retention_module_bitmap { /* clock module, which includes system and modem */ SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), - /* digital peripheral module, which includes Interrupt Matrix, HP_SYSTEM, * TEE, APM, UART, Timer Group, IOMUX, SPIMEM, SysTimer, etc.. */ SLEEP_RETENTION_MODULE_BM_SYS_PERIPH = BIT(SLEEP_RETENTION_MODULE_SYS_PERIPH), + /* Timer Group by target*/ + SLEEP_RETENTION_MODULE_BM_TG0_WDT = BIT(SLEEP_RETENTION_MODULE_TG0_WDT), + SLEEP_RETENTION_MODULE_BM_TG1_WDT = BIT(SLEEP_RETENTION_MODULE_TG1_WDT), + SLEEP_RETENTION_MODULE_BM_TG0_TIMER = BIT(SLEEP_RETENTION_MODULE_TG0_TIMER), + SLEEP_RETENTION_MODULE_BM_TG1_TIMER = BIT(SLEEP_RETENTION_MODULE_TG1_TIMER), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; +#define TOP_DOMAIN_PERIPHERALS_BM (SLEEP_RETENTION_MODULE_BM_CLOCK_SYSTEM \ + | SLEEP_RETENTION_MODULE_BM_SYS_PERIPH \ + | SLEEP_RETENTION_MODULE_BM_TG0_WDT \ + | SLEEP_RETENTION_MODULE_BM_TG1_WDT \ + | SLEEP_RETENTION_MODULE_BM_TG0_TIMER \ + | SLEEP_RETENTION_MODULE_BM_TG1_TIMER) + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 4a1f6cefd4a..ce6770f1b6c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -536,6 +536,7 @@ #define SOC_TIMER_GROUP_SUPPORT_RC_FAST 1 #define SOC_TIMER_GROUP_TOTAL_TIMERS 4 #define SOC_TIMER_SUPPORT_ETM 1 +#define SOC_TIMER_SUPPORT_SLEEP_RETENTION 1 /*--------------------------- WATCHDOG CAPS ---------------------------------------*/ #define SOC_MWDT_SUPPORT_XTAL (1) diff --git a/components/soc/esp32p4/system_retention_periph.c b/components/soc/esp32p4/system_retention_periph.c index 855a47209f9..381b20641a7 100644 --- a/components/soc/esp32p4/system_retention_periph.c +++ b/components/soc/esp32p4/system_retention_periph.c @@ -52,21 +52,6 @@ const regdma_entries_config_t uart_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); -/* Timergroup Registers Context */ -#define N_REGS_TG0() (((TIMG_REGCLK_REG(0) - REG_TIMG_BASE(0)) / 4) + 1) -const regdma_entries_config_t tg_regs_retention[] = { - /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ - [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) }, /* TG0 */ - [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x01), REG_TIMG_BASE(0), REG_TIMG_BASE(0), N_REGS_TG0(), 0, 0), .owner = ENTRY(0) }, - [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x02), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) }, - [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) }, - [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x04), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) }, - [5] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_TIMG_LINK(0x05), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) }, - [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TIMG_LINK(0x06), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) }, - [7] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TIMG_LINK(0x07), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) }, -}; -_Static_assert(ARRAY_SIZE(tg_regs_retention) == TIMG_RETENTION_LINK_LEN, "Inconsistent Timergroup retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1) diff --git a/components/soc/esp32p4/timer_periph.c b/components/soc/esp32p4/timer_periph.c index f799a91f7eb..043ab9764f5 100644 --- a/components/soc/esp32p4/timer_periph.c +++ b/components/soc/esp32p4/timer_periph.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,3 +24,30 @@ const timer_group_signal_conn_t timer_group_periph_signals = { } } }; + +#define N_REGS_TGWDT 6 // TIMG_WDTCONFIG0_REG ... TIMG_WDTCONFIG5_REG & TIMG_INT_ENA_TIMERS_REG + +static const regdma_entries_config_t tg0_wdt_regs_retention[] = { + /*Timer group backup. should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(0), TIMG_WDTCONFIG0_REG(0), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(0), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(0), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(0),TIMG_INT_ENA_TIMERS_REG(0), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(0), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +static const regdma_entries_config_t tg1_wdt_regs_retention[] = { + /*Timer group0 backup. T0_wdt should get of write project firstly. wdt used by RTOS.*/ + [0] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x00), TIMG_WDTWPROTECT_REG(1), TIMG_WDT_WKEY_VALUE, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [1] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x02), TIMG_INT_ENA_TIMERS_REG(1),TIMG_INT_ENA_TIMERS_REG(1), 1, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_WDT_LINK(0x01), TIMG_WDTCONFIG0_REG(1), TIMG_WDTCONFIG0_REG(1), N_REGS_TGWDT, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x03), TIMG_WDTCONFIG0_REG(1), TIMG_WDT_CONF_UPDATE_EN, TIMG_WDT_CONF_UPDATE_EN_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG0_WDT_LINK(0x03), TIMG_WDTFEED_REG(1), TIMG_WDT_FEED, TIMG_WDT_FEED_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, + [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, +}; diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index 1662f733afa..2243d1113ad 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -37,15 +37,19 @@ extern "C" { #define REGDMA_TEEAPM_LINK(_pri) ((0x0f << 8) | _pri) #define REGDMA_UART_LINK(_pri) ((0x10 << 8) | _pri) -#define REGDMA_TIMG_LINK(_pri) ((0x11 << 8) | _pri) -#define REGDMA_IOMUX_LINK(_pri) ((0x12 << 8) | _pri) -#define REGDMA_SPIMEM_LINK(_pri) ((0x13 << 8) | _pri) -#define REGDMA_SYSTIMER_LINK(_pri) ((0x14 << 8) | _pri) -#define REGDMA_BLE_MAC_LINK(_pri) ((0x15 << 8) | _pri) -#define REGDMA_MODEM_BT_BB_LINK(_pri) ((0x16 << 8) | _pri) -#define REGDMA_MODEM_IEEE802154_LINK(_pri) ((0x17 << 8) | _pri) -#define REGDMA_GDMA_LINK(_pri) ((0x18 << 8) | _pri) -#define REGDMA_I2C_LINK(_pri) ((0x19 << 8) | _pri) +#define REGDMA_IOMUX_LINK(_pri) ((0x11 << 8) | _pri) +#define REGDMA_SPIMEM_LINK(_pri) ((0x12 << 8) | _pri) +#define REGDMA_SYSTIMER_LINK(_pri) ((0x13 << 8) | _pri) +#define REGDMA_BLE_MAC_LINK(_pri) ((0x14 << 8) | _pri) +#define REGDMA_MODEM_BT_BB_LINK(_pri) ((0x15 << 8) | _pri) +#define REGDMA_MODEM_IEEE802154_LINK(_pri) ((0x16 << 8) | _pri) +#define REGDMA_GDMA_LINK(_pri) ((0x17 << 8) | _pri) +#define REGDMA_I2C_LINK(_pri) ((0x18 << 8) | _pri) +#define REGDMA_RMT_LINK(_pri) ((0x19 << 8) | _pri) +#define REGDMA_TG0_WDT_LINK(_pri) ((0x1A << 8) | _pri) +#define REGDMA_TG1_WDT_LINK(_pri) ((0x1B << 8) | _pri) +#define REGDMA_TG0_TIMER_LINK(_pri) ((0x1C << 8) | _pri) +#define REGDMA_TG1_TIMER_LINK(_pri) ((0x1D << 8) | _pri) #define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri) #define REGDMA_LINK_PRI_SYS_CLK REGDMA_LINK_PRI_0 @@ -58,6 +62,7 @@ extern "C" { #define REGDMA_LINK_PRI_SYS_PERIPH_LOW REGDMA_LINK_PRI_6 // TG0 & IO MUX & SPI MEM & Systimer #define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_7 #define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_7 +#define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_7 typedef enum { REGDMA_LINK_PRI_0 = 0, diff --git a/components/soc/include/soc/timer_periph.h b/components/soc/include/soc/timer_periph.h index 883e69f787c..1da11986e7f 100644 --- a/components/soc/include/soc/timer_periph.h +++ b/components/soc/include/soc/timer_periph.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "soc/timer_group_struct.h" #include "soc/soc_caps.h" #include "soc/periph_defs.h" +#include "soc/regdma.h" #ifdef __cplusplus extern "C" { @@ -28,6 +29,15 @@ typedef struct { extern const timer_group_signal_conn_t timer_group_periph_signals; +#if SOC_TIMER_SUPPORT_SLEEP_RETENTION && SOC_PAU_SUPPORTED +typedef struct { + const regdma_entries_config_t *link_list; + uint32_t link_num; +} tg_reg_ctx_link_t; + +extern const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS]; +#endif + #ifdef __cplusplus } #endif From 3785506ec15a664a03f7c5f69d1338a54026e6cc Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 23 May 2024 10:42:30 +0800 Subject: [PATCH 247/548] change(esp_driver_gptimer): do gptimer timer target retention by needs --- .../include/driver/gptimer.h | 3 + components/esp_driver_gptimer/src/gptimer.c | 75 ++++++++++++++++++- .../esp_driver_gptimer/src/gptimer_priv.h | 8 +- components/soc/esp32c5/beta3/timer_periph.c | 39 ++++++++++ components/soc/esp32c5/mp/timer_periph.c | 39 ++++++++++ components/soc/esp32c6/timer_periph.c | 39 ++++++++++ components/soc/esp32h2/timer_periph.c | 39 ++++++++++ components/soc/esp32p4/timer_periph.c | 49 ++++++++++++ components/soc/include/soc/timer_periph.h | 1 + 9 files changed, 288 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_gptimer/include/driver/gptimer.h b/components/esp_driver_gptimer/include/driver/gptimer.h index b9c0b8b14bc..825f93db79a 100644 --- a/components/esp_driver_gptimer/include/driver/gptimer.h +++ b/components/esp_driver_gptimer/include/driver/gptimer.h @@ -28,6 +28,9 @@ typedef struct { if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */ struct { uint32_t intr_shared: 1; /*!< Set true, the timer interrupt number can be shared with other peripherals */ + uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the GPTimer registers before/after entering/exist sleep mode. + By this approach, the system can power off GPTimer's power domain. + This can save power, but at the expense of more RAM being consumed */ } flags; /*!< GPTimer config flags*/ } gptimer_config_t; diff --git a/components/esp_driver_gptimer/src/gptimer.c b/components/esp_driver_gptimer/src/gptimer.c index f1d4af46640..6fd66b9b95a 100644 --- a/components/esp_driver_gptimer/src/gptimer.c +++ b/components/esp_driver_gptimer/src/gptimer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,6 +30,10 @@ #include "esp_clk_tree.h" #include "gptimer_priv.h" +#if GPTIMER_USE_RETENTION_LINK +#include "esp_private/sleep_retention.h" +#endif + static const char *TAG = "gptimer"; #if SOC_PERIPH_CLK_CTRL_SHARED @@ -52,6 +56,37 @@ static void gptimer_release_group_handle(gptimer_group_t *group); static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz); static void gptimer_default_isr(void *args); +#if GPTIMER_USE_RETENTION_LINK +static esp_err_t sleep_tg_timer_retention_link_cb(void *arg) +{ + uint32_t group_id = *(uint32_t *)arg; + esp_err_t err = sleep_retention_entries_create(tg_timer_regs_retention[group_id].link_list, + tg_timer_regs_retention[group_id].link_num, + REGDMA_LINK_PRI_6, + (group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER); + if (err == ESP_OK) { + ESP_LOGD(TAG, "Timer group %ld retention initialization", group_id); + } + ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for timer group %ld", group_id); + return err; +} + +static void gptimer_create_retention_module(gptimer_group_t *group) +{ + _lock_acquire(&s_platform.mutex); + int group_id = group->group_id; + if ((group->sleep_retention_initialized == true) && (group->retention_link_created == false)) { + esp_err_t err = sleep_retention_module_allocate((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for timer group %d retention, power domain can't turn off", group_id); + } else { + group->retention_link_created = true; + } + } + _lock_release(&s_platform.mutex); +} +#endif + static esp_err_t gptimer_register_to_group(gptimer_t *timer) { gptimer_group_t *group = NULL; @@ -129,6 +164,12 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re int group_id = group->group_id; int timer_id = timer->timer_id; +#if GPTIMER_USE_RETENTION_LINK + if (config->flags.backup_before_sleep != 0) { + gptimer_create_retention_module(group); + } +#endif // GPTIMER_USE_RETENTION_LINK + // initialize HAL layer timer_hal_init(&timer->hal, group_id, timer_id); // select clock source, set clock resolution @@ -404,7 +445,6 @@ static gptimer_group_t *gptimer_acquire_group_handle(int group_id) // someone acquired the group handle means we have a new object that refer to this group s_platform.group_ref_counts[group_id]++; } - _lock_release(&s_platform.mutex); if (new_group) { // !!! HARDWARE SHARED RESOURCE !!! @@ -417,7 +457,28 @@ static gptimer_group_t *gptimer_acquire_group_handle(int group_id) } } ESP_LOGD(TAG, "new group (%d) @%p", group_id, group); +#if GPTIMER_USE_RETENTION_LINK + if (group->sleep_retention_initialized != true) { + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = sleep_tg_timer_retention_link_cb, + .arg = &group_id + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM) + }; + esp_err_t err = sleep_retention_module_init((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER, &init_param); + + if (err == ESP_OK) { + group->sleep_retention_initialized = true; + } else { + ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for timer group %d retention", group_id); + } + } +#endif // GPTIMER_USE_RETENTION_LINK } + _lock_release(&s_platform.mutex); return group; } @@ -434,7 +495,6 @@ static void gptimer_release_group_handle(gptimer_group_t *group) do_deinitialize = true; s_platform.groups[group_id] = NULL; } - _lock_release(&s_platform.mutex); if (do_deinitialize) { // disable bus clock for the timer group @@ -443,9 +503,18 @@ static void gptimer_release_group_handle(gptimer_group_t *group) timer_ll_enable_bus_clock(group_id, false); } } +#if GPTIMER_USE_RETENTION_LINK + if (group->retention_link_created) { + sleep_retention_module_free((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER); + } + if (group->sleep_retention_initialized) { + sleep_retention_module_deinit((group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_TIMER : SLEEP_RETENTION_MODULE_TG1_TIMER); + } +#endif free(group); ESP_LOGD(TAG, "del group (%d)", group_id); } + _lock_release(&s_platform.mutex); } static esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz) diff --git a/components/esp_driver_gptimer/src/gptimer_priv.h b/components/esp_driver_gptimer/src/gptimer_priv.h index 78428ce09cb..fe072c85d43 100644 --- a/components/esp_driver_gptimer/src/gptimer_priv.h +++ b/components/esp_driver_gptimer/src/gptimer_priv.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,12 +39,18 @@ extern "C" { #define GPTIMER_PM_LOCK_NAME_LEN_MAX 16 +#define GPTIMER_USE_RETENTION_LINK (SOC_TIMER_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP) + typedef struct gptimer_t gptimer_t; typedef struct gptimer_group_t { int group_id; portMUX_TYPE spinlock; // to protect per-group register level concurrent access gptimer_t *timers[SOC_TIMER_GROUP_TIMERS_PER_GROUP]; +#if GPTIMER_USE_RETENTION_LINK + bool sleep_retention_initialized; // mark if the retention link is initialized + bool retention_link_created; // mark if the retention link is created +#endif } gptimer_group_t; typedef enum { diff --git a/components/soc/esp32c5/beta3/timer_periph.c b/components/soc/esp32c5/beta3/timer_periph.c index 4ab27c7fdf2..7036e7ca81a 100644 --- a/components/soc/esp32c5/beta3/timer_periph.c +++ b/components/soc/esp32c5/beta3/timer_periph.c @@ -46,8 +46,47 @@ static const regdma_entries_config_t tg1_wdt_regs_retention[] = { [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; +/* Registers in retention context: + * TIMG_T0CONFIG_REG + * TIMG_T0ALARMLO_REG + * TIMG_T0ALARMHI_REG + * TIMG_INT_ENA_TIMERS_REG + * TIMG_REGCLK_REG + */ +#define N_REGS_TG_TIMER_CFG 5 +static const uint32_t tg_timer_regs_map[4] = {0x10000031, 0x80000000, 0, 0}; + +const regdma_entries_config_t tg0_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG0_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(0), TIMG_T0CONFIG_REG(0), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x03), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x04), TIMG_T0HI_REG(0), TIMG_T0LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x05), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const regdma_entries_config_t tg1_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG1_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(1), TIMG_T0CONFIG_REG(1), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(1), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x03), TIMG_T0LO_REG(1), TIMG_T0LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x04), TIMG_T0HI_REG(1), TIMG_T0LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x05), TIMG_T0LOAD_REG(1), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, }; + +const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_timer_regs_retention, ARRAY_SIZE(tg0_timer_regs_retention)}, + [1] = {tg1_timer_regs_retention, ARRAY_SIZE(tg1_timer_regs_retention)}, +}; #endif diff --git a/components/soc/esp32c5/mp/timer_periph.c b/components/soc/esp32c5/mp/timer_periph.c index 4ab27c7fdf2..7036e7ca81a 100644 --- a/components/soc/esp32c5/mp/timer_periph.c +++ b/components/soc/esp32c5/mp/timer_periph.c @@ -46,8 +46,47 @@ static const regdma_entries_config_t tg1_wdt_regs_retention[] = { [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; +/* Registers in retention context: + * TIMG_T0CONFIG_REG + * TIMG_T0ALARMLO_REG + * TIMG_T0ALARMHI_REG + * TIMG_INT_ENA_TIMERS_REG + * TIMG_REGCLK_REG + */ +#define N_REGS_TG_TIMER_CFG 5 +static const uint32_t tg_timer_regs_map[4] = {0x10000031, 0x80000000, 0, 0}; + +const regdma_entries_config_t tg0_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG0_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(0), TIMG_T0CONFIG_REG(0), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x03), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x04), TIMG_T0HI_REG(0), TIMG_T0LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x05), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const regdma_entries_config_t tg1_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG1_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(1), TIMG_T0CONFIG_REG(1), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(1), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x03), TIMG_T0LO_REG(1), TIMG_T0LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x04), TIMG_T0HI_REG(1), TIMG_T0LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x05), TIMG_T0LOAD_REG(1), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, }; + +const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_timer_regs_retention, ARRAY_SIZE(tg0_timer_regs_retention)}, + [1] = {tg1_timer_regs_retention, ARRAY_SIZE(tg1_timer_regs_retention)}, +}; #endif diff --git a/components/soc/esp32c6/timer_periph.c b/components/soc/esp32c6/timer_periph.c index 7d338258deb..422b536f37a 100644 --- a/components/soc/esp32c6/timer_periph.c +++ b/components/soc/esp32c6/timer_periph.c @@ -45,7 +45,46 @@ static const regdma_entries_config_t tg1_wdt_regs_retention[] = { [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; +/* Registers in retention context: + * TIMG_T0CONFIG_REG + * TIMG_T0ALARMLO_REG + * TIMG_T0ALARMHI_REG + * TIMG_INT_ENA_TIMERS_REG + * TIMG_REGCLK_REG + */ +#define N_REGS_TG_TIMER_CFG 5 +static const uint32_t tg_timer_regs_map[4] = {0x10000031, 0x80000000, 0, 0}; + +const regdma_entries_config_t tg0_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG0_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(0), TIMG_T0CONFIG_REG(0), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x03), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x04), TIMG_T0HI_REG(0), TIMG_T0LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x05), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const regdma_entries_config_t tg1_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG1_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(1), TIMG_T0CONFIG_REG(1), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(1), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x03), TIMG_T0LO_REG(1), TIMG_T0LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x04), TIMG_T0HI_REG(1), TIMG_T0LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x05), TIMG_T0LOAD_REG(1), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, }; + +const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_timer_regs_retention, ARRAY_SIZE(tg0_timer_regs_retention)}, + [1] = {tg1_timer_regs_retention, ARRAY_SIZE(tg1_timer_regs_retention)}, +}; diff --git a/components/soc/esp32h2/timer_periph.c b/components/soc/esp32h2/timer_periph.c index 7d338258deb..422b536f37a 100644 --- a/components/soc/esp32h2/timer_periph.c +++ b/components/soc/esp32h2/timer_periph.c @@ -45,7 +45,46 @@ static const regdma_entries_config_t tg1_wdt_regs_retention[] = { [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; +/* Registers in retention context: + * TIMG_T0CONFIG_REG + * TIMG_T0ALARMLO_REG + * TIMG_T0ALARMHI_REG + * TIMG_INT_ENA_TIMERS_REG + * TIMG_REGCLK_REG + */ +#define N_REGS_TG_TIMER_CFG 5 +static const uint32_t tg_timer_regs_map[4] = {0x10000031, 0x80000000, 0, 0}; + +const regdma_entries_config_t tg0_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG0_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(0), TIMG_T0CONFIG_REG(0), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x03), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x04), TIMG_T0HI_REG(0), TIMG_T0LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x05), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const regdma_entries_config_t tg1_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG1_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(1), TIMG_T0CONFIG_REG(1), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(1), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x03), TIMG_T0LO_REG(1), TIMG_T0LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x04), TIMG_T0HI_REG(1), TIMG_T0LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x05), TIMG_T0LOAD_REG(1), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, }; + +const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_timer_regs_retention, ARRAY_SIZE(tg0_timer_regs_retention)}, + [1] = {tg1_timer_regs_retention, ARRAY_SIZE(tg1_timer_regs_retention)}, +}; diff --git a/components/soc/esp32p4/timer_periph.c b/components/soc/esp32p4/timer_periph.c index 043ab9764f5..b94dacaefb2 100644 --- a/components/soc/esp32p4/timer_periph.c +++ b/components/soc/esp32p4/timer_periph.c @@ -47,7 +47,56 @@ static const regdma_entries_config_t tg1_wdt_regs_retention[] = { [5] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_TG1_WDT_LINK(0x04), TIMG_WDTWPROTECT_REG(1), 0, TIMG_WDT_WKEY_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, }; +/* Registers in retention context: + * TIMG_T0CONFIG_REG / TIMG_T1CONFIG_REG + * TIMG_T0ALARMLO_REG / TIMG_T1ALARMLO_REG + * TIMG_T0ALARMHI_REG / TIMG_T1ALARMHI_REG + * TIMG_INT_ENA_TIMERS_REG + * TIMG_REGCLK_REG + */ +#define N_REGS_TG_TIMER_CFG 8 +static const uint32_t tg_timer_regs_map[4] = {0x10006231, 0x80000000, 0x0, 0x0}; + +const regdma_entries_config_t tg0_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG0_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(0), TIMG_T0CONFIG_REG(0), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(0), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x02), TIMG_T1UPDATE_REG(0), TIMG_T1_UPDATE, TIMG_T1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x03), TIMG_T0UPDATE_REG(0), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG0_TIMER_LINK(0x04), TIMG_T1UPDATE_REG(0), 0x0, TIMG_T1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x05), TIMG_T0LO_REG(0), TIMG_T0LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x06), TIMG_T0HI_REG(0), TIMG_T0LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x07), TIMG_T1LO_REG(0), TIMG_T1LOADLO_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [8] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG0_TIMER_LINK(0x08), TIMG_T1HI_REG(0), TIMG_T1LOADHI_REG(0), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [9] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x09), TIMG_T0LOAD_REG(0), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [10] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG0_TIMER_LINK(0x0a), TIMG_T1LOAD_REG(0), 0x1, TIMG_T1_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + +const regdma_entries_config_t tg1_timer_regs_retention[] = { + [0] = { + .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_TG1_TIMER_LINK(0x00), TIMG_T0CONFIG_REG(1), TIMG_T0CONFIG_REG(1), N_REGS_TG_TIMER_CFG, 0, 0, \ + tg_timer_regs_map[0], tg_timer_regs_map[1], tg_timer_regs_map[2], tg_timer_regs_map[3]), .owner = ENTRY(0) | ENTRY(2) + }, + [1] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x01), TIMG_T0UPDATE_REG(1), TIMG_T0_UPDATE, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [2] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x02), TIMG_T1UPDATE_REG(1), TIMG_T1_UPDATE, TIMG_T1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [3] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG1_TIMER_LINK(0x03), TIMG_T0UPDATE_REG(1), 0x0, TIMG_T0_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [4] = { .config = REGDMA_LINK_WAIT_INIT(REGDMA_TG1_TIMER_LINK(0x04), TIMG_T1UPDATE_REG(1), 0x0, TIMG_T1_UPDATE_M, 0, 1), .owner = ENTRY(0) | ENTRY(2) }, + [5] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x05), TIMG_T0LO_REG(1), TIMG_T0LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [6] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x06), TIMG_T0HI_REG(1), TIMG_T0LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [7] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x07), TIMG_T1LO_REG(1), TIMG_T1LOADLO_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [8] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_TG1_TIMER_LINK(0x08), TIMG_T1HI_REG(1), TIMG_T1LOADHI_REG(1), 2, 0, 0), .owner = ENTRY(0) | ENTRY(2) }, + [9] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x09), TIMG_T0LOAD_REG(1), 0x1, TIMG_T0_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, + [10] = { .config = REGDMA_LINK_WRITE_INIT(REGDMA_TG1_TIMER_LINK(0x0a), TIMG_T1LOAD_REG(1), 0x1, TIMG_T1_LOAD_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, +}; + const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS] = { [0] = {tg0_wdt_regs_retention, ARRAY_SIZE(tg0_wdt_regs_retention)}, [1] = {tg1_wdt_regs_retention, ARRAY_SIZE(tg1_wdt_regs_retention)}, }; + +const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS] = { + [0] = {tg0_timer_regs_retention, ARRAY_SIZE(tg0_timer_regs_retention)}, + [1] = {tg1_timer_regs_retention, ARRAY_SIZE(tg1_timer_regs_retention)}, +}; diff --git a/components/soc/include/soc/timer_periph.h b/components/soc/include/soc/timer_periph.h index 1da11986e7f..1d7cd219b3c 100644 --- a/components/soc/include/soc/timer_periph.h +++ b/components/soc/include/soc/timer_periph.h @@ -36,6 +36,7 @@ typedef struct { } tg_reg_ctx_link_t; extern const tg_reg_ctx_link_t tg_wdt_regs_retention[SOC_TIMER_GROUPS]; +extern const tg_reg_ctx_link_t tg_timer_regs_retention[SOC_TIMER_GROUPS]; #endif #ifdef __cplusplus From 8093516420dd8ea43aeb3fe52589bacbe94b1bf9 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 10 May 2024 16:47:06 +0800 Subject: [PATCH 248/548] ci(esp_system): add task watchdog pd_top sleep retention test case --- .../main/test_task_wdt.c | 41 ++++++++++++++++++- .../sdkconfig.ci.default | 2 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c index 08fbb40a4f4..c924b5c5bbe 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_task_wdt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -15,6 +15,13 @@ #include "test_utils.h" #include "soc/rtc.h" +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +#include "esp_sleep.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_pmu.h" +#endif + #define TASK_WDT_TIMEOUT_MS 1000 static volatile bool timeout_flag; @@ -41,6 +48,36 @@ TEST_CASE("Task WDT task timeout", "[task_wdt]") TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); } +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +TEST_CASE("Task WDT task timeout after peripheral powerdown lightsleep", "[task_wdt]") +{ + timeout_flag = false; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = TASK_WDT_TIMEOUT_MS, + .idle_core_mask = 0, + .trigger_panic = false, + }; + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_init(&twdt_config)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add(NULL)); + + TEST_ESP_OK(sleep_cpu_configure(true)); + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + esp_sleep_enable_timer_wakeup(10 * 1000); + esp_light_sleep_start(); + + TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); + + // Short delay to allow timeout to occur + esp_rom_delay_us(TASK_WDT_TIMEOUT_MS * 1000); + TEST_ASSERT_EQUAL(true, timeout_flag); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete(NULL)); + TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_deinit()); + TEST_ESP_OK(sleep_cpu_configure(false)); +} +#endif + #if SOC_MWDT_SUPPORT_XTAL #if CONFIG_IDF_TARGET_ESP32H2 @@ -92,7 +129,7 @@ TEST_CASE("Task WDT inactive when no task to watch", "[task_wdt]") TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_add(NULL)); esp_rom_delay_us(TASK_WDT_TIMEOUT_MS * 1000); TEST_ASSERT_EQUAL(true, timeout_flag); - /* Remove the task we just addded and make sure the WDT is stopped*/ + /* Remove the task we just added and make sure the WDT is stopped*/ timeout_flag = false; TEST_ASSERT_EQUAL(ESP_OK, esp_task_wdt_delete(NULL)); esp_rom_delay_us(2 * TASK_WDT_TIMEOUT_MS * 1000); diff --git a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default index 31d50f69086..fcbda27d406 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default +++ b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.default @@ -1,3 +1,5 @@ # Default configuration # Used for testing stack smashing protection CONFIG_COMPILER_STACK_CHECK=y +CONFIG_ESP_SLEEP_DEBUG=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y From d917f0fa1b3d0bf2a7f667d8b122db10798c8682 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 10 May 2024 16:46:27 +0800 Subject: [PATCH 249/548] ci(esp_driver_gptimer): add gptimer pd_top sleep retention test case --- .../test_apps/gptimer/main/test_gptimer.c | 90 ++++++++++++++++++- .../test_apps/gptimer/sdkconfig.ci.release | 3 + 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer.c b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer.c index 04c08ce05e9..4d3e6b49878 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer.c +++ b/components/esp_driver_gptimer/test_apps/gptimer/main/test_gptimer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,15 @@ #include "soc/soc_caps.h" #include "esp_attr.h" +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +#include "esp_random.h" +#include "esp_rom_uart.h" +#include "esp_sleep.h" +#include "esp_private/esp_sleep_internal.h" +#include "esp_private/sleep_cpu.h" +#include "esp_private/esp_pmu.h" +#endif + #if CONFIG_GPTIMER_ISR_IRAM_SAFE #define TEST_ALARM_CALLBACK_ATTR IRAM_ATTR #else @@ -596,3 +605,82 @@ TEST_CASE("gptimer_trig_alarm_with_old_count", "[gptimer]") TEST_ESP_OK(gptimer_disable(timer)); TEST_ESP_OK(gptimer_del_timer(timer)); } + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_TIMER_SUPPORT_SLEEP_RETENTION +static gptimer_handle_t timers[SOC_TIMER_GROUP_TOTAL_TIMERS]; +static uint32_t timer_resolution_hz[SOC_TIMER_GROUP_TOTAL_TIMERS]; + +static void test_gptimer_retention(gptimer_config_t *timer_config) +{ + for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) { + TEST_ESP_OK(gptimer_new_timer(timer_config, &timers[i])); + TEST_ESP_OK(gptimer_get_resolution(timers[i], &timer_resolution_hz[i])); + + unsigned long long count_start_value = 0, count_end_value = 0; + + // Let gptimer run for a while + TEST_ESP_OK(gptimer_enable(timers[i])); + TEST_ESP_OK(gptimer_start(timers[i])); + vTaskDelay((esp_random() % 500) / portTICK_PERIOD_MS); + TEST_ESP_OK(gptimer_stop(timers[i])); + TEST_ESP_OK(gptimer_disable(timers[i])); + TEST_ESP_OK(gptimer_get_raw_count(timers[i], &count_start_value)); + + esp_sleep_context_t sleep_ctx; + esp_sleep_set_sleep_context(&sleep_ctx); + TEST_ESP_OK(sleep_cpu_configure(true)); + esp_rom_output_tx_wait_idle(0); + esp_sleep_enable_timer_wakeup(50 * 1000); + esp_light_sleep_start(); + + if (timer_config->flags.backup_before_sleep) { + TEST_ASSERT_EQUAL(PMU_SLEEP_PD_TOP, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); + } else { + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP); + } + + TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result); + + TEST_ESP_OK(gptimer_enable(timers[i])); + TEST_ESP_OK(gptimer_start(timers[i])); + + uint32_t random_time_ms = 500 + esp_random() % 2000; + vTaskDelay(random_time_ms / portTICK_PERIOD_MS); + TEST_ESP_OK(gptimer_get_raw_count(timers[i], &count_end_value)); + + // Error tolerance is 2% + TEST_ASSERT_UINT_WITHIN(random_time_ms / 50, random_time_ms, 1000 * (count_end_value - count_start_value) / (unsigned long long)timer_resolution_hz[i]); + + TEST_ESP_OK(gptimer_stop(timers[i])); + TEST_ESP_OK(gptimer_disable(timers[i])); + TEST_ESP_OK(gptimer_del_timer(timers[i])); + TEST_ESP_OK(sleep_cpu_configure(false)); + } +} + +TEST_CASE("gptimer context kept after peripheral powerdown lightsleep with backup_before_sleep enable", "[gptimer]") +{ + printf("install gptimer driver\r\n"); + gptimer_config_t timer_config = { + .resolution_hz = 10 * 1000, // 10KHz, 1 tick = 0.1ms + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .flags.backup_before_sleep = true + }; + + test_gptimer_retention(&timer_config); +} + +TEST_CASE("gptimer context kept after peripheral powerdown lightsleep with backup_before_sleep disable", "[gptimer]") +{ + printf("install gptimer driver\r\n"); + gptimer_config_t timer_config = { + .resolution_hz = 10 * 1000, // 10KHz, 1 tick = 0.1ms + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .flags.backup_before_sleep = false + }; + + test_gptimer_retention(&timer_config); +} +#endif diff --git a/components/esp_driver_gptimer/test_apps/gptimer/sdkconfig.ci.release b/components/esp_driver_gptimer/test_apps/gptimer/sdkconfig.ci.release index 199b0cf97c3..05634936f48 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/sdkconfig.ci.release +++ b/components/esp_driver_gptimer/test_apps/gptimer/sdkconfig.ci.release @@ -4,3 +4,6 @@ CONFIG_PM_DFS_INIT_AUTO=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y +# For TASK WDT timer PD_TOP sleep retention test +CONFIG_ESP_SLEEP_DEBUG=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y From a6414289416481084f4eab12fd311c8db6ef72eb Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 10 May 2024 21:12:45 +0800 Subject: [PATCH 250/548] fix(ci): use esp_rom_crc32_le in sleep retention frame check --- .../lowpower/cpu_retention/port/esp32c3/sleep_cpu.c | 1 - .../lowpower/cpu_retention/port/esp32c5/sleep_cpu.c | 6 +++--- .../lowpower/cpu_retention/port/esp32c6/sleep_cpu.c | 6 +++--- .../lowpower/cpu_retention/port/esp32h2/sleep_cpu.c | 6 +++--- .../lowpower/cpu_retention/port/esp32p4/sleep_cpu.c | 6 +++--- .../lowpower/cpu_retention/port/esp32s3/sleep_cpu.c | 1 - 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c index 9fdd1d3a768..ebc050fa6f1 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c3/sleep_cpu.c @@ -14,7 +14,6 @@ #include "esp_check.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c index fbb67fd0895..2ed461d2801 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c @@ -14,7 +14,7 @@ #include "esp_check.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" +#include "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" @@ -391,12 +391,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); + *(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size); } static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ + if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts for (int i = 0; i < SOC_UART_NUM; ++i) { if (!uart_ll_is_enabled(i)) { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c index e97de1c0ebe..8d0b0a2bc76 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c @@ -14,7 +14,7 @@ #include "esp_check.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" +#include "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" @@ -431,12 +431,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); + *(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size); } static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ + if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts for (int i = 0; i < SOC_UART_NUM; ++i) { if (!uart_ll_is_enabled(i)) { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c index b30913b2331..c0202477100 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c @@ -15,7 +15,7 @@ #include "esp_check.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" +#include "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" @@ -431,12 +431,12 @@ static IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame_t * #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME static IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); + *(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size); } static IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ + if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts for (int i = 0; i < SOC_UART_NUM; ++i) { if (!uart_ll_is_enabled(i)) { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index e7ea617a9da..68f469a66e8 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -15,7 +15,7 @@ #include "esp_ipc_isr.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" +#include "esp_rom_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" @@ -374,12 +374,12 @@ static TCM_IRAM_ATTR void cpu_domain_dev_regs_restore(cpu_domain_dev_sleep_frame #if CONFIG_PM_CHECK_SLEEP_RETENTION_FRAME static TCM_IRAM_ATTR void update_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - *(frame_crc_ptr) = esp_crc32_le(0, (void *)frame_ptr, frame_check_size); + *(frame_crc_ptr) = esp_rom_crc32_le(0, (void *)frame_ptr, frame_check_size); } static TCM_IRAM_ATTR void validate_retention_frame_crc(uint32_t *frame_ptr, uint32_t frame_check_size, uint32_t *frame_crc_ptr) { - if(*(frame_crc_ptr) != esp_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ + if(*(frame_crc_ptr) != esp_rom_crc32_le(0, (void *)(frame_ptr), frame_check_size)){ // resume uarts for (int i = 0; i < SOC_UART_NUM; ++i) { if (!uart_ll_is_enabled(i)) { diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c index 2e16de3c677..cba8f6ee308 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32s3/sleep_cpu.c @@ -15,7 +15,6 @@ #include "esp_ipc_isr.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp_crc.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_heap_caps.h" From a27aa02fa3f608501735c56115d04abc380c0a07 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Sat, 11 May 2024 19:29:25 +0800 Subject: [PATCH 251/548] fix(esp_hw_support): use iterator for regdma_link_stats to save stack consume Closes https://github.com/espressif/esp-idf/issues/13288 --- components/esp_hw_support/port/regdma_link.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/port/regdma_link.c b/components/esp_hw_support/port/regdma_link.c index d2f0c908cfc..14a766c8d84 100644 --- a/components/esp_hw_support/port/regdma_link.c +++ b/components/esp_hw_support/port/regdma_link.c @@ -445,9 +445,22 @@ static void regdma_link_update_stats_wrapper(void *link, int entry, int depth) regdma_link_update_stats(regdma_link_get_stats(link), entry, depth); } +static void regdma_link_iterator(void *link, int entry, void (*hook)(void *, int, int)) +{ + assert(entry < REGDMA_LINK_ENTRY_NUM); + + int iter = 0; + while (link) { + if (hook) { + (*hook)(link, entry, iter++); + } + link = regdma_link_get_next(link, entry); + } +} + void regdma_link_stats(void *link, int entry) { - regdma_link_recursive_impl(link, entry, 0, regdma_link_update_stats_wrapper); + regdma_link_iterator(link, entry, regdma_link_update_stats_wrapper); } static void regdma_link_destroy_wrapper(void *link, int entry, int depth) From 26cb10acbf322373d080760a2981171382a35ad2 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Sat, 11 May 2024 16:50:29 +0800 Subject: [PATCH 252/548] feat(esp_hw_support): optimize retention link info dump --- .../include/esp_private/esp_regdma.h | 2 - components/esp_hw_support/port/regdma_link.c | 68 ++++++++++++------- components/esp_hw_support/sleep_retention.c | 2 - 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_regdma.h b/components/esp_hw_support/include/esp_private/esp_regdma.h index 57f2ccc487b..03b551d64bb 100644 --- a/components/esp_hw_support/include/esp_private/esp_regdma.h +++ b/components/esp_hw_support/include/esp_private/esp_regdma.h @@ -22,8 +22,6 @@ extern "C" { #if SOC_PAU_SUPPORTED #include "hal/pau_types.h" -#define REGDMA_LINK_DBG 0 /* Enable REGDMA link info dump apis*/ - /** * @brief Create a REGDMA continuous type linked list node without retention buffer and the retention buffer is passed in by the caller * @param backup Register address to be backed up by REGDMA diff --git a/components/esp_hw_support/port/regdma_link.c b/components/esp_hw_support/port/regdma_link.c index 14a766c8d84..0af808ae323 100644 --- a/components/esp_hw_support/port/regdma_link.c +++ b/components/esp_hw_support/port/regdma_link.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #include #include #include +#include #include "esp_private/regdma_link.h" @@ -713,13 +714,17 @@ void * regdma_find_prev_module_link_tail(void *link, void *tail, int entry, uint return NULL; } -#if REGDMA_LINK_DBG static __attribute__((unused)) const char *TAG = "regdma_link"; +static const char* s_link_mode_str[] = { "CONTINUOUS", "ADDR_MAP", "WRITE", "WAIT" }; +static const char* s_boolean_str[] = { "false", "true" }; static void print_info_link_data(FILE *out, const uint32_t buf[], int len) { for (int i = 0; i < len; i++) { - fprintf(out, ((i + 1) % 8) ? "%08lx " : "%08lx\n", buf[i]); + if (i % 8 == 0) { + fprintf(out, "\t\t"); + } + fprintf(out, ((i + 1) % 8) ? "%08"PRIx32" " : "%08"PRIx32"\n", buf[i]); } if (len % 8) { fprintf(out, "\n"); @@ -730,9 +735,13 @@ static void print_info_continuous_wrapper(FILE *out, void *link) { regdma_link_head_t head = REGDMA_LINK_HEAD(link); regdma_link_continuous_t *cons = __containerof(link, regdma_link_continuous_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, restore:%p, buff:%p\n", - cons->stat.module, cons->stat.id, link, *(uint32_t *)&cons->head, cons->body.next, - cons->body.backup, cons->body.restore, cons->body.mem); + assert((cons->stat.module & (cons->stat.module - 1)) == 0); + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, restore start:%p, buff_ptr:%p\n" LOG_RESET_COLOR, + __builtin_ffs(cons->stat.module) - 1, cons->stat.id, link, + s_link_mode_str[cons->head.mode], cons->head.length, s_boolean_str[cons->head.branch], s_boolean_str[cons->head.skip_r], s_boolean_str[cons->head.skip_b], s_boolean_str[cons->head.eof], + cons->body.next, + cons->body.backup, cons->body.restore, + cons->body.mem); print_info_link_data(out, (const uint32_t *)cons->body.mem, head.length); } @@ -740,18 +749,23 @@ static void print_info_addr_map_wrapper(FILE *out, void *link) { regdma_link_head_t head = REGDMA_LINK_HEAD(link); regdma_link_addr_map_t *map = __containerof(link, regdma_link_addr_map_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, restore:%p, buff:%p, map:{%lx,%lx,%lx,%lx}\n", - map->stat.module, map->stat.id, link, *(uint32_t *)&map->head, map->body.next, map->body.backup, - map->body.restore, map->body.mem, map->body.map[0], map->body.map[1], - map->body.map[2], map->body.map[3]); + assert((map->stat.module & (map->stat.module - 1)) == 0); + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, restore start:%p, buff_ptr:%p, map:{%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32"}\n" LOG_RESET_COLOR, + __builtin_ffs(map->stat.module) - 1, map->stat.id, link, + s_link_mode_str[map->head.mode], map->head.length, s_boolean_str[map->head.branch], s_boolean_str[map->head.skip_r], s_boolean_str[map->head.skip_b], s_boolean_str[map->head.eof], + map->body.next, + map->body.backup, map->body.restore, + map->body.mem, map->body.map[0], map->body.map[1], map->body.map[2], map->body.map[3]); print_info_link_data(out, (const uint32_t *)map->body.mem, head.length); } static void print_info_write_wait_wrapper(FILE *out, void *link) { regdma_link_write_wait_t *ww = __containerof(link, regdma_link_write_wait_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:%p, backup:%p, value:%lx, mask:%lx\n", - ww->stat.module, ww->stat.id, link, *(uint32_t *)&ww->head, ww->body.next, + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, value:%"PRIx32", mask:%"PRIx32"\n" LOG_RESET_COLOR, + __builtin_ffs(ww->stat.module) - 1, ww->stat.id, link, + s_link_mode_str[ww->head.mode], ww->head.length, s_boolean_str[ww->head.branch], s_boolean_str[ww->head.skip_r], s_boolean_str[ww->head.skip_b], s_boolean_str[ww->head.eof], + ww->body.next, ww->body.backup, ww->body.value, ww->body.mask); } @@ -759,9 +773,12 @@ static void print_info_branch_continuous_wrapper(FILE *out, void *link) { regdma_link_head_t head = REGDMA_LINK_HEAD(link); regdma_link_branch_continuous_t *cons = __containerof(link, regdma_link_branch_continuous_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, restore:%p, buff:%p\n", - cons->stat.module, cons->stat.id, link, *(uint32_t *)&cons->head, cons->body.next[0], cons->body.next[1], - cons->body.next[2], cons->body.next[3], cons->body.backup, cons->body.restore, + assert((cons->stat.module & (cons->stat.module - 1)) == 0); + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, restore start:%p, buff_ptr:%p\n" LOG_RESET_COLOR, + __builtin_ffs(cons->stat.module) - 1, cons->stat.id, link, + s_link_mode_str[cons->head.mode], cons->head.length, s_boolean_str[cons->head.branch], s_boolean_str[cons->head.skip_r], s_boolean_str[cons->head.skip_b], s_boolean_str[cons->head.eof], + cons->body.next, + cons->body.backup, cons->body.restore, cons->body.mem); print_info_link_data(out, (const uint32_t *)cons->body.mem, head.length); } @@ -770,20 +787,24 @@ static void print_info_branch_addr_map_wrapper(FILE *out, void *link) { regdma_link_head_t head = REGDMA_LINK_HEAD(link); regdma_link_branch_addr_map_t *map = __containerof(link, regdma_link_branch_addr_map_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, restore:%p, buff:%p, map:{%lx,%lx,%lx,%lx}\n", - map->stat.module, map->stat.id, link, *(uint32_t *)&map->head, map->body.next[0], map->body.next[1], map->body.next[2], - map->body.next[3], map->body.backup, map->body.restore, map->body.mem, map->body.map[0], - map->body.map[1], map->body.map[2], map->body.map[3]); + assert((map->stat.module & (map->stat.module - 1)) == 0); + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, restore start:%p, buff_ptr:%p, map:{%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32"}\n" LOG_RESET_COLOR, + __builtin_ffs(map->stat.module) - 1, map->stat.id, link, + s_link_mode_str[map->head.mode], map->head.length, s_boolean_str[map->head.branch], s_boolean_str[map->head.skip_r], s_boolean_str[map->head.skip_b], s_boolean_str[map->head.eof], + map->body.next, + map->body.backup, map->body.restore, + map->body.mem, map->body.map[0], map->body.map[1], map->body.map[2], map->body.map[3]); print_info_link_data(out, (const uint32_t *)map->body.mem, head.length); } static void print_info_branch_write_wait_wrapper(FILE *out, void *link) { regdma_link_branch_write_wait_t *ww = __containerof(link, regdma_link_branch_write_wait_t, head); - fprintf(out, "[%08lx/%04x] link:%p, head:%lx, next:{%p,%p,%p,%p}, backup:%p, value:%lx, mask:%lx\n", - ww->stat.module, ww->stat.id, link, *(uint32_t *)&ww->head, ww->body.next[0], ww->body.next[1], - ww->body.next[2], ww->body.next[3], ww->body.backup, ww->body.value, - ww->body.mask); + fprintf(out, LOG_COLOR_I " [%02d/%04x] link_ptr:%p, head: {mode:%s len:%d branch:%s skip_r:%s skip_b:%s eof:%s}, next:%p, backup start:%p, value:%"PRIx32", mask:%"PRIx32"\n" LOG_RESET_COLOR, + __builtin_ffs(ww->stat.module) - 1, ww->stat.id, link, + s_link_mode_str[ww->head.mode], ww->head.length, s_boolean_str[ww->head.branch], s_boolean_str[ww->head.skip_r], s_boolean_str[ww->head.skip_b], s_boolean_str[ww->head.eof], + ww->body.next, + ww->body.backup, ww->body.value, ww->body.mask); } static void print_link_info(FILE *out, void *args, int entry, int depth) @@ -821,4 +842,3 @@ void regdma_link_dump(FILE *out, void *link, int entry) fprintf(out, "This REGDMA linked list is empty!\n"); } } -#endif diff --git a/components/esp_hw_support/sleep_retention.c b/components/esp_hw_support/sleep_retention.c index c7b88c648ac..8f7a73bf691 100644 --- a/components/esp_hw_support/sleep_retention.c +++ b/components/esp_hw_support/sleep_retention.c @@ -303,7 +303,6 @@ static void sleep_retention_entries_stats(void) _lock_release_recursive(&s_retention.lock); } -#if REGDMA_LINK_DBG void sleep_retention_dump_entries(FILE *out) { _lock_acquire_recursive(&s_retention.lock); @@ -315,7 +314,6 @@ void sleep_retention_dump_entries(FILE *out) } _lock_release_recursive(&s_retention.lock); } -#endif void * sleep_retention_find_link_by_id(int id) { From 1854036f92faeba354572834f7f3af81bb18391a Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 22 May 2024 12:01:16 +0800 Subject: [PATCH 253/548] change(esp_hw_support): use union retention link priority definiation --- components/driver/i2c/i2c.c | 2 +- components/esp_driver_i2c/i2c_common.c | 2 +- components/esp_hw_support/sleep_system_peripheral.c | 4 ++-- components/esp_system/int_wdt.c | 2 +- .../esp_system/task_wdt/task_wdt_impl_timergroup.c | 2 +- components/soc/include/soc/regdma.h | 9 ++++++--- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/components/driver/i2c/i2c.c b/components/driver/i2c/i2c.c index 591177dda89..eb315a4ec49 100644 --- a/components/driver/i2c/i2c.c +++ b/components/driver/i2c/i2c.c @@ -280,7 +280,7 @@ static void i2c_hw_enable(i2c_port_t i2c_num) static esp_err_t i2c_sleep_retention_init(void *arg) { i2c_port_t i2c_num = *(i2c_port_t *)arg; - esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[i2c_num].link_list, i2c_regs_retention[i2c_num].link_num, REGDMA_LINK_PRI_7, I2C_SLEEP_RETENTION_MODULE(i2c_num)); + esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[i2c_num].link_list, i2c_regs_retention[i2c_num].link_num, REGDMA_LINK_PRI_I2C, I2C_SLEEP_RETENTION_MODULE(i2c_num)); ESP_RETURN_ON_ERROR(ret, I2C_TAG, "failed to allocate mem for sleep retention"); return ret; } diff --git a/components/esp_driver_i2c/i2c_common.c b/components/esp_driver_i2c/i2c_common.c index f0daf1a3b8c..8c3f86952e0 100644 --- a/components/esp_driver_i2c/i2c_common.c +++ b/components/esp_driver_i2c/i2c_common.c @@ -52,7 +52,7 @@ static esp_err_t s_i2c_sleep_retention_init(void *arg) { i2c_bus_t *bus = (i2c_bus_t *)arg; i2c_port_num_t port_num = bus->port_num; - esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[port_num].link_list, i2c_regs_retention[port_num].link_num, REGDMA_LINK_PRI_7, I2C_SLEEP_RETENTION_MODULE(port_num)); + esp_err_t ret = sleep_retention_entries_create(i2c_regs_retention[port_num].link_list, i2c_regs_retention[port_num].link_num, REGDMA_LINK_PRI_I2C, I2C_SLEEP_RETENTION_MODULE(port_num)); ESP_RETURN_ON_ERROR(ret, TAG, "failed to allocate mem for sleep retention"); return ret; } diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 531f3dd6706..cd36fe7f527 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -84,7 +84,7 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_systimer_retention_ini #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE esp_err_t sleep_sys_periph_l2_cache_retention_init(void) { - esp_err_t err = sleep_retention_entries_create(l2_cache_regs_retention, ARRAY_SIZE(l2_cache_regs_retention), REGDMA_LINK_PRI_5, SLEEP_RETENTION_MODULE_SYS_PERIPH); + esp_err_t err = sleep_retention_entries_create(l2_cache_regs_retention, ARRAY_SIZE(l2_cache_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_HIGH, SLEEP_RETENTION_MODULE_SYS_PERIPH); ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (L2 Cache) retention"); ESP_LOGI(TAG, "L2 Cache sleep retention initialization"); return ESP_OK; @@ -94,7 +94,7 @@ esp_err_t sleep_sys_periph_l2_cache_retention_init(void) #if SOC_PAU_IN_TOP_DOMAIN esp_err_t sleep_pau_retention_init(void) { - esp_err_t err = sleep_retention_entries_create(pau_regs_retention, ARRAY_SIZE(pau_regs_retention), REGDMA_LINK_PRI_7, SLEEP_RETENTION_MODULE_SYS_PERIPH); + esp_err_t err = sleep_retention_entries_create(pau_regs_retention, ARRAY_SIZE(pau_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_LOW, SLEEP_RETENTION_MODULE_SYS_PERIPH); ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for system (PAU) retention"); ESP_LOGI(TAG, "PAU sleep retention initialization"); return ESP_OK; diff --git a/components/esp_system/int_wdt.c b/components/esp_system/int_wdt.c index 68d031d5337..9a8db626f3b 100644 --- a/components/esp_system/int_wdt.c +++ b/components/esp_system/int_wdt.c @@ -59,7 +59,7 @@ static esp_err_t sleep_int_wdt_retention_init(void *arg) uint32_t group_id = *(uint32_t *)arg; esp_err_t err = sleep_retention_entries_create(tg_wdt_regs_retention[group_id].link_list, tg_wdt_regs_retention[group_id].link_num, - REGDMA_LINK_PRI_6, + REGDMA_LINK_PRI_SYS_PERIPH_LOW, (group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); if (err == ESP_OK) { ESP_LOGD(TAG, "Interrupt watchdog timer retention initialization"); diff --git a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c index 533a4f24616..8b8ed631805 100644 --- a/components/esp_system/task_wdt/task_wdt_impl_timergroup.c +++ b/components/esp_system/task_wdt/task_wdt_impl_timergroup.c @@ -52,7 +52,7 @@ static esp_err_t sleep_task_wdt_retention_init(void *arg) uint32_t group_id = *(uint32_t *)arg; esp_err_t err = sleep_retention_entries_create(tg_wdt_regs_retention[group_id].link_list, tg_wdt_regs_retention[group_id].link_num, - REGDMA_LINK_PRI_6, + REGDMA_LINK_PRI_SYS_PERIPH_LOW, (group_id == 0) ? SLEEP_RETENTION_MODULE_TG0_WDT : SLEEP_RETENTION_MODULE_TG1_WDT); if (err == ESP_OK) { ESP_LOGD(TAG, "Task watchdog timer retention initialization"); diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index 2243d1113ad..b6fd9ff00e8 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -60,9 +60,12 @@ extern "C" { #define REGDMA_LINK_PRI_BT_MAC_BB REGDMA_LINK_PRI_5 #define REGDMA_LINK_PRI_SYS_PERIPH_HIGH REGDMA_LINK_PRI_5 // INT_MTX & HP_SYSTEM & Console UART #define REGDMA_LINK_PRI_SYS_PERIPH_LOW REGDMA_LINK_PRI_6 // TG0 & IO MUX & SPI MEM & Systimer -#define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_7 -#define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_7 -#define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_7 +#define REGDMA_LINK_PRI_GENERAL_PERIPH REGDMA_LINK_PRI_7 // Low retenion priority for general peripherals +#define REGDMA_LINK_PRI_IEEE802154 REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_GDMA REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH typedef enum { REGDMA_LINK_PRI_0 = 0, From 2ab144dc3a51010fc3cd741570e9c6b0715b9a4f Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 23 May 2024 20:07:56 +0800 Subject: [PATCH 254/548] fix(esp_hw_support): set pau entry backup configuration with link update --- components/esp_hw_support/port/esp32p4/pmu_sleep.c | 13 ------------- components/hal/esp32p4/pau_hal.c | 4 ++++ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index a2a55cf83be..3b0487157cf 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -247,19 +247,6 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) } pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); - - // When light sleep (PD_TOP), the PAU will power down. so need use LP_SYS_BACKUP_DMA_CFG2_REG to store recover link address. - if (!dslp && PMU.hp_sys[PMU_MODE_HP_SLEEP].dig_power.top_pd_en) { - if (PMU.hp_sys[PMU_MODE_HP_SLEEP].backup.hp_active2sleep_backup_en || - PMU.hp_sys[PMU_MODE_HP_ACTIVE].backup.hp_sleep2active_backup_en) { - uint32_t link_sel = PMU.hp_sys[PMU_MODE_HP_SLEEP].backup.hp_active2sleep_backup_mode & 0x3; - uint32_t link_addr = REG_READ(PAU_REGDMA_LINK_0_ADDR_REG + link_sel * 4); - lp_sys_ll_set_pau_link_addr(link_addr); - pmu_sleep_enable_regdma_backup(); - } - } else { - pmu_sleep_disable_regdma_backup(); - } } void pmu_sleep_increase_ldo_volt(void) { diff --git a/components/hal/esp32p4/pau_hal.c b/components/hal/esp32p4/pau_hal.c index 38b98ba4e1e..2852d99a925 100644 --- a/components/hal/esp32p4/pau_hal.c +++ b/components/hal/esp32p4/pau_hal.c @@ -20,6 +20,10 @@ void pau_hal_set_regdma_entry_link_addr(pau_hal_context_t *hal, pau_regdma_link_ pau_ll_set_regdma_link2_addr(hal->dev, (*link_addr)[2]); /* The link 3 of REGDMA is reserved, PMU state switching will not use * REGDMA link 3 */ + + // When light sleep (PD_TOP), the PAU will power down. so need use LP_SYS_BACKUP_DMA_CFG2_REG + // to store recover link address. We always use link0 as the default retention entry. + lp_sys_ll_set_pau_link_addr((uint32_t)(*link_addr)[0]); } void IRAM_ATTR pau_hal_start_regdma_modem_link(pau_hal_context_t *hal, bool backup_or_restore) From f6348050e47af141668248bff00d86b0ab3f97b4 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Wed, 5 Jun 2024 11:59:32 +0800 Subject: [PATCH 255/548] fix(ble/controller): Update esp32 bt-lib (1e63e23) - Optimized GATT write and notify throughput on ESP32 - Fixed BLE connect timeout after using DTM on ESP32 - Added ke memory debug tools on ESP32 - Fixed memory leak issue when BLE SCAN and other event coexist on ESP32 --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 994490e4b0e..0d0fe281326 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 994490e4b0edca038456324a532ebe63f7fc19ef +Subproject commit 0d0fe2813269f91576a75d79385c752fb8cf1922 From 171e0a21a14d6f9fb928787621ef4f49eafdb8b7 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 13 Jun 2024 16:19:32 +0800 Subject: [PATCH 256/548] fix(rom): fixed esprv_int_set_threshold on C5 --- components/esp_rom/CMakeLists.txt | 2 +- .../esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in | 4 ++++ components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h | 1 + .../esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld | 1 - components/esp_rom/patches/esp_rom_clic.c | 11 ++++++++++- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 859ebcd58a6..ff207fad6f3 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -69,7 +69,7 @@ if(CONFIG_HAL_WDT_USE_ROM_IMPL) list(APPEND sources "patches/esp_rom_wdt.c") endif() -if(CONFIG_ESP_ROM_CLIC_INT_TYPE_PATCH) +if(CONFIG_ESP_ROM_CLIC_INT_TYPE_PATCH OR CONFIG_ESP_ROM_CLIC_INT_THRESH_PATCH) list(APPEND sources "patches/esp_rom_clic.c") endif() diff --git a/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in b/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in index 11efd8b841b..d162a71b746 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in @@ -82,3 +82,7 @@ config ESP_ROM_HAS_VERSION config ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB bool default y + +config ESP_ROM_CLIC_INT_THRESH_PATCH + bool + default y diff --git a/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h b/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h index 76b76bc17ba..e1286bac1a9 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h +++ b/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h @@ -28,3 +28,4 @@ #define ESP_ROM_RAM_APP_NEEDS_MMU_INIT (1) // ROM doesn't init cache MMU when it's a RAM APP, needs MMU hal to init #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB (1) // ROM supports the HP core to jump to the RTC memory to execute stub code after waking up from deepsleep. +#define ESP_ROM_CLIC_INT_THRESH_PATCH (1) // ROM version of esprv_intc_int_set_threshold incorrectly assumes lowest MINTTHRESH is 0x1F, should be 0xF diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld index 3f5b833a297..8724419cc62 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld @@ -276,7 +276,6 @@ gpio_pad_hold = 0x40000740; /* Functions */ esprv_intc_int_set_priority = 0x40000744; -esprv_intc_int_set_threshold = 0x40000748; esprv_intc_int_enable = 0x4000074c; esprv_intc_int_disable = 0x40000750; esprv_intc_int_set_type = 0x40000754; diff --git a/components/esp_rom/patches/esp_rom_clic.c b/components/esp_rom/patches/esp_rom_clic.c index d4643e3ef5f..7160931c660 100644 --- a/components/esp_rom/patches/esp_rom_clic.c +++ b/components/esp_rom/patches/esp_rom_clic.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include "esp_rom_caps.h" #include "soc/clic_reg.h" #include "riscv/interrupt.h" +#include "riscv/rv_utils.h" #if ESP_ROM_CLIC_INT_TYPE_PATCH @@ -20,3 +21,11 @@ void esprv_int_set_type(int rv_int_num, enum intr_type type) REG_SET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_TRIG, type); } #endif + +#if ESP_ROM_CLIC_INT_THRESH_PATCH +void esprv_int_set_threshold(int priority_threshold) +{ + /* ROM functions assume minimum MINTTHRESH is 0x1F, but it is actually 0xF */ + rv_utils_set_intlevel(priority_threshold); +} +#endif //ESP_ROM_CLIC_INT_THRESH_PATCH From aaf371027dcacce2be9d98d37959199038035e92 Mon Sep 17 00:00:00 2001 From: linruihao Date: Wed, 12 Jun 2024 18:11:23 +0800 Subject: [PATCH 257/548] fix(bt/controller): Fixed assert issue caused by DPORT access --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 0d0fe281326..a4d7731a95d 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 0d0fe2813269f91576a75d79385c752fb8cf1922 +Subproject commit a4d7731a95db8a6cfb98e5068b6757c32ecfaa2a From f1989b0dc1a2e2c9b095ec3ef4775db7d40e5a61 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Thu, 13 Jun 2024 10:24:04 +0200 Subject: [PATCH 258/548] docs(esp_eth): enabled Configure MAC and PHY section for P4 --- docs/zh_CN/api-reference/network/esp_eth.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/zh_CN/api-reference/network/esp_eth.rst b/docs/zh_CN/api-reference/network/esp_eth.rst index e7d181949ef..1ed9aca6a73 100644 --- a/docs/zh_CN/api-reference/network/esp_eth.rst +++ b/docs/zh_CN/api-reference/network/esp_eth.rst @@ -116,9 +116,7 @@ 以太网驱动器由两部分组成:MAC 和 PHY。 -.. TODO remove esp32p4 (IDF-9057) - -.. only:: SOC_EMAC_SUPPORTED and not esp32p4 +.. only:: SOC_EMAC_SUPPORTED MAC 和 PHY 之间的通信可以通过多种方式进行,如: **MII** (媒体独立接口)、 **RMII** (简化媒体独立接口)等。 From a3a9624ca2d3eb216285ef28af0d3800476837b6 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 12 Jun 2024 22:17:58 +0800 Subject: [PATCH 259/548] fix(esp_wifi): fix the issue of tbtt interrupt miss caused by beacon monitor --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 70c2d7f46d6..fda241ceff8 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 70c2d7f46d65a1b7904ce968e6b63a51acfc0745 +Subproject commit fda241ceff83a34609c9fc132d3e19916969f2c8 From ce145a2c92af8705d9517a46712e3cec499f4733 Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Fri, 31 May 2024 18:03:28 +0800 Subject: [PATCH 260/548] fix(wifi):esp32c6 update ld --- .../esp_rom/esp32c6/ld/esp32c6.rom.net80211.ld | 4 ++-- components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld | 12 ++++++------ examples/mesh/ip_internal_network/sdkconfig.defaults | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.net80211.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.net80211.ld index 7a73b4d5a7d..56761322bdc 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.net80211.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.net80211.ld @@ -37,7 +37,7 @@ ieee80211_ampdu_start_age_timer = 0x40000b84; ieee80211_is_tx_allowed = 0x40000b8c; ieee80211_output_pending_eb = 0x40000b90; /*ieee80211_output_process = 0x40000b94;*/ -ieee80211_set_tx_desc = 0x40000b98; +//ieee80211_set_tx_desc = 0x40000b98; //sta_input = 0x40000b9c; wifi_get_macaddr = 0x40000ba0; wifi_rf_phy_disable = 0x40000ba4; @@ -52,7 +52,7 @@ ieee80211_crypto_encap = 0x40000bc0; ieee80211_decap = 0x40000bc8; wifi_is_started = 0x40000bcc; ieee80211_gettid = 0x40000bd0; -ieee80211_encap_esfbuf_htc = 0x40000bd4; +//ieee80211_encap_esfbuf_htc = 0x40000bd4; /* Data (.data, .bss, .rodata) */ net80211_funcs = 0x4087ffac; g_scan = 0x4087ffa8; diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld index ce7c53ed882..30dedb924c6 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -51,7 +51,7 @@ lmacRecycleMPDU = 0x40000c4c; lmacRxDone = 0x40000c50; //lmacSetTxFrame = 0x40000c54; //lmacTxDone = 0x40000c58; -lmacTxFrame = 0x40000c5c; +//lmacTxFrame = 0x40000c5c; mac_tx_set_duration = 0x40000c60; //mac_tx_set_plcp0 = 0x40000c64; //mac_tx_set_plcp1 = 0x40000c68; @@ -173,8 +173,8 @@ pm_allow_tx = 0x40000e30; ppProcTxCallback = 0x40000e38; //mac_tx_set_hesig = 0x40000e3c; ppCalPreFecPaddingFactor = 0x40000e40; -mac_tx_set_tb = 0x40000e44; -mac_tx_set_mplen = 0x40000e48; +//mac_tx_set_tb = 0x40000e44; +//mac_tx_set_mplen = 0x40000e48; hal_get_tsf_timer = 0x40000e4c; ppTxPktForceWaked = 0x40000e50; lmacProcessLongFrameSuccess = 0x40000e54; @@ -187,8 +187,8 @@ lmacProcessAckTimeout = 0x40000e68; //ppRemoveHTC = 0x40000e70; get_estimated_batime = 0x40000e74; is_use_muedca = 0x40000e78; -hal_mac_tx_clr_mplen = 0x40000e7c; -hal_mac_get_txq_state = 0x40000e80; +//hal_mac_tx_clr_mplen = 0x40000e7c; +//hal_mac_get_txq_state = 0x40000e80; hal_mac_clr_txq_state = 0x40000e84; hal_mac_get_txq_complete = 0x40000e88; ht_get_min_subframe_len = 0x40000e8c; diff --git a/examples/mesh/ip_internal_network/sdkconfig.defaults b/examples/mesh/ip_internal_network/sdkconfig.defaults index 95bb5df8328..81c7be5f664 100644 --- a/examples/mesh/ip_internal_network/sdkconfig.defaults +++ b/examples/mesh/ip_internal_network/sdkconfig.defaults @@ -9,3 +9,4 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_MD5=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y From 5869850af27ce2dd376cc8212f43668a965b88fe Mon Sep 17 00:00:00 2001 From: Sachin Billore Date: Tue, 21 May 2024 15:31:09 +0530 Subject: [PATCH 261/548] feat: add esp32p4 APM HAL/LL API --- .../bootloader_support/src/bootloader_mem.c | 2 + .../esp_hw_support/sleep_system_peripheral.c | 3 + components/hal/apm_hal.c | 48 +- components/hal/esp32p4/include/hal/apm_ll.h | 433 ++++++++++++++++++ components/hal/include/hal/apm_hal.h | 93 +++- .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c6/include/soc/soc_caps.h | 1 + .../esp32h2/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32h2/include/soc/soc_caps.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/reg_base.h | 9 +- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 3 - 13 files changed, 592 insertions(+), 15 deletions(-) create mode 100644 components/hal/esp32p4/include/hal/apm_ll.h diff --git a/components/bootloader_support/src/bootloader_mem.c b/components/bootloader_support/src/bootloader_mem.c index 2af61961e10..d9f8466a1c5 100644 --- a/components/bootloader_support/src/bootloader_mem.c +++ b/components/bootloader_support/src/bootloader_mem.c @@ -33,8 +33,10 @@ void bootloader_init_mem(void) * So, at boot disabling these filters. They will enable as per the * use case by TEE initialization code. */ +#ifdef SOC_APM_CTRL_FILTER_SUPPORTED apm_hal_apm_ctrl_filter_enable_all(false); #endif +#endif #if CONFIG_IDF_TARGET_ESP32C5 // TODO: IDF-8615 Remove the workaround when APM supported on C5! // disable apm filter diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index cd36fe7f527..2f37fb1542c 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -39,12 +39,15 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_hp_system_retention_in #if SOC_APM_SUPPORTED static __attribute__((unused)) esp_err_t sleep_sys_periph_tee_apm_retention_init(void *arg) { +/* TBD for ESP32P4 IDF-10020. */ +#ifndef CONFIG_IDF_TARGET_ESP32P4 esp_err_t err = sleep_retention_entries_create(tee_apm_regs_retention, ARRAY_SIZE(tee_apm_regs_retention), REGDMA_LINK_PRI_NON_CRITICAL_TEE_APM, SLEEP_RETENTION_MODULE_SYS_PERIPH); if (err == ESP_OK) { err = sleep_retention_entries_create(tee_apm_highpri_regs_retention, ARRAY_SIZE(tee_apm_highpri_regs_retention), REGDMA_LINK_PRI_CRITICAL_TEE_APM, SLEEP_RETENTION_MODULE_SYS_PERIPH); } ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "TEE/APM"); ESP_LOGD(TAG, "TEE/APM sleep retention initialization"); +#endif return ESP_OK; } #endif diff --git a/components/hal/apm_hal.c b/components/hal/apm_hal.c index c57c7486a2f..cb08dbde485 100644 --- a/components/hal/apm_hal.c +++ b/components/hal/apm_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,6 +9,50 @@ #include "hal/apm_ll.h" #include "hal/log.h" +#if CONFIG_IDF_TARGET_ESP32P4 +void apm_hal_hp_peri_access_enable(apm_ll_master_id_t master_id, apm_ll_hp_peri_t hp_peri, + apm_ll_secure_mode_t sec_mode, bool enable) +{ + apm_ll_hp_peri_access_enable(master_id, hp_peri, sec_mode, enable); +} + + +void apm_hal_lp_peri_access_enable(apm_ll_lp_peri_t lp_peri, bool enable) +{ + apm_ll_lp_peri_access_enable(lp_peri, enable); +} + +void apm_hal_peri_region_config(uint32_t regn_num, uint32_t regn_low_addr, uint32_t regn_high_addr) +{ + apm_ll_peri_region_config(regn_num, regn_low_addr, regn_high_addr); +} + +int apm_hal_peri_region_pms(apm_ll_master_id_t master_id, apm_ll_secure_mode_t sec_mode, + uint32_t regn_num, uint32_t regn_pms) +{ + return apm_ll_peri_region_pms(master_id, sec_mode, regn_num, regn_pms); +} + +int apm_hal_apm_ctrl_clk_gating_enable(apm_ll_apm_ctrl_t apm_ctrl, bool enable) +{ + return apm_ll_apm_ctrl_clk_gating_enable(apm_ctrl, enable); +} + +void apm_hal_dma_region_config(uint32_t regn_num, uint32_t regn_low_addr, uint32_t regn_high_addr) +{ + apm_ll_dma_region_set_low_address(regn_num, regn_low_addr); + apm_ll_dma_region_set_high_address(regn_num, regn_high_addr); +} + +void apm_hal_dma_region_pms(apm_hal_dma_region_config_data_t *pms_data) +{ + HAL_ASSERT(pms_data); + + apm_ll_dma_region_r_pms(pms_data->dma_master, pms_data->pms_r_mask); + apm_ll_dma_region_w_pms(pms_data->dma_master, pms_data->pms_w_mask); +} +#else + void apm_tee_hal_set_master_secure_mode(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_master_id_t master_id, apm_ll_secure_mode_t sec_mode) { apm_tee_ll_set_master_secure_mode(apm_ctrl, master_id, sec_mode); @@ -129,3 +173,5 @@ esp_err_t apm_hal_apm_ctrl_get_int_src_num(apm_ctrl_path_t *apm_path) { return apm_ll_apm_ctrl_get_int_src_num(apm_path->apm_ctrl, apm_path->apm_m_path); } + +#endif //CONFIG_IDF_TARGET_ESP32P4 diff --git a/components/hal/esp32p4/include/hal/apm_ll.h b/components/hal/esp32p4/include/hal/apm_ll.h new file mode 100644 index 00000000000..9757e44b7cf --- /dev/null +++ b/components/hal/esp32p4/include/hal/apm_ll.h @@ -0,0 +1,433 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "hal/assert.h" +#include "soc/dma_pms_reg.h" +#include "soc/hp2lp_peri_pms_reg.h" +#include "soc/hp_peri_pms_reg.h" +#include "soc/lp2hp_peri_pms_reg.h" +#include "soc/lp_peri_pms_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Master Secure Mode + */ +typedef enum { + APM_LL_SECURE_MODE_TEE = 0, /* Trusted execution environment mode (Machine mode). */ + APM_LL_SECURE_MODE_REE = 1, /* Rich execution environment mode (User mode). */ + APM_LL_SECURE_MODE_INV = 2, /* Invalid mode. */ +} apm_ll_secure_mode_t; + +/** + * @brief Bus Masters. + */ +typedef enum { + APM_LL_MASTER_LPCPU = 0, + APM_LL_MASTER_HPCPU0, + APM_LL_MASTER_HPCPU1, + APM_LL_MASTER_DMA, +} apm_ll_master_id_t; + + +/** + * @brief APM Controller + */ +typedef enum { + LP_APM_CTRL = 0, + HP2LP_APM_CTRL, + HP_APM_CTRL, + LP2HP_APM_CTRL, + DMA_APM_CTRL, + MAX_APM_CTRL, +} apm_ll_apm_ctrl_t; + +/** + * @brief HP CPU Peripherals. + */ +typedef enum { + PMS_COREn_XM_PSRAM_ALLOW = 0, + PMS_COREn_XM_FLASH_ALLOW, + PMS_COREn_XM_L2MEM_ALLOW, + PMS_COREn_XM_L2ROM_ALLOW, + PMS_COREn_XM_TRACE0_ALLOW = 6, + PMS_COREn_XM_TRACE1_ALLOW, + PMS_COREn_XM_CPU_BUS_MON_ALLOW, + PMS_COREn_XM_L2MEM_MON_ALLOW, + PMS_COREn_XM_TCM_MON_ALLOW, + PMS_COREn_XM_CACHE_ALLOW, + + PMS_COREn_XM_HP_USBOTG_ALLOW = 32, + PMS_COREn_XM_HP_USBOTG11_ALLOW, + PMS_COREn_XM_HP_USBOTG11_WRAP_ALLOW, + PMS_COREn_XM_HP_GDMA_ALLOW, + PMS_COREn_XM_HP_SDMMC_ALLOW = 37, + PMS_COREn_XM_HP_AHB_PDMA_ALLOW, + PMS_COREn_XM_HP_JPEG_ALLOW, + PMS_COREn_XM_HP_PPA_ALLOW, + PMS_COREn_XM_HP_DMA2D_ALLOW, + PMS_COREn_XM_HP_KEY_MANAGER_ALLOW, + PMS_COREn_XM_HP_AXI_PDMA_ALLOW, + PMS_COREn_XM_HP_FLASH_ALLOW, + PMS_COREn_XM_HP_PSRAM_ALLOW, + PMS_COREn_XM_HP_CRYPTO_ALLOW, + PMS_COREn_XM_HP_GMAC_ALLOW, + PMS_COREn_XM_HP_USB_PHY_ALLOW, + PMS_COREn_XM_HP_CSI_HOST_ALLOW = 50, + PMS_COREn_XM_HP_DSI_HOST_ALLOW, + PMS_COREn_XM_HP_ISP_ALLOW, + PMS_COREn_XM_HP_H264_CORE_ALLOW, + PMS_COREn_XM_HP_RMT_ALLOW, + PMS_COREn_XM_HP_BITSRAMBLER_ALLOW, + PMS_COREn_XM_HP_AXI_ICM_ALLOW, + PMS_COREn_XM_HP_PERI_PMS_ALLOW, + PMS_COREn_XM_LP2HP_PERI_PMS_ALLOW, + PMS_COREn_XM_DMA_PMS_ALLOW, + PMS_COREn_XM_HP_H264_DMA2D_ALLOW = 60, + + PMS_COREn_XM_HP_MCPWM0_ALLOW = 64, + PMS_COREn_XM_HP_MCPWM1_ALLOW, + PMS_COREn_XM_HP_TIMER_GROUP0_ALLOW, + PMS_COREn_XM_HP_TIMER_GROUP1_ALLOW, + PMS_COREn_XM_HP_I2C0_ALLOW, + PMS_COREn_XM_HP_I2C1_ALLOW, + PMS_COREn_XM_HP_I2S0_ALLOW, + PMS_COREn_XM_HP_I2S1_ALLOW, + PMS_COREn_XM_HP_I2S2_ALLOW, + PMS_COREn_XM_HP_PCNT_ALLOW, + PMS_COREn_XM_HP_UART0_ALLOW, + PMS_COREn_XM_HP_UART1_ALLOW, + PMS_COREn_XM_HP_UART2_ALLOW, + PMS_COREn_XM_HP_UART3_ALLOW, + PMS_COREn_XM_HP_UART4_ALLOW, + PMS_COREn_XM_HP_PARLIO_ALLOW269 , + PMS_COREn_XM_HP_GPSPI2_ALLOW270 , + PMS_COREn_XM_HP_GPSPI3_ALLOW271 , + PMS_COREn_XM_HP_USBDEVICE_ALLOW, + PMS_COREn_XM_HP_LEDC_ALLOW, + PMS_COREn_XM_HP_ETM_ALLOW = 85, + PMS_COREn_XM_HP_INTRMTX_ALLOW, + PMS_COREn_XM_HP_TWAI0_ALLOW, + PMS_COREn_XM_HP_TWAI1_ALLOW, + PMS_COREn_XM_HP_TWAI2_ALLOW, + PMS_COREn_XM_HP_I3C_MST_ALLOW, + PMS_COREn_XM_HP_I3C_SLV_ALLOW, + PMS_COREn_XM_HP_LCDCAM_ALLOW, + PMS_COREn_XM_HP_ADC_ALLOW = 94, + PMS_COREn_XM_HP_UHCI_ALLOW, + + PMS_COREn_XM_HP_GPIO_ALLOW = 96, + PMS_COREn_XM_HP_IOMUX_ALLOW, + PMS_COREn_XM_HP_SYSTIMER_ALLOW, + PMS_COREn_XM_HP_SYS_REG_ALLOW, + PMS_COREn_XM_HP_CLKRST_ALLOW, + PMS_COREn_XM_HP_PERI_MAX, +} apm_ll_hp_peri_t; + + +/** + * @brief LP CPU Peripherals. + */ +typedef enum { + PMS_MM_LP_SYSREG_ALLOW = 0, + PMS_MM_LP_AONCLKRST_ALLOW, + PMS_MM_LP_TIMER_ALLOW, + PMS_MM_LP_ANAPERI_ALLOW, + PMS_MM_LP_PMU_ALLOW, + PMS_MM_LP_WDT_ALLOW, + PMS_MM_LP_MAILBOX_ALLOW, + PMS_MM_LP_PERICLKRST_ALLOW = 8, + PMS_MM_LP_UART_ALLOW, + PMS_MM_LP_I2C_ALLOW, + PMS_MM_LP_SPI_ALLOW, + PMS_MM_LP_I2CMST_ALLOW, + PMS_MM_LP_I2S_ALLOW, + PMS_MM_LP_ADC_ALLOW, + PMS_MM_LP_TOUCH_ALLOW, + PMS_MM_LP_IOMUX_ALLOW, + PMS_MM_LP_INTR_ALLOW, + PMS_MM_LP_EFUSE_ALLOW, + PMS_MM_LP_PMS_ALLOW, + PMS_MM_HP2LP_PMS_ALLOW, + PMS_MM_LP_TSENS_ALLOW, + PMS_MM_LP_HUK_ALLOW, + PMS_HP_COREn_MM_LP_SRAM_ALLOW, + PMS_LP_MM_PERI_MAX, +} apm_ll_lp_peri_t; + + +/** + * @brief LP CPU Peripherals. + */ +typedef enum { + PMS_DMA_GDMA_CH0 = 0, + PMS_DMA_GDMA_CH1, + PMS_DMA_GDMA_CH2, + PMS_DMA_GDMA_CH3, + PMS_DMA_AHB_PDMA_ADC, + PMS_DMA_AHB_PDMA_I2S0, + PMS_DMA_AHB_PDMA_I2S1, + PMS_DMA_AHB_PDMA_I2S2, + PMS_DMA_AHB_PDMA_I3C_MST, + PMS_DMA_AHB_PDMA_UHCI0, + PMS_DMA_AHB_PDMA_RMT, + PMS_DMA_AXI_PDMA_LCDCAM, + PMS_DMA_AXI_PDMA_GPSPI2, + PMS_DMA_AXI_PDMA_GPSPI3, + PMS_DMA_AXI_PDMA_PARLIO, + PMS_DMA_AXI_PDMA_AES, + PMS_DMA_AXI_PDMA_SHA, + PMS_DMA_DMA2D_JPEG, + PMS_DMA_USB, + PMS_DMA_GMAC, + PMS_DMA_SDMMC, + PMS_DMA_USBOTG11, + PMS_DMA_TRACE0, + PMS_DMA_TRACE1, + PMS_DMA_L2MEM_MON, + PMS_DMA_TCM_MON, + PMS_DMA_H264, + PMS_DMA_DMA2D_PPA, + PMS_DMA_DMA2D_DUMMY, + PMS_DMA_AHB_PDMA_DUMMY, + PMS_DMA_AXI_PDMA_DUMMY, + PMS_DMA_MAX, +} apm_ll_dma_master_t; + +#define PMS_PERI_MAX_REGION_NUM 2 +#define PMS_DMA_MAX_REGION_NUM 32 + +#define PMS_COREn_XM_PMS_REGn_REG(master_id, sec_mode, hp_peri) \ + ({\ + (PMS_CORE0_MM_HP_PERI_PMS_REG0_REG + (master_id * 0x20) \ + + (sec_mode * 0x10) + ((hp_peri/32) * 0x4) ); \ + }) + +#define PMS_PERI_REGION_LOW_REG(regn_num) \ + ({\ + (PMS_PERI_REGION0_LOW_REG + (regn_num * 8)); \ + }) + + +#define PMS_PERI_REGION_HIGH_REG(regn_num) \ + ({\ + (PMS_PERI_REGION0_HIGH_REG + (regn_num * 8)); \ + }) + +#define PMS_DMA_PMS_R_REG(dma_master) \ + ({\ + (PMS_DMA_GDMA_CH0_R_PMS_REG + (dma_master * 8)); \ + }) + +#define PMS_DMA_PMS_W_REG(dma_master) \ + ({\ + (PMS_DMA_GDMA_CH0_W_PMS_REG + (dma_master * 8)); \ + }) + + +/** + * @brief Configure HP peripherals access permission for the HP CPU0/1. + * + * @param master_id HP CPU0/1 + * @param hp_peri HP peripheral whose access permission to be configured. + * @param enable Permission enable/disable + */ +static inline void apm_ll_hp_peri_access_enable(apm_ll_master_id_t master_id, apm_ll_hp_peri_t hp_peri, + apm_ll_secure_mode_t sec_mode, bool enable) +{ + HAL_ASSERT((master_id > APM_LL_MASTER_LPCPU) && (master_id < APM_LL_MASTER_DMA) + && (hp_peri < PMS_COREn_XM_HP_PERI_MAX) && (sec_mode < APM_LL_SECURE_MODE_INV)); + + if (enable) { + REG_SET_BIT(PMS_COREn_XM_PMS_REGn_REG(master_id, sec_mode, hp_peri), BIT(hp_peri%32)); + } else { + REG_CLR_BIT(PMS_COREn_XM_PMS_REGn_REG(master_id, sec_mode, hp_peri), BIT(hp_peri%32)); + } +} + +/** + * @brief Configure LP peripherals access permission for the LP CPU. + * + * @param lp_peri LP peripheral whose access permission to be configured. + * @param enable Permission enable/disable + */ +static inline void apm_ll_lp_peri_access_enable(apm_ll_lp_peri_t lp_peri, bool enable) +{ + HAL_ASSERT(lp_peri < PMS_LP_MM_PERI_MAX); + + if (enable) { + REG_SET_BIT(PMS_LP_MM_LP_PERI_PMS_REG0_REG, BIT(lp_peri)); + } else { + REG_CLR_BIT(PMS_LP_MM_LP_PERI_PMS_REG0_REG, BIT(lp_peri)); + } +} + +/** + * @brief Configure peripherals configurable address ranges. + * + * @param regn_num Configurable address range number. + * @param regn_low_addr Configurable address range start address. + * @param regn_high_addr Configurable address range end address. + */ +static inline void apm_ll_peri_region_config(uint32_t regn_num, uint32_t regn_low_addr, + uint32_t regn_high_addr) +{ + HAL_ASSERT(regn_num < PMS_PERI_MAX_REGION_NUM); + + REG_WRITE(PMS_PERI_REGION_LOW_REG(regn_num), regn_low_addr); + REG_WRITE(PMS_PERI_REGION_HIGH_REG(regn_num), regn_high_addr); +} + +/** + * @brief Configure peripherals configurable address ranges. + * + * @param master_id LP CPU and HP CPU0/1 + * @param sec_mode CPU privilege mode (Machine/User) which corresponds to (TEE/REE). + * @param regn_num Configurable address range number. + * @param regn_pms Configurable address range permission setting(2-bits field). + * Bit 0: Region 0 permission enable/disable. + * Bit 1: Region 1 permission enable/disable. + * @return Configuration performed successfully? + */ +static inline int apm_ll_peri_region_pms(apm_ll_master_id_t master_id, apm_ll_secure_mode_t sec_mode, + uint32_t regn_num, uint32_t regn_pms) +{ + HAL_ASSERT((master_id < APM_LL_MASTER_DMA) && (sec_mode < APM_LL_SECURE_MODE_INV)); + + regn_pms &= 0x3; + + switch(master_id) { + case APM_LL_MASTER_LPCPU: + REG_SET_FIELD(PMS_PERI_REGION_PMS_REG, PMS_LP_CORE_REGION_PMS, regn_pms); + break; + case APM_LL_MASTER_HPCPU0: + if (sec_mode) { + REG_SET_FIELD(PMS_PERI_REGION_PMS_REG, PMS_HP_CORE0_UM_REGION_PMS, regn_pms); + } else { + REG_SET_FIELD(PMS_PERI_REGION_PMS_REG, PMS_HP_CORE0_MM_REGION_PMS, regn_pms); + } + break; + case APM_LL_MASTER_HPCPU1: + if (sec_mode) { + REG_SET_FIELD(PMS_PERI_REGION_PMS_REG, PMS_HP_CORE1_UM_REGION_PMS, regn_pms); + } else { + REG_SET_FIELD(PMS_PERI_REGION_PMS_REG, PMS_HP_CORE1_MM_REGION_PMS, regn_pms); + } + break; + default: + return -1; + } + + return 0; +} + +/** + * @brief Configure APM controller clock gating. + * + * @param apm_ctrl APM controller (LP_PERI/HP_PERI/HP_DMA/LP2HP_PERI/HP2LP_PERI). + * @param enable Permission enable/disable. + * enable: Enable automatic clock gating. + * disable: Keep the clock always on. + */ +static inline int apm_ll_apm_ctrl_clk_gating_enable(apm_ll_apm_ctrl_t apm_ctrl, bool enable) +{ + uint32_t reg = 0; + + HAL_ASSERT(apm_ctrl < MAX_APM_CTRL); + + switch(apm_ctrl) { + case LP_APM_CTRL: + reg = PMS_LP_PERI_PMS_CLK_EN_REG; + break; + case HP2LP_APM_CTRL: + reg = PMS_HP2LP_PERI_PMS_CLK_EN_REG; + break; + case HP_APM_CTRL: + reg = PMS_HP_PERI_PMS_CLK_EN_REG; + break; + case LP2HP_APM_CTRL: + reg = PMS_LP2HP_PERI_PMS_CLK_EN_REG; + break; + case DMA_APM_CTRL: + reg = PMS_DMA_CLK_EN_REG; + break; + default: + return -1; + } + + if (enable) { + REG_CLR_BIT(reg, BIT(0)); + } else { + REG_SET_BIT(reg, BIT(0)); + } + + return 0; +} + +/** + * @brief Configure DMA configurable address range low address. + * + * @param regn_num Configurable DMA address range number. + * @param regn_low_addr Configurable DMA address range start address. + */ +static inline void apm_ll_dma_region_set_low_address(uint32_t regn_num, uint32_t regn_low_addr) +{ + HAL_ASSERT(regn_num < PMS_DMA_MAX_REGION_NUM); + + REG_WRITE((PMS_DMA_REGION0_LOW_REG + (regn_num * 8)), regn_low_addr); +} + +/** + * @brief Configure DMA configurable address range high address. + * + * @param regn_num Configurable DMA address range number. + * @param regn_high_addr Configurable DMA address range end address. + */ +static inline void apm_ll_dma_region_set_high_address(uint32_t regn_num, uint32_t regn_high_addr) +{ + HAL_ASSERT(regn_num < PMS_DMA_MAX_REGION_NUM); + + REG_WRITE((PMS_DMA_REGION0_HIGH_REG + (regn_num * 8)), regn_high_addr); +} + +/** + * @brief Configure DMA configurable address range read permission. + * + * @param dma_master DMA master whose access permission to be configured. + * @param regn_mask 32-bits field, each bit for corresponding DMA configurable address range permission. + * 0: Disable read permission. + * 1: Enable read permission. + */ +static inline void apm_ll_dma_region_r_pms(apm_ll_dma_master_t dma_master, uint32_t regn_mask) +{ + HAL_ASSERT(dma_master < PMS_DMA_MAX); + + REG_WRITE(PMS_DMA_PMS_R_REG(dma_master), regn_mask); +} + +/** + * @brief Configure DMA configurable address range write permission. + * + * @param dma_master DMA master whose access permission to be configured. + * @param regn_mask 32-bits field, each bit for corresponding DMA configurable address range permission. + * 0: Disable write permission. + * 1: Enable write permission. + */ +static inline void apm_ll_dma_region_w_pms(apm_ll_dma_master_t dma_master, uint32_t regn_mask) +{ + HAL_ASSERT(dma_master < PMS_DMA_MAX); + + REG_WRITE(PMS_DMA_PMS_W_REG(dma_master), regn_mask); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/apm_hal.h b/components/hal/include/hal/apm_hal.h index 16d32d534fd..6f8b6eb5e93 100644 --- a/components/hal/include/hal/apm_hal.h +++ b/components/hal/include/hal/apm_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,93 @@ extern "C" { #if SOC_APM_SUPPORTED #include "hal/apm_ll.h" +#if CONFIG_IDF_TARGET_ESP32P4 + +/** + * @brief DMA configurable region configuration data. + */ +typedef struct { + apm_ll_dma_master_t dma_master; /* DMA master whose access permission to be configured.*/ + uint32_t pms_r_mask; /* Read permission mask. */ + uint32_t pms_w_mask; /* Write permission mask. */ +} apm_hal_dma_region_config_data_t; + +/** + * @brief Configure HP peripherals access permission for the HP CPU0/1. + * + * @param master_id HP CPU0/1 + * @param hp_peri HP peripheral whose access permission to be configured. + * @param enable Permission enable/disable + */ +void apm_hal_hp_peri_access_enable(apm_ll_master_id_t master_id, apm_ll_hp_peri_t hp_peri, + apm_ll_secure_mode_t sec_mode, bool enable); + +/** + * @brief Configure LP peripherals access permission for the LP CPU. + * + * @param lp_peri LP peripheral whose access permission to be configured. + * @param enable Permission enable/disable + */ +void apm_hal_lp_peri_access_enable(apm_ll_lp_peri_t lp_peri, bool enable); + +/** + * @brief Configure peripherals configurable address ranges. + * + * @param regn_num Configurable address range number. + * @param regn_low_addr Configurable address range start address. + * @param regn_high_addr Configurable address range end address. + */ +void apm_hal_peri_region_config(uint32_t regn_num, uint32_t regn_low_addr, + uint32_t regn_high_addr); + +/** + * @brief Configure peripherals configurable address ranges. + * + * @param master_id LP CPU and HP CPU0/1 + * @param sec_mode CPU privilege mode (Machine/User) which corresponds to (TEE/REE). + * @param regn_num Configurable address range number. + * @param regn_pms Configurable address range permission setting(2-bits field). + * Bit 0: Region 0 permission enable/disable. + * Bit 1: Region 1 permission enable/disable. + * @return Configuration performed successfully? + */ +int apm_hal_peri_region_pms(apm_ll_master_id_t master_id, apm_ll_secure_mode_t sec_mode, + uint32_t regn_num, uint32_t regn_pms); + +/** + * @brief Configure APM controller clock gating. + * + * @param apm_ctrl APM controller (LP_PERI/HP_PERI/HP_DMA/LP2HP_PERI/HP2LP_PERI). + * @param enable Permission enable/disable. + * enable: Enable automatic clock gating. + * disable: Keep the clock always on. + * @return Clock gating set successfully? + */ +int apm_hal_apm_ctrl_clk_gating_enable(apm_ll_apm_ctrl_t apm_ctrl, bool enable); + +/** + * @brief Configure DMA configurable address range low address. + * + * @param regn_num Configurable DMA address range number. + * @param regn_low_addr Configurable DMA address range start address. + * @param regn_high_addr Configurable DMA address range end address. + */ +void apm_hal_dma_region_config(uint32_t regn_num, uint32_t regn_low_addr, uint32_t regn_high_addr); + +/** + * @brief Configure DMA configurable address range read permission. + * + * @param pms_data DMA configurable region configuration data. + * @param dma_master DMA master whose access permission to be configured. + * @param regn_mask 32-bits field, each bit for corresponding DMA configurable address range permission. + * 0: Disable read permission. + * 1: Enable read permission. + */ +void apm_hal_dma_region_pms(apm_hal_dma_region_config_data_t *pms_data); + + +#else + /** * @brief Region configuration data. */ @@ -157,7 +244,9 @@ void apm_hal_apm_ctrl_reset_event_enable(bool enable); */ esp_err_t apm_hal_apm_ctrl_get_int_src_num(apm_ctrl_path_t *apm_path); -#endif +#endif //CONFIG_IDF_TARGET_ESP32P4 + +#endif //SOC_APM_SUPPORTED #ifdef __cplusplus } diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index f3f3df1034b..044e3b9018a 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -179,6 +179,10 @@ config SOC_APM_SUPPORTED bool default y +config SOC_APM_CTRL_FILTER_SUPPORTED + bool + default y + config SOC_PMU_SUPPORTED bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index c16ebceee48..7ecbc89d4c9 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -61,6 +61,7 @@ #define SOC_SDIO_SLAVE_SUPPORTED 1 #define SOC_BOD_SUPPORTED 1 #define SOC_APM_SUPPORTED 1 +#define SOC_APM_CTRL_FILTER_SUPPORTED 1 #define SOC_PMU_SUPPORTED 1 #define SOC_PAU_SUPPORTED 1 #define SOC_LP_TIMER_SUPPORTED 1 diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 9ebdecb32cd..e7175ce72d1 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -179,6 +179,10 @@ config SOC_APM_SUPPORTED bool default y +config SOC_APM_CTRL_FILTER_SUPPORTED + bool + default y + config SOC_PMU_SUPPORTED bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 8728e3f730d..ea7c1860881 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -61,6 +61,7 @@ #define SOC_SECURE_BOOT_SUPPORTED 1 #define SOC_BOD_SUPPORTED 1 #define SOC_APM_SUPPORTED 1 +#define SOC_APM_CTRL_FILTER_SUPPORTED 1 #define SOC_PMU_SUPPORTED 1 #define SOC_LP_TIMER_SUPPORTED 1 #define SOC_LP_AON_SUPPORTED 1 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 7c9036b62bf..de143454811 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -207,6 +207,10 @@ config SOC_BOD_SUPPORTED bool default y +config SOC_APM_SUPPORTED + bool + default y + config SOC_PMU_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/reg_base.h b/components/soc/esp32p4/include/soc/reg_base.h index f851cb5c742..4c2bbc2c7eb 100644 --- a/components/soc/esp32p4/include/soc/reg_base.h +++ b/components/soc/esp32p4/include/soc/reg_base.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -195,13 +195,6 @@ #define DR_REG_LPPERI_BASE DR_REG_LP_PERI_CLKRST_BASE #define DR_REG_CPU_BUS_MONITOR_BASE DR_REG_CPU_BUS_MON_BASE -//TODO: IDF-7542 -// #define DR_REG_TEE_BASE 0x60098000 -// #define DR_REG_HP_APM_BASE 0x60099000 -// #define DR_REG_LP_APM0_BASE 0x60099800 -// #define DR_REG_LP_TEE_BASE 0x600B3400 -// #define DR_REG_LP_APM_BASE 0x600B3800 - #define DR_REG_PAU_BASE DR_REG_REGDMA_BASE //TODO: IDF-7688 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 60f0faa36f7..8adbc6b6984 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -69,7 +69,7 @@ #define SOC_FLASH_ENC_SUPPORTED 1 #define SOC_SECURE_BOOT_SUPPORTED 1 #define SOC_BOD_SUPPORTED 1 -// #define SOC_APM_SUPPORTED 1 //TODO: IDF-7542 +#define SOC_APM_SUPPORTED 1 #define SOC_PMU_SUPPORTED 1 #define SOC_DCDC_SUPPORTED 1 #define SOC_PAU_SUPPORTED 1 //TODO: IDF-7531 diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index 0b293ba89e7..f8aaaf3fefd 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -68,8 +68,6 @@ PROVIDE ( MSPI_IOMUX = 0x500E1200 ); PROVIDE ( HP_SYSTEM = 0x500E5000 ); PROVIDE ( HP_SYS_CLKRST = 0x500E6000 ); -PROVIDE ( TEE = 0x60098000 ); /* TODO: IDF-7542 */ -PROVIDE ( HP_APM = 0x60099000 ); /* TODO: IDF-7542 */ PROVIDE ( PMU = 0x50115000 ); PROVIDE ( LP_SYS = 0x50110000 ); @@ -89,7 +87,6 @@ PROVIDE ( LP_PERI_PMS = 0x5012E000 ); PROVIDE ( HP2LP_PERI_PMS = 0x5012E800 ); PROVIDE ( LP_I2C_ANA_MST = 0x50124000 ); PROVIDE ( LP_ANA_PERI = 0x50113000 ); -PROVIDE ( LP_APM = 0x600B3800 ); /* TODO: IDF-7542 */ PROVIDE ( AHB_DMA = 0x50085000 ); PROVIDE ( AXI_DMA = 0x5008a000 ); PROVIDE ( LCD_CAM = 0x500dc000 ); From f7faae7c2d59e8a381f201fa05e537c0a953b746 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 20 May 2024 22:41:32 +0800 Subject: [PATCH 262/548] fix(soc): fix the pms reg headers base addr --- .../soc/esp32p4/include/soc/dma_pms_reg.h | 260 +++++++++--------- .../esp32p4/include/soc/hp2lp_peri_pms_reg.h | 14 +- .../soc/esp32p4/include/soc/hp_peri_pms_reg.h | 38 +-- .../esp32p4/include/soc/lp2hp_peri_pms_reg.h | 12 +- .../soc/esp32p4/include/soc/lp_peri_pms_reg.h | 16 +- 5 files changed, 170 insertions(+), 170 deletions(-) diff --git a/components/soc/esp32p4/include/soc/dma_pms_reg.h b/components/soc/esp32p4/include/soc/dma_pms_reg.h index 273935329d4..d985c15a134 100644 --- a/components/soc/esp32p4/include/soc/dma_pms_reg.h +++ b/components/soc/esp32p4/include/soc/dma_pms_reg.h @@ -14,7 +14,7 @@ extern "C" { /** PMS_DMA_DATE_REG register * Version control register */ -#define PMS_DMA_DATE_REG (DR_REG_PMS_DMA_BASE + 0x0) +#define PMS_DMA_DATE_REG (DR_REG_DMA_PMS_BASE + 0x0) /** PMS_DMA_DATE : R/W; bitpos: [31:0]; default: 539165460; * Version control register. */ @@ -26,7 +26,7 @@ extern "C" { /** PMS_DMA_CLK_EN_REG register * Clock gating register */ -#define PMS_DMA_CLK_EN_REG (DR_REG_PMS_DMA_BASE + 0x4) +#define PMS_DMA_CLK_EN_REG (DR_REG_DMA_PMS_BASE + 0x4) /** PMS_DMA_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether to keep the clock always on. * 0: Enable automatic clock gating. @@ -40,7 +40,7 @@ extern "C" { /** PMS_DMA_REGION0_LOW_REG register * Region0 start address configuration register */ -#define PMS_DMA_REGION0_LOW_REG (DR_REG_PMS_DMA_BASE + 0x8) +#define PMS_DMA_REGION0_LOW_REG (DR_REG_DMA_PMS_BASE + 0x8) /** PMS_DMA_REGION0_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region0. */ @@ -52,7 +52,7 @@ extern "C" { /** PMS_DMA_REGION0_HIGH_REG register * Region0 end address configuration register */ -#define PMS_DMA_REGION0_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xc) +#define PMS_DMA_REGION0_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xc) /** PMS_DMA_REGION0_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region0. */ @@ -64,7 +64,7 @@ extern "C" { /** PMS_DMA_REGION1_LOW_REG register * Region1 start address configuration register */ -#define PMS_DMA_REGION1_LOW_REG (DR_REG_PMS_DMA_BASE + 0x10) +#define PMS_DMA_REGION1_LOW_REG (DR_REG_DMA_PMS_BASE + 0x10) /** PMS_DMA_REGION1_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region1. */ @@ -76,7 +76,7 @@ extern "C" { /** PMS_DMA_REGION1_HIGH_REG register * Region1 end address configuration register */ -#define PMS_DMA_REGION1_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x14) +#define PMS_DMA_REGION1_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x14) /** PMS_DMA_REGION1_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region1. */ @@ -88,7 +88,7 @@ extern "C" { /** PMS_DMA_REGION2_LOW_REG register * Region2 start address configuration register */ -#define PMS_DMA_REGION2_LOW_REG (DR_REG_PMS_DMA_BASE + 0x18) +#define PMS_DMA_REGION2_LOW_REG (DR_REG_DMA_PMS_BASE + 0x18) /** PMS_DMA_REGION2_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region2. */ @@ -100,7 +100,7 @@ extern "C" { /** PMS_DMA_REGION2_HIGH_REG register * Region2 end address configuration register */ -#define PMS_DMA_REGION2_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x1c) +#define PMS_DMA_REGION2_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x1c) /** PMS_DMA_REGION2_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region2. */ @@ -112,7 +112,7 @@ extern "C" { /** PMS_DMA_REGION3_LOW_REG register * Region3 start address configuration register */ -#define PMS_DMA_REGION3_LOW_REG (DR_REG_PMS_DMA_BASE + 0x20) +#define PMS_DMA_REGION3_LOW_REG (DR_REG_DMA_PMS_BASE + 0x20) /** PMS_DMA_REGION3_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region3. */ @@ -124,7 +124,7 @@ extern "C" { /** PMS_DMA_REGION3_HIGH_REG register * Region3 end address configuration register */ -#define PMS_DMA_REGION3_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x24) +#define PMS_DMA_REGION3_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x24) /** PMS_DMA_REGION3_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region3. */ @@ -136,7 +136,7 @@ extern "C" { /** PMS_DMA_REGION4_LOW_REG register * Region4 start address configuration register */ -#define PMS_DMA_REGION4_LOW_REG (DR_REG_PMS_DMA_BASE + 0x28) +#define PMS_DMA_REGION4_LOW_REG (DR_REG_DMA_PMS_BASE + 0x28) /** PMS_DMA_REGION4_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region4. */ @@ -148,7 +148,7 @@ extern "C" { /** PMS_DMA_REGION4_HIGH_REG register * Region4 end address configuration register */ -#define PMS_DMA_REGION4_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x2c) +#define PMS_DMA_REGION4_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x2c) /** PMS_DMA_REGION4_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region4. */ @@ -160,7 +160,7 @@ extern "C" { /** PMS_DMA_REGION5_LOW_REG register * Region5 start address configuration register */ -#define PMS_DMA_REGION5_LOW_REG (DR_REG_PMS_DMA_BASE + 0x30) +#define PMS_DMA_REGION5_LOW_REG (DR_REG_DMA_PMS_BASE + 0x30) /** PMS_DMA_REGION5_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region5. */ @@ -172,7 +172,7 @@ extern "C" { /** PMS_DMA_REGION5_HIGH_REG register * Region5 end address configuration register */ -#define PMS_DMA_REGION5_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x34) +#define PMS_DMA_REGION5_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x34) /** PMS_DMA_REGION5_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region5. */ @@ -184,7 +184,7 @@ extern "C" { /** PMS_DMA_REGION6_LOW_REG register * Region6 start address configuration register */ -#define PMS_DMA_REGION6_LOW_REG (DR_REG_PMS_DMA_BASE + 0x38) +#define PMS_DMA_REGION6_LOW_REG (DR_REG_DMA_PMS_BASE + 0x38) /** PMS_DMA_REGION6_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region6. */ @@ -196,7 +196,7 @@ extern "C" { /** PMS_DMA_REGION6_HIGH_REG register * Region6 end address configuration register */ -#define PMS_DMA_REGION6_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x3c) +#define PMS_DMA_REGION6_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x3c) /** PMS_DMA_REGION6_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region6. */ @@ -208,7 +208,7 @@ extern "C" { /** PMS_DMA_REGION7_LOW_REG register * Region7 start address configuration register */ -#define PMS_DMA_REGION7_LOW_REG (DR_REG_PMS_DMA_BASE + 0x40) +#define PMS_DMA_REGION7_LOW_REG (DR_REG_DMA_PMS_BASE + 0x40) /** PMS_DMA_REGION7_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region7. */ @@ -220,7 +220,7 @@ extern "C" { /** PMS_DMA_REGION7_HIGH_REG register * Region7 end address configuration register */ -#define PMS_DMA_REGION7_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x44) +#define PMS_DMA_REGION7_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x44) /** PMS_DMA_REGION7_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region7. */ @@ -232,7 +232,7 @@ extern "C" { /** PMS_DMA_REGION8_LOW_REG register * Region8 start address configuration register */ -#define PMS_DMA_REGION8_LOW_REG (DR_REG_PMS_DMA_BASE + 0x48) +#define PMS_DMA_REGION8_LOW_REG (DR_REG_DMA_PMS_BASE + 0x48) /** PMS_DMA_REGION8_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region8. */ @@ -244,7 +244,7 @@ extern "C" { /** PMS_DMA_REGION8_HIGH_REG register * Region8 end address configuration register */ -#define PMS_DMA_REGION8_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x4c) +#define PMS_DMA_REGION8_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x4c) /** PMS_DMA_REGION8_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region8. */ @@ -256,7 +256,7 @@ extern "C" { /** PMS_DMA_REGION9_LOW_REG register * Region9 start address configuration register */ -#define PMS_DMA_REGION9_LOW_REG (DR_REG_PMS_DMA_BASE + 0x50) +#define PMS_DMA_REGION9_LOW_REG (DR_REG_DMA_PMS_BASE + 0x50) /** PMS_DMA_REGION9_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region9. */ @@ -268,7 +268,7 @@ extern "C" { /** PMS_DMA_REGION9_HIGH_REG register * Region9 end address configuration register */ -#define PMS_DMA_REGION9_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x54) +#define PMS_DMA_REGION9_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x54) /** PMS_DMA_REGION9_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region9. */ @@ -280,7 +280,7 @@ extern "C" { /** PMS_DMA_REGION10_LOW_REG register * Region10 start address configuration register */ -#define PMS_DMA_REGION10_LOW_REG (DR_REG_PMS_DMA_BASE + 0x58) +#define PMS_DMA_REGION10_LOW_REG (DR_REG_DMA_PMS_BASE + 0x58) /** PMS_DMA_REGION10_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region10. */ @@ -292,7 +292,7 @@ extern "C" { /** PMS_DMA_REGION10_HIGH_REG register * Region10 end address configuration register */ -#define PMS_DMA_REGION10_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x5c) +#define PMS_DMA_REGION10_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x5c) /** PMS_DMA_REGION10_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region10. */ @@ -304,7 +304,7 @@ extern "C" { /** PMS_DMA_REGION11_LOW_REG register * Region11 start address configuration register */ -#define PMS_DMA_REGION11_LOW_REG (DR_REG_PMS_DMA_BASE + 0x60) +#define PMS_DMA_REGION11_LOW_REG (DR_REG_DMA_PMS_BASE + 0x60) /** PMS_DMA_REGION11_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region11. */ @@ -316,7 +316,7 @@ extern "C" { /** PMS_DMA_REGION11_HIGH_REG register * Region11 end address configuration register */ -#define PMS_DMA_REGION11_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x64) +#define PMS_DMA_REGION11_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x64) /** PMS_DMA_REGION11_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region11. */ @@ -328,7 +328,7 @@ extern "C" { /** PMS_DMA_REGION12_LOW_REG register * Region12 start address configuration register */ -#define PMS_DMA_REGION12_LOW_REG (DR_REG_PMS_DMA_BASE + 0x68) +#define PMS_DMA_REGION12_LOW_REG (DR_REG_DMA_PMS_BASE + 0x68) /** PMS_DMA_REGION12_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region12. */ @@ -340,7 +340,7 @@ extern "C" { /** PMS_DMA_REGION12_HIGH_REG register * Region12 end address configuration register */ -#define PMS_DMA_REGION12_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x6c) +#define PMS_DMA_REGION12_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x6c) /** PMS_DMA_REGION12_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region12. */ @@ -352,7 +352,7 @@ extern "C" { /** PMS_DMA_REGION13_LOW_REG register * Region13 start address configuration register */ -#define PMS_DMA_REGION13_LOW_REG (DR_REG_PMS_DMA_BASE + 0x70) +#define PMS_DMA_REGION13_LOW_REG (DR_REG_DMA_PMS_BASE + 0x70) /** PMS_DMA_REGION13_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region13. */ @@ -364,7 +364,7 @@ extern "C" { /** PMS_DMA_REGION13_HIGH_REG register * Region13 end address configuration register */ -#define PMS_DMA_REGION13_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x74) +#define PMS_DMA_REGION13_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x74) /** PMS_DMA_REGION13_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region13. */ @@ -376,7 +376,7 @@ extern "C" { /** PMS_DMA_REGION14_LOW_REG register * Region14 start address configuration register */ -#define PMS_DMA_REGION14_LOW_REG (DR_REG_PMS_DMA_BASE + 0x78) +#define PMS_DMA_REGION14_LOW_REG (DR_REG_DMA_PMS_BASE + 0x78) /** PMS_DMA_REGION14_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region14. */ @@ -388,7 +388,7 @@ extern "C" { /** PMS_DMA_REGION14_HIGH_REG register * Region14 end address configuration register */ -#define PMS_DMA_REGION14_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x7c) +#define PMS_DMA_REGION14_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x7c) /** PMS_DMA_REGION14_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region14. */ @@ -400,7 +400,7 @@ extern "C" { /** PMS_DMA_REGION15_LOW_REG register * Region15 start address configuration register */ -#define PMS_DMA_REGION15_LOW_REG (DR_REG_PMS_DMA_BASE + 0x80) +#define PMS_DMA_REGION15_LOW_REG (DR_REG_DMA_PMS_BASE + 0x80) /** PMS_DMA_REGION15_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region15. */ @@ -412,7 +412,7 @@ extern "C" { /** PMS_DMA_REGION15_HIGH_REG register * Region15 end address configuration register */ -#define PMS_DMA_REGION15_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x84) +#define PMS_DMA_REGION15_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x84) /** PMS_DMA_REGION15_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region15. */ @@ -424,7 +424,7 @@ extern "C" { /** PMS_DMA_REGION16_LOW_REG register * Region16 start address configuration register */ -#define PMS_DMA_REGION16_LOW_REG (DR_REG_PMS_DMA_BASE + 0x88) +#define PMS_DMA_REGION16_LOW_REG (DR_REG_DMA_PMS_BASE + 0x88) /** PMS_DMA_REGION16_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region16. */ @@ -436,7 +436,7 @@ extern "C" { /** PMS_DMA_REGION16_HIGH_REG register * Region16 end address configuration register */ -#define PMS_DMA_REGION16_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x8c) +#define PMS_DMA_REGION16_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x8c) /** PMS_DMA_REGION16_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region16. */ @@ -448,7 +448,7 @@ extern "C" { /** PMS_DMA_REGION17_LOW_REG register * Region17 start address configuration register */ -#define PMS_DMA_REGION17_LOW_REG (DR_REG_PMS_DMA_BASE + 0x90) +#define PMS_DMA_REGION17_LOW_REG (DR_REG_DMA_PMS_BASE + 0x90) /** PMS_DMA_REGION17_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region17. */ @@ -460,7 +460,7 @@ extern "C" { /** PMS_DMA_REGION17_HIGH_REG register * Region17 end address configuration register */ -#define PMS_DMA_REGION17_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x94) +#define PMS_DMA_REGION17_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x94) /** PMS_DMA_REGION17_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region17. */ @@ -472,7 +472,7 @@ extern "C" { /** PMS_DMA_REGION18_LOW_REG register * Region18 start address configuration register */ -#define PMS_DMA_REGION18_LOW_REG (DR_REG_PMS_DMA_BASE + 0x98) +#define PMS_DMA_REGION18_LOW_REG (DR_REG_DMA_PMS_BASE + 0x98) /** PMS_DMA_REGION18_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region18. */ @@ -484,7 +484,7 @@ extern "C" { /** PMS_DMA_REGION18_HIGH_REG register * Region18 end address configuration register */ -#define PMS_DMA_REGION18_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x9c) +#define PMS_DMA_REGION18_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x9c) /** PMS_DMA_REGION18_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region18. */ @@ -496,7 +496,7 @@ extern "C" { /** PMS_DMA_REGION19_LOW_REG register * Region19 start address configuration register */ -#define PMS_DMA_REGION19_LOW_REG (DR_REG_PMS_DMA_BASE + 0xa0) +#define PMS_DMA_REGION19_LOW_REG (DR_REG_DMA_PMS_BASE + 0xa0) /** PMS_DMA_REGION19_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region19. */ @@ -508,7 +508,7 @@ extern "C" { /** PMS_DMA_REGION19_HIGH_REG register * Region19 end address configuration register */ -#define PMS_DMA_REGION19_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xa4) +#define PMS_DMA_REGION19_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xa4) /** PMS_DMA_REGION19_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region19. */ @@ -520,7 +520,7 @@ extern "C" { /** PMS_DMA_REGION20_LOW_REG register * Region20 start address configuration register */ -#define PMS_DMA_REGION20_LOW_REG (DR_REG_PMS_DMA_BASE + 0xa8) +#define PMS_DMA_REGION20_LOW_REG (DR_REG_DMA_PMS_BASE + 0xa8) /** PMS_DMA_REGION20_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region20. */ @@ -532,7 +532,7 @@ extern "C" { /** PMS_DMA_REGION20_HIGH_REG register * Region20 end address configuration register */ -#define PMS_DMA_REGION20_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xac) +#define PMS_DMA_REGION20_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xac) /** PMS_DMA_REGION20_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region20. */ @@ -544,7 +544,7 @@ extern "C" { /** PMS_DMA_REGION21_LOW_REG register * Region21 start address configuration register */ -#define PMS_DMA_REGION21_LOW_REG (DR_REG_PMS_DMA_BASE + 0xb0) +#define PMS_DMA_REGION21_LOW_REG (DR_REG_DMA_PMS_BASE + 0xb0) /** PMS_DMA_REGION21_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region21. */ @@ -556,7 +556,7 @@ extern "C" { /** PMS_DMA_REGION21_HIGH_REG register * Region21 end address configuration register */ -#define PMS_DMA_REGION21_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xb4) +#define PMS_DMA_REGION21_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xb4) /** PMS_DMA_REGION21_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region21. */ @@ -568,7 +568,7 @@ extern "C" { /** PMS_DMA_REGION22_LOW_REG register * Region22 start address configuration register */ -#define PMS_DMA_REGION22_LOW_REG (DR_REG_PMS_DMA_BASE + 0xb8) +#define PMS_DMA_REGION22_LOW_REG (DR_REG_DMA_PMS_BASE + 0xb8) /** PMS_DMA_REGION22_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region22. */ @@ -580,7 +580,7 @@ extern "C" { /** PMS_DMA_REGION22_HIGH_REG register * Region22 end address configuration register */ -#define PMS_DMA_REGION22_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xbc) +#define PMS_DMA_REGION22_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xbc) /** PMS_DMA_REGION22_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region22. */ @@ -592,7 +592,7 @@ extern "C" { /** PMS_DMA_REGION23_LOW_REG register * Region23 start address configuration register */ -#define PMS_DMA_REGION23_LOW_REG (DR_REG_PMS_DMA_BASE + 0xc0) +#define PMS_DMA_REGION23_LOW_REG (DR_REG_DMA_PMS_BASE + 0xc0) /** PMS_DMA_REGION23_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region23. */ @@ -604,7 +604,7 @@ extern "C" { /** PMS_DMA_REGION23_HIGH_REG register * Region23 end address configuration register */ -#define PMS_DMA_REGION23_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xc4) +#define PMS_DMA_REGION23_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xc4) /** PMS_DMA_REGION23_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region23. */ @@ -616,7 +616,7 @@ extern "C" { /** PMS_DMA_REGION24_LOW_REG register * Region24 start address configuration register */ -#define PMS_DMA_REGION24_LOW_REG (DR_REG_PMS_DMA_BASE + 0xc8) +#define PMS_DMA_REGION24_LOW_REG (DR_REG_DMA_PMS_BASE + 0xc8) /** PMS_DMA_REGION24_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region24. */ @@ -628,7 +628,7 @@ extern "C" { /** PMS_DMA_REGION24_HIGH_REG register * Region24 end address configuration register */ -#define PMS_DMA_REGION24_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xcc) +#define PMS_DMA_REGION24_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xcc) /** PMS_DMA_REGION24_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region24. */ @@ -640,7 +640,7 @@ extern "C" { /** PMS_DMA_REGION25_LOW_REG register * Region25 start address configuration register */ -#define PMS_DMA_REGION25_LOW_REG (DR_REG_PMS_DMA_BASE + 0xd0) +#define PMS_DMA_REGION25_LOW_REG (DR_REG_DMA_PMS_BASE + 0xd0) /** PMS_DMA_REGION25_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region25. */ @@ -652,7 +652,7 @@ extern "C" { /** PMS_DMA_REGION25_HIGH_REG register * Region25 end address configuration register */ -#define PMS_DMA_REGION25_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xd4) +#define PMS_DMA_REGION25_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xd4) /** PMS_DMA_REGION25_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region25. */ @@ -664,7 +664,7 @@ extern "C" { /** PMS_DMA_REGION26_LOW_REG register * Region26 start address configuration register */ -#define PMS_DMA_REGION26_LOW_REG (DR_REG_PMS_DMA_BASE + 0xd8) +#define PMS_DMA_REGION26_LOW_REG (DR_REG_DMA_PMS_BASE + 0xd8) /** PMS_DMA_REGION26_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region26. */ @@ -676,7 +676,7 @@ extern "C" { /** PMS_DMA_REGION26_HIGH_REG register * Region26 end address configuration register */ -#define PMS_DMA_REGION26_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xdc) +#define PMS_DMA_REGION26_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xdc) /** PMS_DMA_REGION26_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region26. */ @@ -688,7 +688,7 @@ extern "C" { /** PMS_DMA_REGION27_LOW_REG register * Region27 start address configuration register */ -#define PMS_DMA_REGION27_LOW_REG (DR_REG_PMS_DMA_BASE + 0xe0) +#define PMS_DMA_REGION27_LOW_REG (DR_REG_DMA_PMS_BASE + 0xe0) /** PMS_DMA_REGION27_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region27. */ @@ -700,7 +700,7 @@ extern "C" { /** PMS_DMA_REGION27_HIGH_REG register * Region27 end address configuration register */ -#define PMS_DMA_REGION27_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xe4) +#define PMS_DMA_REGION27_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xe4) /** PMS_DMA_REGION27_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region27. */ @@ -712,7 +712,7 @@ extern "C" { /** PMS_DMA_REGION28_LOW_REG register * Region28 start address configuration register */ -#define PMS_DMA_REGION28_LOW_REG (DR_REG_PMS_DMA_BASE + 0xe8) +#define PMS_DMA_REGION28_LOW_REG (DR_REG_DMA_PMS_BASE + 0xe8) /** PMS_DMA_REGION28_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region28. */ @@ -724,7 +724,7 @@ extern "C" { /** PMS_DMA_REGION28_HIGH_REG register * Region28 end address configuration register */ -#define PMS_DMA_REGION28_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xec) +#define PMS_DMA_REGION28_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xec) /** PMS_DMA_REGION28_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region28. */ @@ -736,7 +736,7 @@ extern "C" { /** PMS_DMA_REGION29_LOW_REG register * Region29 start address configuration register */ -#define PMS_DMA_REGION29_LOW_REG (DR_REG_PMS_DMA_BASE + 0xf0) +#define PMS_DMA_REGION29_LOW_REG (DR_REG_DMA_PMS_BASE + 0xf0) /** PMS_DMA_REGION29_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region29. */ @@ -748,7 +748,7 @@ extern "C" { /** PMS_DMA_REGION29_HIGH_REG register * Region29 end address configuration register */ -#define PMS_DMA_REGION29_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xf4) +#define PMS_DMA_REGION29_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xf4) /** PMS_DMA_REGION29_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region29. */ @@ -760,7 +760,7 @@ extern "C" { /** PMS_DMA_REGION30_LOW_REG register * Region30 start address configuration register */ -#define PMS_DMA_REGION30_LOW_REG (DR_REG_PMS_DMA_BASE + 0xf8) +#define PMS_DMA_REGION30_LOW_REG (DR_REG_DMA_PMS_BASE + 0xf8) /** PMS_DMA_REGION30_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region30. */ @@ -772,7 +772,7 @@ extern "C" { /** PMS_DMA_REGION30_HIGH_REG register * Region30 end address configuration register */ -#define PMS_DMA_REGION30_HIGH_REG (DR_REG_PMS_DMA_BASE + 0xfc) +#define PMS_DMA_REGION30_HIGH_REG (DR_REG_DMA_PMS_BASE + 0xfc) /** PMS_DMA_REGION30_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region30. */ @@ -784,7 +784,7 @@ extern "C" { /** PMS_DMA_REGION31_LOW_REG register * Region31 start address configuration register */ -#define PMS_DMA_REGION31_LOW_REG (DR_REG_PMS_DMA_BASE + 0x100) +#define PMS_DMA_REGION31_LOW_REG (DR_REG_DMA_PMS_BASE + 0x100) /** PMS_DMA_REGION31_LOW : R/W; bitpos: [31:12]; default: 0; * Configures the high 20 bits of the start address for region31. */ @@ -796,7 +796,7 @@ extern "C" { /** PMS_DMA_REGION31_HIGH_REG register * Region31 end address configuration register */ -#define PMS_DMA_REGION31_HIGH_REG (DR_REG_PMS_DMA_BASE + 0x104) +#define PMS_DMA_REGION31_HIGH_REG (DR_REG_DMA_PMS_BASE + 0x104) /** PMS_DMA_REGION31_HIGH : R/W; bitpos: [31:12]; default: 1048575; * Configures the high 20 bits of the end address for region31. */ @@ -808,7 +808,7 @@ extern "C" { /** PMS_DMA_GDMA_CH0_R_PMS_REG register * GDMA ch0 read permission control register */ -#define PMS_DMA_GDMA_CH0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x108) +#define PMS_DMA_GDMA_CH0_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x108) /** PMS_DMA_GDMA_CH0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch0 to read 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -823,7 +823,7 @@ extern "C" { /** PMS_DMA_GDMA_CH0_W_PMS_REG register * GDMA ch0 write permission control register */ -#define PMS_DMA_GDMA_CH0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x10c) +#define PMS_DMA_GDMA_CH0_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x10c) /** PMS_DMA_GDMA_CH0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch0 to write 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -838,7 +838,7 @@ extern "C" { /** PMS_DMA_GDMA_CH1_R_PMS_REG register * GDMA ch1 read permission control register */ -#define PMS_DMA_GDMA_CH1_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x110) +#define PMS_DMA_GDMA_CH1_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x110) /** PMS_DMA_GDMA_CH1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch1 to read 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -853,7 +853,7 @@ extern "C" { /** PMS_DMA_GDMA_CH1_W_PMS_REG register * GDMA ch1 write permission control register */ -#define PMS_DMA_GDMA_CH1_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x114) +#define PMS_DMA_GDMA_CH1_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x114) /** PMS_DMA_GDMA_CH1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch1 to write 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -868,7 +868,7 @@ extern "C" { /** PMS_DMA_GDMA_CH2_R_PMS_REG register * GDMA ch2 read permission control register */ -#define PMS_DMA_GDMA_CH2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x118) +#define PMS_DMA_GDMA_CH2_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x118) /** PMS_DMA_GDMA_CH2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch2 to read 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -883,7 +883,7 @@ extern "C" { /** PMS_DMA_GDMA_CH2_W_PMS_REG register * GDMA ch2 write permission control register */ -#define PMS_DMA_GDMA_CH2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x11c) +#define PMS_DMA_GDMA_CH2_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x11c) /** PMS_DMA_GDMA_CH2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch2 to write 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -898,7 +898,7 @@ extern "C" { /** PMS_DMA_GDMA_CH3_R_PMS_REG register * GDMA ch3 read permission control register */ -#define PMS_DMA_GDMA_CH3_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x120) +#define PMS_DMA_GDMA_CH3_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x120) /** PMS_DMA_GDMA_CH3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch3 to read 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -913,7 +913,7 @@ extern "C" { /** PMS_DMA_GDMA_CH3_W_PMS_REG register * GDMA ch3 write permission control register */ -#define PMS_DMA_GDMA_CH3_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x124) +#define PMS_DMA_GDMA_CH3_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x124) /** PMS_DMA_GDMA_CH3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures the permission for GDMA ch3 to write 32 address regions. Bit 0 * corresponds to region0, and so on. @@ -928,7 +928,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_ADC_R_PMS_REG register * GDMA-AHB ADC read permission control register */ -#define PMS_DMA_AHB_PDMA_ADC_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x128) +#define PMS_DMA_AHB_PDMA_ADC_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x128) /** PMS_DMA_AHB_PDMA_ADC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by ADC. Bit 0 * corresponds to region0, and so on. @@ -943,7 +943,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_ADC_W_PMS_REG register * GDMA-AHB ADC write permission control register */ -#define PMS_DMA_AHB_PDMA_ADC_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x12c) +#define PMS_DMA_AHB_PDMA_ADC_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x12c) /** PMS_DMA_AHB_PDMA_ADC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by ADC. Bit 0 * corresponds to region0, and so on. @@ -958,7 +958,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S0_R_PMS_REG register * GDMA-AHB I2S0 read permission control register */ -#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x130) +#define PMS_DMA_AHB_PDMA_I2S0_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x130) /** PMS_DMA_AHB_PDMA_I2S0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by I2S0. Bit 0 * corresponds to region0, and so on. @@ -973,7 +973,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S0_W_PMS_REG register * GDMA-AHB I2S0 write permission control register */ -#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x134) +#define PMS_DMA_AHB_PDMA_I2S0_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x134) /** PMS_DMA_AHB_PDMA_I2S0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by I2S0. Bit 0 * corresponds to region0, and so on. @@ -988,7 +988,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S1_R_PMS_REG register * GDMA-AHB I2S1 read permission control register */ -#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x138) +#define PMS_DMA_AHB_PDMA_I2S1_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x138) /** PMS_DMA_AHB_PDMA_I2S1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by I2S1. Bit 0 * corresponds to region0, and so on. @@ -1003,7 +1003,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S1_W_PMS_REG register * GDMA-AHB I2S1 write permission control register */ -#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x13c) +#define PMS_DMA_AHB_PDMA_I2S1_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x13c) /** PMS_DMA_AHB_PDMA_I2S1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by I2S1. Bit 0 * corresponds to region0, and so on. @@ -1018,7 +1018,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S2_R_PMS_REG register * GDMA-AHB I2S2 read permission control register */ -#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x140) +#define PMS_DMA_AHB_PDMA_I2S2_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x140) /** PMS_DMA_AHB_PDMA_I2S2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by I2S2. Bit 0 * corresponds to region0, and so on. @@ -1033,7 +1033,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I2S2_W_PMS_REG register * GDMA-AHB I2S2 write permission control register */ -#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x144) +#define PMS_DMA_AHB_PDMA_I2S2_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x144) /** PMS_DMA_AHB_PDMA_I2S2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by I2S2. Bit 0 * corresponds to region0, and so on. @@ -1048,7 +1048,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_REG register * GDMA-AHB I3C MST read permission control register */ -#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x148) +#define PMS_DMA_AHB_PDMA_I3C_MST_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x148) /** PMS_DMA_AHB_PDMA_I3C_MST_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by I3C master. * Bit 0 corresponds to region0, and so on. @@ -1063,7 +1063,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_REG register * GDMA-AHB I3C MST write permission control register */ -#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x14c) +#define PMS_DMA_AHB_PDMA_I3C_MST_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x14c) /** PMS_DMA_AHB_PDMA_I3C_MST_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by I3C master. * Bit 0 corresponds to region0, and so on. @@ -1078,7 +1078,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_UHCI0_R_PMS_REG register * GDMA-AHB UHCI read permission control register */ -#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x150) +#define PMS_DMA_AHB_PDMA_UHCI0_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x150) /** PMS_DMA_AHB_PDMA_UHCI0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by UHCI. Bit 0 * corresponds to region0, and so on. @@ -1093,7 +1093,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_UHCI0_W_PMS_REG register * GDMA-AHB UHCI write permission control register */ -#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x154) +#define PMS_DMA_AHB_PDMA_UHCI0_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x154) /** PMS_DMA_AHB_PDMA_UHCI0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by UHCI. Bit 0 * corresponds to region0, and so on. @@ -1108,7 +1108,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_RMT_R_PMS_REG register * GDMA-AHB RMT read permission control register */ -#define PMS_DMA_AHB_PDMA_RMT_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x158) +#define PMS_DMA_AHB_PDMA_RMT_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x158) /** PMS_DMA_AHB_PDMA_RMT_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by RMT. Bit 0 * corresponds to region0, and so on. @@ -1123,7 +1123,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_RMT_W_PMS_REG register * GDMA-AHB RMT write permission control register */ -#define PMS_DMA_AHB_PDMA_RMT_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x170) +#define PMS_DMA_AHB_PDMA_RMT_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x170) /** PMS_DMA_AHB_PDMA_RMT_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by RMT. Bit 0 * corresponds to region0, and so on. @@ -1138,7 +1138,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_REG register * GDMA-AXI LCD_CAM read permission control register */ -#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x174) +#define PMS_DMA_AXI_PDMA_LCDCAM_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x174) /** PMS_DMA_AXI_PDMA_LCDCAM_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by LCD_CAM. Bit * 0 corresponds to region0, and so on. @@ -1153,7 +1153,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_REG register * GDMA-AXI LCD_CAM write permission control register */ -#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x178) +#define PMS_DMA_AXI_PDMA_LCDCAM_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x178) /** PMS_DMA_AXI_PDMA_LCDCAM_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by LCD_CAM. Bit * 0 corresponds to region0, and so on. @@ -1168,7 +1168,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_REG register * GDMA-AXI GPSPI2 read permission control register */ -#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x17c) +#define PMS_DMA_AXI_PDMA_GPSPI2_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x17c) /** PMS_DMA_AXI_PDMA_GPSPI2_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI2. Bit * 0 corresponds to region0, and so on. @@ -1183,7 +1183,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_REG register * GDMA-AXI GPSPI2 write permission control register */ -#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x180) +#define PMS_DMA_AXI_PDMA_GPSPI2_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x180) /** PMS_DMA_AXI_PDMA_GPSPI2_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI2. Bit * 0 corresponds to region0, and so on. @@ -1198,7 +1198,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_REG register * GDMA-AXI GPSPI3 read permission control register */ -#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x184) +#define PMS_DMA_AXI_PDMA_GPSPI3_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x184) /** PMS_DMA_AXI_PDMA_GPSPI3_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by GP-SPI3. Bit * 0 corresponds to region0, and so on. @@ -1213,7 +1213,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_REG register * AXI PDMA GPSPI3 write permission control register */ -#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x188) +#define PMS_DMA_AXI_PDMA_GPSPI3_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x188) /** PMS_DMA_AXI_PDMA_GPSPI3_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by GP-SPI3. Bit * 0 corresponds to region0, and so on. @@ -1228,7 +1228,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_PARLIO_R_PMS_REG register * GDMA-AXI PARLIO read permission control register */ -#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x18c) +#define PMS_DMA_AXI_PDMA_PARLIO_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x18c) /** PMS_DMA_AXI_PDMA_PARLIO_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by PARLIO * (Parallel IO Controller). Bit 0 corresponds to region0, and so on. @@ -1243,7 +1243,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_PARLIO_W_PMS_REG register * GDMA-AXI PARLIO write permission control register */ -#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x190) +#define PMS_DMA_AXI_PDMA_PARLIO_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x190) /** PMS_DMA_AXI_PDMA_PARLIO_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by PARLIO. Bit * 0 corresponds to region0, and so on. @@ -1258,7 +1258,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_AES_R_PMS_REG register * GDMA-AXI AES read permission control register */ -#define PMS_DMA_AXI_PDMA_AES_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x194) +#define PMS_DMA_AXI_PDMA_AES_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x194) /** PMS_DMA_AXI_PDMA_AES_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by AES. Bit 0 * corresponds to region0, and so on. @@ -1273,7 +1273,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_AES_W_PMS_REG register * GDMA-AXI AES write permission control register */ -#define PMS_DMA_AXI_PDMA_AES_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x198) +#define PMS_DMA_AXI_PDMA_AES_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x198) /** PMS_DMA_AXI_PDMA_AES_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by AES. Bit 0 * corresponds to region0, and so on. @@ -1288,7 +1288,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_SHA_R_PMS_REG register * GDMA-AXI SHA read permission control register */ -#define PMS_DMA_AXI_PDMA_SHA_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x19c) +#define PMS_DMA_AXI_PDMA_SHA_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x19c) /** PMS_DMA_AXI_PDMA_SHA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by SHA. Bit 0 * corresponds to region0, and so on. @@ -1303,7 +1303,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_SHA_W_PMS_REG register * GDMA-AXI SHA write permission control register */ -#define PMS_DMA_AXI_PDMA_SHA_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x1a0) +#define PMS_DMA_AXI_PDMA_SHA_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x1a0) /** PMS_DMA_AXI_PDMA_SHA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by SHA. Bit 0 * corresponds to region0, and so on. @@ -1318,7 +1318,7 @@ extern "C" { /** PMS_DMA_DMA2D_JPEG_PMS_R_REG register * 2D-DMA JPEG read permission control register */ -#define PMS_DMA_DMA2D_JPEG_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1a4) +#define PMS_DMA_DMA2D_JPEG_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1a4) /** PMS_DMA_DMA2D_JPEG_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to read 32 address ranges requested by JPEG. Bit 0 * corresponds to region0, and so on. @@ -1333,7 +1333,7 @@ extern "C" { /** PMS_DMA_DMA2D_JPEG_PMS_W_REG register * 2D-DMA JPEG write permission control register */ -#define PMS_DMA_DMA2D_JPEG_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1a8) +#define PMS_DMA_DMA2D_JPEG_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1a8) /** PMS_DMA_DMA2D_JPEG_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to write 32 address ranges requested by JPEG. Bit 0 * corresponds to region0, and so on. @@ -1348,7 +1348,7 @@ extern "C" { /** PMS_DMA_USB_PMS_R_REG register * High-speed USB 2.0 OTG read permission control register */ -#define PMS_DMA_USB_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1ac) +#define PMS_DMA_USB_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1ac) /** PMS_DMA_USB_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for high-speed USB 2.0 OTG to access 32 address ranges. * Bit 0 corresponds to region0, and so on. @@ -1363,7 +1363,7 @@ extern "C" { /** PMS_DMA_USB_PMS_W_REG register * High-speed USB 2.0 OTG write permission control register */ -#define PMS_DMA_USB_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1b0) +#define PMS_DMA_USB_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1b0) /** PMS_DMA_USB_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for high-speed USB 2.0 OTG to access 32 address ranges. * Bit 0 corresponds to region0, and so on. @@ -1378,7 +1378,7 @@ extern "C" { /** PMS_DMA_GMAC_PMS_R_REG register * EMAC read permission control register */ -#define PMS_DMA_GMAC_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1b4) +#define PMS_DMA_GMAC_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1b4) /** PMS_DMA_GMAC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for EMAC to access 32 address ranges. Bit 0 corresponds * to region0, and so on. @@ -1393,7 +1393,7 @@ extern "C" { /** PMS_DMA_GMAC_PMS_W_REG register * EMAC write permission control register */ -#define PMS_DMA_GMAC_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1b8) +#define PMS_DMA_GMAC_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1b8) /** PMS_DMA_GMAC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for EMAC to access 32 address ranges. Bit 0 corresponds * to region0, and so on. @@ -1408,7 +1408,7 @@ extern "C" { /** PMS_DMA_SDMMC_PMS_R_REG register * SDMMC read permission control register */ -#define PMS_DMA_SDMMC_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1bc) +#define PMS_DMA_SDMMC_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1bc) /** PMS_DMA_SDMMC_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for SDMMC to access 32 address ranges. Bit 0 corresponds * to region0, and so on. @@ -1423,7 +1423,7 @@ extern "C" { /** PMS_DMA_SDMMC_PMS_W_REG register * SDMMC write permission control register */ -#define PMS_DMA_SDMMC_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1c0) +#define PMS_DMA_SDMMC_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1c0) /** PMS_DMA_SDMMC_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for SDMMC to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1438,7 +1438,7 @@ extern "C" { /** PMS_DMA_USBOTG11_PMS_R_REG register * Full-speed USB 2.0 OTG full-speed read permission control register */ -#define PMS_DMA_USBOTG11_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1c4) +#define PMS_DMA_USBOTG11_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1c4) /** PMS_DMA_USBOTG11_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for full-speed USB 2.0 OTG to access 32 address ranges. * Bit 0 corresponds to region0, and so on. @@ -1453,7 +1453,7 @@ extern "C" { /** PMS_DMA_USBOTG11_PMS_W_REG register * Full-speed USB 2.0 OTG full-speed write permission control register */ -#define PMS_DMA_USBOTG11_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1c8) +#define PMS_DMA_USBOTG11_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1c8) /** PMS_DMA_USBOTG11_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for full-speed USB 2.0 OTG to access 32 address ranges. * Bit 0 corresponds to region0, and so on. @@ -1468,7 +1468,7 @@ extern "C" { /** PMS_DMA_TRACE0_PMS_R_REG register * TRACE0 read permission control register */ -#define PMS_DMA_TRACE0_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1cc) +#define PMS_DMA_TRACE0_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1cc) /** PMS_DMA_TRACE0_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for TRACE0 to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1483,7 +1483,7 @@ extern "C" { /** PMS_DMA_TRACE0_PMS_W_REG register * TRACE0 write permission control register */ -#define PMS_DMA_TRACE0_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1d0) +#define PMS_DMA_TRACE0_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1d0) /** PMS_DMA_TRACE0_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for TRACE0 to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1498,7 +1498,7 @@ extern "C" { /** PMS_DMA_TRACE1_PMS_R_REG register * TRACE1 read permission control register */ -#define PMS_DMA_TRACE1_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1d4) +#define PMS_DMA_TRACE1_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1d4) /** PMS_DMA_TRACE1_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for TRACE1 to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1513,7 +1513,7 @@ extern "C" { /** PMS_DMA_TRACE1_PMS_W_REG register * TRACE1 write permission control register */ -#define PMS_DMA_TRACE1_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1d8) +#define PMS_DMA_TRACE1_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1d8) /** PMS_DMA_TRACE1_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for TRACE1 to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1528,7 +1528,7 @@ extern "C" { /** PMS_DMA_L2MEM_MON_PMS_R_REG register * L2MEM Monitor read permission control register */ -#define PMS_DMA_L2MEM_MON_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1dc) +#define PMS_DMA_L2MEM_MON_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1dc) /** PMS_DMA_L2MEM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for L2MEM MON. Each bit corresponds to a region. Bit 0 * corresponds to region0, and so on. @@ -1543,7 +1543,7 @@ extern "C" { /** PMS_DMA_L2MEM_MON_PMS_W_REG register * L2MEM Monitor write permission control register */ -#define PMS_DMA_L2MEM_MON_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1e0) +#define PMS_DMA_L2MEM_MON_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1e0) /** PMS_DMA_L2MEM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for L2MEM monitor to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1558,7 +1558,7 @@ extern "C" { /** PMS_DMA_TCM_MON_PMS_R_REG register * TCM Monitor read permission control register */ -#define PMS_DMA_TCM_MON_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1e4) +#define PMS_DMA_TCM_MON_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1e4) /** PMS_DMA_TCM_MON_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for TCM MON. Each bit corresponds to a region. Bit 0 * corresponds to region0, and so on. @@ -1573,7 +1573,7 @@ extern "C" { /** PMS_DMA_TCM_MON_PMS_W_REG register * TCM Monitor write permission control register */ -#define PMS_DMA_TCM_MON_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1e8) +#define PMS_DMA_TCM_MON_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1e8) /** PMS_DMA_TCM_MON_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for TCM monitor to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1588,7 +1588,7 @@ extern "C" { /** PMS_DMA_REGDMA_PMS_R_REG register * REGDMA read permission control register */ -#define PMS_DMA_REGDMA_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1ec) +#define PMS_DMA_REGDMA_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1ec) /** PMS_DMA_REGDMA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for REGDMA. Each bit corresponds to a region. Bit 0 * corresponds to region0, and so on. @@ -1603,7 +1603,7 @@ extern "C" { /** PMS_DMA_REGDMA_PMS_W_REG register * REGDMA write permission control register */ -#define PMS_DMA_REGDMA_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x1f0) +#define PMS_DMA_REGDMA_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x1f0) /** PMS_DMA_REGDMA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for REGDMA. Each bit corresponds to a region. Bit 0 * corresponds to region0, and so on. @@ -1618,7 +1618,7 @@ extern "C" { /** PMS_DMA_H264_PMS_R_REG register * H264 DMA read permission control register */ -#define PMS_DMA_H264_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x1fc) +#define PMS_DMA_H264_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x1fc) /** PMS_DMA_H264_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures read permission for H264 DMA to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1633,7 +1633,7 @@ extern "C" { /** PMS_DMA_H264_PMS_W_REG register * H264 DMA write permission control register */ -#define PMS_DMA_H264_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x200) +#define PMS_DMA_H264_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x200) /** PMS_DMA_H264_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures write permission for H264 DMA to access 32 address ranges. Bit 0 * corresponds to region0, and so on. @@ -1648,7 +1648,7 @@ extern "C" { /** PMS_DMA_DMA2D_PPA_PMS_R_REG register * 2D-DMA PPA read permission control register */ -#define PMS_DMA_DMA2D_PPA_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x204) +#define PMS_DMA_DMA2D_PPA_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x204) /** PMS_DMA_DMA2D_PPA_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to read 32 address ranges requested by PPA * (Pixel-Processing Accelerator). Bit 0 corresponds to region0, and so on. @@ -1663,7 +1663,7 @@ extern "C" { /** PMS_DMA_DMA2D_PPA_PMS_W_REG register * 2D-DMA PPA write permission control register */ -#define PMS_DMA_DMA2D_PPA_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x208) +#define PMS_DMA_DMA2D_PPA_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x208) /** PMS_DMA_DMA2D_PPA_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to write 32 address ranges requested by PPA. Bit 0 * corresponds to region0, and so on. @@ -1678,7 +1678,7 @@ extern "C" { /** PMS_DMA_DMA2D_DUMMY_PMS_R_REG register * 2D-DMA dummy read permission control register */ -#define PMS_DMA_DMA2D_DUMMY_PMS_R_REG (DR_REG_PMS_DMA_BASE + 0x20c) +#define PMS_DMA_DMA2D_DUMMY_PMS_R_REG (DR_REG_DMA_PMS_BASE + 0x20c) /** PMS_DMA_DMA2D_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to read 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. @@ -1693,7 +1693,7 @@ extern "C" { /** PMS_DMA_DMA2D_DUMMY_PMS_W_REG register * 2D-DMA dummy write permission control register */ -#define PMS_DMA_DMA2D_DUMMY_PMS_W_REG (DR_REG_PMS_DMA_BASE + 0x210) +#define PMS_DMA_DMA2D_DUMMY_PMS_W_REG (DR_REG_DMA_PMS_BASE + 0x210) /** PMS_DMA_DMA2D_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures 2D-DMA permission to write 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. @@ -1708,7 +1708,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_DUMMY_R_PMS_REG register * GDMA-AHB dummy read permission control register */ -#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x214) +#define PMS_DMA_AHB_PDMA_DUMMY_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x214) /** PMS_DMA_AHB_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to read 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. @@ -1723,7 +1723,7 @@ extern "C" { /** PMS_DMA_AHB_PDMA_DUMMY_W_PMS_REG register * GDMA-AHB dummy write permission control register */ -#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x218) +#define PMS_DMA_AHB_PDMA_DUMMY_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x218) /** PMS_DMA_AHB_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AHB permission to write 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. @@ -1738,7 +1738,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_DUMMY_R_PMS_REG register * GDMA-AXI dummy read permission control register */ -#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_REG (DR_REG_PMS_DMA_BASE + 0x21c) +#define PMS_DMA_AXI_PDMA_DUMMY_R_PMS_REG (DR_REG_DMA_PMS_BASE + 0x21c) /** PMS_DMA_AXI_PDMA_DUMMY_R_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to read 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. @@ -1753,7 +1753,7 @@ extern "C" { /** PMS_DMA_AXI_PDMA_DUMMY_W_PMS_REG register * GDMA-AXI dummy write permission control register */ -#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_REG (DR_REG_PMS_DMA_BASE + 0x220) +#define PMS_DMA_AXI_PDMA_DUMMY_W_PMS_REG (DR_REG_DMA_PMS_BASE + 0x220) /** PMS_DMA_AXI_PDMA_DUMMY_W_PMS : R/W; bitpos: [31:0]; default: 4294967295; * Configures GDMA-AXI permission to write 32 address ranges requested by Dummy. Bit 0 * corresponds to region0, and so on. diff --git a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h index e4135f4f897..903bfc178b5 100644 --- a/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/hp2lp_peri_pms_reg.h @@ -14,7 +14,7 @@ extern "C" { /** PMS_HP2LP_PERI_PMS_DATE_REG register * Version control register */ -#define PMS_HP2LP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +#define PMS_HP2LP_PERI_PMS_DATE_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x0) /** PMS_HP2LP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294790; * Version control register */ @@ -26,7 +26,7 @@ extern "C" { /** PMS_HP2LP_PERI_PMS_CLK_EN_REG register * Clock gating register */ -#define PMS_HP2LP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +#define PMS_HP2LP_PERI_PMS_CLK_EN_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x4) /** PMS_HP2LP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether to keep the clock always on. * 0: Enable automatic clock gating @@ -40,7 +40,7 @@ extern "C" { /** PMS_HP_CORE0_MM_PMS_REG0_REG register * Permission control register0 for HP CPU0 in machine mode */ -#define PMS_HP_CORE0_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +#define PMS_HP_CORE0_MM_PMS_REG0_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x8) /** PMS_HP_CORE0_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in machine mode has permission to access LP System * Registers. @@ -267,7 +267,7 @@ extern "C" { /** PMS_HP_CORE0_UM_PMS_REG0_REG register * Permission control register0 for HP CPU0 in user mode */ -#define PMS_HP_CORE0_UM_PMS_REG0_REG (DR_REG_PMS_BASE + 0xc) +#define PMS_HP_CORE0_UM_PMS_REG0_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0xc) /** PMS_HP_CORE0_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in user mode has permission to access LP System * Registers. @@ -492,7 +492,7 @@ extern "C" { /** PMS_HP_CORE1_MM_PMS_REG0_REG register * Permission control register0 for HP CPU1 in machine mode */ -#define PMS_HP_CORE1_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x10) +#define PMS_HP_CORE1_MM_PMS_REG0_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x10) /** PMS_HP_CORE1_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in machine mode has permission to access LP System * Registers. @@ -719,7 +719,7 @@ extern "C" { /** PMS_HP_CORE1_UM_PMS_REG0_REG register * Permission control register0 for HP CPU1 in user mode */ -#define PMS_HP_CORE1_UM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x14) +#define PMS_HP_CORE1_UM_PMS_REG0_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x14) /** PMS_HP_CORE1_UM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in user mode has permission to access LP System * Registers. @@ -944,7 +944,7 @@ extern "C" { /** PMS_REGDMA_LP_PERI_PMS_REG register * LP Peripheral Permission register for REGDMA */ -#define PMS_REGDMA_LP_PERI_PMS_REG (DR_REG_PMS_BASE + 0x18) +#define PMS_REGDMA_LP_PERI_PMS_REG (DR_REG_HP2LP_PERI_PMS_BASE + 0x18) /** PMS_REGDMA_PERI_LP_SRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether REGDMA has permission to access LP SRAM. * 0: Not allowed diff --git a/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h index c7c82bec2fa..a097d8e43f1 100644 --- a/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/hp_peri_pms_reg.h @@ -14,7 +14,7 @@ extern "C" { /** PMS_HP_PERI_PMS_DATE_REG register * Version control register */ -#define PMS_HP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +#define PMS_HP_PERI_PMS_DATE_REG (DR_REG_HP_PERI_PMS_BASE + 0x0) /** PMS_HP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294537; * Version control register. */ @@ -26,7 +26,7 @@ extern "C" { /** PMS_HP_PERI_PMS_CLK_EN_REG register * Clock gating register */ -#define PMS_HP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +#define PMS_HP_PERI_PMS_CLK_EN_REG (DR_REG_HP_PERI_PMS_BASE + 0x4) /** PMS_HP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether to keep the clock always on. * 0: Enable automatic clock gating @@ -40,7 +40,7 @@ extern "C" { /** PMS_CORE0_MM_HP_PERI_PMS_REG0_REG register * Permission control register0 for HP CPU0 in machine mode */ -#define PMS_CORE0_MM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +#define PMS_CORE0_MM_HP_PERI_PMS_REG0_REG (DR_REG_HP_PERI_PMS_BASE + 0x8) /** PMS_CORE0_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in machine mode has permission to access external RAM * without going through cache. @@ -140,7 +140,7 @@ extern "C" { /** PMS_CORE0_MM_HP_PERI_PMS_REG1_REG register * Permission control register1 for HP CPU0 in machine mode */ -#define PMS_CORE0_MM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0xc) +#define PMS_CORE0_MM_HP_PERI_PMS_REG1_REG (DR_REG_HP_PERI_PMS_BASE + 0xc) /** PMS_CORE0_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in machine mode has permission to access HP high-speed * USB 2.0 OTG. @@ -421,7 +421,7 @@ extern "C" { /** PMS_CORE0_MM_HP_PERI_PMS_REG2_REG register * Permission control register2 for HP CPU0 in machine mode */ -#define PMS_CORE0_MM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x10) +#define PMS_CORE0_MM_HP_PERI_PMS_REG2_REG (DR_REG_HP_PERI_PMS_BASE + 0x10) /** PMS_CORE0_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in machine mode has permission to access HP MCPWM0. * 0: Not allowed @@ -702,7 +702,7 @@ extern "C" { /** PMS_CORE0_MM_HP_PERI_PMS_REG3_REG register * Permission control register3 for HP CPU0 in machine mode */ -#define PMS_CORE0_MM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x14) +#define PMS_CORE0_MM_HP_PERI_PMS_REG3_REG (DR_REG_HP_PERI_PMS_BASE + 0x14) /** PMS_CORE0_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in machine mode has permission to access HP GPIO Matrix. * 0: Not allowed @@ -754,7 +754,7 @@ extern "C" { /** PMS_CORE0_UM_HP_PERI_PMS_REG0_REG register * Permission control register0 for HP CPU0 in user mode */ -#define PMS_CORE0_UM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x18) +#define PMS_CORE0_UM_HP_PERI_PMS_REG0_REG (DR_REG_HP_PERI_PMS_BASE + 0x18) /** PMS_CORE0_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in user mode has permission to access external RAM * without going through cache. @@ -853,7 +853,7 @@ extern "C" { /** PMS_CORE0_UM_HP_PERI_PMS_REG1_REG register * Permission control register1 for HP CPU0 in user mode */ -#define PMS_CORE0_UM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x1c) +#define PMS_CORE0_UM_HP_PERI_PMS_REG1_REG (DR_REG_HP_PERI_PMS_BASE + 0x1c) /** PMS_CORE0_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in user mode has permission to access HP high-speed USB * 2.0 OTG. @@ -1128,7 +1128,7 @@ extern "C" { /** PMS_CORE0_UM_HP_PERI_PMS_REG2_REG register * Permission control register2 for HP CPU0 in user mode */ -#define PMS_CORE0_UM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x20) +#define PMS_CORE0_UM_HP_PERI_PMS_REG2_REG (DR_REG_HP_PERI_PMS_BASE + 0x20) /** PMS_CORE0_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in user mode has permission to access HP MCPWM0. * 0: Not allowed @@ -1407,7 +1407,7 @@ extern "C" { /** PMS_CORE0_UM_HP_PERI_PMS_REG3_REG register * Permission control register3 for HP CPU0 in user mode */ -#define PMS_CORE0_UM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x24) +#define PMS_CORE0_UM_HP_PERI_PMS_REG3_REG (DR_REG_HP_PERI_PMS_BASE + 0x24) /** PMS_CORE0_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU0 in user mode has permission to access HP GPIO Matrix. * 0: Not allowed @@ -1458,7 +1458,7 @@ extern "C" { /** PMS_CORE1_MM_HP_PERI_PMS_REG0_REG register * Permission control register0 for HP CPU1 in machine mode */ -#define PMS_CORE1_MM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x28) +#define PMS_CORE1_MM_HP_PERI_PMS_REG0_REG (DR_REG_HP_PERI_PMS_BASE + 0x28) /** PMS_CORE1_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in machine mode has permission to access external RAM * without going through cache. @@ -1558,7 +1558,7 @@ extern "C" { /** PMS_CORE1_MM_HP_PERI_PMS_REG1_REG register * Permission control register1 for HP CPU1 in machine mode */ -#define PMS_CORE1_MM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x2c) +#define PMS_CORE1_MM_HP_PERI_PMS_REG1_REG (DR_REG_HP_PERI_PMS_BASE + 0x2c) /** PMS_CORE1_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in machine mode has permission to access HP high-speed * USB 2.0 OTG. @@ -1839,7 +1839,7 @@ extern "C" { /** PMS_CORE1_MM_HP_PERI_PMS_REG2_REG register * Permission control register2 for HP CPU1 in machine mode */ -#define PMS_CORE1_MM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x30) +#define PMS_CORE1_MM_HP_PERI_PMS_REG2_REG (DR_REG_HP_PERI_PMS_BASE + 0x30) /** PMS_CORE1_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in machine mode has permission to access HP MCPWM0. * 0: Not allowed @@ -2120,7 +2120,7 @@ extern "C" { /** PMS_CORE1_MM_HP_PERI_PMS_REG3_REG register * Permission control register3 for HP CPU1 in machine mode */ -#define PMS_CORE1_MM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x34) +#define PMS_CORE1_MM_HP_PERI_PMS_REG3_REG (DR_REG_HP_PERI_PMS_BASE + 0x34) /** PMS_CORE1_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in machine mode has permission to access HP GPIO Matrix. * 0: Not allowed @@ -2172,7 +2172,7 @@ extern "C" { /** PMS_CORE1_UM_HP_PERI_PMS_REG0_REG register * Permission control register0 for HP CPU1 in user mode */ -#define PMS_CORE1_UM_HP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x38) +#define PMS_CORE1_UM_HP_PERI_PMS_REG0_REG (DR_REG_HP_PERI_PMS_BASE + 0x38) /** PMS_CORE1_UM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in user mode has permission to access external RAM * without going through cache. @@ -2271,7 +2271,7 @@ extern "C" { /** PMS_CORE1_UM_HP_PERI_PMS_REG1_REG register * Permission control register1 for HP CPU1 in user mode */ -#define PMS_CORE1_UM_HP_PERI_PMS_REG1_REG (DR_REG_PMS_BASE + 0x3c) +#define PMS_CORE1_UM_HP_PERI_PMS_REG1_REG (DR_REG_HP_PERI_PMS_BASE + 0x3c) /** PMS_CORE1_UM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in user mode has permission to access HP high-speed USB * 2.0 OTG. @@ -2546,7 +2546,7 @@ extern "C" { /** PMS_CORE1_UM_HP_PERI_PMS_REG2_REG register * Permission control register2 for HP CPU1 in user mode */ -#define PMS_CORE1_UM_HP_PERI_PMS_REG2_REG (DR_REG_PMS_BASE + 0x40) +#define PMS_CORE1_UM_HP_PERI_PMS_REG2_REG (DR_REG_HP_PERI_PMS_BASE + 0x40) /** PMS_CORE1_UM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in user mode has permission to access HP MCPWM0. * 0: Not allowed @@ -2825,7 +2825,7 @@ extern "C" { /** PMS_CORE1_UM_HP_PERI_PMS_REG3_REG register * Permission control register3 for HP CPU1 in user mode */ -#define PMS_CORE1_UM_HP_PERI_PMS_REG3_REG (DR_REG_PMS_BASE + 0x44) +#define PMS_CORE1_UM_HP_PERI_PMS_REG3_REG (DR_REG_HP_PERI_PMS_BASE + 0x44) /** PMS_CORE1_UM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether HP CPU1 in user mode has permission to access HP GPIO Matrix. * 0: Not allowed @@ -2876,7 +2876,7 @@ extern "C" { /** PMS_REGDMA_PERI_PMS_REG register * Permission register for REGDMA */ -#define PMS_REGDMA_PERI_PMS_REG (DR_REG_PMS_BASE + 0x48) +#define PMS_REGDMA_PERI_PMS_REG (DR_REG_HP_PERI_PMS_BASE + 0x48) /** PMS_REGDMA_PERI_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether REGDMA has permission to access all HP peripheral (including CPU * peripherals). diff --git a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h index 6e115cb7037..ba58a6cfde6 100644 --- a/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/lp2hp_peri_pms_reg.h @@ -14,7 +14,7 @@ extern "C" { /** PMS_LP2HP_PERI_PMS_DATE_REG register * Version control register */ -#define PMS_LP2HP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +#define PMS_LP2HP_PERI_PMS_DATE_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0x0) /** PMS_LP2HP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294790; * Version control register. */ @@ -26,7 +26,7 @@ extern "C" { /** PMS_LP2HP_PERI_PMS_CLK_EN_REG register * Clock gating register */ -#define PMS_LP2HP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +#define PMS_LP2HP_PERI_PMS_CLK_EN_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0x4) /** PMS_LP2HP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether to keep the clock always on. * 0: Enable automatic clock gating. @@ -40,7 +40,7 @@ extern "C" { /** PMS_LP_MM_PMS_REG0_REG register * Permission control register0 for the LP CPU in machine mode */ -#define PMS_LP_MM_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +#define PMS_LP_MM_PMS_REG0_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0x8) /** PMS_LP_MM_PSRAM_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether the LP CPU in machine mode has permission to access external RAM * without going through cache. @@ -141,7 +141,7 @@ extern "C" { /** PMS_LP_MM_PMS_REG1_REG register * Permission control register1 for the LP CPU in machine mode */ -#define PMS_LP_MM_PMS_REG1_REG (DR_REG_PMS_BASE + 0x30) +#define PMS_LP_MM_PMS_REG1_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0x30) /** PMS_LP_MM_HP_USBOTG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether the LP CPU in machine mode has permission to access HP * high-speed USB 2.0 OTG. @@ -422,7 +422,7 @@ extern "C" { /** PMS_LP_MM_PMS_REG2_REG register * Permission control register2 for the LP CPU in machine mode */ -#define PMS_LP_MM_PMS_REG2_REG (DR_REG_PMS_BASE + 0xa4) +#define PMS_LP_MM_PMS_REG2_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0xa4) /** PMS_LP_MM_HP_MCPWM0_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether the LP CPU in machine mode has permission to access HP MCPWM0. * 0: Not allowed @@ -703,7 +703,7 @@ extern "C" { /** PMS_LP_MM_PMS_REG3_REG register * Permission control register3 for the LP CPU in machine mode */ -#define PMS_LP_MM_PMS_REG3_REG (DR_REG_PMS_BASE + 0x11c) +#define PMS_LP_MM_PMS_REG3_REG (DR_REG_LP2HP_PERI_PMS_BASE + 0x11c) /** PMS_LP_MM_HP_GPIO_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether the LP CPU in machine mode has permission to access HP GPIO * Matrix. diff --git a/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h b/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h index f95a5a3b853..7074bc5236f 100644 --- a/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h +++ b/components/soc/esp32p4/include/soc/lp_peri_pms_reg.h @@ -14,7 +14,7 @@ extern "C" { /** PMS_LP_PERI_PMS_DATE_REG register * Version control register */ -#define PMS_LP_PERI_PMS_DATE_REG (DR_REG_PMS_BASE + 0x0) +#define PMS_LP_PERI_PMS_DATE_REG (DR_REG_LP_PERI_PMS_BASE + 0x0) /** PMS_LP_PERI_PMS_DATE : R/W; bitpos: [31:0]; default: 2294537; * Version control register */ @@ -26,7 +26,7 @@ extern "C" { /** PMS_LP_PERI_PMS_CLK_EN_REG register * Clock gating register */ -#define PMS_LP_PERI_PMS_CLK_EN_REG (DR_REG_PMS_BASE + 0x4) +#define PMS_LP_PERI_PMS_CLK_EN_REG (DR_REG_LP_PERI_PMS_BASE + 0x4) /** PMS_LP_PERI_PMS_CLK_EN : R/W; bitpos: [0]; default: 1; * Configures whether to keep the clock always on. * 0: Enable automatic clock gating @@ -40,7 +40,7 @@ extern "C" { /** PMS_LP_MM_LP_PERI_PMS_REG0_REG register * Permission control register0 for LP CPU in machine mode */ -#define PMS_LP_MM_LP_PERI_PMS_REG0_REG (DR_REG_PMS_BASE + 0x8) +#define PMS_LP_MM_LP_PERI_PMS_REG0_REG (DR_REG_LP_PERI_PMS_BASE + 0x8) /** PMS_LP_MM_LP_SYSREG_ALLOW : R/W; bitpos: [0]; default: 1; * Configures whether LP CPU in machine mode has permission to access LP system * registers. @@ -272,7 +272,7 @@ extern "C" { /** PMS_PERI_REGION0_LOW_REG register * Region0 start address configuration register */ -#define PMS_PERI_REGION0_LOW_REG (DR_REG_PMS_BASE + 0xc) +#define PMS_PERI_REGION0_LOW_REG (DR_REG_LP_PERI_PMS_BASE + 0xc) /** PMS_PERI_REGION0_LOW : R/W; bitpos: [31:2]; default: 0; * Configures the high 30 bits of the start address of peripheral register's region0. */ @@ -284,7 +284,7 @@ extern "C" { /** PMS_PERI_REGION0_HIGH_REG register * Region0 end address configuration register */ -#define PMS_PERI_REGION0_HIGH_REG (DR_REG_PMS_BASE + 0x10) +#define PMS_PERI_REGION0_HIGH_REG (DR_REG_LP_PERI_PMS_BASE + 0x10) /** PMS_PERI_REGION0_HIGH : R/W; bitpos: [31:2]; default: 1073741823; * Configures the high 30 bits of the end address of peripheral register's region0. */ @@ -296,7 +296,7 @@ extern "C" { /** PMS_PERI_REGION1_LOW_REG register * Region1 start address configuration register */ -#define PMS_PERI_REGION1_LOW_REG (DR_REG_PMS_BASE + 0x14) +#define PMS_PERI_REGION1_LOW_REG (DR_REG_LP_PERI_PMS_BASE + 0x14) /** PMS_PERI_REGION1_LOW : R/W; bitpos: [31:2]; default: 0; * Configures the high 30 bits of the start address of peripheral register's region1. */ @@ -308,7 +308,7 @@ extern "C" { /** PMS_PERI_REGION1_HIGH_REG register * Region1 end address configuration register */ -#define PMS_PERI_REGION1_HIGH_REG (DR_REG_PMS_BASE + 0x18) +#define PMS_PERI_REGION1_HIGH_REG (DR_REG_LP_PERI_PMS_BASE + 0x18) /** PMS_PERI_REGION1_HIGH : R/W; bitpos: [31:2]; default: 1073741823; * Configures the high 30 bits of the end address of peripheral register's region1. */ @@ -320,7 +320,7 @@ extern "C" { /** PMS_PERI_REGION_PMS_REG register * Permission register of region */ -#define PMS_PERI_REGION_PMS_REG (DR_REG_PMS_BASE + 0x1c) +#define PMS_PERI_REGION_PMS_REG (DR_REG_LP_PERI_PMS_BASE + 0x1c) /** PMS_LP_CORE_REGION_PMS : R/W; bitpos: [1:0]; default: 3; * Configures whether LP core in machine mode has permission to access address region0 * and address region1. Bit0 corresponds to region0 and bit1 corresponds to region1. From 79b7e2cd97a3d869bd467788d54cd6267733cf8f Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Mon, 6 May 2024 12:11:56 +0200 Subject: [PATCH 263/548] fix(soc): Fix ROM stack start for esp32c5-mp Update the value SOC_ROM_STACK_START to the expected value from bootloader.ld memory map. --- components/soc/esp32c5/mp/include/soc/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/soc/esp32c5/mp/include/soc/soc.h b/components/soc/esp32c5/mp/include/soc/soc.h index 3cf20c4c3ac..5c3ac9c8e9c 100644 --- a/components/soc/esp32c5/mp/include/soc/soc.h +++ b/components/soc/esp32c5/mp/include/soc/soc.h @@ -208,7 +208,7 @@ #define SOC_DEBUG_HIGH 0x28000000 // Start (highest address) of ROM boot stack, only relevant during early boot -#define SOC_ROM_STACK_START 0x4085c8d0 +#define SOC_ROM_STACK_START 0x4085e9a0 #define SOC_ROM_STACK_SIZE 0x2000 //On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW. From 2ac0fc1f6acb48907cd80919d5497008cf2403b7 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Tue, 7 May 2024 08:06:14 +0200 Subject: [PATCH 264/548] change(heap): Update soc_memory_regions on esp32c5 The array of memory regions is simplyfied by using the macro defined in soc.h (for beta3 and mp respectively). --- components/heap/port/esp32c5/memory_layout.c | 23 +++++++------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/components/heap/port/esp32c5/memory_layout.c b/components/heap/port/esp32c5/memory_layout.c index 6ba81dbd370..5303f4b347e 100644 --- a/components/heap/port/esp32c5/memory_layout.c +++ b/components/heap/port/esp32c5/memory_layout.c @@ -45,11 +45,11 @@ enum { /** * Defined the attributes and allocation priority of each memory on the chip, * The heap allocator will traverse all types of memory types in column High Priority Matching and match the specified caps at first, - * if no memory caps matched or the allocation is failed, it will go to columns Medium Priorty Matching and Low Priority Matching + * if no memory caps matched or the allocation is failed, it will go to columns Medium Priority Matching and Low Priority Matching * in turn to continue matching. */ const soc_memory_type_desc_t soc_memory_types[SOC_MEMORY_TYPE_NUM] = { - /* Mem Type Name High Priority Matching Medium Priorty Matching Low Priority Matching */ + /* Mem Type Name High Priority Matching Medium Priority Matching Low Priority Matching */ [SOC_MEMORY_TYPE_RAM] = { "RAM", { ESP32C5_MEM_COMMON_CAPS | MALLOC_CAP_DMA, 0, 0 }}, [SOC_MEMORY_TYPE_RTCRAM] = { "RTCRAM", { MALLOC_CAP_RTCRAM, ESP32C5_MEM_COMMON_CAPS, 0 }}, #if CONFIG_IDF_TARGET_ESP32C5_MP_VERSION @@ -70,23 +70,16 @@ const size_t soc_memory_type_count = sizeof(soc_memory_types) / sizeof(soc_memor /** * Register the shared buffer area of the last memory block into the heap during heap initialization */ -#define APP_USABLE_DRAM_END (SOC_ROM_STACK_START - SOC_ROM_STACK_SIZE) +#define APP_USABLE_DRAM_END (SOC_ROM_STACK_START - SOC_ROM_STACK_SIZE) const soc_memory_region_t soc_memory_regions[] = { #if CONFIG_SPIRAM && CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - { SOC_EXTRAM_DATA_LOW, (SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW),SOC_MEMORY_TYPE_SPIRAM, 0}, //SPI SRAM, if available + { SOC_EXTRAM_DATA_LOW, (SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW), SOC_MEMORY_TYPE_SPIRAM, 0, false}, //SPI SRAM, if available #endif - { 0x40800000, 0x20000, SOC_MEMORY_TYPE_RAM, 0x40800000, false}, //D/IRAM level0, can be used as trace memory - { 0x40820000, 0x20000, SOC_MEMORY_TYPE_RAM, 0x40820000, false}, //D/IRAM level1, can be used as trace memory -#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION - { 0x40840000, 0x20000, SOC_MEMORY_TYPE_RAM, 0x40840000, false}, //D/IRAM level2, can be used as trace memory - { 0x40860000, (APP_USABLE_DRAM_END-0x40860000), SOC_MEMORY_TYPE_RAM, 0x40860000, false}, //D/IRAM level3, can be used as trace memory -#elif CONFIG_IDF_TARGET_ESP32C5_MP_VERSION - { 0x40840000, (APP_USABLE_DRAM_END-0x40840000), SOC_MEMORY_TYPE_RAM, 0x40840000, false}, //D/IRAM level3, can be used as trace memory -#endif - { APP_USABLE_DRAM_END, (SOC_DIRAM_DRAM_HIGH-APP_USABLE_DRAM_END), SOC_MEMORY_TYPE_RAM, APP_USABLE_DRAM_END, true}, //D/IRAM level3, can be used as trace memory (ROM reserved area) + { SOC_DIRAM_DRAM_LOW, (APP_USABLE_DRAM_END - SOC_DIRAM_DRAM_LOW), SOC_MEMORY_TYPE_RAM, SOC_DIRAM_IRAM_LOW, false}, //D/IRAM, can be used as trace memory + { APP_USABLE_DRAM_END, (SOC_DIRAM_DRAM_HIGH - APP_USABLE_DRAM_END), SOC_MEMORY_TYPE_RAM, APP_USABLE_DRAM_END, true}, //D/IRAM, can be used as trace memory (ROM reserved area) #ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP - { 0x50000000, 0x4000, SOC_MEMORY_TYPE_RTCRAM, 0, false}, //LPRAM + { SOC_RTC_DATA_LOW, (SOC_RTC_DATA_HIGH - SOC_RTC_DATA_LOW), SOC_MEMORY_TYPE_RTCRAM, 0, false}, //LPRAM #endif }; @@ -118,5 +111,5 @@ SOC_RESERVE_MEMORY_REGION((intptr_t)&_rtc_reserved_start, (intptr_t)&_rtc_reserv #ifdef CONFIG_SPIRAM /* Reserve the whole possible SPIRAM region here, spiram.c will add some or all of this * memory to heap depending on the actual SPIRAM chip size. */ -SOC_RESERVE_MEMORY_REGION(SOC_DROM_LOW, SOC_DROM_HIGH, extram_data_region); +SOC_RESERVE_MEMORY_REGION(SOC_EXTRAM_DATA_LOW, SOC_EXTRAM_DATA_HIGH, extram_data_region); #endif From 32c6ee85320dcefc26c3c002bf2dfb3aed33e486 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Thu, 9 May 2024 09:00:54 +0200 Subject: [PATCH 265/548] change(heap): Remove todo of closed ticket in memory_layout.c files Leftover closed ticket removed from memory_layout.c on the following targets: - esp32c5 - esp32c6 - esp32h2 --- components/heap/port/esp32c5/memory_layout.c | 1 - components/heap/port/esp32c6/memory_layout.c | 7 +++---- components/heap/port/esp32h2/memory_layout.c | 7 +++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/components/heap/port/esp32c5/memory_layout.c b/components/heap/port/esp32c5/memory_layout.c index 5303f4b347e..b7b00b804ee 100644 --- a/components/heap/port/esp32c5/memory_layout.c +++ b/components/heap/port/esp32c5/memory_layout.c @@ -102,7 +102,6 @@ SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start, dram_d SOC_RESERVE_MEMORY_REGION((intptr_t)&_iram_start, (intptr_t)&_iram_end, iram_code); #ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP -// TODO: IDF-6019 check reserved lp mem region SOC_RESERVE_MEMORY_REGION(SOC_RTC_DRAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data); #endif diff --git a/components/heap/port/esp32c6/memory_layout.c b/components/heap/port/esp32c6/memory_layout.c index 755e09b0b58..3c0aceb7b0d 100644 --- a/components/heap/port/esp32c6/memory_layout.c +++ b/components/heap/port/esp32c6/memory_layout.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -42,11 +42,11 @@ enum { /** * Defined the attributes and allocation priority of each memory on the chip, * The heap allocator will traverse all types of memory types in column High Priority Matching and match the specified caps at first, - * if no memory caps matched or the allocation is failed, it will go to columns Medium Priorty Matching and Low Priority Matching + * if no memory caps matched or the allocation is failed, it will go to columns Medium Priority Matching and Low Priority Matching * in turn to continue matching. */ const soc_memory_type_desc_t soc_memory_types[SOC_MEMORY_TYPE_NUM] = { - /* Mem Type Name High Priority Matching Medium Priorty Matching Low Priority Matching */ + /* Mem Type Name High Priority Matching Medium Priority Matching Low Priority Matching */ [SOC_MEMORY_TYPE_RAM] = { "RAM", { ESP32C6_MEM_COMMON_CAPS | MALLOC_CAP_DMA, 0, 0 }}, [SOC_MEMORY_TYPE_RTCRAM] = { "RTCRAM", { MALLOC_CAP_RTCRAM, ESP32C6_MEM_COMMON_CAPS, 0 }}, }; @@ -96,7 +96,6 @@ SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start, dram_d SOC_RESERVE_MEMORY_REGION((intptr_t)&_iram_start, (intptr_t)&_iram_end, iram_code); #ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP -// TODO: IDF-6019 check reserved lp mem region SOC_RESERVE_MEMORY_REGION(SOC_RTC_DRAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data); #endif diff --git a/components/heap/port/esp32h2/memory_layout.c b/components/heap/port/esp32h2/memory_layout.c index 5a562df7f2c..224e2ec454d 100644 --- a/components/heap/port/esp32h2/memory_layout.c +++ b/components/heap/port/esp32h2/memory_layout.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,11 +40,11 @@ enum { /** * Defined the attributes and allocation priority of each memory on the chip, * The heap allocator will traverse all types of memory types in column High Priority Matching and match the specified caps at first, - * if no memory caps matched or the allocation is failed, it will go to columns Medium Priorty Matching and Low Priority Matching + * if no memory caps matched or the allocation is failed, it will go to columns Medium Priority Matching and Low Priority Matching * in turn to continue matching. */ const soc_memory_type_desc_t soc_memory_types[SOC_MEMORY_TYPE_NUM] = { - /* Mem Type Name High Priority Matching Medium Priorty Matching Low Priority Matching */ + /* Mem Type Name High Priority Matching Medium Priority Matching Low Priority Matching */ [SOC_MEMORY_TYPE_RAM] = { "RAM", { ESP32H2_MEM_COMMON_CAPS | MALLOC_CAP_DMA, 0, 0 }}, [SOC_MEMORY_TYPE_RTCRAM] = { "RTCRAM", { MALLOC_CAP_RTCRAM, ESP32H2_MEM_COMMON_CAPS, 0 }}, }; @@ -95,7 +95,6 @@ SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start, dram_d SOC_RESERVE_MEMORY_REGION((intptr_t)&_iram_start, (intptr_t)&_iram_end, iram_code); #ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP -// TODO: IDF-6019 check reserved lp mem region SOC_RESERVE_MEMORY_REGION(SOC_RTC_DRAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data); #endif From 04cf7d12300234cee7d709d1f37749dd0969a72d Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Thu, 13 Jun 2024 12:29:55 +0200 Subject: [PATCH 266/548] fix(tools/idf_tools.py): Improve the warning message about the environment --- tools/idf_tools.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 4c0cfe8b68e..1b9dc6d7d64 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -2139,7 +2139,8 @@ def check_python_venv_compatibility(idf_python_env_path: str, idf_version: str) raise SystemExit(1) except OSError as e: # perhaps the environment was generated before the support for VENV_VER_FILE was added - warn(f'Error while accessing the ESP-IDF version file in the Python environment: {e}') + warn(f'The following issue occurred while accessing the ESP-IDF version file in the Python environment: {e}. ' + '(Diagnostic information. It can be ignored.)') def action_export(args: Any) -> None: @@ -2638,7 +2639,8 @@ def action_install_python_env(args): # type: ignore with open(os.path.join(idf_python_env_path, VENV_VER_FILE), 'w') as f: f.write(idf_version) except OSError as e: - warn(f'Error while generating the ESP-IDF version file in the Python environment: {e}') + warn(f'The following issue occurred while generating the ESP-IDF version file in the Python environment: {e}. ' + '(Diagnostic information. It can be ignored.)') else: # The embeddable Python for Windows doesn't have the built-in venv module From 8887599119af4e5dbba1edd4e0b76377870279f5 Mon Sep 17 00:00:00 2001 From: Mohammad-Mohsen Aseman-Manzar Date: Tue, 11 Jun 2024 16:13:34 +0330 Subject: [PATCH 267/548] Fix stack overflow bug for `examples/bluetooth/esp_hid_device` when using esp32s3 with nimble Related to https://github.com/espressif/esp-idf/commit/60354c39a9338961adce8e2fb536f83571ebd82c --- components/esp_hid/src/nimble_hidd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_hid/src/nimble_hidd.c b/components/esp_hid/src/nimble_hidd.c index eec5fc4abff..dc37302e05f 100644 --- a/components/esp_hid/src/nimble_hidd.c +++ b/components/esp_hid/src/nimble_hidd.c @@ -657,7 +657,7 @@ esp_err_t esp_ble_hidd_dev_init(esp_hidd_dev_t *dev_p, const esp_hid_device_conf .queue_size = 5, .task_name = "ble_hidd_events", .task_priority = uxTaskPriorityGet(NULL), - .task_stack_size = 2048, + .task_stack_size = 4096, .task_core_id = tskNO_AFFINITY }; rc = esp_event_loop_create(&event_task_args, &s_dev->event_loop_handle); From ceb6ec92b330061296ef7f93ce5809b7995d956e Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 14 Jun 2024 16:38:44 +0200 Subject: [PATCH 268/548] docs(freertos): Enabled FreeRTOS docs for esp32c5 This commit enables the FreeRTOS doc build for esp32c5. --- docs/docs_not_updated/esp32c5.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 8517a165184..e8504f7f2b7 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -142,9 +142,7 @@ api-reference/system/chip_revision.rst api-reference/system/async_memcpy.rst api-reference/system/random.rst api-reference/system/esp_timer.rst -api-reference/system/freertos.rst api-reference/system/system_time.rst -api-reference/system/freertos_additions.rst api-reference/system/power_management.rst api-reference/system/inc/show-efuse-table_ESP32-C5.rst api-reference/system/inc/revisions_ESP32-C5.rst @@ -152,7 +150,6 @@ api-reference/system/inc/espefuse_summary_ESP32-C5.rst api-reference/system/inc/power_management_esp32c5.rst api-reference/system/mm.rst api-reference/system/esp_https_ota.rst -api-reference/system/freertos_idf.rst api-reference/bluetooth/esp_spp.rst api-reference/bluetooth/esp_l2cap_bt.rst api-reference/bluetooth/esp_hidd.rst From f3ebebb1dd1246b20337fd91f04b8ae7df60d409 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Thu, 6 Jun 2024 20:39:46 +0800 Subject: [PATCH 269/548] fix(gptimer): re-enable test on P4 Remove timer_get_counter_time_sec in the ISR. Keep ISR as fast as possible and not allow FPU usage. --- components/driver/test_apps/.build-test-rules.yml | 4 ---- .../legacy_timer_driver/main/test_legacy_timer.c | 11 ++++------- .../legacy_timer_driver/pytest_legacy_timer_driver.py | 2 -- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index 996eacf13c8..bb61cea137c 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -78,10 +78,6 @@ components/driver/test_apps/legacy_sigma_delta_driver: components/driver/test_apps/legacy_timer_driver: disable: - if: SOC_GPTIMER_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: test not pass, should be re-enable # TODO: IDF-8962 depends_filepatterns: - components/driver/deprecated/**/*timer* diff --git a/components/driver/test_apps/legacy_timer_driver/main/test_legacy_timer.c b/components/driver/test_apps/legacy_timer_driver/main/test_legacy_timer.c index 60c448ac41e..77c1eb50806 100644 --- a/components/driver/test_apps/legacy_timer_driver/main/test_legacy_timer.c +++ b/components/driver/test_apps/legacy_timer_driver/main/test_legacy_timer.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -62,7 +62,6 @@ static bool test_timer_group_isr_cb(void *arg) const timer_group_t timer_group = info->timer_group; const timer_idx_t timer_idx = info->timer_idx; uint64_t timer_val; - double time; uint64_t alarm_value; timer_event_t evt; alarm_flag = true; @@ -70,13 +69,11 @@ static bool test_timer_group_isr_cb(void *arg) timer_group_clr_intr_status_in_isr(timer_group, timer_idx); esp_rom_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx); timer_get_counter_value(timer_group, timer_idx, &timer_val); - timer_get_counter_time_sec(timer_group, timer_idx, &time); evt.type = TIMER_AUTORELOAD_EN; } else { timer_group_clr_intr_status_in_isr(timer_group, timer_idx); esp_rom_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx); timer_get_counter_value(timer_group, timer_idx, &timer_val); - timer_get_counter_time_sec(timer_group, timer_idx, &time); timer_get_alarm_value(timer_group, timer_idx, &alarm_value); timer_set_counter_value(timer_group, timer_idx, 0); evt.type = TIMER_AUTORELOAD_DIS; @@ -363,7 +360,7 @@ TEST_CASE("Timer_read_counter_value", "[hw_timer]") timer_config_t config = { .clk_src = TIMER_SRC_CLK_DEFAULT, .divider = clk_src_hz / TEST_TIMER_RESOLUTION_HZ, - .alarm_en = TIMER_ALARM_EN, + .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, .counter_en = TIMER_START, @@ -469,7 +466,7 @@ TEST_CASE("Timer_counter_direction", "[hw_timer]") timer_config_t config = { .clk_src = TIMER_SRC_CLK_DEFAULT, .divider = clk_src_hz / TEST_TIMER_RESOLUTION_HZ, - .alarm_en = TIMER_ALARM_EN, + .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, .counter_en = TIMER_START, @@ -508,7 +505,7 @@ TEST_CASE("Timer_divider", "[hw_timer]") timer_config_t config = { .clk_src = TIMER_SRC_CLK_DEFAULT, .divider = clk_src_hz / TEST_TIMER_RESOLUTION_HZ, - .alarm_en = TIMER_ALARM_EN, + .alarm_en = TIMER_ALARM_DIS, .auto_reload = TIMER_AUTORELOAD_EN, .counter_dir = TIMER_COUNT_UP, .counter_en = TIMER_START, diff --git a/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py b/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py index 43c6726f689..726f05adc7c 100644 --- a/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py +++ b/components/driver/test_apps/legacy_timer_driver/pytest_legacy_timer_driver.py @@ -1,11 +1,9 @@ # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 support TBD') # TODO: IDF-8962 @pytest.mark.supported_targets @pytest.mark.generic @pytest.mark.parametrize('config', [ From 81b43829a2e425d47f4d030d4f1a3e22c14b3e36 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 17 Jun 2024 14:09:23 +0530 Subject: [PATCH 270/548] fix(nimble): Clear resource before re-starting advertising --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index a1f5999ee87..73112f9b406 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit a1f5999ee87d73c1d71e1e90991fafde4a951ec3 +Subproject commit 73112f9b4068ef7dc541c88c555ff829bebb9f8f From 8a668d6c03a1197e0ddddeddb3e17d6de807949a Mon Sep 17 00:00:00 2001 From: Fu Hanxi Date: Mon, 17 Jun 2024 13:48:12 +0200 Subject: [PATCH 271/548] ci: disable failing esp32c5 builds --- components/driver/test_apps/.build-test-rules.yml | 3 +++ components/esp_driver_ledc/test_apps/.build-test-rules.yml | 3 +++ components/esp_rom/test_apps/.build-test-rules.yml | 3 +++ examples/peripherals/.build-test-rules.yml | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index 996eacf13c8..f445e1381c4 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -54,6 +54,9 @@ components/driver/test_apps/legacy_mcpwm_driver: components/driver/test_apps/legacy_pcnt_driver: disable: - if: SOC_PCNT_SUPPORTED != 1 + - if: IDF_TARGET == "esp32c5" + temporary: true + reason: build failed. track in IDFCI-2204 depends_filepatterns: - components/driver/deprecated/**/*pcnt* diff --git a/components/esp_driver_ledc/test_apps/.build-test-rules.yml b/components/esp_driver_ledc/test_apps/.build-test-rules.yml index 00d99826d13..b18d676013a 100644 --- a/components/esp_driver_ledc/test_apps/.build-test-rules.yml +++ b/components/esp_driver_ledc/test_apps/.build-test-rules.yml @@ -3,6 +3,9 @@ components/esp_driver_ledc/test_apps/ledc: disable: - if: SOC_LEDC_SUPPORTED != 1 + - if: IDF_TARGET == "esp32c5" + temporary: true + reason: build failed. track in IDFCI-2204 disable_test: - if: IDF_TARGET == "esp32p4" temporary: true diff --git a/components/esp_rom/test_apps/.build-test-rules.yml b/components/esp_rom/test_apps/.build-test-rules.yml index 7f94e30b596..dab1a4d00e8 100644 --- a/components/esp_rom/test_apps/.build-test-rules.yml +++ b/components/esp_rom/test_apps/.build-test-rules.yml @@ -7,6 +7,9 @@ components/esp_rom/test_apps/linux_rom_apis: components/esp_rom/test_apps/rom_impl_components: disable: # For ROM impl build tests, disable them if none of the tested features are supported in the ROM + - if: CONFIG_NAME == "no_rom_impl_components" and IDF_TARGET == "esp32c5" + temporary: true + reason: build failed. track in IDFCI-2204 - if: CONFIG_NAME == "rom_impl_components" and ((ESP_ROM_HAS_HAL_WDT != 1 and ESP_ROM_HAS_HAL_SYSTIMER != 1) and (ESP_ROM_HAS_HEAP_TLSF != 1 and ESP_ROM_HAS_SPI_FLASH != 1)) - if: CONFIG_NAME == "no_rom_impl_components" and ((ESP_ROM_HAS_HAL_WDT != 1 and ESP_ROM_HAS_HAL_SYSTIMER != 1) and (ESP_ROM_HAS_HEAP_TLSF != 1 and ESP_ROM_HAS_SPI_FLASH != 1)) diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 7397280ae0a..cac8e376f5d 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -190,12 +190,18 @@ examples/peripherals/lcd/tjpgd: examples/peripherals/ledc: disable: - if: SOC_LEDC_SUPPORTED != 1 + - if: IDF_TARGET == "esp32c5" + temporary: true + reason: build failed. track in IDFCI-2204 depends_components: - esp_driver_ledc examples/peripherals/ledc/ledc_gamma_curve_fade: disable: - if: SOC_LEDC_SUPPORTED != 1 or SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED != 1 + - if: IDF_TARGET == "esp32c5" + temporary: true + reason: build failed. track in IDFCI-22041 depends_components: - esp_driver_ledc From fbd6c9737e73e88390efad9589264f05ac3e2c83 Mon Sep 17 00:00:00 2001 From: LonerDan Date: Tue, 18 Jun 2024 12:49:43 +0200 Subject: [PATCH 272/548] fix(ulp-risc-v): Set RTC GPIO output mode in the correct register for ULP RISC-V According to the ESP32-S2/S3 TRM, the output pin's mode is set in the RTC_GPIO_PINn_REG by programming the RTC_GPIO_PINn_PAD_DRIVER bit. The current ULP RISC-V RTCIO driver however, incorrectly programs the RTC_IO_TOUCH_PADn_REG register field RTC_IO_TOUCH_PADn_DRV. This commit fixes the bug. --- components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h b/components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h index 11e486c2f6d..504b2e0c913 100644 --- a/components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h +++ b/components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_gpio.h @@ -109,7 +109,7 @@ static inline uint8_t ulp_riscv_gpio_get_level(gpio_num_t gpio_num) static inline void ulp_riscv_gpio_set_output_mode(gpio_num_t gpio_num, rtc_io_out_mode_t mode) { - REG_SET_FIELD(RTC_IO_TOUCH_PAD0_REG + gpio_num * 4, RTC_IO_TOUCH_PAD0_DRV, mode); + REG_SET_FIELD(RTC_GPIO_PIN0_REG + gpio_num * 4, RTC_GPIO_PIN0_PAD_DRIVER, mode); } static inline void ulp_riscv_gpio_pullup(gpio_num_t gpio_num) From dbe5a59412aada650c077988c40a83acea089db4 Mon Sep 17 00:00:00 2001 From: "sonika.rathi" Date: Wed, 19 Jun 2024 08:44:51 +0200 Subject: [PATCH 273/548] docs(storage): update esp32p4 storage programming guide --- docs/docs_not_updated/esp32p4.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 96340c579b6..36f8a2bcbda 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -9,18 +9,6 @@ api-guides/esp-wifi-mesh.rst api-guides/dfu.rst api-guides/current-consumption-measurement-modules.rst api-guides/wifi-security.rst -api-reference/storage/vfs.rst -api-reference/storage/spiffs.rst -api-reference/storage/nvs_encryption.rst -api-reference/storage/wear-levelling.rst -api-reference/storage/fatfs.rst -api-reference/storage/nvs_partition_gen.rst -api-reference/storage/nvs_flash.rst -api-reference/storage/partition.rst -api-reference/storage/mass_mfg.rst -api-reference/storage/fatfsgen.rst -api-reference/storage/index.rst -api-reference/storage/nvs_partition_parse.rst api-reference/peripherals/adc_continuous.rst api-reference/peripherals/adc_oneshot.rst api-reference/peripherals/usb_host.rst From 786b68743b23249f329d3413e6c52f740f3adced Mon Sep 17 00:00:00 2001 From: zhangshuxian Date: Fri, 7 Jun 2024 17:08:44 +0800 Subject: [PATCH 274/548] docs: Delete user guide esp32-s2-devkitm-1 --- .../esp32-s2-devkitm-1-v1-annotated-photo.png | Bin 318123 -> 0 bytes .../esp32-s2-devkitm-1-v1-block-diagram.png | Bin 74964 -> 0 bytes .../esp32-s2-devkitm-1-v1-isometric.png | Bin 213233 -> 0 bytes .../esp32-s2-devkitm-1-v1-pin-layout.png | Bin 393823 -> 0 bytes ...esp32-s2-devkitm-1u-v1-annotated-photo.png | Bin 302111 -> 0 bytes .../esp32-s2-devkitm-1u-v1-isometric.png | Bin 164511 -> 0 bytes docs/en/get-started/index.rst | 2 +- .../esp32s2/user-guide-devkitm-1-v1.rst | 321 ------------------ docs/zh_CN/get-started/index.rst | 2 +- .../esp32s2/user-guide-devkitm-1-v1.rst | 321 ------------------ 10 files changed, 2 insertions(+), 644 deletions(-) delete mode 100644 docs/_static/esp32-s2-devkitm-1-v1-annotated-photo.png delete mode 100644 docs/_static/esp32-s2-devkitm-1-v1-block-diagram.png delete mode 100644 docs/_static/esp32-s2-devkitm-1-v1-isometric.png delete mode 100644 docs/_static/esp32-s2-devkitm-1-v1-pin-layout.png delete mode 100644 docs/_static/esp32-s2-devkitm-1u-v1-annotated-photo.png delete mode 100644 docs/_static/esp32-s2-devkitm-1u-v1-isometric.png delete mode 100644 docs/en/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst delete mode 100644 docs/zh_CN/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst diff --git a/docs/_static/esp32-s2-devkitm-1-v1-annotated-photo.png b/docs/_static/esp32-s2-devkitm-1-v1-annotated-photo.png deleted file mode 100644 index 7da28ae2257282f2ba8e23c0674418c2cfdc21d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318123 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%0DHoLOJ#-0_nd_u6ZEOmn}O zO~KDJWl~3Cs+jUf_nA2U6?ej&4-{uoP)%y-(q|_0fl(hB|Dz^PW3MrZ)S$_1=`J3EEk%#|2XxH=2b(;`!sg;(J2O5u;8dYhapO!DDIKK>&5=_#YMHiAXv|{rmViqO(bbDjfre8P!Z# zAS(otShsTRT6JvQUYSYc2=g=sV(C)m1ty||ep<7E(q^DJD9~})BHXAy3)dY{2@>t{ zm;ewRbpp&|?Mkp~}OGC;{9$u~XuoU#Fo zY1g(RlNd@KZxPw^)PXRFROl!mh!_#8x!p}2WFrAPGM?e(G=*eE284jzkejQ40|vL(yyKb+`hRIcOi8aPm;U05FYY!L z^Y5Vnxl__6f2|P=_0Y1>N;q~w=Yi3vR>_}LOA;G3eG%U2@;W$5>F{V@<|hmor{v^I zTC#478r5v3Jnwu}YuHvfXZIl|f>g8TDE;{ENS!#g&s}e5$^$CYsiPerJalZ^L1E?l zq6AcyUq+suobU;m@>f)$URRyp{{y+hp|Ypi^~B(TD)M!qK~crUpc+UGQ}P@LDubcE zBL1^et`-Q33<~k1RtP+yus}_n4hkOlk=Y>E`7z7E;epqMQ2wO}IdS4dC36=~KmGJ; z=Jof`fT~rgT~xMou)2~r8=qdN{W~`5r&Vio$Kajv=7D{Jef0J_?`i?b%`@lkP)tmO zh~cx^{dMc@Pf+0+rp(+_btrR1OA?_D(z7?u7^}qdr>TO4YN(9W?R|CS^l3LfmX+VN zF11EK%-W-oqlZ(1oGJT-e6@a@c`{q)F7Z)wQjJCt=LN!iqSgir`{ z1t3kJr&P9V845j-F?qS*FnTFI1ooK={2;JQIaK+2k-47>mH9xO*JJyaCgfka0Sg)D z$4*_+v3EX)4YBs%?HyaUapReoT8jeYK<@{J$(dUStH8dnTtYLlXw%QD-9TlnKy7fq zmb%>XpuXQYN@2EGeYWsjm8&~hCwGj{@?eXarDp&zP+Ld$90Z`psmiVT>FXD!YF)nv z)oPtFvK1ro&R?v)jKPxdg6$(US0}Ale z$s)y&ai4>c6ir=95!B#|7H3MfBSRupWE4ACS^15S_G1-I^5J(^&6Jb zgz;10$KhJLdMRQuQ=NPDhKD=AABj*N23}6ualm9kT8hd)TytSh!~}wJ`c~QIJ9zARq1f6n(nHh$A*;E5im_E zHg72}%GKh_hbTEcTjhf&t2WRXp>e7aUPfPk_7U=m0wRAuWhbTpDOirOHJ6eoca8`T z(~u$eXy=w~+O_wf8=R&H8DgWX8W;j(mG||S4`kwX*b1q9+WP573aL?7_jT@~`+GFf z;l=AzsbUG$DA!n);7|mvjn$fs@b*^(E71u{a-t@YvIEK$BHnsY<45(=Bm}q*!reke zRNCe9dSl8<7=6_E0c2)pa19%(TD=zPX`s%moUb#h-c_j)->V+ACy$MKQoBQ3%F3iV z3P8+MWht2&k+jQeRijZW-Q1&>KKgpDyHq+NHrkD6k_RsE$M3$bvEyIY`Giwy+^muI z9Xjj=>ajrg3wf1gRketP?NjCnGn5$pA(#AGI_fmwH4rE(4xP1#i1{4FNzd(DCe> z02;8XHx;%U0FxOptc+%VI89BPcGbcfKO?8^qcSR(VxS0381tI8EbC4Y5Cxr7?%F|M z=s)0gB>)Ze;rzvljfl{hgaqYgWl{(PD}_35zk4_W(pUEfhsyzWRyL�eBvYm<&?| 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

5y8Y&t@m|yMj>zw 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

Sxj>UTK^;ebJ6Q)$NM^D`U2$upJ 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 Y|IQP?`EkzF&kR7|>FVdQ&MBb@0QGZ3z5oCK diff --git a/docs/_static/esp32-s2-devkitm-1-v1-block-diagram.png b/docs/_static/esp32-s2-devkitm-1-v1-block-diagram.png deleted file mode 100644 index 5cdeade38270399fda513c9968e0bf17085fdc8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74964 zcmX_ob9f!!_jT0d#5~(J3PnQ3BMy>7kH6<97oP}mO zszxn6rluuIO&^Q~hbdipR`=R{G5V19;xg5GxaNJ%f4KIN_2)FxJbO83n(t=9$GmIY z>*Mt%mbU!7{i16%!F<(eoW6VfkGT$`K7Mw^x@x)Fo7r-m>FVp-!{%vR)z=WXZo9VQ z;_?&*T`h9WE}dxFM8exi&P|oK?vIyle;T!lNA%o}`&E1Vx98JpOs85%IO}ieXCy>g z0_$@UABWwWkMNLW>bv7MFyN0RIeu-{1>!LqQ>vHWEY;J`bBAK^yOZHSt(g@2NM6T9 zsak)#Ki)4`z`L)8@L^cDIc!&MC;v8Y`dvL`Y!eh6h^Ej<+#`AyLPvt#%Yp|Th^SNI(Z$AUR%j&l2`|#wYU#-`f?tNA}JX~)+ zUB&BuzNY1U(fRP={kQQ?81P|3fY|qTHrw^&clx(>x4*~&ub2Iu8~z_}oz{yL-1a~l zSz-j1w|?)hPwmrb%*NgEpCyQ7vb?%)rg$0oE_)zL7<5`34$Hok5J|3jh914`3`RBk z-%N7;R4Y?9J?@1eejQ36m-!`^!B)1+v1(I)7AJy)J6s>si=}OI)sHGca0LgS;J7

=eZQDV_ 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 z zVqlwM^UYrrq2$By8qu4R#)7UYC5$6w*q(an`;then@?)h#Nl>5)6aqz^;>4bj6)I6 z81hbPUriDe$r<5wcE{OkmNph+tB}H%p|Y4R{NuU5A7HPz!Tv6`;@D3?ph1tM_W5pu zWX#YTg1-3{2R|=#^*jGb`8jDP^@JqYv2mR0xjf*UGS_wmh*i%Z1H$y{w_b0V_%*}c z9OFh+S;&~OE2)TD>G@ry((!7f)13;gar9aQTH)8%xxuqPDvnL z7%kK?7c~4kp-s6q>++|#e`>EIQzD1}dz6gr<^frrs;jNS`zyqH-8DE=Vv zrrnD#Sn+&E!rq6>%~B#&t3WW{hf<-GIbXlhY>hOI>&{V#pbT^JDD0_j zahzHfY~B%;7Kj!lzW!^QNl^0lBZyYG?*rj1(tj3EdF^j{6%5a8!l>1hhOH}k`ul$c z4OgY7o(ZuVNBk+>--4^yA?J?x!B>=j>LOK`590z-Bkw|wC3V%e?Y`4g+gSmmq7d9p zRVGnBLn)KC&JvY|pY9Q#pOBW9KFEv3q8WwKS^Z;<2&hOTa3M#8wp~Su&wi%G8n2+B zNr*DAPH>1CV}qSujS%fewHw?j6s5>i{|sO4%&Y8GpS0t=w`YjNjB<_yaz;lLd>+9o9SZLztp&dhtXOQ@?PJz%BjVVswEFJb@TkZUgh znB!ZO6HQK6#{jX_¹m}!2)vN&3`&(xMH#&?yN{qY3;9!kS1*(CBBiok}x@Xc{{ zaj0wN;Jbbij=#%u3I&Wj?I0f;psNdBX&WV^8v&fso!UAKn$b7;$SXQ6!B67M919>Z-z# z=gL~r6EFn{*tJm92}~0OJSE&{huasvkZ5;Z5>P(F%;l9rV$pT|^&KN#ytyr`E@YN1 z<-5CtJ^~B#14VPSkTYLIOhjAnvMWV{nHE{v@$gt^kYO=4LY}O({vfv~+D6^+)NN1GCMqdje zogGLYk>3b$4JyU2whv;do_dD0A-mFrb&j~nk-HDOF1B17ftAXS`n7wlmb&D&A*^%- z35SjR(nZ8<6nrJ9z~zT)iLnHA1>dOK{8hikVRAcW^Y>@a)tepUdAxT2gJTZ=Q}8*G z(z%i+zX*@EB_eT|aKY1J2_i1WZQCk?9o)fe^j0PMHNBDHwY$NL^Gf**&xPLIA)G#} zWb!q{Eldy+VB(-49YS)P7*Mj)KS>M&|!uY>m2@G^QKM~m& zM52sg6=ag4su^Mv_6FZXc+XU4>LE=Nrq!L@j>`0BVzJ{?Y5e!6k4$)J^%RQbt(Fgt z`mfB0A0zX>p0T~iHs2Ma8fS~#$iKhgQ~xM7v=*8QA8srU?sKUEl?Ep2)a+#i`){_T zNjbz;hi1gTZm_(#!S(L@iH~-cITxrH!Wy;NaS-loUlDE-t6uAj)9%kG|Mt=HviTh) zGZ^@4P?Chka>&e$ zyDWD}oSKm6Ck$r4x!da77;ZlSoJu9DbK z>#^!Xu7eJKe`IR%=;T}c4HAzM@=mNIWcttX`3Qnz2K)-YFzycYfePW6#jO2JjCEl| zxA5dFX6hScKiJip&3Q$Gc8 zE8c{dC+}!V_hQ#l@w~-*n_JdzFT`lbi2D~NbY*0-Tj*L`IqZoU;gnXd+^kci*)TtL z#<9HEc1`ikGp6(Q#IwamRI?P5g|d}tdpRh%ApYx*?CNLY5KzcJK;4g%Lx<{=I+U;J zpHDkM34}3=-B993QV>miIpigl9V-n{C4NXSYBe>hUAKa+n@5>shru zs^aqYefAGLyoNtMK#87&`$Y92u}M+C0oAC)H|4iEr@KWns_oU4k3{G;FL7*=AeLeg z+lC@GEYb}Fszsp$Wg+?G?A1!jHrYhereVoh&WwTUpSk^g1w0{6cK@+4MTnc)SZZaV z1p`PYw_~~PEh`u680ST_T`@EEVIQQ!61;c`M!a0>bax0B`$aA3Y8$@lv^L)ddN#OT z5~q;gS4JU+zJ%+SF)z)_;%`B}$;5^2*s0Dm>+Ujs{ft8lsOl4*W+%D5@_R4&P=U|y%uN~Vl|}qkZi7$l9J4jH}$z-Q!L9paWr9shj*4PbYM6; zEA_9Td(A&c?J=3o=ZAN!za5|Sbh~^M|H7~_80r!Seq)}hW{!~-cxoiM!`^g)9pMW; zvc`<}4yZY4?ST=lAKQ4$5b0r6lkl+!MzFrI=GzG7r~Qg%o%I6Ps6wiQ@!-YJdj>y+ z`YyZHRG%WA2P%G=3}TUh)hH%YR4$V|6Yf>pta%@My2M>qVtQdsc?K=KnDG4<2#!Uz z&hzMP5(~?Van`CnPq;hr*Xf74pT+QAk@Q7#CwYxan5xTSqBK60uY(slKYHZtnFR1! zIEXni*;CR85BE2P*94CT{b9BUT-%=eRsG>aH6BHK3R;nDPhR(TZ^687Z-7cUQ6#Mk zVd5@uC;n0RusoVA`KvIYr#(?9>#oIMOiWW|{hy~?x$XgMCG?PJL0v~yAwA%BG^P_B z_YWjjkte$Dg) zEcis_TT;*7G>X$->cbHD&rUMbesJ;4V~@IV9r@duI& zCbQ?<`ts<{ouEqmrsNom^I!ZF1;-G9J9O(VzWB1t{4M|Y=w+DmLGW-Uj3Bgh4q`q_ z0EzEx<}e8m>w9Xz0Opt+`51=~k;4DoGB^ppR45&?M>^oM#mu|8|_ zax(qFitq8qsQ2Pzeq=8SmcHT-R(pHCMhdxU&^+ao@xd?bZg@(`cSP%WD1xZs{#!@@ zddTAskM?pGphDbxkbmzA+~E`fb}BM2##b%x0-0a;n~hGHS?u8O_7us|S!BrTkDhET z+F?K`OE(t>&`kTGgw)+jfXe#BN|Ap8o6E;H-(#Mh=Pbn8kXVNgw|^6Ij#i!7_t%|! z(jpLPmOBl)aEM|}(_lyfH>=nL`FbYe2w0H*bwXq;4uEsy5Q(|lgGk^n@dt2|curiS zyuV4f2dv!55Edd9jX@}?`@j}$%(!koyE}Gw<(OD~Mn+R%%WX@^@=4YGg-z(jWnm`o0n$e9F0_2kAogWk8U|e4E2D<-Xd~_TAgx9t7wij7hldS^ zzgJG^&7_*K_h*)7AoM1JRTg+%8yKZ@(tIOufraOybU5{Im>?8jiH)9IP0=U^6%G+% z0nB6dg|?O$5f$Y!$s+wTl8E@+>-E*(k_{#n4P+W3B_xE!-)RPc+xrSx%Ux0QS5jr} zZM#f^UD1ZaUcjc@21b!S67dJ#nH~b(Xde6*-Kmvs)*7inoC^?YR~q4kFjO7L7PPl2 zoiyqYVtROm4m=86hEE*5U}DX3B}7l!vqdUXYcEVAqr^-j!I0oFeFNh2RPY(i$`L5X z2cQIw0`FQs%&J4_Pz!LFcXSq{B$ypB%t$tMkEL(B6G~ICgv(dT`;M!CFv_ zZ)(? zzCVERVj4s+W5;WY^r8B)TGYY%sMCOd#=UXB9~2|6DwlB0RRJ z@7x2si|+=|*NhzntR@R~Fnvp7UFr?|BW*Pt)4wIKMfxM69zLoKn zZ+dU+aJ7MW;l&(vtGCJ#;-ERf;+w(XX)yzUr1ncG&V!`ak(+T#$DgO|jy)oFkMj`8 zCdqM)QaR|z-xVH@sca_U%g%YUR)VQUkWM9IiJ!I8R}o=;E_Rk%pYd20P0gC#(?Chy zpVV_!8wkB|1e3fv**gzAd@t;QIJU?G0oI};58Jya|9-6o?EG&u%++!i+go)A8N;qQ zSK=^OoZXK+#xJD8#>i?o*MZTf3+Joayp6X$;VE*EJm)h8dZN)-=Cy-0hvBfIfRDx{ z^d9+mua?d}xgrU%-F!woDa{F7D-7NbXSXP@i01p})_BIugFR4tDsm zd3;lOmh`Nu=}=fW>t0)c*4aa>|{ulw}tb=`o*%LCUG-$ z!%DwW&~KrBYeMQkdDOX;$1P@Vpj9YA%3M4|3O}6dh^u+yL5Huz9+*{ks(=mMe?fd~ zv8%EE&em~GHeii?s$n%DbSnC-bo7O;qZIsA%?;v`Rl}p$14b=(Nsr?*;UgVsiHvQ* zJ8My>W%DCP=J1>ghRSao8u3;}`fFuu>|@?5lk&iI_Ti_j=p>#t zDHV#^2rOTfVaN>YSiy6iSf8%?#_K9Mb|}Z|%2*#tDObNwb-*qmD|=h^HxXll9PbYS zA0|p(jZ|3?*#v?WQ~p=)c^TN@(_}(I6*ElXs|`}6&RpapY+P2^W3eO4mH#qqL+X>+R zTJw3?ztp(Hd!(Q7h3flWox!dc_O@b^yT7zSs#k{ROL*_;pO?wt5{5;rohf(pSSOr5 zFyeK6ka0|H_$dGDOJ(>LAHMu1hL}-wDyE&SNA>B+^1*ff_heBcAH7(uSVN7A&g@@D z4TN>1{T7AykHWd_Y>?|9o`n+#hcBz1Sa0slpsWVpRUgW?&==+-gyIjIH|bgoc6~s+ z0JlkH8DabuQcoPoQyh=vQ6F$f$nu5i06!rE)ZLiMBf@%rK1#!l?g+NZ_PMIs<(hq$ z3{R1&IjQ;=vNDykZwXY~lR7#6wy$;vHpXw*1XU^?BJ;~M)@JH$f^=W5ilk{g>O49O zAJ{{FVJf9W_2}xW_!5wi%XF#`rxE9Q{AeN@RZ5K?2>Z*ZFEZeUFV~E+2BFG-N>PNc w@n>ejd|zvD(?#+B6h(?m)R_N2y?^ysM)5ckzsh<51OB^lOXA00009a7bBm000su z000su0T-=_QUC)$qe(;B^R zS6|AwdLDlj|MRfFD(COyE$Qt(&-D4LxAbyALP9)(!(w1{Fv1*@gy6uBh)uG<*TV&o z5z%(pvp6TddiBOopkOh?CjhTPB9JeghtUG zhDN~N1jNK8z>$`ym_#@_+aoeG6sgjrLrioue0+Tn6%mH&)oXuVy?^Qcq9M^Sv5ag* zY-|jIf+JyZG$1K55g*#<(?d-VRqsGCI zWN(O!VmfmY8<>Fb@IW{?dLSt&feo=kKwvN&*^tQCSU5Y_AuKWhE-sD)Q~+SKLwHy? zEF2i&!GZs>(tj3UXR%m}5|FYB#mTntvl`}390_kPZ#=m7-fTbs?2RUv*)tA~j@Y(+ z6Oy6=%+0&?Kx}+CPB;1nV@8j%MuY}fo;`bS-=cLZ$wnWplAp?$Wl84zXmV)7pbc%! zPg01dGW3Ya!(WDx)K!c7>DSI^G+OjAnjArr+nSOtf4PI#k8Q7Og_+eb!elg{L+j>f z*0dR{<~ZEEc^4B#^@Ep(2TotRg}L+Qa%iM7c57VLY%!bdnJ7usm3d0GS{22j{;Ps) zA-V^hS_Py&@~2l`cQer+J_-M#N9ZX98hm}cGk0jy)>5b2-2DSU_lfrmMDs~>o=lul|tBmg;Ga2A1a`|G87#Y85(@JJ5Cp>2;$E`iqFZ%%*)2GK< z{{XDpxD8n{XXXSpV&CCo@NjiSsJ%U0Gde*Uy?@hBaP{!P*8K;tX4xv_$dL}OUVpHp zOY3cKv|7zteN;82c2Y&nR93AS0?dE+`(kJr?d-66{T}128PhGHzh7!G~-N@Z(3EBN)oE_!`>G_^H*l7c*#HIFTwxD(2`73eqoWZ;Lu0gcHQhZ zteTsc(c>r%U4Dw%b-qESOli@pM_a7fxErA%;c#-a!qvqYPhY;q`HL4&u2dQ9J9q#| zp%3A1NJKzXB0St*(>LrP|t9(b}P0s!`&WKxx&#@qID0 z*r~>lpxcQTf4^kRTcj|SY~BbLS0|i2dI+@}G{N$<+flzt1!PF;gI|wdz>FVPp;DRR zaCCA<`*tnZs5n$>P?e2{ftRl9TnIDhRN5z~!@N;o|6ys^5HrG+thq^ldhb7&Z!yo=&)U{u10g zy)b3`l9hS-ES zIGK#dlgbC#b7jN5XYX<5++j?az6i%p9p{c8k7&m#fN3)qATl}<^XJcCZ~0;A zFV7JcmjpLAR~$Zg2u)kJgk6FIcO45>|NJwG6f1-4H?Lsbsui5j286qDvwLf+(K(ZhC!?$Z@_jMfH1B`;`^6lIjEF$5-mQ!LyyQpAvFn8Nrg^B> zdMsA0SdFf|dLkqw1hG7Rc;+jBOPBAUT#0-r!8s8e>xQPST43L=d(o)zH?Z;q5W~Ej zc*L>e(IX^01WxvL_+i#G4D9_KmU30Qa^X0-cJGZ9Y_O{XSGsjSS*~2U!UK%9FdsdB zgg}diuctT9XpzXo{VOps9)8|wkULM#KQ!u#hM0K%VV9yo^EQYG`C#ccX1%dNrGn_( ztqbnoxr=-S^K<+=;^w`laCULSnQIR)z3w0kpE4aa$`nGW5@oS<^Jdg<+yH4aWX7p8 zzjHqV+})j3rK?vihs&34Bh)__TX(KU&z`+uO#(9ID~x8%TjAX4Bj$W1N@2;oIqK;2 zhuVHIGd_iW(GVvG2i3nha^*5SeT-|}I<>y&gL$in{BH-}x^)BV?>}(1D`0{v{cJ1b`SoL$}isiTB_Vugyu4gZtzjO)1M~uL{*|Xv7 z<%@!qzeVwUxj1A_a%?0aQ?~rbogqCkXGx7#T?S*>tijlI`aUL3nF5nJkqvOb+{qKM zW!HAJZrvRtMhyi_2E2LgkG5^T!TPm7Cv4cf_-@axy$Z`P(Weg=1Jx33ZPS|c#i}Kd zr4ck`orB3_GWev+w%cU?wo%`{or8W@c5JxCF)Jz-NrPJTXJYVxzSz5eH@bH2hPA5} z;>>}y*tFvyd%*!O*rgLDj77;(g%HnUd7t4k+1nPF?5)U^JqI2=eU71{CnA`0>DKM1 zu&{deEYm`WM?}P3X|g1LF|<_QNh29sTCBC* zVDL?yy{jy#seMdCmMvXpx^d$czG?Cn@87?|-Me?tvUOwZ*tQ?f-$h~mkBiX0LpwC) zJbC=+8P8iecx*B9yp|3x-oAyS*@Q>WpTNPvQGqO-ZyLl|;tSz-uygNK83GWYD}9qAEO8ML#cA5;gc!{#!nc|6_1U6`W^#@4Z-y* z=Z;paTFZR+*I&P=_ZJ>Ak$C0>PpYa%)Hu{PQu<{`pTp3)Z8ww2-eC4{vo{a^ezK`~ zqmGz9cRs4uXo5W1^1#lCL&V+@OXtqSi$^cv>+Q+QUmzP1hji&PtM0b4S2AbK#?3K_ zL&^?Yc5LN5X@|JD7(9OP04{G{qi(etc=q8V0>eVFbm1UWs#FC_r;jq#`=*ig*@FiJ z?WgaHhRCjJ_^8 zzA$6);-%>K{V+ttL?cVi?5J70DGnU@6*+TcKtxn95}60D?*x`T>}K+Q;DHis3`6Aak}XxOn0KI&~X})}1kL!Bn62;1K-$s;hN{^od%v^d3=@MViN+(N+ug zoY81al`4(FWODA;s=~XTFa4uT2ai1F9VUtsIXxcTzKQX}uA)=dj`(TKb|M{;V6`*i z$^C1{o-HHp-G2rTFBi0|+Ym*|7sIjRClMM<>`D1j*#FxpR4P{rEgF7{H5*o8?7(kO zzI+EmpI&(x$N!2zRI3Lqf4*vc>NO4istIhE^nvy(F=T*>TRu+@XRBB0^!9a%WKOJS zu$a1a>4^gQTnVNGn5-_yU!XYNy`F=dIdgE6k4J@a4Y2p{VVE3Dh$lMe{LMQ!bm|zg zX2^(l?_MKs;lfzCXeO>*zl#iB4ro%nklp>;FD%s?xDhLpi1^s3lB(boKVJ?l4kLbQ zXmMO=*8sWeXtSSsF+=LKIn-9ChP|yZUrcs^GIw@Pc&Q#+#3orK2gWpLv)z_dGbD~S z+$1g!h<45)&aOU@^{Z8Uf6d1u{n_82pje6OC|IBfPW*lnr%(TmteMjB?B$M389k9Z ze{SsEeGHjXXTqDO4^>`MC-lefSME8O>|F(Q!`f&)FN=_rr^?idPyYR)A(BL$)?_Y7 z29lBTNKQkGElk-|NuP3Ok}O%$CMCre$ms3n6mNC3w;wTVJU2-*HY^?nW9l*(J7yTR zuUL!s!9h6p`!U$txgnE>18P+$iiv~Tpiqfgw&T1kF{%*xRojBBno|Df-xm#$evo}c zHY_#3q%D$`e-dUJbDCYXlZ{dlw64WVV5pnG4vkP z66=?*MM0j)JiSxH*&_$uy}W}aohzVl$=VJd!-CB*!Qm`Wa$??6hUBkhES;}aMvN5S z7Y&i&p@BooNY6}PAtbHp5606>@nBr#)U#5oQbt3AJ`=)A;+CxCra3 zd%?Vb&BF^KEP4zYj>5i?c=9BNxlENN4heCIDo;tT{!6}^MK3~yr>u*VDBl+iDL_aG z1SGQ6npH*mvmY&7x{5`q0)a~xE^56e-KT%FS`%UnX|m)t4Ee4zJX5E|z)@4Vi^rpF zB}Zf|)XlzXe4HgX@GVnl^HL>c9Tu+mDLL;?b<*pWq6{YZq9J3- z(!IV~zG z8VM$Qga`OfOXrz5#y~Vrx?F{j7|uPz*=qE3cQGd>#qo%4PZVh!%!$!#r9F||d;yDz z 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⪻+3VxZjqLm65 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

(9jHym6vwATKo};omamsS0uy~DA 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π3i0^bLA3nVjO>)Ga5<`aa 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%0D>pAMvvCd9e6>YcFoR5=y7fR*BW& zeJAzj)kmL)`VA0?hN`~R8uWYSY|R_K0Ck{aeQ1!91E`>;z1V? zwHFC=pl1!iw-DF1Qoh8vHU(Yhe1ZFyXsn=kLp_z)1^gg1>=Fp5tuFoARe!h7_6{N? z{p9nx%L1PftDx-mm|-*5yMzIlP&oP3Deiqxv?s4zMWo{r@#2AhVS*!)w`kLNk;XXf zYG$Me9O#;=YVd~*pYI4RW2;Pkg*}@Wr7vRZsn0t#Bs$W)5sk*vP0kfFBo|d8dD9+f zp#K<0h%uO1j5YdZm-sjOU1J?b2`?8a;5KhLqyMm0X@;fA)kg|MjIVcw9;bW?AmCuF ztvO-Ps}263%3jlPv{kpbS*_SWOJ$jEEkNEZhB%fUc%WYaP!fvu^U#q^4Eo;?f`{`p z;+4W!XEmoX<=-Grh(xqUB9P(3)M;OxAuAmqA@`siuuUaSq-7VG5kBQnDi&F(E?*{* z$R_3;jrrceHCW(;%#_^pjaF=i^#*SMQd}1mL8dg*M+Lods8KR@*8&1jFB6bGy<=qsh`E`$a zPYdzv>s_eyjYIk9=@t^+Y>5~!#U{@Mi3)BV!FE;x+#tk#NtE}z`-B&>BXdWol zg3Ke|F1$*~*)$l=*Ln$BwAong1~Vo4hfxDURE5tW283ARX`Z+zCIt_vS?x@gL+~|G z9o$x%X9(}2UQsU3*5L{uFO@z_syg;qb5=+qn@@|D(V`(Oq}OXOuNssk<(HRg@B zN8q_XvhXrThgCcdU6B(1C$91Pp^SE8>+j9K#*a6tSQOYQQTFQ?F)o8Y^zfmOf!=5Pc<77Ev};uS9ZHX^M%H4bj+n)kF`v&i zMKeByjt1EQiCV04Z@qA%E22XO$JqX4n(h6nUt7b}$#IK($+r$@zQ}1e6bz?sVd!M) z;3w?Kx9+#6)B}`x>c30cr!X0`7S%6pGD+VYXw_x!r`li#0f0-8TudF;st!8TJ07jP1yrf zO6$~KT!w9Gko~2}<;)bU6k{%h8JdsY2mi)AcHAM!K=q>yV#)lTtl8GtI+C5lPFCEvA^-FK^Z(-139m@9H zC)iF+B<_+i)Z|n@%8b^dL8zUVFu8l#y+2KiM4Y?*D}m`kkB~3>aRefr=+8FwlRk3b zW}xy#qtUm=E`!Gm4l9qk9AR$U1m9W)NvQ^!`OSI8y|#SKqG{t18DT4vq`H;*NnsZe zYcP8>S^R=?=NRmjvvhKA)bv72{{sbG=d%QT5=rTI?jVTOo%PJN53q6VY(N^J)2O&K zpfWz5%EHT5goGHkNRz8l+oYwes~*{sVdr;V2S(Fq45exz`y{uC3KPY!BJZAg+vbhh zspx#q*26@{_33W5K5ixrnS6l$phrW>Ns&WgFHp;@ zA*cr9OV&V}XuS_@?1RobYl-AqyQ-fbIF}uq{&BF>$gf4}LRCs(k8T<45>f*EOHT zTP&GPS85oF+e}W8{v=L40W`o&<|iH|uRRjm^#&YMQT>krjfIK>h|>`%xm*qOp_=_N ziM!QBqUBypJV#`OYeQ!SYUy5*U_@%JO^7dl06vF59v2e)hH@M;8_xZ4ScFkif|F|m zMl*R${o#w5>VI_B9ZCAU&LexKqVR=FFze>a_s0raL|m*7N+5lCyE_VZ*DfN~LtB^` z%x0PKG2Gm1o<`LQ&M~7swI@e1pNU~QX^1OQ6K=qBGIA6juoXEGjo7mNK=3v;EnKMR z0lIY?Bgg{HBwU25kAQj%mwjKc_#J*F#|kYpqEj^!^y2BuOAZ(zZtJqUyQ8BJ5+sT3 zwG-t5PfW-N*JER!H~z`RjsD5Sjq+FhVJV>Q*WJ$bas=M~mS}=7p|*aPninAw`F}wE zZ#w{Qqa03R)RgLlUJq$h8_|?hYTy(wm*XyOv!9-%+}A?lbihlD)&c0{k>whY&1BSz zzUW?OAplxrlSC%6iNi#TTlbmdI27+?W3KfZI(iH-6xK@vDYgw3+d!aE(`w^c|5}*v zIxJDvUW)?FbR*z>6Bm^12*)a)8Kn>*9{Aum$i-=~;yZSPZ>44AM*`Ua@M<>QJ=c$O z#IplmH!gED30g$j5TJ_3>qtwD$e(V-b>c9XM`9+Q-_$oH65GG`$+`a#2pHNB=<)ZP zky+@nWm-*b-A=qnE=Zg?+SG1iHlW7&|b^B_U|CBdz*Gcr0qRUm9O&1k$tWO=u5a4NHm9`P-mo5EyH`X5=LkH^5W$ubC0Y|-Sy_mrY)WMaed~-y% zn^>TD_S-%RPKTMpe8V+kE(0%i|C7zWPT7`L4yKLubk>clkX9Fg7`;_jS!pcg5jRhp zuo^;jl|W{G`dMD{gfRBf*w?p_l9=NW_iLDN9cT5H`CkM`N=L(WJ>2j6d>IY=i;bN1 z6biOJQDTGJ3mW2?!VExaHZ08?Z~BlJD~%aLBP{DU(bnEVhK86Wh~qV^+4$nu-(RaV zI308ZLt)#%ce9eF-$*ME?87w3VU!UQBb-ktABn;sQXYGx(TBD9+0@wE zso&LI=zCQ{0gJ8Y&3_my16$5sPRDg#8%#S37@}fzN3ZU8oQjY53=oaaZix5PznBL8 zNf|W$CYq>_!-MzxDzw6&aW?E$vCia`PmPZPizLg=R^ilcrTh^KG)qh=i0?57Z5wD4 zc5U7ujT#uLI`EjpB8Sxhu?~CPq`soHXyC9#KJ*t*%Arw^suscoArWC_(G_Cq`aacQ!ZtIV5cr6H_|CaIwcZbnu zh*bMqJC_fHZc$43s*%e=X;@>=XdE3vV4%Q%b142nKsU~*F1gglG}X`?hK9#umdH>^ z2E)}5Vd{h2BvYl>;G11G4U*5+StpTxpJ=Y4wQ!M7lor$!S1|pMg3E(}`LMH$ti>o$5(T?lY%%M zu;U`A?O+HeE4_4K`L`8e9kl#Lh|g`c1Y4J|44SMv59_{@1!8={WcxM0hfMR26*YJl zm?5bxm-Lm|(JR5`HD@8Ipxob4`KJn`$#=F6OpSU?4Ru`Ku=TEeeRHC{H{xRW&69P<1?NRI(|#gTLYpEbbwby)lSG!1!#Fp z&-y(b`JrGcfMNXS!u7KdRc`FsJ=%>?1~%E>%=^DxZ<8-?S^=FinCW{@lVi6paiMN) z7TlIjubV3BnyJoGLb=_eHE%={>eT zD_25G7yu%MigO*$qwCkZ(}9(dlRbUGCLf{s?zcw>W`~*pp9baqvmIc@9oGY1-`-N6?s(-$KP7d~Z`=0WSA6Vs zpRl5ex6b>Gwk%U8ZYpj&VK3g{ns4HtHoGd`tAyrYb!odp;@+KiVEqFsuKeS+-)&ui zhFy_UU~l&Q(wOexUbz6Uw7Rb%t7)tK zym!2l?gngg@Am!Cer&7u zX0{dQU<9S`xCmT*<=)Ft#CecOcyq$@c)i=%KGc1_L~%5`9_pKI*hN{whWZ|Of$4` z6g##K{DGPW#HtKp9rK`&P)8TXfK}V~h($doM^QptQC%8vNMMa~{ z{Zv*~QIRn!GO`2!2WMk#V*^)QS^3@0+8W@sn;=!$_H<#XGTi>v~YnZ7q8=CO)^7>lU_4f3Wx5&Zo*mmJ5Jv|*@&~{3S;H&dE@=9ask@>gRs30i&3B3dcEDN&vG)8 zNAk4Fpsn%v0~;3HRjyt0+sf3`^iszv>vjc^YxTm)2>d>I4@Z^BTw&1W4)(uq+gKx0 zWpUmeUIv02*UmOHk8QIBeC~!-@+AEpm#uOL{-IV2sPvN%{9r773O~2J6k2$7|KF?g zB@^XA2POWaKJ9eW2n4Ul>;zm-a0yW(i2M2Z{p}9=gl*tFLNWF5i4p3TUwvg`Bd7kx z{RcOF*3+HQ2Nyg?t6VDM@f82{_~JiQ?|k)BV#ornJ7I`;yhZu>7~eLor-T9$%bDqI z-iFT3&xPJDJKbuXeQ#!@ zh8~8)9bSX{xd{Aw;q@9Thk^(X?mPf5Cnyn7r4P#n*Y8^hNI0A~b-9Qe!A`UiSx)+#rv4i+m&7b!th`$9-rIUs#gf;iLSDF8*anDqRXvvX=%xs=yCck zGc$AEq5X33(D}gB=8~XJXz}HC(TK?TxS~mr7-2MD=Evk>O*n!3QcR1>0aB_4Xb;-R zXX=9?PvULyWll}Wz&rvo~P!4`jZZ2hX zEW_)_)Q;lE;D9pp>Jqj@B5RsXy;pHd3ntDh=}3@ z4N-D24=ikKElMu(Q?g(Bm+16uogcO#_BtYBYa2W~LG*SJ4!#!`^uGC9qYB<#X>dK9 z?Mz5Wm?xzrC5<9Foc`69@&O@;AIFd0^$c&v= z+wAeV9o5e?P5KdWL;3Ws27Gy&*6(U!dst@dy-F>c3@3+E<2z|gG^x##x z_?>QN;D1F#e0l&iIJmZt<#T6G4mmKTkw95^bG6~(3Le_(OTp1*#<;ZvF%Ug2#JgA z#l|9%Tpuvu(8sO~U>m(419SMjuD;6Fl%1x#COOGMZV5WiHrOsU%vw?pR8d|O<@i6T z!gOL|VHH|u)Dxtqar`Q+*y;!%LGTjJfF_FCXI(Wl}x_mGE$TM+KS=1YKKcQiujO> zOg^_zfp)-$XRq4$!>5S_^M2oYMER)4=}HK9zqhwn^OhFTOw-T?zZ`|~H(kR)b{Ty> zY`FV}lAzb4ZB>VRN|N4(Bc5{5(PdwJI6n?B=)66mgBv5IOg92`IAlD(-J@O*g?x~7 zo;ZDkQ~%NyLzm~EyX)*H)v2sXd!y^F#3So*Lcg1tKmYu_TuF&WwIRcPYHDiJ>*nA6 z8hjQFJYEgmdVHN@29LNleA(2GHFSli;?N$=&CPd5wu>59w^6v$P#y-*;z`89#x}6HYxWY zrC}2S83@Y&j)7v@u>>IouuzRwWO2X^O8_GbAz)KNSj=KuO(|*uXkrQE1_^6SE+{0B zKyEL5>gf9ioDc7rIp=w1&de_gjOFsTX|7*}O4x!Ft|epk~Ce{1?m}pG>5Fx>2gZOp1?cn0UI5h?LXq zs{^{f*)VD$%TD}@=z8p1Oufuq!rKRN}9GC$i z_ks!EFUE*V+*7{AP=_Oj**}awp)~w6G3>JSVnHc+=+3iLx>2DiK5Is zG8Gbvp4sY+^{8MPv29+>xVa4gkvX>YgCro3o*%Zu-11PR6FpV82jrRCU*MKKLb5yf zs}GyfSEcG~qqM6kywM{E@d=!MHU{4&-FRBB)k)gmC>z02|DhP#tes_8e0Q;J^0~Cv zVXk+*QHHSm*&?on0~1G?!0TEun$gsQFu|HP@aQkCqUQ+Q49x=0w*#+<_CK-xx(gaZ z8hl7N3`&@?T?F(3XQedmNXCoi=#&Eq4^khv93&i9#?VOKm07_u9)+B^Y}H>UeOzW{ z$62$LpnWDWRnv{Sn=2!ko)zI#u=dK90Yi8ZBZoUJ%8qIE{z%&EGB#Ap4#jzaVEdzftdDELp?jq#XkhACsqv zIDT9PwiNYhW%3w*xtAF9X*&$eJaGY6wE8iU`EInm&@j1cRf4G1vhmIlQ(~S!_KyaS zc>U?SiALn6^Ebhq&-9{2gG|&@MPa*_o8hz>>|xof*xfAqEc?FUy}A=+eto8fD!(5` zYG)aT^`yhyTrCuw{mr^Um{j!qGH?kp!%Zi~=$>VRg+8>646L0MN-* zt7IC88)R3gof>8Mpxl&X5a2tVx>L8X0n90j$0bV+ z?SSDdpDCLs{@K*^Hf5?10xg#6znrgAp$;bMM8E2B@g41?L?KR1_^xH^KAX8n53#mf6958&QAtEWRCodGeFb0~N4D*m88J(iE!#3PGcz+YGcz+YGcz+YGc%*i zEL*n4I5Yp;w#(bmDtXy#lE2Ar+oP(ks;=(h%h$$Yu^7P1YPD*i#MNam7?^BjV6aM> zit9sFR>Iij^m!6j&#Cm-_dk~|sfO_bM)xseBdx(GcxTzwjq4JXGd}R3ZPZ z#q#7d`zB9mJagnQY@FPXCtrTJx_TfH zXDa(u4UuUyVf0X#jK&&MrqA5w6)zqhJbB9APl7K&!SGF-5EioqtClZ>(bf@7TC~8h zQ6uo?^#^08-aV{upS(7hZ2s8x{Hlh?NaQV4JSM)Ey>aZQ$%wI-;s5C>MVOt#w^+J^2JkJIC%^?3KYTPhfm<+ z5RSdOx5LXj0ZyH~fXf%|7<1*yW6f8nh-@0#ySVimWznj8_5Qf-RhoqA842YXN&C?d zRf#^70x44^kFv3KK%>UZ5ET`Pd|cFlfuHdF#T!IM#~>Nk$cdvzks@VsTUc@?{jrn-d1>8|2TO4KH53hHnCIynFoyW5y4Mm5p6{#vgVj zJGAZG8K?GdL%9l7arp27RH{-Lg^LtH$1WW>ifPOb?>)6)XGs@pJuC12c5C>NroUHl zDW`u%;y)T9nd*A-@No(USNo?O+jqd^sWTB88j5iYjYcbSrA>nS4_uHTLpnTv^%e=- z-H;@4VhkQO7>}O4g9F!!hl?ktTo@9$JHTRNkFyugV9bzq7&dkxSP2#`TnZbL6Xr~t z7_;Z_G3?)WK$~Lf{l6uQvmvR|r+q%SZ(DTeHUy{HlNWD3L}Yjb!psr4bS(&-^5lTQ z90M0e2P|B%1pVq2gKyeQcD6(vfRLbDEC(7k6LtXQ~6 zYYZ0}W-eKShqo@GMXR=!C5z_U@{0K_jgV*JY=~rxp18=hZmoL3uO8gRpuPhze)2>Z z%~pgNZLxaCQS|B49SfND>g5}>o3t6ut}cl0?StTuFNk3yqq(y!S-PBa1=zIv5L_Kx zuxiN?PE#wqygU&U^c9g&G02j$FcK$@hcs!^M9-Qz<8`%aHIm8u|JCb9LuCHxALh{! zwr%GYLzOC3tj5o0QMg!clrB~gr_Nr$iQ^~Gx@`yKNS%aTVGl=+LbEDGuxiI?)TmJf zhmRhDiT})&7`S@+AUxnbICnI_z>%Z)@#6=spY9x;If#f1$I};YxdS?(cb|SqyuH0F z1qu|g5%5KQk9?c@KDAC%C}kx6qapgmBbjn91@`ROV<=ppu(fQ7%-FkQA=-5vhjVAo zB7t{&JPVA5n~MilEL(#4i|6n>u|wKaX^}Q{8l*~=2qP!XLV*7}WXqNn+%NFh?;c_} zq6Y4QuO8n=j4V+j-(`;G=3qqb`~^{~UR~tQl{Y47VvlhP7p@(wK3IK^`c4(9Z~f5_ zNr-)^hfkk7ZQHX;$LP18UC^s@3xtH5;N#r$_dY%-lm08FZ+n3zO&Vd% z+Kn*qaGbYb4vY@2*m&p+a%9hkc~gh8t4%0WtP;EvCx<(iah3Xwv3kjTbnD4Ra3lo& zw6V3ryLazVs6ZhcK7JCnZ(NW;;+YkNc3rv}+P7|PDPFXA+Cqg2`l;`UEBw(A8A5#l zHKh9Vxr;WM*36y|wc)^7!^-7zj4j)A#)ts}Fnrv2nD}M!T-@Qs-{=wj5gZ!Doz{el zCk~@j)w&oka3HpB-3|vr116)5?7|F92#Yl1#F=xjx3PhSk_R-(JsZadGrdbPS zBB@V8eBfzs;Vxw52lnVU5PkdiL)k)kP_155?Ag8=MM_nJhldNAH*1O2>y~p$njl?g zvNI!Jwmi6a{Th7S-SLvsQjk_|ZiwX0=i%aoG+DBuafi;viNl9mnlx>$b$IOW`_T}6 z&r4(C8WELNp<>n6EYhxIi7IxjJ9G-EnkyP(mwiC9`n9lf!*C}6;t!m6qMnsLouMJsAjH|nwxm2z+*mLDR z4)0lya#b2*>clY^Fl;1GZX?3OBhju?7xd}ZAM01n$Do0OF=P4|q)DF!QC#E#c!mT= zaEG*V*RnzJVr8&#$2NF-xNFbOnlch&hV{qnrCSi+%NHSEKj6#PP~7)>@K2Dyj}iH` z4TxQ?L*Egmgezy8r_ESkakO_d_8rh47cX5$)+||I%R|tX(_|74&i;c2AT%HVdGZ&) zwX4@SA$Up6dRypW?7jG40*V9LN|=JXi~m_|?R{gaJJzUN0nR0Do%7|+Y=YlD_;;x%m5 z*3h7SBlGU{3sAB`V@#Sf8bbyT<$=icz!7TJvMtYiD-y)_MwgDwFnH7?JbC_fcurd-R_C*wd&MVh1a~h^X4mym8%0pW2Bk_A#nIEJkjTXcK@p!ZZ^CGlC|QPU>MV*EFGpw~33o9E z#B*}QyO+;#kjLj~?AcW}YKwFW$uM>*u)3^}wR_o6w+9UF@1P$4)--*L>5D zhN#x5hxGRnS3M#5Do-tTm8U{o86IoE%C#$uEt|El1bz)bm)?E2(4!E~!-M#YBQmB- zM^yPF5~WTBOH4G5A31_y-5PQIbo+tN%lm%r8`QggG(-~qs7pR#`KlF$%V!UphmW3a z>@}z^I`>N0OXFs(tiwk%!s6MRuwdaT)T>ns4ldl$O6J0_=^ITPS*`r9ZG@Ej(GZyy`UllC z(WmRvq?gqKl;`w$`e$O*sS#Y)tXyiWS-Y;~!`BGxSvwBSZqBGzu57^I2@~V1x?(-| z>k%vcgMUVR>y}N%bI0~u)@(bB99it48u44-{bNL=hxL`{?_!BFt+GS?z|nupH`tIQ z`eU0@ty2~0dqAbBFm|5Yt32r~b+7L^{WB_Gp82Knzm%`uCw2WUBa%H=Hp|d{15mqu z!(WA8s}J}+!yjZ9eb1>EsI+NQrpT`JV`G=Dm-~9PYgh^vD*>OxJ{T}$IK12(%olGx z>Ga{f|NI#JM7UL~Ks|?uh)7f_ zSgfEchUmCes9Lt9HSkLS+&n#b z8h?PTtv%MQT!b{4bC6P>2b;-uSTcW+A$8gmmYdh_#dmde{`8{<{=mquYRLFeL$o2C zGGnfVXa$laO@^!2t|2la9KK1DYA}(nF`?irOO-z zH$+DXRAI)s3m4(*<&Iqkj^OdR{dn;y5RoyYgpg3}n>Y#Hy?u*%bsJ*&vSqN4{4-|! zROHWB$kLu^azd^)AL&Z-@`?KOl9g6ewMy2wuE?k7tkkuyE~q7)dy|^Y)82<>JMUuMyzN6fKPB z?*nl2<`qmF(-Q-SPe++jWl^bG4U8W(3ORD+v0S@+(bi;RL(1^Kcg5L|%o+1`*t2x# zg2xXYp?vxBWEZ$1+8Tw6*KQ(1##C^&Cu@N3y?gsEP9EHf$B$nl+F%P?l5$+#NKlA~ zzzy;n>+pjUM1>$KRZ4W|F&u909^{=Ih7;*n6Q|CCld}V|=gJvvGTEAMT)X;%a`;=C z6lX&U7cR7D*f7hyovQ{L4;(mv9zDBZ?Yi|ieBiLQz~gzjqQ#2}xP0m$E1=IGzio7WcGo(3^teskI&~~9ySeeen@_InVeU-PaN+0(1%2+4wPYiB zz|kolif2!OCb%&l9I;1~Fj~xqlw|GK@#`aAcrCBIiq7-rS!+bUfub#g}%5)jX z;NeGJKeGiOe=bnDiK z5+nbR9+C#gH%TK@T<+zP`#7i8w`{F|Wy!LQb_?cAj^4iO6V@yogqn@}qeit_*mY<> zoVc}4BGo;fS3>xvN=p7ndf1Zpe(dZORH#%F!Q@iCefJLT&MsI%nC!~UdkFXvgyl;q zv%>8+f(>yc#eU$BVHnB9&sB!XjrdV?LJh$9iS8gF+!Tb~)upoj2=`}|l_WRf?G4|UV`ArP>dZm4lP==F;uNw&N^cBct;O+wI{k&E6zjEj@+gwlq^#gS1w(| zs8ORS3YCr%+ZKzLt%N;ELMCTBjh!7%0R(m;mxd80i% z=;4^Zd^tL_X^DG&Ps1BGsBCW0yz4)0)AF4^yKBjZ>qkWH)ir#=0^4m1Cx$QDal$?_ zA{gZ>aa%oc0wqhA=G3CZ5J8z7IrEar{v63DY~xH2C5qsSoxL;J2Qd^Za79R1C`T;_ zPVP<^Ja8lq?AwF0XHW4A3a0RZ6C8-VTAl21c=rx;?a-bKpq-evc&+K;xjU8xix&OU zj`n}95%ux0!#*Q~QwO;)U3xfBs0QLu~e0)O%o_n$Zk zS7&!j89N*U2am<^(%seZji(RB-0v3mVI zOdLB3!$yq6JO3~6CAczl^aRwX*$^KMUi_HBm^NiBsqXHGA+499cW`hpVB6+(s9e1U z;V~O@=+K-+f^4d;D;zoG4<(yn9h}(S}XNMRSIsV%gGo@aQ3)KYz_BL?%yk7zD%2k}(T1BnU%{S2j4= zSg>jH4wk!*ym|7WTc_6KwX^X&E*sXaibTFi3D51tfroc(<@-{nN!L2A@BFu>R_qGP zR;p4$(rPtmVQAH+wWWTk!~_ygV)KTzXw;-Rs?}+Lt&A5akcWrjVgv+VLDB?C5D@qg zsnVvx*rEOL@Ot%Tj3z_ni6Hokhc!3ShYrD^duxiP^?6896J_5G&vk&r!Pg1 zuI-Q@p)a1^yG{YOJC<3CSJ+D3s(zV9Dz1O`?>Zu?Vij)KxWPDLU@wcCyC;^;8wO8; z@kI(2!rE<{kvM@5>NRVDoT-u#q`8PhZbtO)+aHUUOvAoC$I$2SUQC)kN1INnzF!J| zuf_gj;Y)9+O+dnt6Q&zV?ca5L>4t43h7W9rUc(lnY3=Gb#3{FK#bT@qiA2tPIeDgh zr7&9;czJkZ_O$5-r_7vJK|Wm7r|MMq`bJ6KA37rHWyLB~Emf?16;re3&7<2kYl>s1 zE}>w-f;d9dz?q{}r*13Eoivm{m_06Ex$StT=q?JWq<>cKsoXT|PyoKwQ(Hb(dZl3l+b0Vd;vM?gOei z;q#~W=+~wkIt^KDqW_LitF?Kyb<~SR#!LIhj|MX^5PF|+jlZ2cDsra zl^PG{$Eol7P2nHD*yXEK52^(#q5LQ!Yr1gaKxDy^B?Qs`aY=bqMjw{~>i$PzMx^YY zJ|g-Lknc*CI!m)yX}{@K)`-@6)zbefjQti>UZt!1UkatH^rCu3LY9{_^y}B#JZaKY zqFMjAq%OHrcpQQ})nrT+4X@NuEBg%KlvVyUi@V zRO{65AMm4tC0#l?c1RThrjrh1F`E)6^o?>Pz-x()MlI?AP(;hRdD}MR$eI-sCQg=J z>c{g^*WdZl21HMOVB>$Bs}fg@S8)l|Oi*c3MzHSz{Re&<6!tZ{(4e4Hd4TgotBaU~ zsd>Fx(E*=7!^X~rqy{r;)~zGj3?z?8w)N5;mAwcfMH{z-QAo_$rB~i$V9j9-XYQ3i9$3PcyCW+ii$H- z!!U7hOe8u?95af;%Ed*BV>8mS9Em>HsnZw{QDMaA_fiqyATnl1g%kVtL`Q^2q04~& zR=-D&?PPFt?fc6{f7dOmVTT?Rcej`lxY|d!xwx59Bu|P)b*e#R4Yuvvi=@euBTbq# z)Z)89C7@TN)j1))ryF@cZq$r*g%bxRcb+`>{N)S$KfK4P#Y;6E03lvhuUQ=)UX-rw z)&uJ|Z9v;@Jt^vGK-aEa3`dUbk0#+B8PcTsxOMxk#3qx8pYdP3Wyy5hxPD`k(|b3r z@*qk3rIRPjq}pcBm77e2+nn!KZWAUvdGZVo9zN!*=UKtk5knqvu%kUPWlez?5{YES zhf**^nBEB!Cq)X1AJ{uN!=IWZZ>Sh}^xzS0X?+pQa-@^Pk*wBPv*+^JC}ho)9_!X` zh@U-Irsy7B`;fF3d9GupPQ}z#Afap>@~!{zTh?zq)TNQhk|mCgiZYw*9Bh#-Z&4&o zk`&=o!?EzN7FuXfFwYAr@xmI-*-kP%HDxpkcT6Nnjy4D)N%6vYQP%Q8#Ts?+?{zc|FN&$xN<_R;biELrc1)MFo{G9!OAj+_wFH+hn-9)AcAQ_#*TnFBm}`< z0`Z>uCD$XO$TV_9;QfdE3M;ba%m#$`lS3AWH$kCr=W4RVSP(*Ws7zVY;lcgeXwtGd zJmbah^1M#fE?qlz7Dec$ow{^gtM4R<%TL-Smx`-0>Rz9x;`$Dja;mI8T_0EZ^1S|1 z>A(6=mrklzui@GfC5kqB^5g;H`y@uyD%H46tQL(mGMS9<5B0#FV_PtG$N;PR8+yWs6C`e~j+k`ygIC&((SIh!I zT%gg#o$GM$;u{pC+WkwvJ4ll}1s*(oqAA?%*t3ItDH{wJH<=P#iSX*xE390$07tg3 zL&_}q@swvsg|a1a{`^HUJz3sI|h5|Rf||# zJkNOKFmgq66~+*G9K)4!O@n)QE_-rBc&p)UQU3U+*Z4n6LwOlxG?_ zYPbgN3HN>&CC8q-jT3*jo*jQkAQC`X=@bmH|;SS|94;YS4Zz zO`k7unf+2$;_4ZR>o1l6t5=9TT)ujD!-}=nELNkxp>lS6j9BrKsy4ys*R>-)y?=o% z`%Y4#h71jX^0{J++@|U_YDEP?JA`aIgjrLkV&R(XMr+ypm|cocLoqjJS6*tKgHjHJL0A5NQguGmMJd@YXnOvtvRX92XQ1P-Sy7%Y--(<;9ziu^*pEw=SpCb_*$TNp%hXYyG zDZNr*(b8p_7@`f&AL^LXB1kyTD+>k>=trf?d2n`eK;mSHxnkeqOTZ`GqX`Ea^7JQ6 znu27sh%jODR5Wc;pSVsq?~{r|pLOPp37EZjnfb}R$3L00(kE(|;^?10?+np@1V6;Q zZ~vZD^Jh+o%v`XB&Hd?{tlkN!*&Xo+$MzjS8FH3Om#c)*6q;*5Ge~9!ZZ(9s@)Rh6 z)%PDE=+O(b>NcISW=;s9;GMIB8_H7e#f1m;mLunQPzPYi>b*E}>Io)~8$)n72yNSR ztn~(U6eWS*7&Ol6DPu(cW(#|+fgPi3+_F9fl5@G+p={F zrKx}hO+L(&F>B@m>w||6evn*LfBfFzPe%V=sayu7Q;&gS0L0j=UR6Rbk1=!gSs2`WaQ@g{ zR49-LmFmpEovSxA(=X{MTDEcB8jZW|lQiKfMMIdj46H)rWGbYu7cIr!yx{8D776X>HrMA#VA-AYSxZ2It3W`B(bxm&*R;0nt@zt<|Wx zw%8z~Yz`#@@;F9~7>l7phryK?edqRFxh0K(f5b-`WbwiWV*Ya%ucTJ9Ex&>17PbAU zZ-bgu>QD&AggJ{=ATxCaZ{2wS6Gf6*wrWYdiC7Oo`o@i#qG+j7+PM)3T5M-ipphjjCM49JhMNu4&$f>dcn)BFsGs6Be$t@lu$N|j1mzkZFz zkvmh+ta>_3S#l8PFI=M@?p3sI-w82cA?$cZG^*Q_+sSI!lYAn(^vaE!Iddt`Ni2NS z_-WK#_ebsOm5G6eL3DmMQ#^1B1=12Eq>Z9{MF`^B5juO#Rc1qJqCg(n=TV7jfTxcg zB0dy__>|Xouya6!`I{VA3|9uB2kh9jnPMbnnh8pRD>rT;A(fx46n3-7NAO6JHL!mD zdJc{e9yA)@O1--@Yo zyZTv3q)X4iiKO1WdyhyNP96U!HKem${vI+IL>JoUl zQ0IRd+O}({*}vens#zy-Q7=~w5Hs;$x8=J?FyOt3hH?VoNwG?k$zCfb z6aWWV!4zbQrs$=CgBL*xM9gP@Dti;rwR40I>2Sp=Rpo$(Yeo>7)5cByg88GrQsp=# zI3(ijt2eGBk_rb<-~_F&B$RtL;wP8N*9PQYfUye(Tq!vm!1!3o(5>0H8&k%Yph((wG;UB& zFJ3&s%_}##``IFYv7$IkiR@@1qt}R>o;pWCN^&)i2b_SDt3ABqCm~e!3DZUo!Gt+W zsSIET=SV9)y?e{8%aN=35OE(P%9Sa_ZR~Q|QpGYyyLtMWckDXsz{y6eD(>qK*|KDn zs3j<`{il19!(`tmTeXR)T(zdw4<9~cm_2sTy&3Zln$u;-XY%olk7=WtVA10F@QIfI zJ-T;Bv^hTR-n&CN`~*mlI3u1uzJ)KJKO!cO2Q5iA(a~m%m^=%G3*@7{h$qOEGac5i zUW?=@GvMXpM;gH3z=17QuAD~FPmmyyc0`EKwBV8(D8(l-lnD}hqfYfkxOIz?dcrK4yCZjmNHXR;%Sscv0Nn?4g6 z(`3PkBgZkKUmN7ekR3CYZq(#_^nIg-MWy|jD@48fN2sP8(6Q?m^^au@5h@pl^b`mC^`aP24h(_Bis9n1r z2l*i`UAc<+3+M4ms6G~Lg*`EQD{&OTZFcS7kBX&BeEWV<46a0%d*U-z5&`jcJH(xuANctUoHEqkG9qb4-;_7?m09wupC z7+p35jlYn>n-On_jX!$ghoU8m!=8J4Y3f9jFJD291*&s8!Z$@qR4>8paQqA&@GkJ6 zi6twctQBik!HN2;Vw6;DfC{1*9`uQ_r1O(jO z$iJyx0b{4mzzu@L9jg|^$VEHs&6<{(j(?d73!s?yc*3`jLS7_Djh7RH?HktXsb(8Z{^mDlfv@D-k+&Y>C$& z-oXF8KN(jBye9VDrCkT?+r0;8E?yzgm(Z3ehB%K6tuST85N>Vl+P0?EvLGBhaEdGh zBPFKo5JpnJnUIt(G5&MpYTmqYi6%WyB2(rJFweIVHcXpt%$J zSx1lB=DBbGzAr15t*4xQ8Tck~!~XrRNe=md3RTLWNrT3Og!Uq9?mQSWXfWBol{rq% zNKS>Er*Gfk>!(mGTeTX=5+)^@5rg5Qr(ojfp&A?6mx=?0Y1TAX?wnNOq3#zAWZowm zAdzokN`R+A!$!67?%^{OD_IV`y0y~)gwYdbcvG1)K)z93^8Na@sJIGMITfn(|Hu_0 zA1NQG$B)#9cj`Y;h<}FE3B5v$nNzrI+j8P%XqZPbA%%47T8|7a2aFmr2z&SCz{E+D zNNR7$t;+@_%a%ulQYA5H&_HC(kpW@E?km@ohB7+{tduGQj?uXcQX(VxpD2B`RSW4V!}u+%^s6{v&7Z6s<=K~(&S#1 zQK2gPmsla{qxB6bSF?euO5eF*sb%=Efuj~IUOYTk&it55OI%5k8;ERnKrJfMZXrQ& zHr3G*xx3JYT2buWy&rcU-bKkG1rQPvj>Yq*p;PyMNWnn~rfS=o4Lhl_GX_hREyWxE z0620Z89 z+S7Epg|w}`N3X&yeo~x2drUiH>};YjV(bJwBZ)XwGGEj$n+46g?k`W1(}(3fa>={Z z`_=cTbgjVmG7^{0R%O&Ps*DO%zBV8#@vk1z%x+}0M$I+lm}U(s5^ObGEnTsC?zE{> zQ+==;C03eY?!4W&eDNalBG9gVd%Sx0iB>($B+(FIUAzP{CXT1!@dNOT?|}iWDw&5& zS*uaB*8ZOQ;w1DN&)e*3L!qXZL;a`1ZsD`%iV-w&%`VZ!aGz zLI%?OMh7&lm>y5_6gb?yS5HmtUphz+RH#l>^{aPDx!7rvCzndsmytBN|5oB3e^uGP z5*O42^lhGo+dx(kj&{4_X!CNw` z=;z|hJY&RYs+$P^JIU zv#P9w{25cGNgkaudkz%LmlX|bmW|%H^QeZAt8&s%6<77@8?Vn(@0T=vnb_&EpOO2x z(&V|g-mkAu;_6uy>ff!>Vuz{@75;83gfEgyK1zB))i0q2QG83*pbH^0Xle4nuU@@$ zDP6W?ppkY_#06j6C9LGJZw5|90yK3_d2p*~$7S7lUP+M%uz|DABlrcKoOcqwnzs^N!f z9mf&U($u|#ylg6!Eg8LT+pZ6*SFZFCb3nOr=D)twj@`4sBW^FD*RWCu>&R*@<T$PFIUY{oM*w5+nRXyrm>OQVAs;=K{%M!0*fn=ewmEZdR`*Pq%$eCd(T`*5{ z;O77e3b-M4>U5Ny3c(Y(W10LVUs*jf`|{F zzMxX2N))pRqm7o2RI>Si#PszL$hg>P6}7iJH!fqr>=~5Z?WRc@MpKT;hH_cqp=P@4 z*@T0;ccWtEa>g=cEBGCxsg$RF&qUetXC*k)xBQjD-)%tpcI!x$0qW2GV<$J>x_R^D z)?NFHh*{PsN+7;?_83=hKO_^$Ko3^g=))qALT2>uLjJXAVv*OWS)E(7U;&cT0&wLT zl_|(ZDR)}X;)= z^XAHn+jnka{><6bFKGmCPkMu-uv-`f3`Css-h(%&P8ncVFBjwbbt}TBPMH;P_x^oX z(Z2nwZ)3k3lr@9G%6IPGGkCarSiBr;B8`-ls#~)fIdZ|+vF|W-3XLdHq8QH5wV;&} zg>IrZ!WCuVR%NC_jvEIhv9Awhrfhh)Kh*rYiOSn{%0Y#3g>~-InYQNLXo0pSIe?o< zGIxLr)fsBms!wSWdxxgYnntc)w_bEteyq{h2d@>W3c<12x_x@$#CvZaLa<#C1?*U{=mzq+CVbuRif&+(- zYAS3ZBP$@5JN==^wk5i;nWL)rF45MtqgYM?x~O{k*pDU|SE33Pc~(Q@ZqD z5_|l&w=94EPhQn)SN&)V4?)wSnXvi#OX_lzr?h&Qre{tOCW?Vla#R#!C}1XLFlEKW zqqBu~AN(l`6-uuW%@9I;^+?J--Jz+>0wqdma=7tn3eb*t$f;weFn#(IIMW$o+gfF? zX6GrYJl};Qh1K#FE{U=w3Q&}X((;sIFF=P4>C&Yzu2{Ordhqy(ZEIJpsi$xjH5=8e zmQbZhDED!tNuHX)5|>L~PQ_z~`jrqnPu+j3?H_-C^9qp)bL7bJ;iLas?-+JO2AYOO zio7W6l}R(nDV7^VvAR7jV8_d*O7vH&T872K_@SA3DooF17AC29#b}0r2vgXW% zJcSE`j^^Ov>IT1u4+xpPpo7Mdnj~QuLFCnU?<3sKL%KwR&Mu!hfgALUY~sLmrt;_9 z+4E>~YXENCxP{K0y40FHX+q3^frEdD>HMSV|CzDhG$1kxXS zp>(-}$ih-=If7e~oDG6$hj10x@{kwIJc>X_=w)2(sx@aDvqX-;i z&ygM1sfH$X=g5(bs?}EN8z#3_s$6%#lu45&>u2qM;*k8NL;dvGGui0Z;zlriSENao zig>|mG@x0Gzz64$rerk=A>Y8ze!Vbu$_%Vrx0Uj<6fWcFh_xTFTx}+38%0UiG#S#+ z#Qkv&sF-S^xHJ`GPEaXF{A8?Hy_#k@KA{p#<*zz*hmO%p(DCzOxVY0=1OK&XP8(Wl z>HV!hZY0T5nv(K!F?ZHXk_AlkuG=0vw`~Xgw^9w-Kp&R&@QUX?Vfyq*6MFX^AZLrn z*>Y_D;)i-nOpFaJ`~-LF)6Kzw+f5`7<9F{rAw{axRQpldo68L?pQ9I81} z<96eE>JmbeDk+pFH#So?D^2=zF+IEWD%+`3`(yu+E977Ks9AGoL^f^O%(#UPeFeIq zP9dJK!=F8Wp}DGAv~VFcTP;|-pdiley$(NOo!PyI!wG|-VlCoqm(W+D2mMgbqcJEJZSmp(4MVlL3BjKhvQ~0F`GP5K1K&5r`IW*uZ1Rna@`4V&Za>Eo14?9J6f)#$pl4e8P*KT5wCgz*nHpq7rOM^euyHf028&9V4cd3@iuu!~ zb9=BshSbT?isgp)?Tjzfe08F+GPyp|#&G9OE$BmNH!4>uOIM#aku+sW(zQNo$~5b! z4sDI_hX+*#F5G`k6|_{;R1)Zno(H(XI2<(hlnqxeUPjvV87L@C2bCXRBY*yU_&|R~ zm8swv6aEQ}YS%`=k~O(vOw=K?$BxY#NG-6_R1C!IM>KbzJ z#q#El=-l5@=dS{L1rl1Z^^D_&$+g4JU&ujyzHOK_ZL&u2yL9!6<^o!2v_)b-(AOZ%s=KHS>zCBVHE>XzI21;LnHCP>ZPcz)8~O6)!rd#x_$}T@pE3!yv(xwN+)4i#5y+l7 zG1e`cf^!7Fmn~bO4X7w=&YwFU1A6zu&FhcprlkRa0vmA-V!U?w?CWAgE-5*$2$lZ? z3QNbzc_R~3b#h#Bm8L>@CU$w1r$Uvl!e4c$^I?)S3^9{8JvEQ-o8L71?Q4=S>LUq7 z^y@Te$*~}Q!B@AYZ>GibX5jhDXM}!2aPrJm>^^)Bi{{S6xkJ0?&EW!)a$6F_@G^Dz zDpV?uHtn17-iCJ4pCW==N+fX=D|OQukf`WLOBpiEEFx&(e#E)rf{lKcc7MUQc{;ce0V`CMc(A7 z#GoIY2yNf82^q8I#o;4I!gJ@!<&Ypj0<*MNE`5ipdwrV3rDJ2KX%ENx^M935b^WRp z^8KZj;swh*Te#sunsuuupk3AcIPUkEPJ;U3!|PXAwPr1r&!5lFkj;h0Ur2WnyrW35 z!sy+%FQ$(l48Qx22?nRd0}>iP($`zt*3FPPg%^&Uehg1;QL=r}6A9}eC~fP6WXTiL zbHyjE9y@}$0-cEqH5Xd>8A}IUDO38=(L^Kk>er8oG>-II=75a|O_ zK_-|DN&a2B_2r6NO(^a-&1tNl1&H?UbV?IJl8ud{qocg)$F?JVpzmafO9#hJlm3c* z{a|l{7Xa1<$cj-@*eoak4FqU2%`q|#HdNc2S_53 zt766KbZ>o_9Z8*UcG93xqcC6mz>MsJb*CQEexe0OP9D>czHn<88BldlBwr4^eDWBz zNG)#Ev_0m`nZj*pEVschYTMEz1}CqP5F9Nz@{o>1*Is?FoTfWu_0X6T8WaE6v}q%| z(oACwBvkTzb8&D-eR?%nNBqXh{Z+mvf_}=@(_(}e+?=~~IainswXJH=i;0J+M$Hn| zj~}CNUb=WGHwl&6YEk|0M~1(8%Tga9GeV|C#j>Rg4A#Y6?s&ecJ*X;F{LnV!6lL7UbsuwwZt(#E3Lp)?2({DoFdGms}gkDNt2 z%~gz}lPi`jqH`-6?XssM5-~6P`AaAd`Xy-JxicK-v?n!H(_Z;K)dn>rIDmW^PwE?n zqVIr#s6}wvhL$lRIbdZq@_T*#i-I&59pVNB=07A;!967dEr)^0~hx=FK%4o1albxH4vp#v4#H=+7~7}m^5 zQ6U=Lq&CxVyn69kb7%hY#T!CW23q?G=DFjHDDq!~ER!NdDn1v4spA);F-=5uqPY%R z4zvxGVLNkRlV#3>dcu+9chhShDb6&TL2IXxTw{TB&t^veNq~jZCyp7@rA=+6)7Djo z4I~3(xk3`Y0FX%OPDxu;&Y6>RajhI6RjJ96WkpF zjk^aA?ry=|-KCKaf_vjmaCaw22<{%-wQ-lmcK_!&`+nc9yEWIGwQ5$4@fJ=Q8>f?Q zFR#h)W^P_V!F9ELybyaVSPw2QtL;Y~?}MYPCq%;dCGiT%lWK`doZ36u0#I4VUbVj!CuqoY+$_q(K! zCUpTDNYd+2LOsawc#KsF#W<&gM2ke+Xi~rR*D$$vY?0?T*D7K$-tSfDxea!spB*+E zKr?xQ)5)HIOGFI}vb#LlHHHPHbjOs*^*b`6 zPo*IuRa6^E{z^0XNrYJ;|vA#Dna7V+;2Bx2Hs zFkVIfNK}}75&y#nE6Et`8g|oH8)9W9Y3zi|iAG7%loWSFj5B`kvnTLw&6BtA)yFvu zsAG_ZIU=V*yu!?i&09y`Tru(>_k(V4#C@8h#~D60M`1d7z4V{cddS&IQ-9ddFw%@_ zf)L3B7DARwx3YfkA8->L_a-nE1&<-ujbvrMY&hym`Y}GcNUgz^l0`EN0v2T?)vZPOMD|fWxZy=-!JcW+VWEzDi6XKUGq{qprv2w%}=q(^&*E z+UzG5plZ)OzIv z_Y2^|VftnI$K1yzAePw6Nw{nVBdX|?gfzDpDBn-+R!jif?5?Z+;zlxZo|qJEX7H)U zG<5Q~(OSGYg|K6b@T2z0!|fsTSyX2hW=8I7!<>CB5X>hnXy129%76JBEw@m`lggh42Wn~ zTS0f9Knp|!g4E;#H-jzag!~a-(wGYZj78;n9{~4{3?hm7tmxTfHs-|^9OP$ZDg~5n zI9zSrP;0o!$JAu=x&6=-+G%|xvl)gn232gcwbb$m=%K!_L(A3*_-)M=H5b-&=x#LG z=DQU_8xJ;D)Y=HhalFw=yc5p5<(wxeksz4gXV(8$hKl#WO1t-xNav(aM0m^CyrJvZ zh{Q|$Q?W`q@AeiUMwVbKys?61LjlrTw@9r~^;}PcwhqCPN@n8$;nmL1UYRt_Ha!A* zwTqP`ywiE1zUOO-f*?<8#r*%Kcm73}-sg7ap6~K1&GQ2^f4>=hi{A-S+;&3sq5Sx%q5g;ou z7xr{}sZrwmM>=f9FoN=1UCyW0=0Gy#v)(UT)R<{3!RUX%7HLsw*@?lC*U90uuuUM^ z9P!ad3QiBW`z^saCVP~2)gi_IlI^tYh^O-eAPq?OTU)&!R8>-Ubb{h7kKkKNBALxh-@tZT6^^GabMcifSz>OIG& zmfHhb4nJSbmwB&dN_fkzi?;{3d}OF7`aS)5KO10&5>mpN5Hk3J5aegSFK-8T*JmZg z)*bJ2a~PUr2=il}0e14gUFFHZKQjUkj=4FT9mr z@AL@6=jMlfA3Wuw4nGm*ys@iF;(n`6Y}XOGoMtxH=ujtW%FSl$sIAIo)AbH7EC9PY z=!+`q1yab_^0t1Dk4sZ4b-8H)UhkeRJ5n(MU=uYgzZF7M!jjkmo+D~8?>WN{ z@yQ@|+0sJR=C^pKZAn|#SOFLtf9fxITwY(fZkFcf6W>WSYc?_>Si=DA*7IT1ot~HS zdF`!hf0D^~gWfqC9o}Y}O&z^PJZhVzY!=#~r=h!uUo^e{#})7O7bnXj+WTTfmrTax zX3w~A=aGNZ(rjpwii1d2eh?qwfJ1<-Yt*-S-w^iRpe^!!2dm*Z_%FwVZ&^*zNzG#QvQ-tL^xEUkndii73d*w!|cyDL7jE?%|63auJDKkyc6RV^B=p7hLFGL*~|;d*!S#bPoQ=h1m{F+;=40+zd| z2qGzGBXNC!C|}#Y&45N*rko72j%8|--K9mKLp@tG#96+&^N=i4CIdzLC#xSobBrt4 z{SirwJ)vQX8eZEu)U{T}!4`#dpAngvv^qX9JHb5Q)bU~~4YAkpr&|J(-Ma(Q8S6;O zQ`Ti8JEQ#EX;}FQLXE)puUa zp@uvWS9svVc`)K+b-X?>EZ0IsEgyd*MTjU)U%9V)t&LvO@#k*I_}&EAoS5j41v&OJ zQK&k(1O2(~MyYTW{OKd6LHr+g;=k){w(#hNS4Cp)nHK&ll>a@&W~U40zDZJBuHKQt znVk*rn2i|mW>KmBvQg8c=~k?AyQUvGpQxF~Tchuw5>Y@vKZc=*ZVRNzb=Ww(msRe& zVoRY>5Wn50ot6Yl!r7X5WKZ3xi6?eFUcsy~jwLeS6i6`n@iEy=W^#QnE^bw_1SF4uE)raU=4{<(lFvt_pjCM)GL`3b)?+70wZSH}*=18u_>-HVS)xtiNf@M=&33JMCUe30386hZDx-450Yz2I3y>$Wa`rpS8>9 zv980E7u1+KK5z}r^7R9W#@Hk1-GS#+jTYlk<}%8^q>_oR6ce#;)0hjd;IZ^Vw)2`f zjN80;6tkQDb7HqMVcc-;qP!F>c+}6RXv5wT{EC1HHtg|-H{^#m15fCN$~eq+$jY2(Lt0 zthatqmd}9u3KPc`vruecW#%J2h7%QpBZqv%pPX@MoeWT_8pQ>=;+0Gq{O1)c;|ilb zmQ+mMU=@&HRtcr>3!n2Q$S<;QjhZ@BA6$bH-6;@B!Ck&e=^nDqXJJsB65X)Fu5 z6RbC?iOFWG`?(-9m$&uyS8zn9M;EEd31+ft04YHXhjo0&5W29RPPTwsd6?O+@O#1h zWR{#S!ob$xt(Z>+y*_x(HmRNVy<)`89=Sc$13k4dF^JPib;Tok$N^-(z*qdZB%P9T zFII3GzsDmGJ1OZOQXFu}qtP;dH1pK@?)u7UA$iNMDp&`Z2O%}mGmXS|y|uP`y?wqn zn48ar+vaCiN6^X>{>De5IK>0#Y;Qeosx4|Vu<)0$G7o3pUe3TxpR4Gb170AOfV;@Qu?KuBd{(ifB5?YA)&mRt zp@ppui^oc6CoO+kS?uMC0k*kaH}q*maUyyA+W!6@_&O@*f6Cg7XA9&ESAT6Ojy1qo zD&P*KzFPy zT1#p(?cWa8gR^CaIc?L9E%;kauhqW-5qa` z(2gOsw2uU6e-)v}|fQ2LstgO-L%wiF&b-@^q6B_9ha}bT-R?ZG=TE#BS zEs;fKJo&tL$h3e&&t=U`!yMtWs-r67zsejAjn;@3rc|El&1M{hG$%?!dsbc+aDwkC zTjHM|_-`+FeK{*!4UaQe=tCxPb#oPlI#9t^46KzDZo>!phTzvgD&yu-<|Qwx9GDa| ze5-V_HXh*3f=01yXwJf)o1hPLnFsO#DF}})I}l||yCS4X2L0-6N1oc1DSRf2&vMeu zh3U3T1|D+Kf}Yd5D%PW4-sS4qYB&AJYwI|V5xPI_{^6>h_D-!Oq;YumvTrUC5<=x> zDYs|By&SGc-aBLYGF3y!QOR>*fI%5G_@7J)6E8^SBQ`gM-qatJPK!4v&BI4IFN`hV zRGUo)+uBLw*Klac@qBNB7weB|FaPj}_7zEF2&IKmGU`!}>R@&iTX-xBIm@@8J0V)d zY#G5`sbfxRx;{fyV;a%g9Fh2b>nXF@#`~Wk6HaRZdD$2E7dpz7Ri)N zOe`$ZvyEm#0S&&VWFpxISuhG!N0ikCx)%+U-hoH*RPCP};(?{Kq!*;gG{JwbODv<^4?pz9BZ!x_vk)Eu=&?^}B!b4@g zrgf`9H9A$z?xB6%7a;Qp@7V01&-%R8-a5 zZBRc$$xUWFy)l-rLELO{?z4}^cKqv&8C22Rlpu)l46qnRFzJidS}@It0G4^{BC6>9 z$|O&Dtg4a!FoZlkiv0WhKiBJ+Y*zC%TZgzNHGtW;BCG8?Z!EDxQIGm3k)h?HVai>s zFRq7wNKx}zbJgjruu&5Vfpz4B{B8hCUozRBg|+@d7!VUS**SkigG1hhRtXIBLKx3V zZ83@@NSWIVLTt_-$LY`rI^HZq6+(?tyh#Is6bv8BIwpmQGU+Jf;Gl{#n-iwN3gY5j-}@o=0i zRFlA^SI-yozHCRUgyCVurnitNDsT|>Z*h&0Cy2s0!zbs znUGs5phNNgzt%_4GhU%{Gita2ax#G5pw>pr9X#eKtdPct=K+}$tk&b8C{w;XAi|R6 zltu0Ia0(L%KuErAGc2-xrd5#_8B@Hwn8mpieJXM-5ohn9?d7vvYh<1StJk3fvDV&b zl~cf_;tQs9-Ysp}g_Vb|tgh%WE!r`Q<7IIBvEwuANBG|I?$Q`WJUZ!_XFNbNBd1l zZSQLV`EOIVI;Eq_7rwAFC#^aI#8vP+O+c7)2Y^4{z( zUH3Tt#cIHyN|}>)5rVjjf#=7pZBRCgf|btMR8n(@)Yt(Pu2t<)IUZ}ipj~FSNr~x4 zCIO+K75i(xQ%SS|p1jJ`cW#VlC#|L|L8bNLdt|A)K+!GKJ`jt`H;=)u*~iRe$D*nu5)R6on&ug%!Sx$e8pjJS=*OFZcw$I`v=`}?zU{cqefR*3tY#{lT&xp&Q!)sRV;BDe|wY8*9 zW4G~sKv`q@wEv?jw(_*sD(qM=A~#ZKaBQ&5^(Wh&3js+uW*ijV)V{!cseVmfF( zt;GJJt=!|sZt-ZXKu0^iwZU4_UDzENBiOA@CArRJT2|RDA%<0Kx ztgYkn;vdzx)G3fpR{iL9t7AJG`?lMR}RokEzJcBO*i)~5zO>z?w%MKO9zCG z#he=5ER1XRgo-{Yp4}NUGWn{vK?3ht?_)c4Jmt%G)umZIKi){9+Oy;KF^4TC5*Y-v zPBe#378yx2N)$~qd3-~zXTS=`QGXDx!bIziUwdt74Zs?II1J^+t{$7OpejR)_a zp`;L_u?oLMF6c_?7))3CY5Kl(LjqIF{w{+detUjKC144>bb&=a`K(UOPGVp{XS70j z4?`_?Y8i%BH{)x9pjffebiQcW=8p`?mG8k)z3%*yS;=Z4WjQ~#{?)HH{wkfP#E|VL ztRxd>VjVrRV9BOT=3r)CR|HbBKA@u)jO$b%ce*XkWiDv#a5cZHto-U+03HjwAW4y# ztELbOQA;Z=;37$Rj&F=l9*f%}$UIyi1$-RD_%4p!bNu$Y^nyU{nH=HNru5;!HgW$k z{_!uPZvonAe?NHRoauBi6aBUOkLO zDhY<#8}@jCAJn$4B~=hWiojwwW0g3ROQEG5^kM8BQjb%g{7;HvUKqZj=}d^nwb^#6 z=XthZPKCJ$UPz2v0B^iX=~=(mzT;IwN=4xmUr9M45RG~N?8M>~SAH6;8GE+f6m~+N z{YyNz2kmsU+J8LbX=*<Z7Dcq zvDtHkFV)(CndLLjA)1Z3pO8vS1Q-h2f1qv|vuL2uTRY|L*jffd33RN$b35QfTx zDxh5Q5kT|$a&bu4=p!e(>gWK<8)WU!Nq;x$R>&_4YJ4E#K4G zGYtP;`1)IJAs@A6EG-fR6}@3bJe?y80k)`!x;!8+k2b|vjfxLmI7z5rluIwAth_~d zk@o3=H8#YT(1)&ZwF;9~G<9}P9uA?+$$$>19p7jMX7}hgtR`f01bmY^7qllyHw^WTs|^~k4Q%kNxdN=<5cIAd?pgEHIW#wj z6&NniJk}D!Jq3yOXk;_^v?`0Wz429>+sbNrjp_03=&DAj3g+GDqiZag+gE$zw0{|#RMx8*P?@t|@dz~-R6HKf zYvl=j7$cftX|_F_EGl&>3MfIu@rT+Xi#dnlK^9iojyBe%H}wV7Uf*ctL$f_xEhv-D zl@#22?ko@F0$i_I{jUG=>$$Mc?Q2ke{@D*sOL(Z=^}W@^nxxlX%?e_37AxnFgzX)0 zN^3t&wtm~{l`ciCXh`yr8&b@)9dQ@AC$Qb%X3S`xBiFN;F`>5@%fW#f5+wWuN{EC! zPzM1vNGWORh8qS?4^rEEQNDgl zO^lItfL||N^TN*NK455gVUz7B$3ihyb)ncn9b;l?Mj~O6J}k!yfNopdg4^~&DU|u6 zA5MNlgyH5gD%XVUT$czac#OrFrW`R0tRm*)0)yVAQSatSGoK`%Q4VHm9SI!t+j0cN zoNaA9O@C`LV7I(nfw^4CZ?BAmfeA^2h24;sQ0NcL;?IJ~=^n%%FI{!4T$LhSuHZt; zV592j{t-Lj)JTc-|NCiGLQ&xmP5%2hh$ zLsh#iy(gb%M4nYQ%bdx%O*;8)%~fl3KQ;4MnFL+D#BIC6Tm^?a#TK9}u3)el!aa{2 z{UvF>xUu&G5pX5p9z=MOws5ak%znV;3<;c(%2Y|EkW)OFO+4EzcR8|l@@!Z1YF~?ny}lb zH|@t;$M`1La~^G1cubcH-ALvtl&Q6}nIf8&&~T_ZUG5LfFbIBEcP6|+laxvk{dFoTIo|N#?l?cQVRznU-_2a~vQAgvV{q#qjrrpp3IBqly)y0<>ar*n2EB)e z*{mpaMyjj*`U0{NdSY(Z|F}lm(79<+s5}KaVLBx=+`-&B#iPe7>am{PMP#Cgg8G#< zG$lokDUsXm36TlVi_OpCeWd+Krm zAX8@(P?35-%U)YbC~J39u}xC&xNl`~lH>*B(wG>Bti$3ui6%TS;6mgJZi)@D75k!33Q+d*_b@P zR$HZX$;VO-<(vyA7t(A7k1QRzVb?;n{syP*;Wz5%ePYGly=7m3oDaryelM-;=Ny5c zU|HAVf7aaU@%|m|RJw(s-@Fg94)ss=WP(VA57|aKt;!XfOAK;sUef8l!^w582Sg^$ zJ5z1Z<13tjExC1iUbCD=&PjB5fPIfnhEmZUncP*PAnq*i#fkX6tuw!ID3R=%K3gKU zuUpn~1A@t_*e+=Skw$+eTc)=JhNq1dY~f-e*BaOL4`U`#|#_H!t`(KGPxV* zei%I3QB}y5Vzk8XQ9#p(MJSs1@AC8@Yt@ChD2`5NrHVMubx961(Fov|)3DU)T>sF4 zE|}`qpfq}eVS@;p33?w3P+UV@#|54@KqXIjXg$*$#L|LsA^I`^PdgQ+Xn-on!+FD~mx;%8f=_je zoJ=b{oOWJOB23zJ$XXIs5k?FnmIJGn5T@C#hyb%B)NN4fwAMN5_OfX>7P+XH$ztES zUtA@Ge4nf|sMYiTwBJ}%Fc-hsp2g}mg)3&U2NttumGo}GCvI&I!|z~I ztW9+l4OUjNx6_r*xxpzV3E1EmdIgGQnIrv)Eb~HI$ zD=4NVObq62WHW{mhKVohX8>F)k?mq3!NJ;X@@Y&z**mR8+~2v^PGqG49AA~i`hqy; zxuQo+WJFOfhJ=A$W_zoS(~;vpIIR>dN%;b!t+BTN1s<<-2yj7)^gIoKg<&lso)v(~ zE;R3}ySW25j8_7+%KT_+JyPik7Ah{Zbnz-Zph!8$OYZ?PRbcN@wUIt>InuNWOcvHm z9YSdaOh{%B;zp5%9I+ZQ{h3E!V+4w5Oef2hDT z|N02yX64sH`iX=}OF-8R`uEU(EZrxm$^-ytnpYx~FbD{su&zIcaU37-%c>>W7<>aF zIKdSS2lytfH;K!`5Ya>zzeiYOPg`O;zrwBV9RIZ+#B%NB zEq;w#`@{PXOGIs2fE$2xz_iqVSVMB`Iv+)=L7~ALgRVHr*8CMqZJpf*tC?iEtZqWJ zP*P|`mi<^7{(18aGKZx@B5=A9A|m{PS!;$>VBm61qnz{K{!y%SUmQBQ&{J4hoUiIf zPdMGQ5&xk6_9s@%Yvf_^#WlUYdF0&+n3bAZsrD3pmhmuO=Vj}cT}DTZeLb3Hv&s?Qu67Du+KS*yp>ZL|_=n|f|(&$@FKA7ED$hn?wN`x4~EuJ}M(m9Pd z@>H!nc%b8uk%d!1X$CHzkAx~lO)5hJuE*~5XJcPoINq?EoC*6Jg{*oXfy$2p| zlg*~aaN24gk%75<2EkgE_zQsjT(15f$xs z!6CI~jO2WT3N~ZvA7UstO60X0?Ih__XTgRuIIJ16%_o}}OmZ98suOV&ZM$J|eN=VS z@RKw>v^4h1Bd)8+STy8u?Wtcnw4aDt4KO(y&iJn_gK6Z%jXB_N=Ea{G*1KFuu8-lt zWWpy=h^~TYXVJ6xmD@bKDGT!KBjJD@uHghKnC^@F?b+B{mq{eV$zlt%nxik~{ z<)$2+=ksjP%=c>J-aIP`$4FRT8xu+$zTEimBGz1X0Br?7Ju}>k_oak}fMgslKL zoDoTgefMv#)VTh3_hH_nHE(DAm%B5wcS6jQkL|wh0lS|N>LJLb9^K=q=;5x(vQdv4 z&G-b7Mx7zm&G@-kwhzVTv;8ksOhZpJ5`j>1(bk>8+u?SJwO`V!7%i(PPl?#jDNEE7 zP6^E5qbTtMdVP;+=;@x&5{O*) zlF~+ik1(*?3QSNZu{cPmfCSt9Hb5e#n~%R^dLuBTx>>=_R4BFw&&jA)n)+yJ^%noe zZeafF#NSN5uXpxvywz)xY(1d6f#XO6ZpKrk=UT*syaLl(?fu;1!A_p4nGy*F0X~YK zMR0prE?CQ;SsVMyNXKkGw?3CWI%RXJISNPgqFl`{b0C+i4Blo-b3#E&Y=PEOS*FCY z2Fn-pzTb+%ot|=cccbQ~(5!3nh%F~*`L}iN1jiv^tzkArCv(sQ^V8{4B@1Too~DKw zh2_Z)jRHoxN7q!E%fCsCN?DNuQQeN}C@dp!+}+VA{S}suGJ6JzKyi$P=Ka69Z4I03eEq5B)l4ddU*ZekM$7QV(g!70F@t1h zrot{T+b5HOtoY9in^PJ;?Ik`1bWyjrrfo9k`eyNi^zdFG{EcO@(PRY1I~Dx@eOZAa zPdP=2^B@vT5>9|04I3}U}H2Lu?(KUkIyD0`(OPDyraj5&JRJ^{u^dr?1Owf+}ZBJGAopN z{0rb6oOAc|iZ`xZE8SwZUorFf&L+gVFxgCkF*890o1C53qtY{6d;MnoWO|`m&hXT{ z*Baki=W$*po|NV5D=m=%Pb>Dxus$@)t+Lk4LoqKqJ=OA5(A84@U&T-7KyxFBHC_H= ze1~#<<-;hY^PfWGO zy_GC~pf-MxjAXh3KpU=+rD$0B5AZ`}xyy?Me@b7GJ>mVp)@iJ7Rx4TO*5j7_a4fs+ zX_aTZ8VU&bacRWg=DJf^gJ#)qEH}JWx);Qcegn*-G+3K8M67FIFzmdm@SThySne$^ zy8hEJ-u|knjLZ~<6adDYjN4vxk(^)HaaE7wb=Z;$qX8-@N_Z59R#@#{kSI4gYzjSt zji2yY4cjNw+`{&T<^=wO7`WLKQiJa_gsy*>> zYdobvp+&`&z#W<4xxmiI&K}@-u8=u_7`RL6h0DZ2NcIgZYfN>+W|A3MEs3PNx=5tr z(<$T&$+#4X%bYLWc^mc?lKQ-&q~_sbQ`Iqx=HrR>)34>IPs;ksov;7PsD_`ud^GZ{ zw~Kq!bkrL>H3G))8N(N~YDqQX6Q^h%rlrIbmI$)UT%qRy36?&+UDnq65}ygolWM3W z0Y@&0ZeV_x&3Dze57Qz-7R4s%Eg>uJv;a75lp=XWjdxZ0)pxfN4LbE<^Sgi9!DuG% z1af~0acM~O9^Xqz4@69FU+ug1t&9~QTIkjezEC+k+N+d+R;UJQ6-qu1lre2HJZ7SB z=umX(43dppsjm4KV5<&W2G8daU9V=NfBj?e#|YC!{`l$4a>Q=<36E zF*E`L6qi5WKupdYoM>;?IVm)!F>S@Nu6o$0W6HI_>G<=V??t(TVA>T{tu0En7H}-G1X?Qi)+c5q%b6Tm+G@Ac*WPc1Z6Chs+6^3dYW~%R9)w zngu^ZMq6OJsbo*3Q0@&3pm% zKaIPAyvWY{)Jr-Rhm*fFNM!&wB$c>DA-pr2p_O=aA`4f^@QA*D!C%6*z80HX1DV!G zy4JhA&Gai|7V{2jHlC&)y6s3Iba< zf44bbyhT5BLuCnb?uXSKT>M!4)djSpblxwab{BYJba=?3+XIPTY8Lp;w4t& z(z-&G^@ILn(yK4>>GTmt3717uO|3|K%r#k}Bx8#e!%^3G)0ajeQ0^_gS|`qxHFf_13ZiAw1}&Bnh+`u;+}13zL~$?AhIktjWIPE$*3e6 z)fx|5h)zIAlLxNb_5#g~>Hxo>>rX;cA8ZV);(Ub-sGyDe8fOQxHrGNwtSM2w)^=IU zg1@srzRRRu3}7`9R-vW7ZjQ@t|0GvGb4YnjomUC9M;;DXsEl6+j z%_??t%bVEkgxoGoa|S(;Lx{_Yn04!M<+h1i`@H;!>Gex-2OUYTc($ntx{$B2eUlv~ zFU{AmF%c_`>saOHEIiz1S#&$Fp-#ArJXZ5VTVFRzz7!_op1>HZ$+i*21Ddk&1gV?z zTnExRXcf4$_vuVUnQ}ClJD_|wiS@q1Uk=*b{9vFPY14V{36hI1d2xHpetEpyIkaeo z4wyWlFJUAX_S;?Bc}5q_`Ta~>MG!ksr0{#D!AR{X!1Y(XF?+Wa1k)=pqUxy5^ezMI ziJ17m#JaB@{MV?DQEWn8GB@SYSVeHGbh%`ic1DuTb;iA7SJL~LRBF{8u4lqQM8m9G zgTvcw8KS`2QY1Xd^WFtqRK@)Dy!+LiyYojvPG4%vdIM-qx_MJLve+Xv6KN!gEMkk3 z^F@;|dPCrTcx7HjEo0rr+BPV5LWul{ z)Pxn66in3e( zJ7{(()oj3#@^+hV$!EU%m1xs!y8$u?xb~4ph6~ggy316n^=FX4uEew$O$yi>LaVCb ztIg%YWz((r(Q%VHeVc5t`0mIS7fplnL$6%BqWZ^kh4$$sw5R#Z$Xej19dZ(Z^8;h9Mo%`9mO4 zW@l(f(yDbrA?zajv*Me$?BxzC>VUY~f}Svp(Q1$f(4shD_tqm*8IZ;{kto6>4e~an zk-gg$ekO}o_Ic+>1Z=Sn(B*vO#ER-)yaV=Z3YqWrqz=E*A?mn~{ta{4UEuF*%?$w+ z$rOGH!%#>zC8Uo1OE>L$@rtK(JvO)qJ5L*5ln&rC=m`X+bmnG_Ke)(4^g52010B__ zNEh%G|2eFbN8W=P_3O%g@P>F1iY!n65we$y_V(%GXkgKP)j@aYh?eB;@!JSrZuW)U zxG~!KY9_7Xw~Q(GIgnR{3P(j9MIBp)@kcvSr8aZe4)u_ooAvpc=Vv;es_1P7W&^r- zuD(W>JWMygm06at_l-3WuM)y~fC~u+9I~SX6_(0#Z<;QNZ~MRJ}(O zay$auh&L~r1LWI!db{#8+pI9+cs^6OlfPLs93P<>za%S&@&P1_p_C_Rous3z_e0}5 zGxUxbAXj8r`1Azu*=%u-V5-t#9$oomm8wG2bVS@~x48N|Pe8`8K_@Qc;KH=^|?!BKC%;M#QLx%OYtw$ z{i7>s*s%7I9vFYlGUvez)dx1_A+Q7~XkfF^-dJ&{%2=#mHfmGJlK2 zUFZ>XeWy*EIEyLsp59)lNf^oOpu9O8gL+LXO*c-oMzZ<%yqrb98wCHt^q#9n`g`+A zw@bIydQMyR3TQoBmiN>P8gQZO1-_6I1V>H%+xjyaU#v@>_*vWqxO5e;*cABblRXPy5q0ZE)N|rklmc}N)hm)LQf9~gz0!X*3p){0~5)@f~$q3 zq_XEMS_b3K_3Pu}DHT+AO?ER(i(>LXdONzV~<2V=y;V4!ZcdJiB!P}IMr6)l8N^-0EhN?E7 zH{bd6U!OXu<->)*=MC;wf)gum|7}M{ZHvKq@}by}9(QOA{hb%&k?Y88aN4lqcG65> z+*v0>wm`NVl^iu9%2Dk+@w)L?`ootjJMWf+)TQE|<^NNSUTnr`nuBvc(m|*0Um~X( z1wENnan3)Mt`f=f2w>f8iM6xCnm5WnvMMzWXFW{@wa?Iz-X%SLevG;$-`mj1Y)E&p zKpuJWa9Vn8v>#^cxE?2SB<_ck1#NuJR09YpRYn*u-cA6i$?tAnsADO$vG#mn&7`p< zF-QHmnmt9h;jskM8uQ`IlDk8r<}&S{9CoHOocp6KB`bxuZH^*6GAlaTO%ajFrsbY* z#Y*HYUBP3%LV+$3k}+1_}G05ULFPI|0#vpy_f&5G5f(l`7hr$ zM0RgKX(;d#NuiG_3^EvVd7s%@F0EN>=$=?s_SpSAFT*3`d%{Rp&T_F4go8t9SI@7s zIq;qv363B(0>{Ho7-TslXMk% zR2s}F9ip@AyOy^d^XIuS0)^mJ2nz`MTjdnt98I4=6UL&BLT$uc4_zQX+ z#xLJN>}8L;&zsrm$=0q}>n|QIG;MEFaX=Tk76+splV6luqoueO!@$D5VNg>kJ<5C*t|wN$bE;Ov`fm5m+; zA1aIdZR^iSM?C9Zj1)wu((}pA0UE3+R+_99Qu-u8jv{jNm!j|)UEO<`@%i7dlG#ng z-Al&seu{JfF9!!@sfasjw%B-{wdhB&b#5i0XVT*R^;|je@~t43d5ffyrer$N)xYzO zh;{^xM0rgM>~u7Wm&DIZwK`Mp`{Iv77vHPhWg-@vSs(ga2NUs%la=%&1eRpj{Pj7( z=Pr|a5;=8YiQrB<@~Z@5p>i|8?#l2l$V25h{MtG*?C+gFnd(zw{v_K#_FqdP+jo!&|ZK%cJ@r#}44bvtZEsdkBtgucpZ?MYfA+U~nGx^WvwXu`Df%F;g2 zQqX0gm{MHDPK$JSBgSR7QqkM}Ehrk!P-aROvI-k9p$d}X=7b+^GM5qt-VgsDuHLaf zlKzXgzA}?cG_h@KV%xSgv2EM7I<{?1Y}>Z&&fWj>xzCgH2KqtQZ&&SIwZChHCm4ZJ z>>^Vot7$WWWvXdVyz03LJQ2-zalP>{X95a91SUMn}+pH!@`AQalkbBW~7V+gvufX^%(p@~^wHUS}->%d& z)6zb5QBpDJ-k@hp2?Vp*=Wu+CHx;Kzw)ZY1ryHfz4eK9@RO0bv@afj;pFBgUx4t58 zLqw9>%>pMGkrNwdIdiys6kXqx3KQgA-=C-BM+ToP8<1SPculu*cVz(RomFeuxWc9WeVv#ojCcHJL z@BB1c)F0Ib=MRp@)9k>ZMzaH%&2}a7C&7^(5*_h4OmxeZPzNyM{$Mn-G0Mk*Wx6N_ z+Y6ORJP+gzIUbTzM8VR2UByZ<*=s}SI*TXA-?)6gXL7m*=Zm9yGtkiVARvC*v}gMk z3{Y7N3dcu6U2n}gpoWt+_Ps`0}gu%h^18S5=pa>u4VlVsN zH~9J(Aw_%!MIgKATSz5=thZ1we(x{8C5gksI|~Z`(MVk`7XWv6z@UE&Cc8IFXk1qC zVFZr{49k8*9pL;w`gC?TF07cM-;U*L$lfSo#n$A36{GU#QLSD)vYGz|7dWG%Bpy{< zFN;+E!>}ol(LCjBCUGU;`HV5JJO~VYdr-dTLco}TQ2Xy7c+Th^BxT*`u%6O`rCW;E zXzz{mm-qZ5GZn(m{28Z9_%0Ve)E_G})d5$wKBw?0cxzmo)``1DLWdEn7`z<85izDy zV$Hd*xrW1WhO*1imtZrfT7$RdAGC2yq&zNCH=~RwpW8c_G$Ie(Bl7psu=XKMRn2iciMZnu-?6gfE5}K+A(F| z@eHM`R_@o<{!wQgsu8osVY;wTo#r@0G05uAZC{FlH*z;>rQ3>|!nT9sbDGFI=Cet!W_XDFS1 zfnM`0hYh(s7K;3z4kod!ynwj!52qqsLlg{oj-&cE#Ro~^UBI4U;&#Yjlw@+vGik~t zv&j%>qX(SiO{NcNv35_A`Y0OkxyjJ9pf-3VIw=}0yXwfCj~KbEm-(;IT=uuEPS;@4 zU@XOm7P4gYZBaff#l8D4gnSt+jLkDxvxqbs;khmkB)QKMdUiOX_D*gtoCl0i{kOXy z$mIcXgk6xMBx)oscV12oUC;U~*UJL-@S7r$-oBXjKj@=UyB?7GSyRp_l{nwqDf^c! zFP=4>!HwR#Ci5}9Yo+lVav=hUJ8?9aVm16jG%Eka9}7D$hffrJRg||cmW;dJeZm9= zS?iDC=wH&}@F=JkoAoxBpkMLR@<`816D#reCY5xUHUHT-!m5_4b^k&Y_(Gowa#*lCBNJdKcc^m-tu%6uOOA2Ez&eP@9R`vB#YmC`b#PS_|a{~AoBSNP5EIw z12GyQiFNph1Hn!!4VrkjN;>R!OimRH{C&W_uoI;Vyzg^yK2(`9XVx8R^ zip^@QFj75vEH}dNRj}P#3`^-TKR@7$ayt1bVinr`ZE#lXXG3UZ`uHUGPA9JMM2QB? z6D{$eJQZd`3T`3)&Sby;m#~3au52{krU+9EbtxfWeo9u7*96R4RRlXM;`AJ z@Hvu-#o!GH=09PytWBZ_qDxDdgOBZ@jJB&YdOCBQTHCZ+u*5mOK31QQYd5}NyxHtYis_HK@^6Ak|72OBy{-}5OA|HHl z5Kn5cd8;NRcK5vBkd;W_xeL!~wTtF(d8G6ZuCdW>vS^J?Qp@6Yn36ub`L+U&#xoE-&=jsQ>y*?8EKDrL9s7V&r|GEabC98gi_A_ z;&8a@;66M1RF^*xPhp4u8=oZ}wL%;`g1Fqy5gnwJpPzgP-%O40iUA-8(nPd{o|@W! z%wu{9g`$;jd&*|o6Jd^BA&3zL%CgsNEsCs9q|gjW;szY!brO1CQJ)ud?lTpq#1Q9= zCP~S_fj-KOTPY2>TRQHKF3+5|caBiR9l{H^n6gh~pEv6|WwI5b$_1&dpOWem5FLzqwlFRZX1a4=gX2)c_g@0?W-a8YLmf0W< zxK}I|%B1e1-;Gx1{&Aodiy??p&>F-zKKsvlijWV1WohLLq@9J8#i}lhG5&d#Y*LtdWU^?t8O!7f4f2Sg z0yx}|YLYX{q_>`+ZopN`qxAH1>-iAW*`#!*ByhLOnkj7Zvn0ub#adK_->a!spB1@2gh zu5N!nZv#lrxCjGDO=;ZL?nRwYbfAe24W$QGR3#v|DrL95;_z>qUd#57Swd$N(2GL| zb*VF9&;8YNxBqU(`yOJv8KKG38&KYpoQ@32Zgk%yRN+X`O${EV{N5`-#KSS8u1^3F z!~PJ|$AgD&e{mOj6qb;F_?C>@F-A7a^w;s}N`T>xy$dw^%b-531v{XO48(CgC0(1lA&%7R}^fAYAJSPDd{(G-(jo^g%)EEkfZ+YNAXqJzXpgXxfslIr;_reX@u0 zeL*UPKR%~)xSVSS1`0>V5%9_!UtT_js*Y29mt5F&3OsfbiQ7GQc|eX8BtR%vSr=bx zt94(dk|XuS)tOgmxcqyb9y*vS*ysiU?qW;PeC2nHCMw!FeB9BwSZQH$A4BdkmQn4t z+T}?%Qao{TiXN?tg0IAIIUR9*QT=gwy-^zuM+Gy=5&@ql5jYCA5j;P^%m$xROLT_D z4CT8&GMGy&4F4dp+%?+mz!R4(;_U4sov&B5HyRw4@16;}>`Y0s3cLIilM&cURFxR- ziMfukI(V%A>5e0Eynpes>B71sl-N+T)N%+c?JqiGX5Az`oxq4`SFdzL%anT;@(B{B zH4yP!$9*o!AWZN`g`l}tRTSJy4tp3Lj3`Wq{j-#r%Z~9{g}4^J{-MASi)eR||VkB1m|H4YYd*OPnt59bu~^F}^LcR{bXi z(>~0QRW6yKQn?nJJU$I%Lj0W%UV5m4n(-Hh-W#kz&1N$S992wLVqj#u%8 zKjz#*&#TsDH?ka2sg(l~OFzQ-)BF1k;aMy6DkkTWPNIPUbBCG=ZicU<{Ug4knVbkA z2(ZYP9kF4kPI0;avehiR@!3E+?SUs`HXB`#bHURE7sF!gT{N<5w0
$aJW7M^5W(Z7t@e+@KQBvbCPG!MIH>w(1K&^Ku-W@0k$?RjWTquWgWbupLb-#6 ziSQktOB!iX7I`P;%ZL?9jVU6=aPYNJZ$Ump#_4a6SSYtQp|UVPGne zj)7pNP!w1QX%n+5lFtVGRmB99%@`JDs1VmuQpT$h%{1tms#GeW-SBr6^GRY)l0Hp` zcrp`-1&Ud_p+ZRWE2C)%^rVQ4awFYjaNA)~g^^>oj1~sO?S1Bu>Qw1_6zH~lBW-oI zEJSN@AY%a7&A1}qktAd`X~LD}3}K{-2+vn&17G18+k|*?e_gpXhV3Pw zinyR+M3T9jFMc$888#MIE>re;Jvdr{+?4UR(kx;(o7Nn4R!J_yxcdm`W>uT^IjPFm z2J21r?mkW^=(1wE;9LOaIB`_COxSUM{(&fy+;OGhS_z8Y1m}B|e z5MLiJMel)x+9DTZIR(x)(U7#@KQT?`Vx5{cTFv=HU6Yu+20U7=SJ9cM;u*|FOhX#p zjAnDlS5A!!3OW7^59l=_PuOURMdq60j@iVqqTtyJfsj8acpZrIWsw8^I0isv$zulc z&s9VQnAKO!s-t#TjxR+{%c{ttikX0|_ z2><~a9foKnGFh?tg`p2c$c4M`h>R#S`q-k|^PJe|`c3A1!^n2!8a3d6OTZ1%0t;}2y&<8CKFW1?FO!r;H{7gU=^ z%-g_;EC?@gNGs_ zk^7>MeIh4@YsSHqTLHoB>KrDFWc?k77sq(O#yBxjw*OeVDIJQ8g1Mq@eq!SW?+=aV zS*5kGJf7sOK}(C%yb9gQiV6KoD5QvJbtv4mloRgMlh1uMc;5tFtNq-eY>v6=P98e> z+e4BZ^%f;MtuD^65b0FKoo$E=rjkOeGSntU(|cH}Q_vaA zmN|oH=O=(kSet;;u_C1a<5Bs2$Fm#N;`)c)l+R~&*BsBYnUntFQQ`czG22xYBO#P1+T<9G}iIi^FDCfSMaPgDtsSx6o>}4sdxIt|rw- zA1rt(r5bq*e?NSSU!?f0uXkB2IhQjk>UjTUwNgeW@tu1pNUPTrU$CoL#<&_+61}~D zek5&N6OxZGB#cg{Q{~Z(T#-h{`P96Llu;dm}4jfm?ksRiS<;a z>4aDGP{lQq6oHJchp)MOPC~*BAv=2_07**of+)NE*)9_J@GR?7<{9JU^9qG1Y{rN z?St5p$x(pPayt!Nb23#nb!sV>P(`zcyudqiSbYs=h>xqKKWio19 z=_ppNIT(@l`&4(++HZZ zR2p^2Z)XBLDcz@@Cd-BZiLbfQT9#H6A$uEic5(V&a(~|)MvAbQ8C~W{HK<-v5+xo< z#vSG!8SZ|_{jmx*RWUe?Cz6moTW!RkFZljf-?Yb_>3Q@Vej*t&adyB#)F$r41iQT_ zfJ+%3$}n#>DFiowz~TM+r{BVMG)r_}x#QVs)JzsgYfu0_C~9t=1=R+L0XGEO=KUI1 z8Z8!JB%UxkBq~T{PGposLBjTr4-r*L&d787ZYzP=>z7WiCzvXAGEqHYs0cI@l*bR~ zEdfIAg#1RLR-G!H8vRDFx5#9F{;k>KGL@WAV(JIoCPVowy{zS`qVxY^q!fM#f|7Pn zre;mz+4r30$W-Hr^lon;5M0ygh-^aluQmnT;kj+&r(64vf7*K$R%eMXUOMYP5)LF( zOVj`zX{sRT{P}`kO%*lDiW9Z`x$;cqZEMfLNv!f0_v1|pNC<`;mtA{JmhAbOR938U zrxe6q-NsER+o58*b4V`ylJg~NJn1{bP6mc!0k!0Hg+t5ab~V z9DQO>_(4G)ti@U@yDtb&S`a(Q*Fpk8mOLaSW$et6hR#5&HgDnxqgB3(E{q$%=uPIK zIVfpd@3Lr}wPv`Rw|6>UK?mX&1>c*{5b~D)E#Ts{zD3MbbusJp5k28cQXY}teTc;M z3xE&F9bh$VT1`MUHM+2Nuy_4>^Z}aJrpd=&c&)c)-T0|$>Esucw-fDs3(#)u&%P9B zvAipA$@{uwxgp)5uc?R_jF9W+@27Ni^FHfvd9A+^h5zO_fx0N20ctdOx9**%Fqd6lc zAq^~;QmfJGhTCXcY{nYTVCGPY86KJ{`5Hn+-qsOfWoT38ddNSN5FPUM9>e4Pkgr-7 zw4xQAFYt^Qf0Y>U)Wg54H@PrXiha&^sVrd$H3;j5d?pIsr?h=Mq1?ZH_U_%4u}CBv zxGM~^fM~$zcp?x)GZR;--Hf*cr(rD0#n|rl2t1@k5#^Hr?_=r1c-1F?8kI?DJB@|< z7Sd*vA^DJSrOau7cmFtMg}>SfazvX@K0AlCp*|^UPQ@Qhqk>TEqr4cUy0BUNHCoyv zEl0{qe`MKI)D3t28{73I?(s&{&pH^Cywu&N=B-f}e)l6xJ+Jp8N}fK9s3s}ZL za^03l;X(-^Q@3~IPHHjv=fgBV*e4$}>|)^pL?H{>xy_jriZp==;{r?YK>E(BL+O3Z z>Zq!o#3X)gVOb#&YwI2@LXDyrD7!Q%Nv>snlI$-)F?iv`hC)EdtFHVwU9zL}e7+Qz zAlu1ta=!hyr5zW3p13KqCndfww@@lOSe77+7#H2;7GS{PeTg|7i#Zt5n@J(6k6Tie z!a*Ce`vSGV5;^}LPl5YBM`EU^EiyEOA(8SWnzDKD2sAX}=6}RgW#+;Pf5_U;A`(fL z09ntM^YE>4NxKdw(d{Y`=basJm@3lm>b@`|pW8e9Vp2zphw9&qE8pm&y=%1%8pe4Q zOI23F-B8m>cCl8V%@WVowE?S8((R&ig|YL!0XI|>2hm!-La6QFL<@}IH)hYh=Vp}f z6I=vA9f2eYhTX&81&z4^GWgu^PLkxjqPCr6!(i1=z*X*bZ#OJ)uK^KfH(SlH-&juZ zpKr0ZoU-^1IpLfH?2ef`y}rU5nvJ8HzJYqY9fgVqp`&tm(J@vnc|N6TEUw)E?l#^& zO3Q1M5u^LX$ZA- z(VnCPd|g2_#e`01^tFt?MHy}Siy~P3TSEgAQLXY>0#c$5pDNP^RUI7?C=MC$BheW` zT_(_pRmY1^_dG)ByTdT1k~t?t>%$8|MXxT;fiv*mVL|qe7m$MFoxX^NdiSc79>{6A z)Gu+b?2O)240&nt_cAn25Rhyx&hqx%H@nzFdOUtwAIVJhR~_2ukYFCk6;m@fz{zeNleLdrSQMPJ9RI8rPs`B} zz!=3P%}DvN7TmnlZd z)twANXgN67+pcwNAoA<+TyA#4F_fqExGp*Cv;i?|a>fuPHLIG9xgtNxPRckFkkEG4Qd7YG%k~vDsoRDN)`ZAF?xR#}Kk~2dYpzNWHd8)Q1QY4W zERJBlUsCa%)Far{CUb9T!Y!T834bD{2&^j=wH-^C<}G`+SKF&-G#*0J>2O(Odj?6w z>)MS#wPJ;p-y6f(>3!d%z4s-}n$7S<{el9z`PW@sWF?PJ2M>+WcQ-tpbV{5qeT_3! z;rszi@%DE%;SNRnxq^?Gbmpe?2?%d+HUZ+`sCxKhCywOGj-zIbjCjMHUL0l|KIZfc zjE9DWWYp&JnP+p^ah@+*hVL1bCRIFYII(d#O8k87?T#>giYnNFf`Qof5_LeuuG-y4 zJStG7S+Te`U^bNrAdu`Yr+j7i`Ed zRqs7TuG8rtoAmej?rx9!xBLAjn8|n=ktV0cLaE(&NQ1=)zM*6%V=yv!D}7Fh1v$du zsD6jVkQ5qwLmW#^Qcs-9&iO*oj^RrwHN{yyk~{0KcPh=2>E)g2e@uiw&yDBB{OV%gARLM+pKB&i?_6z%;q3iJ`K6*Om>THhG9ssbME2R< zp_&8pbfx&@BOf&lp!*FqF3~VCd&(2O3MkRE(xVUJpgWAj60O z)?gIa)tDTAlS_hCtCb+G79Ebgcy*(bU%$eInqKjDztOy2@QHefBO_%aB4kEpsr?Z7 znSUf47Ix0|AI(BLSvVKaiv6DOuhwoQ^r&d!@HrvLmjhRJzHh+iWM$4UeJIAd zbu2L=vMFBPC22tLr4$h2E=Py@dt>XyDR8hxz54(Jal22U&AoZN(>>YJ^(n||IX|TY ziay)w+H{L6MxCcr=9?@W7wKr8LIRO({1rXjXOudMxP`ABg|Id9U>Gp|*;HKfm5#cz z$VZt-TU31vq5LKg4&x^M88%1xI-Bsb&T7QKI=`+6@~A*$Wjjr&H^7)QhtmuHWNc(C zjRG=N1|afQ>seQduHQjQMYWuhEhm|)bjgPt_lX}bo)FD-ky{SL@waNdDR9Y()zK(2 zRiqjp;005o(+&1SyC=#~4u1Q>NJCIQseUl=3ZbpB0nEETB|Tq!aMt)HHdt1vfP!B0 zORJSURJHpR0H9uO$@sbO*GG}>6?lYh-}m)*7yd4x1`jW9txDw*;5=~MB(D=9OJ)sr z(aqIa^W@@V+WBTIDt-l+tCP6k>HSjUV{Ske$fP$Q$-#Oscch%&Y{;MOfo(pr8Z>-u zx!`T7h3on7YpTr8pkyvYHETIh={PX9`WyvNkYLAz7xaT~k8Nu?o5KsK81`t$lZjkg zq44H$sPgsonT#!NLqfA`gTuoZvfQ2&8OF&0F+OtuOF zaiA??dW55nQT;%9muhVy9NDm6kUnAq_&?`boDi5k%F+a%Mb{rK>H*hfLBfUQ)I8W% z8!bg#_KxF)XhH!z7K+sZzbfE93SZhxBJl7o`H-UD4cfGxa(lYpduCtK{tszkX`}+* zrB*vwD;22u^cm-?iomRL)n~ zp2z?;Suv~-bP7y91Vj`~sYCD88%-z0ETztRd^Xbe@$(-8y&~S9F-GlJ{!ZTZB~RTK ziR)m`7E+GmuW!N>JuGaamguy2la#B)F&d2jPA(?az{5@gF)Glo)y9RLN{~`la--)8 zO>12c6;3`{f##K#Q6OST(Zo&KI)lm6k>N^l&Nt}7dOrE(FD)%Sl?N#Ys`EtzC8||u z&2$PTl@Lo<^!T1dyI?&r>-k0Z1ul)8PCl|!)3S+|6Wi^H(7!uoatCsTGyRn-lOgr_ zEOMw5@g5whqa+53(bp9H@hcvNGU*`>?EO0#4Y4ZX_8W=x$+K;?O{j@vI2ub>cHpi| zg%s_+#F^QQLBq(V8CzA`KJl9t{?!e$;X6R%JA!ceWlOntVB9!qES<(Kz?k#l5W`>3 z*Z53vCksAQ3UwS>TO5H_vw1EvPNlrt3jwR3Y{jbQne*1;t* z0MV>mC!cy4$+*Mq1%AF{Do@k8b|nvN82((68hy*k=?)5@Nve)c>ISwQKfhG7GO2Ud z&3gldNp_>g?QvQ_J5n=)#9dxfLu zg*EBko|kQAHyI*kT`L=8F?x^u5sX?Qw15q;2md!M;E9z{6|jkya-bU7+_&;?_%sh1e|~-)Ex9Qfr{e^x`_a$wGN; z&aJE7W+uR0T-c-a?9bzQIqU1IHHPR|T2e$BVs2R@@w)0jhuXi=lbfmtreqG~R*L~c zp}dqWEp$jf{2v~?!KyFKTX(}iUG7q>?BpDVp+LG1MEe$#=%&qYHiHTVAy3otCn zV~8=rGe6kzj9bW$fLk{ggB$-tk5z8xRlh?1Xy^&hV+(q)8tT9EsK!wj_6VmazESIr zm-9TyTsF1k%%#Otc2)4#nEBCPrRBV}yOnh;zLaq-`dpqYc8{wc72~6+|8IKWsqyyd zR*LKC;sZ+0RJ=%gP?cUERA?_1G8E3Mc=+gD+J*ak^CL>{cLj*RMh3*? zZo&2PKlkq1t^RzBx<`ni{TiPiDc*8q;LqTwAW*?d!S9Uz;j{Q~uBocm4f?t9vx}9J za%WY!^M#X(0}wXF3`pQ*29~GV%zDX+C-Z0E_itWjH@DVgLW!tw%6v*{;$OeYC@BMr z2=kq#+$7y3+}LGay1pBy>z-bHgK}R!?A&j%3kTNfpZQL<%tp>l802eZK4!}*+3mJ& zJ-%XAhz*GijraD+_S$;-q&etI2;zde2~JKjU*Ryb(-U``{vDVWp zjBZAFNV=J-o#S?!x1_O-HK)MR)U zetfvWy}6jK1v?qhCA@d7ep8K;b}TnWgfiVnOs*6X0`P=s@C2hr|<74ig0*% zr2I{{o9*mYo6cu5X2>^gPuGj%L|$oA#TPc+PF@OrIz7q&U$B~?iKW3#_lvOVjV7EA z@7fc6#vto&M69##Dx_EGIYJo@>ku8h^U|}sVp{ouXBLy=n&Z?C*x5;?kUC@;cV)Y+ zfVs}4u=0h7YMaMEM7PIlkR@Y=yY=ajq=l0Ypi?6AhTpiL_SzVeSWnVRN^RS9$?L2# zt=~gTr^S+VzEts8soN>oYqP=jep_>{N|Mo2?Ka2P?ALu)8Vsz}WB+fCF6sQc-6@mH zrZx@lIBuO1u)p-o24m-9_(1_W6|SIDF~yzEl;mb>cHX@C&pg9vy@~nuxaR2Cksfqf z9&oP)u=Flu+DpDk%;OJ6{N_Rm_?M%z7IeRQN|x3Hou|L~?4}eet5cZ;&~tNFvGj8A z@f|W473mZkL<0Tn{kgfM1&X9HB9CrmP8pbv;shu=LCc82<5iIC6J;i9PRFfCCdLm&cFz zH4TQG15QP}=7s9dou$she_nI}CfO`g4tmk_+o*K8n*0!PaI)7n7_4O49mzgfoYj#- zg&Ey-D|Om`-95`m_k=#(v5E#$7GTNdGA=~EW=6t3S7|mP`EvZ{mcbdZ<)%H3%0SHU zc+J_Ra^`q*JfS?wPsKUL3lS_UocT7dHb4;vJdg4#eT%=Vkt4ZH1Cc!#ex)^@Fd$Yh zXSw9VlG<$Z>(MM`Z5=wLWn7yd>wO>uf z$Xov~t@qx9gOa2})#59*zFsfauED>KFU1Jc*93t9@CXcUE3e==u`|NJs^)QNU`MEI z=FY3t7D37xf_$ys1l*oQ7-OB*bI}Br*h9%AQ1AKK6_bwrcKQ#w-Ty6>`hks!%RiYd zC(SX(S2nWS+hKUq(J2AawftTiy@${R29Zloa155RblHMjarm`pRy>O-J*;2OKBwQA zitaTmqfNC50KlQSLhtoSh7T{~@b1g<)E1uEL3vx>?>>#wOlR{2t#_250&)kiFD9fj zRXpK?>VGKwZ9P3;N=*`s6Ep_INE*8PMkWOLxf`zLQ8)mRPh}Hix303@w_$+{4%g^Q zUT^dF>@4*j%Jg2jXKuHf_MyQ+?WTYyC9LmH?bv_%krIA9f$;JSF#$29_f1*_sTfFnGyG_jo)yS~1K|`$cM0`(g^mx~z;-aReV0(w7DSufbl*;TG4O7HX z%Gsg@QC_ZxQyv_H(~o}YVG({H;I-^SY>&Js?-37~VBEEP_1pq3_k1t5;S6my!JqC2 z3&SbE`SO_@uFixn?{};66Pdm6Tayo~*M{YAPu#zj*s<~X9Gzhq9xjOIb_)HbJ5zh= z$`_jST+{h23+=H)-t8z7VpZ3nO1>%&3aOYwzmY^b7!0~uni%;bb4yOZ_-FfzocB*> zjvA^FO0s_xrTo~H`V0H*|8KK-9HZ0UPFn;Qv)@7iX8mv+E%xnw>;Hp3B^qx(0QIXu5+r*BL$S(}dm50TMYv9H@A6EWA$M zm!$jllg7x?aF=!hY0dqZ+g&Xh@<-E^EiBb z!_JvepkzOh+9Ql39MG;)8{7A`x)QS0}C6lY3!1N@6Y{D{CyTs zTD6KXwz_`dka4(!pT~!FTyDGmbQ1f}AteES$d=MVP~|6YMIT%uJ2#3_(artjdv9aKoD5&=#s0q?<>s`d2Rp}&DBUU|Cxu@ zcN*#ZLB^z~*lE_JGG zENaXZTn&{+lw}OL(QDgF8o^oJq*&?m_1NMDF3!f z#XPbJxWJ<99?0iUk@q6>XOc##P)gLJ=Y$Wyp^kzfl-9mKwFz??rY2*p0&uNDv zkA}KbhO_tRRxH)n4xK#wmwL+R&i@i$y}>Ry;)T z`bympRhhfTZ1M22axHtAwx(Yx^kTcqgxcF@)C`nJBaB=YG5%=d zR_CbFrmLrYLlLr@!qQN~$s}>FhPh-2>M7Da;Ld!&dm9O7?#p^-TPZ!(*nXEQ)e`OhT+<=CCs3LY& z8zppvruG9GD&;xwv-PCyvVfag9fSFg;+0oCs{3t7;lte!C#3=n11cTD9V=EV6}&c^ z4>^K zX*a)Y)=B#Fw8?YV|5KD3JALin|NC>Sgn~M5=h5|Q8vEb#?aNoMlwGa2JPD@O1$bFi z;DY}(pkM3fhL?k|c8QV;CDIG;F2-|_tOW+0MhA&SLhVX}9UKAb_W;MUdr?@Q2P1@N;C?X-rW63_M`UShcT6S7AXA{aG%+<7Y$zrAw*1DY`-*L*)KNfVFX zL&ay8S*v!M?TkcL%T$sUo7IcfO`0C&fTxJ{Llz0gm;W?@+{j?E*(_l%9m|I?JM2G? zs!OA@-!}k|v_Rus_%Sjzb_vTcn}~~fm78}}(`n|@_xLS%kW?JT9ad1W*r!u1k8ex{ zsBe5&Rtw@-ip@i9`pu0mL7o2)EbiJfF5b`P5j|h5pn^oeOAt9k&!LSqR}oK4Nq_m( z9EkobL6%C875SV6(@_#AiGb=o5S0?DAbvtksWF{5ikV76k)LW2wLUgi7M|z#e*QolNroQtvx|dW^RaQB`%0^uw z|3Th7!WS8f#31h`O$j8v{vts-EFL72_6>G_x#3SFr)?3^!)^ zM1X=q0@kMq)qY7Gr!mRcH9~YL%H`&xMvs`bi6{0iz{kr&-Ol(AL=o$|UasFemU9Fo zHMO3*ntb2~8RC;$(Lp0#!apy>{kH}Hx8EEbZ>oRm4)!IbR+mN?K5vfp;N~oEKa9)d zmJsYDJt*O5GwWeIKKT`Qoce#qOnz6)j|Z7J8u#jkYKEMy7~pFy2z`;-J!D44w}OT+A`q50y*7@yTzM zem$ZMMtum8Yp2c6Un_Hw06}Js?n53D(FFI3Y1E5lG8z!yFp71`?blk2Y5`mhB7DBz z!tEY6v5yxo4TuxM`$wbUtlA$LNF|SFHSvaT1S==;GLgw59m_mi9XjG`z>3_~X)?F@^w?l-mXg*t|-MF^EruG>-^L-#$X3tVAvYpy_ zZ#HwsxLduHaDLW4WwKrU?rOJcZwE{OWwv?5KkP$W`PCP=)cnA2Hi5Oyff`DTR;VcZ z{8lQRn^w&eCn+-&GENauk^$**V#Oqa@VGm1kK8y!@lm7o2NXw8e$o6WypoPa-K`!Q z@a4LN71kR-=F$)x9#RfT0DL{-V+PM#yM4lbc=O3n!QVgjtCwUB(2|J^Je`MQ>HTq0K#h zNq+de9j!8Eu-$QMc6t=bi1JUsb%+(SeLP<$f}@fuL+L4Zo5FE|uZJB+kXh}SgePr_ z!5mG{;Bh&J`T+d>9}=Y9fuHy1R<*W!;9RbMzXKYuDyU7VzMQW8QXuy4Uk51Cs1o7Gn0y9;VWq+H45aDFHXK%Yi* zcyKf>(~s@OCt*dA7Qzso8FbMG;#11W!F+V3%}LGL_uZotxA$!$ZSf ztD6*IG(1LjNCO50s~O;bZ(DTR@i{3|Ei}Co5{1b%aWFe|`a)SA)en?V7q-U*dhAu#eConUy$ zYPDEcUzU_PHcBfjw##)*MDtU5xwej%_;GhUT?lqHA=EZ(uS7`s{{h!PD8FIB#6brz z3sB*3l~`D}K0cmo;w%AXAS_{vAWlZit*47FmPAk`S7Z>r7&oE5#bWYcQADGp=!0s@ zJgHi}2544p7F8mgt0)Nx%PHac^UA*6yDcu2o+2TkC@&s5Bzg1Xl4OFqo;`g^3KuOV zfq?dLxkO1$xM<0hEr%;11{-Dx%i=h& z=U`awT)7@_8mg*_P6{2;jO*_>0{=21o!wN00x4nHv!!@@yGvqRf@@f=>_j>8lCLK% zmV1w)q-*Cc5&;`E8FYzoV$A%sU#`2V$}3d8JQl@9O{XB~){`OuA-tEK9?%?Yua-Q; z1KNXiB7wvOPegv90zj2>xI?4pDUg(yA}5h)T)B8&>Njd6x!{QD^LA|BB;F9u0Rev2 zl+P7z~6hu{|aIs=?8r$^ipg}gU+eGYiQs0Xn45rSg*7#SDC z0=h4mynSWfqPcSO)_vD30a@kysgrLWJbGy6@};YuGdrX1oX)$aj#_$U>6P2zbQ9CO zDKmNJcBWp-4UCpKr%gKpZ|+)dF6Xj8lQ+-NKAhpT&XjBVZzj@pVC@}f+H|UEy-Z&3 z_7~8+sk6gbjrhlWG<%)4SJYs`x^*qO_v*gX4Nef2u@(+~<0jg;A;B0aMa#R`VeCC} z+(KzoexRrhbDDQS%a*&I5=ktE!pJ-Bp{@JqQ3P@Z)I<0+o^X;B_fnL`m&Fnj8?TrQ zT%{Q0kzqyX!eoqON6#ej5ZEfWh*K^WHY00SESD;9n*4)8VATdlNVe>9=f)MulsQx? zR;$5pa)6SRl$@MuYw^A!#32vIp5&!|FR);79>fcTumHn@-DTF!OA>(G<31-`)tXIZ z9g2*esHPy|NfU&!2)w9|XET^GX@VttapirLHfhwPv25GCnXyTd1+y2+Nl?c`-u)tU zjmmCfIf3%!FYMB_OP6kCN|)%dY15WWftiDn&`P!xAMM}8d=KZlGmQOvn(zEaF!t|i z@7vzSxliXh^BmJ&>+NOsyy?ri-rm;qZ-=qJrlb?V(C<+s+x%sFFadMpJK=zt|Qw}oW>ox`BRp594s6t^fng8_ndLbZ$JHg3^4i+a_f}(-EQ*-E%6DRNu z#_!FZB}8t+pg0b3&-TY}(a_8(sLzy_3&>b*-@fMh`k=w`%7FecpnD@e_+Z#jv+3yv z&$#~oM&O^iKy+myS8%&?=dO2VKh>`FmOBxV7Ms%(4v#C_ybnaM8)EGM1ZEKt(H0t| ztXAF4qoElTmybpH(8tTyQXx?^>a$PYmr-LUiXZfZwUFpHkp<-a7`5WKv3CA=2xy&v zs&3-OB-drv{HbPX`dHYWUqo)ATE2>+#lXqhf|^|$0d@9pTa3vp-Br_ziz$NpSQb@cp%AF#d;--l46sj zL9@EZYR=1bJT|7XuswJ;MH7GeX$kaBHtE#8yJQUtm3IffX_@kJe2ORIlOtDd7IiV{ z(Y=TDn}6Q9kuxP;7A;yhc-({uZ(KTm0q(UIhir!B;{V_B_$L`mnPZH*>*Pt3pZoZ; zPo`u-?Yn5{l9I4%ha@4Vz~LG!S&#>|-B~lgmy)Q6v~2sVtX;do(zuPpQG)LF9=PKf z{Mumobo4hkR`8ZV?|h7PUuSvyjaQkh=Vj%p)z&0qF@lC5?@$Rg?R0W0iss28R67t= zGilT6DLIB|?A_aUEPq&vno%rC?C2hFxfEYJa`1ozhh&k8)vL>f6)QNE+$B%0T+;8= zS0pH#uXrNlb4`tv=i1khH%BjLfxB_)J(99DYs;#Y%XxPMfRyR8^`JyihQ+5RUnes?`FzOUVAZR z&S?Xq_0DMnYucK-mYd7D?9b%QbF>djeJLxZO_0v743dS5mVz?*ShA0H z?D#*-ozJf94x1Nr23f_-nQ(sKZYd$ICxi+Hb+`4&#Hj>YqFgJ87;E>9j!l3DNs*?_ z8=;wdMNXeSE2^oR0(z8!>WZ?Eb)h&=eaDg)nk5+;=bo%xhTMYkSh#2XAgn!D$ca($ zQZOVyGJE;UTjSP4L*R|YFIaMhddsdIJJ{VbiJQ7F;IiZN|f%PSMHWz6NUncl&O@xJM=wHo@5z0dbq4!yGG`Q zWt9|EXELKmsXwt&)$%fa>I7-`R7+eN<^QI9nG&DuJ#aLbAEAnmDmVEb6X+lL-TxE% z{)eMj$T&PABcr@?hv$iW_Sp`Oh7B6KOqw+Lv1bt%`1*&?kj(|RCJL>@cyRoOvSZgS zdHJ*NWbXKpvV87%DU!FM#IyTey>UmjY~Lj>_UMdJ)N&;mq(_%$<&`&vS`u+pSx<(D z)<26yhOQN>f>Qx}AC8wUl-~HbI*(fX0i@U}O!P)aOHnQLMxusQZlFJE`{BaEP#bgI z`W5TXnk}n*Gj)dCy?I{zVL`i~x>7cqzc8I;$$|5d3at}fssbM2k6Vk)3wwAabFi%E zT`-(tLDjEQM^12JdBMH9hA=TYDpuxi-V2@cqr8o2Zg{~Os?jUHFb^yminhv>@ZcnC z{q)mv?C^0paCnbQL`whKfc^qiZfy#wiAuJMdU=#qO*e9z1U^5u1W z`0?;IJ$iKK_ya?=4wUpylmCPX{rCP2|Ih`($8aMUP0wjFCQo{%Q(GJ$>~~qWZmqO# z`?PG_un81~jh=1)-aQPRpb0|IgSvg=s;tH$a3wqTSEELw_HkdfESxB@-ua|;hi7Ez zPpjnPFUClTB1K?*-j;!Hy(^iKL#X_sT9rzYJ9jQwwD>2+iAlqv;>fjj;v7uyk|m2< zbjH!+r=@&ZY($P6vy7$^K*c;@t$HH$PGoWUsf{^zixB|*Q>17S>4kw*?py%~DBaQH zikCdWZnFD2=*_*mmhiG#tva$}>vl{2;sy<)Czvbfkt=J|MNg4rFFDHMD33sK2khef z1@p_>uk@Ai(|?dcC5lLoZqGxnY?7Wmdo$64<;NdpA!S$nF@29@S-4;k&L-|KHfv3#hrQm)*N}x_BY?8UFc*MWes|`pUum`|^Wq zxr6d$sL}t)mGlo;Aj(Bi0Hpk|QmSDixp(@6EdFu4wCnJKEML1x&YZsh ziQsAx&&vI&TdT5Mxp_zS?LQ*bDwnr}hewZ{0*4oA-lTzbQmJam{{07~K%sDmU=~bS zG;&c5@%Qt!=oYm;#!3hJJzVR^<9u^`yPTzz*8^Ouu zE>)`3WN~bxEh;RGsKe44hL(YSZ808FeXPyk-tGIcV(~)p!&c>&E$`_Q&u$SW^k;~AVeNVad@AQ!LPX49yK210AMB1KAsuUxs@;p>~JT7w1+_pxy(Mw)T` zFC*}GT_8#zvFm!=x^>&9K%x8*YgeyzL`OxttXj1g8HJCmTD#HOu^qVoRD65Rg1IOJ zqH>{ZPL30A)Gzje`V=TwkOh+@5AHhT+gWp@La8FsyHh85x>!ybGyEgTp1qI+hZjOw z@f4_D>nTb>Da~H27y$%BH5~*Jw?Z;O+rZ|MWH2MPe|k!U_CnT@zYrX) zd~$IAE=#SSahI7t%(2i!o&B7h&@@q&vgN~v4_%ba{NT~89d&9}I=Fr3fl8`Iue8bk zGDrTatN-4*SgxZ-kM2EV*7R=+6v(Hj4g z7W4uiU0JVQux=GCx_tFIs8yuYM-lMQ?p^ZB$KCg@rAiVM91IG!7y{bQ zn$Ve`6_hos7uu0X;!~wu=~B|U&x;bo;`M?9r6$1D@?@2t)*qC6_aC9)7$arMRhB~s z_gfmj9IL(FlS>^yw0@>NYAX-r-M3$ruSS0%nL(4f zb?FXW^t`NIwNl!(eFnc=aj=miq)@|xoB}JQ)3cpqHtHuT%?I&gGhuOH&!RNP3CxHa zHE1l?E}zG7L^ZjL8Su~Bw=s@h7-4ZLb0Xe*7-KCS2b<7ke0VKdu*5YcDyDqlLiruv zPyeA{l`54lKV}D8L!dN@m3YkcGI=f2OY`VS z-JkD;Q0unze(_~Xa-GD&@nF|ZW>P)VzP&74w@%99RC*8ix$e3F{z0-8E>|V!igTbN z?hw&Ke%L0%2bYz=9NDFL-Zt{n^odfp$y0Ln>;(jiS9Olctvh$5X+zY}!OcSmqqb`0 zIw@Vc1agC-mWs$DCVMz^N?_*9IGYaRR5`&Q@g8X0rXXL@fH^&0ei?Mek4csyiJU~G zisYC1+YV~DD2YP8QmamV*|Tdm+@qkhg~37LiyDa9j=015(%;skPHoF(R) z!m~-SJUI~t#-dXdC*7f^9-=)wbSNCVZQG=In|AWr&>^yB863MnKdDrvIE;X6@_L_V z<;}ibrDyL~InAzfafP|qly;ln!>EQ~JL z@?}!GXbA+E%1y&Do{P6@p8R>_{)0Pb8Z@ZCYU|c*Etxo$QI>sjn8{KH7jMh%#>d-ow5@v*o-SMiH= zeo0_D(&6S82@Ldg>B3EP=r zWfGPEty;SA81D#+mXHYnE*{7n4k2-e!^PO6HbY;$FRRlN;#_xc755+DT@n)Gq+#op zQVg38l~-Iie_YCyDUTc^5q+w&oC=}x-dnH8bI(5~&v)-CQ@@=c&vxr1-%t5Ya)RPj zey%-Mizj(jR{7-Pw?O%}%DnlrB@3sCMP>6$OR&hI^5eJZqEU9Yx>C)9mzTY4Hv9G* zmi22kSPMr_HE)P^ca$Yv@!sOWi+AtQz4^24n>jxF{F~5RdGkF2g@f0Z!4B3%rPtpX z#S)j6Pd{6FQ=tFMuw1#jZl2!HWz&k9vhnAga{k6caf9$~+_Z@-nmbEM6f8>E06*D( z;GoRnBv2PT${N)Vp3I_Q_F1S(3IuPgYm7X+5FyQ)HB+`Q;=hlCM;)T7^@-iEU!ro{kV@wl>TFSizb7v!b2sjsM|j$(tjagf?x4kkL<;%$v=IgI$aYEIC24=g1+USp(%P z>MQI=uJ!9Tm4O5L-t`F%oigW#*)O6^plFC*Y`SSXur*ustB|*s+0%9yd)mM__owAr zW?=R1TxQQ}+MYM?roE}xe0u$A`QMCUX`{c_WnQp;gBIOeHhs6-n=iMQeVf+c(SyZ- zhp23z8hYNUj8UL^(%VHem<%B^~;SyO5EOiRg;Gdpw%a*$M1IsCk3%cVQw%4CX0Fj%Wr9a+DA zBLs9HCk4L%)-fLdcR`t07@AMhyjACO>VP3toiZSQQDsTaN9lu&`pbR#NP&F$qi8JntXCCzm4$bnyvBSqQWy_W|8QSE(o*n%6 zra^Q|uy%yVge>yxOQYncIb+2=c%7_TwO^_=ZzDNyn-iWluVl}bQ!bv`FEJQE6)jcP zGDr1Cze!uG0aQO6KaUynEyO%A1o=;C1hw7Rw--f12<<90s>w0TYZoq949XxfW7;%1 zPYl8H$M*BVPfCLp&tM&R&cf4k^E~1b$~EW|RYp{e*$`-uN1P1Zdv%tq?6xco3HC{m zaMH8a9AKieC{aTXWfJZ|(jN?0Nf$;cf;&~0SNh2nTutK;dcby7X}Q{@s7oM3*1)hx zI9a^lZn={G;YSE<(4Y_A|3E5MsU??{(XeL^b{-gG`2?Yok|a0o-jv=wd&t!9zn2E} z>&w?;zLw@K+sUxuBP~_<@Zu$`lWOrA<(|HU+j zwVP?QSJ$W8w4HnOK=?CHKlhH?`>%JA?$3J5FZ)-^q;bj8vULZUfO_{@6!`-1Jo3)l zZ^#`8_z|CvU>A%QS8q4VsR4U1ELeUXlaF7faz%0RakC`QTQ+T#X04jZHn=}7F22$R z^y;fm-jRbrl*2+YCyXn^vjbYk37IbygGc)cp<53ufkUD z0eZu4x3qTSFzwaQ3cS2Eftk+o5Dwc5FTE^7-+mM45V<5*-dqSwS4)d#t;uJXPYF5g z!%3(@lV6UWR5839Mbkj-K}LT1rMx+K5Ohlbi!udENTq>XEu$|*%~C0Iupm|MOu1&B z%20@WUU8;S~l{h@#^@~%B?c~yE({eVl28PARsdu(S>9yCtEdW#1>5( zzE`PIvB4WR?nS7N3h95TkFLKn4U)FQ=qeu2|K(mC+joApYWeCi>Bmj5SPNJda|hS2 zmyR9hVJw7R6L@-nXNu%SJ5|kA^CAeVQl^-!+q_>Q?nmgxs9OU6z#W3qq;5VRpl+TC z(^s|LTZCtml0<&Ged{_NM_lF2_db#`#qtx=<8>S`6oy5-RpOX5#R`_TJiEs-8QQmR zD^Is+C0VkDh#&93G?t2}s?Xng9NNJ{B6z2Aj`R{#etKyv=tq4Qty5ZI38lmF0ax$`^faZAumy8@HQa!gIywp?UouMB{-xpt$Z@&FjW^kHC;khNy z-%swuKHwOF5JCMVN6wt`Vy`~1jW1%&dDE>?%?3WDE0jrnu~+XG-g$e-_qxgGF3f{} zy`1w}VK39P$?Lo@X#xP8I?)1xm4^<>mCDeRAr; zRb&gjW!{`gB30_kxs&^3%c^-&|LN`$h^LUYIJM3O``5t)3knXDLSe!3-Qu5Ntpx=gsE2nYA@Y{I^Z9s7V^`mo`D3Yt zs4!2N4G3Bu>xH3qq9ir-8n#W*oztLyDj{FCbh-R6Yo5H+f1rFj<_kD&NcCY+CnK;- zbF9tk)4mu3EYLxzl*8mEIr4@xuU%vbs_`07v{Gf{GN{hzNfL+qQ`I74Wx(!6{Sx%+ z{deD!Fixx==FUY)^0Mk~vcBNn<-~j#MM{1D{LpD}Eb0Ix@w2g;--mojy}rzyJ8#m~ zt=m6cx@1vSVl!H3xpx2GaQ#DQ5LT--cGIU#_L@6)(UjSP z^Oghz?Ucd?uFJByi{<&%FEDu=Qm0W1sad%a@&$hx_Tgyx2zBqMh!_jMf2mIwnYUm$ zr^YOHVI~n9g1XF6^^UuERlK%&v(%|w3(LEMXw>>itBx5%81$1B=eb|QP43-fre1q@kFHlzAVOAw17Kz z>JAsnT_W+~9-1|~yg>+QlxlbnG>F;l)rp;26egx(q{Sq*XaxRIy{<$SxMDhL8qCHI z>WHccr;P_}m%z< zZQrdaCYx5~oYqNU>P*_2D7Js>eWeGJUcGrvdhl9j$~FBr(;#}}*gMd)=~UBtnY`ZZ zFQ|D_XNR+=J9KEi3p(S|io+OpC>->fpM&t17%sgrm6s%#}Ob za+aX)@Xh!iae5FWW54}IQa!NU@Z2VwHvA<0x;K-F%MP&kBAJDWk}XdOB>caC!f8Js zMC`bF3M4CCfxIIRa*Sx`jRN_@AlCiqV}q2hUWwgYq+;nZ&{FH9c%h<_IT(Gdh)0r& zJ5;3;P&K4KWybQ2I0bY@>B*oCRXJ02$g;q2*tc_s`1%LJ#%?0ZmMpedw@f8Cda1CO zp*N7mE4M5f^We@%-Y;J{D+BuVl__W>5KrDB)IqLv_Q|#DH{|(VFHkoLdc~jTE7OAq zE4zz66^(RdVJ5+~%AGT>RH;^3%Ah8{ZQW)#Yd_1vCD3%7anZII8dkD&X{7XL zT>N=Q{1`89*{te?<*RoWR#g=)K8Lkd=s)dpo)adobH}6=Qq%VNlwO$~M$`7Zf!DiU zre4$O^{eH7Gm2$alyj%f574~+=}RcAUIxaLJHu$60Zc+o;>Oa&^GlpPdp_vH58t~R z0FHh5W9-T+JldFxohE=Fnr;%(yGj<`egmtUuu%m}d z+jh@TABThLsJ)bRsykZ8B3&s?w^T{|!UQ`LEvv_-3He|n5)i0fF; zEak>2dZ{jmd;_w`ew@SiDuL)>?XBuE)?3I~P5*SoG>toA1Hmz)2Sy#yM!0$x|kC zLNt+>gcv-#lt+E$2;f?x=yGd8BcNp)z;INLZa~WdG4CvSIIe*pHQ^9J)># zm*dpwV-U%`$bm3Fdr_VBzpr3%FJp;@G z=~Jy_^|A$^V}8P~kqQbW7x zCac7{s<^}wT-1+=9~l`ztdhIZv{_3zh~?s=2N=#W;Z@S_0=+?;6!A_`zgZ>aLF7Hz zk2e*y-&d1dJ>}E_Q)im$XzAp?bosLMfB7XVCdrqu$a97lk?K{e$;y?B^bE63Glh1z zFrPVjz4)zhsJp27{(=4bIB}5caC-Q%h~qfjbRO^6@w1E`^@Y@A)7r9iD;rJ(oW^7h z86@(qvbRv7qI=GtKU*DU1{&P|d5VvJcP^HFahT&w%XIaUcW>LK&HJNAe>u|6-_Pyh zLDZE=q_VsER_?ezkm7pXmIKXY1_V)WDCwJ+qQ0$ zL$E+S-8_+qAH@;$a%&e=X|^xkLM(L(cH0CzFCM@XVvc-y1V0~=%k7~!LjB|s&ZS+v zf-rG?h>QZuK_-b8yQwZloy6);p=PN9uu)ksDUYOk(~2_qv&ph#;Zk|NcYk82x03nu z(3pj@q@GcRyfaw#?%aemUu}8!y>~3njr$L;lol;oK|IIFZY29^@ux&^P?jLLbx~G1 z50vYu!1R9UCHdjIsTNl)kup_*QFYyR-;-;02#V-i-(j6yv>IegsloVwmaI&!o zV>nIbW1$%aS5Jw3*tt@_Zhfgyy*f0>7ZL~4V*JF(GHcckR?J1^)~N<{!93wuY-Vzu zIDS->L2vbUv~SZXU*#%Qu4xPxvum60Zt`XqH*-YGop*5OGJ9Ur_Ppue-k;WMKD~am z+{{S>mtKGNw*M$1-Fitq&h(}9(ue9*s%+WO_3Bn1wRi7fCifcGh7B5}=E<8+j-9_D zTS0@C%o-tnGbTv?9v$S+jcD=l^o7Nm1igTUZb%ri3^!1lQm`=L1f9KR?Wn2PM(E_y zOC{Jk!%|r=%ze3g?LKVTN9bg=mQ7nWiHBbZp%U)lKmqO)ujh%7PYGbP+sGE0S<2+g zA&Ie%ETLZtzN|j~?q{i9sk|&)wphY)=av(wzdKOf&yTk9n*(1#b!4+NY|vc%P(gVE zdCuhV6T#Q7z(t!c?+<%dUVZf?=>_Z58>bWM$(?cFWZ->~jKBO+A6bg-S7?r`mXirJ zBUTO;A4T_h-k;qZPSwP*W2G3mS4x4a1TU#HxEG_4V}& z@m9_v;cwLJDfHlcW!m?Xt>v3gheKnPOw zY$0coXV02GsdnAkHxC~=5(Yb!@U;F?p+Rq%_}O4-oVr1BoQ;t62XDfu63eZRuWx|7 z(ti*#kyN?!=q`e@_brbhNhloZ380ta4;EIp-USgk_~b&dhQjKU>>C>n`1i#(6|O3Gw%kOoTGX=I@C>^O}79#VF~9 z{K5C#cTk&Y1$v18UWo6BW5+hhGUC2n zvhUlSpmu)p!|eHR_q-MrAN4*>eyXNp0w*qWQy-y_}QGsGh`t+9jic z?{J`f%ydoBi`oMX_{j7%;a=m1}l7apK_2 z3Kc3$Dq6Vs6-Qj;umi`=xv9&YTD2R?sL4x-IT$FN+tiaRdG^TCmFJ}>3U>8dwFi}W zBtL^@tyrRdsS>1Pr)Oo_v{{xNhRO|^Hf=&&!U(i|`^)eVA6ch}Zzg|hmrSrGgg{4t zbhA_IgisZc9P}NCP_TIMLUQ)VA?uX58JU2=QZW`FP8$fJ5EO`;q11SJsas3w-@msE z9`e3C+qtWB$0t_#Ql*7JoS;137%0U{kB*%{!Qeu{DxNTL5|f-+%BgVw-UE4g(AzS3 z%xJWn!z`UGWyPw@L<5KFsZp|Y6}fosq!lLN1~xSJ?%uXoxeh`XdcdulyN<8oT`RGrj035*}o=GeUHX3*IwxYx<~IfAk5b*#3v_zyJQYMT-^D<^j*>ELj=}0R8(9)#~r7AL|4QtlO9PIc@6ssVoPaZ->L>xvIfaOYp z->*~`%Y>!L$-uwLMN?r+031VAr*VN}fF=%VGEoFCZ7Zu_X~*H!@%z~`kjjsNE<(cr zyAxHR_d}I_@$#k8v3)yO%{}@))3HI{uSU=C3Ck9yZdHCgP0R!|cb(AYaxVKbdHW=H zhBpgA%QgL%N3nQGUES7T@v0%-OSLLoqK86Xmw-+;f11fD8guOYKCE%~|T; zs_m-Y;B^;PVqA%HT^w|VK+jDn zk{l+bD^$Y&?l01~LKqGvVr9#LO*ovMC(k_FTE>qZXR%(_Zp8UQkLQ^539|L{F8W?U z9QAJU<(HqyC&NFM%`C)bNaTN*FhH*MXxD(tfZ*@k8~>Xc_c! zOR1duwq(WW!_?K-n1|<(mMt1X@H)6RLw@o=4j=qQ_8&Toju##jQ7}yAqq#Au)U*3& z*q*-}Ju1_`{|-DKAs`b`CyFjuMZz=Vuj;+`--Xi@B7OVylVKmcFV$f;kNWy^*?s7| z)T&ui9^ASoF%NH{lHw&(e>#9%qJq5iLO1Ewt%H0z{7adHYQ7JBj~MY8oF#|!=-FKw zqmBCzE5^kT`NQ7(kkeoX=E1=-W5Pu7WU+=K!OxL9yVR{)8QSWhY}~#R4qOUq>(Lfk zqahl0Y~Cydix-14Ra7?P7|+WGH>E5TKQsou{`xD_*dMZZR3%1aBP{340p2nUOT~5_ zJ4(0Co#n%!gB71)0kANv-;8O2E(Ep@)il;r8eYOsFfMAerkV=uGrC$hrQOlxdJ{F2 zcu?5pa`@2Ca_-6v@rTio3AVR##MBnQLBmG!RErjJ2Ndi$sH$2#x;Q*##q#CDzxsOA zdk^nF$OKCr^Z&F^*Z&TS<)2Q2=%DCMqKiiF`q#Kc^UQ0PC*1e<$uzG->5_|oIdO2q zk^Q^sr-A_DY*ey_=XK0jyxZme-HS5vy*_+1hpgUoRPyHxLK`?A9G7zl>5j{Iq{r%& zWa_x@r1$gBTfTf%R?wnFbB>W@nKXeN9{c!2%2XwUu9fX)=~=OzA`kIJUBeAxJ_{(z zeykv;V$pa)+O}>hJ7F1D3ip-l5bCGhf~3WOfie;QUYUGdq&qG^7tUXR(q&$RZMCFT z>o%Y(UZI)vP4oL3}>+p_J z8TAg`we{6-xuBy2Z7^ryT#GnAgKhqY1Opw0V?A$BCDkHMWWuYX{Le>?m6&^%EfxR6 zC(g-_bC*a#WI1z}EYjnWZjci_K6yYoS&a0}gOW(_5r84iBPuzs4|+|ybnAkiT4ol9 z9>FXWs?{h*WfQ?Ge@ADTCC ze|Z|jyu7|JyO|<68mu$1RlAOU44LXJxaTiWbZqf5CF@_ka??>Df3Y*5Q71QT+}J8} z{tB+oy)s57jQhxPY(4IS*W>^y>Z$B(513eiNTWXi<+yeIs&sy)gKYU30Um_$Pit0# zZmeQbX0o_7x|8x)(1|qqL_HZgpdYk^e9zmf<3e8y1&0-+osH41CRU3Nh^Mx8$=gzn1H;eO3GS zB!*ryX3aonD^^|^^bx1d2cTqr7Ht%W)3-}-y)>$p68Opdrbno(BqOmudiaRU0v((9 z-Awsn_=nPjU3w+7MF8lZ3ORcZ7$o108!I8OU(dm%s*3u^NkUdXh{i1v3xgHFBGTW+ zNrAo=DnBeN)(5l(9=q5e+&L|)ScYexee$8SLWZN9ymJ>$A>>pB0_%iDreovAeALKW zO4lhdKYsF5dAV0lP~04%bmTkl4+E8jR#My+!rlWK1~HRFJa~xnh)ifc{aDg+QiHay_?Ho~X+D)>A>RXi&L)1T0;-Vil@3nWRqL z8nP35XVljtEso)<173mS7HY|&6rQPQEjY*(#@t(0ELtGZ5PPFWeT8Q6a`|!Q3{WeW zBe+X-ar2U#EF7fmQZQeBxpAAIsHqM&=%Q={GIdOxJh@S;r=Hr(xc_d_>T~`o*S~y$ zq&E<%@|`JDkmLvpbR;@_;{yT$Pqk}NUw&G>6Cs(8BtA-z<*N?CSvrB5%9jW_Cd-yR zH|18mD@5Y6OfnCtTf2dU2XET8jSrv3qV$Em%OP#ej@xJ#Pn|Lo%f9O}?wc3)Ui8T9#eglw@zbR+telG`aB6k3VTfB0K6b{cT zZ@khE3&N4oy<1nAxp)z(`o8Fj#albL{tjhoXlM!5$x_cOYVqjKZ&e3$?|t+EG2VAc z+ou}H>^Tc%+peDpBHB^zVe2w}>UT2ejlpOR%;tG2QPSuyb^Rq5h#r9*yFTY~_T1S@g$fqhrz7Tzk1Br;HAwPC8XUu}mK(#S zI?}XdANhR5KxvS$jfvzUulDIAACCM6kL}5_1pfTO)p%)SVT>LBt&C+Cz5;Qn9GvcG z#qQ!{Shi%Lwc{yQi%n5YBorgzV!wsMqoEj7J~MvucT%tUQ&PQFZQO^JmC6-+%A7er zz%urb>###ZaU}gI#Q9qve+m(vTc%8zgehxJsa>@)J3EnW5fVnAnf(5{Zxhe`fwXAZ z7S?c9)I8>4c3TV$-RqbGJY~svg0OP@Y3Us4+3RI_7>l1ToJp)=hi}}tsdeIw`Q}@R zzI6^1a)&%(@hn)fRw`GifYf}RCG=Ddo;#;xB9l>7OjL7NRd7P^%A!szT-5-Kg%e5N zNt`T`aUE2sNKt8mN%YR`TVx(;C939rhk!I&C8{(%Fp~>W zt1c7Yu%xB@c=Ot2)M27o0L^6+ao2}^^pT7kGhSwVKMM=UF7m;L!=+uP))Jf}1R{A8 zj_pdym{Fh0>NV@7esk!Bs8bSk3Xd$HYROFE1jYox$YbIqaxFVB!V1;k!g`eSv53duqWRXmsK9fxX);o{(cJskI zW_DSJb*cJmZqm4k`dL0yqk84-yZ0QZ%W1-4La;}^`oCgP*q`~ATOj&!W|1(t&5`RG zk~QCsr1-e%9xi8H&mKMcYLyD*V~(Ag=j)9cuLqO*$N2=E@pqGfy<5nOM7dnJ{=D4A z;?;rb#?u%i22Z;stmxv zCYCuNRGXlPDp->Ihze(O~Xsk&LV;wN!n_f)Iu(ye0~>?shku{*ni z*GGY-xunK{x_N-}W2K03)iqqN?)-VXOvI*R-rNP~TzP}4Ou&gmciFsgvpn0SGgg9C zI3XKDfRDt1c3G)ap@KB7Q&on&I~14LKo+4cTy;wE^EnkCbGi6^ z(8_X!-=k=iqDHFEmdxg%TrgiMSD}`&VbvPg+k@n*v7^}OqofPQVY^^*XrLfxV8iAowrkvr@{)G{;apf$DO8Ev} zeY_kztDfWer0m>$UkJ-U92NXxSqnyKKpHqW7y&Vjl4Q^;@1insOqML2%kJuDO*R## z=>$+Vf=&qKTB!tn^p~Hr09>SU_39Q1rvXJbtX(0C=6olSxF@}L_dc|XFYbpPuydc0 z;-!e)@yQ5z0XC`%*7Qn3zvO6d$b>ig04Kb{@f6?`Cu|V{D>RDT$K#>uJ1`hd13Az#` z%8iSBaP##G_|*!|n>F?1>DZLSm{^a-b(+WvFAkM*6^cuZN>4UgPbzQZE@jJ9lSyMn$k}~|IYCr|SVOvH zf_Z?KcF?>pz8opf_3FjR$)aIr#|^f0>e#_Thh`J@VA-PCc$5#5pZDySZ&6|C_3Se; z3aPx87iKlIPg0FUMhFpH+Jc8b_EXoymLY1O#FgY}o z-hhGqERLNn8jZhl>rOnsUCQX9_o+S=dm9$;upS)21rGi3dp^g4_b|EmVG@iA|>s`zEvuq8xr-tRo zaWU>uJpOg_;L|DIb@RscZto8r;!yv!*@@V6?A&eHw*RPnJ(M_p-ii3QeL*fqfrxV^C_N<~8sZ1E% zEnS#BDJV>a;{E;nIRa|JT^c&{U3SkX93O<@8RQ03ze@7sq;Z>W(z^RVaY>Aj>^X~B z=!%L16VW&xG;pBwLrZxS3q@y~J2+C}!+74Wq)b6KYy0Y-U`SMiWttx}$pg;OMiwh< zZQhG*8KIv}P4&Tr2NMWj{VneD~>$#ISGYJKhUp8EE+B5I&EE9u)5F~ zS56+r2OAUi0}EAC11eQ~)KdrI1P+#-xGEdr4PfQ!!qATNq_tplA*q~6$4gI{)b42+^XUf> zw_{UBPn|q@kj@P=KlF9<(tKJfEp75TUrf0j&UwzI*Pp%Zzsm_?|E<3wZG!y#gLwlr2tETcE z>L59De#kz+qP}HW83K1wr$&ZW7|$9=gfSZzwkU)Rqfif@3lM` z%b+?!g7ir=Z&$C4SNE zv!Q<*&6@R~DwT_Jc5RP!^zN>DJI*O@^}nVGxV`tM^6sQNQqn-s1CuiYIa_lP1|m8} z8q}TlUXU7(Pn)9)@t8$AST9XRGp`BBMxos*QIWaeHtsoA^Mj;rk*XkT7bX~q;6&D| zWv?3fw%An=N}*MY)+ukFfP*Cs5{8Ye@})Uo>C7As*v+Yz5J)`)VG`4n1b((ZU{2)? z4LQL}6wiL>^jIiL4Z?@KEN-jXs-ctVcd@+>S@eSZv~t8M)mVv9ZT0e$P_(VmMjBtz zs-gYp&#pI=$e74M^GP{gtgr4R*{PVWoqP%-fw^*G+4T3;aM*tTf1X}#U-Upur&W#@ zlOE0sdpd#P#2H||3#lb3Jf6u17_uv4DM!kjMxZ!*>E@Fv2G;_YUy!5F5_M)Tzv7b+kYahdtM;Ga9M%Iho`y`>SGVZFse)E`GBl!ufw% z7~m07uj7mIXw`)3)ZlN39Fj#@jRnd?8D?C~@+`L^>AEb3ST(u~%e?>6MB-5jWY4m}huP#ulB9(h z``4cKe4beubJgiJ+AcY-CXi5pq;r1@-OhP*pKR{*$z?fB-%P*yZ6FK#HEI~gg5x*I z@Ai8=Uu%ZOR$!-v4Ua9zwRju>{!y{b=yXP(g@y2N5m_zk3i^C0oo3w0!+q6fLbR=5 zJQ%y$D4#m)v0lHQDk5^X68qD4%{J@w_<}TsA}x%A84+qMc3gS3K1D^w{pH7IBA3il zN**iL&cm0@lN0q0%c*XkzYIn{7&+aJv;uB~kX@_R;f735-7;Klypu-y!_gUN1nwosZ1k{xGR0onoCnIf={a-w^Ze!m9y40wC@eQnoa29a+Mu{&DYe=!j()WwxOWiu?+^$#?%c{vu2hOxSOdes zcG-9XY}9l-Uf$RH6^(=8eE#-cyluPEL1QR;9QhWi_B#hl0E8WkYk7Mt7KGANpjNz? zUUBcXl<%$`?Cg$77xLe@phM0m@$3Gfmqw#YBcPBH-Ak;9o7DEm8cU$e8x*=0Xe5J2 z`NdZKCee+_C!$)T9(brrD#c$+7G^ty$iA7~V_tW$(S!y0F3j61%N}MznLg2ed8Q4v z0sy*1AS&p=ohd_!c@`5aKBS}Jh{vGrKPk6r$yRK2=Qscdg`!av&bC|#cMnfDUM0&J zd%x}!`AFEO76*06wa1l4>T>2=e9a|SU{0JT0@_1M&%h(kd;@v%uMQ852_Md>*?R)| zO81XETKUPl9jtXF&*@W$1Q;<8qhY=N!W;^PyG%9Xas}E_aHVDbb3Fb za}>Ex4v&g*iH^8!zS%rOwfrIEh6uXn#A|H(_!q9~6i;r@pig6uY_(|y&`sq>Q4Aj&2t%ho_d%CJa#ZKy5#h-W^8&>=qZnYah zbhKf0wIAsz^U9jLuf!kDPW z1J!EPszIk=c|P5iNyO{UA$^6STzAJwA2%P11?fFovKoD6@=JOSfytvoBaPGu%p@gm z7f-W^ZgP)BfLRIiaKs4xBN_B=|8^Swuis)!u2(TB&N~Ql2Kx^+8=mlZ#FW;-ViD7z z?PS1Hi&TtgX?f@8lb6fca&;RrO2XV+&YKtQ^0&*{#|RC=Z_?l)|F$Nod%~qE^;5>r z{Q|rzcF&Kv0?Cxh7A!WKr~6fh?dGWrnn{{J`=zp7fcT;YF@i!V;=&EDgg@H;;j!== z=}hT{*}^65CLXV?f8Sot$q@h|sTSK`TPL1diJ-h0j&(^dN52%VB3SCEEBLy_DXo-Q zNadSYmbNpA%*|zLp$$ne-0%jr@9*5S}UwS@;$gs-%RG%;`_< z{LIvul$>w&5iAyq%H3v)Jx}XacjFa-^HJ66?4FLo{9>T`hv_h|{_gNA61MDJUqGMr zsWk83RBR3>^cLj@gkk3783Xd%FIY}HGI+4Zf^CqogI^@Xg2HS;x+x&kZPSUx7 zQN1sh)DCaDyH-c{-%~}(u_iURt4;)CA|g^%<(f#>R~*XJTEI%yZ8^Zm@uRwzU*}|GiRV z^{N%#PtzyF6;#f++)W81G*BRg`|x#bhFdkp`V-3??EsrRuW#4;sU$Rnd zI3Q=M(Ifq1o^SH6M7VbPud=Kk4-jshR<%Z#YKY$lFC}q7ydO*wggJuTiaY6IEL!yb zZ>WA;_@>LaAEry9L)x8aZl89ypa%+)gYHPs$_{rqaDjB7J2kmogMH5FJY+{|a+a*j zZLuCki8E$Ckl5-ha)j-vaFhsbo+ii?CSrx}f@s-a#zX2fsA_jMh4o?7=E`*s=`41Y zWkaWWj{(Ywc-`iUwOoeZ`kb3Xj-5VW4eMtnk;r9k>C}2{2|L0ql}ZmHXzOm<(a8&B zgheAxTMniSC>^MNhD3tLd1%|E3Pjpjw#iav(*hM>j*Nq2=QZ8b4M)@gEK%8iuHCU) zgnS^RTCPVG)?#KDU_WmjQwv_YbaNB>S_$v^roZzaPS+JvY`Dowe%OqMR)tzUygpLL z5ce(@y!OTJ)3q07Qx^G7{gbe01VZtwcG7J}ELEvKycS>EDUl|=g`Xp93vc_ldbCTK zO%;yTGt&k?X@2W!6A>tr0aqWcZpaUsX%*6*$@-&`pWlPvQLTjI5j~iup|#qyr(l0E zRJH@92Y`nU-9?x~?|qd!Asn2C{zux%6A{x1v~qM3&NPo?u$lsUZZaeZ(}>SV!vPHH z5aIjNgz#2%cB2x z*c-28zd;&MoqM>^kZDYynVQc#UjDep)A+6*b|`z|DD&dVea!?hg6wkmr%nOo_+GR- zah%W>)QA3Ms>S&0X z*_M2*jx~$kHL4MGC~DXiFta3P>hJ67*~Yhz6_JH|RGW&G3BB7xCYK6C#|J)Afm3n~ z-pV=-^C`>@KKXB7(dhOy8Sk{CM49x+NJSfSNbsDe)oG=O9VX?;W*u)Poor>8Bod94 z6?$M2eTe!Zve#pp{rG!do?7RZY$_2u`-%QPQyR_mpFPmcL%!Yo3*RuT13TQwY11!h zXD^il8E-_)^WjTbl_rNm2ZGmWXA~ClF7TJAju3WQe17qjf3D197Sc|yvtM<^WM<1> z9lqq7aj7E7$B10yzylZT@hu8J9K0^GztLu?W@)HQzg-lPVCb~(j&i^5U;(@D-Lp6y zvGV81OPTqUjJ!+vh>0Qx{oy_-m!C0J6$hI*BJuoH{8Zzrl%YyNo3n6yOl3)8`l*=l?qNy=ya71h@0cm8!-W}9DP3i$X4^GjFP~Jh7S@)>)Jweq@3-5!ixqBOpf zsUIR^?R6{Jh{9xt_bw78K&=j*!;B+v`GrK69Hf8DI8<#&K*d2~U$pF->ahk36O(lR z7G*D#OXYDZ6Evf+oPZ|hlrScZOR>z*q)fXhf%?ON`z{XL@ob#vB*o=!3Z1CX>XOp@ zeop~3Hl8+D)OYq*xnVxEJUpH==w^F*895+>q;`{C(bBDV{dJ&x}UjtNl)dbBH&ZXr{>KS&w*uz!P$Io!>Rg z?&OuiVhhVU+WpX}*Sdw~3Xiq%j=Lv-Q=lvI<)K$~!J!Vf>f89cQKl|FqK`hL)1i^| z*7G!MjyL|F^5(bL7A_34YW)>!ZiP;$jVe_Ex-CGe=Jq0+tD#UhE`7qF#V{zC{0%+bd86mwWL z`DLGTuEmzkqb+UXN=N_Ngv`H`wS^3}iX~k$znHR?7N!|`lOtQd>eHDAlQWpg<#Us3 zsfFps;7F8one<_Lg6Ui}$F&5KO}xL*daaK)PoG}8YxxKe&0g)usy?3t)K(HjiX4TK zYx!A!xYFKBegE2dAccM)-hNdNh)9Yie-z=;X)0JQg-N&_1mByfbM1%48yOROiih5y z9~Lu@?H33u0bvG!@Sp{X zRyYbJ3+a()ye?8xtAyupg2>St~}Xc)U;b&1&8k3ARPd7btOk1YM?{&(i;M z2w{Vr3UoKeUsZNDG&p3+)MT>?Lc610i>_E81cRDT5+ChJrw`Ww$Wf}5LL5^9QM_Z^ zy1q!tbt>|%6hvZ=To+?+;B9o0UA*xh&jP+h5mC=)A=_M`uLH?s_lVs7K3uOL(*?~f zL-u>Ay8;GnjcE(M`X~~LA&chfy$^$rIY+N>Itrl@Ev~XSN=M1YqA<1tG24jlUxami z>)7Dxxb!!C@iL#*QiM0~P)1N&nMaV@VYsRNI>t^6D9#Wg*}Pp$^JrrpK>eBPPl&d# z6Vjr5|Ae&(fl!>OwdxD30r}@-mgRztJc0lF~Czs#`kvv)Ekxj+}*Td;DKO{PI3}KP?|i;5)#N_ zV>e@^gJg-WB*UyMn=1)gp`Dh}YuhBWz<7S?o#6qy{sTd(VZy_I zbMy~%yi2*+W5P(<7o6%zomu8ennzI!2b}y~{I{@O>CKZod%$4h{Ow?eGso3ldWWQ- zi))no+xp;wATK4{!J-LS9tvV1mbhg+ov%phzj2TOl4Fk?(zWzM}M(nHb@8YHtVrQK#BdeulkxnD`v3zNV+oK&b5p32HNcbeI96_ zeckSh(IlNsD2Ne^N9vRMfY?R5VF(!us8~r%Wds}0@DVDzs6a}Gr@Xrv9y$hrlgWrn z`uB^VAJD1mcicbwe*F7>LLQV(`#yT#ry*^Uja(*Z!l@FNQq-wEbuEPzF~@fRW}Gs<1Socn(z!F;CW7(d#B1jYfH_D;Te4bjOkVT{_vY9kL|kI0 z_?njlB$QnWDI0UEdMy|aPoD09l&gd&8R7|-mZwylR$iTa%v@cCJmTQ0sq<&HRHnje zsUbBMBXC*LBO`&(ua04pn}Z%Fz~4rybc!=r%(h}UaEfYCGNc%ilq7JHD{Sg=K{G5 z;2I6OyYW(%`h)o!dkR{WAyHm$Q#0zBo{JVC8(!(;eOXp7Purn?N<^Go6IfudaI@nb z01b_P#vj^CtE&(P9 zPKGivm1x-EN;H4s6I2c$=d5(P+OBe+GimtZHF^5&&U&4LNnBLHZc^KDq^}UQ`L=57 z?@yowjY_3^zC7hs-GtR*d$W~v&01Mz_&#i!CPI3zvXAVxL%ItKU!jmq?8M z7U__XV2!m}$6}2eg-Sy`2JbC6{B(E(Hf~C5MKH}arDgkF9&I{(I$aPoQjF$1AjnvUo@ge9vJR2uJ%ODHis-c3(N|3QEc)I?o zvDRwRk-!x7oAMP?Ura&h1RRxSjJ#A?rs6@(qU&_LHjE&Y<|6#?B^w0ziwxsjfCaklAzoP{t0b(c&semnVb-QqU zzxnURUWS)Hs{;bm{B9N+HGj&X84_v~3)Vtws?HV5g$IGpd$!zWxXm z^<)B1ZZMQ5V2Z|sCMDAEe(dT}F`AhOkK`<3;^ucdExPY7<84gWv^rgLG-2xJ3=Fn+ zPjL*4PRkIh-F0`~8|#E?P?85*p=sLyQA*h~)7i|rf{}68MXIL@01ei%U20XPTY%89 zFe5f3HdmzxO7EN@x@wkoxGwskC_|k}?H?2rh}1K%vJlNtiy)UVXrx;JJC<9qhXPv< z*%>QYxJ0|{faxMvd+s_SsE&U*j0tY8U-@#WK{->wEfyG5DQOe!D1YZ#o)4nxrv6-T z!-ig~H=@jDD8fnW!CGtZz~AEr`@RKr`8ZnLD5Om~J!PFmpYk*Rvg{NtukjLyPb7|b zq_8n}V1d1bDy_e?^Q!27tQ0ZOEYnc^e>FcY*f{jP5tVZ!bJQ8ytG1{u*Jwa-s{BPB z(v$sgoSlcr2JP?w*BpjUrL9FF>e9#LRw*E_yz-iN+6f!hX!tEc#B-WO)fpsJt<91D za4>sq)}808N9{Dz&DPD(%dz#WDJfi#~@3)nk7c zoOZmaPb7{EJ2!V0d%oO+Pov9{;0d=3G*u#Ht)vDK9MOlOvaI{-OlpzFyU@8VKgbOt zIkT4Lxd8mgAKw~t-1o+J)g!(-P;IGv4JMM;PNT^bgB%^vFbn705c;t?E*qnsqq{4ig#O9{uYg zp(ai%)oL-uj(L6SS`~W2Stt8Ra_x8i9nR~jD4)g0SovDSTUm2T)$sNzlHEE}#KtsT zNTInCJdSY>7nZ>lI0zg~ygTb{F-8)#ChAG2hP70Un*<1`d%YoZF=E}tQQciep&H~G zAdzGDh?fX$6cevqhC26nu46?DOX0bcPQ=~~x zMscbWcGE^@E+#Vua~Jv5{7QfLbX6Z2Q^XvBE~i5ME3zpQkn%9^IwC z7Ye`J&ZY1~ZtQ;5$l1HO;UjEicoOt82-^@^*1t6<6lKwstQ9m!u>E<3r{4B(iD;}(i?(Ol2gi7oP(V-d`s z^FtFUp`tEMl0+Xw1H9lv3&_JrA&!Pi)M~OZIT@iKov`)vKN@pF-oAlDxYHP;&ch0} zdU7KH#Gb!izj+4VX?40)B~fN*z=U{kQt39`(z^_)O6fP@Xg4`LDh`Rc!cD&k)P{jQ z`fD?Y(mQOA(9oqPKD-&lQ0NrNZ_XaM7(EZjzgxC3-b#O{m!Nn9F__75c&61UBvQo% z6{sV!9=}K4ffm^%$;yy!&&G(=$g%Tn{}syp_!aE>4CTvziOky%$EBg&0Zod|#i`8F zUU%Pzbb@ETa$?q$jatL?%Wy)Tb8zdin*KTybPdi~valSxtEnwD6nF2y)II#p;^3(+=uv;3hL8!v zX4Oy7TV(w9iwxl{7zs^~PNm2#*K#kQ{cnBZl2-vVC5>f&g)2q5^2^PxPnlLh@nW?C z*4i*pnO+HLW(XN}AH9Q^ipk=Q8wu!4vYy{(9_V{}(Wcy}v*TGOMp06D{>FIe8}xHh!q}t63G^H?Zqq9R+p2Fiu~6VG_tyb*Aj=P->Us0)4EnnS!B{URRNiGKb{I2 zsT_523s~h)UflwfTBV_b85*_jukoGm7GamWzjxVCs_ZP@-hnr38`3Fs|3>cnNRz0B zoW=V%G7l}mJ8^4tE;`9^9T&?~3LFOr8Ad)Gz8KZ>N^8|9$V*}Y38GaS67JRX98VK2 z7$09=FZ)%r&k$NA!tWW6REMyF%$@hQVx4mIQVB|tuYYE^0PQXdnAs};Pnol23vwSl z@Aw_QXc{s^8qAf3N$*Ez2`9544VoFbUzfX`yJWTY9&|h``-rM{^SRp6>Szs&h-fqa zViNLtl4zCG$5W`O%+wq4cEHdR~xM_}Oi1q2_K#w7U)9LG0HH?!J!JqQKV1eMp zq%?{#ueImO-PJ2v(Hl{K@p|7Tf!~7Bk`F1xlCcHWm37c$QHdF#$sl)g^7k<(K3-|OHXfhJUyf%Vs2uk(;_uE^>C@NgBOBJNP#U$(vZC#0_U|KM+^-c0b8N5q&nUTQ{~t?ZYv z&sS-&09}3~bJs)F*S1@ACHh~2yIspQYt+$a%!y_l-NZt_duWQJNb@=M1mP|=rVc!R zhjX@T4;nlOe7-+bX-Rv-2I@#HS82~wpM~otWm0R?N8@}nN4=eCX#^a@ zSE-Bs?tDR_4YwVSo@g=I38OH9LK*c+@RY(4&negz|Gp>z_0WmvSx&z;4`q1toZ+u? zM#-XOQa`e-aiwiIzO=9@2(0mT_VSviJ)~5_YWEtr8>R&!-&ZN)4Ozu=phEjvg-$(m z$GlDc{g~6=dO`;30ZXjL%0`j=naymcDs{$M8S6iT`p_&pKyVlDTIvP^JY}&~T4%lf z)ljKkhuJuhDz4Z>jQBcqc%Mq$gl1J@s;jRD`UZ?y(826xf=Jb3wYY*@#8<7lk{eK? zyVno|%8xwNx7k#8F!L|8*52sQNck9iS6mB+&bS{A^te#ku+@0>7v><7U$@}uAWYn` zryH567faT~khnnMF_|oGpTxkQ)v;OLS@e{B>!CMwV)!|UiFh7xMx=*s{NW|V_?MYc zzS0#DV4eN&tmB(HA;k(!ny5lU4j@XYDNEGcj^Fu~*Hm0=7paiYY;S$xQv4Oa(3Y<0 zj_vY2K52_LH)W{a0~ofi{}W>~v#*;J|JuGT%OfBF$7;DO#70B6v%?c!wf9lfjzu3$ z?RuFCm8hmb*p@u2RPXrBLuN=y`;Q<{32&_423-N*WnPv}Oqh4|eixZC((j#?sOpI# z@Zzs?hX7BdMyE5F`GIb}(hs$#h+?w(PGsEI@9`hGOZdo>Fb^-OKEt0to8k4t2?d`q zf^FFsw1eMlBJMHQ%SC}7j&CqPqFNGsS>!*7c8IYEG8a>J(<=7NBNQoV6<3DrRRZno z%a=y)htrKgEl3ggGhSc+fkLa1Y5SfCr0*_9$DGTcUESb@;Qc?cuM%yPEXFHeQ;KDZ zE^D>Mb%(ixvN(%^vU=PJ!2Tz?D8f&MMp=RGpX>{_vU$9p>Qe~HvADCTNo0TXz57qq|#F%*~uTpcB% z?ZBV6q989&z)dybt6uke79NLH@Wz|y0~*}A!Zvpbj1aMe_r#zZaX71~!Ub>jelxZh zcVAq0$_>M4419K9))P;G$zx+6umzmzvq*pw5sQ}#<<+{tkWLV+R}Lzlt4R%JAlLE! zp~yLsNPNs?Q~<-TqA`oRVJ#tuI3_i~#eL^yR9IXr9vs=#7@V?2bGQ~#Bwjl)A{^Q# zew+Itq4jPEQgGl+C?rGu{=17i$rxDzh11XdvIJK;i;?Mke`_nB;tMY4=({5_3heHi zC&&VaJx`ay;~q7`?RvaS?t05_hg>P|p(vpmu;76FuHs8Xh~Z0>rc-;@8g@INZ++7MjAxT_lgmTWmv-tB_!G zm6m^IP5`@RYfKz$YIf-sYo(G{ztd5RcKNhU1LO>i`L-cn4oHhossfpV$n;TQC&5^} zYyIQpbF(*>L!$`%39yqtQwo(8oVSThl02WAH#(Wb<(Y~JIAhWzyY*-`O-bceZFrnh z&Zu^Olh4asNxjQA166_@KR^96;hEMtNR2(Geb7#4f2umoagpMwq$9i;z)bc#AkkiL z!l|f4jz6Nqt@kNjsk_=tEc8n@=kU8D6Nd1U;meXY#z*+FwVZ-YIQwY9>b_MwKuD0b z-3%%op{GN!+O>dADv6rM_b{IWFPkV^0tV^!rZY%*faL6WqhvJ6A~CGziZrKlTWi^_ zhZ<*nCDqCujl*Y`*A-qv-X!7g0`cM{ECCqU>l^NzG(O zipS(huHw*4HY+*uSilV*6l|yh>P)1NNCQr*#qhS@U9q$DjJ@pe$B(;KrbHGglL<&$ z@9{6b^e}T*syUo)3|h8md-WyF`42G(gDfm&ef!n$Zxy^kjfE7iq?F8ns~}7N$gy(~ zqX?AUst?R@2yPb2YW%)VoyUY~z1fH;Og6S+nYTbEH?Dx~--}-sL7_PR~-kL>d7)HTI3lx&)mJ85BXkv7ocGKPnX1k1+AklO@fdgmw4 z7g0WnQKr|>jq25Hy~aq6&zlestnldfA};F3rILLfdBg~P`(=|a7L4BVFj9XwX~J_p zKmcMglSh=mA!lpx?p(6`gGJVwApVq^#X6MdF0?x3^c?3ameT;pP3ByJ-)vvqiTXE+o~7b&`32i{oU$l4?Mkk(AnWU8;C&?A*a5 zR64e9^ag#t*hIBx!$W%eK@dQsrZ1RDr0h`NArJz#kXZ5mDkUS@7ofj&5##l6q1X}6 zi~{yUslOF*XMfpR-hi2nZ&Uq}BM(nO+Pgu_8M{cfI{2Is3%oK;2);iO$H=#B3VM9o zhXQ`cU3I_v5P3BWTKAhF`1)WuK}Y9seaJl|(X~;Q+|wiv(9inmDU4uA+8MT*C9bPb zj>W7p39J{iS}o5)57}!o83*x zwz};%Xz6yB4MiMnF6BwB#G*~+^svHJttXI-@9G|>NrP;ycUe)9!@1&T%8fo^soA69 z%mj&if_Nn;lX@Z{Rzwx@K#4(oov61JY^L&v*;*`A|HEdt7gnuSC;g}3smw!8cR(TG zK)({lF(@oHswK3Y$V>MSzv+wi}@pZa#;^`rU-3V#NhaR1yUwo7UcbUE8Zy$ zh*Q(^Q<6mNJBRf~%IR^QLqtEee|?B#umu1BlS7RXR(Mhy?ixbo{~@3Mya`%Vtu)>X zvmGA2r~eSp*EURZ)j2c1vnJw6m>(?b%VQC!3v`~3Ej>NnTlv~uPe+^1(IstGA4iv< zn-Vl3&@!2==#WXHhA^_QunQ^}&+gd@H6KIRL&K73{%Ey@=b&mGR0#w+{H%nUopgo- zd2qemOCqh9&b!mnnFEZyKa_-rqCVX9h>w-H*cm$Gsx`D8&}c(Z&l((Vw}nBVh!H;^ z!ej{ghh?n+VraP2MGc|)K|{z>5Scyj`a^;VG+Lso598C>M~{nZL~B56WWy!rpgFgh zi2u0gK}CnVEM(uJD{P4T=lgRqg!;5fyc3Lo&(Yk#dl@{gNKsS{H*%!DZpi0h4%5ZA zpWK)_{@!sD@<{e6OdfHN^x;(m!{quyDZ{2#Ny;R;(2y(0ws54qu8x($ z6{nygQtyV0G1GoD5gn8=_|43go6yM5k$4cV+KtuNI7BByZ1TZ9tQV6Huh%^cFd2&R ze3FdBKJ<85)u^Vct+rrU)Du+SUelTE@bdyHMmK=;TDwchqUaogE0%1PUTU8mys1B1 z0>E8^LamrMt3qnNOoq-yK7KES;-No?ZW!GZ#&>IXiuS7n{8sN*nn2)(kvYQhz_o+! zXYj;ay3AkOe%{C-iJT$Qml5!wS1$$qCYEV^5bV>KY;cNq@(!H%ZbTjJ52(r(@yCh<*ac}lf% z;*yzv0#A-(j2$Y=b)G)yywEwrqgvg#uX!(ASCWIt=krI0@VXVcUF$(31y(Z4eqZ9> z+c{|hg$)%av?i{Y@A8)E%WD%b@g*jwO$@cgR}weHxONn5z=92SZQnPtTjQwZFra|_ z4#@qEtWT5Un1c5weZD=>+8MKh(~|7?dh&-QyIx{C7ZFd_Qo4OInN%!xKUrDdpA~W; zaCX_dB^&0==g|p6@Fb3X%ifMCif>kpUlua6dw-(f^EKB|8Uni8K?Q77?&e_1rd^G6 zeo&^$Zn4^$4bfo0X!#+`oq&?^^WFExc;bTXmmF!gz(1>NXA#!AjuGH)Vs;Z6W2`sZ zgI`Ge#it}p$^0(S3I{`g!BV?N`)DM) zo47D|xkjj&1BY|=3uebHNtTK#Z3gKY{yftzMi3iOMh#uw93YOvz2tf}k7&*WM84Qs z=%9*sP-NXN-t|FZ?|oEQ7h6QthrJ?EceKb%;bCr2u!^Pe)9#M?&+5 zJx@x+PRDk~uUtNM|)uP~<=Q)nYt3I+094 zV8gBehrJmMmXDXwTXIlR1qpFS2m!1KoBU>|nzZ&yzPi5X<0ivVNp>HZJqiKZvZLCx z26KcPBl%tcFFGz)AcmS{o~J&ux!!YuwD7B?P^8Nd=^*`p-HQTX@|IsUY@0>!X0!Qkgrn=$<)^10 zqj$7%+G~*xcw~IcXdX!8?8>}0SU=r@JI|WgF+45(45sCc^VPn+yXQ*e@wyV6V+g0M zP^*5p*m^(27z?M}O5cWn#gb~S6|6riDSCN)OhlJDNJ5o@!{2ug%kb1y?*XJOA0;nU zsATFl0YAQk*C@Mk`+y) z1}LbEMP_+~AsVMkQw~D@_CQv&i8QP;+MFpfd#3Kvkcebks3P)pgqOJy`Q#VVWaMa& z5eSttUAvu}>Y1l~KU5g!s>|ZdeJNa8;3#bAd;xwKmWprG_uSe0*<^lm3TATHY4WY| zb8>$j(iu$zW2dapUG+kaW4)g93t8s=@xD4UD_)vgQ|PAb$m$B4Xi{&>ylCrs9};=f zw2t@r@I?{<2+-rg-fPVPy^xP-cA{ep~cY-%ysjKCXl?%WG_t1YNQ1Mr1% zJwS@&dT<5ekrQ{*Y1CXDlb(TMtc#G%I%Y{5Na zoruGy7J@9`&JygLGAnkt{31L|&HF&=grZ|317ZW3I5ah#2y|j{Tcq4VRFDI&PG8!= z#``n(RcXGMmuC-SOpGRXpi(i8*VC|_c*6uZ-`apbFPv8*pNE9nRq;7~1X~@>1`1n( z;vQM}EN6b~g59sy>;lgC9|km5xj24{dKt=)sRyN_N#oJ&u~u{Khv$CLbMNonBEQkk z8Q?5`HsqUiH&P{A`~TRrhI`Z7$@(%q8zLbP zjq-nQJ;~d3rx%*sH`m*284CXLru(Ofo=V~5Ix$xe%3su3M2gwLR;@F@e$MUhhN+po z;gA*R+0hd9hgF)fft?vj^^XI@zEMJ$Qa$We#rfT(vtefEY$m^;$IUQ6NVH$^%i+zs zzXwcw%^rJp%a6PZ+-IT8e$HEJ4s8E%!PUxXrEc~|bznztp=9RUbM!dx>6Ok?W8nqp z)q=%qS@N9Pc%SX0VA~!zSU8^num=8~n|o(#eGqzkGw$9)%Tf+1yS&@KXv-t|fx|g% z&+Y4gFut}a*Qn+E%C3iEBo2;Nti_5E9q=#<@ie_%-GPC>_hkuCN< z`;Y!~jXvcPCrenVSTfn%3p9S+0gmUkNt1dniIX`@1CBfP%n#+0nH(BtOJ&fPj^HN! z?~G>4#?}KkL9SlLZJXhPJ$Cl?Rj2mpp$f~XdcG8E4yewjPp}rc z6?j2s&B3PBaZdyw*Rg}GlbKp zxlee>dxyuB(rJ9B-l5ih30OF&wLf0pAzt_Gs0S}aTw`k0Th1%B(`Ru87cc3IE+6D= ze)maHU)FKbXZee5WN zrlB>BRT?6D1$&Bn-gnzCu17cAv1D7TL-k&a=$0_7oo@uY)-W4uZIr&FC>HQDgb?aVJW z{(WPc@uzEeY4nt8xqEncXzy?@@punsU!`5*KmZeO{1nUA7!~c?Xno|Sq(iq;Rj1h` zs#xJmjA|D{u9iPy8gDryL~?iJ zBi5nD>(gT0rl?m>jxzNj_4(!ZFkxKlfww$aJ0R z-TNt<`ej=bn5_F9o;_|75)wANzP)MsGu})!J@1_oRokXR>;z7Ual>6?u-Q>yvD)+< z9mK$R9jib-@luO5M<*^2JjRV52l>1QQg1g#4<%40OC6_1cyt|{1#jG~r{SHOz>2WJ z$R>O6Ikog87Ec{&+ugkZNULfyn!i&X#xLl9u&=P4|2=GFYxHQ?wuKB>{VN$RzU|5Ql za!p)|R2{o{1|Z~IHkfSqN4GLZCtAV(Jjvthwzt#}t!)||zSL#jEd@+zIFP?VJm)O; zH}nL0H1p16v(jrGWwF-&2K+xly>02j^N4!4T#JRW;vaEh*M=VdeepD$8Ot7CgXX2n zI-rr^k<@PIg1&hAOWTZH$xOdVmu@Pvo7twOrGgmit9I@Dz=@uV7yE#zur{A?Y-TUUvObk7@^zvR@%R8JTuNPUR&IGw&+bil3sI9 zYub9*RY3nAikx+})1&!+U1x2txWzjEErhf1zmLemeD$5mdA?4TDfY194$UnEr6qFW z;*2;MRI5KI?qm6;wUHCnYWf;Aptbdgg9H?k5C`hP$2x@GMxXV1$YUWu+pi_dwWCxo z(X0~6TyJXCd3rmMIQqm35-6_%~NOwykT?3*ZAP7n~ zN+Z%R<46qM-7s_t!!UFW@s00$zVAD~|IhhvuIrh)o_p_guf6tj?-lGf@9QU(d7s@H zl61L2Q2Vd;LTP$5u1C)6=Uxxm%{1yViIpNjhAyX}5;9-QnynH0R{yC^Rv#E5-;|B3 z*IExxhpB?`DTYg>UzFhSoL`Xxe`)q=4trZc-mGD%%?n9>uQG?!_sIUy8fd(kY6cid zgj8ERLEK|7YucD-y&fk?FTsIGDTl zmJu~l{6Fp{g-pA>!bgv0thR-s$&qG13vJega3UH~P^P?-FAVp*#u-&N>J@p>R1M<9 zri$Rx4$}U?p#punweH37E=#wy)jbKbd|0Y4zMC$v;NO>9T3@q-kuX z+~l%E+`M2_MBB#Pn?Hy+nN7kH?dJNXco0?~7&-Q9lUCg0m!QkThm|jG^J&-@?z-!X zKUM8@f2_4NUKSf&w!>Y|=)$t;S3~le$L@^7EKsle&QU4tT_uVCVLmRtWXG3@fs zP>s(>{?DanoAU`8wmK>Jv$Pe~f5f<(e!VVM4MUersi#Z)#1u5Bw#fd#3%8`rdv%@L z8i+qqOZF0F&G$CjZ>dS-c=rLOC4J$({s;;^%R66h9!qn-^;WI-f3^6(Ilw4r{vS=k zjPfgj>C8EWc7J7<VBuGU@9@@S2>0%@G?PEx9r z3a3UqyFc(Qh@iI+nNGu%L1;9=+=$?~Y?|9YvUeoPkuVAMF?U|SsHrn|9?FMiNl%vp zg#<%EdxVMH5(r0IZ5fR6tMei4wwCg+lFX`D6Gwl4q1!IL=pCz_dGduOv3r>-mxJcz z|L=y@?EH5+^BEnyo5mWZjhbTb{A{?@wC^6`hv`3+R%^})TbwS>pyab|UECVHT$7^S zzjNEM-#2(%ssCAZe4?1mdSlWm+(zLxq^(fa7E&+>MU;)L_NDEwq`5Dh*SaE|Z1a$_ zzI(#cV>7NOv2iB1MI`T@J`YM`>L&sCdq18gb>-sivXtAh4+Vdz1ZCznxfTbV$xMBe z@Y$bT9RB+Pg)O>45yI(%HL{J!Qj97@DgcJ6vRIQJB`A+B}bn$F# zhw|7V*wecY)u7d;4TJ11F6lmsdLNbP$+XU8M-b%6AuPSeX(f?XutLl&ORx4^;V7TG ztemW@zt>&|X_uM&RCCp} z#7u6Hkm=YnE7&MP(DS@z2fr$lTcYk#ScldWqudGQuH@IYj~e?LjLdpVTOIUCXlLx6 z)|794xM1Gjd>=794I3tMnF`gbCHC}=bct!aa$Q=4<_M#Prh->jWBpcAPcKguG@;13 zJ)U18tx-Zj7%r<4ZLO7lM+l8Ne3x5^@koQ!bGupz&yf|`HJZ6?owhb&9hv#u2h=j^ zSYWu@YJ&%9gJDl5bvmD9;kTjCImECgC=6V7G2Z$$N+hHW)~LM-Zi{*p+1WM2cSnpj z>C}#Z$68yua-`c}PACVdj;z+zQKv_pK*?&*mBV`T2vK>6q4PQ%P&S_&C32tD3ND{l z9WKE19@1$MZR~8i3cut36UFAe+6vx;)k36sL@m@ikF3H<()i8Z*l)2s4?0@%N_20~ z>Vdvg2yS+)G!SVbL~LpnKf_jR;`cn=C7uPSI4#qe+}kF9M)m0u4!$Y zH_Vr(-?fiC5H{&yY%O1E+`k3;_f^FEhg{s^#-S$G!Mv864DNa$+#^^JzlRw z(96V#+*6yTN&qC+n&sQ}a@*m@*mKrpsI9c1^1s2F;hue8b9{+#KghS!2KznYmq(h{ zWXe63oSxrmy5B=v$}=SZ?qNt7o?mTxqqL?vxx)|gD7FW>+OWJTX>Gepp1N!wZOq>w zOa#+PqT=`;s#y)^!}88hFywtun5IXJqIf|uLYW!a?M)*@4nu^Aer-`=DAI?JX%nuN z0J!Kg5qzRyqkkq6jN0TKu*W<0S8P+A_2B`R5!zspyj`8_D9}|UTpNrE_1r7r3)HFp z%ck9nP_otxzx~dru39yGBBtfl2$uoQ;S7P0;WY{Jjc2lkRmMNLZqBxS3CHtu-^)n? zIgW6*OVWPnnT392i%;am`b79R6d!k$BVSq8r3x*mkrtzZSmNOV<0j zwm4GEXl8Uk^8EzPqcroV4D9|y=Kfaa{9dOG3t!&LXuaKZT)_Ueqn zK7Eq_3Z6Bf&|GOlXGrdvXMsb2Gi)4O-L`t}a4R^DlH!`cx#GKC1?~k7w*%i583efK zNkr70Npx11b--YEFi}P4$OGlCOB6feq5H%EdtkB1+NyEQ11=Tz{+aS zstr;M4a&50mfy|%{kBD(YJe_$b6biTjDy>f&(_2K#~K{0p-CmckA+X!p!{WfC?z{s zmI&|kGOY`%%V`)0rxT6H5V^UE1#J56-n{}XWo60E{`4$Zk%_PtJAu}Facd+QdK1$x z@#qyS%PfB7Z3$Z4GRcl_PrVUARE3;bhRnNZ*_%z*$!T?&+Fq<4y z>A{aWKO~M{?uohvinK9A5I79M@3VztW_{a4Jx@{D>$Q~a`!76IQHZDmD+Gcdja`dK zQTU;!PWI}*0t?X%KGFyYyJ0Ma17K$qb2O`{tu9Igk!!s=BXxDfW{S$C+&u+u@7uch z|J+dof%|D03bo7fVLFka5_M(OQDTB+%iDyl0q?Vh5|NQJxPPN3byN}9Fk^Bq9gEcc z6E<~gkloAd&W~$(F>6=$%x204mdh)aCuW+0`;ro09OG7g1c%+I)A2J<@>_E}rR4jD zavQ^Yper?-R&8+W=8yvHrsZ+sZ+^rfy-woX{3Bx*ak`t4E5SdUX%oJCiZWhUSpo)Y zwgOr||FUSaM>e^NSh~+t1dzPgyWwT-R12ocPq=N*AWrW`T*EjtXqY_E46TT>7 zKTROES1=mAnjB46=xx9x_TXn#Ku*2;J7L#ZTi)<%!fMv)`h8}Z*l2r%qSP9Tq z9Ny7T<%qfeXeiYRe@6Y+hEGzIH+1gs1`yX9D9V4kk%)7JXzKdr?Pg%`IiV^ybGeOb ze|KXi3Mv&;kt8`7r7#7AFAXkZJuQVb(mP!pS@~`c*sUL#drO6mfKsy3xT2!6dsjwZ z-h`N1lO7I@Tc9+^w7*%w8i`-h0mv(Lh7Yvzt&CeKgY(cGt5ydA^VT}c{e~DKY%CW) zz|RmEe6exwAmC5pznFjNNHGw5n&Ji?C_U2peZpaa3fy^Fo$HG%bV2&Yf<> z0nbs!y@Mzh8#(VtUnD(|QhFxWoicvD{&#jdLhy|fQpd7o z@7TluH`9x<1W_OOoV4~imgUN_B{>;cik${{zS_z?cs0+?TR!;u{lkjEvYgzqC0pm@ z<4uyqX*8ApqTjLp!Lgov8tPoh=5vy?7*pn>l)N0aB*zCjuO2pDu8^-mJt_(*T{ou# zd5eBNhB-Z*io7o^a}ET?(*|P);@auxWb>{+@p_&d`^LDD@+@0a3YW5@SV&5yBzuJH z$~2?P0;oolElo50O;bXq3rA*jw2D;do&J~iOc2BP!Phlr4Ng{Y812N~<*0>8v4j2c zCb<XmF0v~ zpe7WXSXCL;URs7bad;jrWp-t^iV#b;$&Z}nqe=x7oaS#FqUgslzRP%SlV4cso>v5q zf^y`id%YjO>L-*h(z-{N;LUjo$P0zOk#qMagFJ}=i9Yi}ejy`6^@E z?+@pb>Uug*R&C+9?NUhkOa(1Qw_iLEPc)(MBKhmNQmy!X;~L-Ik7UP<8*2SDsbk`UbWLa8VGVYG&2L3}|qeq*$f(~!zY19`dN>Aq!(K1*}w+bLlgRLv+j zc7Z)NliS*cI3H?SJ5vA{Uh|MxT_-QjH5=UR4ul{*(a<_0olSlc|c0546l@c)VN(r z@3>m~qgR9DaJCxC36Ra9FZ@+pzB(5_`bQS7c`Efdy=c!gE;Hpu_59Ea)H!iklm#c{ zVtqhtbj;3IFS*d6;;?U&7xk{g((&=}Y=JekY^5aw_py@=9ygk1Kznvb*9zGP`GS=b zOI<15CeAQy0+q}~w!hz0=&v^WgQpBiopr!~t3V{)TEu-~q+;E$q34p`h0hg(|HfTR z+(>8k3IHSA@T~{o(~qu%d=m05OGQ&n#s^MA>4d4qDaOuIyI$T7|AENK7W%P&nwRqf ziZ7QVTyDh!u;*G^{J?{`@*^umh1QJbWrEn&XQ(9(3kw6wdEWX&xL`QkiiS*=gL8fT zBoM_RZHI6a=JJS)i~E%68G3mmOB&8mr8P=b_|P{$MNZbL%9vM1RuA}90@gfhV#}dT*G@9O%d}){W(cmMS zSm&!0mQAY!Dqj9DJ-Sp^k+RFg@aqbb$`q$k&E^~%oNJee{_YjIB*vd-rea_QLr+)Q z;s~rWor|$_rKp8Im3}n=5mi_4+FtXRd?2tf0yQ%S-VxZG`!e4zm*N=ixs1@}_J+f_?L`y$o`rcdheNlBCl zZF&AdjX{2m9twX$C2?9&9K5vmElgP%zZX!~bx9(d%8FPS%zYEth-hrC%?Ag$Tbc5> z9#Y82U6Zq!cCHYs8MO1Y8u3LjPTilID|T;(dNjy?VX%t{8KK|R6XG4K%9F7w@L42k zvl#)sSGee9wK8YAo5C+Jy(#m1+l)x{xU{~)I?yn#>E%;oOvX%r9&7S-?(@3b z-mNEd$E$5&kt6!=fEEwnUmv4eiE08|%^{8Ulb6D&;{SA**?+v|ePwWa)seG@ z5|aM^LI;&Zt4*^lZEYy^SR9abG9m4^h@26|aEJWAN&8Hk@84q)Bj*n5Bgh-s=~DB#>n zlXGNWkvLN(KV^fj2U5aggDRm`x8ZpDK}p3}_yL&dUi?Q)0dHjcelDG79@R=a zt6Xi@H2VEVDkaTr!r>`d^r*bMY1Z~=x#TPz>1(Lpi4d%xoSMPD;6;4Yt>1}og4Vl~~XuVq} zfu6a8tw5f>lvc6`FoVsXC)(0m1w!aFtjCeGQHdDadday*5|;{|Z!ekJV5GK?T$L(&EDilQ*WR?0y+c zgPD+u0KuOA{voHjljV@J;<*D3PQ3?~8r+tblVzXx7&&Y+bl@G=;R+UDcXImK|&!VkSBf94Q||XTWJlHV;6sc{!P5k_wf2eUyh-mpaNJ#x&vdK z{b}-2cbyM6)sBZ=t$5>z3n3cG%fVktzv7s#$0-A9SFQqg?3&@rayeV<&mG>IapS@l=WAX9L;fZfs~45H<}()gPxRza>4ySm+j#nbbEXCT+Ik zqY4brxd&vYR@aK2Rx~tyCXFlqIhhdLl`@r5;)s(*s0ui*{3X=&e8>)StseI%mXMaC zHzBj>4FGbt=?C_?L62o}>!jxX8IhG+o|HW#NhT#JtfaK_Ef?giHE6)@wDoCpKr2ae zi{pz_*5-G&2;iX^6C`-=ZG8Otgo@na(**x4!-Z-#4QB;~RYp5Gh|trmbg2cZ^mSj~ z$1(cMsU5996x`P8r0?kvL;#fH%Br@KBkCRzactpz^}?|1+?dGJolmk6d_H~RCsLD0 zIzS!eui9ZQsyUY{{V{5P#oBp1*B8}_5UY-KhKTy0&L9Ia24z4J$B|{rvRZa1oesF4 zE;XMWWMXPq9@M67Wj^+*IZv>>gCzOO%gkscNf2KT2jCf2^*b_20 zZ4UUAx9L)_n&%gy9WTQw@CUG0eqS*z2((-k8SQkVmC*7&i#K4eDbdR0;;=LO@XcsB zt>ZhB_+@Z343GNem023zbL%^Tl8X_{*>-!zUA{EoiE24`?Ec0NVe(RH67MJQxNP|5v`N+8Rf@ivtZ%E=P#8uAt5Wg1bzWZ-5DM#!6>~uEYi(j~HcVwi+Z8`O zxAB`glSBG2syZG@{lg;rS8r6_grcsjzT}i+zDF|h@Lx5bbpsFx}k;-}Bqpu}*Tx_=WB4@3A3xQ%8k3^c6L5Kv7v+=dHFF#fycq56{Bzy?g z`mcx&tAHKt?a3LpSeJ58F{FHZ;o7CcZK?N_RIf);C!}@Fd7nc^Q%yY0XhF*ova50R%j*|7vzVH07&I~V zV2kU88!aioBHOwI)X9b93;B(OluwB~Rqoip?WDu}LOHt2==2$9Q{__ME$mxfT=V#V1e4bvE__vTstkPB%!k$H`G@ z@yBFMALX|&rBzbuu^F3Q+Z{2FciG7^OSVunXoV;x5%&&viL4VZ2t1v=kQ7Jj4CoW( zc;cxZA9tFT5U+_b_;C^M@dXtm?(&tLeU*9hXZF;426Bq0X&S%b%Z>e`7Q)W#4TIIP zy0-!fH_I>H)VQU_Ej+(CvIu;p7OCtn#s8fIzA5VPX=%#o%=UAFB$f8(auUq56z(x0 zaUs2ih2ac6pC`%Xx`l!AnJaId?JV_Vb+28g%gk#TQU zT9GOVPYZ^G($aU{pW({U$zisYG*s;wDzLJ#vhQ5%PrJxA_&s(O{jK2oP=;UM5&cO$ zmD^tK%>&-wufeaeolDSn40x^W`;V;%FgpY}Ifo+(1n~yj$^!N$`pQPEZKwD6nsDPH z-^pV=;EiP`#h25XL7xYWuio=32|njA#Ew*!);(h7OwH%k+O4!~q9pwrH=zD~VZ$~n zTwOalyHnCuQW!v?4E=CwM=AJO-&dq(xruRu@!>}a)!0*`dEsY$uPc4U!bx6Bo+@qi zN*Fe4ie=LMc3ERUoisRx0>T29I!joW-Q(EF@dEQ?Q-_R(pu`Gyj_>7`=Gk~7q<6{h z=v{cF#aBO^VP&X0QqQw}QQsS4O=iO6iFfX!9MzmWMNp6-eg3L9C~h-rIk zc}tndA-dvqyjv^Frvp7`w!wnxH4@24ucab(^-c|-{e_zrvqs7|Plao$vr=u_DZaU; z7t*^gylw+p3&E3r>>A!90Bpp_xXu2o$LZ+P2PhVNJGgjgjAQBtla-Ykn5eu*_!+IWJZPKg~n!ANYV)s zJ^2cW-hT{}wtd_vVR3Se-Ne1@ueY&OY3h%OZxE=pw_nt{^n#x5EPct{oS=K=s0nTNr$6yxr#^k&9Ys=#~%Y zHYy!wlQq0CFfh<;Z8h#U7C<_0C>SSVmQ7^yf}cN$WLd?cmpVJEzAN2yAoYzu`A~9A zKHPG6ObX*2RvCS&p5&6gwtwPIv4-P!R}DYBVx2_Qd5eyE?Wm`dz4KpA)OU+8nO24^ zG>0@~LJqmMcD^c__WpcRg+^rjc{;1h&Oa;&Ugv26lAL}Mo0K2FIRw0*74LX*HW{c4 z-##hM@P7*t^PHK8K<-F{GrzlBbYV;lcu03(8p3()+?Kbc^j3>TaQInYtziogaCTvO z#6FPI?BPoBGad9jjs-T=*r=0zhogP)?2P7!q&IFoASdBYHb(aAXTe{^{Ye(CDfBqj zVhf??fAPXLAF?>JFllbMJ5QX37C#fxdQP79%H3YVnt8;;*#CAt<Z zJC2d76V%=t7SFZ1CEe*E;vUaD&3}GbLqWsZ9@4FFP78?iN zdq(vm<;@SM7EqZEvS(`@~cOa_mDS2fUx!Y$oW8^JbV8c zGzx$L^|$s!79#dCBOt(gv5dniPsmy=4g=!q2G~)`I9DBC=E{kGiHo=CYITUTWuxFtW5$PHR7#dv>+;wh>O%P_tc( zrxKkSgwFl6cbk<^C4_a>ZN{I#Wqb^tXk(i`Ax=j2LSOv_dRN#IY5<2l9>og_)-Dgj zg|Y2FKZ~L~mYVQLdZn;W*uT|DnY@Vx)GXiD; zY~1LlBRV(Sq#ZL<@5RFj)BuToyL+#hs=kT+oF9;5#KVCCe}NeLBD_!rbIs&$#TC0S zL2lDsHSGs4$OQDP8bU8lwF<*eU#~`e^Oa0kqY@{Cv!2ne@j6sW(skI3tQLuAUmuZBAu(8oy^Y68~Q zu1=s4Yl}4-RpA0|P^*EUc_ZmPy6Wya^?;i)X}LOuG5# zzR@Q?qpXZ7m8Eb!+I#I%(3vLL5BQiQigeC6RNQtJ>7EewQb)U_V<>wO?eAY(eGLp2 zC%Ivwev&vgdxaZix^?42z%8I%2XD}-Wc0vxCeL~LmgOPJ-jIIMSg`a(x|^gjz-Nu0 zBnb2*^#cvwW{rB)Op~Lnj(t3?R#($A7s6bSuXzfG7Bl!K^jm)RPD$8@agWFLwy_%< zusKEl0ND_SFWgy;h_Np%JCY}T_Len*OBAc{*Lv64;@473Xfn`)e->a$Ak!H4!_ zo7;$o+c6;gDxD62xcynkxK{Xx0NztaA@7AE_Qz2SckL31(LWJ7cpo9l2e66!g@7Ti z10ir^;k4r2$lbjGxt^r163P0;#GJD@XBe88gKTl_?^4H4ZEs2?;Z_ah~hITrp4!AHTU!D$|~LT*E{*a_ni2yjzlJDT5EnN68r}He$oiy1G+?x!C^Eg=v>L@ccL;%isqgdecdLEJLH=TXDv4 z!J)G8EC-=dduqeyWO{hj+S($-e8n0GeUgJ))p+p<36x{Nongw<0n;Z1#zj^k@N}Tt zB0jX)FF8Gldvtn->48%@flENgvp~eD8Lh1SCDQoWtfs$TqYDB}c$2onv5WUiTUXuD zKUz*Gt;>`=;!oAPt=p^UPpZ#WeY$nLtSYZS+=E>Jq)D(kxGl<8L1cgI20RHzB%P33?Ul;8_R+NLkME3H$7Y2m> z0rXc}YSZ|V;|j#+7pi=ej9{5H_%S{E!l-GEq-o(=B};`;#cFYGx1k4bN_k0*^}XVs zO?48%4dZ*!lOT8f+N2BkEMfVrP*GLRVrxu-=Sjm3Nu9bVZe6*pu_n`qmQKL)sKcud z=Wlex{3Egg7(xl!vyJ73eV z#;N<{Mpg4oFOfm!&r(8paUqT=rrjLXUmv30 zEJBk1ux1-4{jC%2`s6-Wxo3;&eJE%&85{NEzM9}M(%pG}LM()%y#FOW5!8T3mzvQj z6mTdy@uDS&lfG)H$7l(GLJ`|%|W&p=IVlYNVx!Zfrz46?_`8Ks=Du(dm zsCftbqTVMIqZd>hnUUkNixWWa=?2G^wYe#Tz@iP*#hvFS0w?JQK)NqE5*VPcE5#UB zSQ;6D?M9fl_2{OHDr9di`>#v;&XIR_$kNN3Lhq-Rw*d2>R*~ik&;?Yv9HkJMXoGF- zw|*-{7;QGqb~8Auh8{H#yPh6;P+7j3FM>?Az&VGTJ!5=sdEVV4WnAps`?bXzGBX8& zH@zdLG^3&GH?kvf(sWtWpd0F{B$G0Tb4O8$YN7V`qD>f!8#^<79m>(9eUwcEQqeD& z1Ak-{9P9ttVqpnpyHU*PrX!-4#^l;WquX}z2stz_w~L#Ie~sJq`gzp427Z1rCR}k! z#QZ%OQh35At(^I54=!#&Rt~m)S~}fdv#c5aR^`z2iiN5m8;`qag7R|G*)%sh6(cL3 zeTte#JeD%?n#E6ehlvR@OTdseqZ;!Sx49bPdcFn~YJ5u)_{&|^ouRLJ>OP7(r}9NY z-le7b06~{p`u?l0+MiG(^Aqvq-YPP6GM_4uRn}TR$8I9s`!f;3vmwI$Mb)6#*b}PB z)!3EpRG@`3RO;IsoOykH^miUEx|N>5oGP!QFCh7VS4M>Q!Ql)X_if0IA->S%aTR_! ziKG?mf2AM9Hn&-{l?4lTapU3ou+c5pqYnFFg>rhE-yP3|WkDYRIPf#8wZ-65AA5T( zGd|@so+qvXsgziC1DASs)deGUp>&~Qq!sB91#@vf zL*6&A;Y@??Lheq?Zy(GBz-x#zc*H(5ATc5WDgekuF#fI%h~#UqI7?mm<1<2KvwU^> zw0mu2c=&ULS#hXcdIN=LSIMH%eHaM;_9%hM16tMw3}50M9>xQXIf{EP_$?UI$sXe7 zX)9hF%m-|gDoOe@TJ`Av@lzZ=WFA#a@#QCAVsxt=U@Rs6Txa-~Rz!oeJ;g)q9Lz9Z zBRIE?0&$KiL2bPXh7rAb2*!IeQIdu9q}bQbNQ-!Iz)fU?Rre_sr5hD`49*SP&+_)) z3VwdCELu-c1iCz2h$*X^K1iKhMQ@}qdi*8cW8qx&rYk|~<2v;FYeQ(eQ)<=CWRnvQ z9m2&&(wlAb1$}kdwK-4mmp9QrhFZ&Be8f*3UCxgei0ye5GqhRCwVrnYlW00ftX)pY zNgEwywKPd=_KYPG>__ig@qkq-FrpP?P*y9DvDx!1)MgEY*AAI zzyX9FL9f~9k2>EB5c(zQA2&tkvNL}5HT$ez|BQ_Dnf++|u)sz$5n=3WYybGF)Q0eV z`^>wA788M3Sm}hPYmOP4l)=q}Zh`iOqL7AeXX{h@0;LnY*Ckbf^dmk(b1@F&lRu*= zjLSTf)vJKjcDBf37R^^*T6c4J)}W0+CPR&S3Xc=(oghHW_fx6?Rs>5i<>MXF;rwTH0yJ=)`thhf>i%Ii zbbaArnH`CgkJv}vSGivzMUB^kU1a7!Hz$Bc2vpu85`{LmXPJjE(EUS)-`lqB2!(=- z_F9Fxs|!GQ%i85VJ;sU5BS_$02PXe0`uf`heG0^Xzk#1v?tEcBEYQ1F6`jG_<*Do9 zABq%D&12HMn$k^s&)t-2pzko6yGAr>Ec(?#(^^C`A(khiJ(Ufk*)Pmzk`8RbF+KK2F`&aG{_4hPk0DB zUjjEcjl_MbB8pz#cP1kHnq2V32);4bPVw(NYB@$Z{UebSzah+p-x1_vT9|ZaOypM5 zIjeZUvvpI$h+Jx4=?gaPdjDmaV)^U4?7i5em@2w3pMj58@}k?FHowbAFlpM7iG)lM zKWna*5z7R3oZ}sjVgx-R$qLP1K6J;XzEHUQOYYz@mbJvgAwJ~#ij<^0uhqke?n!4o z*3y%2EZ>gWb89(mSclv1T|bOU`r_k-lwZJBhEdOp>iveJLF@P4vp#(8N|9p2-~0X1 zT&*jEd?9AP3sWVy#MOteS0z#6<&;Op%f;Rwqw+%EJQ{jmeeE$VX&xBli#P5`zh=n# z)Is7@LrUnNt!9^y4S-hM;yDEd#pfSw-V2y>N z@)zi!frICo)a>gtktHdN^2&tolWnqF z1n*>CCuMgxX6e>M;Y#4);mhK3;xg0NjA};5Z*itbJ<_*Y4`dGy_8fT^ z|A_##F;q1iskwE8F86~l?R^u&Z~9=)D0q9JNqo2hN>m%$0W~We2d_P@xnAuVtaY5+ z)kk?AR3($8Dy;^sCADmJA{noRSY9;gV@lJ-)8BEUC$nV?Q!$fcsXSBCpNe4Uxy`TT zP+aysoJtUQ7xLU9=n%MqB$nZ0C4vSsM2||DFawY75}DBn^P>)hUSOK1wEWc*Ow(G5 z$&eDv!>1sF7s%kqXk5S$eRf?#zC9-9XpLKSx()l~bR?giq50wk;zQB}RB+p*6L2^1 zgcs6big#RS)sFey6$2J_vh_Vo)JE7C&)gN)X_U1o09dR_v_9GJYqjkWfodU|!XZ}6 zunPJV=LSC<2Q~9jx7liJFr5!+X68HD{jXIoKYUsHxuGzT$L-7Wp?=6=Oj_Bl>Z0n( ztax{{a%FN#Xp`OoxbWswStYLC)b3Q{eMK(dsykWSVNSbBW0aWvBE54knW2{*$08&J z6K2Hi$vM^Fv6#`Fp$&%O*2pD}^o8G1#k|9tYj9AIz~RArLQ+h|V4~u~<`C0`Yg;1A z*e{#K=+dR^J|&C4r?r$r-54%7k_csd6`gS_@+B!mL}#wSFl_y=K%Ho~lm*DEIi5VS ze(L&7*ZW=tZS|APw=xdxcXZe+s=Y|8;&k-ND^2qP@t^A=VSYWZw~d}3r2XHjIR=!- zNqCrE7?5rldbjL;w*4IC8FpDJ;e|2oj@R|6LjrtB^6Ac{S_R6!cGlQjNi4C`E~fCw z2Actad|O$F*y=xD^Ez4GjBFmiI_tj{x}QR|UmyjWqz~^HP*v|uDFRX3T`1yn*U`>i zTfTj{*mu^Cb4loN)?cBcur@AmAK~e~0>ZhxfJFfS{|NGJJBk6_*SpON9EZ2-ofM$H z`G0nU{-eYN5%fUC?{y*PRNKT89Z|4{=>JGKTGsE!cKWaSGwDFvC@HY%=n5IAkhFF= z-0?2t#tP)D^W4j8>O18{r{9NUIz9f3aApP;E?-BOgNbr}IJvn=k&UXC^w;&aYL{^a zpwFbe+In&EK-K#vgKOX8IERK(1i5ULgh)w)++1vdzL>Zo>12y46*K%D3TVu#$`#(= z4fCKHg)&{%=amgBQrD_bbi3Q|!yrlmyFpg1mF#B6-?3an*}Mv|K0ltdC$L+OW6Ipq z^rbtFGR~(xCHGhJ$zy@2OjtQfZE1v&POyMtE1wS1s|9VTeqox48M7n)UF>I#)7_*j zW-R|4eUBVXwtD2`K5UY=t6DXGX|4#cr-1lImuzLh{k*x`jRb5|9w8SSWfcFMUF={+ z%^m8fwL8l0K@BI+c{y)GYSVYu`xIU}-)Bysgz*z#012h*9i3cS_bJtQ`|CLmx}~E` zQVH~Pe&w}rmiJ7RZ8#Z?c0jjtb+tk73!wiXS+1$L0^XZb@yjr+CZxt0ty6}Uvy6cK)aaqhUVEl|YNx8Yao7Ou?QCSe1 zxA8_q-c^p~ii|t!6-L$WB|6LvY2dw-o1x{z?oD5(eDPfzz(T<+Hc$A=ef}t^Go8ak z^@v!oN7sK_D>kTV@KY4LKKea{t@`(@=^pW`2ql7Tsr~*BKsBZ z#vTcWJL0FL8R?b9fBe?U5DPv2frKddo~x&Fe0lydRuik2i95AxL;hGK`rGc`)Y$hV zYuj|Sc4_W0n9Se$7gKt*JocwvsqkDhRn`9fY_BQfxj&S??c4L0WRE(NlF0>Bke-#y zMJhVNH>~{rV7}Uw$GE0mTl)=*IXJ7=`uRzQRnTnuTV{~ib0X-X-)<2a#iGu<4WXzy zdzD$^pZoXw9)l_AV*(`6!0t0u7&9YA98u;VkrGkAb}9MJru%z^-)!w3MeV+Vm1!)s z$`9WxM-)mY=z2^CLj4mFa*z$j-N%z(H zz%-#o#L$ISn|Q8V1+9yp^_rMD5M?)z!PgC8?RxQn!7ZJ+2sxPX7(P<| z)+t-X=0{~(a**!+c9RIo{Av<{G)NR zhr+dqtV!mZ0g=GPouQ1NT{-68Z&`jj3t3jjM>&%|(95yJyQdDkgkJVF8(al@|^x8)+!;$8qR#` z&dj3mse@oJtfS@o4W$DazgZ)t4&4i1I=dmcKNmf0S!3-iTG;x&u**@~YB~vGl zc08(Lqmv5sm{a877{-Ne*K@8t1}>XOWD1x7>-3p{>b1E*Pr{+7iMhUKhAp9D@2}s_ zJQ?TKjV2YwJH_R|#U+;i(8}~mfhIm6ov+@vb*E6$5fUywl=O9Uxe-x%jbqM|&i{d$ z{@pBEuWX5v{(QGa?O>KkXaLLuFph9qOF|Cn=IJ(Lmgu(wiUM}DiP`tIB#^f)CnTpN zY%{@G1|?5#j23E@Ut_f}Pjo3$zt2k3e!-H6)lgZ-zsu}u5kfNcz9bvh+-lN9*n#xm z<%PU(mmSBK_d(+yzt>{f!0zPRs?p=))sh&R3035FY#XV5kZe;UE^Fh;8k) z!;~nzg;#Mxpv{vjxaUjCJcpEh@j|t4fl(x5v0yryx)==)O-M$j_d}6GbwI8cf1%^f zpL8Gw9~b_#t$%ppS@K`7-L$X9*H>(qzJnuJ%p)U0Gysw-{T7tbaz4jp_ch{hy}kNv z5|(j}TO3k?4neEX!b(;xY4}3Si8HoV}D71}4 z!6PiR@`t^V^%(tUFjRN#|6%PN+anFMZr#{6JGRm3*zVXiJGSklV_O~Dwyh2;X2)g) zr`CG++1L4SzU}=Ns-CB6%sIxmXKVlGr`|7yZ<>Yeg%ZAU(AT|uZ)qNqv7V^#?2RHr zqtI@@mdV|}938PrGsm^4_Rwpf$hcw5#=+-pB-#m8BorMy0A7PiY$Xq%ibeC z{bt+B^1PybBdJ>5wcmiu|%a!;b7Hq9!{51vcg^%z~xaqJu#kX_2KSjzRR3P z8tLiixAM>gSO4Ttrsh2+`D12mTtOBZlKRRN(2q|Z%>`-AJf6^c3C|J+S7*>Mcx052 z9Vmu(s&BccC!tq7x!8H(Jeq*Tj7ikJoSBg#RP@_nlAf13IqaT4=bSr?M*NPt=39NlO#PNuZ{TR8H>;YqGi>sR-yR6m*x z!DdEzBO(i_A}x92PEMxkv%a@XU%|E?^XKWZra?!a=d@vAB z^C!F10K?EUP>QH7U#Q))>Sd>&tM4kEibePYluWrEgWqKS&o<8V6tCr0^jyMu)~RtM zTi|B*W5-y-O0Ca0B-mb{Gvcqqe1EB8CVrA+sryo?JTW~ZcseU;ku#t_H?zt7pZ)#igI#e=BgY;)3WodcoI-Zw6T%Z z+;V&+)yQ6O=5)<}CPM|h-P^FGJ85M4Rqew$OQhc!dCNG-c+MUxaicSwFv5!I_hrS| zaZAyt!^Pd(X0?Ttf++q-zj}##hV6FaBFQ2rUAA6t+pzS0qUb15!@KWkkQq$)1!RTX zEKw%>(Gq|1JiW2{$s${??XtQdBWHOhb%;Sv6r|co48;$xy2>m}h)N{wJa+Cs*sj19 z*XGyQ$ z8z4*Fh6%}RPy45aa{rkrq}~ zu^`;;h&b@b7W#4#JhOv=<6n}oiCUav9dK9+e@n0Z_9U3)UROXL{AT-YtExX`1|{@H zhcguNV9cY!uN);jPqNY>_6GABmsN$8llR^y5bS=1@TZBbGU84m+(tq;TV)@`cLA?VQvXN zAZG&tBqje7e0a{c<8%D|Rav)lolZ5zu>Os^^&05m2LXh6x*fCDzAN+pQZRhHJpg_N zwAHwzT!11^Q~l>~7a%DLgq$mUOagv*QjOh=Rc$@P+b(sI00Vx*?6YY76hs>1q`f5g z*o8#(ZTB5%B&<}gQpxb5=A*>{IRBFMmKMEtZZ#WFu>nIGoB6Q=A^ry56q9!d(kGzdL5=n8!DxH;kRE_$9SUyMW& znZC;0*&+9=LD0lN&hZV;lf56?yaf+TY8gJBoV&ngj@e50F;I8TT_?D)51XsnicBI} z0=_y?In{75Y~PmV3w$Xp`Of%T#*0(+i3x$~G5>F*QeFJbYNh7X1(E<;0JyHLRvB-W zWPmL~EMa+{yM_oxn14zBTY&ZP_|g4cW(OI5z-Y$HQ}B9=;{f?AIs%mZPu;#>R9PF& zfO@ZNeg6?s8>xjlmeDvjY4F7hG;=ssv=B3AEHE%gK)pNDs;>AS0v>TIp+ytuxDMZ2 zlV(~lrte;?oaqc$;{LI|^5Q{s?DFq?0z5NZNlMx!7V5YtIoauUGO+GvQ!NKlsB0N> zf-QfFY4rZNXw2eA8+~uqog?|J-Fn4@NiEmzh6<8Rl9$S>`W}}Y*z{`Sl3I!02L)<> zWa_W{^E_Yd{0ym9KibL;WHGQV8N7azEU|pg18o%UPT)2@T0#25Uw^9KEnst}rJ~1- zBw#yf6>n|z`S#$A&DUplaW3YXkXvEmvA@?pzYnDkiHHxhC$H{HO9H-o1_Av5>!T?A z@j}$~OgCCPS9KylB1m}t8zDDhYg9e@2uGcpH$sPPp4WIG$;WdS|6%iV10Bx^D%|yf zA=r?xoVW8j%-8y4+u7>%wPZxQr4{+L^mM$a;HS&B9r8?#Mv^|@LO3!>Tp!u&WWVF_ zO!m>V7Wwvwae79~OTyeC7WW{Fbr1XZ5eAowPh!4)1Ky})-i^|k9Lwag*?K7U5f)<4 zkncS&CWvwC!NXpgXCbm({>$vZ%Yz>mSY8kUFnTs_gg=^~(Mm(~@~6dS>%hr0T+t@L zSDJi$$`WZst2APNac{1wEI9OiuP}@`uLWy2M*Q=^m?6QO^q>=2!g#%icUKX$fRy}G zH^HF-e6Yn~t8rPQTIZVRABdH=R`4zJh;^ER^3K?^5z7~=GM_mhBC;6ikM}OcqnbM1yh#|DPh(bgN_yFPHTjBjM9ob^(kgX(j#WWO{6)pA`yvhE4GJ zS2>=(+47Xe;2({NG}|qEDfUIUAW_v_f9N(9<_3tuY3%VT>DHmikw6*ld*aNaN$PYV zk?P7opOMOl6*68pk>D4Y;znsz2B>nCR1GuoBvff^9PAIQXs+;sDQfwT8E=XakG_KV zWtx2RoxC1*0I}G-w6iA)oBL_tRP4TCD^#r0X;KM_%{dZvx8YYtAP%lwx}Iy$(e4xv zsP)DZ;H*yD7v?M3?`#iXz-wfxE;J8hT})Z6 zd6`fzQuB-4LJi1Y{Etw_1qt;?P5BXJ2*b*LkkhgePP6XzpO_@8a{S_pX0m zuk+Cvj>nGMsz=3X8NqN$99_A3mHW6`Xuk>vpC@D-G`7e_vt0<4((%J+w*6>Mifx}< z23*5p1d%O;fzJ%+aJhxs`QOHfZ~mc0;$@5vR!-s=w3Qhl^+)$XF2wUH&QveSGLr6o z%Olc1XX}SxHMOwuWDH41QAq^N_#(65C8B4@NiB#Ss7@&h^v{guDNRjn0DSSlC8u{JXw)wZBjapMVe&}PUQAxfg2!CAVUub8Y zYEt~ZXDL1Rds6O5o^R~%MjGmM!ylm=w+D2j;>WuDW1Q8hv%GGXwx$7D_B)K5zg==P z#L7(Nox<`ADZf1u@f{QEp@H$y{XWvyEY94|Y#RI-dW$a8}bpyF}0dhT++k&ATjx#=d3e@deGN$vCDX3sS+3h0SOgDBG*t&J_`wGydL#) z$c?1$y07iB<5+*!hC?^D^6h|LC#%tIqtLN+7|+pe%DenqaWwz?p*x4~y7y##?3<6R z8Ra$7bf_Zx3(K&PUqsMO(aws;zf-6(SD`PvH@lrx2OE6umGxH0v6s5Hw-0}9=kBD- zAX8v(z$#6>gAqwUP8wCf+4J>-I*Cy4^_K^LS8C!D)DS@Gj_dFJ)cW6BH%(`xfbI>y z{C=()V8efX&EzzdbZqrT>yJ`uO_X+9G0)S;g7<>m!C%W&yrTZ^xx)>Ps^GLr2tdI*?N&#jWLJGr3HUk(>pgE~GN-9tlD{OTmnLXE0dN z&2xB7i~Djyn+>gI&Z(8=$R}i})Y?E*Y^~(uT)UkordHD#f@#zU#NGb$2 zCw<-VyJHFo*;<)qr3{J}dWSCC^qcl}sC}p2fJ690$`HAAxO*?^X_e58u!(Z=vv^v|EN3(=e!%56hw`&fwmW{Ic23 z_$ks4JQ=6->NUSJD;jDH8W1vGm*Vhc5y=ctI1=#u+ui=n!#C+M6AUuPNT`s^m+@t2 zl(CT=ZOlvMIfG-J%b5Av48t)XnzrAaiM;&UXCmuu{@^ukY%zKl@Ojp<%enkuA+}oY z)?}Azu?B1(&*s=yjR009p@XWpkQ;Q}&&F9Jn6xs|rl5 zl%JeKpM5{mQP*S43XJ>CFz<;oD|If{_6*kWethoqVk5bRD)bq+V~Khq14*5qqJ&qQ z7qyvjmwCftiZ~e#76YP0WLyV(ex1zbiiMI0b`yNxyx(ber${vDyZ<(#>n=;Mepv{n zPA%yR+yZ?Of-g)N%5Q<-n*2|1Hg&!T9IuG!h(&vFp+4ZVA1NN(Bhr~bh6C_41{~b0b5AaahyIuiS ze{uf%jg>Bo_Y0aq3|h!fV7%q9!jpDz}(-cdVZB&bi4VU1L5DD^xZn=AI2Mdxh9!vbW^8lwRBjdnhw{f z#HQK$sJt$jBlJpT1un^7(2Lf5D242s zr8e2J?MLkam*1YfWw6Sno9r8b^zW4d89TJ7C0oGLHE^1)Yb;5~bC zjoU%zN~M7pg3vOU5&C!<2R`eGlJ9q{Vo_kFaudS61~d$oH6kucyxbcbG< zau-ve?X;!1vV6oI^;$8iki}4hkV9YG*S6pnmhhN)lkIa}SjuRPkpQi93F~1G_fB2c zCxM)4+ulFH-}t{One^I|&gDdB)TPzw*uVIjG9a0pC~kNStX_I~=a_*3OnI{a)6R<9+YW>yi}&J`R^q zH=V}x56a`8a5?ta_q0tezFyp|f#)ZEUONSLkH~tz@>@StfPMixIPJu1$78p4{Q{YE$ox`&!l!2m=;f|sm6=?Q_06B?NV~7_A&#x{( zr*|ITuIrO$;AQ`Zf4)$iQ2h0MzU^RA1p^+*$bwIvck#mht7^bz?_GM_Q4s<{y#1Si z=lWcomX)4-Ovj_T@av%MqYhO{YNPzQ=Ee;}XV^3sxq4Cw!a57nt5jFGUsksM+Cs^$x6)}5a5w6jjwQ^pGvXOl3P7j-oc zE{zu}o)+gzc7Ut)Lln~;mlFzs>We-}w>Aei^Sz52BddNG0`1ckBF++v6E+)(dfs+jv%R0;ltOygT?aPF2g+?&tW$4pm8fK07RF z%lKxmymkc%9oNmR+~qGyyRJmXxs5-(ABJf(wvN^g%}Ux;`WEj{t^ks2mkKrpENiU} zaBbfNYMtg^`sCm7XDFry`rs4{(aqZbxJ7KTP_t}T!40-HrOeD;MhsjKL7~ig+%!6F zwzZYcWbwq>d;abE{Nu`eEo_!B_&_>vguR+h^G9x||3g@%%RnxNbi{6@U*F zjF_Ur)F2gsr=)&xksHM%useVLua9Z?_y|fE9==ckAjh8kzG@YXcKQWBxtV@`{=MEg ztrGkn7t<{+=>wEq$M+--^80A;57^~tHgN7EsXN5`^lSkN2HEL6oASZzdwiBLeRZ?3 zh5y<9sQb5ZGAQzjcs%pU-c5R%7QK9io5S5MWVVqZMW*AGmV$4NsBzh})DtfGW>Xr#J1sn}BjW5ou+1SNZT zM`H~d?daS9onenGGzNM0hO5z8zTYt&tl;>jE<|KliQ^N!6eTPZ0}4DB%l9b-;XkWN z9)9aEoK(m11F*q`b!ruj%l3NM6~L65v57i3O19wf^8L-E{pX*@=y(tMQR+u&f!>2^gl~6U8f799KBpxo7vtOCUwY28d`Ill zydE-oZZ_me;ij9?4g4kue%RZ@3qG~?ybL;4E3WJH;r+SN(TTbWL*8Z>6wjHX)EtC! z!Hv~s!oNS1@ud!K+d&k|l-JsKd_R@l@)+#|yjTwodm9FP zUzt6hr~KFJ`^2pzHHF^#PR&Db5GA>JY zYiVY-jv^`_)9(@N&y%vjcijma0Fl{e#pv4;H_y=UQ~5Q4;~$m^QDt~WbTsP()FPCf z#SK%4{`jfSbx(|%_ojZOpq|Xct+&an}?LqdCFH zVB)d_)wZjxi{7ql=SQxhNwvTm?2SC8bGxN8iP~C8YhNCLH@$yEmr@JgP%ebbd}M-C z=ERfCy{1W*WipUNR5w~|NF<7WwVTM(uuWV-!m(kM^%%(vlC9m%(W;bt%qh6z*;d8x z5K4$18DOAH8L?=pP<+B%99g!XG+IHYKlb&<6?gawT%jH#2IC^7VGnCi*AYefhK$M+ zB?H8hihQ~5bcaVr?+=aY_yxj-?l^M~bjjKWj}S(!ui(qxA;}9&{+1*Tjts{X9yC$K zb=V1@E(ffB&?jPm$@LJ*RxCvDVIIJKx ze%<^0%>#51*ngE?v)1Gp6@NbtG`$vP&{JH5cu47t#SveO?1^0l!Cp7H6VEnT=J~82 z&t^NIZhGJzGve`GNA%-7%AOmTOD^kKH)cTCN3SMW7QAQq9&15NTHJ-Y-x4L0J)~m@ z8uXe#`yAfVpn){!6LI5^59-}41^=yHw9V*!&H};6JG_*UmFTpL^u>BrcJ69}z=o}< zZ(ydRS}0;1cef*TRGu-H_24y(mX(s6o~U%#@4wD{@oL#Tq_FG0D*b7O{X3;S@%mG#+4$qE!2hFb<9<%iG&kuuMd-bqNxx?dv|>d6Wy?=P9Kk+3rIll7Tv#m-`#=v2XtDZ%vGYahu=g2<{8kqSwB- z85tAK-fwKJ{n#Jdq8i?YK4+(8mx9yyC9K&X(|nT=9h~XVRJpaQ+MwZ(EL0WoW8NTX z-~GZ#CMdRicopV%l^86F4#Lyj+J5B_9J^{RsNI`wKldyvj?9QS<%@q0bZ5z~7vp$dt&X3foXGRG_^39#Jd}SK zB05?IHC2k;1%MdV-lVVOlWxjT>R~!Z`ujO&;g-f5Rq1%fmxMnWt?xC~mRNcfAMk!d z7uEP+LsqKxB`%Y}8Sxc@fWY=6ZD?_&(kM~IfpS5AezBo^rl!Gcc?cqhUH{VORJ9u4 zI9cP|DinW_CH=)H@q223bGek4Hdx$Pi8CD{oH|biqq|t% zLm2N~w)XoRbI%RNxv-y$I!(32Up4v9StA2JFqNC4R47{EVM0ft*dWC92Ai16gO0yd zOKSvNwWfVvpM=+gCo2$`i>cx}OgS-qp}ddSlj_v4rQ^L{{zUhw#*|_@)_n@u z7GimxlW+QtiCg!(2V7B&{l!v!C(~7XRt5IV8Cd#F5D1hRR{G;mZ`KA_<|Wz_QpK)z zob&;7LXgc6zW6qp)gs0EVJz@W7$j;M%(LzpQdjuL;K=eWi9rPzQAP`J12We&q;3d^ zL$-r+s+Yy6qef3L6r4Tue)r`(0c#T22>vuVhYG1D>I3zQ-9jxkt8mfC$jE1FRr$#6 zyGf-TUL8}C-Jh~IE6C?*h8|11fVYP}$0klp{m$OKq#ci4j~XAk4&s-Z^v!1vK+xrX zF#`ctNgsYBeGeba51_`NZ+6-*mX5l^*6Wk8XW*AT(DpwfszUIyj7unO0|Hd}+bR1G zi{knj5M-KPBMt}@C6GqZeUx8_~vCb9vd(8`PTuvTx_97R9z0w(so{6 ztUe~668OT~W!wK5yDIGV#9e z?4+-Sw=bS)4lgzDYWsh2~8G&P1Z)RNH>i@U7KdIA^zie9w(4UeV*Lkwk&fAT3H?v zjr2lCG2~|0zY+)!CX;5$9u2NF9yJWLId)J2j69VoKcdzU)ia(mUPB8+)~KL=-e5@=l!|2N z?K!Tna|fK-S7c@^Wc)-|kieibl%kd@o#M$_ma)Lgbjm>{*{82jq|VD>Y`JCLeO}-z zB(4Y}S{ieklloyiKI!@dOHVJp=qQf^=G~ zL};%Ne5}TsxXyChF6Ccw$00i(?xu{9er(u6;P&pkBCpDWK`S^tuZ>W49IG5A9S*$o zzWO4~rJ9&r3B1DWi7MS~rgNe+le}hQF%#1#(>#+h$<|ZF4os_vuYZ2{=-K&<`LGRz zJ7Q#Z9+DL82WH3k9*chpKtowEiw#^llda`Y2+&Mj1vtWCv+1tm)k+BVe6P~fg#b&# zO=cKL?yu+_Dnz(x_N>c-HuCM`QSbumM1+=`{z}Y^VTAe-vdxH*A z^iVI(pDRE$7kqAaqb?y0;3GqaB4ETP`fIt>fe*0e{~Oe{27nCj%TI#l>wr+0BE--8 zV;OB)IJ=GN+v^`&zDwEp{%;cpEx$CTrs$^;tK>r$77mQ1Lpd&Ul@F9o?k`gdJpk$_ z&uuultDW`JOn~_HaQ(7NwX{e@=D2mDY4t>5txfwQI5)ix&!`g83B$k#&m>-418w6-G*+3R-!b8$+>3=7*q7tlgUX{HrzTPj0IytHpNWPBaKacdT}8 z&}c>x#lBK>P?RgF3|5SYd0^BnDhJ9<(iI!FY?~ix@~qKLbE#LVyIHgl)^&_Z$k>H| z*Y4D>pit+Mdr)apMzC(0+~@x^8rCb}NlVtI7B7T~z-;(KDW+fW&)GhYX!Z&&uXL!xqe&jP)=rbdF6jS2w_KCR4mYD16 zs}<3XuwdfLaHy~HE7FqE{vL)swiG&X85 zX!O^?Ia44YILu(M4^pWkS`ewxEF5}2VD`puUsmaL=$CN}sTsKi1eUPB2)>q3nX?q! z)b3;~QiPaNgb|_HL!lEx;gjP>L-8mBa5G<9;FSAdEUIo%z*bE~)bSXWlLC(w6%-J+ zJI}#Nn}3P&{BydW3Gv9|cjM1spYMw$;yJsT&E+Ew>W}PoybX>C0mtFMynXHSCl`Hd zUEWRiKiRQ^ZT$kRbsIij{#TFd)rK3;x>MEwF$V1FJv$hC{`j&7#G|+We{;r;NT9!^ z>#-%!=6CE3L}7Ax2K4rsl1e{$w{6W`&$HJvIfC+k_#kS*$1CF92S}{(rtdI&bzgtg zZBVV>Aa*=$h$uc>?^r@;cN#M3akhz=yoLschQ1h?oQ0?EpyIF7Zr8)S!b z?H^gze9j`TIFDJtt*`;QX_i+U_$DK)%+yw4qlrl12}BMwm`DeYZ0C_f;4u}#=d+l| zR0WW=&`gwHq=#zkVpdwM_Qj2ci3%q=0OdM z)$$rK_o5wfkJ}FLlYvl47n|{Ru#ApVI7OLO$@n!8DhGMFd`tpISS^x8H&Pj~nf1f$ zO_u8;em^!wdVIhL@GO=I+8TA3bhI%n+8{&SYo)WyVJDinMNtM|NqQrii4)kvYCLtp0niA|c!0x3qe1G=vkiz(`_Dw`=`=WFAJ=!_ATKFt zaPj4ao>3Z=mk%nrU5A;uMFgMxDW^kM&HOq6n4^U}%^7A>d7Za8s>NqI_W?+4Qqoe@TxMBWe+_=y&zo&bIm z6et~x!Wc{s|E0)&RIr85fLoJ{gp}tYct0U<=lwI8Zpg2O3f>VO<)42BwYtB@b~le% z=(QQrz$Ba!My$f~q#^ULhW1`P;>p;q2wyluxC#_bdLF~I$L(nc46H*iOd?G%>afh% zlik30G=zqEatH;T1bdlWfUKE*gB9KHq<*9;nFMCC3}}uF%tA!kiDVh~0}Ry>o(##Y zwpuZNlv!P{UJ6xhPl#(4$yRX2!6Y43KWDbSLyJYazE>`g#^RwBXLny!o$#ujqE0L z=$+MRw(`C`Jv@l$dq0aQa5kUv1C+XDlf6VMP=G*-ITl4W=F!oaqdR`*XP~uiFKD3! zxw@>_*Jq>Z;}jq8z@r-=RQn(3f)l7s`Jt0{N#OSt;O5__I0n3bY3(-$jX1SwL1Qn1 zRL?*sh-V;|kmN2~kX>&+s9hg)9v76t{}Ry8^{gJsOWfuC@1`sp3RXzB-hb=3s{VU` z>*081Xm=5ZgqM#?$l3CUf?*FciBaVi_lxz1E>PUp)_KVHdnFWv}i+weI` z*Rh_am{~Z)@OV%}21@Lv%S^|G%0ZP;1<`4$4*K6*(q1%KdS^KdnaclK;Wq4b7o?-_ z(@nim*Y~?TF2w0knmUmQI?5}00BvMZlR0XWILzyze>=ait5|J$yS6YNW~fyF*63HQ zjat~k%*6iSCS7VYsoH4 zi%i6KqU=8^MbnZ2+`Y z5wGncOP@BTk#L@$efdll*HRj@p){+w^(@O*G$(x?;cDTm0^DviQ4SJ8;{AssF|&sR zRGwdF9w(k~4FNJ6WDDr3eY(nqM>^tg0tdgI1#L#OTm{+QZ*^e{0hbD(D!$PN^Z?NY zTCZ**&69jCUI!Lp}Q%ly5auI*k>UIL)lY)F(fU)e%v`}R8%#YcWx?Yd3&o&6rAM|h-j z@}RHlBMxA9bcQXS^*x0LOU$^i#eO>_Fxqsr#;|KY+%G{56CY}{K#Qkp@qSFC%ty8r=L8w+Tw{)9c4#jU%B~~XblNT}t!4*JFHq!GrEN{q*KS-_# z&TBxk70v5>DaSzZ4o<1SyGTek4M_WW@w}!Uo{r#2+Se={JVffO2D=!Upcdf;n zGY!{6A3{9otwb(FzG4QfstRbw*c{Q-Td;?6%XKKTLOHnuu@y0)%XIG8M=m#dCk#Y& zSTuW!dY-Rno(6!|9Xj8P_e`?T3?x(2C`_h@Bz~Rn8o9sG4Qpj(a>{?}d>rzsQ(BKQ zyZJF%#`-k$Z1>vuYUFh3isVfQ-7x4B9fLlVO3{=RZSMqOsk7LQFCJ1uP9p7J{2N|J=tIu;&iOz!LXYASG zd^C&2fhkh)E(YO|>~)p@h5nzA)U;@)jtt~`j%%IyZf751%d1--lI{Ju|0xwxUyaM_ z{mVhi1F!|;XY8B+KG^GXo$jqyxnF%fUYzcS@;vVnrHYFvo)mJptzE;0@1S2v*CixR zw2(-o9HmoY-)&2wkLVD41fcUbbi=4=s*jIb(wxbc((JjdbmPZ!z;a+K{nKmp6PvGw z8eqj7`VWBdKWi!UsIo(ga}1#+7}0(TE~51@-(Uod4W0-3x6X zkUS_GEjx65xWk$M%;sp&%Z)_nQZ(((@ zgVpCce}J#jBH%zgc{>Ko-G2QR23i|=?0DfO9U5o1SP?%mqBwiMlbdM0n@^=^RB|q8 z#nOek;gL7a4P;7B#s`y%m{U3O(y3}`1=Hd>C0idM3BpjRBOJBTiy+bedA#75TemOJ z+x7*TR|%UbW;);YR}Sms_in*ukDj=i)P-r*TGr_N2=g=t<51n8{_I>V-Ce7N2Txzp z$J1Wb_vzX4dEO#QmaV}NCSm&l;w3J7gAQQdmYK?QhYln$W*}1}vdD-)Phz4sqzvo( z&iunAFM9FTJN~g+=V+IxDY81QsFX&O$-%uo!jDQ}hqzA(DNmW~)b;caJjE9_o7cQi z;OzyH8D4#)oIBSP%R7%fhK^C=1bZZnLvPqXt{h^oLl)|BBS?kHokT4vy%h*R+cx+Qh?jmjRw-!9GtAr7+wRP~7o*M502@3&WgyiXZoz zUCy?|N|r~7Zd+b$%5@_ZBJpu1-k+t=cIqFnXnxkRw4yI(+>qyTbRYti?mE}|5pM2N zvaIKwfX9~gb?+_tD`TA&=&5Dvv3Erh>yIUfsaxr3GNHuKyPGGOw-jB*6a- zslxZf2L-H5K}-m?|39N|FrvRo>HVJX9e%kIlsFOU>Xa}7ndU6x&-VbGGd+J@AY?pf zEXj2bV17g-mZ>|L!lbHJ zVe(P11*7AgkD#2QY?zQ&(0S_~g&XaKN?`SgdcLJPb;PnLR z*y+p}4#p{wHHZ(AID+4(>T(MM@St!6z&#O*vhWzl5`SN?N1-5yEe6n0DoX&ybEpSN zsRt!k%b*~QLNrsfsgYDM9En~DV{KNcf0eTx*ZLkG0ol0MRi8* z&99PJL-#k3k_(^hQT+-mh?B#kA_+WPI6$L+#@N_Bk3q+7Ms$7hFGJ-93` zPFUj+(j?I$NCP+>7ER2sFjHi|b*M%QGlUubL+eF<%?oC8u&3bvc&LC+IoyID`n?xV ziui7Re#>NTNmidw)o6ZB_G~Z~4mqY$XmZ101{@n54jmbm?0K1KGwgYP0$iKzI8W`; zk4Lu_(^x+7098_=ZhazwQP z?2eQ6wg7N3N-YYRpZkBTZF{~O$1v(HPl{r3xUkz|u5TrxJE38K5jcg@`#vbo``2}w zBqW--8vgd>HktodqZn&Gn(A;wXqm7eku`x{JSVcuMJDTpm9HrBFSSPAN?jDTS&27+ z2Fq*;#u~!!p^>55-X&0YBl=GVEPZQ#Um2=lO4H)DI?)w2HhN!<`7)L*EQ1jTy_lP% zPu^6X)ZQ7gY9M91foUh7ASnV3L>6do;FBhyz)m zlWa%03Ky;vn z@49<=5>22a{g3SOhWn4OhP%uiVxxFJ9(Sba>i^lmLw5TjJlt{%9+)nx! z`hQ5AA-8S5&Mzqn@TJwC_BnQt>IIGdh0VMFB9@QAqW*w-n^xrq?`hTIYPHC7Zv9zw`X%usOL8aZ`lNTcdRzE0BCR|K! zV2{|9v~;!OL#wX+R@^fNCguW*uaz4CSN(bw*V^Bs^BU6g&@IQ2SN9QhNV~5mw=^v> zoPB&-29KOZrU(TU@-}{SVR1MS&!v88mE7B{{s^JRhh*s$yU3L2W>rey2()pduuaG7 z@%b%}TBBvYUr@D;%;(6g)p|vTi&RcKrryO(<`J>H?cS|NNsf~~rjX(&1g2zRrL+&eRhmXk z7NBNTAM%gCm+kh{<(NZXn@j$F68Wnav>@B>gHzHm<0j?VSarJ)<8Q>Wk`n`65P~>id{+Mvpk&V1+gVjof7#kLa zHHN%%A}exvTtmNBYAi!)yC-pW`_nlDlFk{QCia>N>$Z7L@w+{{W4fhS*?L*an53T_ zJ&{-=Y4V8db9vpV(yau4e_x!$EP0+Njt9gFkGayE3kCb+v!3Ff2rcmus|gPi9Z0V! z+b2wNYgYa4OX#k=pSw17n>S-nuf7QS;j@Sl|MO~#ag`8_nm7EcG~?|K(+D;EH%@=nLpX9F z!#cz66QN#{1##-+sOF^)u(7TX{+2X%o?7 zqc;TB_Oxh3x*I^MN11AzMjn9o1=a#!`yO@>AycY%F^5TQvc$rSr(Wf4XZfWF?rwk- z8WHap+Yx0nnX~uW;J> zE^=S{02$QRo(JLs`4)A{dcqDW}f}+;qZBQW)$) zI`d&M4_lnvPDf5-poEc?p{7SsafvP zNRvTaqTc;f;H{A~?#Tr{HT^#T5kc<09Fi1I@xh9n<>N{LK)Bl$&fab* zIUz)>mA8sjD-x-5(3D?s3Upyb{X9ABS*r!H8%xIYidBoPTc=LWyt9U)SYZ$?N%_jT zNrwpz8hAM&q757l*skpxZOX(SDF}719X)c$VR#)sc$E7E1-VTt!mkM#-Mb6ulWeP6 zt&UxP^B{l}*Vr%Pz9qM&Jf83m_~)kszCpD0+jJE;l~?6f)-?qu2&`@1xct#m!5-yE`-wi{kPva zX3~awGqou{d+^9H&=6vPPT51L0hn8rO7=2ZNdKlCfvcYjHrHOee9$$3f3~84)sOb} zE3e}-iiJW(SpWW)qNM~=b#s>WzH*Rt>~J%4ae&;FLpJuy@iyu`p(w|JAbd3yEqB@A zJ8s0ck%+bm{5zUJu_&s0MS#!+L-5ga(Ow7^;6FJ^Bv0kv^>0E9%!|)~42%k<2 zSh+9TfrmMY_N?MyyvPVNQK(1-R=Z}MplhzaG9)e`&K`dBk!lp;n$q+9Zo&A;wm<*u z^S50&@Y=<^WWzEcryeY`O^x|O8Z zkeU@&U3IyMIIUg1(k|+MJ|?G?m@%s0pid)qez%k8mJ)p>-K5x_47o$v5)qWtjFApu z8>x?vUN&o|UAP<*NC8Alkm2Z|d|dj#F^$n*+1j#eD@+$-j3b<-aB8pFxXv-Qw?@5* zL|tHg$)ZmrqN;s|Ha2_qJno^09Es90@(Q+m{#m5>wiHXq~v%zgCD6@Vw82D=v3a;-)+vqToND;lPl7ab94hPWGZ!1 zG9gT*z@=&m7@}&s$0A+t0U6-9B~~tP)yQZk_<>CLIIDnG9!`<3_MLm#Z@>RaiQ!q~ zlMs@6!>txipum^kd}BX>d3F!s%@vV!>*Lg)JY_29JU}pl2tMJ`Xif?sAbr8jPkLGo zzMJOOzEcN^N6oa~CgB^wL?pX@81{cuR7>Fb6@g;BaONL4yD8hN!eVvmThft(4y-YP zxebMoy0mi`l!!3Zm@N^2O+|gZJ>pe-9a+|~^LYS%_OvYfZ?ekqw+OXa+LhiJl_d^msr(jg^U^qCQy8Rx4c<_aP=ivpThE<1^fV zW_8?!ydNbzTi=7ikTrHV!jJoLzPQp6INQs+K#^IqrvY$D`RTaWpxU+T20i@1BQht} zr&i8_9-UhSA31({&8X3z-gdzS{nqi$hw=>w;l?RY<)mO7W;*7$+P`}6%f?fzWq8#tan_H1o`?vteSr#q2PoX|mh z1BG?!HXgNc?TT*o8`OkAWA@0)BNZgnwrpH`ckkYPp1<{`+unKY^*26=j0dTY7hGYZ zp%BjK-~?N`l5oZG_gd|$rETPEk6H}TKb4owvu-DoDF0dr?D;|4cjAnbtdwnC2O!0P z1Ns8honX5l99xc^uxM=AIQ5+^ze|^{gvIW%gA|nd@Z*o*JRHi0&54n8@nFctz(?*P zf@pV+aLofxF*`fYDo|jn4U+2~zyh~X;SW^%h!`?k7 z0Ej$>S*wwC>DL?h_zfT-S91|cDP+_uB2C4sBEzWGi1R#_NS(G|P@Mv5W7ONP5&720 zKKk@yigInSk3Rm`)^A*Imt1^-U3}q1)`olf@rUnlT!&I`rLCo(IE7}IVWU16ZBr)C zunRA~#IC*RX8Ys!KY+{sz-|JH1k=2K##KSng}T(^8cD86m#}1W(W@%G?fx zXr|yBTEAhHWBM)IwS%E`w&{~+lC2Gs#fk2yB+o3@dE$}QA;zU5qa7ILn2qlNe}B?? z_UdKNJ^zS(@#R>1^Nm-CWQunkhhqmMqd z-aUKU&p-cQpO5{*?!NU_f&pTja3Ek#;jig><<}76TH9H6=kN<2-QdcZrQwv)vr?rkkkGod}d*iO>@ln zC{c(Z!7)LZsVPC{5yAKC^cgMhd+gEGDL38}+@N8-MX$g5>TTV-b=$$1NN&hZT^_z*5Y=*UrWEg0N82w7_ z^T!nL{m1odTgUqSeyR4rb#3eC+x*g>SKEQ>j)DAdb)st`{G|DtF0n22Q1?|(e|+Mp z(2y?Do6hjp`aJUw(rM3eFpSt$w zOTgd5Yn zxuqhwBIqOd_|mZn_VAEL?8V_jo%6dngnl;>G;(4}1Cl1fL9$xt-(m^WDgMQ#3x)Bj zOWDM-gbOFx*ss3Ctd?y@!Q8rH&>&!7j@ly+KW?`ZK{fEof!6=>>j(&V)@IF_O~u7a zt$*JHn>l-?C7s#>YY) zb?n;9Mvr{Y;y_yN)}yC&>)DsQiHRoI|CX&=*mz8TJIUmK{gqeUy;USvBbp@2R7`Kp zI(I=6=wQE3{K>|R`H*~tvUdFymm&;QB20FP6%xS|1H?-R$)S8a{9!8LS)75e zDo&Z?spJY(s!+jBQ#1XY7hmIDs9?9?OVYEOHf^$7M4Pd`;{bGmWnGwL9AM~bm1bKMzBEJjvZ{+@ZmOt0%;1^ zh({|^PD~I)IU8S?V*(=Vj8RPYVHD6RJzx1c@*&n@h+-e)@Ns{bqO?vQF$4KBWaiUc z;fSDC&S5HU>Kqa|ctJE5unsX{y@&Ew$d@JfsvN;o|ej(@Hcz7O7`Pd@y};y`p( zVXGu^hlJgx`E%hLyl_E4|2W1>o01jRu3h2Gvt7D%#};23{;6F=0+LH& zif7g>N&tG!CAJ6ai z+x~cMpRG;%{n-EOO;~<1{)?qj*MmBrcisg-L0t+@ojlnnFE=l^V&zJkHBtP54H#Sy z9u@IfV)?jdDwHW*kdl@W8WasNEQ+=4q%)WxQc(%Qh=i%=66_T9bN}P7p`{erB^UOy z^E$V-#F}ftfWrKdQD76_8DifB#abPZSZh(>svtMimd=@lG>d5j>G%uaqY{QzBl-=EFr!6 zJdbFHk|2a>8JS>bT&ny!GA${>Pi}0O0*LFPgEDF9l+rr2)Wg>Mp}Y`LN#)$+p}AZ& z@G2N|jE$r$bOMaynP*=FH1W87j?YTchr*o&&*QWk%zqg~?K$m+L0nWC0UnV=9Ui1c z%X{y<$@vS>x~ParAciz&)$5V@>;!dY+O+M6rg;hB+$ZocMUeaQtqV3-zkUPe$m>bg z&4c-pU&6f#V@>GW3b|If=U_sQ^*j_MSG{6wLc?zfRz`d|z6IvJ@7lG?_l+4dItbs& zPmezO)cp+`H9k&`2@%-T6b%V+1XABPw|?&T|HBNNV<1eLe}VK;X}wHB!Vb;lU+ogD z__gcQeay_1)Q8)&Z&PaPrp>ez7FDlOKB!lZZhMD3@_6mlD_0I0I`p}p;^Gqu!!QOb za!1%!OBbyNjduwjXddt>gRE80idHTb=`Wk2Q4o%gKUidk@g2x$fkrH%7cco@S11#GxHR2=eMV zzd6jOP|Rj|)YYh3s|-?hC=6mEHh)RE1$M)=g8(|*WX}zK&ieK3Pfe9w)}T%;Tf1rn zl0P7rl`4Y!m5Q^xIvPqXr?J(<rcSRojE`A<$9JL#O! zrHDj(QK$pld} zx2vfmqRNLNu3LZ>d1lxv)L7X}*za9nh#jPOSu1j59&>)OS+iz3bY2z8iUdtST0js? zLeHu=mx$aAfGxRTNxn2otI$h;sYrd@V`f{-iw!+)C9NuwOwU+aN?8&Ce;D^QiJRr^ z;rnm5h7B6nh7FtXX?$wU+P1el$@y8eVu_6(_YFBv5iqfM0z~kwF&|<~P-ey?TpX=H zqiS50GFCb0F#aN8aKdY=Tfdc!pYRTlDsMV-=Ujp;GBF2Ud(E{jnrzY1g|=+PVv7)% zC8K2VY=q%efskQEh)J7)JED2S;FpSXulezlsrD6cIyGxlBVsH$xJUOsR*9lv@$oSO z-+1%oK@)zN7~sJ8mospVfs~jcUM5K; z${%5&&#Rb>vK>mv*1ffA)&F7N&W(c`)vK3B{p~Oc7Uia&I9hAroY^mQ?$T}8z)LPk zUa)jonXK%*BBUZDA30P(Tnz;}oszKMjGJSx9@s^w^wrL z*xe~O-lJWTSqzw4SK&x*N}ZDZl&!t$>T9hbiCEb%ibRqjMciWWBPe0)DMDnUu&Ya} z;CpqFAtc4!oupiuCPV<)1)nIygcC#l!3`FNLsm&*)22-!Ts756b;YnH#m7pXWhNMt zso;146UrH{B)Z#f9_*Oeop(NG-&6i|$1X6sfc>aezO3DI+hCl#^{md46*h0hYO3-L zBZ0H5b?VUG5|Abvwdw9cQBzY-+HoSMew$Au6XT0es7Tk*q*VK9(p;qR+pG#;gp)8= zZ`(R zav(sb2qpdKgLhnXS0}=UTchzzpZ*77v)hT#ig6fEDpj13laB9*8YWa$j7IWJfxu@= zdx6p9ArUKwLIs^l;p31ON*U?Pm#(lG(`VrGC^ zuOSMonk|P|-*MB`Hh=znTTa4j_wK!jkXuLM;@4K0(DXOo9PPB2SBF0f)XZ_p|8@r3 z>_S%(A5bLKUz8udy(q)3$BhWS0-<4+Kh80xwQb zmt_ddoB%kO$cG<~#)Nv3`6|o1oP{HwLBx)D?-Z5|*Vd>o@k|(XW9qrIw%)yZTVtO8 zu_K2;g;;4-2?^Ic*RNaOjvd?=oXB%5%k$j0VcpH$dvqI|l6uN6zG%R^Z@l)#)0pbA zrJ2b2t~2S|7Y)$*x!>Q z=z+uvmG<(rSgkrWCznl(x?%3jg@s8+PhvRmPAL9LU?aqha zwtYy|cMiVZuDzQ&u>uOQsk>^NylHtoRvd%bl$?>raj6ptNTFyG(?k$F9f z+98`Dc!2ehoE9DmASBHz^*Zo3HuElqzh4w*BgamZ}Yrd>yp9S>5@_O!L2 zyy=qVOY9V-Xl0g=i9@(Yj&(wf^xcYBI#5NHqVVop=ATmFJRQS1{w|Je5v)>N%Qe?u zYpKa;Hu(N09nRG$qRo2rKHsjw93%U^!c|qPB_}5pv)C?bmn6C99RQRqB@HtO+CXS< zmQ|@z1Bo`wyXuPTY{8tFws660@WyVk`gsj(4+)ahswUWIFr363q-7|1 zl9)4R0;z_!F&T&tMT>odZ)MnvFA!}Sj4eIUN|QUYja-)vD^@~_Lh;31=1hdsW>HYA zLZX96QHk7>WQiAWbCUR{O`GFPNY4#@25hb|6x51wc@`1jF%ZmR2e8aGSumMPfy(dN zvkw{WKiG;Tm?qP*twFOE*1BzLOFe#!K!LS3Y07Ve`Iffrdyc?7j@T~~e<2C9p56E0 z{kCY)LYw^i?>OO0LwEB*5`a-bMHOl*(;1J{MO78x!V@zHa$&Sc{!n0PQq<*eeyh~9 zbOeWywU>rJ?ead_wr*v;hVLe z4|l;V9pl0TRs{0{n$9t_Bly)+>iOgM-?H=Z2d-Ydis;4^t3u5b72Hx`HQ~=G3Q)LZ z>Dj5=X9(|WEZSluK`d)*JGDu=b?auOK~Ii^LDwQkBZ7p?J%rCsnf$#?oj%=m?muiH zF;wXc&JPYN6>9Y>Hc=S;124Wbe8|`@zbY6waL}uxM~{99;8Lu3`S9Uj)iH5aiQ@Yx z7AUoT?pHhm=NQPp@g@XHBN34iS@jw=e7}C9M(@(Dmkac52sE+iylnY3>oxvy^^)T^ zoY%2+(EPdc2muMV3Nhu1N~e|ys#&wvyKP#x-v9FtKaI-C$uDeJr%7;=`c1(JI&9b8 z_AKG6p}Dp`t12NW|3ak=!!z=G>XK6RfGzr;@4Np6sMonPL_#nCHSSf1h-K$f~h?h;c~l zn9DHnh)B7pEQpfq*3caY4>dnx2K+e z2ERfW;j`69nmY)={m^Qn1=Oll&+1W9wicPla?W2i@Cs_UA0T|ShPCR{($=h9?HEcv zgfS7RH;;3duUXBiP~$yf<65grIBpUJvo7r0(|W%;42SGKZ0AW3C>SKykP9O!{^|O) z26Rd4QRjo&2woW^%wBr&6&K=L2J==a2#OL9moHsJeGIU*V2WM4bq5mWsO=<|NBCtY zPoyA$SKuB#wo5L!(3$|9zX~5u5y!pt>Ij>*WWG_O%r3wDa)Jo@+S`~BKmBwRS=Z$( zg;3i*-OjgO5XRSELJI@P@$ttWx0>AV`|pgf-yv+DVj3z(qGr|V)!jWj`P7pzGi?0K z=NXts5k3;#N)XRpl^4aR!uaHrK0`s75TtQJ zl1Q+m>f0W`!QzLOB5B4tjC2HQ;UuS~J=_(+;IZOXmZ3GPZb zb^ZDcLrRy4edf!tA3wiv!Td9wI(2*gzWax~LrA%c)D$BLqywDb+>aSJ$3Xtg*FZ0i zy8gLD*8l7GPjwAIsGYkbzWkvxStqJCYTL5t$e}|RHz+O_6cN&6ThHGsM{N-}!?9w) zm?qFJO{R$C!Bf_uZCktPmcb72@2>mrcaGmQGUo5Q|6Y6iskZj!>#vb~IEVH)Dg(Z2 zZ;yJ5jQ7*_>{CzJ$_*QA%sZp(uEE#YUEGsUZ`06x4)2$%3IiQXQRuK)MCT|G5}N5W zvEl$bT_l+bfJq)dc0gh~iINZ4%dfsj-o^=g^ob`yLY`|CftOJMrySEiNhG~J_uTVVqh14h;q{S(`tGvNKKa1r&YBDX zC3&=JEeEE#kz-GgA5xVN?U8Sfv|&S^M?>rl^hbm<&ph_jGf4Y8?U(W6T@ZkZX2n4q zgYZc>X&qZXGwU9Ua*y)37e#%ALXE=}Ma8qhRjxcfevnR$W z^w$yrg&V^13!(z`ar8XVnp7F{szFyeCi~@=-;hLlr!8AL--bT>j00}G@BRl|1mnvu zy~;Zdqv4(X3*w%!gIvv(;y{x+wW=f3R7ImooInHhZ4LDsrMCu@PDw^GGK9J+^X+_&TCg-JwGq-t^KIF1pqD&{CO@V_veG>(Xy zAkFuHp8MR>PjT%9*8lvzn5e3%;1IU%kE#FB+HSq=UYy>WKryaw&qJ7dpamoX7n2^`BX5$81feA^`XcrB-!p`f`jU1B+F!c8*sP+&{H;D+dA2C;kb6$cCbkAs< zj1KeWonXbWJjNI5bTM;)o#>Q$M|68!n;4z`bh`yypx#9p+GLtiLZaLq3It#PwBuO& zecB(G0r5)_HvRi=6YV?dlzcP(XM5(ECu|)4x73t$r^(3Ys9HJ_D)b&oOL6Dn9nAsN zLGy7P8UC@Ddb{@MVw*OsBS2syc|X1E1O?_)V?Qo_p>dr>n!v#b@vrlnQ6l?G_7~tp8u}JI6r&AAHQbJThtFJg)N3w6sVT{|>(;Bk5LF(#Y6wv+P2XC*bnefcfwh=3e?GN2ARZaK;Hd2(!4XASnYn!K zr$H-i!FS%m7R=vGmBU|gpx3mH;3d_r7muTvh@pI7Mu^^;KW~dIC#tDI-6|H>ysdLS zrU5ge4C#hQ(L49-aP`v{tz3tsp6?=!YJsqO-SyYm20|q#V>S?h;nUIg>Y`m*1Fv!i zp{@#({QxsTBK{XK4J9-x7eF7UqXtk0`5Gz40-=%_NmK!X!3Qjvvj{VW=0pTfxd8+{ zk@K>}wg6@*qE($dm|aNkV?O)D-hAsV+fI0DQBgQc@@If)89wYO=iDc(8e*U*DVaw& z1yoArr98$?KYf&%>$OQlZ0>vjS%>%7r$e8xb&EG!27Ru7=w7=7d%sWvdj6}=Mdd#DI4cgwUBxmIjGbp8w&pL_w*?n2R;WbTpEItM1H`IjF=8l;{n z?9wrE;ZucT4%2fHvDO?a`bvaf(OC+}5OG)WGM&FPQGCl6F0k2Crx4B@Y1L{~!>l#R zAx_I@Bs6%1;wp4Ehhvy7r)eOOxO2$t=Embpx+cx12ssD1b4x=IgDZYtcvo~?JRChw zy=QudJSi54rJAIfi9J3=BP;^1Z@Q6UwkOuW+K%vhkmZmbXIloj-4Z zW5!C<-3GeDeGffgAH4TI^AgH)sbCG78Vo4aDiX=}+8Zy}610+JBI1GxI}Rt@k82I7 zS-U3n;jb$Y2eE9IYZn^Q6KL|<*!Tbg)PO$@CS_yahf5p!+5MC&~ zNA9Pa=f~n7lc4p$ZQobRz;@rS>4! zv}ygq1BVU;$K!*jQKwAyd0l(mo0yn*GBx$|q#wQ;AFLurih*z3tc|nRPhYeX=jd@F zvl`fSL}lfiBC#;!49?vc`*!s6wru52!e=X5srYyYVXhBD8Rnrl8}m8+38Ij$yZSn# zh!40?M~U)@v-&lw+QMbaF*Th=;sq2D*pMBVULK}8ov^sXJRDJyln5bERll`R#Vi${TTLqpTe((Y6tE4eb zIA*yb5L^3ULl3djGV>9crRXzN5iG{?$`*}rL?DtZa>r3%Y&&q|ZrZ%v4i%KKKKI;% zk7WS63Skn*7&p=?RI2V64+psa1Y@6?n&~7}75Hk@xEaw%E1V=PY1rK%Og~?ohyUX+ z)hK#L2*uZ4ccWc~-{aQ7x7fRHjQN&Rod6D1A>Nxs(aWzO&&=OVX8!S?JXYr4nTx8kF*O#E|pQ=yI7K z`Jr^RGHb!|zJqUb#F3%FgV@!&A7noFi`{X1=yYq%K$MRPx5aaOS zLqWaj)d{)hwwsBhd!P~#dA|;Q_R)~3lYig+(4)`aas7=q&V>d5@>tAFJPq+n-H+D! zaYx1LexKU>KHnC&4BW3{{V(ts-^cIMQv3Zlf%|=%?-O`TV4Lr!V|{zzx?>=65C!hk zLF%MGzwS@q5BA$y2DbTizbttHI##Fpl>;AP-N55sg&rfg|yv>&m@f%T4Id-OYRSyX5m z(&j{KRI{ArhsKiee!!BB^HBr9CliQjLa0pdE!SUf*I$1lRRT{#Sc9zwG5(R52DQoRib zFZ|4ze?;^|*j*5UB!A{a(!V12cz@X9$GnShhrmcx)F~5<$A!s4b#qi_g#M94DKXJ7 zheFGOaby8QBdoJHw1`+S9Og&QKw0sc_Y|}!PUp@m2e&rls8b*Phz8+(lH?817vtx> zDVB%Wsf(whyF4D6%x7U_kw?Jv{WWVyt&6zGTqOo3RA29RE6zFMwBnQ!LZrpID`S)X zPUzr*RLPU?g;BU_#&cQ=QVK)=Td9eM^oJIJWN-*rs(q z_BjoN$?%ipC)rPsmiqb0D&8vI_Ul^eMftmj5ICm#(hqI7Ft}mk#$VU1SMRGW8`cg@ z%}9HpVnp@*P1>CITD^vizmI?^G;Y=W#e;`-U-`iOx5a<`{SQT%1vxND|zxcAttuoaJU&H?(94X-@Rjde8fH=tUE$LchMZ~Ere+t`;Nd7lq}WC(tyNK8ig5S?-rD`SHC4)fV&>)5dy-sEt5`njPH?{Hv6*1PcPQXt+6 zK^g0jT{>_OMX$=)h}T|WK5_tP9Ae$N_ptZgf6rch`BjL~8A7;g*_-dYVH>w>wePs~5qC2&G6%`G(_ycEs{BBC!Y==aCL*r6qsmXV@jnHEMUxaLgI z_R=a<%u5jdG%yAszS2S%L&K{g;R*ajLTq+_9G3=D#&ZGCBzZJJ7#Q?Z|9j)gojRDIo!VJOz>oNyw40doG z%qI?Q^;cUk3@r=Iq>y`v!l|uuKsxzHx)kStLCO+_c)=XXM1>f|wMiIJ@~hqzMWxY! zC@i!H{1@RQHYT4wW^cUyyff)3e`WX!!wEP30D)kRO_=yS$MLv{7}GuEa!*2JmM~NN zgwWc!MqNX8QJ$3n(xz6!hLkyOZ~OP}vLYh78no<)Fqdg-2}2h&(DK#uf{vX$8d3~e znbG9_2k%*W?AXcR>eXtj`1r#QZawe3PMcwtqO}f6#nTflJ$(qIAHFSc8Mt55>3`}I zxX&LGxZk(=e%j~TO0EYU7r0Ny`t87V$3RMQMSoHLg#G{x5V)>w{Q}$kx?lPW_1ij^ zAHVqM;(z^qZI#^b_xX0e^zD8ezwMW5*Shata@+4Kd3?$3!14UPz_I-N{i}ZdIDakb z8wwV7v)1iiY04VS`FSfxNpmA=bzW1aPG|6A^Pz1iy%gM zr7<_9I>&Gl=B7#&tJuZ;2BOO6+Q(n~Y|ECAfOpSrb{iSa^Ja~+f#oDcmbP`9lI+Dt z@3Y?6`LDa_PI5A8IpUx?>y?N?=|~vukz#CrBCITb5O z&^k@@Q~@8EBD8Wzt`qSWo>CT3Wcvtxy$8&ygoJo7q%Z@Bn6uAeETQp;NVv!@ZZroX zC&J=14z)v{gc6%i7^;B!A~87~I}ElIS@=peynN6=`~H_di0~R`x8HmtHPo-guYq*W zb;M%#7J-rZ%Q?chdC=oPY=1`g@WSuL3;q$y?vVWHAF@M3cxTr1b0Yb(M@ zpPG_}&#<92ZPDD;t=<3#<5r~qILFNNeEE*h?hp)kM)Ftb{=`rV@^x=!$H-r~o%hk1 zf~oT(zga0xC7?%20$D79E9!TWKnq2FMPn*WJDp-t2u=kVc{bzsNw$-u)ilam3%&Ua zrJL6*oNEzWpGptx2M*^9=R1=_F*@qjgoj5^U#>9dwO3!(eYXAm_n$Tl8}@iG6*uP& z8~W01O&T}Z3o~K5f*fKnH_z3$DRs1pb+-(p6P~X4rTX}v+I(NN1@`gnzE8>hzOUc! zw*$vMTbuU#u^j{9hV{<6pWmTnU|Zm}Z`U%gUF-Vu7v%f-Z7p>!zg_Zp-~Zof_vcdI z!14UCXKO3D&tJRx`h8mJ=lA(_-^Xuj>3@Ou6xdJu1IO|G1KKoMZcen1b!EV76_R7t ztYxc_`}Xg=J-%GoIxRZ2Ejo7m6g~1VX+?+J|KNRBSFThcI4SAixF3ETUvT==$q-eA zODG#}1IX6iwsk*PRgW@KkzI6A7rX4j9x#d77SyE{j^AW^;-Q;u#Wn!`a1g6#lH~UY zdOlunFve-CJ50DnHW?vmP{JU5n*Etm~t_}<S|1}pL8@6 z#b!x!QU3@`WMU#&r_&uFmMKgc3s2NB2$`#tTqnY6bgeuE41||x9 zG5c}Uw-NQZ&~=^cobYUOqb`N z?^S^i0)-s=Eu;wZ!5X3ZT76fBqw8fQO@pC;M<1&=on&TeKUxZtarq>eQ&7AB!{N45lRFkt`!M zrC05)UGCn$d;5bIoY%e6g+E?qUURUtHrc0N{Dh-0*Is<~ zA*)v_%=+dg+tn8|vz_}=DBpXS92BHK2#&Izv$FE6U+?oBe8ye3-b{FLxDCAKI-*^G zqUYls`{^en>}A+fk3DMR#{Xm+@gIm0>4TC~&E@lNF(ZH*xGzEja33SzeUD;CNhB+lb49ME&Rzig z$j8p~Gvt8>$uZeW3E3OTs;+9~5-MPhTL?<(;IWk@yDZBZ-O@A>{Iz zJN?2H6~%w9{)Q6#xF7j~bRW`=R#=Z4ytFTS+j|M=YjTgKoE6O)tQNIsHqi8vAtFj46pQ}MMB z1elcMbi4G5K_uqYMnmfl7~(ZxxQ%qVBaSjL@38-t|Np}3GcSi%Z__ZthtLU&+ZCWyKyLgZH z@odUDUZ@Zc-8YlL9I(z~3BpGw2fzGId1$K4j^$xmWJ0VW8qFevgff_PDb$=Ub^Xq;Y*yh*$Qe&x~-}ao=Z=Y=pfBusDe7j%%-57!G zTKE0^b@*++ujF}3ZU>I%_XUpS=kH(jD|wu@bsc^je=U9t#w4P#D5zPBmOnIU+Vp$! zN}k>sz4gY{?b_d3sY=ylVlX1SE!uRvck!axYX=OvAovfmie(ee6rsWV6CLZS;T09+ z=LGfX+uNBu#(X)APbb^@^gIuLN`$p+TNkw4vcPYI+NRw}wq?gL)P3-UYE{MWk!3&r z`iG19Nd_sk2nlZC;u%(naN*&Xk8sf}#~{KYC=rBF%3PG5nU3Ti?W8<~n#$m;>s0Y0 zIqL6v;U4?;+i$E1zLp=pA7_ctz*TU~DsrV-?2tau7Li6xkZ6GW70EvWF_nm{g))m{ zz@a*IDh0pDE0`coQ%mI%n>Bx>eSiCX4i2Mnqk1;tjn~o2$`H8*WD3U+5$714YO7~J z?5?@;7VO(?LArgy-g#p@-gSb{LCDRftUpZPPVP?o^#{g21s(h0LWA9xHXchHu(NBM2~UC;|$x2tUh zV3uRYe#LVvYhQf(olS>`AN%7s7{=E&{`;@&o_p^CqikS6fL^oEinrJ(=Zm@la4%xv2`|WVjv0$M>S0Qg}^Y+cx_UY5> z`h!&Lyzcs&J{~plohN{3Ntb2<4Io~?F%(EaG5oxHuLAxlNjE(GP!}B&c)Z#I_xp7% zeP8wQKYy&>*3uv2`=8T50%zwxXx%>`Jy}95gX`6AFrr?AhHt1{e-Na6h*Ky?wCk!? zuKwzYLwlcT->P}R#;xl^Dv~&eJqR;EbavA5<9jhL)Z+sWJC0+#O7&WpLX3F$WA@Xp z8}NA~+5LCjf)Aw&(J9ldVLhtZ6T)Buw#djkqq3(vPJgA zhwoESaJd!0IAn5?jr)chZXl5{&fz6J`sgEM%%@>8iQq#f=K|?)~Z!A5Ets(FB5*Tq<#Bs^$G}WVr9Fc{}q%^ ze%F>RT}V~Mwk9Z-$&)5g_hhoo#AGSWPEly(%9TfhO?An!AH4smH2^rV2oqmiLLz{h zRc-y2^@fYk`E2w?slZjKKTU^e89CHvxzkdJ%=(CTw@Q`D=SqY{Nv9>H{W>k zo5O|;A4+jBT!qEBT$<~@Blg<&-|;)gK>j;s{ogpJ=k#=CRh|U5lt|%@789YxiMp-Y zb$nsQu_FVkSF6>aAm7nKCH;-_{d=|zTE5Rp#%N)@7?*;tU2=w4jxSj3B}x` z@B2S?lH$Rw-hanwsWJN(!Zo#9V=|Nz;LK2J-`iG?a)XdTL@^RE|Dc`GLZV zq9AyZ4)FmnZhQfov!en0Lzn=xmOjsJZjkvv2Xaf*i@ zdB`?FNM3vS1*<^Ot9Sq@9Re@TWT$^KrZfmXZ1OsyAVyWJcHO!z>Syz|ZT8SZLu?|o zKxWUHO)x=O=Z8QI)Io0kMB5d8B_gg{Qbd&aVL416iZE*3whhcL%if|E$2jcrp)l!7 zyJE`0T$ly=EQd2k5Nf!GBAXn}6f+Tq!(G=YVlH%G`2}>r0yfmS<**l!q6SdZUG18+ zZ6Us_Pd@sXfQl+ssY*qwUAq?Zt24+v16hRu1;PB3k0b3V6a2CcojZ{ekz_m2o)Qxi zfG?pp*CD5L20j9rGZW)0upMmg<7XO;xp2Um6~))K|MQ~pg~#YN|syC>;}P(W)zhrh|xOX_$M(&+Y;W23PXl#5Vf@3+6bj*63cb+{;-pK6PGpT)(YeY-h!UYQ` z?|h7!Es3^t$s)@xJY%VxGY)9~9Nv|aFsr1bBlrl{;49+U@Ny}iiAr_6|5^6t@P};v zA{6Pwnr$iHyFHN$Vb>9*GiS}5fCA`d7W zLXWgqbI|&K*Y6wy`R|(f|3A;`Uml1mbUZq@O^2@cZdtc_b`6rAU>Fu#y}|bOJum7H zWXLhfqkenn;GRb=>er*ik_Af(H|{h#usiP>ice#ey*T_4 z8+iRdtF&+miBu%|@$xTTb;LI9JZfjqZUo(}DtuK4hrQ>nJE=x^3HI+(4pS<>ps6** z{Bc>)0BVr`ilmlrt(!Ntx$~DG9V$|)nDC2`iYZ8nRw$)@Vkpt^iT217PXK9u#(tad zGvnV)M*2{Qz%C>=@>=-dWyjaAFi(8c(MJesvGX^G?@Oi@fv!seSNLfqAj7Lwu8E1` zN0Kd<0_P66WI-k-xkUs8q}#2x+(;(*TswB+sC_u{U8L7g%rWKMwJ9J#iIZY%8cz<| z__#=zP;-h>?YBym%2}s&jq!&>TkR^P?WLhl+L05Bp9ne42a>B89jv zVs;(#aquA!^<2&;bN{8mTTD2O^6qF9c&9*Ju?CrPTcF&?RAdWQ%K^C(S z_@{g?{O^9)NqMemRuu+w)zt$jZ@h~T5Mc1?ORw941+(p?=N_i|VlverI}VmA)w_SdiWV|*wQF5+|DY*h65{9)xKUf-<4p#>88PUJ`8B* z&TXy?HAU$xj(1f;jRb`=XvN~RCzG?RJ}40P-7*Mmd4;Vzns3$W*F}R)uy44xe)vcf z1d^6^I;0MT=32CF6Z*yHpT6+Klh3_eu6((yhlV`-)UAUDk0$!gSt2|gD1KW1=l^vK zgqI8Xr}!tyw&X>r%}KnzQ@}E?-S;bbyx-PR=knVcCh+)xVgJi^e=Z#pIG(n(?`&-) z_xW?HuivMoetw@{_kH}fmi`xbPl5fkKX4r1-(O$gwr}(O1IIkuIKH3GN8ccjT<2A* zQNtxJsg0l3g(MmZUQvGIrmcpqSu%4{M=B#8Ik^vqc_#K`t`8|aAvU`3H1OUeyaksp zSHW($`X*bpU<-s`jHPA+*G^sW_6@3XFF#q=mKDiMFq^w_w{1CHK+T1!*0)bziV&5- z#E=NoM>>?O5aL$e4p9cRTE&_a`>8+#&k}M`GLa6^I-pJkiqe8`3S^JV)I+R56=Vz?FP3@-62uzvilI>=GQk8#nK;dw`u^uwa&bH0EQ<>XxTam$WQ$ zE#!ISV9`-Ia2XB1OTN`_SdC&?vXi7)DtQ61NW7_s58BM%ejXpp&%2g6lka^lQK z4;&_2zci5KlkvrTVh|CKbm!r_X=g`>JgW$%|h zVa)xl{&SDpH{gJM{MkpALBv%>m}HmME$!JShuHP_Ha-KEraW51`0+p5N1sq8nDV|t zAqWAoXXs1MqvhTQy zJa5~&g}I3)cp}km0}iEpnbIz7_`WBfv|Ny_LwKI~n7c}GEy@!i=n)N&kX{(U85nXz z>2kJp_W@h;#%LH~mJJ+urFA{8gH58O!p%2-$QW2SVU}VV*_cpyAeN7ICLdTn@42Fu z51*pm$+y!0b*u>E3kLVCtG)i}8}!HDg;|Y%L9xf$Q4V&$s!dr)$~{TtBCQ z6wlZHxfxY+k2eud!!L>-hs=X~jPzr~x40y_7 z#u>yCO#@=dCZ-bzf3axf2qB*@1b}ZDsk{tz<(Dj8LgA;GnB`L0j>kL}fwqD92;wb= zI0F=$>zGjykmERTdv@(=H(YVK6`~a>T=N)p?G=d?S0)%qGu#eh(?51J+YYVY3<5xg zP5xt!_3D42O`JLlc=r*uY}RzU?#j!|s>E28a$PKrI_Og-PboG??zroAmxLJS;Avo3FbZja@)y84u*>7q!4IR!4JDCs+N?jw z-cRNp-nNOq|6xxKf7#CK&>nN;6(p}Nx9(lLQ1_*h%_fSfbC=H6{rrpU%@Lz)>GH*P z*S!zg{X?F#P3zZExT&AboH^50QQ!S*O4gpi{3Osy`KH=;>||e3>Q?}kGPm{Ub-qI~ zUd(eEaPif4_igvvn{U5vLzgaqIAc0ROVZn}ycNCo5`Trji!@=h4 zy9>qsar`*IA0r*8r-BP&;>j;MdI%;3h8FMBvExU$mUIvdisw&0oGgSOnH7UUG0r9d zQ}2)iTI8Inpc#s(Gz@dpjG2q66Elkv&G%a0^LskY^@}gR0+ezKfhG9CnA?oZGuE(4 za~O5FZQigJ-%%mH$HR6gX&+i^oLzp&Knlhk#MeUdBGHYjH?DSJ@{8s!CRAGjK}E2+ zQmq48?q&U(hout9SfygQO-zB9!ap$vwf&#`xz7yyCAV43b&3g2F_#Hk_ZOu$zwVcT zZGPP^MaF~cz&(>u{e>^2&`F)cF!%IJMDt%)vE_(rX-Vt zkWmm+lv}n`NN|&3!-k(f^^ZwE2N#|h*t}u2f)%Sbg@l%l!*Q623Lggn?P14>#2PvB z3p>omcNr$D`|h~bRxh4Ny^a0kUu4_U58Y^s*6z1FBx)545>rqT9tslDlYkI&9gO>x zS6l%zi6!c03RaU`ha_AYtf6Drzl3~4dD_HMO-mtBZ2p$z3|%R=KMbBcIC z=!vQlhLditZ29uk6+cF_5D*kNrJ*Io%mV_$JUNZRX%g(fz=iZ$Y+rW_15r~|{DP6h z$!>(%sD6g3o*T8mhdStsM;{pi0iskdFfu|CE?=Xvl|5RXLPlG7kT4k>sE3axV*}5% zyY9K)?!D(Or2U^6kJceC1MYul+~J1m?8%qXJMDn!QF4TJjFiuJpwb~p6BxZ*&DBN%MOsjh-;0z}Nt&$iQtlX;iRSYo+~ z(0PM~2*C^{HEPwCKoj5%e@@88RJ z!}Iu%V1suFZx(hL-@Wr4@zNGYeSsj|^Sq|kvPne}AoB`NAKV|3loh$YW}W&A+!Lb) zk(U13_e-^%jm`z`_v>2vzBcMQbuJh%McHv{hFkZguYt77F!YkKs* zwC3JjTVKzpl5urfN=itb#x36H(51)IVQ3tkI(K<^;j};ccI(_eRz;@f&R+V%{t8k?r4mgb>#O)}>QhyZeqC(Fh0)E{GzVy`G)Q%(n$gcG{ss>3kFr za6Z1+xF~G!^=~du67wjlTc;+WvipdZN#z3;#64Pz z>Y<46i&*f1!CQ2=b56S&C77~qAAASki?x6z*+Fgc5td4#VU+S<&{iDmyoe)IQaqbA zHvn@2!Nlw#DuL#aM=>ffTFr%Ovpn+n6F{?kVq1Xw9)&hk89z#UYJ#7@aXM}0AGU7u zMk*>EgwSO}n4_#8l@l8`YGg;bmp5J_BzX58(39I*oA#YR8Xn<@PjwJv+qG_C$I|kx zT&41WV4fk-ZZZYH`dGKV{VA9<7DBrltq3U_9?6x-3c`;Kell@MBT?j=lM1-@9He%c zopN9r9{?4fM$}mp0S=13lG8SqNFjyqDim5HiU~<2lcpiFm#Czi`Yta7Gmav-L@+fs z3SA|=)A?7TiBjTya)d6CoQJO6dXR_H$X*-u2>_DS>|z9i`LkwQ2mt`s4Y-in@4tgg zu-V$T>qx%OTA*KgV>-OrzW#cQ3&&Mm_$+Y3@?dOYm4YWx83Nt0%z;t(ltfeosUv58 zHV*uT_3B%TmQ5&ATN^~@?bKBN#c6EiDr0_R7zK}5;S_12+PTdP@?qGuEo-AjF#r2V_mR-(Xls|b;YL7;64U(3x6S5^SC)!325 z2FoWF2{R{6$_l8Gn2et*ylG=sdN@7f48eNAR*9lz?~+t_InekUH>|P&mkq$*Gsp(t zd;=!KT$_Sc_rthxR+=b6_g?Eg#9S7~cKcRTOso-y)|*vy`rxsk;m+aV%8{gD53p%H@5B2H|TXkmyfl5b}s5n3t1NNWxhVF!e#__qo7n7$Zi0g^6h~$zyeF z*mF-<{jf8n?I}Dp%62EE*9zB8U z9&KAd6n=&pB*`f!(SYP%>(slSEu23alU{~h0x|iS2pmbWeJ|)kWYkfhIySlb7lJx>DhSu= zLUv)GVjLo_MSq&O1VcM%s)tF8PE6ZpcG{ zkZMOUgXT%Qb26-~cpO)RUn{}#VIma?6gW-JO)89C(O#L+ z;(6x;=h?Uk6%P+owB*mJ9hp)Ez6jL;F;qIUpUwZi_F%OsUp{U4C zl=UhoL`Vq&dI8lQ)T(X!_fDTYc3ojsYKN{}dlgbmF!<1kV+ELALK-(|`9_WEwP)`? zuy+JCw_A?;Zd}o+lgU8|L@Ql3;BsdfdFwqS_Dvh@`DY)o9=+OG-qi7S`!%f~B4M^* z);IR^_n%`Hdd0f;>J5Vs#K=*|7AUeLFHW8^g^GzskeqRj!Z7Z>^>*vuuRjuXhE+xS zfBChS371@eL<$BM3`i36;2W-m*iqUQ!Z2Xq)ppV4m)eu$pfn?Yq7=^0Fp{|h#OHDt z9CL8`hXiq%!=236GQ@FtWEm; zH%wBS?TSHHyO8l;h|b%0U@t^E1KhGj&Np`R4Oc^?%i154r#iEn{9uY`I)y2%2L86o zuNr8Zw{5aT^A>aOnCUQW1>*xz$%COUziKHgI}w=h(0w;hvt}zkn>h#>Vbp^^<^EQz zSxoX`-$U~FM%bd4#ipgf^)=BP6M!!cvW+PI&7v>HUVrGe8XM|=~a$C5!Eh(s%V z{OL!WIai_SGEvI+q$t4_%^RS-R<+#pV~n2)5M~(uz-&8sg0Se)c|p-=YgMaOIipFD z7RXQLB`yD3f9Dv;f9v%BXPjINMhpclBse@gyr6mO_Cr=Kow+PJG9(zp*8J-6!6B(> zMMVv3*W1&nYqyz6hw5IvYT=x9o!T@l_4992EILePF4TO`f-7QQ4sH@c)w-$n$!8#+ zLX=*6ZK$j<_aVtt@8znvjm4UjyX#!HFVnrCG| zB~B!?IEIj#o!fUJRX%6!D8Mys`YdXMTxa!ww69gWIvLK3!0bw~3op9ZjshG1`ZFLU z<5Rd{;0@NR&qemhrytv6wH~*g-MUjleJqeHYi%sopIEL8OqBb=6vG8^9|Q_0ff2Pp z@GnlAP?VVa!G5K!z+99KFTyKJy)>*sk{e|L(tQ*Y8*Y%F`iKolY{<$XuSDb0M;K`N zU{E!O`NqX1xV()J?pskss;XFshS3ft2UWEt3l~`wOuqp9s!u=v)>80a4SnG`cEP|H zPt_C~Q1|}MJMOk6WMf}+(EzlV$~N$-8yLScb2Y_ox&2OVWNgK?E< z8EBObGmPgTUxePHj$OM_&*r2(|NJu${gnStd+z~XRgwP<|88!2uLME}CG_4q2!eo$ zqR4_+P*72^_jM6OELgx**MenTyMovd1r+Im^j<=TkPt}k^(OE4JIPPS^CY=34`q(UE5qRn7OHA&Z zV@U^P{m<*92;Ze_ET~;O^fZpE<(^U~w)&zdn4 zFF_Z>;9@fz2{*uDGXxKW7aHuy5lj`wnFtpj6N2wpu2kh^N`AJNoXtV7OGJ{$DR#pQ zJl2z(oZ{}=yU&)kty}IhpC5j&=7an<_+u6jd;#$>RbTpM%F>3}ZH2S6;jHsNE)>7< zYnvtSrEMpFU2%EAx<*{8`AGAL*77Z!f=s{LddXJ%D?{ zl$MTUv=keC*(J!f_%W=DUNC3gL3lePCnqf`>S5}^!y=>9gm;C}A28nrgH0CTP5iGf zy$VaLGl&s(wM?3Hv&7&zi|{7D`0LM2cEw&j``}IcV|foj_+Fa#BCNe4r7049ahLGL zCm+hv#S3ukcD>A*{byJ)B^uv`q$5WVDfj{D*Kd%_LBF=Z$|)8h?9DF;-%$QofA!kO zYRCn#dL}We9p`letNw#U#Vjbmkq8HsMvsJrn$~M{IOOJ&Z|Dqv!!Y*rQGsb5j$QWQ z=p++H5dJVo2o*1!^G9IU;lb`^4|W?x2m>DrC3$upq6I_7op(+(zAHWfVOYnoh~d@@ zES-T#e$ETXQ;vn^h8rfK4_>nP%TJ)Vh7kaQ8!{1CF5c1!$Dxem;rNH<$ovecq}F{1 zkJ7^NUHWX{A{<2(nFZV%3)c%TA)Z-kicCisnoyYa2DNG~UAo|HAIEH`lF#61@hsl{ zTjR*_V%dM-pd7%?F%*jT%ya25G5*Xb;)h*uAZ)!60eTk_yWHXegyJcebI5|2kFYe+(b1J5p@FXSwHjUP`RJ@ktC5~;oZWa)= z_)(;mdP8NP0K3jMFB_(HEu9_Uy;OcRclBSTXUmCKoWiwKxXRJCmV~pe^v<^8oczwV zEl+W_EFHh|(K-3pX1`R9_C-sTsd&58y7Ft=zCY`Bn>5bLNdtLi!UmjCfnELq0eL+J z40;KC<}<@Y%=ld9WusG%zH^r>JUls}Nqksj)b6U>{2W({gvQvi`<5bYXmwyDyg?@; z$Xy#Gtr~a5)p*`YnL2eQ@+u%u;my||H+pC33~fpC<`MWo`pCxZ$6=L}j$Mhb2_MfN zX#gfKWS+)RNr6e|lLy_w=`(3~LoATw<42*4Ex}toCpSc)gf6dBH(Uh}m6!l4b` zS~KP8r{}==FANqicVZ&&l6lY1fz?+gBJa+{vD8)a=4-FZyLkI&OfREA#w>^w_wYG@ zegx+}ewff0z6676e!As|;~Ii+C_A=qNBI27IEu@ZNB%McDTI5;<4?|oXYnco7xYE8 z!dv8{Prs7cvz{<{<+CtJtzWYq&(ahVez1J?)z?Tld<6Fmlu^S*<39c}_2!#QA0A|) zDi{KM0?VBYr0w-botA9eF;p)q)r*5!GSOd#Nx{AYy8`qR%S{oE`7rTdVTN@VRu_L? z>^ne5!v-Gz6=NY7K6Hq&bXtP&E&g=K!vvXwxAe=#T!DqV5pvnX;tIh8Pn=3OPLyLt zUyd;P*T5Y3b_sxKu^T&`P%H-M623b;DdPeR<00QYQZ<7e~++sO~L}Z1C&(phCSF@Acy=N~BJkB82m>-T1_acMk zPU9us2*x43U_rKP_imF?8R4ysAwmU0wWlSY#pi`l#jc?xj^T6p?`Ojq`SAeg5%h9fLxGv%df4%M}e{qlRtXy2JC`vLD@a)a#7A4t)?tB;|Cj z+;KN@Cd5R@tv5pf9)YQ&yg;rP(O#0%3S{~Nx5$v8Bju*4w@OT06DXDguvj2*RAHth zZTSgKX8R?#6pD3ZjpGjEvdb<;;JuzE$9e(0qMx1fJa#q3u=Ov*F+f9k?#1U|L54Tx z056z$M#~F-eFgpvd2;Wx+vRC^Cey#b7Yh&bknp$2q)28b178S?04!s0{EQzkt#LR_ zbE3n(2gghZqmD_Rv6Vi@M4yN7D?CD*haJk~$y4N3c?@NL*`c5C4<52n;!nBZEsZiNY|1wv-5#f~dahF>&H7B2eO9Iq8)hsOz&GXXv? z7?47DfrX6+QkZU`6Tw~ylQOgF#bMXhxqC+}0LKtJD%C84Gz}&%qX>8~(b1pg$DdY7 z9z4yt@C4zQin@(vuoOE5^VbdQ)*$#~todIE-vg|th@bYgeD=i`_&jii4;?@S7F9;M z<&hbae0i|g;sxG}9StG4u&~cGR>1oM#u0I}FuoPo9WiVRN74<8rXU>aP%lB>jPU4a z>D;js^bmWYsLqsDaC)3Fd6IE-%)|oB$iPS^i$w#@eXzPRc}nnXJgYQOp=pJM=cMUx z5S%qTG;1Qc*g<7rVLWx>lr+RqQ;$yF5RwGZn)eP^ddJJZ4dR z)24sIZr_)`IV={~FPh8b8R73#e~W~&t}rdD$*cbouk)Z7saGnvs7m0@;0`Kbnb8<4XM)~^X_iB+?T6QKQ)3eRi*bL&_9 zIILMhycbe{;%pnqr|^bbj;%cLty;H(qA^!KTCfC)&?LEW@-;GcPwWm&Qk#}N5N$iLwog-NDDiV@0V;uV*hNswl)l{h+s!hj1SCPCQy*Gz~7aJjGG z+cIXsU>r*@r7S(YX*SC@Z!TOs=)xaUmX+e|7n2XqaNd0L4SD*RXQXSd?y?-`=Zil7 z5*A$v2>BfftDHvCci>PNHENXEL9JQ4M%E$M#vAXx1IrueAUbuz&S(xo&c7s!kU=jH zF~evKz@-D-gSRtxMbO`1vgR=s!=F&|!QBPph*D&c*7#4gFb{p(5cbJq}gxx_gqBV2pI0Tk@ zv!9raokN~{_2mLsDupA$b0LnBmP;pi_=n)Au?#y+=7Q&OB7J)pmyEenxN;e}Ts^RO zFiT-6c3XpBi17=o;gZvL%Y_35AwBIN`S|k>BqJkP2KVj;XV3^a1?#=7+jnA-$uXbv z{+-)l9hid`oQ5*`M&yiv$Yslyz~ARIOsrvThJ~T!P=uSuE@zk9G34BZy9Vm<8 zu6IP-M=jkr2luk>W{GSA?XLBE332Zgxh$2$hxIGAD!~BR62WgC(QoBs7#w) z`4p!7+IHgYHffv}@paMIaIM$S^R35-Vx-W^$4%^w^YoBIhYn3@+O+A12%D0}9SjIu z&6_9wxHod!nv(pS3oaShyK=*ZODSIvNn z0|pMp#8GTQmo$ep(Asrt1&)*W;h&Y`CsQ!tVA6qQ4UcE|9OlRc(}S7!F#Ry-T>;MJ zuZErerI%eU4p0 z;Rq_23MKm;H{2jOSUew_H46&WkuYEVNZy|RH%w4zSV;Y3<*N1YZ)k&*xJ_}~u^qdV zL(uUYG5!P$8p-21tZ>U{@esJh3L*J4_#%QSUTbtz%yyUoBZP+V5bxVP68GhJ#~1 zUT&z21`9hkEOVK47~Kq>CZoWgRhTQF3ciBhJ2v<2+Csjlz|Nd`f566>sAdUmJ`#m0iCB;b_!f z|F1^C{=(slgh|G`uwA=$Z$XIJnGlaf1V0k5%Jv<*ys&BQ(hEYv1EpE(hLR7bsO~YX zT?Iw1qr3Jbd6kuxx1h&!HjaKgl}R#k_=V=!p?CuThg#bStb!yDnq zA?@ICULrg8orSsVQA{ok%;e?+B{1##F^5P2CP2m?I)z*%nFzX9gawN^-8l&(i!e-B zk!Kt+yEw^tV`B5iM33LEIWLcmkCJ;I`7?5#&y|%+mtj%zfv5HJFfUF=_>i~Yfj?Si zK0XUx=AYsCi4lU$vVkKRn8ji;rDr^q)w~Cfm&!T8Vo{0+^FdnN1@i7&Z{f(s8{Kurk1%(qk))VSIjN>Ng zX<*C++Xr6lq+@a?hPkgqP{EchTgelTKW-*w#C4KB{rbs>3x`N=#MElpq6wu+G(767 z_c7JGK#YW09C;rMgBg3=5dEU3I6iv-nSl`iuw!w=(NF+Bj|c9Y2K`Qmti^)(AV14j+^KL6Jg?;b}kiipu~=gl+m4Aps)TW1{+?E5FObCtG^_9^^G^o zSVbT<8DAtyF~)&-5$f5sg)|9=F396m<%d+mhtCwaU~%@qQ!iisGLEB6)`wCV}AxzAHOUHs$ z{C6j`Xz|^_q{hE^3eNRy64%6&m7DKXm|KivlZb#f-gvDYOm*{rUbFJu-0ZZ;etrR- zcmMt|JfxtQg<^apjvm}Fvz`Ce*GR;342s*Eq*do`;&b?CNsL8?ypdgH`Res@$E{z< z*s&93;J{%xYQm%glVTi@VAqj~RJ>b}Bq|wisxHJG3WpU>u{`j=y$EIA)J)|5I7*u_ zeTE!CEGv2ypM{y|)3c^yvh_vKNKAMLb@8`%FzFx>(0vcwhFlexo{&?6&R;z9=gde? zY5$r@jD8ffxMgfE&T)#Crj2&SjI zOm;o)78oat3x=7X@w`0h;{t5L!{FJN+=`2j2iqWelXD@&#A(8zke@pjCWK-L97Yjl z1mBA<83q4`_HYs$E7x87Cv#MmfrY&xj`%>1$s7wC`o_eE*$tzS}rW~)!<>7H~N$ZtEg_sGS~n|Qma?}1n1UuILaD=vAb8Aw{DFbHKXL| z*)tG5APG528c35y&5eWW6-Y~P2Ei=*3>*NH@@7!JpOrPMm&rHqSz-Xp3wySca2!*i zqn@1f40mx=_}Tk!yZy?x?c4mK3UGXm#wdjy=5I!SOE@}&ffsz0@RRqh^l^D(m*jGJ z=Yx))r}=GZoxd@{SQ4g}!t7FUED7g-)>VeWS@KeRb*uWX!nD-;vTfJvcOdqt)z|-j z8v%UDxR@YIuD5&inDPCPBjg^O`Mwws>~_UAjzVm!MyWVokHii0Tet1_%!bve69WCJ z0(*3C3y<#2cyo-#n=RGY<;K&PZ;U^!UMGu}euv4p!X$fY-=-PjZdFKRfCoDp#2lLb zupB&|h6xOBhNZBx$Jsb186Lj`Ls89q;vsnJ@7<#Zl{d(ihfB zr%oqJ6)b4@woMb)^t3ZFfw8y{n6Lqq?>tU2Z^eAu<&g@0n)LY2fakO?b}M0U_%d<2 z@Fs2+4@}Suzrvp|roigDnF0_dJPJDyEJ8e1;&`zWl+H|e#s|XiU?*Z;@5?a>mcWbq zN-T=IrFstVJk1ZVHjbZ~>>xEMYP%))r%jn|q`>>qyok?e!H zX%_mK(5$&h?39=j91RxBci(+0anM^GJ&8OV@Q|nXHT5ji zZQ#*hJI7~2htWrd*FOom>#n<2o_zc<*}G@A%$)Uv97JYEn4_AwXubOMl^r;qd-~~T z<)RTIU;&2YOxTt7>(?6-br#08Li+UXjn5p*Eyk7kTug|2>>xPE{4Q{@V90vh5;R;W z`29c|3tDwL{OsM!&HZlkz;`lV+_5pD@i?@EbTjWkPhwJLPvHQmQq1dQjj6f zK5@UCgkMq9xaQIt;b@qzJqk+n1Q^h(gBQHTNyRtLdi|r14mVu8vA;A z4j)Z-4<0^l-2+;R@n#8Jgss0{t!qhs(rKIba>}&vtUK|_ zt8gt9P99#`)>2_g?`)HfIKp|^e0JLjH^epc-=v%?+#tMzSgN*_g8A*d{(|L^0W4iiEVHs zCbscwXH$|N!eZh%opRQV(-ruVt|q6C5kCYw$DL?{{V5Lf~7-Zj5NS8S?hMu z$SCQSHeE(Y<7TZ8Ff$9L)Q6-A7OQk*8GIc1II^+}<%MUTLC)@E)fgvqZ}3gI zWvW~_WRMK%-AfK1I*0(8=U`P9h-cy)TxQH#%h4b9pP3hP;BDT!YiH=8?liP(R{sF! zx`DE8-3B~YIimTlfG2*LJUM$NJl+eWRjWjVKiP)GGY0yETk#?hW)>`(=^`Vau_E)q zxRgRy!Xq$Ra+%!+#?BYx!tuaR;DsNb2o`3f>%)S^r3GWkesOu>4uk=E(8mfa9Q+oY=@qYarwkjfG&YQNm2DOf z9y=(3B3RlmyRC4RHk@_-*A6M2wpsFC+II3Q{XYZOdy&?br@XbnoH*?}X%)wkm*TXp zG}>mVm;FpO9r3mtr6)d5-%9&F)`?)J4I<{|Bm6Mt7YTZ0m{E=Vd@Uhg?ojZ0$<5fq>1Cl z!^=AolV&8sR%GL|K{B8C#+YOa<+G38$I%zEIO4660UCMSMGXNL3ggXMWyLca~#GdrVIH9^HD# z(BTgv`O&LJ595zxFXlAQ#e)6mS4-r*&k!BhM8b{W#t6@g1&(j>>@w=?Q#PD4FCQ^P z{_*}NvUc@KdG3iPkhZpqoI8~U3%u^qd(dDRHfWG>#2a(T2!w?BLYA#uES)-ZH9N5a z`0x}$XG29hO?o-~`|=16K?cn@;V*Y@Tpk!Ck$NSL4<{??ZrpeW@rC0f!?#cu1!DBC znv=Q~Gqm7kh#C{&7%NW&R**_8e5u%JQeoDiQx}9eX@&8{?h40v9pJOH5CIyyckP5c zIIm&{6(rj?ekV_+rsHGdRR&7FRCvQv`&?q1_AeYiwCkBh4H{J7jnoG@7s~VVa(ynkVBq^NJpb%p z$g_RRrUx*^&i&zsWfebf*y0@--3a-s_`XB^#>6~puu6C@o3Gc)rf zp+zFXc+9{={I&f3_1EN*OGe6bvmckC!!DG0&pnH*jn6=_-V~0Lsq)&JpUUtN7s&_6 zO~K=s^{ZDP)W{6^W&1uEH*UP#GG#JCyuU2@2-e4)7AJ2UmSMU@L|iOVUa;!o#odz! z+mCXZG(j)K92X4j(i|yWCk`Df-@qp%0=tMkb z!0>&-XT<2kCPsiUGGN*O{DRExggX=NK=8f7lnx#)L8vgi%CRHIBmr^NdiCgqBS&9Y z)4`+}h80{$9zas5)i>QFkK8>C{y~#u$L3|ywM7if&T~8`4jyyIw(PO>@t2>tGCV9a z6~|OQ{EovQ0$r}2RQ0=G{V>1%CEQ6nguk!5sDX-Eh zjl#99vTHs$Mc0@0Bk->u0emUBJMrq)t>>IZ4dZ`G+P&>1KmUw=aq&$*>36}1o8W0~ zELSjbc$zhDv2gwBA7;1j&^B<}_TA8Rlwp#F^0uM~6N@iQEnDD-CLB?2f0AdBHLe-L zjL)0*v{aRxL*_*vDDQpcyN_R%uYcSIy#>zCVG-nyGkoNl!@7WJ6i$Jd&#`#;W3rwu z0|yKQu1XH!{Cmj2K9bP50p7e3TM1^IJ9qEJ(N2-km2d(sz;VyL)2BlCzDS=X?_iK1W4L7 zVld1^JECuon%&fx%P*F9VNN=0<_r_&WA&pgc$`h;;9qb3M4IUkOUJ!A^J>SsPRS1v_3k%>sj zJK@@!kRkA}Ecxb399W5_`xg|NV5nV{Rnm?47_;+X4qX2H>=;^0TKk0Tc*T~ zz%DZu@zy5abTfioddr`YOJxLNnyp;BQZBo4ybO$w_q_Ag8}17(y7=`+UYT|`cNd&E z`5&L5SvdG>(Mgr{|JyFJfN)^+!F6R}X~XQc!dcpI*7=_UYQwe7lK0ZKlfN#xwZZjX z#M$!LuB{K+9~-AI@+%)pUW(JY(rBBdUiLHDbi~_olwSK_w-u)Jw#?e(D4pI<+gjGf zLs(t(3b*4az zNMeX_9Q5UJ4;CqJDE`fxJ&uw1+_apcH@C^~2Lz1<80307&c?)uZ41$So zDUR%-ks=n0CoI;=K+BZHIR$w#>E@dy8Ga}|uxr}8X&WrdJaWx-*T|jIZk0(B#>?c} zZ!80}QQgJK^ciuzcN~d^j+jzz4ec86_ zW&zP721RN~LanQCW!5%J8>V$F$#2u}UQU@do^>bQmc_c_6;2*r+SXEGO7Co|EW&x& ze0JLjH^epcl&#};K04*G<&sz1+7~TVrsC~V>&mZf`~IxkZPGZe^U>J6TGvwLINO9P z% zM^EBdq8ozrf!5B^G%$lS6=-q0t7-aUiB3`>Y)e8t(5hf z56Q8U1u$_9hK?iyI~#wagD65|ScWPo#N_E05+)gNE;|Rcon=%U(3YhW++9L&cP9iV z1SwpD1rHwFy@25E7Tkk-;Sd}Of+kpDg}b{><;|Pd-D`Sgde)lZFNu(OYNc?@EVqehSn3qPa^{6H2Ez2}5Qh8KoK5=u^%$YGw%D@^Ylcj0xbM4ufjGd!UO+FB5N9Ng=~hR>U8|LFg}?Kf!MY<+_U%K$ z4muadXiLngU1^i!=<>vHmvAHt_PCYA7N;6gA^hkt^Kngrx|w#!i=uZQ&~vgKB6v|` zc@l_X+(M~k-fk>}L5s-NZYY4q%k5TY#Yj6@!s#Agb$TA)0hi8&EU(6&rHL!$G8((= zJe2J*{5z9j1ags+fJw?f%tNMx6e8m(f+&4V%czlb479pWZ;^??e(_e+Y=EqJ{Jzg| z)(6gQdn^t%{EFgw!eZ^JcDK6(7Z&4wz8Ffa`q!17#gm-tSX^gPSz+4{z*OH=Ng3#$ zhC9hw4OFv{FQito`hL5S|KyYO&98is&w;|oaI@^&LQxBv!l-_O#YC3~1H<+uH0U9B zSYA-Hp_Xg);`-sFo%PAYG;XiOXs)_;7cI4Qq8o#Eg?*Y3Jl*|xhwJHwyvFtd5E$DU zouVDuYPd1%%RFOX>ecJ@$a_t*&EG?Zfe(8QUd;VAzKD)8`S<20y3m4!O8+KKxXKiZ z382>ZclLBfzIVkV4!sRt-{Zut#%vEi=HU$CDj_CHah-l)4JP!*8Dj7|o&9wfc&T^F zFF}=03@wVuMsexZhbtmoE;l8D5ilbs1oeV|v zxYlT(zxp6_DdjXT0u=}cyO5Eq{lc8Ho^h8Tc19ZV%&?qEuyZVR`Yo0Bb|Lm>a8}v3 zTG={`ON8E0VFc=xC`W=c8gij#Y415QSmC<$`S9i5IcB0OcdL3X#WGjVkV1Q`f%);$ z-T8_ScRhN7Kjp({Vf||@J*cdgekd?HgG)|^no~jL)-_8?zYZAmu+fj^*XPMS^63o^ zJ?MCeJk_U*LGxApPx%9_qpf1g++=N|box1op|f5WUYx?GdP?E0lg8tr+`tbEb~TDK)}H?YofwS`QW&HRz6;L23a4dFUUV%PA}*)Miw z0YE+{j#sl9{o}^A1-4h$6KrobL5luZsx9=h*7VMUpyT{|jwAp!Pb1CP4qMx~$E77h z+##%+3v?8HNQZf*5(+-n-0S)7^~mT*ub1J#PHX_QDaEV&h9b0(YF!s*yjVFKKSGI)et-zr7*Jv9XINyA7gxo&IQi;eBRDS>QA*?JxHT*qzn;_XH96vKp^cXh@Q*(m6^QNXx5SeEyrhAQ z4#~&~D7Jg6&n%=MyLd-3L_@Cu&%5iP+}a8u_V@a{YQD7(8KdRV>pBa5g6B(4&{FoNkWd+F zv=UCm*7oHHfv*>JR+D;JrL<(67X`g1dC$mWW4MoxUbyyYk&Ibx0}#H?&DJT(UX7nV zvlCW#1Ygvjl=A&a-|y}hKFRm}_t)|jKG zhz&5eF5|KD-qJ{ip^_2JkRm6;{yAyWzNYG8uoDPXJAJu%F=v2T^6pb;g8^;a)4Q91 zpf4nB&HSN&%V)#@BmdJ|E}bwpt;@Rj@L_uTkk*aQ&34eU^E0YMPpXw^4V)y)}Z;Sxvn`nKmOFV(Jf#G+P?=Vhg3EM+rh98zc)&Fd;9pLD2(>Now zb=IDw%*RWz?0$YS!;6jDEmooo!tDddiKyp=(x%u65`DY7Smk;qDh|)p4EPWr(D!k> z!;zPIM(PcANXY9*dp17?GGvy4km6}fr>^P{7egL*qF;D=-^apq9rsPEZ>RA#Glt-x z_$Z&*ki-IkvR1#x6jv^zOEpZG*-C%>EPeiF(R`@K5c~L+O5qDP_*%400Z*|&`%3~- zfVpP#S0X4)yX4qaUYk1K@(xV5vGk> zqiLh84jq{Afxd4Ljq^>d2!g}QK73x-VvXOSP>z(L{L|4&CbR!#kqtRG^k-43&>L~D z=M-2MB(Dlha%2tLy)E^}cD~-a*?0BC3vWrgUnpneZSMaBsKYODwA#Zpc_D7LwiKT~J!x7fT_;@=TlOftw+MiQzr<9^bVk)c^qW<7YMf>6Q&c^TQz zFsjsI=M{!=Uk|k(se&$)I=Ewhs_#apqFah6CV#p;w+dHtT-N#dBWi873;`=#313+D zBnN);sCgx!C71!l92it-*s2b4SY_k27*F07fcO(l8C{?^^p^%x;0iqLT>iY(T?=bX z9ML;QcF{LXzes4NF<@ABZ0LV)jj)Ms7A)tmKVlEFN#6%L;LRdp{9ra^y;~_ZFm`0xicZypk(0_YOuoYTD zs%U@PGq2_wiJ&e$41Yn#gQNU>&YE#`d7-o9l$D;&)M{>sH}fN;4rvr1aPM>6soiDN zp>ywX5MX{xPWEAPqQk(Vr=`tDrr>pmxr0?w{pZA!8U#w`9GT-rPeM(|b`iN1a!Lv~} zw8;`2_+mYfHr?jLmb^h&@1=)FHnGyzt460yUFqQ{i&5#%lkXEQCFXXlwKf_0qu1Jc z1f|f4h@t4UjxpDkX`;XFeUL!KP10Qa7z<_>Zgk)lw#qJn8H2CSfdzipKBR^S+#4qz zKi}f%wQ+Jn?Exqm$<0CW$8Pq=iS2YO3f?Gp?tcMuGVxQUU^Cca8%J9bVjol<)U;9z zSy^rx+y;x>ZL)c7x275Yx$3k9{MMzcP#h7bM+-s8FK5_5*^7iVDXG_v)iWx7(_TZsR7hb+rB)bTJ9>I#REPfwT?8Gu9Wdf{Al{-l}=j04ibipzudz=XrG6 zDb$yP3*}MIF1HfUuERyg15=iI4 z?T#pxz9yO;;9Fa06?F^X#{6P-mRNi~&H86$+O&`w|t3tQY7lK0|?A7U4L5fiD8UN6nm6j}<>+;kTOu zAHcKO!{NjuEqVg`y+X!Wm-jdOG|28x-vWZfp}S}%2Iuv4j#Mv5?wqb7Md!=NncVwK zk+{@EQ9snac3e3D@t~&PKrz#J zcb9@9e7ztlKv*|r>>`?i*~z%ybf=}Z_0o?Bk+Xh$XH0iM7s`@Oq}^OQWf$vvl{U4{ z%^#Qu(?!y>w)^6n!4)09ll)+B7R4MaR7|i?XqcSkJ-qtH=R=bHYTtsoY}M(}{{c4> zF<4%iPy-UFsAB+c*OwAY8H+i`ub}yZ#ZaNMJJlb7(a`$SKP4{H__lTydtY_ZkiAWI z@!xpK$s2q2YFcdGE`+(0J;@cV*-K~cf!R=D{ZI(fv0tDqV4bX@KswlF2#c8(?WXq| zYLzM0Q?yN#TN;#v4Eb|GDO!+sH>JJg!thdoF|mgDB;-x0V5G5%aH?+?#=B%xn1jOh zDpEnAtmE0jE^=J;hi)fJZ<7kUv*bqOgN9-whUU7#6GNqFf-NLvq=5Is=Hz4y6CJ0K zwvS%qaJ=qGu=g7b&>E8J9#95hCD%p?I$tlwlcwKTo);Gjlzcl5M7GDk3g;{4xsGK0 z6-*A{k_k2Bl3nrMIdOiMb-26S1wZtug?wE#`va16e`&9jTxqlUDrad=GIYZ_1v&H; zA<7^1KtzNnDy*L!(G&3GteO3cYbd{roO!0rmchBTL3dJ%y)M4f!Qvx_BymukA2`;* zdNgnj%rdXWeRO=^1SEQ?%146pk%)C$owI`_RPgc1?az}fEjMLd%+SU-$Ex^WLg3eR z)AzN$%n?X>YULC3v_%56qkEbxmWc$67)*L|F%jF-qAA=W7XBPT8b+mf4B?Cjx2aw( zHztgwxA;qD2vJOW3q_4K&xZr?#E^Q(`ts(yZtHyNYKeyNR60Vp5y`@E`K@K55V^J8p3MPg^R>&;o zEe(=!5V!#vTvx?qH#eNev%Gdj{93B=gm8%5_d}*BMzD_27A8Kek>ZD#jklzJvO1qW znYSyGclOedvgtINbk6NH@@}xMUG%Wx@7yV^*#WPblFmSeEZQ;M6#1JEG*ZI?a<)?h z38rNZiK;q0XRN2#6dNl+^khnw?{B$FO_u2yrn*(L={o?Jh_9a!j4Y3AjmdXoW} z81vu%_<5!pU`Er}QGp?@CN!GwFP3fh~Bg4vxuNnIP66ep%@oP{X4HYTuNKUI(Ols_cw1`xR}q>MpTgCi$U zT%lvO>0a_XfyX1lW9BWLNMx;k%cuvkPwshokd<5|ySuA+zXsgUa9g_+tU-PMbXS8N z+qq87V8e5QbemQCMk4+WFCBaQxtdA8oA)zIR-*kY>d z%vL*;>)H{QSemb2Lp67JTsmPBR;T%;d7%-)La@eA+;Wcl{_TN8Pfw1&?`6Wn@Y%ir zV1h!FTNiP7&IrgFMeNV+B=Gh-?+(d^@Vc`<$FfkLGg{>F)qw}Nl=9b5rf2%)u}h$t znJAv{M={0et zRVVwkkU|iQMvZ>|R9ef+l+YY+S;*D>iKG2%hsgb@D38sxDbIak)LK3e>zOtTsuGyR zG;dBOoJv!wG41F|VCgPnGg}>))5qRzyFk~x46M)>x_9nJ5w1Fn;L4a{fGcE5)M1>B5wIp z`0^g7^J7vQd>_ScFfrHKL!a=K${HxYgbo=|4c$adce$}5gk^EuEIT#Z4slOqr5VP< zGh)f2euNSmpKWXh%KLY?OIqg)g}hO-F>=utvR<_Sv2lXQh^Bq5TWI0?ScG8ktqbokXg5!Sfzqrr+dEJ9 z;|%!qll-z+pb1J?-9XVMW(-DEf%GS7wUDUovWVJsA;0y?%M)P&Wsi|bR<<5ef71x7 z4nsW1A%Fv&xVMyU&?C-s3)sJ(&Impo=wSPJeqbJ;Q#6t=s=xIz7Cfj~%!XQCh z`7@pO$)Tn@7Bsq<3Cwmxq8Nfl` z$aNLYAE`R2P$qw1TF?9<5&n(Xv&PV`NTXDl0eK|h$!D#&OOpRYI9M73HzuEw`pHk0 z8&c)NNj9K497gFI&K8j|AIP;rR3FvzLXRea6^6A>N9{?}AK1^WUAFVVIn}3s>wVYD zIP!nC2Td@a-aA(s4WakyxV7_;o9XCEQ#Q#w2+{pR4TyX$W zJey(!xqj09hkLbCSm*VhnO9ZkwgM)$tcnnpK3%+%$L9oM;s?7n1QA9$76ZA_h|re^ zK73963yTvov!W&9P0CGs0$lVN2--w=e$cWS=7#vM@ezN2XaT2KubxvQW%7xu{Wghi zTux`gltcQ`%^I1Yt0(6pL3OInNf*AunI%1yFZp@k&ahx`s?jrkB9|uhqj1M~XWr8B zLPHQnw56QKWmD#1*QKphM$ zChuK`nQX5TVMAySR6#UJQTqL0tGaTZ*+{8mR+&NU1Uv#0cq#CmE7A-6b;?r1wJ(Gx3Cd|u*Oc$-HvNr)BOnx zAt*nnUt+4qWi~|yS!GXWpA>{u9@DVJv?MnK>P=orl@kkr@aW6||1Sp(memr?x7Q)A z9k#yjHgC9&nx%Kh@$r4Qc!aJq6TdyO_R;i#<)I7uSX=zAuLX%?$eJGaBk8z3#Ab<=!ZsCX({qv275!wG$WEsEd|xuHwj-L{Vs1&^J^ zSO+qnS7z$XbJ6iHks`w2+HZa}OVlZKC;FNpW5nkZ$KcVeCZ-Q!jvd1f*{gc5(x7ue ziK+Q~m@jDuPCZNQLn5sygM)YY#yg0OIPay1faekVg2yau6f?#Y5J~$s>qrsokUP5c zA!RcEcgfF?t#(eaR1m6Cv0b||SKl&Y*qX}}TtpgLg4F(kAm;~@amA?OX`BTdc=%5G zS3_#i?^0veB81~lBN-+!oYW(sT@PIkEiv(FJL3b#rTVFC4-#TS$80E(?#;qFi%l_U zSiemB(S?gYXlLwvl5Z2{>w=5`a(w(S#(+1!bu>(>PSqWp@TXxFfIIm-N2XO z!d29PhTm=M8hZpK9quC!U)w=qOf~GIUAgC0W%Z4p1Qb#j@a%@uOdL1U24io_Wr<-mzWzJc4y@VDwN<%|~!sbl5 z(*h8diBSAOP;X-uPZs^zVN_DAouz-Wmig~VD)riywyR@tesS^cr-Z(+6TsS_+i>QS z*s1;Gx@6_0>f9t3gT>5<>4UwS$ut%^;Ny=3l=nP0S5j0%6tdYq^3`O# zxb4B}cMuyFTq<1e08DYY(%6_h(z66j@n;%SPN32EW;s6La5OTvtv-o5K2dnXgLxAK zY59j^_^n^v-8OhecT@p$Q5S|E?jc-EyBAw;XlA<3wln7iTX5BjUh$97Gsw&)4j2ue zQ>KEEDLH@QF3GS7PE4ETDiB=qa@T@cSjPBE>RqUl)Pi$;Oei)tGq_kZ zC#SMPir=`5Ab$i%;ICtNcHA7ykUo=H7CGDiRr5+m*_bX!-^C7nl*IP+4;EsUl!rK` ze`rn%r50!_X9~vqG4FC{R`SpbgC4qGLNaSEoP4Nd7=p}tb4wYl@rTBrJ75e;8W6it z*^qH;LF+AhN?NfYe;jPL;J9B9B42t=Xr$fF@4YpZ$mfk)QjgMLO;F9J+%e5!2mu|! zM8iMQSV=!!aX8pM?lbO>JBikKE|xN%o8#sU;tFwNm&1_US})0HE1ZUhTkhsyn#C`f zCG1dyFvY+OK@>?~mbe%jfr+MPgL_IU;ZM$Q4i{q1bIaJH5=_%Wv7L$*zkF5QAM4?q zaz29zO&>;}_;-n}r&(sirrD8~vRc*HU%bubNf>T_R~i*b&?1QRuXBH$mkrkLesvCx zCq~dRk)?&a0vIFK#(qUW=cL?3;*|KhL>n$ZhFNn$f-P#*(bKJaN*!B>qk?YHavIxX zKM?tfHx+&fTv~>5xYb7`^eB|8mJZsb zEiOHFmP?5r$rVnE8wm;kLw38xrbH837|W8nOiynrc#uEAIIzQA1Q6fl=sI zU*Q#O#WOs-C*k+9>;?o?IC#G@Oj}pncz^S}fBN$>f7Ix4)j9ShfXh92wgcUep6 zmrQvdvN;JixCWD5HW7>)tYtoph3O9dS5vkw&KGnbCyfm6m)zoE;SXX@ho&UlmEB9B z2BYf(3g&m(M#g8tfy-J&t^v;e&lN6p2SSJrH=&8{_m!8&({EF?r)srKw}ZNnyI6LFmb(`Rst3FpTKsfEXK?|E$CbTMeHGu>qoV108RbPSeh8AV4D0 zYFA~TU4v^5E9B8_qzbe8hDLddmD~vyhBP~QJ4~~Tr<%;A48pD_m?>sp*NE1zcd3gq zBeuYk5>{*|U+UagMZb60cK%1Y#xZkZyZL}c!9>}xUFowQQHoN>IZL!1=`n0$A?;VG zUGX0fxXwBy)Q_5+lhg?FPE_%sszZKbvuP_&xlx#okM2Dm9e-I7lPFRCDr*5vVQ0DV z837qVW10Dv(Y~7Q>#xLFr70V?R)^IF?JLm{F_G6Y6cBTTwAT8DsA53wbNc*~`O%`% z`CGQaHX4rK@9-I^P74%z*XYHe=UpiDcvP%f4rv-?Bs#S$TTJepeozu@MqH-GC^|+~ zLPwo<(gUzw5z$~<-;DLJ5EJ8ELuZ1nx7OCJFiuXFc*9x(dK|I=LOT@T0!~`A#PCq! z3-{(C%dPBvB3Y@(9Ls%3&Kem`MMM`%fs`nxj?Be|6?B0;p@1H`ySgFE;b=w+6T}dN zLkl6kn53!B#Ww)Svt%!6}rQ+h|WQw5;T!!1}<>ikR6@W^9v=PbI05mYHrLkjDRNi284O6$uS=;4S&zYiS&FB<2_- zPfq%o^%Xk9lEy<}g)~JCkk20H!Vr+iK;0+czba{T5>@^Nt^e|)v@`nuxWViw<|rOp z9XmTxi<>HtB{e%|N?CDlmR*WvA1VyZU(_NQPxRcmiR%bXN=;)|c&Or9Pniu}@U7h7 zaTphUxNgg9Y~*{qtt;e|(bTH`3aNeyi??P_W^S!@0xiJr@nF~R@%kc1gjT7$m z9{H`qU}-^VE9WJK-vh?r7d$F|zb!umHxY(HKwP{{0@1Z9p8BZaIL#ur+e-Ks3T+CS^O@h}awR zK^uM*_jAnDVpK$(x7$#H0RqA1Q{hvNscxi85QPelSDf2vj)aP3|i9LnX5GDSkH zDQz=0HCkYQWw~l6)L!iiTaw6fg^jtG8iM>|BR0))r4t1r{lexAc754)=jZizja7|{ zT7vvl)3uyM8|E7o)ZJm$-6`7ESshIyuQ4g{+7NO(`0XG{(#vctOwo9&!{sYgvbMH` zgoq0}$EVm>j#tOC((*VgX7G%DOr3qbeK_{u4NW+QOB}kKuNa&+c93hB>BOG0iG;UXC1HP6EAw;nA)^&}ER}2d8F4C#vR3EW-chuy z1+jr7w9z9q=q<5zy*lR?zqy;m^{OBuO+BAdVTl22PVuZ=MzC6SZ}J=mVND~5%yPLz zlgy;j#(ES41y}evtQe?`Egk$dy-nEte@;GBzMc!5>iG@xfaek&vA)>B zKB>Ox5g0Jor=|;=2{VoU=eC1?X+YS2niE)647Sr%AwsJB27)#N0z0PmH*hKofwG^} zKIymH&7Xm;s{ii`7|N@?21`<6_Fe<0Iv7eI<-) zwCsdloG+!$k)w#%JyC^mRs(*<%U8mmM&HO@^b<{2D3u6t5CCs2ln59LdS)uM3cS0UehU|D02{m^#$wp856OegR1=sVLCmjuU9?@l?} zS(aGR&M}Yi&sfIXwjH!XS>?HPcHqjym|)2`Nc4KA!lfhI(^Aj6vGVQ^*sL=zvPfL) z@*ih1Sl$m-HymKi@`dfwv8bFaY61Ti3)R&Bf-AuIYp4E>``PV^aNBo{g@Gm?6=`?r zZDKfR^!NxTDnaduKiF;{<1TZbJ__hYTpl9z^16HN@3YkucYOqT&tL7NZ*C*a*Ux$s5ZzYGZuMREt4sphy#-=NcirnCU@ta4 z&|OO?$<{>rqX^fn*(CF1P&NXL`3wV47hEGz&zJ~^j77zd_Qj~Oi>dz57@>$Yjw8Od zrI(=S-zt~7?sF;5!Pnh7W_4)WsR{!ac_R~Hj)`*MBO%HA;#){DX8Z4<%&i{!yCUop z$G=QLtB4K7;rs>Q8n@5C&gBnXMqf6B#Zn61VyBIIT;=5x8$>n(EyCC74zVyXnY)gz z^|lXJy1Z=jx|_ARd9JGT(^yF|<_Uj7Itq$(7Tpe`9jWXEu_jLSaKtN$TBJ%=c%&Dv zDA=e=uSbvaYv+4=q1REV29PxHelg_;rUs=1c%EV%?4Fsm@8w8Pv;p1!m1)*PY&2Xp zQ)+UpXG_HN9=jL8V; z>!WoK2?o$vGDq#-NU5tBD-`l+=rT{rveiLszi(#04r#JM6(|v_kwNV`3 z9oyBM|LR`|;l(f4`U(FDIVOOEhV5+i_Cww#q z_!P(A!+7RL`Eho&yYvwK(#?n^x(@?Ac^gR1*Ea<+S5pq=#2Hje!3%X{I$8t;4a~|$ zU|}cpYq8@%Z``G5$3E`s`FlMTU)P_^quzbpvroS!`qHy@WPlf7riEW~%*kE=Pmdo+ zq~PpQ5u45A9FxU$bfLGS?@N2hVxGqPL|i! zGNmCW5Flewyz-NaFUl1~KDo9r?;nnezY#T*!91Zo$|q2}{anq;x<0}SdRWJE!Z`OAur_kthytR|uQimslHdnFE-KdGM z93l7HyGoZ*O7Qsj4*}Q5z5R^tpEQt zdX)keR5=T*zQCek-E`8_^Eybx>CV%~$N0WIUvD*#^cC-R@4Fl5(`^t}{>~_?h|L8$ z8s#}E%6VjjUHDo!cjEW&){kIp{Wl+`E8cs07NXWyub z6>D^W>^jz&^q}s`Y*ddt^Rh=j++|5*P3IQ2&HEawiyPqY2Q++}f>%c;AB3II=IS{} zU@NM{b6sEcoW>sn{;K1Jde_Hsz|N*==98-6f0_Ab>08k9;?Lp&5ti7cK-nTZU|y0! zOM^Jfc{Vn%zRGDjTM%Jc<%nn=3g(IMm}Xi^L{@b(>Z#!_97~@&Rp+oCrb(FMh9s&` zfHBXoF)luypQ-gBdr7~y@^zkAfgkPCeSG>IKk2A#Wffmq**IyCXoOM~#@Rd4r;QL8 z(%K*h6j^ZF+e)*Spj$cU`}h%SCKn!lD}SVRCHUsu`#wrPB)f*jv!S(i)D?Cr>ss@2;&tO3M%Boz2-2lwH^jO!VP=Jjq z#hPzJZ1nbEJqvG0d{kZYTz@Xi_LO4+(z}#|_F$E=wZBIH>3Nokgtl(SO$$C$pDuc$ zR74p<`By1N)H{;q>@{-!_rVEF;5<^4JZTvgJDtzchdDATo0r+9lr=7TFzQ3DJ2g{R zBw=n?n`9sDcrXIeNjVEMIT;C&nl4h@_2W_p(gvgc)8nsZ#ZGo%R>s@nG^1><%lQc8 zN1T%8`hqtr`vaN-#fa6c9HiM7dyLIZjy^s+Yx8+RkMdXJNX>V4J#I@Eb0_@J>jtK{ zUK^jBMPvTXS=~jqtqOFRmZVTSMo|b%KQm>6Ra*?sb(`$On_>E~-hAOkgMvLpOCh9z zPLVUkGA+_n7xEV%D4J?ZMVnDS83h^CtOn`?mBJSW{jh_vvGh3~v2P=e}hVYD(I>LnTBIkc7ggm#l?$eo5IQyqbF*_m&b1BA9|9vb6 z`DZNme?DD()ImiYn<#SDsq^<7kGY}zO7?e;Ok*D8l%aJCA(mdJQyN3c@EQ?Cfm;+t zl`MjSg6zNGzH#?~qc{rtEdf2=d!k1m*f(1LpQVZ9rV&*jyG0R~9O{4W8Czbn{0*Lk}i_5vEJ zf;35Ex%_xtrg1GtO)}G94*6f4OT!DpV}=A%d?h~i2@H@!K|Gzuw-FXk4A7>`6ZXAu;{?`dWtkXcRWygSgu}3Hc}7)ye_qEVHu=)+3)su+D}4Vs*^mG4@{8(Z%I~f4-(6 zd-i#jqaJ8_R@!uCkq - ESP32-S2-DevKitM-1 <../hw-reference/esp32s2/user-guide-devkitm-1-v1> + ESP32-S2-DevKitM-1 ESP32-S2-DevKitC-1 <../hw-reference/esp32s2/user-guide-s2-devkitc-1> ESP32-S2-Kaluga-Kit <../hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit> diff --git a/docs/en/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst b/docs/en/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst deleted file mode 100644 index 5174afa98ee..00000000000 --- a/docs/en/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst +++ /dev/null @@ -1,321 +0,0 @@ -================== -ESP32-S2-DevKitM-1 -================== - -:link_to_translation:`zh_CN:[中文]` - -This user guide provides information on Espressif's small-sized development board ESP32-S2-DevKitM-1. - -ESP32-S2-DevKitM-1 is entry-level development board. Most of the I/O pins on the module are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S2-DevKitM-1 on a breadboard. - -+----------------------+-----------------------+ -| |ESP32-S2-DevKitM-1| | |ESP32-S2-DevKitM-1U| | -+----------------------+-----------------------+ -| ESP32-S2-DevKitM-1 | ESP32-S2-DevKitM-1U | -+----------------------+-----------------------+ - -.. |ESP32-S2-DevKitM-1| image:: ../../../_static/esp32-s2-devkitm-1-v1-isometric.png - -.. |ESP32-S2-DevKitM-1U| image:: ../../../_static/esp32-s2-devkitm-1u-v1-isometric.png - -The document consists of the following major sections: - -- `Getting started`_: Provides an overview of the ESP32-S2-DevKitM-1 and hardware/software setup instructions to get started. -- `Hardware reference`_: Provides more detailed information about the ESP32-S2-DevKitM-1's hardware. -- `Hardware Revision Details`_: Revision history, known issues, and links to user guides for previous versions (if any) of ESP32-S2-DevKitM-1. -- `Related Documents`_: Gives links to related documentation. - - -Getting Started -=============== - -This section describes how to get started with ESP32-S2-DevKitM-1. It begins with a few introductory sections about the ESP32-S2-DevKitM-1, then Section `Start Application Development`_ provides instructions on how to get the ESP32-S2-DevKitM-1 ready and flash firmware into it. - - -Contents and Packaging ----------------------- - - -.. _user-guide-s2-devkitm-1-v1-ordering-info: - -Ordering Information -^^^^^^^^^^^^^^^^^^^^ - -The development board has a variety of variants to choose from, as shown in the table below. - -.. list-table:: - :header-rows: 1 - :widths: 41 24 9 8 18 - - * - Ordering Code - - On-board Module [#]_ - - Flash - - PSRAM - - Antenna - * - ESP32-S2-DevKitM-1-N4R2 - - ESP32-S2-MINI-2 - - (Recommended) - - 4 MB - - 2 MB - - PCB on-board antenna - * - ESP32-S2-DevKitM-1U-N4R2 - - ESP32-S2-MINI-2U - - (Recommended) - - 4 MB - - 2 MB - - External antenna connector - * - ESP32-S2-DevKitM-1 - - ESP32-S2-MINI-1 - - 4 MB - - --- - - PCB on-board antenna - * - ESP32-S2-DevKitM-1U - - ESP32-S2-MINI-1U - - 4 MB - - --- - - External antenna connector - * - ESP32-S2-DevKitM-1R - - ESP32-S2-MINI-1 - - 4 MB - - 2 MB - - PCB on-board antenna - * - ESP32-S2-DevKitM-1RU - - ESP32-S2-MINI-1U - - 4 MB - - 2 MB - - External antenna connector - - -.. [#] The ESP32-S2-MINI-2 and ESP32-S2-MINI-2U modules use chip revision v1.0, and the rest use chip revision v0.0. For more information about chip revisions, please refer to `ESP32-S2 Series SoC Errata`_. - - -Retail Orders -^^^^^^^^^^^^^ - -If you order a few samples, each ESP32-S2-DevKitM-1 comes in an individual package in either antistatic bag or any packaging depending on your retailer. - -For retail orders, please go to https://www.espressif.com/en/contact-us/get-samples. - - -Wholesale Orders -^^^^^^^^^^^^^^^^ - -If you order in bulk, the boards come in large cardboard boxes. - -For wholesale orders, please go to https://www.espressif.com/en/contact-us/sales-questions. - - -Description of Components -------------------------- - -.. _user-guide-devkitm-1-v1-board-front: - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitM-1 - front - :figclass: align-center - - ESP32-S2-DevKitM-1 - front - -.. figure:: ../../../_static/esp32-s2-devkitm-1u-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitM-1U - front - :figclass: align-center - - ESP32-S2-DevKitM-1U - front - -The key components of the board are described in a clockwise direction. - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - Key Component - - Description - * - On-board module (ESP32-S2-MINI-1 or ESP32-S2-MINI-1U in figures above) - - ESP32-S2-MINI series modules with an on-board PCB antenna or a connector for an external antenna. This series of modules, known for its small size, have a flash and/or a PSRAM integrated in the chip package. For more information, please refer to :ref:`user-guide-s2-devkitm-1-v1-ordering-info`. - * - Pin Headers - - All available GPIO pins (except for the SPI bus for flash) are broken out to the pin headers on the board. Users can program ESP32-S2FH4 chip to enable multiple functions such as SPI, I2S, UART, I2C, touch sensors, PWM etc. For details, please see :ref:`user-guide-devkitm-1-v1-header-blocks`. - * - 3.3 V Power On LED - - Turns on when the USB power is connected to the board. - * - USB to UART Bridge - - Single USB-UART bridge chip provides transfer rates up to 3 Mbps. - * - Reset Button - - Reset button. - * - Micro-USB Port - - USB interface. Power supply for the board as well as the communication interface between a computer and the ESP32-S2FH4 chip. - * - Boot Button - - Download button. Holding down **Boot** and then pressing **Reset** initiates Firmware Download mode for downloading firmware through the serial port. - * - RGB LED - - Addressable RGB LED, driven by GPIO18. - * - 5 V to 3.3 V LDO - - Power regulator that converts a 5 V supply into a 3.3 V output. - * - External Antenna Connector - - On **ESP32-S2-MINI-2U** and **ESP32-S2-MINI-1U** module only. For connector dimensions, please refer to Section External Antenna Connector Dimensions in module datasheet. - - -Start Application Development ------------------------------ - -Before powering up your ESP32-S2-DevKitM-1, please make sure that it is in good condition with no obvious signs of damage. - - -Required Hardware -^^^^^^^^^^^^^^^^^ - -- ESP32-S2-DevKitM-1 -- USB 2.0 cable (Standard-A to Micro-B) -- Computer running Windows, Linux, or macOS - -.. note:: - - Be sure to use an appropriate USB cable. Some cables are for charging only and do not provide the needed data lines nor work for programming the boards. - - -Software Setup -^^^^^^^^^^^^^^ - -Please proceed to :doc:`../../get-started/index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an application example into your ESP32-S2-DevKitM-1. - -.. note:: - - ESP32-S2 series of chips only is only supported in ESP-IDF master or version v4.2 and higher. - - -Hardware Reference -================== - -Block Diagram -------------- - -A block diagram below shows the components of ESP32-S2-DevKitM-1 and their interconnections. - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-block-diagram.png - :align: center - :scale: 70% - :alt: ESP32-S2-DevKitM-1 (click to enlarge) - :figclass: align-center - - ESP32-S2-DevKitM-1 (click to enlarge) - - -Power Supply Options -^^^^^^^^^^^^^^^^^^^^ - -There are three mutually exclusive ways to provide power to the board: - -- Micro-USB Port, default power supply -- 5V and GND pin headers -- 3V3 and GND pin headers - -It is recommended to use the first option: micro USB Port. - - -.. _user-guide-devkitm-1-v1-header-blocks: - -Header Block ------------- - -The two tables below provide the **Name** and **Function** of the pin headers on both sides of the board (J1 and J3). The pin header names are shown in :ref:`user-guide-devkitm-1-v1-board-front`. The numbering is the same as in the `ESP32-S2-DevKitM-1 Schematics `_ (PDF). - - -J1 -^^^ - -=== ==== ========== ============================================================= -No. Name Type [#]_ Function -=== ==== ========== ============================================================= -1 3V3 P 3.3 V power supply -2 0 I/O/T RTC_GPIO0, GPIO0 -3 1 I/O/T RTC_GPIO1, GPIO1, TOUCH1, ADC1_CH0 -4 2 I/O/T RTC_GPIO2, GPIO2, TOUCH2, ADC1_CH1 -5 3 I/O/T RTC_GPIO3, GPIO3, TOUCH3, ADC1_CH2 -6 4 I/O/T RTC_GPIO4, GPIO4, TOUCH4, ADC1_CH3 -7 5 I/O/T RTC_GPIO5, GPIO5, TOUCH5, ADC1_CH4 -8 6 I/O/T RTC_GPIO6, GPIO6, TOUCH6, ADC1_CH5 -9 7 I/O/T RTC_GPIO7, GPIO7, TOUCH7, ADC1_CH6 -10 8 I/O/T RTC_GPIO8, GPIO8, TOUCH8, ADC1_CH7 -11 9 I/O/T RTC_GPIO9, GPIO9, TOUCH9, ADC1_CH8, FSPIHD -12 10 I/O/T RTC_GPIO10, GPIO10, TOUCH10, ADC1_CH9, FSPICS0, FSPIIO4 -13 11 I/O/T RTC_GPIO11, GPIO11, TOUCH11, ADC2_CH0, FSPID, FSPIIO5 -14 12 I/O/T RTC_GPIO12, GPIO12, TOUCH12, ADC2_CH1, FSPICLK, FSPIIO6 -15 13 I/O/T RTC_GPIO13, GPIO13, TOUCH13, ADC2_CH2, FSPIQ, FSPIIO7 -16 14 I/O/T RTC_GPIO14, GPIO14, TOUCH14, ADC2_CH3, FSPIWP, FSPIDQS -17 15 I/O/T RTC_GPIO15, GPIO15, U0RTS, ADC2_CH4, XTAL_32K_P -18 16 I/O/T RTC_GPIO16, GPIO16, U0CTS, ADC2_CH5, XTAL_32K_N -19 17 I/O/T RTC_GPIO17, GPIO17, U1TXD, ADC2_CH6, DAC_1 -20 5V P 5 V power supply -21 G G Ground -=== ==== ========== ============================================================= - - -J3 -^^^ - -=== ==== ===== ======================================================== -No. Name Type Function -=== ==== ===== ======================================================== -1 G G Ground -2 RST I CHIP_PU -3 46 I GPIO46 -4 45 I/O/T GPIO45 -5 RX I/O/T U0RXD, GPIO44, CLK_OUT2 -6 TX I/O/T U0TXD, GPIO43, CLK_OUT1 -7 42 I/O/T MTMS, GPIO42 -8 41 I/O/T MTDI, GPIO41, CLK_OUT1 -9 40 I/O/T MTDO, GPIO40, CLK_OUT2 -10 39 I/O/T MTCK, GPIO39, CLK_OUT3 -11 38 I/O/T GPIO38, FSPIWP -12 37 I/O/T SPIDQS, GPIO37, FSPIQ -13 36 I/O/T SPIIO7, GPIO36, FSPICLK -14 35 I/O/T SPIIO6, GPIO35, FSPID -15 34 I/O/T SPIIO5, GPIO34, FSPICS0 -16 33 I/O/T SPIIO4, GPIO33, FSPIHD -17 26 I/O/T SPICS1, GPIO26 -18 21 I/O/T RTC_GPIO21, GPIO21 -19 20 I/O/T RTC_GPIO20, GPIO20, U1CTS, ADC2_CH9, CLK_OUT1, USB_D+ -20 19 I/O/T RTC_GPIO19, GPIO19, U1RTS, ADC2_CH8, CLK_OUT2, USB_D- -21 18 I/O/T RTC_GPIO18, GPIO18, U1RXD, ADC2_CH7, DAC_2, CLK_OUT3, RGB LED -=== ==== ===== ======================================================== - -.. [#] P: Power supply; I: Input; O: Output; T: High impedance. - - -Pin Layout -^^^^^^^^^^^ - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-pin-layout.png - :align: center - :scale: 15% - :alt: ESP32-S2-DevKitM-1 (click to enlarge) - :figclass: align-center - - ESP32-S2-DevKitM-1 Pin Layout (click to enlarge) - - -Hardware Revision Details -========================= - -This is the first revision of this board released. - - -Related Documents -================= - -* `ESP32-S2 Series Chip Revision v1.0 Datasheet`_ (PDF) -* `ESP32-S2 Series Chip Revision v0.0 Datasheet `_ (PDF) -* `ESP32-S2 Series SoC Errata`_ (PDF) -* `ESP32-S2-MINI-2 & ESP32-S2-MINI-2U Module Datasheet `_ (PDF) -* `ESP32-S2-MINI-1 & ESP32-S2-MINI-1U Module Datasheet `_ (PDF) -* `ESP32-S2-DevKitM-1 Schematics `_ (PDF) -* `ESP32-S2-DevKitM-1 PCB Layout `_ (PDF) -* `ESP32-S2-DevKitM-1 Dimensions `_ (PDF) -* `ESP Product Selector `_ - -For other design documentation for the board, please contact us at `sales@espressif.com `_. - -.. _NRND: https://www.espressif.com/en/products/longevity-commitment?id=nrnd -.. _ESP32-S2 Series Chip Revision v1.0 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s2-v1.0_datasheet_en.pdf -.. _ESP32-S2 Series SoC Errata: https://espressif.com/sites/default/files/documentation/esp32-s2_errata_en.pdf diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index d651c66a7e9..44c994e89c7 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -122,7 +122,7 @@ :maxdepth: 1 ESP32-S2-Saola-1 <../hw-reference/esp32s2/user-guide-saola-1-v1.2> - ESP32-S2-DevKitM-1 <../hw-reference/esp32s2/user-guide-devkitm-1-v1> + ESP32-S2-DevKitM-1 ESP32-S2-DevKitC-1 <../hw-reference/esp32s2/user-guide-s2-devkitc-1> ESP32-S2-Kaluga-Kit <../hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit> diff --git a/docs/zh_CN/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst b/docs/zh_CN/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst deleted file mode 100644 index 03e03e38de7..00000000000 --- a/docs/zh_CN/hw-reference/esp32s2/user-guide-devkitm-1-v1.rst +++ /dev/null @@ -1,321 +0,0 @@ -================== -ESP32-S2-DevKitM-1 -================== - -:link_to_translation:`en: [English]` - -本指南介绍了乐鑫的小型开发板 ESP32-S2-DevKitM-1。 - -ESP32-S2-DevKitM-1 是乐鑫一款入门级开发板。板上模组大部分管脚均已引出至两侧排针,开发人员可根据实际需求,轻松通过跳线连接多种外围设备,同时也可将开发板插在面包板上使用。 - -+----------------------+-----------------------+ -| |ESP32-S2-DevKitM-1| | |ESP32-S2-DevKitM-1U| | -+----------------------+-----------------------+ -| ESP32-S2-DevKitM-1 | ESP32-S2-DevKitM-1U | -+----------------------+-----------------------+ - -.. |ESP32-S2-DevKitM-1| image:: ../../../_static/esp32-s2-devkitm-1-v1-isometric.png - -.. |ESP32-S2-DevKitM-1U| image:: ../../../_static/esp32-s2-devkitm-1u-v1-isometric.png - -本指南包括如下内容: - -- `入门指南`_: 简要介绍了 ESP32-S2-DevKitM-1 和硬件、软件设置指南。 -- `硬件参考`_: 详细介绍了 ESP32-S2-DevKitM-1 的硬件。 -- `硬件版本`_:介绍硬件历史版本和已知问题,并提供链接至历史版本开发板的入门指南(如有)。 -- `相关文档`_: 列出了相关文档的链接。 - - -入门指南 -======== - -本节介绍了如何快速上手 ESP32-S2-DevKitM-1。开头部分介绍了 ESP32-S2-DevKitM-1,`开始开发应用`_ 小节介绍了怎样在 ESP32-S2-DevKitM-1 上烧录固件及相关准备工作。 - - -内含组件和包装 --------------- - - -.. _user-guide-devkitm-1-v1-ordering-info: - -订购信息 -^^^^^^^^ - -该开发板有多种型号可供选择,详见下表。 - -.. list-table:: - :header-rows: 1 - :widths: 30 30 10 10 20 - - * - 订购代码 - - 搭载模组 [#]_ - - Flash - - PSRAM - - 天线 - * - ESP32-S2-DevKitM-1-N4R2 - - ESP32-S2-MINI-1-2 - - (推荐) - - 4 MB - - 2 MB - - PCB 板载天线 - * - ESP32-S2-DevKitM-1U-N4R2 - - ESP32-S2-MINI-1-2U - - (推荐) - - 4 MB - - 2 MB - - 外部天线连接器 - * - ESP32-S2-DevKitM-1 - - ESP32-S2-MINI-1 - - 4 MB - - --- - - PCB 板载天线 - * - ESP32-S2-DevKitM-1U - - ESP32-S2-MINI-1U - - 4 MB - - --- - - 外部天线连接器 - * - ESP32-S2-DevKitM-1R - - ESP32-S2-MINI-1 - - 4 MB - - 2 MB - - PCB 板载天线 - * - ESP32-S2-DevKitM-1RU - - ESP32-S2-MINI-1U - - 4 MB - - 2 MB - - 外部天线连接器 - - -.. [#] ESP32-S2-MINI-2 和 ESP32-S2-MINI-2U 模组使用 v1.0 版本芯片,其余模组使用 v0.0 版本芯片。更多关于芯片版本的信息,请参考 `《ESP32-S2 系列芯片勘误表》`_。 - - -零售订单 -^^^^^^^^ - -如购买样品,每个 ESP32-S2-DevKitM-1 开发板将以防静电袋或零售商选择的其他方式包装。 - -零售订单请前往 https://www.espressif.com/zh-hans/company/contact/buy-a-sample。 - - -批量订单 -^^^^^^^^ - -如批量购买,ESP32-S2-DevKitM-1 开发板将以大纸板箱包装。 - -批量订单请前往 https://www.espressif.com/zh-hans/contact-us/sales-questions。 - - -组件介绍 --------- - -.. _user-guide-devkitm-1-v1-board-front: - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitM-1 - 正面 - :figclass: align-center - - ESP32-S2-DevKitM-1 - 正面 - -.. figure:: ../../../_static/esp32-s2-devkitm-1u-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitM-1U - 正面 - :figclass: align-center - - ESP32-S2-DevKitM-1U - 正面 - -以下按照顺时针的顺序依次介绍开发板上的主要组件。 - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - 主要组件 - - 介绍 - * - 板载模组(上图中为 ESP32-S2-MINI-1 或 ESP32-S2-MINI-1U) - - ESP32-S2-MINI 系列模组,可搭载 PCB 板载天线或外部天线连接器。该系列模组尺寸小,flash 和/或 PSRAM 集成在芯片封装内。更多信息,详见 :ref:`user-guide-devkitm-1-v1-ordering-info`。 - * - Pin Headers(排针) - - 所有可用 GPIO 管脚(除 flash 的 SPI 总线)均已引出至开发板的排针。用户可对 ESP32-S2FH4 芯片编程,使能 SPI、I2S、UART、I2C、触摸传感器、PWM 等多种功能。请查看 :ref:`user-guide-devkitm-1-v1-header-blocks` 获取更多信息。 - * - 3.3 V Power On LED(3.3 V 电源指示灯) - - 开发板连接 USB 电源后,该指示灯亮起。 - * - USB-to-UART Bridge(USB 转 UART 桥接器) - - 单芯片 USB 至 UART 桥接器,可提供高达 3 Mbps 的传输速率。 - * - Reset Button(Reset 键) - - 复位按键。 - * - Micro-USB(Micro-USB 接口) - - USB 接口。可用作开发板的供电电源或 PC 和 ESP32-S2FH4 芯片的通信接口。 - * - Boot Button(Boot 键) - - 下载按键。按住 **Boot** 键的同时按一下 **Reset** 键进入“固件下载”模式,通过串口下载固件。 - * - RGB LED - - 可寻址 RGB 发光二极管,由 GPIO18 驱动。 - * - 5 V to 3.3 V LDO(5 V 转 3.3 V LDO) - - 电源转换器,输入 5 V,输出 3.3 V。 - * - External Antenna Connector(外部天线连接器) - - 仅 **ESP32-S2-MINI-2U** 和 **ESP32-S2-MINI-1U** 模组带有外部天线连接器。连接器尺寸,请参考模组规格书的 外部天线连接器尺寸章节。 - - -开始开发应用 ------------- - -通电前,请确保 ESP32-S2-DevKitM-1 完好无损。 - - -必备硬件 -^^^^^^^^ - -- ESP32-S2-DevKitM-1 -- USB 2.0 数据线(标准 A 型转 Micro-B 型) -- 电脑(Windows、Linux 或 macOS) - -.. 注解:: - - 请确保使用适当的 USB 数据线。部分数据线仅可用于充电,无法用于数据传输和编程。 - - -软件设置 -^^^^^^^^ - -请前往 :doc:`../../get-started/index`,在 :ref:`get-started-step-by-step` 一节查看如何快速设置开发环境,将应用程序烧录至 ESP32-S2-DevKitM-1。 - -.. 注解:: - - ESP32-S2 系列芯片仅支持 ESP-IDF master 分支或 v4.2 以上版本。 - - -硬件参考 -======== - -功能框图 --------- - -ESP32-S2-DevKitM-1 的主要组件和连接方式如下图所示。 - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-block-diagram.png - :align: center - :scale: 70% - :alt: ESP32-S2-DevKitM-1 (点击放大) - :figclass: align-center - - ESP32-S2-DevKitM-1 (点击放大) - - -电源选项 -^^^^^^^^ - -以下任一供电方式均可给 ESP32-S2-DevKitM-1 供电: - -- Micro-USB 接口供电(默认) -- 5V 和 GND 排针供电 -- 3V3 和 GND 排针供电 - -建议选择第一种供电方式:micro USB 接口供电。 - - -.. _user-guide-devkitm-1-v1-header-blocks: - -排针 ----- - -下表列出了开发板两侧排针(J1 和 J3)的 **名称** 和 **功能**,排针的名称如图 :ref:`user-guide-devkitm-1-v1-board-front` 所示,排针的序号与 `ESP32-S2-DevKitM-1 原理图 `_ (PDF) 一致。 - - -J1 -^^^ - -==== ==== ========= ========================================================================= -序号 名称 类型 [#]_ 功能 -==== ==== ========= ========================================================================= -1 3V3 P 3.3 V 电源 -2 0 I/O/T RTC_GPIO0, GPIO0 -3 1 I/O/T RTC_GPIO1, GPIO1, TOUCH1, ADC1_CH0 -4 2 I/O/T RTC_GPIO2, GPIO2, TOUCH2, ADC1_CH1 -5 3 I/O/T RTC_GPIO3, GPIO3, TOUCH3, ADC1_CH2 -6 4 I/O/T RTC_GPIO4, GPIO4, TOUCH4, ADC1_CH3 -7 5 I/O/T RTC_GPIO5, GPIO5, TOUCH5, ADC1_CH4 -8 6 I/O/T RTC_GPIO6, GPIO6, TOUCH6, ADC1_CH5 -9 7 I/O/T RTC_GPIO7, GPIO7, TOUCH7, ADC1_CH6 -10 8 I/O/T RTC_GPIO8, GPIO8, TOUCH8, ADC1_CH7 -11 9 I/O/T RTC_GPIO9, GPIO9, TOUCH9, ADC1_CH8, FSPIHD -12 10 I/O/T RTC_GPIO10, GPIO10, TOUCH10, ADC1_CH9, FSPICS0, FSPIIO4 -13 11 I/O/T RTC_GPIO11, GPIO11, TOUCH11, ADC2_CH0, FSPID, FSPIIO5 -14 12 I/O/T RTC_GPIO12, GPIO12, TOUCH12, ADC2_CH1, FSPICLK, FSPIIO6 -15 13 I/O/T RTC_GPIO13, GPIO13, TOUCH13, ADC2_CH2, FSPIQ, FSPIIO7 -16 14 I/O/T RTC_GPIO14, GPIO14, TOUCH14, ADC2_CH3, FSPIWP, FSPIDQS -17 15 I/O/T RTC_GPIO15, GPIO15, U0RTS, ADC2_CH4, XTAL_32K_P -18 16 I/O/T RTC_GPIO16, GPIO16, U0CTS, ADC2_CH5, XTAL_32K_N -19 17 I/O/T RTC_GPIO17, GPIO17, U1TXD, ADC2_CH6, DAC_1 -20 5V P 5 V 电源 -21 G G 接地 -==== ==== ========= ========================================================================= - - -J3 -^^^ - -==== ==== ===== ======================================================== -序号 名称 类型 功能 -==== ==== ===== ======================================================== -1 G G 接地 -2 RST I CHIP_PU -3 46 I GPIO46 -4 45 I/O/T GPIO45 -5 RX I/O/T U0RXD, GPIO44, CLK_OUT2 -6 TX I/O/T U0TXD, GPIO43, CLK_OUT1 -7 42 I/O/T MTMS, GPIO42 -8 41 I/O/T MTDI, GPIO41, CLK_OUT1 -9 40 I/O/T MTDO, GPIO40, CLK_OUT2 -10 39 I/O/T MTCK, GPIO39, CLK_OUT3 -11 38 I/O/T GPIO38, FSPIWP -12 37 I/O/T SPIDQS, GPIO37, FSPIQ -13 36 I/O/T SPIIO7, GPIO36, FSPICLK -14 35 I/O/T SPIIO6, GPIO35, FSPID -15 34 I/O/T SPIIO5, GPIO34, FSPICS0 -16 33 I/O/T SPIIO4, GPIO33, FSPIHD -17 26 I/O/T SPICS1, GPIO26 -18 21 I/O/T RTC_GPIO21, GPIO21 -19 20 I/O/T RTC_GPIO20, GPIO20, U1CTS, ADC2_CH9, CLK_OUT1, USB_D+ -20 19 I/O/T RTC_GPIO19, GPIO19, U1RTS, ADC2_CH8, CLK_OUT2, USB_D- -21 18 I/O/T RTC_GPIO18, GPIO18, U1RXD, ADC2_CH7, DAC_2, CLK_OUT3, RGB LED -==== ==== ===== ======================================================== - -.. [#] P:电源;I:输入;O:输出;T:可设置为高阻。 - - -管脚布局 -^^^^^^^^ - -.. figure:: ../../../_static/esp32-s2-devkitm-1-v1-pin-layout.png - :align: center - :scale: 15% - :alt: ESP32-S2-DevKitM-1 管脚布局(点击放大) - :figclass: align-center - - ESP32-S2-DevKitM-1 管脚布局(点击放大) - - -硬件版本 -========== - -无历史版本。 - - -相关文档 -======== - -* `ESP32-S2 系列芯片 v1.0 版本技术规格书`_ (PDF) -* `ESP32-S2 系列芯片 v0.0 版本技术规格书 `_ (PDF) -* `《ESP32-S2 系列芯片勘误表》`_ (PDF) -* `《ESP32-S2-MINI-2 & ESP32-S2-MINI-2U 技术规格书》 `_ (PDF) -* `《ESP32-S2-MINI-1 & ESP32-S2-MINI-1U 技术规格书》 `_ (PDF) -* `ESP32-S2-DevKitM-1 原理图 `_ (PDF) -* `ESP32-S2-DevKitM-1 PCB 布局 `_ (PDF) -* `ESP32-S2-DevKitM-1 尺寸图 `_ (PDF) -* `乐鑫产品选型工具 `__ - -有关本开发板的更多设计文档,请联系我们的商务部门 `sales@espressif.com `_。 - -.. _不推荐用于新设计: https://www.espressif.com/zh-hans/products/longevity-commitment -.. _ESP32-S2 系列芯片 v1.0 版本技术规格书: https://www.espressif.com/sites/default/files/documentation/esp32-s2-v1.0_datasheet_cn.pdf -.. _《ESP32-S2 系列芯片勘误表》: https://espressif.com/sites/default/files/documentation/esp32-s2_errata_cn.pdf From 7e5ab45fbb84fbd69b0ebf51a6fab0c3d62004fe Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 20 Jun 2024 12:22:56 +0800 Subject: [PATCH 275/548] ci(rom): disable rom wdt test on C5 --- components/esp_rom/test_apps/.build-test-rules.yml | 1 + components/esp_rom/test_apps/rom_impl_components/README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/test_apps/.build-test-rules.yml b/components/esp_rom/test_apps/.build-test-rules.yml index 7f94e30b596..dc4f83d5510 100644 --- a/components/esp_rom/test_apps/.build-test-rules.yml +++ b/components/esp_rom/test_apps/.build-test-rules.yml @@ -9,6 +9,7 @@ components/esp_rom/test_apps/rom_impl_components: # For ROM impl build tests, disable them if none of the tested features are supported in the ROM - if: CONFIG_NAME == "rom_impl_components" and ((ESP_ROM_HAS_HAL_WDT != 1 and ESP_ROM_HAS_HAL_SYSTIMER != 1) and (ESP_ROM_HAS_HEAP_TLSF != 1 and ESP_ROM_HAS_SPI_FLASH != 1)) - if: CONFIG_NAME == "no_rom_impl_components" and ((ESP_ROM_HAS_HAL_WDT != 1 and ESP_ROM_HAS_HAL_SYSTIMER != 1) and (ESP_ROM_HAS_HEAP_TLSF != 1 and ESP_ROM_HAS_SPI_FLASH != 1)) + - if: SOC_WDT_SUPPORTED == 0 components/esp_rom/test_apps/rom_tests: disable_test: diff --git a/components/esp_rom/test_apps/rom_impl_components/README.md b/components/esp_rom/test_apps/rom_impl_components/README.md index 3a502b1f86f..bf47d80ec64 100644 --- a/components/esp_rom/test_apps/rom_impl_components/README.md +++ b/components/esp_rom/test_apps/rom_impl_components/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | From 14d93dea7550be2e3f8c56ce4119698b81546fee Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 8 May 2024 15:17:02 +0300 Subject: [PATCH 276/548] feat(soc): Update efuse related soc_caps for c61 and c5 (MP/beta3) --- .../keys/with_key_purposes/esp_efuse_api_key.c | 4 ++-- .../main/with_key_purposes/test_efuse_keys.c | 10 +++++----- components/hal/efuse_hal.c | 2 +- components/hal/esp32c61/include/hal/efuse_ll.h | 15 +++++++++++++++ components/hal/include/hal/efuse_hal.h | 2 +- .../esp32c5/beta3/include/soc/Kconfig.soc_caps.in | 4 ++++ .../soc/esp32c5/beta3/include/soc/soc_caps.h | 2 +- .../esp32c5/mp/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c5/mp/include/soc/soc_caps.h | 2 +- .../soc/esp32c61/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32c61/include/soc/soc_caps.h | 2 +- .../soc/esp32h2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32h2/include/soc/soc_caps.h | 1 + .../soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + 15 files changed, 46 insertions(+), 13 deletions(-) diff --git a/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c b/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c index 0d48b1fd4e3..aa8a464ef9f 100644 --- a/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c +++ b/components/efuse/src/efuse_controller/keys/with_key_purposes/esp_efuse_api_key.c @@ -288,7 +288,7 @@ esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpo purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 || purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 || #endif -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY || #endif purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY)) { @@ -303,7 +303,7 @@ esp_err_t esp_efuse_write_key(esp_efuse_block_t block, esp_efuse_purpose_t purpo purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 || purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 || #endif //#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY || #endif #if SOC_KEY_MANAGER_SUPPORTED diff --git a/components/efuse/test_apps/main/with_key_purposes/test_efuse_keys.c b/components/efuse/test_apps/main/with_key_purposes/test_efuse_keys.c index 13452f0989e..f6a49cfa829 100644 --- a/components/efuse/test_apps/main/with_key_purposes/test_efuse_keys.c +++ b/components/efuse/test_apps/main/with_key_purposes/test_efuse_keys.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,7 +63,7 @@ TEST_CASE("Test efuse API blocks burning XTS and ECDSA keys into BLOCK9", "[efus purpose = ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2; TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_write_key(EFUSE_BLK9, purpose, &key, sizeof(key))); #endif -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY purpose = ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY; TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_efuse_write_key(EFUSE_BLK9, purpose, &key, sizeof(key))); #endif @@ -90,7 +90,7 @@ static esp_err_t s_check_key(esp_efuse_block_t num_key, void* wr_key) purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 || purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 || #endif -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY || #endif purpose == ESP_EFUSE_KEY_PURPOSE_HMAC_DOWN_ALL || @@ -169,7 +169,7 @@ TEST_CASE("Test esp_efuse_write_key for virt mode", "[efuse]") purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_1 || purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_256_KEY_2 || #endif //#ifdef SOC_EFUSE_SUPPORT_XTS_AES_256_KEYS -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY purpose == ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY || #endif purpose == ESP_EFUSE_KEY_PURPOSE_XTS_AES_128_KEY)) { @@ -204,7 +204,7 @@ TEST_CASE("Test 1 esp_efuse_write_key for FPGA", "[efuse]") esp_efuse_purpose_t purpose [] = { ESP_EFUSE_KEY_PURPOSE_USER, -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY ESP_EFUSE_KEY_PURPOSE_ECDSA_KEY, #else ESP_EFUSE_KEY_PURPOSE_RESERVED, diff --git a/components/hal/efuse_hal.c b/components/hal/efuse_hal.c index 68e06d530a8..8c15849d8fc 100644 --- a/components/hal/efuse_hal.c +++ b/components/hal/efuse_hal.c @@ -47,7 +47,7 @@ IRAM_ATTR bool efuse_hal_flash_encryption_enabled(void) return enabled; } -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY void efuse_hal_set_ecdsa_key(int efuse_blk) { efuse_ll_set_ecdsa_key_blk(efuse_blk); diff --git a/components/hal/esp32c61/include/hal/efuse_ll.h b/components/hal/esp32c61/include/hal/efuse_ll.h index 1c5238d2e6c..c219dc2999b 100644 --- a/components/hal/esp32c61/include/hal/efuse_ll.h +++ b/components/hal/esp32c61/include/hal/efuse_ll.h @@ -84,6 +84,16 @@ __attribute__((always_inline)) static inline uint32_t efuse_ll_get_chip_ver_pkg( return (uint32_t)0; } +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_ecdsa_key_blk(void) +{ + return EFUSE0.conf.cfg_ecdsa_blk; +} + +__attribute__((always_inline)) static inline void efuse_ll_set_ecdsa_key_blk(int efuse_blk) +{ + EFUSE0.conf.cfg_ecdsa_blk = efuse_blk; +} + /******************* eFuse control functions *************************/ __attribute__((always_inline)) static inline bool efuse_ll_get_read_cmd(void) @@ -137,6 +147,11 @@ __attribute__((always_inline)) static inline void efuse_ll_set_pwr_off_num(uint1 EFUSE0.wr_tim_conf2.pwr_off_num = value; } +__attribute__((always_inline)) static inline void efuse_ll_rs_bypass_update(void) +{ + EFUSE0.wr_tim_conf0_rs_bypass.update = 1; +} + /******************* eFuse control functions *************************/ #ifdef __cplusplus diff --git a/components/hal/include/hal/efuse_hal.h b/components/hal/include/hal/efuse_hal.h index 240c1ab1350..ce4aaf1eee0 100644 --- a/components/hal/include/hal/efuse_hal.h +++ b/components/hal/include/hal/efuse_hal.h @@ -61,7 +61,7 @@ uint32_t efuse_hal_get_major_chip_version(void); */ uint32_t efuse_hal_get_minor_chip_version(void); -#if SOC_ECDSA_SUPPORTED +#if SOC_EFUSE_ECDSA_KEY /** * @brief Set the efuse block that should be used as ECDSA private key * diff --git a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in index fec9d4ad5db..51f555389be 100644 --- a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in @@ -571,6 +571,10 @@ config SOC_TIMER_GROUP_TOTAL_TIMERS int default 2 +config SOC_EFUSE_ECDSA_KEY + bool + default y + config SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS int default 3 diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index de656045300..4e8f3f99af9 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -463,7 +463,7 @@ // #define SOC_EFUSE_DIS_DIRECT_BOOT 1 // #define SOC_EFUSE_SOFT_DIS_JTAG 1 // #define SOC_EFUSE_DIS_ICACHE 1 -// #define SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK 1 // XTS-AES key purpose not supported for this block +#define SOC_EFUSE_ECDSA_KEY 1 /*-------------------------- Secure Boot CAPS----------------------------*/ // #define SOC_SECURE_BOOT_V2_RSA 1 diff --git a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in index e51199cc96d..8b61d088e9f 100644 --- a/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/mp/include/soc/Kconfig.soc_caps.in @@ -351,6 +351,10 @@ config SOC_TIMER_GROUP_TOTAL_TIMERS int default 2 +config SOC_EFUSE_ECDSA_KEY + bool + default y + config SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS int default 3 diff --git a/components/soc/esp32c5/mp/include/soc/soc_caps.h b/components/soc/esp32c5/mp/include/soc/soc_caps.h index 79223254a09..b49d69e530b 100644 --- a/components/soc/esp32c5/mp/include/soc/soc_caps.h +++ b/components/soc/esp32c5/mp/include/soc/soc_caps.h @@ -458,7 +458,7 @@ // #define SOC_EFUSE_DIS_DIRECT_BOOT 1 // #define SOC_EFUSE_SOFT_DIS_JTAG 1 // #define SOC_EFUSE_DIS_ICACHE 1 -// #define SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK 1 // XTS-AES key purpose not supported for this block +#define SOC_EFUSE_ECDSA_KEY 1 /*-------------------------- Secure Boot CAPS----------------------------*/ // #define SOC_SECURE_BOOT_V2_RSA 1 diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index f77de6e2ff9..3585115350b 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -795,7 +795,7 @@ config SOC_EFUSE_DIS_ICACHE bool default y -config SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK +config SOC_EFUSE_ECDSA_KEY bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 9ed294cbea2..802b85fa285 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -452,7 +452,7 @@ #define SOC_EFUSE_DIS_DIRECT_BOOT 1 #define SOC_EFUSE_SOFT_DIS_JTAG 0 #define SOC_EFUSE_DIS_ICACHE 1 -#define SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK 1 // XTS-AES key purpose not supported for this block +#define SOC_EFUSE_ECDSA_KEY 1 /*-------------------------- Secure Boot CAPS----------------------------*/ #define SOC_SECURE_BOOT_V2_RSA 0 diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 9ebdecb32cd..2a611faab31 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1171,6 +1171,10 @@ config SOC_EFUSE_ECDSA_USE_HARDWARE_K bool default y +config SOC_EFUSE_ECDSA_KEY + bool + default y + config SOC_SECURE_BOOT_V2_RSA bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 8728e3f730d..1ebfce96269 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -458,6 +458,7 @@ #define SOC_EFUSE_DIS_ICACHE 1 #define SOC_EFUSE_BLOCK9_KEY_PURPOSE_QUIRK 1 // XTS-AES and ECDSA key purposes not supported for this block #define SOC_EFUSE_ECDSA_USE_HARDWARE_K 1 // Force use hardware TRNG supplied K for ECDSA +#define SOC_EFUSE_ECDSA_KEY 1 /*-------------------------- Secure Boot CAPS----------------------------*/ #define SOC_SECURE_BOOT_V2_RSA 1 diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 7c9036b62bf..bd69a4b750f 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1423,6 +1423,10 @@ config SOC_EFUSE_DIS_DOWNLOAD_MSPI bool default y +config SOC_EFUSE_ECDSA_KEY + bool + default y + config SOC_SECURE_BOOT_V2_RSA bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 60f0faa36f7..3072daf2ee9 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -562,6 +562,7 @@ #define SOC_EFUSE_SOFT_DIS_JTAG 1 /* Capability to disable the MSPI access in download mode */ #define SOC_EFUSE_DIS_DOWNLOAD_MSPI 1 +#define SOC_EFUSE_ECDSA_KEY 1 /*-------------------------- Secure Boot CAPS----------------------------*/ #define SOC_SECURE_BOOT_V2_RSA 1 From 9e95b9b29c9eb84d694bebdd7aa184f47fe3252f Mon Sep 17 00:00:00 2001 From: Shyamal Khachane Date: Thu, 20 Jun 2024 14:36:44 +0530 Subject: [PATCH 277/548] fix(esp_wifi): Backport some fixes to v5.3 1. Fix issue of station PMF not getting reset when disconnecing from PMF connection 2. Fix a memory leak that occurs when the SAE connection is interrupted 3. Drop any received auth responses that use a different algorithm than the one currently in use --- components/esp_wifi/lib | 2 +- components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index fda241ceff8..eacd07f165f 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit fda241ceff83a34609c9fc132d3e19916969f2c8 +Subproject commit eacd07f165fee254b37ee5819208e1185549ec59 diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 32f8efec0e1..5d1281f6d8d 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -294,7 +294,6 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) case WIFI_REASON_ASSOC_FAIL: case WIFI_REASON_CONNECTION_FAIL: case WIFI_REASON_HANDSHAKE_TIMEOUT: - esp_wpa3_free_sae_data(); wpa_sta_clear_curr_pmksa(); wpa_sm_notify_disassoc(&gWpaSm); break; @@ -308,6 +307,7 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) owe_deinit(); #endif /* CONFIG_OWE_STA */ + esp_wpa3_free_sae_data(); supplicant_sta_disconn_handler(reason_code); } From 357e0f9bf16222b8c0a7a090c106eca6347c8195 Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Mon, 29 Apr 2024 15:43:53 +0200 Subject: [PATCH 278/548] docs(esp_hw_support): Adjusted RNG docs to reflect P4 changes --- docs/docs_not_updated/esp32p4.txt | 1 - docs/en/api-reference/system/random.rst | 30 ++++++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 96340c579b6..5a2b69eddea 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -43,6 +43,5 @@ api-reference/network/esp_nan.rst api-reference/network/esp_wifi.rst api-reference/network/index.rst api-reference/system/sleep_modes.rst -api-reference/system/random.rst api-reference/system/power_management.rst api-reference/system/inc/power_management_esp32p4.rst diff --git a/docs/en/api-reference/system/random.rst b/docs/en/api-reference/system/random.rst index abca5925d06..4a71b1ef0b2 100644 --- a/docs/en/api-reference/system/random.rst +++ b/docs/en/api-reference/system/random.rst @@ -5,15 +5,16 @@ Random Number Generation {IDF_TARGET_RF_NAME: default="Wi-Fi or Bluetooth", esp32s2="Wi-Fi", esp32h2="Bluetooth or 802.15.4 Thread/Zigbee", esp32c6="Wi-Fi or Bluetooth or 802.15.4 Thread/Zigbee"} {IDF_TARGET_RF_IS: default="are", esp32s2="is"} -{IDF_TARGET_BOOTLOADER_RANDOM_INCOMPATIBLE: default="", esp32="I2S, "} {IDF_TARGET_NAME} contains a hardware random number generator (RNG). You can use the APIs :cpp:func:`esp_random` and :cpp:func:`esp_fill_random` to obtained random values from it. The hardware RNG produces true random numbers so long as one or more of the following conditions are met: -- RF subsystem is enabled. i.e., {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} enabled. -- An internal entropy source has been enabled by calling :cpp:func:`bootloader_random_enable` and not yet disabled by calling :cpp:func:`bootloader_random_disable`. -- While the ESP-IDF :ref:`second-stage-bootloader` is running. This is because the default ESP-IDF bootloader implementation calls :cpp:func:`bootloader_random_enable` when the bootloader starts, and :cpp:func:`bootloader_random_disable` before executing the application. +.. list:: + + :SOC_WIFI_SUPPORTED or SOC_IEEE802154_SUPPORTED or SOC_BT_SUPPORTED: - RF subsystem is enabled. i.e., {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} enabled. + - The internal entropy source (SAR ADC) has been enabled by calling :cpp:func:`bootloader_random_enable` and not yet disabled by calling :cpp:func:`bootloader_random_disable`. + - While the ESP-IDF :ref:`second-stage-bootloader` is running. This is because the default ESP-IDF bootloader implementation calls :cpp:func:`bootloader_random_enable` when the bootloader starts, and :cpp:func:`bootloader_random_disable` before executing the application. When any of these conditions are true, samples of physical noise are continuously mixed into the internal hardware RNG state to provide entropy. Consult the **{IDF_TARGET_NAME} Technical Reference Manual** > **Random Number Generator (RNG)** [`PDF <{IDF_TARGET_TRM_EN_URL}#rng>`__] chapter for more details. @@ -22,9 +23,26 @@ If none of the above conditions are true, the output of the RNG should be consid Startup ------- -During startup, ESP-IDF bootloader temporarily enables a non-RF entropy source (internal reference voltage noise) that provides entropy for any first boot key generation. However, after the application starts executing, then normally only pseudo-random numbers are available until {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} initialized. +During startup, the ESP-IDF bootloader temporarily enables the non-RF internal entropy source (SAR ADC using internal reference voltage noise) that provides entropy for any first boot key generation. + +.. only:: not SOC_WIFI_SUPPORTED and not SOC_IEEE802154_SUPPORTED and not SOC_BT_SUPPORTED + + However, after the application starts executing, then normally only pseudo-random numbers are available until the internal entropy source has been enabled again. + +.. only:: SOC_WIFI_SUPPORTED or SOC_IEEE802154_SUPPORTED or SOC_BT_SUPPORTED + + However, after the application starts executing, then normally only pseudo-random numbers are available until {IDF_TARGET_RF_NAME} {IDF_TARGET_RF_IS} initialized or until the internal entropy source has been enabled again. + + +To re-enable the entropy source temporarily during application startup, or for an application that does not use {IDF_TARGET_RF_NAME}, call the function :cpp:func:`bootloader_random_enable` to re-enable the internal entropy source. The function :cpp:func:`bootloader_random_disable` must be called to disable the entropy source again before using any of the following features: + +.. list:: + + - ADC + + :esp32: - I2S -To re-enable the entropy source temporarily during application startup, or for an application that does not use {IDF_TARGET_RF_NAME}, call the function :cpp:func:`bootloader_random_enable` to re-enable the internal entropy source. The function :cpp:func:`bootloader_random_disable` must be called to disable the entropy source again before using ADC, {IDF_TARGET_BOOTLOADER_RANDOM_INCOMPATIBLE} {IDF_TARGET_RF_NAME}. + :SOC_WIFI_SUPPORTED or SOC_IEEE802154_SUPPORTED or SOC_BT_SUPPORTED: - {IDF_TARGET_RF_NAME} .. note:: From 9fbec0a819813ca3796b1f9a9dfbf590dcdacde9 Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 12 Jun 2024 21:04:26 +0800 Subject: [PATCH 279/548] feat(bluetooth/controller): update controller api name on ESP32-C6 and ESP32-H2 --- components/bt/controller/esp32c6/bt.c | 66 ++++++++------- components/bt/controller/esp32h2/bt.c | 83 ++++++++++--------- .../bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- .../bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- .../bt/porting/nimble/src/os_msys_init.c | 8 +- components/esp_hw_support/modem_clock.c | 4 +- 6 files changed, 92 insertions(+), 73 deletions(-) diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index ed005edc70d..c27045ee176 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -123,7 +123,7 @@ typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); ************************************************************************ */ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); -extern int ble_controller_init(esp_bt_controller_config_t *cfg); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int r_ble_log_deinit_async(void); @@ -131,12 +131,12 @@ extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); extern void r_ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_controller_deinit(void); -extern int ble_controller_enable(uint8_t mode); -extern int ble_controller_disable(void); +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); extern int esp_register_ext_funcs (struct ext_funcs_t *); extern void esp_unregister_ext_funcs (void); -extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); @@ -149,17 +149,19 @@ extern int os_msys_init(void); extern void os_msys_deinit(void); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); -extern void esp_ble_set_wakeup_overhead(uint32_t overhead); +extern void r_esp_ble_set_wakeup_overhead(uint32_t overhead); #endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ -extern void esp_ble_change_rtc_freq(uint32_t freq); +extern void r_esp_ble_change_rtc_freq(uint32_t freq); extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); -extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); -extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; extern uint32_t _bt_controller_bss_start; @@ -551,7 +553,7 @@ static void sleep_modem_ble_mac_modem_state_deinit(void) void sleep_modem_light_sleep_overhead_set(uint32_t overhead) { - esp_ble_set_wakeup_overhead(overhead); + r_esp_ble_set_wakeup_overhead(overhead); } #endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ @@ -744,7 +746,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto free_mem; } - ble_get_npl_element_info(cfg, &npl_info); + r_ble_get_npl_element_info(cfg, &npl_info); npl_freertos_set_controller_npl_info(&npl_info); if (npl_freertos_mempool_init() != 0) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); @@ -821,14 +823,20 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto modem_deint; } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED - ret = ble_controller_init(cfg); + ret = esp_ble_register_bb_funcs(); if (ret != ESP_OK) { - ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } + + ret = r_ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); goto modem_deint; } ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); - esp_ble_change_rtc_freq(slow_clk_freq); + r_esp_ble_change_rtc_freq(slow_clk_freq); ble_controller_scan_duplicate_config(); @@ -845,7 +853,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) } ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); - esp_ble_ll_set_public_addr(mac); + r_esp_ble_ll_set_public_addr(mac); ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; @@ -856,8 +864,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) free_controller: controller_sleep_deinit(); os_msys_deinit(); - ble_controller_deinit(); + r_ble_controller_deinit(); modem_deint: + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -891,7 +900,8 @@ esp_err_t esp_bt_controller_deinit(void) modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); - ble_controller_deinit(); + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -939,7 +949,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) coex_enable(); #endif // CONFIG_SW_COEXIST_ENABLE - if (ble_controller_enable(mode) != 0) { + if (r_ble_controller_enable(mode) != 0) { ret = ESP_FAIL; goto error; } @@ -967,7 +977,7 @@ esp_err_t esp_bt_controller_disable(void) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_FAIL; } - if (ble_controller_disable() != 0) { + if (r_ble_controller_disable() != 0) { return ESP_FAIL; } #if CONFIG_SW_COEXIST_ENABLE @@ -1101,7 +1111,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_DEFAULT: case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; @@ -1114,7 +1124,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { stat = ESP_OK; } break; @@ -1134,13 +1144,13 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - if (ble_txpwr_set(power_type, handle, power_level) == 0) { + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { stat = ESP_OK; } break; @@ -1160,7 +1170,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: case ESP_BLE_PWR_TYPE_DEFAULT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_PWR_TYPE_CONN_HDL0: case ESP_BLE_PWR_TYPE_CONN_HDL1: @@ -1171,7 +1181,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); break; default: return ESP_PWR_LVL_INVALID; @@ -1193,11 +1203,11 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - tx_level = ble_txpwr_get(power_type, handle); + tx_level = r_ble_txpwr_get(power_type, handle); break; default: return ESP_PWR_LVL_INVALID; diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index 248b2058ac0..db5dc8e6a66 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -59,8 +59,8 @@ ************************************************************************ */ #define NIMBLE_PORT_LOG_TAG "BLE_INIT" -#define OSI_COEX_VERSION 0x00010006 -#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD +#define OSI_COEX_VERSION 0x00010006 +#define OSI_COEX_MAGIC_VALUE 0xFADEBEAD #define EXT_FUNC_VERSION 0x20221122 #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 @@ -115,7 +115,7 @@ typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); ************************************************************************ */ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); -extern int ble_controller_init(esp_bt_controller_config_t *cfg); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int r_ble_log_deinit_async(void); @@ -123,35 +123,37 @@ extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); extern void r_ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_controller_deinit(void); -extern int ble_controller_enable(uint8_t mode); -extern int ble_controller_disable(void); +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); extern int esp_register_ext_funcs (struct ext_funcs_t *); extern void esp_unregister_ext_funcs (void); -extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); extern uint32_t r_os_cputime_get32(void); extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); -#if CONFIG_FREERTOS_USE_TICKLESS_IDLE -extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); -extern void esp_ble_set_wakeup_overhead(uint32_t overhead); -#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ -extern void esp_ble_change_rtc_freq(uint32_t freq); extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); extern void r_ble_rtc_wake_up_state_clr(void); extern int os_msys_init(void); extern void os_msys_deinit(void); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE +extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); +extern void r_esp_ble_set_wakeup_overhead(uint32_t overhead); +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ +extern void r_esp_ble_change_rtc_freq(uint32_t freq); extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); -extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); -extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; extern uint32_t _bt_controller_bss_start; @@ -538,9 +540,10 @@ static void sleep_modem_ble_mac_modem_state_deinit(void) void sleep_modem_light_sleep_overhead_set(uint32_t overhead) { - esp_ble_set_wakeup_overhead(overhead); + r_esp_ble_set_wakeup_overhead(overhead); } -#endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE +#endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ + esp_err_t controller_sleep_init(void) { @@ -716,7 +719,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto free_mem; } - ble_get_npl_element_info(cfg, &npl_info); + r_ble_get_npl_element_info(cfg, &npl_info); npl_freertos_set_controller_npl_info(&npl_info); if (npl_freertos_mempool_init() != 0) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); @@ -730,10 +733,10 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) */ ble_npl_eventq_init(nimble_port_get_dflt_eventq()); #endif // CONFIG_BT_NIMBLE_ENABLED - /* Enable BT-related clocks */ modem_clock_module_enable(PERIPH_BT_MODULE); modem_clock_module_mac_reset(PERIPH_BT_MODULE); + /* Select slow clock source for BT momdule */ #if CONFIG_BT_LE_LP_CLK_SRC_MAIN_XTAL esp_bt_rtc_slow_clk_select(MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL); slow_clk_freq = 100000; @@ -771,6 +774,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #if CONFIG_SW_COEXIST_ENABLE coex_init(); #endif // CONFIG_SW_COEXIST_ENABLE + #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; @@ -791,16 +795,20 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto modem_deint; } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + ret = esp_ble_register_bb_funcs(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } - ret = ble_controller_init(cfg); + ret = r_ble_controller_init(cfg); if (ret != ESP_OK) { - ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); goto modem_deint; } ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); - - esp_ble_change_rtc_freq(slow_clk_freq); + r_esp_ble_change_rtc_freq(slow_clk_freq); ble_controller_scan_duplicate_config(); @@ -815,10 +823,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); goto free_controller; } - ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); - esp_ble_ll_set_public_addr(mac); + r_esp_ble_ll_set_public_addr(mac); ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; @@ -829,8 +836,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) free_controller: controller_sleep_deinit(); os_msys_deinit(); - ble_controller_deinit(); + r_ble_controller_deinit(); modem_deint: + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -862,7 +870,8 @@ esp_err_t esp_bt_controller_deinit(void) modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); - ble_controller_deinit(); + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -910,7 +919,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) coex_enable(); #endif // CONFIG_SW_COEXIST_ENABLE - if (ble_controller_enable(mode) != 0) { + if (r_ble_controller_enable(mode) != 0) { ret = ESP_FAIL; goto error; } @@ -938,7 +947,7 @@ esp_err_t esp_bt_controller_disable(void) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_FAIL; } - if (ble_controller_disable() != 0) { + if (r_ble_controller_disable() != 0) { return ESP_FAIL; } #if CONFIG_SW_COEXIST_ENABLE @@ -1072,7 +1081,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_DEFAULT: case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; @@ -1085,7 +1094,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { stat = ESP_OK; } break; @@ -1105,13 +1114,13 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - if (ble_txpwr_set(power_type, handle, power_level) == 0) { + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { stat = ESP_OK; } break; @@ -1131,7 +1140,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: case ESP_BLE_PWR_TYPE_DEFAULT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_PWR_TYPE_CONN_HDL0: case ESP_BLE_PWR_TYPE_CONN_HDL1: @@ -1142,7 +1151,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); break; default: return ESP_PWR_LVL_INVALID; @@ -1164,11 +1173,11 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - tx_level = ble_txpwr_get(power_type, handle); + tx_level = r_ble_txpwr_get(power_type, handle); break; default: return ESP_PWR_LVL_INVALID; diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index 405de681735..c2b9d7c8c2a 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit 405de68173533500319e9e2eb1c5bb13ca0a60f5 +Subproject commit c2b9d7c8c2ab4872ffe4f0501c4753fcbc96ba48 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 586a2272642..c2c9f4161f2 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 586a22726421eff1bf1bd6e57f378de1f51b8f72 +Subproject commit c2c9f4161f2ed200dbbcec71fbfd26da0241f376 diff --git a/components/bt/porting/nimble/src/os_msys_init.c b/components/bt/porting/nimble/src/os_msys_init.c index bf4f4145166..1a121e6d0b5 100644 --- a/components/bt/porting/nimble/src/os_msys_init.c +++ b/components/bt/porting/nimble/src/os_msys_init.c @@ -82,12 +82,12 @@ static struct os_mempool os_msys_init_2_mempool; #endif #if CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER -extern int esp_ble_msys_init(uint16_t msys_size1, uint16_t msys_size2, uint16_t msys_cnt1, uint16_t msys_cnt2, uint8_t from_heap); -extern void esp_ble_msys_deinit(void); +extern int r_esp_ble_msys_init(uint16_t msys_size1, uint16_t msys_size2, uint16_t msys_cnt1, uint16_t msys_cnt2, uint8_t from_heap); +extern void r_esp_ble_msys_deinit(void); int os_msys_init(void) { - return esp_ble_msys_init(SYSINIT_MSYS_1_MEMBLOCK_SIZE, + return r_esp_ble_msys_init(SYSINIT_MSYS_1_MEMBLOCK_SIZE, SYSINIT_MSYS_2_MEMBLOCK_SIZE, OS_MSYS_1_BLOCK_COUNT, OS_MSYS_2_BLOCK_COUNT, @@ -96,7 +96,7 @@ int os_msys_init(void) void os_msys_deinit(void) { - esp_ble_msys_deinit(); + r_esp_ble_msys_deinit(); } #else // CONFIG_BT_LE_MSYS_INIT_IN_CONTROLLER diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index e4b1a292192..da1a77bea4e 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -381,8 +381,8 @@ void modem_clock_select_lp_clock_source(periph_module_t module, modem_clock_lpcl modem_clock_hal_enable_ble_rtc_timer_clock(MODEM_CLOCK_instance()->hal, true); #if CONFIG_IDF_TARGET_ESP32H2 if (!rc_clk_en) { - extern void esp_ble_rtc_ticks_delay(uint32_t ticks); - esp_ble_rtc_ticks_delay(2); + extern void r_esp_ble_rtc_ticks_delay(uint32_t ticks); + r_esp_ble_rtc_ticks_delay(2); clk_ll_rc32k_disable(); } #endif // CONFIG_IDF_TARGET_ESP32H2 From 064fa71277a397b5b81bc26dbe21dec41b921a36 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 13 Jun 2024 12:16:27 +0800 Subject: [PATCH 280/548] feat(bluetooth/controller): update controller api name on ESP32-C2 --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index 3878fc3d687..8ddd8acac49 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit 3878fc3d687ed70798952e25bdb2514e023d80dc +Subproject commit 8ddd8acac498fcbb76b5a39c5c7d4025238298ab From 430d65225e69a3ac6f90b93f0d92fb1868caf7a8 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 13 Jun 2024 14:08:32 +0800 Subject: [PATCH 281/548] feat(bluetooth/controller): update controller api name on ESP32-C5 --- components/bt/controller/esp32c5/bt.c | 78 ++++++++++--------- .../bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/components/bt/controller/esp32c5/bt.c b/components/bt/controller/esp32c5/bt.c index 7e13c7124c9..95b314299e0 100644 --- a/components/bt/controller/esp32c5/bt.c +++ b/components/bt/controller/esp32c5/bt.c @@ -121,7 +121,7 @@ typedef void (*interface_func_t) (uint32_t len, const uint8_t*addr, bool end); ************************************************************************ */ extern int ble_osi_coex_funcs_register(struct osi_coex_funcs_t *coex_funcs); -extern int ble_controller_init(esp_bt_controller_config_t *cfg); +extern int r_ble_controller_init(esp_bt_controller_config_t *cfg); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size); extern int r_ble_log_deinit_async(void); @@ -129,12 +129,12 @@ extern void r_ble_log_async_select_dump_buffers(uint8_t buffers); extern void r_ble_log_async_output_dump_all(bool output); extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -extern int ble_controller_deinit(void); -extern int ble_controller_enable(uint8_t mode); -extern int ble_controller_disable(void); +extern int r_ble_controller_deinit(void); +extern int r_ble_controller_enable(uint8_t mode); +extern int r_ble_controller_disable(void); extern int esp_register_ext_funcs (struct ext_funcs_t *); extern void esp_unregister_ext_funcs (void); -extern int esp_ble_ll_set_public_addr(const uint8_t *addr); +extern int r_esp_ble_ll_set_public_addr(const uint8_t *addr); extern int esp_register_npl_funcs (struct npl_funcs_t *p_npl_func); extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); @@ -149,15 +149,17 @@ extern void os_msys_deinit(void); extern const sleep_retention_entries_config_t *esp_ble_mac_retention_link_get(uint8_t *size, uint8_t extra); extern void esp_ble_set_wakeup_overhead(uint32_t overhead); #endif /* CONFIG_FREERTOS_USE_TICKLESS_IDLE */ -extern void esp_ble_change_rtc_freq(uint32_t freq); +extern void r_esp_ble_change_rtc_freq(uint32_t freq); extern int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); extern int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); -extern int ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); -extern int ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -extern int ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); +extern int r_ble_txpwr_set(esp_ble_enhanced_power_type_t power_type, uint16_t handle, int power_level); +extern int r_ble_txpwr_get(esp_ble_enhanced_power_type_t power_type, uint16_t handle); +extern int r_ble_get_npl_element_info(esp_bt_controller_config_t *cfg, ble_npl_count_info_t * npl_info); extern char *ble_controller_get_compile_version(void); +extern int esp_ble_register_bb_funcs(void); +extern void esp_ble_unregister_bb_funcs(void); extern uint32_t _bt_bss_start; extern uint32_t _bt_bss_end; extern uint32_t _bt_controller_bss_start; @@ -723,7 +725,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) goto free_mem; } - ble_get_npl_element_info(cfg, &npl_info); + r_ble_get_npl_element_info(cfg, &npl_info); npl_freertos_set_controller_npl_info(&npl_info); if (npl_freertos_mempool_init() != 0) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "npl mempool init failed"); @@ -780,13 +782,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) coex_init(); #endif // CONFIG_SW_COEXIST_ENABLE - ret = ble_controller_init(cfg); - if (ret != ESP_OK) { - ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_init failed %d", ret); - goto modem_deint; - } - - ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; @@ -804,11 +799,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif // CONFIG_BT_CONTROLLER_LOG_DUMP if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); - goto controller_init_err; + goto modem_deint; } #endif // CONFIG_BT_CONTROLLER_LOG_ENABLED + ret = esp_ble_register_bb_funcs(); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "esp_ble_register_bb_funcs failed %d", ret); + goto modem_deint; + } - esp_ble_change_rtc_freq(slow_clk_freq); + ret = r_ble_controller_init(cfg); + if (ret != ESP_OK) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "r_ble_controller_init failed %d", ret); + goto modem_deint; + } + + ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble controller commit:[%s]", ble_controller_get_compile_version()); + r_esp_ble_change_rtc_freq(slow_clk_freq); ble_controller_scan_duplicate_config(); @@ -825,7 +832,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) } ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); - esp_ble_ll_set_public_addr(mac); + r_esp_ble_ll_set_public_addr(mac); ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; @@ -835,13 +842,13 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) free_controller: controller_sleep_deinit(); + os_msys_deinit(); + r_ble_controller_deinit(); +modem_deint: + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -controller_init_err: r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - os_msys_deinit(); - ble_controller_deinit(); -modem_deint: esp_phy_modem_deinit(); // modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); @@ -872,10 +879,11 @@ esp_err_t esp_bt_controller_deinit(void) // modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); + r_ble_controller_deinit(); + esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED r_ble_log_deinit_async(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ble_controller_deinit(); #if CONFIG_BT_NIMBLE_ENABLED /* De-initialize default event queue */ @@ -920,7 +928,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode) coex_enable(); #endif // CONFIG_SW_COEXIST_ENABLE - if (ble_controller_enable(mode) != 0) { + if (r_ble_controller_enable(mode) != 0) { ret = ESP_FAIL; goto error; } @@ -948,7 +956,7 @@ esp_err_t esp_bt_controller_disable(void) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_FAIL; } - if (ble_controller_disable() != 0) { + if (r_ble_controller_disable() != 0) { return ESP_FAIL; } #if CONFIG_SW_COEXIST_ENABLE @@ -1082,7 +1090,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_DEFAULT: case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; @@ -1095,7 +1103,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type, power_level) == 0) { stat = ESP_OK; } break; @@ -1115,13 +1123,13 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - if (ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { + if (r_ble_txpwr_set(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0, power_level) == 0) { stat = ESP_OK; } break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - if (ble_txpwr_set(power_type, handle, power_level) == 0) { + if (r_ble_txpwr_set(power_type, handle, power_level) == 0) { stat = ESP_OK; } break; @@ -1141,7 +1149,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_ADV: case ESP_BLE_PWR_TYPE_SCAN: case ESP_BLE_PWR_TYPE_DEFAULT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_PWR_TYPE_CONN_HDL0: case ESP_BLE_PWR_TYPE_CONN_HDL1: @@ -1152,7 +1160,7 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type) case ESP_BLE_PWR_TYPE_CONN_HDL6: case ESP_BLE_PWR_TYPE_CONN_HDL7: case ESP_BLE_PWR_TYPE_CONN_HDL8: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_CONN, power_type); break; default: return ESP_PWR_LVL_INVALID; @@ -1174,11 +1182,11 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po case ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT: case ESP_BLE_ENHANCED_PWR_TYPE_SCAN: case ESP_BLE_ENHANCED_PWR_TYPE_INIT: - tx_level = ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); + tx_level = r_ble_txpwr_get(ESP_BLE_ENHANCED_PWR_TYPE_DEFAULT, 0); break; case ESP_BLE_ENHANCED_PWR_TYPE_ADV: case ESP_BLE_ENHANCED_PWR_TYPE_CONN: - tx_level = ble_txpwr_get(power_type, handle); + tx_level = r_ble_txpwr_get(power_type, handle); break; default: return ESP_PWR_LVL_INVALID; diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index 45dda7a690a..3996803d35b 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit 45dda7a690af994e8e6a41cc3b029506335d169f +Subproject commit 3996803d35bcb79283bb7dcff60a11092339a838 From a21f65cb5b070be93d74d82eec4c7e3d70edf8f0 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 20 Jun 2024 19:12:06 +0800 Subject: [PATCH 282/548] feat(bluetooth/controller): adjust bt/porting code structure and delete redundant code --- components/bt/CMakeLists.txt | 7 +- components/bt/controller/esp32c2/bt.c | 5 +- components/bt/controller/esp32c5/bt.c | 4 +- components/bt/controller/esp32c6/bt.c | 4 +- components/bt/controller/esp32h2/bt.c | 4 +- components/bt/host/bluedroid/hci/hci_hal_h4.c | 2 +- .../nimble => include}/ble_hci_trans.h | 19 +- .../bt/porting/{mem => include}/bt_osi_mem.h | 0 .../porting/{nimble => }/include/os/endian.h | 0 .../bt/porting/{nimble => }/include/os/os.h | 0 .../{nimble => }/include/os/os_error.h | 0 .../porting/{nimble => }/include/os/os_mbuf.h | 4 +- .../{nimble => }/include/os/os_mempool.h | 0 .../porting/{nimble => }/include/os/queue.h | 46 ++- .../bt/porting/{nimble => }/include/os/util.h | 0 .../{nimble/src => mem}/os_msys_init.c | 0 .../bt/porting/nimble/include/nimble/ble.h | 319 ------------------ .../nimble/include/nimble/nimble_opt.h | 34 -- .../nimble/include/nimble/nimble_opt_auto.h | 132 -------- .../nimble/include/nimble/nimble_port.h | 79 ----- .../freertos}/include/nimble/nimble_npl.h | 17 +- .../npl/freertos/src/npl_os_freertos.c | 63 ++-- 22 files changed, 73 insertions(+), 666 deletions(-) rename components/bt/porting/{nimble/include/nimble => include}/ble_hci_trans.h (93%) rename components/bt/porting/{mem => include}/bt_osi_mem.h (100%) rename components/bt/porting/{nimble => }/include/os/endian.h (100%) rename components/bt/porting/{nimble => }/include/os/os.h (100%) rename components/bt/porting/{nimble => }/include/os/os_error.h (100%) rename components/bt/porting/{nimble => }/include/os/os_mbuf.h (99%) rename components/bt/porting/{nimble => }/include/os/os_mempool.h (100%) rename components/bt/porting/{nimble => }/include/os/queue.h (81%) rename components/bt/porting/{nimble => }/include/os/util.h (100%) rename components/bt/porting/{nimble/src => mem}/os_msys_init.c (100%) delete mode 100644 components/bt/porting/nimble/include/nimble/ble.h delete mode 100644 components/bt/porting/nimble/include/nimble/nimble_opt.h delete mode 100644 components/bt/porting/nimble/include/nimble/nimble_opt_auto.h delete mode 100644 components/bt/porting/nimble/include/nimble/nimble_port.h rename components/bt/porting/{nimble => npl/freertos}/include/nimble/nimble_npl.h (83%) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index d32a6d372cb..6dd5ef9b378 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -575,7 +575,7 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) list(APPEND srcs "porting/npl/freertos/src/npl_os_freertos.c" - "porting/nimble/src/os_msys_init.c" + "porting/mem/os_msys_init.c" ) if(CONFIG_BT_CONTROLLER_DISABLED) @@ -585,7 +585,6 @@ if(CONFIG_BT_ENABLED) endif() list(APPEND include_dirs porting/include - porting/nimble/include porting/npl/freertos/include porting/transport/include ) @@ -727,7 +726,6 @@ if(CONFIG_BT_ENABLED) "host/nimble/port/src/nvs_port.c" ) list(APPEND include_dirs - porting/include host/nimble/nimble/porting/nimble/include host/nimble/port/include host/nimble/nimble/nimble/transport/include @@ -756,9 +754,8 @@ if(CONFIG_BT_ENABLED) endif() list(APPEND include_dirs + porting/include host/nimble/nimble/porting/npl/freertos/include - host/nimble/nimble/porting/nimble/include - host/nimble/nimble/nimble/include ) endif() diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 38ae519a56d..29c3332604b 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -16,7 +16,10 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED + #include "nimble/nimble_port_freertos.h" #ifdef ESP_PLATFORM @@ -28,7 +31,7 @@ #endif #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" diff --git a/components/bt/controller/esp32c5/bt.c b/components/bt/controller/esp32c5/bt.c index 95b314299e0..17794564355 100644 --- a/components/bt/controller/esp32c5/bt.c +++ b/components/bt/controller/esp32c5/bt.c @@ -15,7 +15,9 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port_freertos.h" #include "esp_private/esp_modem_clock.h" @@ -28,7 +30,7 @@ #endif // CONFIG_SW_COEXIST_ENABLE #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index c27045ee176..ca87e35a613 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -15,7 +15,9 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port_freertos.h" #include "esp_private/esp_modem_clock.h" @@ -28,7 +30,7 @@ #endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index db5dc8e6a66..adb10d4981f 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -15,7 +15,9 @@ #include "sdkconfig.h" +#if CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port.h" +#endif // CONFIG_BT_NIMBLE_ENABLED #include "nimble/nimble_port_freertos.h" #include "esp_private/esp_modem_clock.h" @@ -28,7 +30,7 @@ #endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #include "os/endian.h" #include "esp_bt.h" diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index a2ee1d1121b..9663126ad62 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -36,7 +36,7 @@ #include "stack/hcimsgs.h" #if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER) -#include "nimble/ble_hci_trans.h" +#include "ble_hci_trans.h" #endif #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) diff --git a/components/bt/porting/nimble/include/nimble/ble_hci_trans.h b/components/bt/porting/include/ble_hci_trans.h similarity index 93% rename from components/bt/porting/nimble/include/nimble/ble_hci_trans.h rename to components/bt/porting/include/ble_hci_trans.h index 5bbf9224601..05267b6be77 100644 --- a/components/bt/porting/nimble/include/nimble/ble_hci_trans.h +++ b/components/bt/porting/include/ble_hci_trans.h @@ -1,20 +1,7 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 */ #ifndef H_HCI_TRANSPORT_ diff --git a/components/bt/porting/mem/bt_osi_mem.h b/components/bt/porting/include/bt_osi_mem.h similarity index 100% rename from components/bt/porting/mem/bt_osi_mem.h rename to components/bt/porting/include/bt_osi_mem.h diff --git a/components/bt/porting/nimble/include/os/endian.h b/components/bt/porting/include/os/endian.h similarity index 100% rename from components/bt/porting/nimble/include/os/endian.h rename to components/bt/porting/include/os/endian.h diff --git a/components/bt/porting/nimble/include/os/os.h b/components/bt/porting/include/os/os.h similarity index 100% rename from components/bt/porting/nimble/include/os/os.h rename to components/bt/porting/include/os/os.h diff --git a/components/bt/porting/nimble/include/os/os_error.h b/components/bt/porting/include/os/os_error.h similarity index 100% rename from components/bt/porting/nimble/include/os/os_error.h rename to components/bt/porting/include/os/os_error.h diff --git a/components/bt/porting/nimble/include/os/os_mbuf.h b/components/bt/porting/include/os/os_mbuf.h similarity index 99% rename from components/bt/porting/nimble/include/os/os_mbuf.h rename to components/bt/porting/include/os/os_mbuf.h index e6fd6b907e6..c6ea6b6e85d 100644 --- a/components/bt/porting/nimble/include/os/os_mbuf.h +++ b/components/bt/porting/include/os/os_mbuf.h @@ -65,7 +65,7 @@ struct os_mbuf_pool { /** - * A packet header structure that preceeds the mbuf packet headers. + * A packet header structure that proceeds the mbuf packet headers. */ struct os_mbuf_pkthdr { /** @@ -89,7 +89,7 @@ struct os_mbuf { */ uint8_t *om_data; /** - * Flags associated with this buffer, see OS_MBUF_F_* defintions + * Flags associated with this buffer, see OS_MBUF_F_* definitions */ uint8_t om_flags; /** diff --git a/components/bt/porting/nimble/include/os/os_mempool.h b/components/bt/porting/include/os/os_mempool.h similarity index 100% rename from components/bt/porting/nimble/include/os/os_mempool.h rename to components/bt/porting/include/os/os_mempool.h diff --git a/components/bt/porting/nimble/include/os/queue.h b/components/bt/porting/include/os/queue.h similarity index 81% rename from components/bt/porting/nimble/include/os/queue.h rename to components/bt/porting/include/os/queue.h index c184a394edb..868f9abfa4f 100644 --- a/components/bt/porting/nimble/include/os/queue.h +++ b/components/bt/porting/include/os/queue.h @@ -1,33 +1,27 @@ /* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. + * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * SPDX-License-Identifier: Apache-2.0 * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.7 2002/04/17 14:21:02 des Exp $ + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef _QUEUE_H_ diff --git a/components/bt/porting/nimble/include/os/util.h b/components/bt/porting/include/os/util.h similarity index 100% rename from components/bt/porting/nimble/include/os/util.h rename to components/bt/porting/include/os/util.h diff --git a/components/bt/porting/nimble/src/os_msys_init.c b/components/bt/porting/mem/os_msys_init.c similarity index 100% rename from components/bt/porting/nimble/src/os_msys_init.c rename to components/bt/porting/mem/os_msys_init.c diff --git a/components/bt/porting/nimble/include/nimble/ble.h b/components/bt/porting/nimble/include/nimble/ble.h deleted file mode 100644 index f037d3565b8..00000000000 --- a/components/bt/porting/nimble/include/nimble/ble.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) - * - * SPDX-License-Identifier: Apache-2.0 - * - * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD - */ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_BLE_ -#define H_BLE_ - -#include -#include -#include "syscfg/syscfg.h" -#include "os/os.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* The number of advertising instances */ -#define BLE_ADV_INSTANCES (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + 1) - -/* BLE encryption block definitions */ -#define BLE_ENC_BLOCK_SIZE (16) - -/* 4 byte header + 251 byte payload. */ -#define BLE_ACL_MAX_PKT_SIZE 255 - -struct ble_encryption_block -{ - uint8_t key[BLE_ENC_BLOCK_SIZE]; - uint8_t plain_text[BLE_ENC_BLOCK_SIZE]; - uint8_t cipher_text[BLE_ENC_BLOCK_SIZE]; -}; - -/* - * BLE MBUF structure: - * - * The BLE mbuf structure is as follows. Note that this structure applies to - * the packet header mbuf (not mbufs that are part of a "packet chain"): - * struct os_mbuf (16) - * struct os_mbuf_pkthdr (8) - * struct ble_mbuf_hdr (8) - * Data buffer (payload size, in bytes) - * - * The BLE mbuf header contains the following: - * flags: bitfield with the following values - * 0x01: Set if there was a match on the whitelist - * 0x02: Set if a connect request was transmitted upon receiving pdu - * 0x04: Set the first time we transmit the PDU (used to detect retry). - * channel: The logical BLE channel PHY channel # (0 - 39) - * crcok: flag denoting CRC check passed (1) or failed (0). - * rssi: RSSI, in dBm. - */ -struct ble_mbuf_hdr_rxinfo -{ - uint16_t flags; - uint8_t channel; - uint8_t handle; - int8_t rssi; - /* XXX: we could just use single phy_mode field */ - int8_t phy; - uint8_t phy_mode; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int8_t rpa_index; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - void *user_data; -#endif -}; - -/* - * Flag definitions for rxinfo - * - * Note: it's ok to have symbols with the same values as long as they cannot be - * set for the same PDU (e.g. one use by scanner, other one used by - * connection) - */ -#define BLE_MBUF_HDR_F_CONN_CREDIT (0x8000) -#define BLE_MBUF_HDR_F_IGNORED (0x8000) -#define BLE_MBUF_HDR_F_SCAN_REQ_TXD (0x4000) -#define BLE_MBUF_HDR_F_INITA_RESOLVED (0x2000) -#define BLE_MBUF_HDR_F_TARGETA_RESOLVED (0x2000) -#define BLE_MBUF_HDR_F_EXT_ADV_SEC (0x1000) -#define BLE_MBUF_HDR_F_EXT_ADV (0x0800) -#define BLE_MBUF_HDR_F_RESOLVED (0x0400) -#define BLE_MBUF_HDR_F_AUX_PTR_WAIT (0x0200) -#define BLE_MBUF_HDR_F_AUX_INVALID (0x0100) -#define BLE_MBUF_HDR_F_CRC_OK (0x0080) -#define BLE_MBUF_HDR_F_DEVMATCH (0x0040) -#define BLE_MBUF_HDR_F_MIC_FAILURE (0x0020) -#define BLE_MBUF_HDR_F_SCAN_RSP_TXD (0x0010) -#define BLE_MBUF_HDR_F_SCAN_RSP_RXD (0x0008) -#define BLE_MBUF_HDR_F_RXSTATE_MASK (0x0007) - -/* Transmit info. NOTE: no flags defined */ -struct ble_mbuf_hdr_txinfo -{ - uint8_t flags; - uint8_t reserve0; - uint8_t pyld_len; - uint8_t hdr_byte; - uint16_t offset; -}; - -struct ble_mbuf_hdr -{ - union { - struct ble_mbuf_hdr_rxinfo rxinfo; - struct ble_mbuf_hdr_txinfo txinfo; - }; - uint32_t beg_cputime; - uint32_t rem_usecs; -}; - -#define BLE_MBUF_HDR_IGNORED(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_IGNORED)) - -#define BLE_MBUF_HDR_SCAN_REQ_TXD(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD)) - -#define BLE_MBUF_HDR_EXT_ADV_SEC(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_EXT_ADV_SEC)) - -#define BLE_MBUF_HDR_EXT_ADV(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_EXT_ADV)) - -#define BLE_MBUF_HDR_DEVMATCH(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH)) - -#define BLE_MBUF_HDR_SCAN_RSP_RXD(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD)) - -#define BLE_MBUF_HDR_AUX_INVALID(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_INVALID)) - -#define BLE_MBUF_HDR_WAIT_AUX(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)) - -#define BLE_MBUF_HDR_CRC_OK(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_CRC_OK)) - -#define BLE_MBUF_HDR_MIC_FAILURE(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_MIC_FAILURE)) - -#define BLE_MBUF_HDR_RESOLVED(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RESOLVED)) - -#define BLE_MBUF_HDR_INITA_RESOLVED(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_INITA_RESOLVED)) - -#define BLE_MBUF_HDR_TARGETA_RESOLVED(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED)) - -#define BLE_MBUF_HDR_RX_STATE(hdr) \ - ((uint8_t)((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RXSTATE_MASK)) - -#define BLE_MBUF_HDR_PTR(om) \ - (struct ble_mbuf_hdr *)((uint8_t *)om + sizeof(struct os_mbuf) + \ - sizeof(struct os_mbuf_pkthdr)) - -/* BLE mbuf overhead per packet header mbuf */ -#define BLE_MBUF_PKTHDR_OVERHEAD \ - (sizeof(struct os_mbuf_pkthdr) + sizeof(struct ble_mbuf_hdr)) - -#define BLE_MBUF_MEMBLOCK_OVERHEAD \ - (sizeof(struct os_mbuf) + BLE_MBUF_PKTHDR_OVERHEAD) - -/* Length of host user header. Only contains the peer's connection handle. */ -#define BLE_MBUF_HS_HDR_LEN (2) - -#define BLE_DEV_ADDR_LEN (6) -extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; -extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; - -/* BLE Error Codes (Core v4.2 Vol 2 part D) */ -enum ble_error_codes -{ - /* An "error" code of 0x0 means success */ - BLE_ERR_SUCCESS = 0x00, - BLE_ERR_UNKNOWN_HCI_CMD = 0x01, - BLE_ERR_UNK_CONN_ID = 0x02, - BLE_ERR_HW_FAIL = 0x03, - BLE_ERR_PAGE_TMO = 0x04, - BLE_ERR_AUTH_FAIL = 0x05, - BLE_ERR_PINKEY_MISSING = 0x06, - BLE_ERR_MEM_CAPACITY = 0x07, - BLE_ERR_CONN_SPVN_TMO = 0x08, - BLE_ERR_CONN_LIMIT = 0x09, - BLE_ERR_SYNCH_CONN_LIMIT = 0x0a, - BLE_ERR_ACL_CONN_EXISTS = 0x0b, - BLE_ERR_CMD_DISALLOWED = 0x0c, - BLE_ERR_CONN_REJ_RESOURCES = 0x0d, - BLE_ERR_CONN_REJ_SECURITY = 0x0e, - BLE_ERR_CONN_REJ_BD_ADDR = 0x0f, - BLE_ERR_CONN_ACCEPT_TMO = 0x10, - BLE_ERR_UNSUPPORTED = 0x11, - BLE_ERR_INV_HCI_CMD_PARMS = 0x12, - BLE_ERR_REM_USER_CONN_TERM = 0x13, - BLE_ERR_RD_CONN_TERM_RESRCS = 0x14, - BLE_ERR_RD_CONN_TERM_PWROFF = 0x15, - BLE_ERR_CONN_TERM_LOCAL = 0x16, - BLE_ERR_REPEATED_ATTEMPTS = 0x17, - BLE_ERR_NO_PAIRING = 0x18, - BLE_ERR_UNK_LMP = 0x19, - BLE_ERR_UNSUPP_REM_FEATURE = 0x1a, - BLE_ERR_SCO_OFFSET = 0x1b, - BLE_ERR_SCO_ITVL = 0x1c, - BLE_ERR_SCO_AIR_MODE = 0x1d, - BLE_ERR_INV_LMP_LL_PARM = 0x1e, - BLE_ERR_UNSPECIFIED = 0x1f, - BLE_ERR_UNSUPP_LMP_LL_PARM = 0x20, - BLE_ERR_NO_ROLE_CHANGE = 0x21, - BLE_ERR_LMP_LL_RSP_TMO = 0x22, - BLE_ERR_LMP_COLLISION = 0x23, - BLE_ERR_LMP_PDU = 0x24, - BLE_ERR_ENCRYPTION_MODE = 0x25, - BLE_ERR_LINK_KEY_CHANGE = 0x26, - BLE_ERR_UNSUPP_QOS = 0x27, - BLE_ERR_INSTANT_PASSED = 0x28, - BLE_ERR_UNIT_KEY_PAIRING = 0x29, - BLE_ERR_DIFF_TRANS_COLL = 0x2a, - /* BLE_ERR_RESERVED = 0x2b */ - BLE_ERR_QOS_PARM = 0x2c, - BLE_ERR_QOS_REJECTED = 0x2d, - BLE_ERR_CHAN_CLASS = 0x2e, - BLE_ERR_INSUFFICIENT_SEC = 0x2f, - BLE_ERR_PARM_OUT_OF_RANGE = 0x30, - /* BLE_ERR_RESERVED = 0x31 */ - BLE_ERR_PENDING_ROLE_SW = 0x32, - /* BLE_ERR_RESERVED = 0x33 */ - BLE_ERR_RESERVED_SLOT = 0x34, - BLE_ERR_ROLE_SW_FAIL = 0x35, - BLE_ERR_INQ_RSP_TOO_BIG = 0x36, - BLE_ERR_SEC_SIMPLE_PAIR = 0x37, - BLE_ERR_HOST_BUSY_PAIR = 0x38, - BLE_ERR_CONN_REJ_CHANNEL = 0x39, - BLE_ERR_CTLR_BUSY = 0x3a, - BLE_ERR_CONN_PARMS = 0x3b, - BLE_ERR_DIR_ADV_TMO = 0x3c, - BLE_ERR_CONN_TERM_MIC = 0x3d, - BLE_ERR_CONN_ESTABLISHMENT = 0x3e, - BLE_ERR_MAC_CONN_FAIL = 0x3f, - BLE_ERR_COARSE_CLK_ADJ = 0x40, - BLE_ERR_TYPE0_SUBMAP_NDEF = 0x41, - BLE_ERR_UNK_ADV_INDENT = 0x42, - BLE_ERR_LIMIT_REACHED = 0x43, - BLE_ERR_OPERATION_CANCELLED = 0x44, - BLE_ERR_PACKET_TOO_LONG = 0x45, - BLE_ERR_MAX = 0xff -}; - -/* HW error codes */ -#define BLE_HW_ERR_DO_NOT_USE (0) /* XXX: reserve this one for now */ -#define BLE_HW_ERR_HCI_SYNC_LOSS (1) - -/* Own Bluetooth Device address type */ -#define BLE_OWN_ADDR_PUBLIC (0x00) -#define BLE_OWN_ADDR_RANDOM (0x01) -#define BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT (0x02) -#define BLE_OWN_ADDR_RPA_RANDOM_DEFAULT (0x03) - -/* Bluetooth Device address type */ -#define BLE_ADDR_PUBLIC (0x00) -#define BLE_ADDR_RANDOM (0x01) -#define BLE_ADDR_PUBLIC_ID (0x02) -#define BLE_ADDR_RANDOM_ID (0x03) - -#define BLE_ADDR_ANY (&(ble_addr_t) { 0, {0, 0, 0, 0, 0, 0} }) - -#define BLE_ADDR_IS_RPA(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ - ((addr)->val[5] & 0xc0) == 0x40) -#define BLE_ADDR_IS_NRPA(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ - ((addr)->val[5] & 0xc0) == 0x00) -#define BLE_ADDR_IS_STATIC(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ - ((addr)->val[5] & 0xc0) == 0xc0) - -typedef struct { - uint8_t type; - uint8_t val[6]; -} ble_addr_t; - - -static inline int ble_addr_cmp(const ble_addr_t *a, const ble_addr_t *b) -{ - int type_diff; - - type_diff = a->type - b->type; - if (type_diff != 0) { - return type_diff; - } - - return memcmp(a->val, b->val, sizeof(a->val)); -} - -#ifdef __cplusplus -} -#endif - -#endif /* H_BLE_ */ diff --git a/components/bt/porting/nimble/include/nimble/nimble_opt.h b/components/bt/porting/nimble/include/nimble/nimble_opt.h deleted file mode 100644 index f0e988b27b0..00000000000 --- a/components/bt/porting/nimble/include/nimble/nimble_opt.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_NIMBLE_OPT_ -#define H_NIMBLE_OPT_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Include automatically-generated settings. */ -#include "nimble/nimble_opt_auto.h" - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/bt/porting/nimble/include/nimble/nimble_opt_auto.h b/components/bt/porting/nimble/include/nimble/nimble_opt_auto.h deleted file mode 100644 index c4baec843be..00000000000 --- a/components/bt/porting/nimble/include/nimble/nimble_opt_auto.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 The Apache Software Foundation (ASF) - * - * SPDX-License-Identifier: Apache-2.0 - * - * SPDX-FileContributor: 2019-2022 Espressif Systems (Shanghai) CO LTD - */ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_NIMBLE_OPT_AUTO_ -#define H_NIMBLE_OPT_AUTO_ - -#include "syscfg/syscfg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/*** - * Automatic options. - * - * These settings are generated automatically from the user-specified syscfg - * settings. - */ - -#undef NIMBLE_BLE_ADVERTISE -#define NIMBLE_BLE_ADVERTISE \ - (MYNEWT_VAL(BLE_ROLE_BROADCASTER) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)) - -#undef NIMBLE_BLE_SCAN -#define NIMBLE_BLE_SCAN \ - (MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER)) - -#undef NIMBLE_BLE_CONNECT -#define NIMBLE_BLE_CONNECT \ - (MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL)) - - -/** Supported client ATT commands. */ - -#undef NIMBLE_BLE_ATT_CLT_FIND_INFO -#define NIMBLE_BLE_ATT_CLT_FIND_INFO \ - (MYNEWT_VAL(BLE_GATT_DISC_ALL_DSCS)) - -#undef NIMBLE_BLE_ATT_CLT_FIND_TYPE -#define NIMBLE_BLE_ATT_CLT_FIND_TYPE \ - (MYNEWT_VAL(BLE_GATT_DISC_SVC_UUID)) - -#undef NIMBLE_BLE_ATT_CLT_READ_TYPE -#define NIMBLE_BLE_ATT_CLT_READ_TYPE \ - (MYNEWT_VAL(BLE_GATT_FIND_INC_SVCS) || \ - MYNEWT_VAL(BLE_GATT_DISC_ALL_CHRS) || \ - MYNEWT_VAL(BLE_GATT_DISC_CHRS_UUID) || \ - MYNEWT_VAL(BLE_GATT_READ_UUID)) - -#undef NIMBLE_BLE_ATT_CLT_READ -#define NIMBLE_BLE_ATT_CLT_READ \ - (MYNEWT_VAL(BLE_GATT_READ) || \ - MYNEWT_VAL(BLE_GATT_READ_LONG) || \ - MYNEWT_VAL(BLE_GATT_FIND_INC_SVCS)) - -#undef NIMBLE_BLE_ATT_CLT_READ_BLOB -#define NIMBLE_BLE_ATT_CLT_READ_BLOB \ - (MYNEWT_VAL(BLE_GATT_READ_LONG)) - -#undef NIMBLE_BLE_ATT_CLT_READ_MULT -#define NIMBLE_BLE_ATT_CLT_READ_MULT \ - (MYNEWT_VAL(BLE_GATT_READ_MULT)) - -#undef NIMBLE_BLE_ATT_CLT_READ_MULT_VAR -#define NIMBLE_BLE_ATT_CLT_READ_MULT_VAR \ - (MYNEWT_VAL(BLE_GATT_READ_MULT_VAR)) - -#undef NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE -#define NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE \ - (MYNEWT_VAL(BLE_GATT_DISC_ALL_SVCS)) - -#undef NIMBLE_BLE_ATT_CLT_WRITE -#define NIMBLE_BLE_ATT_CLT_WRITE \ - (MYNEWT_VAL(BLE_GATT_WRITE)) - -#undef NIMBLE_BLE_ATT_CLT_SIGNED_WRITE -#define NIMBLE_BLE_ATT_CLT_SIGNED_WRITE \ - (MYNEWT_VAL(BLE_GATT_SIGNED_WRITE)) - -#undef NIMBLE_BLE_ATT_CLT_WRITE_NO_RSP -#define NIMBLE_BLE_ATT_CLT_WRITE_NO_RSP \ - (MYNEWT_VAL(BLE_GATT_WRITE_NO_RSP)) - -#undef NIMBLE_BLE_ATT_CLT_PREP_WRITE -#define NIMBLE_BLE_ATT_CLT_PREP_WRITE \ - (MYNEWT_VAL(BLE_GATT_WRITE_LONG)) - -#undef NIMBLE_BLE_ATT_CLT_EXEC_WRITE -#define NIMBLE_BLE_ATT_CLT_EXEC_WRITE \ - (MYNEWT_VAL(BLE_GATT_WRITE_LONG)) - -#undef NIMBLE_BLE_ATT_CLT_NOTIFY -#define NIMBLE_BLE_ATT_CLT_NOTIFY \ - (MYNEWT_VAL(BLE_GATT_NOTIFY)) - -#undef NIMBLE_BLE_ATT_CLT_INDICATE -#define NIMBLE_BLE_ATT_CLT_INDICATE \ - (MYNEWT_VAL(BLE_GATT_INDICATE)) - -/** Security manager settings. */ - -#undef NIMBLE_BLE_SM -#define NIMBLE_BLE_SM (MYNEWT_VAL(BLE_SM_LEGACY) || MYNEWT_VAL(BLE_SM_SC)) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/components/bt/porting/nimble/include/nimble/nimble_port.h b/components/bt/porting/nimble/include/nimble/nimble_port.h deleted file mode 100644 index 0035fee6c34..00000000000 --- a/components/bt/porting/nimble/include/nimble/nimble_port.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _NIMBLE_PORT_H -#define _NIMBLE_PORT_H - -#include "sdkconfig.h" -#include "esp_err.h" -#include "nimble/nimble_npl.h" - -#define NIMBLE_CORE (CONFIG_BT_NIMBLE_PINNED_TO_CORE < CONFIG_FREERTOS_NUMBER_OF_CORES ? CONFIG_BT_NIMBLE_PINNED_TO_CORE : tskNO_AFFINITY) - -#define NIMBLE_HS_STACK_SIZE CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE - -#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED -#define NIMBLE_LL_STACK_SIZE CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** -* @brief nimble_port_init - Initialize controller and NimBLE host stack -* -* @return esp_err_t - ESP_OK ( if success) -* Error code in case of failure -*/ -esp_err_t nimble_port_init(void); - -/** -* @brief nimble_port_deinit - Deinitialize controller and NimBLE host stack -* -* @return esp_err_t - ESP_OK ( if success) -* Error code in case of failure -*/ -esp_err_t nimble_port_deinit(void); - -void nimble_port_run(void); -int nimble_port_stop(void); - -/** - * @brief esp_nimble_init - Initialize the NimBLE host stack - * - * @return esp_err_t - */ -esp_err_t esp_nimble_init(void); - -/** - * @brief esp_nimble_deinit - Deinitialize the NimBLE host stack - * - * @return esp_err_t - */ -esp_err_t esp_nimble_deinit(void); - -struct ble_npl_eventq *nimble_port_get_dflt_eventq(void); - - -#ifdef __cplusplus -} -#endif - -#endif /* _NIMBLE_PORT_H */ diff --git a/components/bt/porting/nimble/include/nimble/nimble_npl.h b/components/bt/porting/npl/freertos/include/nimble/nimble_npl.h similarity index 83% rename from components/bt/porting/nimble/include/nimble/nimble_npl.h rename to components/bt/porting/npl/freertos/include/nimble/nimble_npl.h index c11a2972dfd..c9482044b74 100644 --- a/components/bt/porting/nimble/include/nimble/nimble_npl.h +++ b/components/bt/porting/npl/freertos/include/nimble/nimble_npl.h @@ -1,20 +1,7 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * SPDX-License-Identifier: Apache-2.0 */ #ifndef _NIMBLE_NPL_H_ diff --git a/components/bt/porting/npl/freertos/src/npl_os_freertos.c b/components/bt/porting/npl/freertos/src/npl_os_freertos.c index c93a2224d77..29e2567d553 100644 --- a/components/bt/porting/npl/freertos/src/npl_os_freertos.c +++ b/components/bt/porting/npl/freertos/src/npl_os_freertos.c @@ -1,9 +1,7 @@ /* - * SPDX-FileCopyrightText: 2019-2023 The Apache Software Foundation (ASF) + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 - * - * SPDX-FileContributor: 2019-2024 Espressif Systems (Shanghai) CO LTD */ #include @@ -18,7 +16,6 @@ #include "freertos/timers.h" #include "freertos/portable.h" #include "nimble/npl_freertos.h" -#include "nimble/nimble_port.h" #include "os/os_mempool.h" #include "esp_log.h" @@ -481,32 +478,32 @@ IRAM_ATTR npl_freertos_mutex_release(struct ble_npl_mutex *mu) ble_npl_error_t npl_freertos_sem_init(struct ble_npl_sem *sem, uint16_t tokens) { - struct ble_npl_sem_freertos *semaphor = NULL; + struct ble_npl_sem_freertos *semaphore = NULL; #if OS_MEM_ALLOC if (!os_memblock_from(&ble_freertos_sem_pool,sem->sem)) { sem->sem = os_memblock_get(&ble_freertos_sem_pool); - semaphor = (struct ble_npl_sem_freertos *)sem->sem; + semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - memset(semaphor, 0, sizeof(*semaphor)); - semaphor->handle = xSemaphoreCreateCounting(128, tokens); - BLE_LL_ASSERT(semaphor->handle); + memset(semaphore, 0, sizeof(*semaphore)); + semaphore->handle = xSemaphoreCreateCounting(128, tokens); + BLE_LL_ASSERT(semaphore->handle); } #else if(!sem->sem) { sem->sem = malloc(sizeof(struct ble_npl_sem_freertos)); - semaphor = (struct ble_npl_sem_freertos *)sem->sem; + semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - memset(semaphor, 0, sizeof(*semaphor)); - semaphor->handle = xSemaphoreCreateCounting(128, tokens); - BLE_LL_ASSERT(semaphor->handle); + memset(semaphore, 0, sizeof(*semaphore)); + semaphore->handle = xSemaphoreCreateCounting(128, tokens); + BLE_LL_ASSERT(semaphore->handle); } #endif @@ -516,19 +513,19 @@ npl_freertos_sem_init(struct ble_npl_sem *sem, uint16_t tokens) ble_npl_error_t npl_freertos_sem_deinit(struct ble_npl_sem *sem) { - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); - vSemaphoreDelete(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); + vSemaphoreDelete(semaphore->handle); #if OS_MEM_ALLOC - os_memblock_put(&ble_freertos_sem_pool,semaphor); + os_memblock_put(&ble_freertos_sem_pool,semaphore); #else - free((void *)semaphor); + free((void *)semaphore); #endif sem->sem = NULL; @@ -540,22 +537,22 @@ IRAM_ATTR npl_freertos_sem_pend(struct ble_npl_sem *sem, ble_npl_time_t timeout) { BaseType_t woken; BaseType_t ret; - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); if (in_isr()) { BLE_LL_ASSERT(timeout == 0); - ret = xSemaphoreTakeFromISR(semaphor->handle, &woken); + ret = xSemaphoreTakeFromISR(semaphore->handle, &woken); if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } } else { - ret = xSemaphoreTake(semaphor->handle, timeout); + ret = xSemaphoreTake(semaphore->handle, timeout); } return ret == pdPASS ? BLE_NPL_OK : BLE_NPL_TIMEOUT; @@ -566,21 +563,21 @@ IRAM_ATTR npl_freertos_sem_release(struct ble_npl_sem *sem) { BaseType_t ret; BaseType_t woken; - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; - if (!semaphor) { + if (!semaphore) { return BLE_NPL_INVALID_PARAM; } - BLE_LL_ASSERT(semaphor->handle); + BLE_LL_ASSERT(semaphore->handle); if (in_isr()) { - ret = xSemaphoreGiveFromISR(semaphor->handle, &woken); + ret = xSemaphoreGiveFromISR(semaphore->handle, &woken); if( woken == pdTRUE ) { portYIELD_FROM_ISR(); } } else { - ret = xSemaphoreGive(semaphor->handle); + ret = xSemaphoreGive(semaphore->handle); } BLE_LL_ASSERT(ret == pdPASS); @@ -773,8 +770,8 @@ npl_freertos_callout_deinit(struct ble_npl_callout *co) uint16_t IRAM_ATTR npl_freertos_sem_get_count(struct ble_npl_sem *sem) { - struct ble_npl_sem_freertos *semaphor = (struct ble_npl_sem_freertos *)sem->sem; - return uxSemaphoreGetCount(semaphor->handle); + struct ble_npl_sem_freertos *semaphore = (struct ble_npl_sem_freertos *)sem->sem; + return uxSemaphoreGetCount(semaphore->handle); } From f7baa7feb2355ed2386048a803a56fd524a13b31 Mon Sep 17 00:00:00 2001 From: cjin Date: Fri, 26 Apr 2024 17:39:10 +0800 Subject: [PATCH 283/548] fix(ble): added c6 config check for ble light sleep --- components/bt/controller/esp32c6/bt.c | 3 +++ examples/bluetooth/nimble/power_save/README.md | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index ca87e35a613..489327f0281 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -581,6 +581,9 @@ esp_err_t controller_sleep_init(void) goto error; } #if CONFIG_FREERTOS_USE_TICKLESS_IDLE +#if CONFIG_BT_LE_SLEEP_ENABLE && !CONFIG_MAC_BB_PD +#error "CONFIG_MAC_BB_PD required for BLE light sleep to run properly" +#endif // CONFIG_BT_LE_SLEEP_ENABLE && !CONFIG_MAC_BB_PD /* Create a new regdma link for BLE related register restoration */ rc = sleep_modem_ble_mac_modem_state_init(1); assert(rc == 0); diff --git a/examples/bluetooth/nimble/power_save/README.md b/examples/bluetooth/nimble/power_save/README.md index bfad7b536dd..048de15e257 100644 --- a/examples/bluetooth/nimble/power_save/README.md +++ b/examples/bluetooth/nimble/power_save/README.md @@ -140,4 +140,5 @@ X: This feature is currently not supported. - ESP32 does not support the use of main XTAL in light sleep mode, so an external 32kHz crystal is required. - ESP32C2 support XTAL frequency of 26MHz and 40MHz, the XTAL frequency is set to 26MHz in default. -- ESP32C2 support external 32kHz crystal by connecting the crystal to the chip through pin0 \ No newline at end of file +- ESP32C2 support external 32kHz crystal by connecting the crystal to the chip through pin0 +- ESP32C6 REQUIRES CONFIG_ESP_PHY_MAC_BB_PD to be set for light sleep to run properly \ No newline at end of file From 4b08ddb0f3081eececbee47bb0078eca4085ab3b Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Sat, 1 Jun 2024 01:48:40 +0800 Subject: [PATCH 284/548] feat(hal_utils): added float to fixed point function --- components/hal/hal_utils.c | 61 ++++++++++++ components/hal/include/hal/hal_utils.h | 33 +++++++ .../test_apps/hal_utils/main/CMakeLists.txt | 1 + .../hal_utils/main/test_fmt_convert.c | 94 +++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 components/hal/test_apps/hal_utils/main/test_fmt_convert.c diff --git a/components/hal/hal_utils.c b/components/hal/hal_utils.c index 68ea4bb60ad..9e4aa794ce6 100644 --- a/components/hal/hal_utils.c +++ b/components/hal/hal_utils.c @@ -7,6 +7,14 @@ #include "hal/hal_utils.h" #include "hal/assert.h" +#ifndef BIT +#define BIT(n) (1UL << (n)) +#endif + +#ifndef BIT_MASK +#define BIT_MASK(n) (BIT(n) - 1) +#endif + __attribute__((always_inline)) static inline uint32_t _sub_abs(uint32_t a, uint32_t b) { @@ -131,3 +139,56 @@ uint32_t hal_utils_calc_clk_div_integer(const hal_utils_clk_info_t *clk_info, ui // Return the actual frequency return clk_info->src_freq_hz / div_integ; } + +typedef union { + struct { + uint32_t mantissa: 23; + uint32_t exponent: 8; + uint32_t sign: 1; + }; + uint32_t val; +} hal_utils_ieee754_float_t; + +int hal_utils_float_to_fixed_point_32b(float flt, const hal_utils_fixed_point_t *fp_cfg, uint32_t *fp_out) +{ + int ret = 0; + uint32_t output = 0; + const hal_utils_ieee754_float_t *f = (const hal_utils_ieee754_float_t *)&flt; + if (fp_cfg->int_bit + fp_cfg->frac_bit > 31) { + // Not supported + return -3; + } + + if (f->val == 0) { // Zero case + *fp_out = 0; + return 0; + } + if (f->exponent != 0xFF) { // Normal case + int real_exp = (int)f->exponent - 127; + uint32_t real_mant = f->mantissa | BIT(23); // Add the hidden bit + // Overflow check + if (real_exp >= (int)fp_cfg->int_bit) { + ret = -1; + } + // Determine sign + output |= f->sign << (fp_cfg->int_bit + fp_cfg->frac_bit); + // Determine integer and fraction part + int shift = 23 - fp_cfg->frac_bit - real_exp; + output |= shift >= 0 ? real_mant >> shift : real_mant << -shift; + } else { + if (f->mantissa && f->mantissa < BIT(23) - 1) { // NaN (Not-a-Number) case + return -2; + } else { // Infinity or Largest Number case + output = f->sign ? ~(uint32_t)0 : BIT(31) - 1; + ret = -1; + } + } + + if (ret != 0 && fp_cfg->saturation) { + *fp_out = (f->sign << (fp_cfg->int_bit + fp_cfg->frac_bit)) | + (BIT_MASK(fp_cfg->int_bit + fp_cfg->frac_bit)); + } else { + *fp_out = output; + } + return ret; +} diff --git a/components/hal/include/hal/hal_utils.h b/components/hal/include/hal/hal_utils.h index b95931c252b..f5860da5737 100644 --- a/components/hal/include/hal/hal_utils.h +++ b/components/hal/include/hal/hal_utils.h @@ -7,6 +7,7 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { @@ -148,6 +149,38 @@ static inline uint32_t hal_utils_calc_lcm(uint32_t a, uint32_t b) return (a * b / hal_utils_gcd(a, b)); } +/** + * @brief Fixed-point data configuration + * + */ +typedef struct { + uint32_t int_bit; /*!< Integer bit of the fixed point */ + uint32_t frac_bit; /*!< Fractional bit of the fixed point */ + bool saturation; /*!< Whether to limit the value to the maximum when fixed-point data overflow. + * When set true, the value will be limited to the maximum when the float type data is out of range. + * When set false, the function will return false when the float type data is out of range. + */ +} hal_utils_fixed_point_t; + +/** + * @brief Convert the float type to fixed point type + * @note The supported data format: + * - [input] float (IEEE 754): + * sign(1bit) + exponent(8bit) + mantissa(23bit) (32 bit in total) + * - [output] fixed-point: + * sign(1bit) + integer(int_bit) + fraction(frac_bit) (less or equal to 32 bit) + * + * @param[in] flt IEEE 754 float type data + * @param[in] fp_cfg Fixed-point data configuration + * @param[out] fp_out The output fixed-point data + * @return + * 0: Success + * -1: Fixed point data overflow, `fp_out` will still be assigned + * -2: Float is NaN + * -3: Invalid configuration + */ +int hal_utils_float_to_fixed_point_32b(float flt, const hal_utils_fixed_point_t *fp_cfg, uint32_t *fp_out); + #ifdef __cplusplus } #endif diff --git a/components/hal/test_apps/hal_utils/main/CMakeLists.txt b/components/hal/test_apps/hal_utils/main/CMakeLists.txt index 09293d7c0e0..927a3601977 100644 --- a/components/hal/test_apps/hal_utils/main/CMakeLists.txt +++ b/components/hal/test_apps/hal_utils/main/CMakeLists.txt @@ -1,4 +1,5 @@ idf_component_register(SRCS "test_app_main.c" + "test_fmt_convert.c" "test_calc_clk_div.c" "test_hal_utils_misc.c" INCLUDE_DIRS "." diff --git a/components/hal/test_apps/hal_utils/main/test_fmt_convert.c b/components/hal/test_apps/hal_utils/main/test_fmt_convert.c new file mode 100644 index 00000000000..04670cb6d21 --- /dev/null +++ b/components/hal/test_apps/hal_utils/main/test_fmt_convert.c @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "hal/hal_utils.h" + +#ifndef BIT +#define BIT(n) (1UL << (n)) +#endif + +TEST_CASE("test_float_to_fixed_point", "[fmt_convert]") +{ + float f_nan = NAN; + float f_inf = INFINITY; + float f0 = 100.9f; + float f_zero = 0; + float f_precise = 0.5f; + float f_int = 2.0f; + float f_frac = 1.0f / 3.0f; + float f_dec = 1.453f; + float f_neg = -1.25f; + uint32_t out = 0; + hal_utils_fixed_point_t fp_cfg = { + .int_bit = 24, + .frac_bit = 8, + .saturation = false, + }; + + // Invalid arguments case + TEST_ASSERT_EQUAL_INT(-3, hal_utils_float_to_fixed_point_32b(f_dec, &fp_cfg, &out)); + printf("Invalid arguments case passed!\n"); + fp_cfg.int_bit = 2; + + // Overflow case + TEST_ASSERT_EQUAL_INT(-1, hal_utils_float_to_fixed_point_32b(f0, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(0x64E6, out); // integ: 0x64 = 100, frac: 0xE6 / 0x100 = 0.8984375 + printf("Overflow case passed!\n"); + + // Not-a-Number case + TEST_ASSERT_EQUAL_INT(-2, hal_utils_float_to_fixed_point_32b(f_nan, &fp_cfg, &out)); + printf("Not-a-Number case passed!\n"); + + // Infinity case + TEST_ASSERT_EQUAL_INT(-1, hal_utils_float_to_fixed_point_32b(f_inf, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(BIT(31) - 1, out); + printf("Infinity case passed!\n"); + + fp_cfg.saturation = true; + // Limit overflow case + TEST_ASSERT_EQUAL_INT(-1, hal_utils_float_to_fixed_point_32b(f0, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(BIT(10) - 1, out); // Limit to the maximum value, integ: 0x03 = 3 | frac: 0xff / 0x100 = 0.99609375 + printf("Limit overflow case passed!\n"); + + // Zero case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_zero, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(0, out); // Special case, 0 = 0 + printf("Zero case passed!\n"); + + // Precision case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_precise, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(BIT(7), out); // frac: 0x80 / 0x100 = 0.5 + printf("Precision case passed!\n"); + + // Integer case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_int, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(BIT(9), out); // integ: 2 | frac: 0x00 / 0x100 = 0 + printf("Integer case passed!\n"); + + // Fraction case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_frac, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(0x055, out); // 0x55 / 0x100 = 0.33203125 + printf("Fraction case passed!\n"); + + // Decimal case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_dec, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(0x173, out); // integ: 0x01 = 1, frac: 0x73 / 0x100 = 0.44921875 + printf("Decimal case passed!\n"); + + // Negative case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f_neg, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(BIT(10) | BIT(8) | (BIT(6)), out); // sign: 1 | integ: 1 | frac: 0x40 / 0x100 = 0.25 + printf("Negative case passed!\n"); + + fp_cfg.int_bit = 8; + // Integer bits case + TEST_ASSERT_EQUAL_INT(0, hal_utils_float_to_fixed_point_32b(f0, &fp_cfg, &out)); + TEST_ASSERT_EQUAL_UINT32(0x64E6, out); // integ: 0x64 = 100, frac: 0xE6 / 0x100 = 0.8984375 + printf("Integer bits case passed!\n"); +} From 8c225c02001a32af2af7e639cebe459ccf04ab02 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Sat, 1 Jun 2024 01:50:25 +0800 Subject: [PATCH 285/548] feat(isp_awb): support isp auto white balance --- components/esp_driver_isp/CMakeLists.txt | 3 +- .../esp_driver_isp/include/driver/isp.h | 1 + .../esp_driver_isp/include/driver/isp_af.h | 2 +- .../esp_driver_isp/include/driver/isp_awb.h | 207 +++++++++++++ .../esp_driver_isp/include/driver/isp_types.h | 33 +++ .../include/esp_private/isp_private.h | 1 + components/esp_driver_isp/src/isp_awb.c | 280 ++++++++++++++++++ .../test_apps/isp/main/test_isp_driver.c | 48 +++ components/hal/esp32p4/include/hal/isp_ll.h | 175 +++++++++++ components/hal/include/hal/isp_hal.h | 67 ++++- components/hal/include/hal/isp_types.h | 14 + components/hal/isp_hal.c | 72 +++++ .../isp/auto_focus/main/isp_af_dsi_main.c | 2 +- 13 files changed, 901 insertions(+), 4 deletions(-) create mode 100644 components/esp_driver_isp/include/driver/isp_awb.h create mode 100644 components/esp_driver_isp/src/isp_awb.c diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index 2a6b0371154..7ce185791b9 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -10,7 +10,8 @@ set(requires) if(CONFIG_SOC_ISP_SUPPORTED) list(APPEND srcs "src/isp_core.c" - "src/isp_af.c") + "src/isp_af.c" + "src/isp_awb.c") endif() if(CONFIG_SOC_ISP_BF_SUPPORTED) diff --git a/components/esp_driver_isp/include/driver/isp.h b/components/esp_driver_isp/include/driver/isp.h index 50674cb7b2d..38088eb9388 100644 --- a/components/esp_driver_isp/include/driver/isp.h +++ b/components/esp_driver_isp/include/driver/isp.h @@ -13,4 +13,5 @@ #include "driver/isp_core.h" #include "driver/isp_af.h" +#include "driver/isp_awb.h" #include "driver/isp_bf.h" diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index d3d9522d79b..67bfa58b52e 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -178,7 +178,7 @@ typedef struct { /** * @brief Prototype of ISP AF Env detector event callback * - * @param[in] handle ISP AF controller handle + * @param[in] af_ctrlr ISP AF controller handle * @param[in] edata ISP AF Env detector event data * @param[in] user_data User registered context, registered when in `esp_isp_af_env_detector_register_event_callbacks()` * diff --git a/components/esp_driver_isp/include/driver/isp_awb.h b/components/esp_driver_isp/include/driver/isp_awb.h new file mode 100644 index 00000000000..64dab9e7872 --- /dev/null +++ b/components/esp_driver_isp/include/driver/isp_awb.h @@ -0,0 +1,207 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "driver/isp_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief AWB controller config + */ +typedef struct { + isp_awb_sample_point_t sample_point; /*!< AWB sample point of the ISP pipeline. + * ISP_AWB_SAMPLE_POINT_BEFORE_CCM: sample before Color Correction Matrix(CCM). + * ISP_AWB_SAMPLE_POINT_AFTER_CCM: sample after Color Correction Matrix(CCM). + * If your camera support to set the manual gain to the RGB channels, + * then you can choose to sample before CCM, and set the gain to the camera registers. + * If your camera doesn't support the manual gain or don't want to change the camera configuration, + * then you can choose to sample after CCM, and set the calculated gain to the CCM + */ + isp_window_t window; /*!< Statistic window of AWB. + * Suggest to set it at the middle of the image and a little smaller than the whole image. + * It will be more reliable because the edges of image are easily to be overexposure, + * the overexposure pixels are almost at maximum luminance, + * which are not good references to calculate the gain for white balance. + */ + struct { + isp_u32_range_t luminance; /*!< Luminance range of the white patch. Range [0, 255 * 3] + * Not suggest to set the max value to 255 * 3, + * because these pixels are too bright, very possible to be overexposure. + * So the pixels that too bright should not be the reference of the white balance. + * And the minimum value better to be 0 to allow the white balance work under low luminance environment. + */ + isp_float_range_t red_green_ratio; /*!< Red to green ratio of the white patch. Range [0, 4.0). + * The ratio could be as wider as possible, + * so that all the distorted pixels will be counted for the reference of white balance. + */ + isp_float_range_t blue_green_ratio; /*!< Blue to green ratio of the white patch. Range [0, 4.0) + * The ratio could be as wider as possible, + * so that all the distorted pixels will be counted for the reference of white balance. + */ + } white_patch; /*!< white patch configuration */ + int intr_priority; /*!< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with + * a relative low priority (1,2,3) otherwise the larger the higher, 7 is NMI. + */ +} esp_isp_awb_config_t; + +/** + * @brief New an ISP AWB controller + * + * @param[in] isp_proc ISP Processor handle + * @param[in] awb_cfg Pointer to AWB config. Refer to ``esp_isp_awb_config_t``. + * @param[out] ret_hdl AWB controller handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid + * - ESP_ERR_INVALID_STATE Invalid state + * - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags + * - ESP_ERR_NO_MEM If out of memory + */ +esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_awb_config_t *awb_cfg, isp_awb_ctlr_t *ret_hdl); + +/** + * @brief Delete an ISP AWB controller + * + * @param[in] awb_ctlr AWB controller handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_del_awb_controller(isp_awb_ctlr_t awb_ctlr); + +/** + * @brief Enable an ISP AWB controller + * + * @param[in] awb_ctlr AWB controller handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_enable(isp_awb_ctlr_t awb_ctlr); + +/** + * @brief Disable an ISP AWB controller + * + * @param[in] awb_ctlr AWB controller handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_disable(isp_awb_ctlr_t awb_ctlr); + +/** + * @brief Trigger AWB white patch statistics for one time and get the result + * @note This function is a synchronous and block function, + * it only returns when AWB white patch statistics is done or timeout. + * It's a simple method to get the result directly for one time. + * + * @param[in] awb_ctlr AWB controller handle + * @param[in] timeout_ms Timeout in millisecond + * - timeout_ms < 0: Won't return until finished + * - timeout_ms = 0: No timeout, trigger one time statistics and return immediately, + * in this case, the result won't be assigned in this function, + * but you can get the result in the callback `esp_isp_awb_cbs_t::on_statistics_done` + * - timeout_ms > 0: Wait for specified milliseconds, if not finished, then return timeout error + * @param[out] out_res AWB white patch statistics result + * + * @return + * - ESP_OK On success + * - ESP_ERR_TIMEOUT Wait for the result timeout + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_get_oneshot_statistics(isp_awb_ctlr_t awb_ctlr, int timeout_ms, isp_awb_stat_result_t *out_res); + +/** + * @brief Start AWB continuous statistics of the white patch in the window + * @note This function is an asynchronous and non-block function, + * it will start the continuous statistics and return immediately. + * You have to register the AWB callback and get the result from the callback event data. + * + * @param[in] awb_ctlr AWB controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Null pointer + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_start_continuous_statistics(isp_awb_ctlr_t awb_ctlr); + +/** + * @brief Stop AWB continuous statistics of the white patch in the window + * + * @param[in] awb_ctlr AWB controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Null pointer + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_awb_controller_stop_continuous_statistics(isp_awb_ctlr_t awb_ctlr); + +/** + * @brief Event data of callbacks + */ +typedef struct { + isp_awb_stat_result_t awb_result; /*!< The AWB white patch statistics result */ +} esp_isp_awb_evt_data_t; + +/** + * @brief Prototype of ISP AWB event callback + * + * @param[in] handle ISP AWB controller handle + * @param[in] edata ISP AWB event data + * @param[in] user_data User registered context, registered when in `esp_isp_awb_env_detector_register_event_callbacks()` + * + * @return Whether a high priority task is woken up by this function + */ +typedef bool (*esp_isp_awb_callback_t)(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_evt_data_t *edata, void *user_data); + +/** + * @brief Group of ISP AWB callbacks + * + * @note These callbacks are all running in an ISR environment. + * @note When CONFIG_ISP_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * Involved variables should be in internal RAM as well. + */ +typedef struct { + esp_isp_awb_callback_t on_statistics_done; ///< Event callback, invoked when white patches statistic done. +} esp_isp_awb_cbs_t; + +/** + * @brief Register AWB event callbacks + * + * @note User can deregister a previously registered callback by calling this function and setting the to-be-deregistered callback member in + * the `cbs` structure to NULL. + * @note When CONFIG_ISP_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM. + * Involved variables (including `user_data`) should be in internal RAM as well. + * + * @param[in] awb_ctlr AWB controller handle + * @param[in] cbs Group of callback functions + * @param[in] user_data User data, which will be delivered to the callback functions directly + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments + * - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment + */ +esp_err_t esp_isp_awb_register_event_callbacks(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_cbs_t *cbs, void *user_data); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_isp/include/driver/isp_types.h b/components/esp_driver_isp/include/driver/isp_types.h index f374793d2cd..a8baa1926e2 100644 --- a/components/esp_driver_isp/include/driver/isp_types.h +++ b/components/esp_driver_isp/include/driver/isp_types.h @@ -12,6 +12,34 @@ extern "C" { #endif +/** + * @brief ISP unsigned integer range type + * @note Whether the edge value are included depends on the variable itself + */ +typedef struct { + uint32_t min; ///< Minimum unsigned int value + uint32_t max; ///< Maximum unsigned int value +} isp_u32_range_t; + +/** + * @brief ISP float range type + * @note Whether the edge value are included depends on the variable itself + */ +typedef struct { + float min; ///< Minimum float value + float max; ///< Maximum float value +} isp_float_range_t; + +/** + * @brief ISP AWB result + */ +typedef struct { + uint32_t white_patch_num; ///< white patch number that counted by AWB in the window + uint32_t sum_r; ///< The sum of R channel of these white patches + uint32_t sum_g; ///< The sum of G channel of these white patches + uint32_t sum_b; ///< The sum of B channel of these white patches +} isp_awb_stat_result_t; + /** * @brief Type of ISP processor handle */ @@ -22,6 +50,11 @@ typedef struct isp_processor_t *isp_proc_handle_t; */ typedef struct isp_af_controller_t *isp_af_ctlr_t; +/** + * @brief Type of ISP AWB controller handle + */ +typedef struct isp_awb_controller_t *isp_awb_ctlr_t; + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_isp/include/esp_private/isp_private.h b/components/esp_driver_isp/include/esp_private/isp_private.h index 7b25b298828..03b0f078434 100644 --- a/components/esp_driver_isp/include/esp_private/isp_private.h +++ b/components/esp_driver_isp/include/esp_private/isp_private.h @@ -64,6 +64,7 @@ typedef struct isp_processor_t { uint32_t v_res; /* sub module contexts */ isp_af_ctlr_t af_ctlr[SOC_ISP_AF_CTLR_NUMS]; + isp_awb_ctlr_t awb_ctlr; isp_fsm_t bf_fsm; } isp_processor_t; #endif diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c new file mode 100644 index 00000000000..b1a4523d307 --- /dev/null +++ b/components/esp_driver_isp/src/isp_awb.c @@ -0,0 +1,280 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "driver/isp_awb.h" +#include "isp_internal.h" + +typedef struct isp_awb_controller_t { + isp_fsm_t fsm; + portMUX_TYPE spinlock; + intr_handle_t intr_handle; + isp_proc_handle_t isp_proc; + QueueHandle_t evt_que; + SemaphoreHandle_t stat_lock; + esp_isp_awb_cbs_t cbs; + void *user_data; +} isp_awb_controller_t; + +static const char *TAG = "ISP_AWB"; + +static void s_isp_awb_default_isr(void *arg); + +/*--------------------------------------------- + AWB +----------------------------------------------*/ +static esp_err_t s_isp_claim_awb_controller(isp_proc_handle_t isp_proc, isp_awb_ctlr_t awb_ctlr) +{ + assert(isp_proc && awb_ctlr); + + esp_err_t ret = ESP_ERR_NOT_FOUND; + portENTER_CRITICAL(&isp_proc->spinlock); + if (!isp_proc->awb_ctlr) { + isp_proc->awb_ctlr = awb_ctlr; + ret = ESP_OK; + } + portEXIT_CRITICAL(&isp_proc->spinlock); + + return ret; +} + +static void s_isp_declaim_awb_controller(isp_awb_ctlr_t awb_ctlr) +{ + if (awb_ctlr && awb_ctlr->isp_proc) { + portENTER_CRITICAL(&awb_ctlr->isp_proc->spinlock); + awb_ctlr->isp_proc->awb_ctlr = NULL; + portEXIT_CRITICAL(&awb_ctlr->isp_proc->spinlock); + } +} + +static void s_isp_awb_free_controller(isp_awb_ctlr_t awb_ctlr) +{ + if (awb_ctlr) { + if (awb_ctlr->intr_handle) { + esp_intr_free(awb_ctlr->intr_handle); + } + if (awb_ctlr->evt_que) { + vQueueDelete(awb_ctlr->evt_que); + } + if (awb_ctlr->stat_lock) { + vSemaphoreDelete(awb_ctlr->stat_lock); + } + free(awb_ctlr); + } +} + +esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_awb_config_t *awb_cfg, isp_awb_ctlr_t *ret_hdl) +{ + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE(isp_proc && awb_cfg && ret_hdl, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + isp_awb_ctlr_t awb_ctlr = heap_caps_calloc(1, sizeof(isp_awb_controller_t), ISP_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(awb_ctlr, ESP_ERR_NO_MEM, TAG, "no mem for awb controller"); + awb_ctlr->evt_que = xQueueCreateWithCaps(1, sizeof(isp_awb_stat_result_t), ISP_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(awb_ctlr->evt_que, ESP_ERR_NO_MEM, err1, TAG, "no mem for awb event queue"); + awb_ctlr->stat_lock = xSemaphoreCreateBinaryWithCaps(ISP_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(awb_ctlr->stat_lock, ESP_ERR_NO_MEM, err1, TAG, "no mem for awb semaphore"); + awb_ctlr->fsm = ISP_FSM_INIT; + awb_ctlr->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + awb_ctlr->isp_proc = isp_proc; + + // Claim an AWB controller + ESP_GOTO_ON_ERROR(s_isp_claim_awb_controller(isp_proc, awb_ctlr), err1, TAG, "no available controller"); + // Register the AWB ISR + uint32_t intr_st_reg_addr = isp_ll_get_intr_status_reg_addr(isp_proc->hal.hw); + int intr_priority = awb_cfg->intr_priority > 0 && awb_cfg->intr_priority <= 7 ? BIT(awb_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; + ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(isp_hw_info.instances[isp_proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | intr_priority, intr_st_reg_addr, ISP_LL_EVENT_AWB_MASK, + s_isp_awb_default_isr, awb_ctlr, &awb_ctlr->intr_handle), err2, TAG, "allocate interrupt failed"); + + // Configure the hardware + isp_ll_awb_enable(isp_proc->hal.hw, false); + isp_ll_awb_set_sample_point(isp_proc->hal.hw, awb_cfg->sample_point); + isp_ll_awb_enable_algorithm_mode(isp_proc->hal.hw, true); + ESP_GOTO_ON_FALSE(isp_hal_awb_set_window_range(&isp_proc->hal, &awb_cfg->window), + ESP_ERR_INVALID_ARG, err2, TAG, "invalid window"); + isp_u32_range_t lum_range = awb_cfg->white_patch.luminance; + ESP_GOTO_ON_FALSE(isp_hal_awb_set_luminance_range(&isp_proc->hal, lum_range.min, lum_range.max), + ESP_ERR_INVALID_ARG, err2, TAG, "invalid luminance range"); + isp_float_range_t rg_range = awb_cfg->white_patch.red_green_ratio; + ESP_GOTO_ON_FALSE(rg_range.min < rg_range.max && rg_range.min >= 0 && + isp_hal_awb_set_rg_ratio_range(&isp_proc->hal, rg_range.min, rg_range.max), + ESP_ERR_INVALID_ARG, err2, TAG, "invalid range of Red Green ratio"); + isp_float_range_t bg_range = awb_cfg->white_patch.blue_green_ratio; + ESP_GOTO_ON_FALSE(bg_range.min < bg_range.max && bg_range.min >= 0 && + isp_hal_awb_set_bg_ratio_range(&isp_proc->hal, bg_range.min, bg_range.max), + ESP_ERR_INVALID_ARG, err2, TAG, "invalid range of Blue to Green ratio"); + + *ret_hdl = awb_ctlr; + + return ESP_OK; + +err2: + s_isp_declaim_awb_controller(awb_ctlr); +err1: + s_isp_awb_free_controller(awb_ctlr); + + return ret; +} + +esp_err_t esp_isp_del_awb_controller(isp_awb_ctlr_t awb_ctlr) +{ + ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(awb_ctlr->isp_proc->awb_ctlr == awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "controller isn't in use"); + ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + s_isp_declaim_awb_controller(awb_ctlr); + + isp_ll_awb_enable_algorithm_mode(awb_ctlr->isp_proc->hal.hw, false); + s_isp_awb_free_controller(awb_ctlr); + + return ESP_OK; +} + +esp_err_t esp_isp_awb_controller_enable(isp_awb_ctlr_t awb_ctlr) +{ + ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + + esp_intr_enable(awb_ctlr->intr_handle); + isp_ll_awb_clk_enable(awb_ctlr->isp_proc->hal.hw, true); + isp_ll_enable_intr(awb_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AWB_MASK, true); + xSemaphoreGive(awb_ctlr->stat_lock); + awb_ctlr->fsm = ISP_FSM_ENABLE; + + return ESP_OK; +} + +esp_err_t esp_isp_awb_controller_disable(isp_awb_ctlr_t awb_ctlr) +{ + ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + + isp_ll_enable_intr(awb_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AWB_MASK, false); + isp_ll_awb_clk_enable(awb_ctlr->isp_proc->hal.hw, false); + esp_intr_disable(awb_ctlr->intr_handle); + awb_ctlr->fsm = ISP_FSM_INIT; + xSemaphoreTake(awb_ctlr->stat_lock, 0); + + return ESP_OK; +} + +esp_err_t esp_isp_awb_controller_get_oneshot_statistics(isp_awb_ctlr_t awb_ctlr, int timeout_ms, isp_awb_stat_result_t *out_res) +{ + ESP_RETURN_ON_FALSE_ISR(awb_ctlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + TickType_t ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + + xSemaphoreTake(awb_ctlr->stat_lock, ticks); + // Update state to avoid race condition + awb_ctlr->fsm = ISP_FSM_START; + esp_err_t ret = ESP_OK; + // Reset the queue in case receiving the legacy data in the queue + xQueueReset(awb_ctlr->evt_que); + // Start the AWB white patch statistics and waiting it done + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, true); + // Wait the statistics to finish and receive the result from the queue + if ((ticks > 0) && xQueueReceive(awb_ctlr->evt_que, out_res, ticks) != pdTRUE) { + ret = ESP_ERR_TIMEOUT; + } + // Stop the AWB white patch statistics + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, false); + awb_ctlr->fsm = ISP_FSM_ENABLE; + xSemaphoreGive(awb_ctlr->stat_lock); + + return ret; +} + +esp_err_t esp_isp_awb_controller_start_continuous_statistics(isp_awb_ctlr_t awb_ctlr) +{ + ESP_RETURN_ON_FALSE_ISR(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + + if (xSemaphoreTake(awb_ctlr->stat_lock, 0) == pdFALSE) { + ESP_LOGW(TAG, "statistics lock is not acquired, controller is busy"); + return ESP_ERR_INVALID_STATE; + } + awb_ctlr->fsm = ISP_FSM_START; + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, true); + + return ESP_OK; +} + +esp_err_t esp_isp_awb_controller_stop_continuous_statistics(isp_awb_ctlr_t awb_ctlr) +{ + ESP_RETURN_ON_FALSE_ISR(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); + + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, false); + awb_ctlr->fsm = ISP_FSM_ENABLE; + xSemaphoreGive(awb_ctlr->stat_lock); + + return ESP_OK; +} + +/*--------------------------------------------------------------- + INTR +---------------------------------------------------------------*/ +static void IRAM_ATTR s_isp_awb_default_isr(void *arg) +{ + isp_awb_ctlr_t awb_ctlr = (isp_awb_ctlr_t)arg; + isp_proc_handle_t proc = awb_ctlr->isp_proc; + + uint32_t awb_events = isp_hal_check_clear_intr_event(&proc->hal, ISP_LL_EVENT_AWB_MASK); + + bool need_yield = false; + + if (awb_events & ISP_LL_EVENT_AWB_FDONE) { + isp_awb_ctlr_t awb_ctlr = proc->awb_ctlr; + // Get the statistics result + esp_isp_awb_evt_data_t edata = { + .awb_result = { + .white_patch_num = isp_ll_awb_get_white_patcherence_cnt(proc->hal.hw), + .sum_r = isp_ll_awb_get_accumulated_r_value(proc->hal.hw), + .sum_g = isp_ll_awb_get_accumulated_g_value(proc->hal.hw), + .sum_b = isp_ll_awb_get_accumulated_b_value(proc->hal.hw), + }, + }; + // Invoke the callback if the callback is registered + if (awb_ctlr->cbs.on_statistics_done) { + need_yield |= awb_ctlr->cbs.on_statistics_done(awb_ctlr, &edata, awb_ctlr->user_data); + } + BaseType_t high_task_awake = false; + // Send the event data to the queue, overwrite the legacy one if exist + xQueueOverwriteFromISR(awb_ctlr->evt_que, &edata.awb_result, &high_task_awake); + need_yield |= high_task_awake == pdTRUE; + /* If started continuous sampling, then trigger the next AWB sample */ + if (awb_ctlr->fsm == ISP_FSM_START) { + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, true); + } + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +esp_err_t esp_isp_awb_register_event_callbacks(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_cbs_t *cbs, void *user_data) +{ + ESP_RETURN_ON_FALSE(awb_ctlr && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "detector isn't in the init state"); +#if CONFIG_ISP_ISR_IRAM_SAFE + if (cbs->on_statistics_done) { + ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_env_change), ESP_ERR_INVALID_ARG, TAG, "on_env_change callback not in IRAM"); + } + if (user_data) { + ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); + } +#endif + awb_ctlr->cbs.on_statistics_done = cbs->on_statistics_done; + awb_ctlr->user_data = user_data; + + return ESP_OK; +} diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index c6a3abcbe96..33b6c84cb90 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -56,3 +56,51 @@ TEST_CASE("ISP AF controller exhausted allocation", "[isp]") } TEST_ESP_OK(esp_isp_del_processor(isp_proc)); } + +TEST_CASE("ISP AWB driver basic function", "[isp]") +{ + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 80 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_CSI, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + }; + isp_proc_handle_t isp_proc = NULL; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + TEST_ESP_OK(esp_isp_enable(isp_proc)); + + isp_awb_ctlr_t awb_ctlr = NULL; + uint32_t image_width = 800; + uint32_t image_height = 600; + /* Default parameters from helper macro */ + esp_isp_awb_config_t awb_config = { + .sample_point = ISP_AWB_SAMPLE_POINT_AFTER_CCM, + .window = { + .top_left = {.x = image_width * 0.2, .y = image_height * 0.2}, + .btm_right = {.x = image_width * 0.8, .y = image_height * 0.8}, + }, + .white_patch = { + .luminance = {.min = 0, .max = 220 * 3}, + .red_green_ratio = {.min = 0.0f, .max = 3.999f}, + .blue_green_ratio = {.min = 0.0f, .max = 3.999f}, + }, + }; + isp_awb_stat_result_t stat_res = {}; + /* Create the awb controller */ + TEST_ESP_OK(esp_isp_new_awb_controller(isp_proc, &awb_config, &awb_ctlr)); + /* Enabled the awb controller */ + TEST_ESP_OK(esp_isp_awb_controller_enable(awb_ctlr)); + /* Start continuous AWB statistics */ + TEST_ESP_OK(esp_isp_awb_controller_start_continuous_statistics(awb_ctlr)); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_isp_awb_controller_get_oneshot_statistics(awb_ctlr, 0, &stat_res)); + /* Stop continuous AWB statistics */ + TEST_ESP_OK(esp_isp_awb_controller_stop_continuous_statistics(awb_ctlr)); + TEST_ESP_ERR(ESP_ERR_TIMEOUT, esp_isp_awb_controller_get_oneshot_statistics(awb_ctlr, 1, &stat_res)); + /* Disable the awb controller */ + TEST_ESP_OK(esp_isp_awb_controller_disable(awb_ctlr)); + /* Delete the awb controller and free the resources */ + TEST_ESP_OK(esp_isp_del_awb_controller(awb_ctlr)); + + TEST_ESP_OK(esp_isp_disable(isp_proc)); + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); +} diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index eaf0760e1a0..1636882ba91 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -65,6 +65,7 @@ extern "C" { #define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF) #define ISP_LL_EVENT_AF_MASK (ISP_LL_EVENT_AF_FDONE | ISP_LL_EVENT_AF_ENV) +#define ISP_LL_EVENT_AWB_MASK (ISP_LL_EVENT_AWB_FDONE) /*--------------------------------------------------------------- AF @@ -83,6 +84,22 @@ extern "C" { #define ISP_LL_DVP_DATA_TYPE_RAW10 0x2B #define ISP_LL_DVP_DATA_TYPE_RAW12 0x2C +/*--------------------------------------------------------------- + AWB +---------------------------------------------------------------*/ +#define ISP_LL_AWB_WINDOW_MAX_RANGE ((1<<12) - 1) +#define ISP_LL_AWB_LUM_MAX_RANGE ((1<<10) - 1) +#define ISP_LL_AWB_RGB_RATIO_INT_BITS (2) +#define ISP_LL_AWB_RGB_RATIO_FRAC_BITS (8) + +typedef union { + struct { + uint32_t fraction: ISP_LL_AWB_RGB_RATIO_FRAC_BITS; + uint32_t integer: ISP_LL_AWB_RGB_RATIO_INT_BITS; + }; + uint32_t val; +} isp_ll_awb_rgb_ratio_t; + /** * @brief Env monitor mode */ @@ -992,6 +1009,164 @@ static inline void isp_ll_clear_intr(isp_dev_t *hw, uint32_t mask) hw->int_clr.val = mask; } +/*--------------------------------------------------------------- + AWB +---------------------------------------------------------------*/ +/** + * @brief Enable / Disable AWB clock + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +static inline void isp_ll_awb_clk_enable(isp_dev_t *hw, bool enable) +{ + hw->clk_en.clk_awb_force_on = enable; +} + +/** + * @brief Enable AWB statistics + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable / Disable + */ +__attribute__((always_inline)) +static inline void isp_ll_awb_enable(isp_dev_t *hw, bool enable) +{ + hw->cntl.awb_en = enable; +} + +/** + * @brief Set AWB sample point + * + * @param[in] hw Hardware instance address + * @param[in] point Sample point + * - 0: Before CCM + * - 1: After CCM + */ +static inline void isp_ll_awb_set_sample_point(isp_dev_t *hw, isp_awb_sample_point_t point) +{ + hw->awb_mode.awb_sample = point; +} + +/** + * @brief Set AWB algorithm mode + * + * @param[in] hw Hardware instance address + * @param[in] enable Enable algorithm mode 1 + */ +static inline void isp_ll_awb_enable_algorithm_mode(isp_dev_t *hw, bool enable) +{ + hw->awb_mode.awb_mode = enable; +} + +/** + * @brief Set AWB window range + * + * @param[in] hw Hardware instance address + * @param[in] top_left_x Top left pixel x axis value + * @param[in] top_left_y Top left pixel y axis value + * @param[in] bottom_right_x Bottom right pixel x axis value + * @param[in] bottom_right_y Bottom right pixel y axis value + */ +static inline void isp_ll_awb_set_window_range(isp_dev_t *hw, uint32_t top_left_x, uint32_t top_left_y, uint32_t bottom_right_x, uint32_t bottom_right_y) +{ + hw->awb_hscale.awb_lpoint = top_left_x; + hw->awb_vscale.awb_tpoint = top_left_y; + hw->awb_hscale.awb_rpoint = bottom_right_x; + hw->awb_vscale.awb_bpoint = bottom_right_y; +} + +/** + * @brief Set AWB luminance range + * + * @param[in] hw Hardware instance address + * @param[in] min Minimum luminance + * @param[in] max Maximum luminance + */ +static inline void isp_ll_awb_set_luminance_range(isp_dev_t *hw, uint32_t min, uint32_t max) +{ + hw->awb_th_lum.awb_min_lum = min; + hw->awb_th_lum.awb_max_lum = max; +} + +/** + * @brief Set AWB R/G ratio range + * + * @param[in] hw Hardware instance address + * @param[in] min Minimum R/G ratio in fixed-point data type + * @param[in] max Maximum R/G ratio in fixed-point data type + */ +static inline void isp_ll_awb_set_rg_ratio_range(isp_dev_t *hw, isp_ll_awb_rgb_ratio_t min, isp_ll_awb_rgb_ratio_t max) +{ + hw->awb_th_rg.awb_min_rg = min.val; + hw->awb_th_rg.awb_max_rg = max.val; +} + +/** + * @brief Set AWB B/G ratio range + * + * @param[in] hw Hardware instance address + * @param[in] min Minimum B/G ratio in fixed-point data type + * @param[in] max Maximum B/G ratio in fixed-point data type + */ +static inline void isp_ll_awb_set_bg_ratio_range(isp_dev_t *hw, isp_ll_awb_rgb_ratio_t min, isp_ll_awb_rgb_ratio_t max) +{ + hw->awb_th_bg.awb_min_bg = min.val; + hw->awb_th_bg.awb_max_bg = max.val; +} + +/** + * @brief Get AWB white patch count + * + * @param[in] hw Hardware instance address + * @return + * - white patch count + */ +__attribute__((always_inline)) +static inline uint32_t isp_ll_awb_get_white_patcherence_cnt(isp_dev_t *hw) +{ + return hw->awb0_white_cnt.awb0_white_cnt; +} + +/** + * @brief Get AWB accumulated R value of white patches + * + * @param[in] hw Hardware instance address + * @return + * - Accumulated R value of white patches + */ +__attribute__((always_inline)) +static inline uint32_t isp_ll_awb_get_accumulated_r_value(isp_dev_t *hw) +{ + return hw->awb0_acc_r.awb0_acc_r; +} + +/** + * @brief Get AWB accumulated G value of white patches + * + * @param[in] hw Hardware instance address + * @return + * - Accumulated G value of white patches + */ +__attribute__((always_inline)) +static inline uint32_t isp_ll_awb_get_accumulated_g_value(isp_dev_t *hw) +{ + return hw->awb0_acc_g.awb0_acc_g; +} + +/** + * @brief Get AWB accumulated B value of white patches + * + * @param[in] hw Hardware instance address + * @return + * - Accumulated B value of white patches + */ +__attribute__((always_inline)) +static inline uint32_t isp_ll_awb_get_accumulated_b_value(isp_dev_t *hw) +{ + return hw->awb0_acc_b.awb0_acc_b; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index c239fa43184..335c8b92dc2 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -13,7 +13,9 @@ #pragma once #include +#include #include "hal/isp_types.h" +#include "hal/hal_utils.h" #ifdef __cplusplus extern "C" { @@ -60,7 +62,7 @@ void isp_hal_init(isp_hal_context_t *hal, int isp_id); * * @param[in] hal Context of the HAL layer * @param[in] window_id Window ID - * @param[in] window Window info, see `isp_af_window_t` + * @param[in] window Window info, see `isp_window_t` */ void isp_hal_af_window_config(const isp_hal_context_t *hal, int window_id, const isp_window_t *window); @@ -86,6 +88,69 @@ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t m */ void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config); +/*--------------------------------------------------------------- + Color Correction Matrix +---------------------------------------------------------------*/ +/** + * @brief Set Color Correction Matrix + * + * @param[in] hal Context of the HAL layer + * @param[in] saturation Whether to enable saturation when float data overflow + * @param[in] flt_matrix 3x3 RGB correction matrix + * @return + * - true Set success + * - false Invalid are + */ +bool isp_hal_ccm_set_matrix(const isp_hal_context_t *hal, bool saturation, const float flt_matrix[3][3]); + +/*--------------------------------------------------------------- + AWB +---------------------------------------------------------------*/ +/** + * @brief Set the window of the AWB + * + * @param[in] hal Context of the HAL layer + * @param[in] win Pointer to the window of the AWB + * @return + * - true Set success + * - false Invalid arg + */ +bool isp_hal_awb_set_window_range(const isp_hal_context_t *hal, const isp_window_t *win); + +/** + * @brief Set the luminance range of the white patch + * + * @param[in] hal Context of the HAL layer + * @param[in] lum_min Minimum luminance + * @param[in] lum_max Maximum luminance + * @return + * - true Set success + * - false Invalid arg + */ +bool isp_hal_awb_set_luminance_range(const isp_hal_context_t *hal, uint32_t lum_min, uint32_t lum_max); + +/** + * @brief Set the R/G ratio of the white patch + * + * @param[in] hal Context of the HAL layer + * @param[in] rg_ratio_range Range of Red to Green ratio + * @return + * - true Set success + * - false Invalid arg + */ +bool isp_hal_awb_set_rg_ratio_range(const isp_hal_context_t *hal, float rg_min, float rg_max); + +/** + * @brief Set the B/R ratio of the white patch + * + * @param[in] hal Context of the HAL layer + * @param[in] bg_ratio_range Range of Blue to Green ratio + * @return + * - true Set success + * - false Invalid arg + */ +bool isp_hal_awb_set_bg_ratio_range(const isp_hal_context_t *hal, float bg_min, float bg_max); + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 2d02ae3cd81..be08bd177bc 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -108,6 +108,20 @@ typedef enum { ISP_BF_EDGE_PADDING_MODE_CUSTOM_DATA, ///< Fill BF edge padding data with custom pixel data } isp_bf_edge_padding_mode_t; +/*--------------------------------------------------------------- + AWB +---------------------------------------------------------------*/ + +/** + * @brief ISP AWB sample point in the ISP pipeline + * + */ +typedef enum { + ISP_AWB_SAMPLE_POINT_BEFORE_CCM, ///< Sample AWB data before CCM (Color Correction Matrix) + ISP_AWB_SAMPLE_POINT_AFTER_CCM, ///< Sample AWB data after CCM (Color Correction Matrix) +} isp_awb_sample_point_t; + + #ifdef __cplusplus } #endif diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index 16b496a3af9..96de231e919 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include "sdkconfig.h" @@ -13,6 +14,9 @@ #include "hal/isp_hal.h" #include "hal/isp_ll.h" #include "hal/isp_types.h" +#include "hal/hal_utils.h" + +#include "esp_rom_sys.h" /** * ISP HAL layer @@ -68,3 +72,71 @@ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t m return triggered_events; } +/*--------------------------------------------------------------- + AWB +---------------------------------------------------------------*/ +bool isp_hal_awb_set_window_range(const isp_hal_context_t *hal, const isp_window_t *win) +{ + if (win->top_left.x > win->btm_right.x || + win->top_left.y > win->btm_right.y || + win->btm_right.x > ISP_LL_AWB_WINDOW_MAX_RANGE || + win->btm_right.y > ISP_LL_AWB_WINDOW_MAX_RANGE) { + return false; + } + isp_ll_awb_set_window_range(hal->hw, win->top_left.x, win->top_left.y, + win->btm_right.x, win->btm_right.y); + return true; +} + +bool isp_hal_awb_set_luminance_range(const isp_hal_context_t *hal, uint32_t lum_min, uint32_t lum_max) +{ + if (lum_min > lum_max || lum_max > ISP_LL_AWB_LUM_MAX_RANGE) { + return false; + } + isp_ll_awb_set_luminance_range(hal->hw, lum_min, lum_max); + return true; +} + +bool isp_hal_awb_set_rg_ratio_range(const isp_hal_context_t *hal, float rg_min, float rg_max) +{ + // Convert to fixed point + isp_ll_awb_rgb_ratio_t fp_rg_min = {}; + isp_ll_awb_rgb_ratio_t fp_rg_max = {}; + hal_utils_fixed_point_t fp_cfg = { + .int_bit = ISP_LL_AWB_RGB_RATIO_INT_BITS, + .frac_bit = ISP_LL_AWB_RGB_RATIO_FRAC_BITS, + .saturation = false, + }; + if (hal_utils_float_to_fixed_point_32b(rg_min, &fp_cfg, &fp_rg_min.val) != 0) { + return false; + } + if (hal_utils_float_to_fixed_point_32b(rg_max, &fp_cfg, &fp_rg_max.val) != 0) { + return false; + } + + // Set AWB white patch R/G ratio range + isp_ll_awb_set_rg_ratio_range(hal->hw, fp_rg_min, fp_rg_max); + return true; +} + +bool isp_hal_awb_set_bg_ratio_range(const isp_hal_context_t *hal, float bg_min, float bg_max) +{ + // Convert to fixed point + isp_ll_awb_rgb_ratio_t fp_bg_min = {}; + isp_ll_awb_rgb_ratio_t fp_bg_max = {}; + hal_utils_fixed_point_t fp_cfg = { + .int_bit = ISP_LL_AWB_RGB_RATIO_INT_BITS, + .frac_bit = ISP_LL_AWB_RGB_RATIO_FRAC_BITS, + .saturation = false, + }; + if (hal_utils_float_to_fixed_point_32b(bg_min, &fp_cfg, &fp_bg_min.val) != 0) { + return false; + } + if (hal_utils_float_to_fixed_point_32b(bg_max, &fp_cfg, &fp_bg_max.val) != 0) { + return false; + } + + // Set AWB white patch B/G ratio range + isp_ll_awb_set_bg_ratio_range(hal->hw, fp_bg_min, fp_bg_max); + return true; +} diff --git a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c index d8f84c2b0c1..2e60bac2551 100644 --- a/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c +++ b/examples/peripherals/isp/auto_focus/main/isp_af_dsi_main.c @@ -92,7 +92,7 @@ static void af_task(void *arg) /** * AF window, windows for ISP hardware to record the - * - lunimance + * - luminance * - definition * of the current windows */ From 4b3e01407635c373e552c563a3423c7271d76003 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Sat, 1 Jun 2024 01:54:21 +0800 Subject: [PATCH 286/548] docs(isp_awb): add isp awb programming guide --- .../esp_driver_isp/include/driver/isp_af.h | 2 +- .../esp_driver_isp/include/driver/isp_types.h | 8 + components/esp_driver_isp/src/isp_awb.c | 43 ++-- .../test_apps/isp/main/test_isp_driver.c | 14 ++ components/hal/esp32p4/include/hal/isp_ll.h | 2 +- components/hal/include/hal/isp_hal.h | 15 -- components/hal/include/hal/isp_types.h | 10 +- components/hal/isp_hal.c | 2 - docs/en/api-reference/peripherals/isp.rst | 221 ++++++++++++++---- 9 files changed, 229 insertions(+), 88 deletions(-) diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 67bfa58b52e..8a69698d24e 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -178,7 +178,7 @@ typedef struct { /** * @brief Prototype of ISP AF Env detector event callback * - * @param[in] af_ctrlr ISP AF controller handle + * @param[in] af_ctrlr ISP AF controller handle * @param[in] edata ISP AF Env detector event data * @param[in] user_data User registered context, registered when in `esp_isp_af_env_detector_register_event_callbacks()` * diff --git a/components/esp_driver_isp/include/driver/isp_types.h b/components/esp_driver_isp/include/driver/isp_types.h index a8baa1926e2..ea171bb0927 100644 --- a/components/esp_driver_isp/include/driver/isp_types.h +++ b/components/esp_driver_isp/include/driver/isp_types.h @@ -30,6 +30,14 @@ typedef struct { float max; ///< Maximum float value } isp_float_range_t; +/** + * @brief ISP AF result + */ +typedef struct { + int definition[ISP_AF_WINDOW_NUM]; ///< Definition, it refers how clear and sharp an image is + int luminance[ISP_AF_WINDOW_NUM]; ///< Luminance, it refers how luminant an image is +} isp_af_result_t; + /** * @brief ISP AWB result */ diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index b1a4523d307..9d4543f3c49 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -12,7 +12,7 @@ #include "esp_check.h" #include "esp_heap_caps.h" #include "driver/isp_awb.h" -#include "isp_internal.h" +#include "esp_private/isp_private.h" typedef struct isp_awb_controller_t { isp_fsm_t fsm; @@ -142,40 +142,43 @@ esp_err_t esp_isp_awb_controller_enable(isp_awb_ctlr_t awb_ctlr) { ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "controller isn't in init state"); + awb_ctlr->fsm = ISP_FSM_ENABLE; - esp_intr_enable(awb_ctlr->intr_handle); + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_ERROR(esp_intr_enable(awb_ctlr->intr_handle), err, TAG, "failed to enable the AWB interrupt"); isp_ll_awb_clk_enable(awb_ctlr->isp_proc->hal.hw, true); isp_ll_enable_intr(awb_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AWB_MASK, true); xSemaphoreGive(awb_ctlr->stat_lock); - awb_ctlr->fsm = ISP_FSM_ENABLE; - return ESP_OK; + return ret; +err: + awb_ctlr->fsm = ISP_FSM_INIT; + return ret; } esp_err_t esp_isp_awb_controller_disable(isp_awb_ctlr_t awb_ctlr) { ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + xSemaphoreTake(awb_ctlr->stat_lock, 0); + awb_ctlr->fsm = ISP_FSM_INIT; isp_ll_enable_intr(awb_ctlr->isp_proc->hal.hw, ISP_LL_EVENT_AWB_MASK, false); isp_ll_awb_clk_enable(awb_ctlr->isp_proc->hal.hw, false); esp_intr_disable(awb_ctlr->intr_handle); - awb_ctlr->fsm = ISP_FSM_INIT; - xSemaphoreTake(awb_ctlr->stat_lock, 0); return ESP_OK; } esp_err_t esp_isp_awb_controller_get_oneshot_statistics(isp_awb_ctlr_t awb_ctlr, int timeout_ms, isp_awb_stat_result_t *out_res) { - ESP_RETURN_ON_FALSE_ISR(awb_ctlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); + ESP_RETURN_ON_FALSE(awb_ctlr && (out_res || timeout_ms == 0), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + esp_err_t ret = ESP_OK; TickType_t ticks = timeout_ms < 0 ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); - xSemaphoreTake(awb_ctlr->stat_lock, ticks); + ESP_GOTO_ON_FALSE(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, err, TAG, "controller isn't in enable state"); // Update state to avoid race condition awb_ctlr->fsm = ISP_FSM_START; - esp_err_t ret = ESP_OK; // Reset the queue in case receiving the legacy data in the queue xQueueReset(awb_ctlr->evt_que); // Start the AWB white patch statistics and waiting it done @@ -187,30 +190,34 @@ esp_err_t esp_isp_awb_controller_get_oneshot_statistics(isp_awb_ctlr_t awb_ctlr, // Stop the AWB white patch statistics isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, false); awb_ctlr->fsm = ISP_FSM_ENABLE; +err: xSemaphoreGive(awb_ctlr->stat_lock); - return ret; } esp_err_t esp_isp_awb_controller_start_continuous_statistics(isp_awb_ctlr_t awb_ctlr) { - ESP_RETURN_ON_FALSE_ISR(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "controller isn't in enable state"); - + ESP_RETURN_ON_FALSE(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(awb_ctlr->cbs.on_statistics_done, ESP_ERR_INVALID_STATE, TAG, "invalid state: on_statistics_done callback not registered"); + esp_err_t ret = ESP_OK; if (xSemaphoreTake(awb_ctlr->stat_lock, 0) == pdFALSE) { ESP_LOGW(TAG, "statistics lock is not acquired, controller is busy"); return ESP_ERR_INVALID_STATE; } + ESP_GOTO_ON_FALSE(awb_ctlr->fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, err, TAG, "controller isn't in enable state"); awb_ctlr->fsm = ISP_FSM_START; isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, true); - return ESP_OK; + return ret; +err: + xSemaphoreGive(awb_ctlr->stat_lock); + return ret; } esp_err_t esp_isp_awb_controller_stop_continuous_statistics(isp_awb_ctlr_t awb_ctlr) { - ESP_RETURN_ON_FALSE_ISR(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); - ESP_RETURN_ON_FALSE_ISR(awb_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); + ESP_RETURN_ON_FALSE(awb_ctlr, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(awb_ctlr->fsm == ISP_FSM_START, ESP_ERR_INVALID_STATE, TAG, "controller isn't in continuous state"); isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, false); awb_ctlr->fsm = ISP_FSM_ENABLE; @@ -236,7 +243,7 @@ static void IRAM_ATTR s_isp_awb_default_isr(void *arg) // Get the statistics result esp_isp_awb_evt_data_t edata = { .awb_result = { - .white_patch_num = isp_ll_awb_get_white_patcherence_cnt(proc->hal.hw), + .white_patch_num = isp_ll_awb_get_white_patch_cnt(proc->hal.hw), .sum_r = isp_ll_awb_get_accumulated_r_value(proc->hal.hw), .sum_g = isp_ll_awb_get_accumulated_g_value(proc->hal.hw), .sum_b = isp_ll_awb_get_accumulated_b_value(proc->hal.hw), diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index 33b6c84cb90..3ed34672425 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -57,6 +57,15 @@ TEST_CASE("ISP AF controller exhausted allocation", "[isp]") TEST_ESP_OK(esp_isp_del_processor(isp_proc)); } +static bool test_isp_awb_default_on_statistics_done_cb(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_evt_data_t *edata, void *user_data) +{ + (void) awb_ctlr; + (void) edata; + (void) user_data; + // Do nothing + return false; +} + TEST_CASE("ISP AWB driver basic function", "[isp]") { esp_isp_processor_cfg_t isp_config = { @@ -88,6 +97,11 @@ TEST_CASE("ISP AWB driver basic function", "[isp]") isp_awb_stat_result_t stat_res = {}; /* Create the awb controller */ TEST_ESP_OK(esp_isp_new_awb_controller(isp_proc, &awb_config, &awb_ctlr)); + /* Register AWB callback */ + esp_isp_awb_cbs_t awb_cb = { + .on_statistics_done = test_isp_awb_default_on_statistics_done_cb, + }; + TEST_ESP_OK(esp_isp_awb_register_event_callbacks(awb_ctlr, &awb_cb, NULL)); /* Enabled the awb controller */ TEST_ESP_OK(esp_isp_awb_controller_enable(awb_ctlr)); /* Start continuous AWB statistics */ diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index 1636882ba91..fbac2e908c4 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -1123,7 +1123,7 @@ static inline void isp_ll_awb_set_bg_ratio_range(isp_dev_t *hw, isp_ll_awb_rgb_r * - white patch count */ __attribute__((always_inline)) -static inline uint32_t isp_ll_awb_get_white_patcherence_cnt(isp_dev_t *hw) +static inline uint32_t isp_ll_awb_get_white_patch_cnt(isp_dev_t *hw) { return hw->awb0_white_cnt.awb0_white_cnt; } diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index 335c8b92dc2..fd291e7ec51 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -88,21 +88,6 @@ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t m */ void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config); -/*--------------------------------------------------------------- - Color Correction Matrix ----------------------------------------------------------------*/ -/** - * @brief Set Color Correction Matrix - * - * @param[in] hal Context of the HAL layer - * @param[in] saturation Whether to enable saturation when float data overflow - * @param[in] flt_matrix 3x3 RGB correction matrix - * @return - * - true Set success - * - false Invalid are - */ -bool isp_hal_ccm_set_matrix(const isp_hal_context_t *hal, bool saturation, const float flt_matrix[3][3]); - /*--------------------------------------------------------------- AWB ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index be08bd177bc..13808353d01 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -82,12 +82,14 @@ typedef enum { #endif /** - * @brief ISP AF result + * @brief ISP AF window */ typedef struct { - int definition[ISP_AF_WINDOW_NUM]; ///< Definition, it refers how clear and sharp an image is - int luminance[ISP_AF_WINDOW_NUM]; ///< Luminance, it refers how luminant an image is -} isp_af_result_t; + uint32_t top_left_x; ///< Top left x axis value + uint32_t top_left_y; ///< Top left y axis value + uint32_t bottom_right_x; ///< Bottom right x axis value + uint32_t bottom_right_y; ///< Bottom right y axis value +} isp_af_window_t; /*--------------------------------------------------------------- BF diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index 96de231e919..7d33af5c5d7 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -16,8 +16,6 @@ #include "hal/isp_types.h" #include "hal/hal_utils.h" -#include "esp_rom_sys.h" - /** * ISP HAL layer */ diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 41887198090..15220418a28 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -4,7 +4,7 @@ Image Signal Processor Introduction ------------ -{IDF_TARGET_NAME} includes an image signal processor (ISP), which is a feature pipeline that consists of many image processing algorithms. ISP receives image data from the DVP camera or MIPI-CSI camera, or system memory, and writes the processed image data to the system memory through DMA. ISP shall work with other modules to read and write data, it can not work alone. +{IDF_TARGET_NAME} includes an Image Signal Processor (ISP), which is a feature pipeline that consists of many image processing algorithms. ISP receives image data from the DVP camera or MIPI-CSI camera, or system memory, and writes the processed image data to the system memory through DMA. ISP shall work with other modules to read and write data, it can not work alone. Terminology ----------- @@ -16,6 +16,39 @@ Terminology - RGB: Colored image format composed of red, green, and blue colors classified into RGB888, RGB565, etc., based on the bit width of each color - YUV: Colored image format composed of luminance and chrominance classified into YUV444, YUV422, YUV420, etc., based on the data arrangement - AF: Auto-focus + - AWB: Auto-white balance + +ISP Pipeline +------------ + +.. blockdiag:: + :scale: 100% + :caption: ISP Pipeline + :align: center + + blockdiag isp_pipeline { + orientation = portrait; + node_height = 30; + node_width = 120; + span_width = 100; + default_fontsize = 16; + + isp_header [label = "ISP Header"]; + isp_tail [label = "ISP Tail"]; + isp_chs [label = "Contrast &\n Hue & Saturation", width = 150, height = 70]; + isp_yuv [label = "YUV Limit\nYUB2RGB", width = 120, height = 70]; + + isp_header -> BF -> Demosaic -> CCM -> RGB2YUV -> isp_chs -> isp_yuv -> isp_tail; + + BF -> HIST + Demosaic -> AWB + Demosaic -> AE + Demosaic -> HIST + CCM -> AWB + CCM -> AE + RGB2YUV -> HIST + RGB2YUV -> AF + } Functional Overview ------------------- @@ -24,8 +57,8 @@ The ISP driver offers following services: - `Resource Allocation <#isp-resource-allocation>`__ - covers how to allocate ISP resources with properly set of configurations. It also covers how to recycle the resources when they finished working. - `Enable and disable ISP processor <#isp-enable-disable>`__ - covers how to enable and disable an ISP processor. -- `Get AF oneshot result <#isp-af-get-oneshot-result>`__ - covers how to get AF oneshot result. -- `Start AF statistics continuously <#isp-af-start-conti-stat>`__ - covers how to start the continuous AF statistics. +- `Get AF statistics in one shot or continuous way <#isp-af-statistics>`__ - covers how to get AF statistics one-shot or continuously. +- `Get AWB statistics in one shot or continuous way <#isp-awb-statistics>`__ - covers how to get AWB white patches statistics one-shot or continuously. - `Register callback <#isp-callback>`__ - covers how to hook user specific code to ISP driver event callback function. - `Thread Safety <#isp-thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. - `Kconfig Options <#isp-kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver. @@ -36,8 +69,8 @@ The ISP driver offers following services: Resource Allocation ^^^^^^^^^^^^^^^^^^^ -Install Image Signal Processor (ISP) Driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Install ISP Driver +~~~~~~~~~~~~~~~~~~ ISP driver requires the configuration that specified by :cpp:type:`esp_isp_processor_cfg_t`. @@ -59,8 +92,8 @@ If the configurations in :cpp:type:`esp_isp_processor_cfg_t` is specified, users You can use the created handle to do driver enable / disable the ISP driver and do other ISP module installation. -Install Image Signal Processor (ISP) Auto-Focus (AF) Driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Install ISP Auto-Focus (AF) Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ISP auto-focus (AF) driver requires the configuration that specified by :cpp:type:`esp_isp_af_config_t`. @@ -76,33 +109,66 @@ If the configurations in :cpp:type:`esp_isp_af_config_t` is specified, users can You can use the created handle to do driver enable / disable the ISP AF driver and ISP AF Env module installation. -Uninstall Image Signal Processor (ISP) Driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Install ISP Auto-White-Balance (AWB) Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ISP auto-white-balance (AWB) driver requires the configuration specified by :cpp:type:`esp_isp_awb_config_t`. + +If an :cpp:type:`esp_isp_awb_config_t` configuration is specified, you can call :cpp:func:`esp_isp_new_awb_controller` to allocate and initialize an ISP AWB processor. This function will return an ISP AWB processor handle on success. You can take following code as reference. + +.. code:: c + + isp_awb_ctlr_t awb_ctlr = NULL; + uint32_t image_width = 800; + uint32_t image_height = 600; + /* The AWB configuration, please refer to the API comment for how to tune these parameters */ + esp_isp_awb_config_t awb_config = { + .sample_point = ISP_AWB_SAMPLE_POINT_AFTER_CCM, + .window = { + .top_left = {.x = image_width * 0.2, .y = image_height * 0.2}, + .btm_right = {.x = image_width * 0.8, .y = image_height * 0.8}, + }, + .white_patch = { + .luminance = {.min = 0, .max = 220 * 3}, + .red_green_ratio = {.min = 0.0f, .max = 3.999f}, + .blue_green_ratio = {.min = 0.0f, .max = 3.999f}, + }, + }; + ESP_ERROR_CHECK(esp_isp_new_awb_controller(isp_proc, &awb_config, &awb_ctlr)); + +The AWB handle created in this step is required by other AWB APIs and AWB scheme. + +Uninstall ISP Driver +~~~~~~~~~~~~~~~~~~~~ If a previously installed ISP processor is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`esp_isp_del_processor`, so that to release the underlying hardware. -UnInstall Image Signal Processor (ISP) Auto-Focus (AF) Driver -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +UnInstall ISP AF Driver +~~~~~~~~~~~~~~~~~~~~~~~ If a previously installed ISP AF processor is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`esp_isp_del_af_controller`, so that to release the underlying hardware. +UnInstall ISP AWB Driver +~~~~~~~~~~~~~~~~~~~~~~~~ + +If a previously installed ISP AWB processor is no longer needed, it's recommended to free the resource by calling :cpp:func:`esp_isp_del_awb_controller`, it will also release the underlying hardware. -.. _isp-enable-disable: -Enable and Disable Image Signal Processor (ISP) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. _isp-enable-disable: -Image Signal Processor (ISP) ----------------------------- +Enable and Disable ISP +^^^^^^^^^^^^^^^^^^^^^^ +ISP +--------- Before doing ISP pipeline, you need to enable the ISP processor first, by calling :cpp:func:`esp_isp_enable`. This function: * Switches the driver state from **init** to **enable**. Calling :cpp:func:`esp_isp_disable` does the opposite, that is, put the driver back to the **init** state. -Image Signal Processor (ISP) Auto-Focus (AF) Processor ------------------------------------------------------- +ISP AF Processor +---------------- Before doing ISP AF, you need to enable the ISP AF processor first, by calling :cpp:func:`esp_isp_af_controller_enable`. This function: @@ -110,13 +176,17 @@ Before doing ISP AF, you need to enable the ISP AF processor first, by calling : Calling :cpp:func:`esp_isp_af_controller_disable` does the opposite, that is, put the driver back to the **init** state. -.. _isp-af-get-oneshot-result: +.. _isp-af-statistics: -Get Auto-Focus (AF) Oneshot Result -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +AF One-shot and Continuous Statistics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Calling :cpp:func:`esp_isp_af_controller_get_oneshot_statistics` to get oneshot AF statistics result. You can take following code as reference. +Aside from the above oneshot API, the ISP AF driver also provides a way to start AF statistics continuously. Calling :cpp:func:`esp_isp_af_controller_start_continuous_statistics` to start the continuous statistics and :cpp:func:`esp_isp_af_controller_stop_continuous_statistics` to stop it. + +Note that if you want to use the continuous statistics, you need to register the :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_statistics_done` or :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_change` callback to get the statistics result. See how to register in `Register Event Callbacks <#isp-callback>`__ + .. code:: c esp_isp_af_config_t af_config = { @@ -129,26 +199,6 @@ Calling :cpp:func:`esp_isp_af_controller_get_oneshot_statistics` to get oneshot /* Trigger the AF statistics and get its result for one time with timeout value 2000ms. */ ESP_ERROR_CHECK(esp_isp_af_controller_get_oneshot_statistics(af_ctrlr, 2000, &result)); -.. _isp-af-start-conti-stat: - -Start Auto-Focus (AF) Statistics Continuously -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Aside from the above oneshot API, the ISP AF driver also provides a way to start AF statistics continuously. Calling :cpp:func:`esp_isp_af_controller_start_continuous_statistics` to start the continuous statistics and :cpp:func:`esp_isp_af_controller_stop_continuous_statistics` to stop it. - -Note that if you want to use the continuous statistics, you need to register the :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_statistics_done` or :cpp:member:`esp_isp_af_env_detector_evt_cbs_t::on_env_change` callback to get the statistics result. See how to register in `Register Event Callbacks <#isp-callback>`__ - -.. code:: c - - isp_af_ctlr_t af_ctrlr = NULL; - esp_isp_af_config_t af_config = { - .edge_thresh = 128, - }; - isp_af_result_t stat_res = {}; - /* Create the af controller */ - ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); - /* Enabled the af controller */ - ESP_ERROR_CHECK(esp_isp_af_controller_enable(af_ctrlr)); /* Start continuous AF statistics */ ESP_ERROR_CHECK(esp_isp_af_controller_start_continuous_statistics(af_ctrlr)); // You can do other stuffs here, the statistics result can be obtained in the callback @@ -156,13 +206,14 @@ Note that if you want to use the continuous statistics, you need to register the // vTaskDelay(pdMS_TO_TICKS(1000)); /* Stop continuous AF statistics */ ESP_ERROR_CHECK(esp_isp_af_controller_stop_continuous_statistics(af_ctrlr)); + /* Disable the af controller */ ESP_ERROR_CHECK(esp_isp_af_controller_disable(af_ctrlr)); /* Delete the af controller and free the resources */ ESP_ERROR_CHECK(esp_isp_del_af_controller(af_ctrlr)); -Set Auto-Focus (AF) Environment Detector -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Set AF Environment Detector +^^^^^^^^^^^^^^^^^^^^^^^^^^^ Calling :cpp:func:`esp_isp_af_controller_set_env_detector` to set an ISP AF environment detector. You can take following code as reference. @@ -175,8 +226,8 @@ Calling :cpp:func:`esp_isp_af_controller_set_env_detector` to set an ISP AF envi ESP_ERROR_CHECK(esp_isp_new_af_controller(isp_proc, &af_config, &af_ctrlr)); ESP_ERROR_CHECK(esp_isp_af_controller_set_env_detector(af_ctrlr, &env_config)); -Set Auto-Focus (AF) Environment Detector Threshold -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Set AF Environment Detector Threshold +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Calling :cpp:func:`esp_isp_af_env_detector_set_threshold` to set the threshold of an ISP AF environment detector. @@ -186,13 +237,80 @@ Calling :cpp:func:`esp_isp_af_env_detector_set_threshold` to set the threshold o int luminance_thresh = 0; ESP_ERROR_CHECK(esp_isp_af_env_detector_set_threshold(env_detector, definition_thresh, luminance_thresh)); +ISP AWB Processor +----------------- + +Before doing ISP AWB, you need to enable the ISP AWB processor first, by calling :cpp:func:`esp_isp_awb_controller_enable`. This function: + +* Switches the driver state from **init** to **enable**. + +Calling :cpp:func:`esp_isp_awb_controller_disable` does the opposite, that is, put the driver back to the **init** state. + +.. _isp-awb-statistics: + +AWB One-shot and Continuous Statistics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Calling :cpp:func:`esp_isp_awb_controller_get_oneshot_result` to get oneshot AWB statistics result of white patches. You can take following code as reference. + +Aside from the above oneshot API, the ISP AWB driver also provides a way to start AWB statistics continuously. Calling :cpp:func:`esp_isp_awb_controller_start_continuous_statistics` starts the continuous statistics and :cpp:func:`esp_isp_awb_controller_stop_continuous_statistics` stops it. + +Note that if you want to use the continuous statistics, you need to register the :cpp:member:`esp_isp_awb_cbs_t::on_statistics_done` callback to get the statistics result. See how to register it in `Register Event Callbacks <#isp-callback>`__ + +.. code:: c + + bool example_isp_awb_on_statistics_done_cb(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_evt_data_t *edata, void *user_data); + // ... + isp_awb_ctlr_t awb_ctlr = NULL; + uint32_t image_width = 800; + uint32_t image_height = 600; + /* The AWB configuration, please refer to the API comment for how to tune these parameters */ + esp_isp_awb_config_t awb_config = { + .sample_point = ISP_AWB_SAMPLE_POINT_AFTER_CCM, + .window = { + .top_left = {.x = image_width * 0.2, .y = image_height * 0.2}, + .btm_right = {.x = image_width * 0.8, .y = image_height * 0.8}, + }, + .white_patch = { + .luminance = {.min = 0, .max = 220 * 3}, + .red_green_ratio = {.min = 0.0f, .max = 3.999f}, + .blue_green_ratio = {.min = 0.0f, .max = 3.999f}, + }, + }; + isp_awb_stat_result_t stat_res = {}; + /* Create the awb controller */ + ESP_ERROR_CHECK(esp_isp_new_awb_controller(isp_proc, &awb_config, &awb_ctlr)); + /* Register AWB callback */ + esp_isp_awb_cbs_t awb_cb = { + .on_statistics_done = example_isp_awb_on_statistics_done_cb, + }; + ESP_ERROR_CHECK(esp_isp_awb_register_event_callbacks(awb_ctlr, &awb_cb, NULL)); + /* Enabled the awb controller */ + ESP_ERROR_CHECK(esp_isp_awb_controller_enable(awb_ctlr)); + + /* Get oneshot AWB statistics result */ + ESP_ERROR_CHECK(esp_isp_awb_controller_get_oneshot_statistics(awb_ctlr, -1, &stat_res)); + + /* Start continuous AWB statistics, note that continuous statistics requires `on_statistics_done` callback */ + ESP_ERROR_CHECK(esp_isp_awb_controller_start_continuous_statistics(awb_ctlr)); + // You can do other stuffs here, the statistics result can be obtained in the callback + // ...... + // vTaskDelay(pdMS_TO_TICKS(1000)); + /* Stop continuous AWB statistics */ + ESP_ERROR_CHECK(esp_isp_awb_controller_stop_continuous_statistics(awb_ctlr)); + + /* Disable the awb controller */ + ESP_ERROR_CHECK(esp_isp_awb_controller_disable(awb_ctlr)); + /* Delete the awb controller and free the resources */ + ESP_ERROR_CHECK(esp_isp_del_awb_controller(awb_ctlr)); + .. _isp-callback: Register Event Callbacks ^^^^^^^^^^^^^^^^^^^^^^^^ -Register Image Signal Processor (ISP) Auto-Focus (AF) Environment Detector Event Callbacks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Register ISP AF Environment Detector Event Callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After the ISP AF environment detector starts up, it can generate a specific event dynamically. If you have some functions that should be called when the event happens, please hook your function to the interrupt service routine by calling :cpp:func:`esp_isp_af_env_detector_register_event_callbacks`. All supported event callbacks are listed in :cpp:type:`esp_isp_af_env_detector_evt_cbs_t`: @@ -201,6 +319,15 @@ After the ISP AF environment detector starts up, it can generate a specific even You can save your own context to :cpp:func:`esp_isp_af_env_detector_register_event_callbacks` as well, via the parameter ``user_data``. The user data will be directly passed to the callback function. +Register ISP AWB Statistics Done Event Callbacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After the ISP AWB controller finished statistics of white patches, it can generate a specific event dynamically. If you want to be informed when the statistics done event takes place, please hook your function to the interrupt service routine by calling :cpp:func:`esp_isp_awb_register_event_callbacks`. All supported event callbacks are listed in :cpp:type:`esp_isp_awb_cbs_t`: + +- :cpp:member:`esp_isp_awb_cbs_t::on_statistics_done` sets a callback function when finished statistics of the white patches. As this function is called within the ISR context, you must ensure that the function does not attempt to block (e.g., by making sure that only FreeRTOS APIs with ``ISR`` suffix are called from within the function). The function prototype is declared in :cpp:type:`esp_isp_awb_callback_t`. + +You can save your own context via the parameter ``user_data`` of :cpp:func:`esp_isp_awb_register_event_callbacks`. The user data will be directly passed to the callback function. + .. _isp-thread-safety: Thread Safety From b0fcdccd5b448997d20f3d9809369fa79bc3d9e2 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 13 Jun 2024 12:36:22 +0800 Subject: [PATCH 287/548] fix(isp_awb): fixed continuous mode only triggered once --- components/esp_driver_isp/src/isp_awb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index 9d4543f3c49..3fd89266d97 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -259,6 +259,7 @@ static void IRAM_ATTR s_isp_awb_default_isr(void *arg) need_yield |= high_task_awake == pdTRUE; /* If started continuous sampling, then trigger the next AWB sample */ if (awb_ctlr->fsm == ISP_FSM_START) { + isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, false); isp_ll_awb_enable(awb_ctlr->isp_proc->hal.hw, true); } } From 4189c54abb11290ebb441ee6dc874187e80ad367 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 14 Jun 2024 18:26:37 +0800 Subject: [PATCH 288/548] feat(isp_awb): support to change config after initialized --- .../esp_driver_isp/include/driver/isp_af.h | 2 +- .../esp_driver_isp/include/driver/isp_awb.h | 17 ++++++- components/esp_driver_isp/src/isp_awb.c | 48 ++++++++++++------- components/hal/include/hal/isp_types.h | 10 ---- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/components/esp_driver_isp/include/driver/isp_af.h b/components/esp_driver_isp/include/driver/isp_af.h index 8a69698d24e..67bfa58b52e 100644 --- a/components/esp_driver_isp/include/driver/isp_af.h +++ b/components/esp_driver_isp/include/driver/isp_af.h @@ -178,7 +178,7 @@ typedef struct { /** * @brief Prototype of ISP AF Env detector event callback * - * @param[in] af_ctrlr ISP AF controller handle + * @param[in] af_ctrlr ISP AF controller handle * @param[in] edata ISP AF Env detector event data * @param[in] user_data User registered context, registered when in `esp_isp_af_env_detector_register_event_callbacks()` * diff --git a/components/esp_driver_isp/include/driver/isp_awb.h b/components/esp_driver_isp/include/driver/isp_awb.h index 64dab9e7872..2846e9778bb 100644 --- a/components/esp_driver_isp/include/driver/isp_awb.h +++ b/components/esp_driver_isp/include/driver/isp_awb.h @@ -49,8 +49,8 @@ typedef struct { * so that all the distorted pixels will be counted for the reference of white balance. */ } white_patch; /*!< white patch configuration */ - int intr_priority; /*!< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with - * a relative low priority (1,2,3) otherwise the larger the higher, 7 is NMI. + int intr_priority; /*!< The interrupt priority, range 0~3, if set to 0, the driver will try to allocate an interrupt with + * a relative low priority (1,2,3) */ } esp_isp_awb_config_t; @@ -82,6 +82,19 @@ esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_a */ esp_err_t esp_isp_del_awb_controller(isp_awb_ctlr_t awb_ctlr); +/** + * @brief Reconfigure the ISP AWB controller + * @note This function is allowed to be called no matter the awb controller is enabled or not. + * + * @param[in] awb_ctlr AWB controller handle + * @param[in] awb_cfg Pointer to AWB config. Refer to ``esp_isp_awb_config_t`` + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid + */ +esp_err_t esp_isp_awb_controller_reconfig(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_config_t *awb_cfg); + /** * @brief Enable an ISP AWB controller * diff --git a/components/esp_driver_isp/src/isp_awb.c b/components/esp_driver_isp/src/isp_awb.c index 3fd89266d97..435515a9a4b 100644 --- a/components/esp_driver_isp/src/isp_awb.c +++ b/components/esp_driver_isp/src/isp_awb.c @@ -18,6 +18,7 @@ typedef struct isp_awb_controller_t { isp_fsm_t fsm; portMUX_TYPE spinlock; intr_handle_t intr_handle; + int intr_priority; isp_proc_handle_t isp_proc; QueueHandle_t evt_que; SemaphoreHandle_t stat_lock; @@ -72,6 +73,25 @@ static void s_isp_awb_free_controller(isp_awb_ctlr_t awb_ctlr) } } +static esp_err_t s_esp_isp_awb_config_hardware(isp_proc_handle_t isp_proc, const esp_isp_awb_config_t *awb_cfg) +{ + isp_ll_awb_set_sample_point(isp_proc->hal.hw, awb_cfg->sample_point); + ESP_RETURN_ON_FALSE(isp_hal_awb_set_window_range(&isp_proc->hal, &awb_cfg->window), + ESP_ERR_INVALID_ARG, TAG, "invalid window"); + isp_u32_range_t lum_range = awb_cfg->white_patch.luminance; + ESP_RETURN_ON_FALSE(isp_hal_awb_set_luminance_range(&isp_proc->hal, lum_range.min, lum_range.max), + ESP_ERR_INVALID_ARG, TAG, "invalid luminance range"); + isp_float_range_t rg_range = awb_cfg->white_patch.red_green_ratio; + ESP_RETURN_ON_FALSE(rg_range.min < rg_range.max && rg_range.min >= 0 && + isp_hal_awb_set_rg_ratio_range(&isp_proc->hal, rg_range.min, rg_range.max), + ESP_ERR_INVALID_ARG, TAG, "invalid range of Red Green ratio"); + isp_float_range_t bg_range = awb_cfg->white_patch.blue_green_ratio; + ESP_RETURN_ON_FALSE(bg_range.min < bg_range.max && bg_range.min >= 0 && + isp_hal_awb_set_bg_ratio_range(&isp_proc->hal, bg_range.min, bg_range.max), + ESP_ERR_INVALID_ARG, TAG, "invalid range of Blue to Green ratio"); + return ESP_OK; +} + esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_awb_config_t *awb_cfg, isp_awb_ctlr_t *ret_hdl) { esp_err_t ret = ESP_FAIL; @@ -91,27 +111,14 @@ esp_err_t esp_isp_new_awb_controller(isp_proc_handle_t isp_proc, const esp_isp_a ESP_GOTO_ON_ERROR(s_isp_claim_awb_controller(isp_proc, awb_ctlr), err1, TAG, "no available controller"); // Register the AWB ISR uint32_t intr_st_reg_addr = isp_ll_get_intr_status_reg_addr(isp_proc->hal.hw); - int intr_priority = awb_cfg->intr_priority > 0 && awb_cfg->intr_priority <= 7 ? BIT(awb_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; - ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(isp_hw_info.instances[isp_proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | intr_priority, intr_st_reg_addr, ISP_LL_EVENT_AWB_MASK, + awb_ctlr->intr_priority = awb_cfg->intr_priority > 0 && awb_cfg->intr_priority <= 3 ? BIT(awb_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; + ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(isp_hw_info.instances[isp_proc->proc_id].irq, ISP_INTR_ALLOC_FLAGS | awb_ctlr->intr_priority, intr_st_reg_addr, ISP_LL_EVENT_AWB_MASK, s_isp_awb_default_isr, awb_ctlr, &awb_ctlr->intr_handle), err2, TAG, "allocate interrupt failed"); // Configure the hardware isp_ll_awb_enable(isp_proc->hal.hw, false); - isp_ll_awb_set_sample_point(isp_proc->hal.hw, awb_cfg->sample_point); isp_ll_awb_enable_algorithm_mode(isp_proc->hal.hw, true); - ESP_GOTO_ON_FALSE(isp_hal_awb_set_window_range(&isp_proc->hal, &awb_cfg->window), - ESP_ERR_INVALID_ARG, err2, TAG, "invalid window"); - isp_u32_range_t lum_range = awb_cfg->white_patch.luminance; - ESP_GOTO_ON_FALSE(isp_hal_awb_set_luminance_range(&isp_proc->hal, lum_range.min, lum_range.max), - ESP_ERR_INVALID_ARG, err2, TAG, "invalid luminance range"); - isp_float_range_t rg_range = awb_cfg->white_patch.red_green_ratio; - ESP_GOTO_ON_FALSE(rg_range.min < rg_range.max && rg_range.min >= 0 && - isp_hal_awb_set_rg_ratio_range(&isp_proc->hal, rg_range.min, rg_range.max), - ESP_ERR_INVALID_ARG, err2, TAG, "invalid range of Red Green ratio"); - isp_float_range_t bg_range = awb_cfg->white_patch.blue_green_ratio; - ESP_GOTO_ON_FALSE(bg_range.min < bg_range.max && bg_range.min >= 0 && - isp_hal_awb_set_bg_ratio_range(&isp_proc->hal, bg_range.min, bg_range.max), - ESP_ERR_INVALID_ARG, err2, TAG, "invalid range of Blue to Green ratio"); + ESP_GOTO_ON_ERROR(s_esp_isp_awb_config_hardware(isp_proc, awb_cfg), err2, TAG, "configure awb hardware failed"); *ret_hdl = awb_ctlr; @@ -138,6 +145,15 @@ esp_err_t esp_isp_del_awb_controller(isp_awb_ctlr_t awb_ctlr) return ESP_OK; } +esp_err_t esp_isp_awb_controller_reconfig(isp_awb_ctlr_t awb_ctlr, const esp_isp_awb_config_t *awb_cfg) +{ + ESP_RETURN_ON_FALSE(awb_ctlr && awb_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + int intr_priority = awb_cfg->intr_priority > 0 && awb_cfg->intr_priority <= 3 ? BIT(awb_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; + ESP_RETURN_ON_FALSE(intr_priority == awb_ctlr->intr_priority, ESP_ERR_INVALID_ARG, TAG, "can't change interrupt priority after initialized"); + + return s_esp_isp_awb_config_hardware(awb_ctlr->isp_proc, awb_cfg); +} + esp_err_t esp_isp_awb_controller_enable(isp_awb_ctlr_t awb_ctlr) { ESP_RETURN_ON_FALSE(awb_ctlr && awb_ctlr->isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index 13808353d01..a664d8001a7 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -81,16 +81,6 @@ typedef enum { #define ISP_AF_WINDOW_NUM 0 #endif -/** - * @brief ISP AF window - */ -typedef struct { - uint32_t top_left_x; ///< Top left x axis value - uint32_t top_left_y; ///< Top left y axis value - uint32_t bottom_right_x; ///< Bottom right x axis value - uint32_t bottom_right_y; ///< Bottom right y axis value -} isp_af_window_t; - /*--------------------------------------------------------------- BF ---------------------------------------------------------------*/ From 8562e3be12848073a01c807848e6fa5d059cd458 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 24 Jun 2024 10:27:56 +0800 Subject: [PATCH 289/548] fix(ci): build rmt examples as long as it's driver support is finished --- examples/peripherals/.build-test-rules.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index cac8e376f5d..b6d05fd2151 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -313,12 +313,14 @@ examples/peripherals/rmt/ir_nec_transceiver: examples/peripherals/rmt/musical_buzzer: disable: + - if: SOC_RMT_SUPPORTED != 1 - if: SOC_RMT_SUPPORT_TX_LOOP_COUNT != 1 depends_components: - esp_driver_rmt examples/peripherals/rmt/stepper_motor: disable: + - if: SOC_RMT_SUPPORTED != 1 - if: SOC_RMT_SUPPORT_TX_LOOP_AUTO_STOP != 1 depends_components: - esp_driver_rmt From 8d8d8cbf182a2e8de760584c80bca19b832f438a Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 20 Jun 2024 18:09:59 +0800 Subject: [PATCH 290/548] fix(lcd): build errors with deprecated lcd types in cpp Closes https://github.com/espressif/esp-idf/issues/14029 --- .../esp_lcd/include/esp_lcd_panel_dev.h | 4 +- components/esp_lcd/include/esp_lcd_types.h | 24 ++++-------- .../system/cxx_build_test/main/CMakeLists.txt | 14 +++++-- .../cxx_build_test/main/test_i2c_lcd.cpp | 39 +++++++++++++++++++ 4 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp diff --git a/components/esp_lcd/include/esp_lcd_panel_dev.h b/components/esp_lcd/include/esp_lcd_panel_dev.h index 1a86d2b964b..f39bdf299fa 100644 --- a/components/esp_lcd/include/esp_lcd_panel_dev.h +++ b/components/esp_lcd/include/esp_lcd_panel_dev.h @@ -20,8 +20,8 @@ extern "C" { typedef struct { int reset_gpio_num; /*!< GPIO used to reset the LCD panel, set to -1 if it's not used */ union { - lcd_rgb_element_order_t color_space; /*!< @deprecated Set RGB color space, please use rgb_ele_order instead */ - lcd_rgb_element_order_t rgb_endian; /*!< @deprecated Set RGB data endian, please use rgb_ele_order instead */ + esp_lcd_color_space_t color_space; /*!< @deprecated Set RGB color space, please use rgb_ele_order instead */ + lcd_color_rgb_endian_t rgb_endian; /*!< @deprecated Set RGB data endian, please use rgb_ele_order instead */ lcd_rgb_element_order_t rgb_ele_order; /*!< Set RGB element order, RGB or BGR */ }; lcd_rgb_data_endian_t data_endian; /*!< Set the data endian for color data larger than 1 byte */ diff --git a/components/esp_lcd/include/esp_lcd_types.h b/components/esp_lcd/include/esp_lcd_types.h index f70858df0f6..ca15370b93d 100644 --- a/components/esp_lcd/include/esp_lcd_types.h +++ b/components/esp_lcd/include/esp_lcd_types.h @@ -41,25 +41,15 @@ typedef enum { } lcd_rgb_element_order_t; /** @cond */ -/** - * @brief LCD color space type definition (WRONG!) - * @deprecated RGB and BGR should belong to the same color space, but this enum take them both as two different color spaces. - * If you want to use a enum to describe a color space, please use lcd_color_space_t instead. - */ -typedef enum { - ESP_LCD_COLOR_SPACE_RGB, /*!< Color space: RGB */ - ESP_LCD_COLOR_SPACE_BGR, /*!< Color space: BGR */ - ESP_LCD_COLOR_SPACE_MONOCHROME, /*!< Color space: monochrome */ -} esp_lcd_color_space_t __attribute__((deprecated)); - -// Ensure binary compatibility with lcd_color_rgb_endian_t -ESP_STATIC_ASSERT((lcd_rgb_element_order_t)ESP_LCD_COLOR_SPACE_RGB == LCD_RGB_ELEMENT_ORDER_RGB, "ESP_LCD_COLOR_SPACE_RGB is not compatible with LCD_RGB_ORDER_RGB"); -ESP_STATIC_ASSERT((lcd_rgb_element_order_t)ESP_LCD_COLOR_SPACE_BGR == LCD_RGB_ELEMENT_ORDER_BGR, "ESP_LCD_COLOR_SPACE_BGR is not compatible with LCD_RGB_ORDER_BGR"); - /// for backward compatible typedef lcd_rgb_element_order_t lcd_color_rgb_endian_t; -#define LCD_RGB_ENDIAN_RGB LCD_RGB_ELEMENT_ORDER_RGB -#define LCD_RGB_ENDIAN_BGR LCD_RGB_ELEMENT_ORDER_BGR +#define LCD_RGB_ENDIAN_RGB (lcd_color_rgb_endian_t)LCD_RGB_ELEMENT_ORDER_RGB +#define LCD_RGB_ENDIAN_BGR (lcd_color_rgb_endian_t)LCD_RGB_ELEMENT_ORDER_BGR + +typedef lcd_rgb_element_order_t esp_lcd_color_space_t; +#define ESP_LCD_COLOR_SPACE_RGB (esp_lcd_color_space_t)LCD_RGB_ELEMENT_ORDER_RGB +#define ESP_LCD_COLOR_SPACE_BGR (esp_lcd_color_space_t)LCD_RGB_ELEMENT_ORDER_BGR +#define ESP_LCD_COLOR_SPACE_MONOCHROME (esp_lcd_color_space_t)2 /** @endcond */ /** diff --git a/tools/test_apps/system/cxx_build_test/main/CMakeLists.txt b/tools/test_apps/system/cxx_build_test/main/CMakeLists.txt index 695b17a1b3e..59cbf3f832a 100644 --- a/tools/test_apps/system/cxx_build_test/main/CMakeLists.txt +++ b/tools/test_apps/system/cxx_build_test/main/CMakeLists.txt @@ -1,6 +1,12 @@ -idf_component_register(SRCS cxx_build_test_main.cpp - test_soc_reg_macros.cpp - test_cxx_standard.cpp +set(srcs cxx_build_test_main.cpp + test_soc_reg_macros.cpp + test_cxx_standard.cpp) + +if(CONFIG_SOC_I2C_SUPPORTED) + list(APPEND srcs test_i2c_lcd.cpp) +endif() + +idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "." - PRIV_REQUIRES driver + PRIV_REQUIRES driver esp_lcd REQUIRES soc) diff --git a/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp b/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp new file mode 100644 index 00000000000..1f0ee9263b5 --- /dev/null +++ b/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp @@ -0,0 +1,39 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "esp_lcd_panel_vendor.h" + +const esp_lcd_panel_dev_config_t panel_config0 = { + .reset_gpio_num = 0, + .color_space = ESP_LCD_COLOR_SPACE_MONOCHROME, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = 16, + .flags = { + .reset_active_high = false, + }, + .vendor_config = NULL, +}; + +const esp_lcd_panel_dev_config_t panel_config1 = { + .reset_gpio_num = 0, + .color_space = ESP_LCD_COLOR_SPACE_BGR, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = 16, + .flags = { + .reset_active_high = false, + }, + .vendor_config = NULL, +}; + +const esp_lcd_panel_dev_config_t panel_config2 = { + .reset_gpio_num = 0, + .rgb_endian = LCD_RGB_ENDIAN_BGR, + .data_endian = LCD_RGB_DATA_ENDIAN_LITTLE, + .bits_per_pixel = 16, + .flags = { + .reset_active_high = false, + }, + .vendor_config = NULL, +}; From fe2b23b93af35efa77f704548d02062eac5adba5 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 21 Jun 2024 11:04:15 +0800 Subject: [PATCH 291/548] fix(i2c_lcd): using function overloading to keep esp_lcd_new_panel_io_i2c becuase _Generic is not available in C++ Closes https://github.com/espressif/esp-idf/issues/14037 --- components/esp_lcd/include/esp_lcd_io_i2c.h | 41 +++++++++++++++++-- .../cxx_build_test/main/test_i2c_lcd.cpp | 39 ++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/components/esp_lcd/include/esp_lcd_io_i2c.h b/components/esp_lcd/include/esp_lcd_io_i2c.h index 73ee69e55e0..7d1b0fc02c9 100644 --- a/components/esp_lcd/include/esp_lcd_io_i2c.h +++ b/components/esp_lcd/include/esp_lcd_io_i2c.h @@ -67,6 +67,43 @@ esp_err_t esp_lcd_new_panel_io_i2c_v1(uint32_t bus, const esp_lcd_panel_io_i2c_c */ esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +/** + * @brief Create LCD panel IO handle + * + * @param[in] bus I2C bus ID, indicates which I2C port to use + * @param[in] io_config IO configuration, for I2C interface + * @param[out] ret_io Returned IO handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +static inline void esp_lcd_new_panel_io_i2c(uint32_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io) +{ + esp_lcd_new_panel_io_i2c_v1(bus, io_config, ret_io); +} + +/** + * @brief Create LCD panel IO handle + * + * @param[in] bus I2C bus handle, returned from `i2c_new_master_bus` + * @param[in] io_config IO configuration, for I2C interface + * @param[out] ret_io Returned IO handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +static inline void esp_lcd_new_panel_io_i2c(i2c_master_bus_handle_t bus, const esp_lcd_panel_io_i2c_config_t *io_config, esp_lcd_panel_io_handle_t *ret_io) +{ + esp_lcd_new_panel_io_i2c_v2(bus, io_config, ret_io); +} +#else /** * @brief Create LCD panel IO handle * @@ -80,8 +117,6 @@ esp_err_t esp_lcd_new_panel_io_i2c_v2(i2c_master_bus_handle_t bus, const esp_lcd */ #define esp_lcd_new_panel_io_i2c(bus, io_config, ret_io) _Generic((bus), \ i2c_master_bus_handle_t : esp_lcd_new_panel_io_i2c_v2, \ - default : esp_lcd_new_panel_io_i2c_v1) (bus, io_config, ret_io) \ + default : esp_lcd_new_panel_io_i2c_v1) (bus, io_config, ret_io) -#ifdef __cplusplus -} #endif diff --git a/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp b/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp index 1f0ee9263b5..cb058d62c06 100644 --- a/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp +++ b/tools/test_apps/system/cxx_build_test/main/test_i2c_lcd.cpp @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_io.h" +#include "driver/i2c_master.h" const esp_lcd_panel_dev_config_t panel_config0 = { .reset_gpio_num = 0, @@ -37,3 +39,40 @@ const esp_lcd_panel_dev_config_t panel_config2 = { }, .vendor_config = NULL, }; + +void test_i2c_lcd_apis(void) +{ + i2c_master_bus_config_t i2c_bus_conf = { + .i2c_port = -1, + .sda_io_num = GPIO_NUM_0, + .scl_io_num = GPIO_NUM_2, + .clk_source = I2C_CLK_SRC_DEFAULT, + .glitch_ignore_cnt = 0, + .intr_priority = 1, + .trans_queue_depth = 4, + .flags = { + .enable_internal_pullup = true, + } + }; + + i2c_master_bus_handle_t bus_handle; + i2c_new_master_bus(&i2c_bus_conf, &bus_handle); + + esp_lcd_panel_io_handle_t io_handle = NULL; + esp_lcd_panel_io_i2c_config_t io_config = { + .dev_addr = 0x3c, + .on_color_trans_done = NULL, + .user_ctx = NULL, + .control_phase_bytes = 1, + .dc_bit_offset = 6, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + .flags = { + .dc_low_on_data = false, + .disable_control_phase = false, + }, + .scl_speed_hz = 10 * 1000, + }; + + esp_lcd_new_panel_io_i2c(bus_handle, &io_config, &io_handle); +} From 79c48b470789748835714ab41c3ce5656272d50c Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Fri, 19 Apr 2024 13:38:22 +0800 Subject: [PATCH 292/548] feat(esp_pm): add DCDC always on config --- components/esp_hw_support/Kconfig | 2 ++ .../esp_hw_support/port/esp32p4/Kconfig.dcdc | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 components/esp_hw_support/port/esp32p4/Kconfig.dcdc diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index b6b44bac402..196d54e723d 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -325,6 +325,8 @@ menu "Hardware Settings" endmenu + orsource "./port/$IDF_TARGET/Kconfig.dcdc" + orsource "./port/$IDF_TARGET/Kconfig.ldo" # Invisible bringup bypass options for esp_hw_support component diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.dcdc b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc new file mode 100644 index 00000000000..071eb3d246a --- /dev/null +++ b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc @@ -0,0 +1,29 @@ +menu "DCDC Regulator Configurations" + depends on SOC_GP_LDO_SUPPORTED + + config ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + bool "Keep DC-DC power always on during light-sleep" + default y + help + ESP32P4 will switch the power supply to LDO before sleeping, and switch to DCDC after waking up. + These two processes take a long time and may bring some risks for some short duration + light sleep. (DCDC -> LDO: 2.5ms (max), LDO -> DCDC: 1.2 ms) + Enabling this option will make chip powered by DCDC during light sleep to reduce some power switch + risks, this will also increase the power consumption during the light sleep. + + DO NOT DISABLE UNLESS YOU KNOW WHAT YOU ARE DOING. + + config ESP_SLEEP_DCM_VSET_VAL_IN_SLEEP + int "DCDC voltage parameter during sleep" + default 14 + range 0 31 + depends on ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + help + This value determines the voltage of the DCDC chip during sleep. The same parameter value may + correspond to different voltage values on different models of DCDC chips. Please update this + value according to the model of external DCDC selected in your hardware solution. + + For the DCDC chip model recommended by ESP, the recommended configuration + valuesare listed below: + - TI-TLV62569/TLV62569P: 14 +endmenu From dd5a5f1cf21e8078cac9711f29cb6787b500620a Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 23 Apr 2024 21:11:37 +0800 Subject: [PATCH 293/548] feat(esp_hw_support): support DCDC always on --- .../include/esp_private/esp_pmu.h | 5 +- .../cpu_retention/port/esp32c5/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32c6/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32h2/sleep_cpu.c | 2 +- .../cpu_retention/port/esp32p4/sleep_cpu.c | 2 +- .../esp_hw_support/port/esp32c5/pmu_sleep.c | 5 +- .../esp_hw_support/port/esp32c6/pmu_sleep.c | 5 +- .../esp_hw_support/port/esp32h2/pmu_sleep.c | 5 +- .../esp_hw_support/port/esp32p4/Kconfig.dcdc | 5 +- .../esp_hw_support/port/esp32p4/pmu_init.c | 1 - .../esp_hw_support/port/esp32p4/pmu_sleep.c | 50 +++++++++++++------ .../port/esp32p4/private_include/pmu_param.h | 6 ++- components/esp_hw_support/sleep_modes.c | 26 +++++++--- 13 files changed, 77 insertions(+), 39 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index 5661db98743..d985b0823f2 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -270,7 +270,7 @@ void pmu_sleep_shutdown_dcdc(void); * @brief DCDC has taken over power supply, shut down LDO to save power consumption */ void pmu_sleep_shutdown_ldo(void); -#endif +#endif // SOC_DCDC_SUPPORTED /** * @brief Enter deep or light sleep mode @@ -302,9 +302,10 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp /** * @brief Finish sleep process settings and get sleep reject status + * @param dslp True if sleep requests id deep-sleep * @return return sleep reject status */ -bool pmu_sleep_finish(void); +bool pmu_sleep_finish(bool dslp); /** * @brief Initialize PMU related power/clock/digital parameters and functions diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c index 2ed461d2801..69d2abc5d3c 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c5/sleep_cpu.c @@ -435,7 +435,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c index 8d0b0a2bc76..66adf7de72f 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32c6/sleep_cpu.c @@ -475,7 +475,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c index c0202477100..c4ed6893094 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32h2/sleep_cpu.c @@ -475,7 +475,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index 68f469a66e8..fcc7e927673 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -429,7 +429,7 @@ static TCM_IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } esp_err_t TCM_IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index 6d8e27faf38..262ce0086e6 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -274,11 +274,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index 7396e41b8c2..b6c11b8632e 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -341,11 +341,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32h2/pmu_sleep.c b/components/esp_hw_support/port/esp32h2/pmu_sleep.c index a59e81f1ecc..ab32613ab59 100644 --- a/components/esp_hw_support/port/esp32h2/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h2/pmu_sleep.c @@ -258,11 +258,12 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp ; } - return ESP_OK; + return pmu_sleep_finish(dslp); } -bool pmu_sleep_finish(void) +bool pmu_sleep_finish(bool dslp) { + (void)dslp; return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.dcdc b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc index 071eb3d246a..a4d3ab3d37a 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.dcdc +++ b/components/esp_hw_support/port/esp32p4/Kconfig.dcdc @@ -24,6 +24,7 @@ menu "DCDC Regulator Configurations" value according to the model of external DCDC selected in your hardware solution. For the DCDC chip model recommended by ESP, the recommended configuration - valuesare listed below: - - TI-TLV62569/TLV62569P: 14 + values are listed below: + + - TI-TLV62569/TLV62569P: 14 endmenu diff --git a/components/esp_hw_support/port/esp32p4/pmu_init.c b/components/esp_hw_support/port/esp32p4/pmu_init.c index a0d3c53be26..92d67002fdf 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_init.c +++ b/components/esp_hw_support/port/esp32p4/pmu_init.c @@ -79,7 +79,6 @@ void pmu_hp_system_init(pmu_context_t *ctx, pmu_hp_mode_t mode, pmu_hp_system_pa pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); pmu_ll_hp_set_dcm_mode (ctx->hal->dev, mode, anlg->bias.dcm_mode); pmu_ll_hp_set_dcm_vset (ctx->hal->dev, mode, anlg->bias.dcm_vset); - pmu_ll_hp_set_bias_xpd (ctx->hal->dev, mode, anlg->bias.xpd_bias); pmu_ll_hp_set_dbg_atten (ctx->hal->dev, mode, anlg->bias.dbg_atten); pmu_ll_hp_set_current_power_off (ctx->hal->dev, mode, anlg->bias.pd_cur); pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, mode, anlg->bias.bias_sleep); diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 3b0487157cf..0b3d5cbaf28 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -149,26 +149,35 @@ const pmu_sleep_config_t* pmu_sleep_config_default( iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G1) ? BIT(1) : 0; iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G2) ? BIT(2) : 0; iram_pd_flags |= (pd_flags & PMU_SLEEP_PD_MEM_G3) ? BIT(3) : 0; - config->power = power_default; - - pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags); - config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period); if (dslp) { config->param.lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US, slowclk_period); pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags); config->analog = analog_default; } else { + // Get light sleep digital_default pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags); config->digital = digital_default; + // Get light sleep analog default pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(pd_flags); #if CONFIG_SPIRAM analog_default.hp_sys.analog.pd_cur = 1; analog_default.lp_sys[PMU_MODE_LP_SLEEP].analog.pd_cur = 1; #endif + +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + power_default.hp_sys.dig_power.dcdc_switch_pd_en = 0; + analog_default.hp_sys.analog.dcm_vset = CONFIG_ESP_SLEEP_DCM_VSET_VAL_IN_SLEEP; + analog_default.hp_sys.analog.dcm_mode = 1; +#endif config->analog = analog_default; } + + config->power = power_default; + pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(pd_flags); + config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, pd_flags, adjustment, slowclk_period, fastclk_period); + return config; } @@ -194,6 +203,8 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) { assert(ctx->hal); + pmu_ll_hp_set_dcm_mode (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dcm_mode); + pmu_ll_hp_set_dcm_vset (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.dcm_vset); pmu_ll_hp_set_current_power_off (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.pd_cur); pmu_ll_hp_set_bias_sleep_enable (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.bias_sleep); pmu_ll_hp_set_regulator_sleep_memory_xpd (ctx->hal->dev, HP(SLEEP), analog->hp_sys.analog.slp_mem_xpd); @@ -250,10 +261,10 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) } void pmu_sleep_increase_ldo_volt(void) { - REG_SET_FIELD(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_DBIAS, 30); - REG_SET_BIT(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_HP_ACTIVE_HP_REGULATOR_XPD); + pmu_ll_hp_set_regulator_dbias(&PMU, PMU_MODE_HP_ACTIVE, 30); + pmu_ll_hp_set_regulator_xpd(&PMU, PMU_MODE_HP_ACTIVE, 1); // Decrease the DCDC voltage to reduce the voltage difference between the DCDC and the LDO to avoid overshooting the DCDC voltage during wake-up. - REG_SET_FIELD(PMU_HP_ACTIVE_BIAS_REG, PMU_HP_ACTIVE_DCM_VSET, 24); + pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, 24); } void pmu_sleep_shutdown_dcdc(void) { @@ -301,19 +312,26 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, ; } - return pmu_sleep_finish(); + return pmu_sleep_finish(dslp); } -TCM_IRAM_ATTR bool pmu_sleep_finish(void) +TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) { - REG_SET_FIELD(PMU_HP_ACTIVE_BIAS_REG, PMU_HP_ACTIVE_DCM_VSET, 27); - if (pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { - // If sleep is rejected, the hardware wake-up process that turns on DCDC - // is skipped, and software is used to enable DCDC here. - pmu_sleep_enable_dcdc(); - esp_rom_delay_us(950); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!dslp) { + // Keep DCDC always on during light sleep, no need to adjust LDO. + } else +#endif + { + pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, 27); + if (pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { + // If sleep is rejected, the hardware wake-up process that turns on DCDC + // is skipped, and software is used to enable DCDC here. + pmu_sleep_enable_dcdc(); + esp_rom_delay_us(950); + } + pmu_sleep_shutdown_ldo(); } - pmu_sleep_shutdown_ldo(); unsigned chip_version = efuse_hal_chip_revision(); if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { diff --git a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h index b1c3aec1751..a3c48c04202 100644 --- a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h @@ -105,7 +105,7 @@ const pmu_lp_system_analog_param_t* pmu_lp_system_analog_param_default(pmu_lp_mo typedef union { struct { uint32_t reserved0 : 21; - uint32_t dcdc_switch_pd_en: 1; + uint32_t dcdc_switch_pd_en: 1; uint32_t mem_dslp : 1; uint32_t mem_pd_en : 1; uint32_t reserved1 : 6; @@ -153,7 +153,9 @@ typedef union { typedef struct { struct { - uint32_t reserved0 : 25; + uint32_t reserved0 : 18; + uint32_t dcm_vset : 5; + uint32_t dcm_mode : 2; uint32_t xpd_bias : 1; uint32_t dbg_atten : 4; uint32_t pd_cur : 1; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 481095366a5..12d12fbef3d 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -896,8 +896,15 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #if SOC_PMU_SUPPORTED #if SOC_DCDC_SUPPORTED - s_config.rtc_ticks_at_ldo_prepare = rtc_time_get(); - pmu_sleep_increase_ldo_volt(); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!deep_sleep) { + // Keep DCDC always on during light sleep, no need to adjust LDO voltage. + } else +#endif + { + s_config.rtc_ticks_at_ldo_prepare = rtc_time_get(); + pmu_sleep_increase_ldo_volt(); + } #endif pmu_sleep_config_t config; @@ -982,11 +989,18 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif #if SOC_DCDC_SUPPORTED - uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period); - if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) { - esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us); +#if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON + if (!deep_sleep) { + // Keep DCDC always on during light sleep, no need to adjust LDO voltage. + } else +#endif + { + uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period); + if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) { + esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us); + } + pmu_sleep_shutdown_dcdc(); } - pmu_sleep_shutdown_dcdc(); #endif #if SOC_PMU_SUPPORTED From 6eae7bc996bf5842c690b6fc6b1b7c627eee8b93 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 23 Apr 2024 17:28:34 +0800 Subject: [PATCH 294/548] change(esp_system): trigger digital system reset in brownout isr --- components/esp_system/port/brownout.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/esp_system/port/brownout.c b/components/esp_system/port/brownout.c index cce5f65deff..d90dcc911ad 100644 --- a/components/esp_system/port/brownout.c +++ b/components/esp_system/port/brownout.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,7 @@ #include "soc/soc.h" #include "soc/rtc_periph.h" #include "esp_attr.h" +#include "esp_rom_sys.h" #include "bootloader_flash.h" #include "esp_intr_alloc.h" #include "hal/brownout_hal.h" @@ -56,7 +57,10 @@ IRAM_ATTR static void rtc_brownout_isr_handler(void *arg) ESP_DRAM_LOGI(TAG, "Brownout detector was triggered\r\n\r\n"); } - esp_restart_noos(); + esp_rom_software_reset_system(); + while (true) { + ; + } } #endif // CONFIG_ESP_SYSTEM_BROWNOUT_INTR From 04429c9042b8a82cc545239193f79c9715886bae Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 29 Apr 2024 11:57:28 +0800 Subject: [PATCH 295/548] change(esp_hw_support): update xtal_freq after assume to avoid mass print in DFS --- components/esp_hw_support/port/esp32c6/rtc_clk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk.c b/components/esp_hw_support/port/esp32c6/rtc_clk.c index 3beac67c3c2..015a002562c 100644 --- a/components/esp_hw_support/port/esp32c6/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c6/rtc_clk.c @@ -362,6 +362,7 @@ soc_xtal_freq_t rtc_clk_xtal_freq_get(void) uint32_t xtal_freq_mhz = clk_ll_xtal_load_freq_mhz(); if (xtal_freq_mhz == 0) { ESP_HW_LOGW(TAG, "invalid RTC_XTAL_FREQ_REG value, assume 40MHz"); + clk_ll_xtal_store_freq_mhz(SOC_XTAL_FREQ_40M); return SOC_XTAL_FREQ_40M; } return (soc_xtal_freq_t)xtal_freq_mhz; From 33e6eaaabf60fa19bfff20c19675a9f36a117129 Mon Sep 17 00:00:00 2001 From: Shreyas Sheth Date: Thu, 6 Jun 2024 11:19:17 +0530 Subject: [PATCH 296/548] fix(wpa_supplicant): Fix wpa3 AP crash because of dangling pointer --- components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c index 360eee44e68..03650627802 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa3.c @@ -564,6 +564,7 @@ int wpa3_hostap_auth_init(void *data) &g_wpa3_hostap_task_hdl) != pdPASS) { wpa_printf(MSG_ERROR, "wpa3_hostap_auth_init: failed to create task"); os_queue_delete(g_wpa3_hostap_evt_queue); + g_wpa3_hostap_evt_queue = NULL; return ESP_FAIL; } From 69ab9d7a17724cb2358603dd10a2daa106950af3 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 14 Jun 2024 12:11:09 +0800 Subject: [PATCH 297/548] Revert "fix(rom): fixed esprv_int_set_threshold on C5" This reverts commit 171e0a21a14d6f9fb928787621ef4f49eafdb8b7. --- components/esp_rom/CMakeLists.txt | 2 +- .../esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in | 4 ---- components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h | 1 - .../esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld | 1 + components/esp_rom/patches/esp_rom_clic.c | 11 +---------- 5 files changed, 3 insertions(+), 16 deletions(-) diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index ff207fad6f3..859ebcd58a6 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -69,7 +69,7 @@ if(CONFIG_HAL_WDT_USE_ROM_IMPL) list(APPEND sources "patches/esp_rom_wdt.c") endif() -if(CONFIG_ESP_ROM_CLIC_INT_TYPE_PATCH OR CONFIG_ESP_ROM_CLIC_INT_THRESH_PATCH) +if(CONFIG_ESP_ROM_CLIC_INT_TYPE_PATCH) list(APPEND sources "patches/esp_rom_clic.c") endif() diff --git a/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in b/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in index d162a71b746..11efd8b841b 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32c5/mp/esp32c5/Kconfig.soc_caps.in @@ -82,7 +82,3 @@ config ESP_ROM_HAS_VERSION config ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB bool default y - -config ESP_ROM_CLIC_INT_THRESH_PATCH - bool - default y diff --git a/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h b/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h index e1286bac1a9..76b76bc17ba 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h +++ b/components/esp_rom/esp32c5/mp/esp32c5/esp_rom_caps.h @@ -28,4 +28,3 @@ #define ESP_ROM_RAM_APP_NEEDS_MMU_INIT (1) // ROM doesn't init cache MMU when it's a RAM APP, needs MMU hal to init #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB (1) // ROM supports the HP core to jump to the RTC memory to execute stub code after waking up from deepsleep. -#define ESP_ROM_CLIC_INT_THRESH_PATCH (1) // ROM version of esprv_intc_int_set_threshold incorrectly assumes lowest MINTTHRESH is 0x1F, should be 0xF diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld index 8724419cc62..3f5b833a297 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.ld @@ -276,6 +276,7 @@ gpio_pad_hold = 0x40000740; /* Functions */ esprv_intc_int_set_priority = 0x40000744; +esprv_intc_int_set_threshold = 0x40000748; esprv_intc_int_enable = 0x4000074c; esprv_intc_int_disable = 0x40000750; esprv_intc_int_set_type = 0x40000754; diff --git a/components/esp_rom/patches/esp_rom_clic.c b/components/esp_rom/patches/esp_rom_clic.c index 7160931c660..d4643e3ef5f 100644 --- a/components/esp_rom/patches/esp_rom_clic.c +++ b/components/esp_rom/patches/esp_rom_clic.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,7 +7,6 @@ #include "esp_rom_caps.h" #include "soc/clic_reg.h" #include "riscv/interrupt.h" -#include "riscv/rv_utils.h" #if ESP_ROM_CLIC_INT_TYPE_PATCH @@ -21,11 +20,3 @@ void esprv_int_set_type(int rv_int_num, enum intr_type type) REG_SET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_TRIG, type); } #endif - -#if ESP_ROM_CLIC_INT_THRESH_PATCH -void esprv_int_set_threshold(int priority_threshold) -{ - /* ROM functions assume minimum MINTTHRESH is 0x1F, but it is actually 0xF */ - rv_utils_set_intlevel(priority_threshold); -} -#endif //ESP_ROM_CLIC_INT_THRESH_PATCH From d6eedc04bf020359396d6fa7752334bde1f5cc77 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 14 Jun 2024 12:11:19 +0800 Subject: [PATCH 298/548] Revert "fix(intr): fixed intr threshhold min level on C5" This reverts commit a6c2c4149d9424ba9476f6cb63cc6097bcab2edc. --- components/soc/esp32c5/mp/include/soc/clic_reg.h | 2 +- components/soc/esp32c61/include/soc/clic_reg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/soc/esp32c5/mp/include/soc/clic_reg.h b/components/soc/esp32c5/mp/include/soc/clic_reg.h index 35b8003feee..324cfd8c8ab 100644 --- a/components/soc/esp32c5/mp/include/soc/clic_reg.h +++ b/components/soc/esp32c5/mp/include/soc/clic_reg.h @@ -10,7 +10,7 @@ extern "C" { #endif -#define NLBITS 4 +#define NLBITS 3 #define CLIC_EXT_INTR_NUM_OFFSET 16 #define DUALCORE_CLIC_CTRL_OFF 0x10000 diff --git a/components/soc/esp32c61/include/soc/clic_reg.h b/components/soc/esp32c61/include/soc/clic_reg.h index 219c1756472..5ce606a178b 100644 --- a/components/soc/esp32c61/include/soc/clic_reg.h +++ b/components/soc/esp32c61/include/soc/clic_reg.h @@ -10,7 +10,7 @@ extern "C" { #endif -#define NLBITS 4 +#define NLBITS 3 #define CLIC_EXT_INTR_NUM_OFFSET 16 #define DR_REG_CLIC_BASE (0x20800000) From 561146f52bb10facc1a3e389b4c14c0ce714e83d Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Tue, 21 May 2024 17:02:55 +0800 Subject: [PATCH 299/548] fix(lwip): fixed the dhcp pool error on dhcp server --- components/lwip/apps/dhcpserver/dhcpserver.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/components/lwip/apps/dhcpserver/dhcpserver.c b/components/lwip/apps/dhcpserver/dhcpserver.c index 112bdf070b4..b6516806434 100644 --- a/components/lwip/apps/dhcpserver/dhcpserver.c +++ b/components/lwip/apps/dhcpserver/dhcpserver.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1006,7 +1006,7 @@ static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len) dhcps->client_address.addr = dhcps->client_address_plus.addr; } - if (flag == false) { // search the fisrt unused ip + if (flag == false) { // search the first unused ip if (first_address.addr < pdhcps_pool->ip.addr) { flag = true; } else { @@ -1399,7 +1399,7 @@ static void kill_oldest_dhcps_pool(dhcps_t *dhcps) assert(pre != NULL && pre->pnext != NULL); // Expect the list to have at least 2 nodes p = pre->pnext; minpre = pre; - minp = p; + minp = pre; while (p != NULL) { pdhcps_pool = p->pnode; @@ -1413,8 +1413,11 @@ static void kill_oldest_dhcps_pool(dhcps_t *dhcps) pre = p; p = p->pnext; } - - minpre->pnext = minp->pnext; + if (minp == dhcps->plist) { + dhcps->plist = minp->pnext; + } else { + minpre->pnext = minp->pnext; + } free(minp->pnode); minp->pnode = NULL; free(minp); From 18470061ab8c240ef42c82294e733c28553dc278 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 21 Jun 2024 19:58:06 +0530 Subject: [PATCH 300/548] docs(secure_boot): Add secure boot signature verification time for esp32p4 --- docs/en/security/secure-boot-v2.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/security/secure-boot-v2.rst b/docs/en/security/secure-boot-v2.rst index 039c70c0b3e..f0a85e27226 100644 --- a/docs/en/security/secure-boot-v2.rst +++ b/docs/en/security/secure-boot-v2.rst @@ -11,11 +11,11 @@ Secure Boot V2 {IDF_TARGET_ECO_VERSION:default="", esp32="(ECO 3 onwards)", esp32c3="(ECO 3 onwards)"} -{IDF_TARGET_RSA_TIME:default="", esp32c6="~2.7 ms", esp32h2="~4.5 ms"} +{IDF_TARGET_RSA_TIME:default="", esp32c6="~2.7 ms", esp32h2="~4.5 ms", esp32p4="~2.4 ms"} -{IDF_TARGET_ECDSA_TIME:default="", esp32c6="~21.5 ms", esp32h2="~36 ms"} +{IDF_TARGET_ECDSA_TIME:default="", esp32c6="~21.5 ms", esp32h2="~36 ms", esp32p4="~10.3 ms"} -{IDF_TARGET_CPU_FREQ:default="", esp32c6="160 MHz", esp32h2="96 MHz"} +{IDF_TARGET_CPU_FREQ:default="", esp32c6="160 MHz", esp32h2="96 MHz", esp32p4="360 MHz"} {IDF_TARGET_SBV2_DEFAULT_SCHEME:default="RSA", esp32c2="ECDSA (V2)"} From 7e1bdbd683387e6770f85034143f92fb3740a5b3 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 21 Jun 2024 14:04:35 +0530 Subject: [PATCH 301/548] fix(tools/esp_prov): Fix incorrect input decoding when using console transport - Closes https://github.com/espressif/esp-idf/issues/14013 --- tools/esp_prov/transport/transport_console.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/esp_prov/transport/transport_console.py b/tools/esp_prov/transport/transport_console.py index 8fbcc2fe9c1..246a15e7aaa 100644 --- a/tools/esp_prov/transport/transport_console.py +++ b/tools/esp_prov/transport/transport_console.py @@ -1,8 +1,7 @@ -# SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 # - -from utils import hex_str_to_bytes, str_to_bytes +from utils import str_to_bytes from .transport import Transport @@ -16,4 +15,4 @@ async def send_data(self, path, data, session_id=0): except Exception as err: print('error:', err) return None - return hex_str_to_bytes(resp) + return bytearray.fromhex(resp).decode('latin-1') From 1ae89b72cb305faf4c678917f79ff617eda353e2 Mon Sep 17 00:00:00 2001 From: Li Shuai Date: Wed, 19 Jun 2024 17:09:20 +0800 Subject: [PATCH 302/548] fix(wifi): fix the issue of wifipwr losing its clock during sleep on the esp32c6 eco1 --- components/esp_hw_support/modem_clock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_hw_support/modem_clock.c b/components/esp_hw_support/modem_clock.c index e4b1a292192..b838cca6d19 100644 --- a/components/esp_hw_support/modem_clock.c +++ b/components/esp_hw_support/modem_clock.c @@ -390,9 +390,9 @@ void modem_clock_select_lp_clock_source(periph_module_t module, modem_clock_lpcl if (efuse_hal_chip_revision() != 0) { if (src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) { pmu_sleep_enable_hp_sleep_sysclk(true); + modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, true); + modem_clock_domain_clk_gate_disable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP); } - modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, true); - modem_clock_domain_clk_gate_disable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP); } #endif break; @@ -452,9 +452,9 @@ void modem_clock_deselect_lp_clock_source(periph_module_t module) if (efuse_hal_chip_revision() != 0) { if (last_src == MODEM_CLOCK_LPCLK_SRC_MAIN_XTAL) { pmu_sleep_enable_hp_sleep_sysclk(false); + modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, false); + modem_clock_domain_clk_gate_enable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP); } - modem_clock_hal_enable_wifipwr_clock(MODEM_CLOCK_instance()->hal, false); - modem_clock_domain_clk_gate_enable(MODEM_CLOCK_DOMAIN_WIFIPWR, PMU_HP_ICG_MODEM_CODE_SLEEP); } #endif break; From ae4013c1a62154ad557a2b59748ca14eb0481a2f Mon Sep 17 00:00:00 2001 From: gongyantao Date: Mon, 17 Jun 2024 11:06:29 +0800 Subject: [PATCH 303/548] fix(bt): add integrity check when temporary link key selected --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index a4d7731a95d..405cac4cba9 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit a4d7731a95db8a6cfb98e5068b6757c32ecfaa2a +Subproject commit 405cac4cba9c010ed2f378d7f202f62a3bee8f7a From 872319ac5e56138d8bad3040d888b126ce9f6477 Mon Sep 17 00:00:00 2001 From: chenjianxing Date: Wed, 5 Jun 2024 15:56:57 +0800 Subject: [PATCH 304/548] fix(phy): add phy calibration data check when mode is not none calibration --- components/esp_phy/lib | 2 +- components/esp_phy/src/phy_init.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/components/esp_phy/lib b/components/esp_phy/lib index 792ba5917ee..06e7625de19 160000 --- a/components/esp_phy/lib +++ b/components/esp_phy/lib @@ -1 +1 @@ -Subproject commit 792ba5917ee8191e7264143e69f9e6f8c1c0eacc +Subproject commit 06e7625de197bc12797dd701d6762229bca01826 diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index d56e8d6e34c..34316de5183 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -873,8 +873,7 @@ void esp_phy_load_cal_and_init(void) ESP_LOGW(TAG, "saving new calibration data because of checksum failure, mode(%d)", calibration_mode); } - if ((calibration_mode != PHY_RF_CAL_NONE && err != ESP_OK) || - (calibration_mode != PHY_RF_CAL_FULL && ret == ESP_CAL_DATA_CHECK_FAIL)) { + if ((calibration_mode != PHY_RF_CAL_NONE) && ((err != ESP_OK) || (ret == ESP_CAL_DATA_CHECK_FAIL))) { err = esp_phy_store_cal_data_to_nvs(cal_data); } else { err = ESP_OK; From 31056446421b3d6b1007cc371ac737ca0c310ecb Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Mon, 17 Jun 2024 12:00:33 +0800 Subject: [PATCH 305/548] feat(esp32p4): make revision v0.1 the default version --- components/esp_hw_support/port/esp32p4/Kconfig.hw_support | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support index 49b77c0ccf8..2471aaa6023 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.hw_support +++ b/components/esp_hw_support/port/esp32p4/Kconfig.hw_support @@ -1,6 +1,6 @@ choice ESP32P4_REV_MIN prompt "Minimum Supported ESP32-P4 Revision" - default ESP32P4_REV_MIN_0 + default ESP32P4_REV_MIN_1 help Required minimum chip revision. ESP-IDF will check for it and reject to boot if the chip revision fails the check. From 52a5fbf3f9216b80f902887b53da7d1b44e9b7de Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 21 Jun 2024 15:13:46 +0200 Subject: [PATCH 306/548] fix(ulp-risc-v): Fixed RTC I2C multi-byte read/write issue for ULP RISC-V This commit fixes an issue where multi-byte reads and writes over the RTC I2C peripheral got stuck on the esp32s2 and esp32s3. Closes https://github.com/espressif/esp-idf/issues/12235 --- components/ulp/ulp_riscv/ulp_riscv_i2c.c | 25 +++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/components/ulp/ulp_riscv/ulp_riscv_i2c.c b/components/ulp/ulp_riscv/ulp_riscv_i2c.c index a56be4c1bd2..3d73b22e376 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_i2c.c +++ b/components/ulp/ulp_riscv/ulp_riscv_i2c.c @@ -47,6 +47,9 @@ rtc_io_dev_t *rtc_io_dev = &RTCIO; /* Read/Write timeout (number of iterations)*/ #define ULP_RISCV_I2C_RW_TIMEOUT CONFIG_ULP_RISCV_I2C_RW_TIMEOUT +/* RTC I2C lock */ +static portMUX_TYPE rtc_i2c_lock = portMUX_INITIALIZER_UNLOCKED; + static esp_err_t i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_io_num) { /* Verify that the SDA and SCL GPIOs are valid RTC I2C io pins */ @@ -348,6 +351,8 @@ void ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size) SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE); SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); + portENTER_CRITICAL(&rtc_i2c_lock); + for (i = 0; i < size; i++) { /* Poll for RTC I2C Rx Data interrupt bit to be set */ ret = ulp_riscv_i2c_wait_for_interrupt(ULP_RISCV_I2C_RW_TIMEOUT); @@ -368,15 +373,17 @@ void ulp_riscv_i2c_master_read_from_device(uint8_t *data_rd, size_t size) /* Clear the Rx data interrupt bit */ SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_RX_DATA_INT_CLR); } else { - ESP_LOGE(RTCI2C_TAG, "Read Failed!"); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: Read Failed!"); uint32_t status = READ_PERI_REG(RTC_I2C_INT_RAW_REG); - ESP_LOGE(RTCI2C_TAG, "RTC I2C Interrupt Raw Reg 0x%"PRIx32"", status); - ESP_LOGE(RTCI2C_TAG, "RTC I2C Status Reg 0x%"PRIx32"", READ_PERI_REG(RTC_I2C_STATUS_REG)); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x%"PRIx32"", status); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: RTC I2C Status Reg 0x%"PRIx32"", READ_PERI_REG(RTC_I2C_STATUS_REG)); SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, status); break; } } + portEXIT_CRITICAL(&rtc_i2c_lock); + /* Clear the RTC I2C transmission bits */ CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE); CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); @@ -422,6 +429,8 @@ void ulp_riscv_i2c_master_write_to_device(uint8_t *data_wr, size_t size) /* Configure the RTC I2C controller in write mode */ SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 1, 27); + portENTER_CRITICAL(&rtc_i2c_lock); + for (i = 0; i < size; i++) { /* Write the data to be transmitted */ CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_MASTER_TX_DATA_MASK); @@ -440,15 +449,17 @@ void ulp_riscv_i2c_master_write_to_device(uint8_t *data_wr, size_t size) /* Clear the Tx data interrupt bit */ SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR); } else { - ESP_LOGE(RTCI2C_TAG, "Write Failed!"); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: Write Failed!"); uint32_t status = READ_PERI_REG(RTC_I2C_INT_RAW_REG); - ESP_LOGE(RTCI2C_TAG, "RTC I2C Interrupt Raw Reg 0x%"PRIx32"", status); - ESP_LOGE(RTCI2C_TAG, "RTC I2C Status Reg 0x%"PRIx32"", READ_PERI_REG(RTC_I2C_STATUS_REG)); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x%"PRIx32"", status); + ESP_EARLY_LOGE(RTCI2C_TAG, "ulp_riscv_i2c: RTC I2C Status Reg 0x%"PRIx32"", READ_PERI_REG(RTC_I2C_STATUS_REG)); SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, status); break; } } + portEXIT_CRITICAL(&rtc_i2c_lock); + /* Clear the RTC I2C transmission bits */ CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE); CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START); @@ -505,7 +516,7 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) i2c_dev->i2c_ctrl.i2c_i2c_ctrl_clk_gate_en = 1; #endif // CONFIG_IDF_TARGET_ESP32S2 - /* Configure RTC I2C timing paramters */ + /* Configure RTC I2C timing parameters */ ESP_RETURN_ON_ERROR(i2c_set_timing(cfg), RTCI2C_TAG, "Failed to configure RTC I2C timing"); /* Enable RTC I2C interrupts */ From 6c01ce3ae28cdc95b7790ce7c1a96a6468c89b8a Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 27 May 2024 17:21:14 +0800 Subject: [PATCH 307/548] fix(bt/bluedroid): Fixed L2CAP using wrong handle - Fixed the issue of using the wrong handle to handle the BTA_JV_L2CAP_READ_EVT event. - Closes https://github.com/espressif/esp-idf/issues/13847 --- components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c index 5cd777c5a3e..a32a56d5dd9 100644 --- a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c +++ b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c @@ -945,7 +945,7 @@ void btc_l2cap_cb_handler(btc_msg_t *msg) break; // to do disconnect } memset(p_data_buf, 0, count + sizeof(BT_HDR)); - p_data_buf->len = BTA_JvL2capRead(p_data->data_ind.handle, slot->id, p_data_buf->data, count); + p_data_buf->len = BTA_JvL2capRead(p_data->l2c_read.handle, slot->id, p_data_buf->data, count); if (p_data_buf->len > 0) { fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT); } else { From 4a919356ba9a66d1a83430cb8a4ec7449c57924d Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Mon, 27 May 2024 17:28:04 +0800 Subject: [PATCH 308/548] fix(bt/bluedroid): Fixed deadlock caused by not unlocking --- .../bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c index a32a56d5dd9..7c5157736a9 100644 --- a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c +++ b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c @@ -906,7 +906,6 @@ void btc_l2cap_cb_handler(btc_msg_t *msg) fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT); } else { osi_free(p_data_buf); - break; } } osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex); @@ -950,7 +949,6 @@ void btc_l2cap_cb_handler(btc_msg_t *msg) fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT); } else { osi_free(p_data_buf); - break; } } osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex); @@ -1060,7 +1058,7 @@ static ssize_t l2cap_vfs_write(int fd, const void * data, size_t size) if (!enqueue_status) { BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd); osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex); - //block untill under water level, be closed or time out + //block until under water level, be closed or time out tx_event_group_val = xEventGroupWaitBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE, pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS); From d054c4bcb6435c7897fdc5e206c095ca92492e11 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 18 Jun 2024 23:05:14 +0800 Subject: [PATCH 309/548] fix(huk): switch case fall through unexpected --- components/hal/esp32p4/include/hal/huk_ll.h | 44 +++++++++++-------- .../hal/esp32p4/include/hal/lp_i2s_ll.h | 6 +-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/components/hal/esp32p4/include/hal/huk_ll.h b/components/hal/esp32p4/include/hal/huk_ll.h index 6fa5b98f2aa..6b5a50a64fd 100644 --- a/components/hal/esp32p4/include/hal/huk_ll.h +++ b/components/hal/esp32p4/include/hal/huk_ll.h @@ -58,30 +58,36 @@ static inline void huk_ll_continue(void) /* @bried Enable or Disable the HUK interrupts */ static inline void huk_ll_configure_interrupt(const esp_huk_interrupt_type_t intr, const bool en) { - switch(intr) { - case ESP_HUK_INT_PREP_DONE: - REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PREP_DONE_INT_ENA, en); - case ESP_HUK_INT_PROC_DONE: - REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PROC_DONE_INT_ENA, en); - case ESP_HUK_INT_POST_DONE: - REG_SET_FIELD(HUK_INT_ENA_REG, HUK_POST_DONE_INT_ENA, en); - default: - return; + switch (intr) { + case ESP_HUK_INT_PREP_DONE: + REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PREP_DONE_INT_ENA, en); + break; + case ESP_HUK_INT_PROC_DONE: + REG_SET_FIELD(HUK_INT_ENA_REG, HUK_PROC_DONE_INT_ENA, en); + break; + case ESP_HUK_INT_POST_DONE: + REG_SET_FIELD(HUK_INT_ENA_REG, HUK_POST_DONE_INT_ENA, en); + break; + default: + return; } } /* @bried Clear the HUK interrupts */ static inline void huk_ll_clear_int(const esp_huk_interrupt_type_t intr) { - switch(intr) { - case ESP_HUK_INT_PREP_DONE: - REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PREP_DONE_INT_CLR, 1); - case ESP_HUK_INT_PROC_DONE: - REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PROC_DONE_INT_CLR, 1); - case ESP_HUK_INT_POST_DONE: - REG_SET_FIELD(HUK_INT_CLR_REG, HUK_POST_DONE_INT_CLR, 1); - default: - return; + switch (intr) { + case ESP_HUK_INT_PREP_DONE: + REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PREP_DONE_INT_CLR, 1); + break; + case ESP_HUK_INT_PROC_DONE: + REG_SET_FIELD(HUK_INT_CLR_REG, HUK_PROC_DONE_INT_CLR, 1); + break; + case ESP_HUK_INT_POST_DONE: + REG_SET_FIELD(HUK_INT_CLR_REG, HUK_POST_DONE_INT_CLR, 1); + break; + default: + return; } } @@ -108,7 +114,7 @@ static inline esp_huk_gen_status_t huk_ll_get_gen_status(void) */ static inline uint32_t huk_ll_get_date_info(void) { - // Only the least siginificant 28 bits have desired information + // Only the least significant 28 bits have desired information return (uint32_t)(0x0FFFFFFF & REG_READ(HUK_DATE_REG)); } diff --git a/components/hal/esp32p4/include/hal/lp_i2s_ll.h b/components/hal/esp32p4/include/hal/lp_i2s_ll.h index 17f3aba185f..c25e3c57dfd 100644 --- a/components/hal/esp32p4/include/hal/lp_i2s_ll.h +++ b/components/hal/esp32p4/include/hal/lp_i2s_ll.h @@ -23,7 +23,7 @@ extern "C" { #endif -#define I2S_LL_GET_HW(num) (((num) == 0)? (&LP_I2S) : NULL) +#define LP_I2S_LL_GET_HW(num) (((num) == 0)? (&LP_I2S) : NULL) #define LP_I2S_LL_EVENT_RX_DONE_INT (1<<0) #define LP_I2S_LL_EVENT_RX_HUNG_INT_INT (1<<1) @@ -146,7 +146,7 @@ static inline void lp_i2s_ll_clk_source_div_num(int id, uint32_t val) * @param a div a * @param b div b */ -static inline void i2s_ll_tx_set_raw_clk_div(int id, uint32_t a, uint32_t b) +static inline void lp_i2s_ll_tx_set_raw_clk_div(int id, uint32_t a, uint32_t b) { if (b <= a / 2) { LPPERI.lp_i2s_rxclk_div_xyz.lp_i2s_rx_clkm_div_yn1 = 0; @@ -297,7 +297,7 @@ static inline void lp_i2s_ll_rx_enable_pdm(lp_i2s_dev_t *hw) /** * @brief Configure LP I2S rx channel bits and bits mode */ -static inline void i2s_ll_rx_set_sample_bit(lp_i2s_dev_t *hw, int chan_bits, int bits_mode) +static inline void lp_i2s_ll_rx_set_sample_bit(lp_i2s_dev_t *hw, int chan_bits, int bits_mode) { hw->rx_conf1.rx_tdm_chan_bits = chan_bits - 1; hw->rx_conf1.rx_bits_mod = bits_mode - 1; From b52b99a756181cb7b036bdaf4e450ad32eae364e Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 17 Jun 2024 11:11:06 +0800 Subject: [PATCH 310/548] change(adc): refactor DMA memory allocation --- components/esp_adc/adc_continuous.c | 13 ++++--------- components/esp_adc/adc_dma_internal.h | 2 ++ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index 7fb2f68dcac..381ad55f8d1 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -37,7 +37,6 @@ #include "adc_continuous_internal.h" #include "esp_private/adc_dma.h" #include "adc_dma_internal.h" -#include "esp_dma_utils.h" #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" #include "esp_private/esp_cache_private.h" @@ -192,11 +191,7 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi } //malloc internal buffer used by DMA - esp_dma_mem_info_t dma_mem_info = { - .extra_heap_caps = (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA), - .dma_alignment_bytes = 4, - }; - esp_dma_capable_calloc(1, hdl_config->conv_frame_size * INTERNAL_BUF_NUM, &dma_mem_info, (void **)&adc_ctx->rx_dma_buf, NULL); + adc_ctx->rx_dma_buf = heap_caps_calloc(INTERNAL_BUF_NUM, hdl_config->conv_frame_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); if (!adc_ctx->rx_dma_buf) { ret = ESP_ERR_NO_MEM; goto cleanup; @@ -205,7 +200,7 @@ esp_err_t adc_continuous_new_handle(const adc_continuous_handle_cfg_t *hdl_confi //malloc dma descriptor uint32_t dma_desc_num_per_frame = (hdl_config->conv_frame_size + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED; uint32_t dma_desc_max_num = dma_desc_num_per_frame * INTERNAL_BUF_NUM; - esp_dma_capable_calloc(1, (sizeof(dma_descriptor_t)) * dma_desc_max_num, &dma_mem_info, (void **)&adc_ctx->hal.rx_desc, &adc_ctx->adc_desc_size); + adc_ctx->hal.rx_desc = heap_caps_aligned_calloc(ADC_DMA_DESC_ALIGN, dma_desc_max_num, sizeof(dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); if (!adc_ctx->hal.rx_desc) { ret = ESP_ERR_NO_MEM; goto cleanup; @@ -550,12 +545,12 @@ esp_err_t adc_continuous_flush_pool(adc_continuous_handle_t handle) return ESP_OK; } -esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t * const unit_id, adc_channel_t * const channel) +esp_err_t adc_continuous_io_to_channel(int io_num, adc_unit_t *const unit_id, adc_channel_t *const channel) { return adc_io_to_channel(io_num, unit_id, channel); } -esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int * const io_num) +esp_err_t adc_continuous_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *const io_num) { return adc_channel_to_io(unit_id, channel, io_num); } diff --git a/components/esp_adc/adc_dma_internal.h b/components/esp_adc/adc_dma_internal.h index 5cdc73e2bae..747ea7d5cc4 100644 --- a/components/esp_adc/adc_dma_internal.h +++ b/components/esp_adc/adc_dma_internal.h @@ -32,6 +32,8 @@ typedef struct { intr_handle_t dma_intr_hdl; } adc_dma_t; +#define ADC_DMA_DESC_ALIGN 4 + #ifdef __cplusplus } #endif From 3e3e1c77ba8530b992576f680278a497b2ff7162 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 17 Jun 2024 11:28:07 +0800 Subject: [PATCH 311/548] change(aes): refactor DMA buffer allocation --- components/mbedtls/port/aes/dma/esp_aes_dma_core.c | 9 +-------- components/mbedtls/port/sha/dma/sha.c | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c index 5788b0c2f8e..038a8ec3722 100644 --- a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c +++ b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c @@ -8,7 +8,6 @@ #include "esp_attr.h" #include "esp_cache.h" #include "esp_check.h" -#include "esp_dma_utils.h" #include "esp_err.h" #include "esp_heap_caps.h" #include "esp_intr_alloc.h" @@ -323,13 +322,7 @@ static inline void dma_desc_append(crypto_dma_desc_t **head, crypto_dma_desc_t * static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) { - void *ptr = NULL; - esp_dma_mem_info_t dma_mem_info = { - .extra_heap_caps = caps, - .dma_alignment_bytes = DMA_DESC_MEM_ALIGN_SIZE, - }; - esp_dma_capable_calloc(num, size, &dma_mem_info, &ptr, actual_size); - return ptr; + return heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, num, size, caps | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); } static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_dma_desc_num, size_t cache_line_size) diff --git a/components/mbedtls/port/sha/dma/sha.c b/components/mbedtls/port/sha/dma/sha.c index 7963818d496..25c66fde4fd 100644 --- a/components/mbedtls/port/sha/dma/sha.c +++ b/components/mbedtls/port/sha/dma/sha.c @@ -29,7 +29,6 @@ #include #include -#include "esp_dma_utils.h" #include "esp_private/esp_crypto_lock_internal.h" #include "esp_private/esp_cache_private.h" #include "esp_log.h" From 8cabe4380b06566a97aff3e1db7de7d19a33f040 Mon Sep 17 00:00:00 2001 From: Xiaoyu Liu Date: Mon, 13 May 2024 17:55:07 +0800 Subject: [PATCH 312/548] docs(sys-time): add esp32c5 info into programming guide docs --- docs/docs_not_updated/esp32c5.txt | 2 -- docs/en/api-reference/system/esp_timer.rst | 2 +- docs/en/api-reference/system/system_time.rst | 6 +++--- docs/zh_CN/api-reference/system/esp_timer.rst | 2 +- docs/zh_CN/api-reference/system/system_time.rst | 6 +++--- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index e8504f7f2b7..786d0766876 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -141,8 +141,6 @@ api-reference/system/efuse.rst api-reference/system/chip_revision.rst api-reference/system/async_memcpy.rst api-reference/system/random.rst -api-reference/system/esp_timer.rst -api-reference/system/system_time.rst api-reference/system/power_management.rst api-reference/system/inc/show-efuse-table_ESP32-C5.rst api-reference/system/inc/revisions_ESP32-C5.rst diff --git a/docs/en/api-reference/system/esp_timer.rst b/docs/en/api-reference/system/esp_timer.rst index 981780d5bae..eb2d7456e31 100644 --- a/docs/en/api-reference/system/esp_timer.rst +++ b/docs/en/api-reference/system/esp_timer.rst @@ -5,7 +5,7 @@ ESP Timer (High Resolution Timer) {IDF_TARGET_HR_TIMER:default = "SYSTIMER", esp32 = "LAC timer"} -{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c6 = "52", esp32h2 = "52", esp32p4 = "52"} +{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c5 = "52", esp32c6 = "52", esp32h2 = "52", esp32p4 = "52"} .. only:: html diff --git a/docs/en/api-reference/system/system_time.rst b/docs/en/api-reference/system/system_time.rst index e3b1581253f..3713fc69b92 100644 --- a/docs/en/api-reference/system/system_time.rst +++ b/docs/en/api-reference/system/system_time.rst @@ -3,11 +3,11 @@ System Time :link_to_translation:`zh_CN:[中文]` -{IDF_TARGET_RTC_CLK_FRE:default="Not updated", esp32="150 kHz", esp32s2="90 kHz", esp32s3="136 kHz", esp32c3="136 kHz", esp32c2="136 kHz", esp32c6="150 kHz", esp32h2="150 kHz", esp32p4="150 kHz"} +{IDF_TARGET_RTC_CLK_FRE:default="Not updated", esp32="150 kHz", esp32s2="90 kHz", esp32s3="136 kHz", esp32c3="136 kHz", esp32c2="136 kHz", esp32c5="136 kHz", esp32c6="136 kHz", esp32h2="136 kHz", esp32p4="136 kHz"} {IDF_TARGET_INT_OSC_FRE:default="Not updated", esp32="8.5 MHz", esp32s2="8.5 MHz", esp32s3="17.5 MHz", esp32c3="17.5 MHz", esp32c2="17.5 MHz"} {IDF_TARGET_INT_OSC_FRE_DIVIDED:default="Not updated", esp32="about 33 kHz", esp32s2="about 33 kHz", esp32s3="about 68 kHz", esp32c3="about 68 kHz", esp32c2="about 68 kHz"} -{IDF_TARGET_EXT_CRYSTAL_PIN:default="Not updated", esp32="32K_XP and 32K_XN", esp32s2="XTAL_32K_P and XTAL_32K_N", esp32s3="XTAL_32K_P and XTAL_32K_N", esp32c3="XTAL_32K_P and XTAL_32K_N", esp32c6="XTAL_32K_P and XTAL_32K_N", esp32h2="XTAL_32K_P and XTAL_32K_N", esp32p4="XTAL_32K_P and XTAL_32K_N"} -{IDF_TARGET_EXT_OSC_PIN:default="Not updated", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} +{IDF_TARGET_EXT_CRYSTAL_PIN:default="Not updated", esp32="32K_XP and 32K_XN", esp32s2="XTAL_32K_P and XTAL_32K_N", esp32s3="XTAL_32K_P and XTAL_32K_N", esp32c3="XTAL_32K_P and XTAL_32K_N", esp32c5="XTAL_32K_P and XTAL_32K_N", esp32c6="XTAL_32K_P and XTAL_32K_N", esp32h2="XTAL_32K_P and XTAL_32K_N", esp32p4="XTAL_32K_P and XTAL_32K_N"} +{IDF_TARGET_EXT_OSC_PIN:default="Not updated", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c5="XTAL_32K_P", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} Overview diff --git a/docs/zh_CN/api-reference/system/esp_timer.rst b/docs/zh_CN/api-reference/system/esp_timer.rst index 279c2e99079..8c857990989 100644 --- a/docs/zh_CN/api-reference/system/esp_timer.rst +++ b/docs/zh_CN/api-reference/system/esp_timer.rst @@ -5,7 +5,7 @@ ESP 定时器 {IDF_TARGET_HR_TIMER:default = "SYSTIMER", esp32 = "LAC 定时器"} -{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c6 = "52", esp32h2 = "52"} +{IDF_TARGET_HR_TIMER_Resolution:default = "Not updated", esp32 = "64", esp32s2 = "64", esp32c3 = "52", esp32s3 = "52", esp32c2 = "52", esp32c5 = "52", esp32c6 = "52", esp32h2 = "52"} diff --git a/docs/zh_CN/api-reference/system/system_time.rst b/docs/zh_CN/api-reference/system/system_time.rst index 48f9d678e0e..4f405f19b61 100644 --- a/docs/zh_CN/api-reference/system/system_time.rst +++ b/docs/zh_CN/api-reference/system/system_time.rst @@ -3,11 +3,11 @@ :link_to_translation:`en:[English]` -{IDF_TARGET_RTC_CLK_FRE:default="未更新", esp32="150 kHz", esp32s2="90 kHz", esp32s3="136 kHz", esp32c3="136 kHz", esp32c2="136 kHz", esp32c6="150 kHz", esp32h2="150 kHz", esp32p4="150 kHz"} +{IDF_TARGET_RTC_CLK_FRE:default="未更新", esp32="150 kHz", esp32s2="90 kHz", esp32s3="136 kHz", esp32c3="136 kHz", esp32c2="136 kHz", esp32c5="136 kHz", esp32c6="136 kHz", esp32h2="136 kHz", esp32p4="136 kHz"} {IDF_TARGET_INT_OSC_FRE:default="未更新", esp32="8.5 MHz", esp32s2="8.5 MHz", esp32s3="17.5 MHz", esp32c3="17.5 MHz", esp32c2="17.5 MHz"} {IDF_TARGET_INT_OSC_FRE_DIVIDED:default="未更新", esp32="约 33 kHz", esp32s2="约 33 kHz", esp32s3="约 68 kHz", esp32c3="约 68 kHz", esp32c2="约 68 kHz"} -{IDF_TARGET_EXT_CRYSTAL_PIN:default="未更新", esp32="32K_XP 和 32K_XN", esp32s2="XTAL_32K_P 和 XTAL_32K_N", esp32s3="XTAL_32K_P 和 XTAL_32K_N", esp32c3="XTAL_32K_P 和 XTAL_32K_N", esp32c6="XTAL_32K_P 和 XTAL_32K_N", esp32h2="XTAL_32K_P 和 XTAL_32K_N", esp32p4="XTAL_32K_P 和 XTAL_32K_N"} -{IDF_TARGET_EXT_OSC_PIN:default="未更新", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} +{IDF_TARGET_EXT_CRYSTAL_PIN:default="未更新", esp32="32K_XP 和 32K_XN", esp32s2="XTAL_32K_P 和 XTAL_32K_N", esp32s3="XTAL_32K_P 和 XTAL_32K_N", esp32c3="XTAL_32K_P 和 XTAL_32K_N", esp32c5="XTAL_32K_P 和 XTAL_32K_N", esp32c6="XTAL_32K_P 和 XTAL_32K_N", esp32h2="XTAL_32K_P 和 XTAL_32K_N", esp32p4="XTAL_32K_P 和 XTAL_32K_N"} +{IDF_TARGET_EXT_OSC_PIN:default="未更新", esp32="32K_XN", esp32s2="XTAL_32K_P", esp32s3="XTAL_32K_P", esp32c3="XTAL_32K_P", esp32c2="GPIO0", esp32c5="XTAL_32K_P", esp32c6="XTAL_32K_P", esp32h2="XTAL_32K_P", esp32p4="XTAL_32K_P"} 概述 From dc9f9bf9570124b0267911c769dc6d40c78f3211 Mon Sep 17 00:00:00 2001 From: Lou Tianhao Date: Mon, 24 Jun 2024 20:46:33 +0800 Subject: [PATCH 313/548] docs(pm): add description for gpio_wakeup --- docs/en/api-reference/system/sleep_modes.rst | 20 +++++++++++++++++-- .../api-reference/system/sleep_modes.rst | 20 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/docs/en/api-reference/system/sleep_modes.rst b/docs/en/api-reference/system/sleep_modes.rst index 2fb87648fbd..faf68f80d74 100644 --- a/docs/en/api-reference/system/sleep_modes.rst +++ b/docs/en/api-reference/system/sleep_modes.rst @@ -304,6 +304,20 @@ RTC peripherals or RTC memories do not need to be powered on during sleep in thi esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON); + .. only:: SOC_PM_SUPPORT_TOP_PD + + .. note:: + + .. only:: SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + In Light-sleep mode, if you set Kconfig option :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`, to continue using :cpp:func:`gpio_wakeup_enable` for GPIO wakeup, you need to first call :cpp:func:`rtc_gpio_init` and :cpp:func:`rtc_gpio_set_direction`, setting the RTCIO to input mode. + + Alternatively,you can use :cpp:func:`esp_deep_sleep_enable_gpio_wakeup` directly in that condition for GPIO wakeup, because the digital IO power domain is being powered off, where the situation is the same as entering Deep-sleep. + + .. only:: not SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + In Light-sleep mode, if you set Kconfig option :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`, to continue using :cpp:func:`gpio_wakeup_enable` for GPIO wakeup, you need to first call :cpp:func:`rtc_gpio_init` and :cpp:func:`rtc_gpio_set_direction`, setting the RTCIO to input mode. + .. only:: not SOC_RTCIO_WAKE_SUPPORTED GPIO Wakeup @@ -313,11 +327,13 @@ RTC peripherals or RTC memories do not need to be powered on during sleep in thi Additionally, IOs that are powered by the VDD3P3_RTC power domain can be used to wake up the chip from Deep-sleep. The wakeup pin and wakeup trigger level can be configured by calling :cpp:func:`esp_deep_sleep_enable_gpio_wakeup`. The function will enable the Deep-sleep wakeup for the selected pin. - .. only:: esp32c6 or esp32h2 + .. only:: SOC_PM_SUPPORT_TOP_PD .. note:: - In Light-sleep mode, setting Kconfig option :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` will invalidate GPIO wakeup. + .. only:: SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + In Light-sleep mode, if you set Kconfig option :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`, you can use :cpp:func:`esp_deep_sleep_enable_gpio_wakeup` directly for GPIO wakeup, because the digital IO power domain is being powered off, where the situation is the same as entering Deep-sleep. UART Wakeup (Light-sleep Only) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-reference/system/sleep_modes.rst b/docs/zh_CN/api-reference/system/sleep_modes.rst index 10a67020d52..76567ecffea 100644 --- a/docs/zh_CN/api-reference/system/sleep_modes.rst +++ b/docs/zh_CN/api-reference/system/sleep_modes.rst @@ -304,6 +304,20 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒 esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON); + .. only:: SOC_PM_SUPPORT_TOP_PD + + .. note:: + + .. only:: SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + 在 Light-sleep 模式下,如果设置 Kconfig 选项 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,为了继续使用 :cpp:func:`gpio_wakeup_enable` 用于 GPIO 唤醒, 需要先调用 :cpp:func:`rtc_gpio_init` 和 :cpp:func:`rtc_gpio_set_direction`,用于设置 RTC IO 为输入模式。 + + 或者, 可以使用直接调用 :cpp:func:`esp_deep_sleep_enable_gpio_wakeup` 用于 GPIO 唤醒,因为此时 digital IO 的电源域已经被关闭,这个情况类似于进入 Deep-sleep。 + + .. only:: not SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + 在 Light-sleep 模式下,如果设置 Kconfig 选项 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,为了继续使用 :cpp:func:`gpio_wakeup_enable` 用于 GPIO 唤醒, 需要先调用 :cpp:func:`rtc_gpio_init` 和 :cpp:func:`rtc_gpio_set_direction`,用于设置 RTC IO 为输入模式。 + .. only:: not SOC_RTCIO_WAKE_SUPPORTED GPIO 唤醒 @@ -313,11 +327,13 @@ RTC 控制器中内嵌定时器,可用于在预定义的时间到达后唤醒 此外,可将由 VDD3P3_RTC 电源域供电的 IO 用于芯片的 Deep-sleep 唤醒。调用 :cpp:func:`esp_deep_sleep_enable_gpio_wakeup` 函数可以配置相应的唤醒管脚和唤醒触发电平,该函数用于启用相应管脚的 Deep-sleep 唤醒功能。 - .. only:: esp32c6 or esp32h2 + .. only:: SOC_PM_SUPPORT_TOP_PD .. note:: - 在 Light-sleep 模式下,设置 Kconfig 选项 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP` 将使 GPIO 唤醒失效。 + .. only:: SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP + + 在 Light-sleep 模式下,如果设置 Kconfig 选项 :ref:`CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP`,可以使用直接调用 :cpp:func:`esp_deep_sleep_enable_gpio_wakeup` 用于 GPIO 唤醒,因为此时 digital IO 的电源域已经被关闭,这个情况类似于进入 Deep-sleep。 UART 唤醒(仅适用于 Light-sleep 模式) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From ad31f4f02969f887922744e281b319a405bb4978 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Tue, 30 Apr 2024 12:25:32 +0800 Subject: [PATCH 314/548] fix(bt): Update bt lib for ESP32-C3 and ESP32-S3(eca46a0) - Fixed adv data buffer free after restart adv - Fixed BLE interrupt allocation using esp API --- components/bt/controller/esp32c3/bt.c | 91 +++++++++++-------- components/bt/controller/lib_esp32c3_family | 2 +- .../port/esp32c3/esp_cpu_intr.c | 3 +- .../port/esp32s3/esp_cpu_intr.c | 31 +------ components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 +- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 +- .../esp_intr_dump/expected_output/esp32c3.txt | 11 +-- 7 files changed, 65 insertions(+), 77 deletions(-) diff --git a/components/bt/controller/esp32c3/bt.c b/components/bt/controller/esp32c3/bt.c index e053cfdf40e..0a461d071fb 100644 --- a/components/bt/controller/esp32c3/bt.c +++ b/components/bt/controller/esp32c3/bt.c @@ -115,7 +115,7 @@ do{\ } while(0) #define OSI_FUNCS_TIME_BLOCKING 0xffffffff -#define OSI_VERSION 0x00010008 +#define OSI_VERSION 0x00010009 #define OSI_MAGIC_VALUE 0xFADEBEAD /* Types definition @@ -142,15 +142,24 @@ typedef struct { typedef void (* osi_intr_handler)(void); +typedef struct { + int source; /*!< ISR source */ + int flags; /*!< ISR alloc flag */ + void (*fn)(void *); /*!< ISR function */ + void *arg; /*!< ISR function args*/ + intr_handle_t *handle; /*!< ISR handle */ + esp_err_t ret; +} btdm_isr_alloc_t; + /* OSI function */ struct osi_funcs_t { uint32_t _magic; uint32_t _version; - void (*_interrupt_set)(int cpu_no, int intr_source, int interrupt_no, int interrpt_prio); - void (*_interrupt_clear)(int interrupt_source, int interrupt_no); - void (*_interrupt_handler_set)(int interrupt_no, intr_handler_t fn, void *arg); - void (*_interrupt_disable)(void); - void (*_interrupt_restore)(void); + int (* _interrupt_alloc)(int cpu_id, int source, intr_handler_t handler, void *arg, void **ret_handle); + int (* _interrupt_free)(void *handle); + void (*_interrupt_handler_set_rsv)(int interrupt_no, intr_handler_t fn, void *arg); + void (*_global_intr_disable)(void); + void (*_global_intr_restore)(void); void (*_task_yield)(void); void (*_task_yield_from_isr)(void); void *(*_semphr_create)(uint32_t max, uint32_t init); @@ -195,8 +204,8 @@ struct osi_funcs_t { uint32_t (* _coex_schm_interval_get)(void); uint8_t (* _coex_schm_curr_period_get)(void); void *(* _coex_schm_curr_phase_get)(void); - void (* _interrupt_on)(int intr_num); - void (* _interrupt_off)(int intr_num); + int (* _interrupt_enable)(void *handle); + int (* _interrupt_disable)(void *handle); void (* _esp_hw_power_down)(void); void (* _esp_hw_power_up)(void); void (* _ets_backup_dma_copy)(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_rem); @@ -277,11 +286,10 @@ extern uint32_t _bt_controller_data_end; /* Local Function Declare ********************************************************************* */ -static void interrupt_set_wrapper(int cpu_no, int intr_source, int intr_num, int intr_prio); -static void interrupt_clear_wrapper(int intr_source, int intr_num); -static void interrupt_handler_set_wrapper(int n, intr_handler_t fn, void *arg); -static void interrupt_disable(void); -static void interrupt_restore(void); +static int interrupt_alloc_wrapper(int cpu_id, int source, intr_handler_t handler, void *arg, void **ret_handle); +static int interrupt_free_wrapper(void *handle); +static void global_interrupt_disable(void); +static void global_interrupt_restore(void); static void task_yield_from_isr(void); static void *semphr_create_wrapper(uint32_t max, uint32_t init); static void semphr_delete_wrapper(void *semphr); @@ -319,8 +327,8 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); static uint32_t coex_schm_interval_get_wrapper(void); static uint8_t coex_schm_curr_period_get_wrapper(void); static void * coex_schm_curr_phase_get_wrapper(void); -static void interrupt_on_wrapper(int intr_num); -static void interrupt_off_wrapper(int intr_num); +static int interrupt_enable_wrapper(void *handle); +static int interrupt_disable_wrapper(void *handle); static void btdm_hw_mac_power_up_wrapper(void); static void btdm_hw_mac_power_down_wrapper(void); static void btdm_backup_dma_copy_wrapper(uint32_t reg, uint32_t mem_addr, uint32_t num, bool to_mem); @@ -341,11 +349,11 @@ static void bt_controller_deinit_internal(void); static const struct osi_funcs_t osi_funcs_ro = { ._magic = OSI_MAGIC_VALUE, ._version = OSI_VERSION, - ._interrupt_set = interrupt_set_wrapper, - ._interrupt_clear = interrupt_clear_wrapper, - ._interrupt_handler_set = interrupt_handler_set_wrapper, - ._interrupt_disable = interrupt_disable, - ._interrupt_restore = interrupt_restore, + ._interrupt_alloc = interrupt_alloc_wrapper, + ._interrupt_free = interrupt_free_wrapper, + ._interrupt_handler_set_rsv = NULL, + ._global_intr_disable = global_interrupt_disable, + ._global_intr_restore = global_interrupt_restore, ._task_yield = vPortYield, ._task_yield_from_isr = task_yield_from_isr, ._semphr_create = semphr_create_wrapper, @@ -390,8 +398,8 @@ static const struct osi_funcs_t osi_funcs_ro = { ._coex_schm_interval_get = coex_schm_interval_get_wrapper, ._coex_schm_curr_period_get = coex_schm_curr_period_get_wrapper, ._coex_schm_curr_phase_get = coex_schm_curr_phase_get_wrapper, - ._interrupt_on = interrupt_on_wrapper, - ._interrupt_off = interrupt_off_wrapper, + ._interrupt_enable = interrupt_enable_wrapper, + ._interrupt_disable = interrupt_disable_wrapper, ._esp_hw_power_down = btdm_hw_mac_power_down_wrapper, ._esp_hw_power_up = btdm_hw_mac_power_up_wrapper, ._ets_backup_dma_copy = btdm_backup_dma_copy_wrapper, @@ -478,35 +486,44 @@ static inline void esp_bt_power_domain_off(void) esp_wifi_bt_power_domain_off(); } -static void interrupt_set_wrapper(int cpu_no, int intr_source, int intr_num, int intr_prio) +static void btdm_intr_alloc(void *arg) { - esp_rom_route_intr_matrix(cpu_no, intr_source, intr_num); -#if __riscv - esprv_int_set_priority(intr_num, intr_prio); - esprv_int_set_type(intr_num, 0); -#endif + btdm_isr_alloc_t *p = arg; + p->ret = esp_intr_alloc(p->source, p->flags, p->fn, p->arg, p->handle); } -static void interrupt_clear_wrapper(int intr_source, int intr_num) +static int interrupt_alloc_wrapper(int cpu_id, int source, intr_handler_t handler, void *arg, void **ret_handle) { + btdm_isr_alloc_t p; + p.source = source; + p.flags = ESP_INTR_FLAG_LEVEL3 | ESP_INTR_FLAG_IRAM; + p.fn = handler; + p.arg = arg; + p.handle = (intr_handle_t *)ret_handle; +#if CONFIG_FREERTOS_UNICORE + btdm_intr_alloc(&p); +#else + esp_ipc_call_blocking(cpu_id, btdm_intr_alloc, &p); +#endif + return p.ret; } -static void interrupt_handler_set_wrapper(int n, intr_handler_t fn, void *arg) +static int interrupt_free_wrapper(void *handle) { - esp_cpu_intr_set_handler(n, fn, arg); + return esp_intr_free((intr_handle_t)handle); } -static void interrupt_on_wrapper(int intr_num) +static int interrupt_enable_wrapper(void *handle) { - esp_cpu_intr_enable(1 << intr_num); + return esp_intr_enable((intr_handle_t)handle); } -static void interrupt_off_wrapper(int intr_num) +static int interrupt_disable_wrapper(void *handle) { - esp_cpu_intr_disable(1<priority = 1; intr_desc_ret->type = ESP_CPU_INTR_TYPE_NA; diff --git a/components/esp_hw_support/port/esp32s3/esp_cpu_intr.c b/components/esp_hw_support/port/esp32s3/esp_cpu_intr.c index acd0cbe83dd..7c0ef80acc7 100644 --- a/components/esp_hw_support/port/esp32s3/esp_cpu_intr.c +++ b/components/esp_hw_support/port/esp32s3/esp_cpu_intr.c @@ -20,31 +20,6 @@ typedef struct { } intr_desc_t; -/** - * @brief Reserve the interrupts on the core where Bluetooth will run. - * The macro CONFIG_BT_CTRL_PINNED_TO_CORE is only defined if Bluetooth controller is enabled. - * It is set to the core where it will run. - */ -#ifdef CONFIG_BT_CTRL_PINNED_TO_CORE - #if CONFIG_BT_CTRL_PINNED_TO_CORE == 0 - #define CORE_0_INTERRUPT_5 ESP_CPU_INTR_DESC_FLAG_RESVD - #define CORE_1_INTERRUPT_5 0 - #define CORE_0_INTERRUPT_8 ESP_CPU_INTR_DESC_FLAG_RESVD - #define CORE_1_INTERRUPT_8 0 - #elif CONFIG_BT_CTRL_PINNED_TO_CORE == 1 - #define CORE_0_INTERRUPT_5 0 - #define CORE_1_INTERRUPT_5 ESP_CPU_INTR_DESC_FLAG_RESVD - #define CORE_0_INTERRUPT_8 0 - #define CORE_1_INTERRUPT_8 ESP_CPU_INTR_DESC_FLAG_RESVD - #endif -#else // Bluetooth not enabled - #define CORE_0_INTERRUPT_5 0 - #define CORE_1_INTERRUPT_5 0 - #define CORE_0_INTERRUPT_8 0 - #define CORE_1_INTERRUPT_8 0 -#endif - - const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = { /* Interrupt 0 reserved for WMAC (Wifi) */ #if CONFIG_ESP_WIFI_TASK_PINNED_TO_CORE_0 @@ -57,12 +32,10 @@ const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = { [3] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, /* Interrupt 4 reserved for WBB */ [4] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, 0 } }, - /* Interrupt 5 reserved for BT/BLE Controller */ - [5] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { CORE_0_INTERRUPT_5, CORE_1_INTERRUPT_5 } }, + [5] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, [6] = { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, [7] = { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, - /* Interrupt 8 reserved for BT/BLE Controller */ - [8] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { CORE_0_INTERRUPT_8, CORE_1_INTERRUPT_8 } }, + [8] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, [9] = { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, [10] = { 1, ESP_CPU_INTR_TYPE_EDGE, { 0, 0 } }, [11] = { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index 60c97f4923d..b454cd5986b 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -1243,7 +1243,7 @@ r_rw_cryto_aes_cmac = 0x4000145c; r_rw_v9_init_em_radio_table = 0x40001460; r_rwble_sleep_enter = 0x40001468; r_rwble_sleep_wakeup_end = 0x4000146c; -r_rwbtdm_isr_wrapper = 0x40001470; +/* r_rwbtdm_isr_wrapper = 0x40001470; */ r_rwip_active_check = 0x40001474; r_rwip_aes_encrypt = 0x40001478; r_rwip_assert = 0x4000147c; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 9f23d00f6b9..ea7f4737ba1 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -1493,7 +1493,7 @@ r_rw_cryto_aes_cmac = 0x40004cf8; r_rw_v9_init_em_radio_table = 0x40004d04; r_rwble_sleep_enter = 0x40004d1c; r_rwble_sleep_wakeup_end = 0x40004d28; -r_rwbtdm_isr_wrapper = 0x40004d34; +/* r_rwbtdm_isr_wrapper = 0x40004d34; */ r_rwip_active_check = 0x40004d40; r_rwip_aes_encrypt = 0x40004d4c; r_rwip_assert = 0x40004d58; diff --git a/tools/test_apps/system/esp_intr_dump/expected_output/esp32c3.txt b/tools/test_apps/system/esp_intr_dump/expected_output/esp32c3.txt index 6140d1557b6..5d10779cd1c 100644 --- a/tools/test_apps/system/esp_intr_dump/expected_output/esp32c3.txt +++ b/tools/test_apps/system/esp_intr_dump/expected_output/esp32c3.txt @@ -5,11 +5,11 @@ CPU 0 interrupt status: 2 1 Level Used: RTC_CORE 3 1 Level Used: FROM_CPU_INTR0 4 1 Level Used: SYSTIMER_TARGET0_EDGE - 5 * * Reserved + 5 1 Level Used: TG0_WDT_LEVEL 6 * * Reserved - 7 1 Level Used: TG0_WDT_LEVEL - 8 * * Reserved - 9 1 Level Used: UART0 + 7 1 Level Used: UART0 + 8 * * Free + 9 * * Free 10 * * Free 11 * * Free 12 * * Free @@ -32,5 +32,4 @@ CPU 0 interrupt status: 29 * * Free 30 * * Free 31 * * Free -Interrupts available for general use: 18 -Shared interrupts: 0 \ No newline at end of file +Interrupts available for general use: 20 \ No newline at end of file From 1b3672489789c4aeb29fb8cc1269be7cc96f7b06 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Mon, 3 Jun 2024 11:14:46 +0800 Subject: [PATCH 315/548] fix(bt): Update bt lib for ESP32-C3 and ESP32-S3(0738a61) - Fixed BT BB interrupt allocation - Refactor the prefix of assert print - Fixed HCI LE set privacy mode command handle --- components/bt/controller/lib_esp32c3_family | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 4 ++-- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index 1a086eab61e..29d5555ca1f 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit 1a086eab61e78fa243d67c33206ece4022129ee1 +Subproject commit 29d5555ca1febeb132f5a13556893f3419d2d640 diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld index e45a80e496c..b2710d0da52 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld @@ -115,7 +115,6 @@ r_lld_con_evt_time_update_eco = 0x40001d0c; r_lld_con_start_eco = 0x40001d10; r_lld_con_frm_isr_eco = 0x40001d14; r_lld_con_tx_eco = 0x40001d18; -r_lld_scan_evt_start_cbk_eco = 0x40001d20; r_lld_ext_scan_dynamic_pti_process_eco = 0x40001d28; r_lld_scan_frm_eof_isr_eco = 0x40001d2c; r_lld_sync_start_eco = 0x40001d30; @@ -215,6 +214,7 @@ r_lld_scan_start_eco = 0x40001d24; r_lld_scan_try_sched_eco = 0x40001dac; r_lld_scan_start_hook = 0x40001c74; r_lld_init_start_hook = 0x40001cb8; +r_lld_scan_evt_start_cbk_eco = 0x40001d20; */ diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index b454cd5986b..77b4cfbdc6c 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -1107,7 +1107,7 @@ r_lld_res_list_is_empty = 0x40001220; r_lld_res_list_local_rpa_get = 0x40001224; r_lld_res_list_peer_rpa_get = 0x40001228; r_lld_res_list_peer_update = 0x4000122c; -r_lld_res_list_priv_mode_update = 0x40001230; +/* r_lld_res_list_priv_mode_update = 0x40001230; */ r_lld_reset_reg = 0x40001238; r_lld_rpa_renew = 0x4000123c; r_lld_rpa_renew_evt_canceled_cbk = 0x40001240; @@ -1246,7 +1246,7 @@ r_rwble_sleep_wakeup_end = 0x4000146c; /* r_rwbtdm_isr_wrapper = 0x40001470; */ r_rwip_active_check = 0x40001474; r_rwip_aes_encrypt = 0x40001478; -r_rwip_assert = 0x4000147c; +/* r_rwip_assert = 0x4000147c; */ r_rwip_crypt_evt_handler = 0x40001480; r_rwip_crypt_isr_handler = 0x40001484; r_rwip_eif_get = 0x40001488; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index ea7f4737ba1..6e6187961da 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -1357,7 +1357,7 @@ r_lld_res_list_is_empty = 0x40004644; r_lld_res_list_local_rpa_get = 0x40004650; r_lld_res_list_peer_rpa_get = 0x4000465c; r_lld_res_list_peer_update = 0x40004668; -r_lld_res_list_priv_mode_update = 0x40004674; +/* r_lld_res_list_priv_mode_update = 0x40004674; */ r_lld_reset_reg = 0x4000468c; r_lld_rpa_renew = 0x40004698; r_lld_rpa_renew_evt_canceled_cbk = 0x400046a4; @@ -1496,7 +1496,7 @@ r_rwble_sleep_wakeup_end = 0x40004d28; /* r_rwbtdm_isr_wrapper = 0x40004d34; */ r_rwip_active_check = 0x40004d40; r_rwip_aes_encrypt = 0x40004d4c; -r_rwip_assert = 0x40004d58; +/* r_rwip_assert = 0x40004d58; */ r_rwip_crypt_evt_handler = 0x40004d64; r_rwip_crypt_isr_handler = 0x40004d70; r_rwip_eif_get = 0x40004d7c; From 73ef188a8c9351232bf13e05518ef5ca88c85d3e Mon Sep 17 00:00:00 2001 From: linruihao Date: Tue, 4 Jun 2024 17:18:33 +0800 Subject: [PATCH 316/548] fix(bt): Overwrite a function in esp32c3 eco7 rom --- components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld index b2710d0da52..9150a4e32ce 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.eco7.ld @@ -141,7 +141,6 @@ r_bt_bb_recorrect_is_dead = 0x40001d84; r_bt_bb_restart_hw_recorrect = 0x40001d88; r_ke_task_handler_pre = 0x40001da0; r_ke_task_handler_end = 0x40001da4; -r_ke_task_handler_get_overwrite = 0x40001da8; r_lld_scan_frm_skip_isr_eco = 0x40001db0; r_lld_ext_scan_dynamic_pti_reset = 0x40001db4; r_llc_rem_phy_upd_proc_continue_eco = 0x40001db8; @@ -215,6 +214,7 @@ r_lld_scan_try_sched_eco = 0x40001dac; r_lld_scan_start_hook = 0x40001c74; r_lld_init_start_hook = 0x40001cb8; r_lld_scan_evt_start_cbk_eco = 0x40001d20; +r_ke_task_handler_get_overwrite = 0x40001da8; */ From 14b64bfede2e8132c7f9531d3199feaab0a60261 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Tue, 14 May 2024 14:50:53 +0800 Subject: [PATCH 317/548] fix(bt/bluedroid): Fixed BLE security vulnerability when using fixed IRK --- components/bt/host/bluedroid/Kconfig.in | 15 +++++++++-- .../include/common/bluedroid_user_config.h | 8 +++++- .../common/include/common/bt_target.h | 10 +++++-- .../bluedroid/stack/btm/btm_ble_privacy.c | 3 +++ .../bt/host/bluedroid/stack/btm/btm_dev.c | 27 +++++++++++++------ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 58859d35f89..f66333932d3 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -85,7 +85,7 @@ config BT_A2DP_ENABLE depends on BT_CLASSIC_ENABLED default n help - Advanced Audio Distrubution Profile + Advanced Audio Distribution Profile config BT_SPP_ENABLED bool "SPP" @@ -140,7 +140,7 @@ config BT_HFP_WBS_ENABLE default y help This enables Wide Band Speech. Should disable it when SCO data path is PCM. - Otherwise there will be no data transmited via GPIOs. + Otherwise there will be no data transmitted via GPIOs. menuconfig BT_HID_ENABLED @@ -312,6 +312,17 @@ config BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE In order to reduce the pairing time, slave actively initiates connection parameters update during pairing. +config BT_BLE_SMP_ID_RESET_ENABLE + bool "Reset device identity when all bonding records are deleted" + depends on BT_BLE_SMP_ENABLE + default n + help + There are tracking risks associated with using a fixed or static IRK. + If enabled this option, Bluedroid will assign a new randomly-generated IRK + when all pairing and bonding records are deleted. This would decrease the ability + of a previously paired peer to be used to determine whether a device + with which it previously shared an IRK is within range. + config BT_STACK_NO_LOG bool "Disable BT debug logs (minimize bin size)" depends on BT_BLUEDROID_ENABLED diff --git a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h index 81cfbaacdd3..ee1f548db36 100644 --- a/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h +++ b/components/bt/host/bluedroid/common/include/common/bluedroid_user_config.h @@ -218,7 +218,13 @@ #define UC_BT_SMP_MAX_BONDS 8 #endif -//Device Nane Maximum Length +#ifdef CONFIG_BT_BLE_SMP_ID_RESET_ENABLE +#define UC_BT_BLE_SMP_ID_RESET_ENABLE CONFIG_BT_BLE_SMP_ID_RESET_ENABLE +#else +#define UC_BT_BLE_SMP_ID_RESET_ENABLE FALSE +#endif + +//Device Name Maximum Length #ifdef CONFIG_BT_MAX_DEVICE_NAME_LEN #define UC_MAX_LOC_BD_NAME_LEN CONFIG_BT_MAX_DEVICE_NAME_LEN #else diff --git a/components/bt/host/bluedroid/common/include/common/bt_target.h b/components/bt/host/bluedroid/common/include/common/bt_target.h index 0adad84fb05..34ff48bc929 100644 --- a/components/bt/host/bluedroid/common/include/common/bt_target.h +++ b/components/bt/host/bluedroid/common/include/common/bt_target.h @@ -290,6 +290,12 @@ #define SMP_SLAVE_CON_PARAMS_UPD_ENABLE FALSE #endif /* UC_BT_SMP_SLAVE_CON_PARAMS_UPD_ENABLE */ +#if (UC_BT_BLE_SMP_ID_RESET_ENABLE) +#define BLE_SMP_ID_RESET_ENABLE TRUE +#else +#define BLE_SMP_ID_RESET_ENABLE FALSE +#endif + #ifdef UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP #define BLE_ADV_REPORT_FLOW_CONTROL (UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP && BLE_INCLUDED) #endif /* UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP */ @@ -569,7 +575,7 @@ #define BT_CLASSIC_BQB_INCLUDED FALSE #endif -/* This feature is used to eanble interleaved scan*/ +/* This feature is used to enable interleaved scan*/ #ifndef BTA_HOST_INTERLEAVE_SEARCH #define BTA_HOST_INTERLEAVE_SEARCH FALSE #endif @@ -1385,7 +1391,7 @@ #define GATT_CONFORMANCE_TESTING FALSE #endif -/* number of background connection device allowence, ideally to be the same as WL size +/* number of background connection device allowance, ideally to be the same as WL size */ #ifndef GATT_MAX_BG_CONN_DEV #define GATT_MAX_BG_CONN_DEV 8 /*MAX is 32*/ diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index be4b9d15411..9d937b718e2 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -1147,6 +1147,9 @@ void btm_ble_add_default_entry_to_resolving_list(void) BD_ADDR peer_addr = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; BT_OCTET16 peer_irk = {0x0}; + // Remove the existing entry in resolving list When resetting the device identity + btsnd_hcic_ble_rm_device_resolving_list(BLE_ADDR_PUBLIC, peer_addr); + btsnd_hcic_ble_add_device_resolving_list (BLE_ADDR_PUBLIC, peer_addr, peer_irk, btm_cb.devcb.id_keys.irk); } #endif diff --git a/components/bt/host/bluedroid/stack/btm/btm_dev.c b/components/bt/host/bluedroid/stack/btm/btm_dev.c index f9e3ed2bd4c..169dcc14494 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_dev.c +++ b/components/bt/host/bluedroid/stack/btm/btm_dev.c @@ -179,20 +179,31 @@ BOOLEAN BTM_SecAddDevice (BD_ADDR bd_addr, DEV_CLASS dev_class, BD_NAME bd_name, *******************************************************************************/ BOOLEAN BTM_SecDeleteDevice (BD_ADDR bd_addr, tBT_TRANSPORT transport) { - tBTM_SEC_DEV_REC *p_dev_rec; if (BTM_IsAclConnectionUp(bd_addr, transport)) { BTM_TRACE_WARNING("%s FAILED: Cannot Delete when connection is active\n", __func__); return FALSE; } + if ((p_dev_rec = btm_find_dev(bd_addr)) != NULL) { /* Tell controller to get rid of the link key, if it has one stored */ BTM_DeleteStoredLinkKey (p_dev_rec->bd_addr, NULL); - btm_sec_free_dev(p_dev_rec, transport); + btm_sec_free_dev(p_dev_rec, transport); } +#if (BLE_SMP_ID_RESET_ENABLE == TRUE) + /* + * There are tracking risks associated with using a fixed or static IRK. + * A best-practices approach, when all pairing and bonding records are deleted, + * assign a new randomly-generated IRK. + */ + if (list_is_empty(btm_cb.p_sec_dev_rec_list)) { + btm_ble_reset_id(); + } +#endif + return TRUE; } @@ -640,7 +651,7 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) tBTM_SEC_DEV_REC *p_dev_rec = NULL; tBTM_SEC_DEV_REC *p_oldest = NULL; list_node_t *p_node = NULL; - UINT32 ot = 0xFFFFFFFF; + UINT32 old_ts = 0xFFFFFFFF; /* First look for the non-paired devices for the oldest entry */ for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { @@ -650,13 +661,13 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) continue; /* Device is paired so skip it */ } - if (p_dev_rec->timestamp < ot) { + if (p_dev_rec->timestamp < old_ts) { p_oldest = p_dev_rec; - ot = p_dev_rec->timestamp; + old_ts = p_dev_rec->timestamp; } } - if (ot != 0xFFFFFFFF) { + if (old_ts != 0xFFFFFFFF) { return (p_oldest); } @@ -666,9 +677,9 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) continue; } - if (p_dev_rec->timestamp < ot) { + if (p_dev_rec->timestamp < old_ts) { p_oldest = p_dev_rec; - ot = p_dev_rec->timestamp; + old_ts = p_dev_rec->timestamp; } } return (p_oldest); From 2845990aff0462779bcb1a27a6d0cc3d5957b80e Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Tue, 4 Jun 2024 15:43:34 +0800 Subject: [PATCH 318/548] feat(bt/bluedroid): Add definition for the reason of BLE authentication failure --- .../api/include/api/esp_gap_ble_api.h | 54 +++++++++++++++---- .../bluedroid/stack/btm/btm_ble_privacy.c | 2 +- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h index ea52baf00e5..75fd3419e6e 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -661,21 +661,55 @@ typedef struct { esp_bt_octet16_t oob_r; /*!< the 128 bits of randomizer value */ } esp_ble_local_oob_data_t; +/** +* @brief Definition of the authentication failed reason +*/ +typedef enum { + // Failure reason defined in Bluetooth Core Spec 5.0 Vol3, Part H, 3.5.5 + ESP_AUTH_SMP_PASSKEY_FAIL = 78, /*!< The user input of passkey failed */ + ESP_AUTH_SMP_OOB_FAIL, /*!< The OOB data is not available */ + ESP_AUTH_SMP_PAIR_AUTH_FAIL, /*!< The authentication requirements cannot be met */ + ESP_AUTH_SMP_CONFIRM_VALUE_FAIL, /*!< The confirm value does not match the calculated comparison value */ + ESP_AUTH_SMP_PAIR_NOT_SUPPORT, /*!< Pairing is not supported by the device */ + ESP_AUTH_SMP_ENC_KEY_SIZE, /*!< The resultant encryption key size is not long enough */ + ESP_AUTH_SMP_INVALID_CMD, /*!< The SMP command received is not supported by this device */ + ESP_AUTH_SMP_UNKNOWN_ERR, /*!< Pairing failed due to an unspecified reason */ + ESP_AUTH_SMP_REPEATED_ATTEMPT, /*!< Pairing or authentication procedure is disallowed */ + ESP_AUTH_SMP_INVALID_PARAMETERS, /*!< The command length is invalid or that a parameter is outside the specified range */ + ESP_AUTH_SMP_DHKEY_CHK_FAIL, /*!< The DHKey Check value received doesn’t match the one calculated by the local device */ + ESP_AUTH_SMP_NUM_COMP_FAIL, /*!< The confirm values in the numeric comparison protocol do not match */ + ESP_AUTH_SMP_BR_PARING_IN_PROGR, /*!< Pairing Request sent over the BR/EDR transport is in progress */ + ESP_AUTH_SMP_XTRANS_DERIVE_NOT_ALLOW, /*!< The BR/EDR Link Key or BLE LTK cannot be used to derive */ + + // Failure reason defined in Bluedroid Host + ESP_AUTH_SMP_INTERNAL_ERR, /*!< Internal error in pairing procedure */ + ESP_AUTH_SMP_UNKNOWN_IO, /*!< Unknown IO capability, unable to decide association model */ + ESP_AUTH_SMP_INIT_FAIL, /*!< SMP pairing initiation failed */ + ESP_AUTH_SMP_CONFIRM_FAIL, /*!< The confirm value does not match */ + ESP_AUTH_SMP_BUSY, /*!< Pending security request on going */ + ESP_AUTH_SMP_ENC_FAIL, /*!< The Controller failed to start encryption */ + ESP_AUTH_SMP_STARTED, /*!< SMP pairing process started */ + ESP_AUTH_SMP_RSP_TIMEOUT, /*!< Security Manager timeout due to no SMP command being received */ + ESP_AUTH_SMP_DIV_NOT_AVAIL, /*!< Encrypted Diversifier value not available */ + ESP_AUTH_SMP_UNSPEC_ERR, /*!< Unspecified failed reason */ + ESP_AUTH_SMP_CONN_TOUT, /*!< Pairing process failed due to connection timeout */ +} esp_ble_auth_fail_rsn_t; + /** * @brief Structure associated with ESP_AUTH_CMPL_EVT */ typedef struct { - esp_bd_addr_t bd_addr; /*!< BD address peer device. */ - bool key_present; /*!< Valid link key value in key element */ - esp_link_key key; /*!< Link key associated with peer device. */ - uint8_t key_type; /*!< The type of Link Key */ - bool success; /*!< TRUE of authentication succeeded, FALSE if failed. */ - uint8_t fail_reason; /*!< The HCI reason/error code for when success=FALSE */ - esp_ble_addr_type_t addr_type; /*!< Peer device address type */ - esp_bt_dev_type_t dev_type; /*!< Device type */ - esp_ble_auth_req_t auth_mode; /*!< authentication mode */ -} esp_ble_auth_cmpl_t; /*!< The ble authentication complete cb type */ + esp_bd_addr_t bd_addr; /*!< BD address of peer device */ + bool key_present; /*!< True if the link key value is valid; false otherwise */ + esp_link_key key; /*!< Link key associated with peer device */ + uint8_t key_type; /*!< The type of link key */ + bool success; /*!< True if authentication succeeded; false otherwise */ + esp_ble_auth_fail_rsn_t fail_reason; /*!< The HCI reason/error code for failure when success is false */ + esp_ble_addr_type_t addr_type; /*!< Peer device address type */ + esp_bt_dev_type_t dev_type; /*!< Device type */ + esp_ble_auth_req_t auth_mode; /*!< Authentication mode */ +} esp_ble_auth_cmpl_t; /*!< The ble authentication complete cb type */ /** * @brief union associated with ble security diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 9d937b718e2..9ddf746ae9b 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -330,7 +330,7 @@ void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len) BTM_TRACE_DEBUG("%s status = %d", __func__, status); if (!btm_ble_deq_resolving_pending(pseudo_bda)) { - BTM_TRACE_ERROR("%s no pending resolving list operation", __func__); + BTM_TRACE_DEBUG("%s no pending resolving list operation", __func__); return; } From d617f8d5b0ca7e839b1ec20c2a547de8aebfe64a Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 26 Jun 2024 17:19:00 +0800 Subject: [PATCH 319/548] feat(bluetooth/controller): Fixed the issue of unresponsiveness when using hci uart mode on ESP32-C6 and ESP32-H2 --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index c2b9d7c8c2a..ed6c0b4e0ab 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit c2b9d7c8c2ab4872ffe4f0501c4753fcbc96ba48 +Subproject commit ed6c0b4e0ab3b8ddce5d8bc65e417b1adcbca5b4 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index c2c9f4161f2..2d69367e13a 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit c2c9f4161f2ed200dbbcec71fbfd26da0241f376 +Subproject commit 2d69367e13a928afb73d1a8c579c0dad98eb9393 From 2543313f80091a67edb34f9e8e0c480f52b8d1a6 Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 26 Jun 2024 17:19:33 +0800 Subject: [PATCH 320/548] feat(bluetooth/controller): Fixed the issue of unresponsiveness when using hci uart mode on ESP32-C5 --- components/bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index 3996803d35b..5f428f91411 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit 3996803d35bcb79283bb7dcff60a11092339a838 +Subproject commit 5f428f914114c88470bf0a785f08840c2b35abca From 350d4c03da318e9a1112cc499e1b2d5655d0a0c6 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 27 Jun 2024 16:17:05 +0800 Subject: [PATCH 321/548] docs(ulp): fix doxygen comment formatting --- components/ulp/lp_core/include/ulp_lp_core.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/ulp/lp_core/include/ulp_lp_core.h b/components/ulp/lp_core/include/ulp_lp_core.h index 447c814ddac..d737d638aca 100644 --- a/components/ulp/lp_core/include/ulp_lp_core.h +++ b/components/ulp/lp_core/include/ulp_lp_core.h @@ -31,9 +31,9 @@ typedef struct { uint32_t wakeup_source; /*!< Wakeup source flags */ uint32_t lp_timer_sleep_duration_us; /*!< Sleep duration when ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER is specified. Measurement unit: us */ #if ESP_ROM_HAS_LP_ROM - bool skip_lp_rom_boot; /* !< Skips the LP rom code and boots directly into the app code placed in LP RAM, - this gives faster boot time for time sensitive use-cases at the cost of skipping - setup e.g. of UART */ + bool skip_lp_rom_boot; /*!< Skips the LP rom code and boots directly into the app code placed in LP RAM, + this gives faster boot time for time sensitive use-cases at the cost of skipping + setup e.g. of UART */ #endif //ESP_ROM_HAS_LP_ROM } ulp_lp_core_cfg_t; From 429eb0952c41bc860430085f600525799cfec0c8 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Sun, 28 Apr 2024 11:17:32 +0800 Subject: [PATCH 322/548] fix(ble/bluedroid): Fixed BLE report event when connection fails --- .../bt/host/bluedroid/stack/btm/btm_ble.c | 40 ++++++++++++------- .../bt/host/bluedroid/stack/btu/btu_hcif.c | 3 ++ 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c index 334001fe7b9..0d1e8fd6268 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble.c @@ -217,7 +217,7 @@ void BTM_BleLoadLocalKeys(UINT8 key_type, tBTM_BLE_LOCAL_KEYS *p_key) break; default: - BTM_TRACE_ERROR("unknow local key type: %d", key_type); + BTM_TRACE_ERROR("unknown local key type: %d", key_type); break; } } @@ -694,7 +694,7 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR BTM_TRACE_DEBUG ("btm_find_dev_type - unknown device, BR/EDR assumed"); } } - } else { /* there is a security device record exisitng */ + } else { /* there is a security device record existing */ /* new inquiry result, overwrite device type in security device record */ if (p_inq_info) { p_dev_rec->device_type = p_inq_info->results.device_type; @@ -707,7 +707,7 @@ void BTM_ReadDevInfo (BD_ADDR remote_bda, tBT_DEVICE_TYPE *p_dev_type, tBLE_ADDR } else if (memcmp(p_dev_rec->ble.pseudo_addr, remote_bda, BD_ADDR_LEN) == 0) { *p_dev_type = BT_DEVICE_TYPE_BLE; *p_addr_type = p_dev_rec->ble.ble_addr_type; - } else { /* matching static adddress only */ + } else { /* matching static address only */ *p_dev_type = BT_DEVICE_TYPE_BREDR; *p_addr_type = BLE_ADDR_PUBLIC; } @@ -1061,7 +1061,7 @@ tBTM_SEC_ACTION btm_ble_determine_security_act(BOOLEAN is_originator, BD_ADDR bd ** LE link for LE COC. ** ** Parameter bdaddr: remote device address. -** psm : PSM of the LE COC sevice. +** psm : PSM of the LE COC service. ** is_originator: TRUE if outgoing connection. ** p_callback : Pointer to the callback function. ** p_ref_data : Pointer to be returned along with the callback. @@ -1078,7 +1078,7 @@ BOOLEAN btm_ble_start_sec_check(BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_originat /* If there is no application registered with this PSM do not allow connection */ if (!p_serv_rec) { - BTM_TRACE_WARNING ("%s PSM: %d no application registerd", __func__, psm); + BTM_TRACE_WARNING ("%s PSM: %d no application registered", __func__, psm); (*p_callback) (bd_addr, BT_TRANSPORT_LE, p_ref_data, BTM_MODE_UNSUPPORTED); return FALSE; } @@ -1151,7 +1151,7 @@ void btm_ble_rand_enc_complete (UINT8 *p, UINT16 op_code, tBTM_RAND_ENC_CB *p_en /* If there was a callback address for vcs complete, call it */ if (p_enc_cplt_cback && p) { - /* Pass paramters to the callback function */ + /* Pass parameters to the callback function */ STREAM_TO_UINT8(params.status, p); /* command status */ if (params.status == HCI_SUCCESS) { @@ -1208,7 +1208,7 @@ void btm_ble_increment_sign_ctr(BD_ADDR bd_addr, BOOLEAN is_local ) ** Function btm_ble_get_enc_key_type ** ** Description This function is to get the BLE key type that has been exchanged -** in betweem local device and peer device. +** in between local device and peer device. ** ** Returns p_key_type: output parameter to carry the key type value. ** @@ -1235,7 +1235,7 @@ BOOLEAN btm_ble_get_enc_key_type(BD_ADDR bd_addr, UINT8 *p_key_types) ** ** Description This function is called to read the local DIV ** -** Returns TRUE - if a valid DIV is availavle +** Returns TRUE - if a valid DIV is available *******************************************************************************/ BOOLEAN btm_get_local_div (BD_ADDR bd_addr, UINT16 *p_div) { @@ -1487,7 +1487,7 @@ void btm_ble_link_sec_check(BD_ADDR bd_addr, tBTM_LE_AUTH_REQ auth_req, tBTM_BLE BTM_TRACE_DEBUG ("dev_rec sec_flags=0x%x", p_dev_rec->sec_flags); - /* currently encrpted */ + /* currently encrypted */ if (p_dev_rec->sec_flags & BTM_SEC_LE_ENCRYPTED) { if (p_dev_rec->sec_flags & BTM_SEC_LE_AUTHENTICATED) { cur_sec_level = BTM_LE_SEC_AUTHENTICATED; @@ -1691,7 +1691,7 @@ tBTM_STATUS btm_ble_start_encrypt(BD_ADDR bda, BOOLEAN use_stk, BT_OCTET16 stk) ** ** Function btm_ble_link_encrypted ** -** Description This function is called when LE link encrption status is changed. +** Description This function is called when LE link encryption status is changed. ** ** Returns void ** @@ -1949,7 +1949,7 @@ static void btm_ble_resolve_random_addr_on_conn_cmpl(void *p_rec, void *p_data) ** Function btm_ble_connected ** ** Description This function is when a LE connection to the peer device is -** establsihed +** established ** ** Returns void ** @@ -2060,7 +2060,7 @@ void btm_ble_conn_complete(UINT8 *p, UINT16 evt_len, BOOLEAN enhanced) peer_addr_type = bda_type; match = btm_identity_addr_to_random_pseudo (bda, &bda_type, FALSE); - /* possiblly receive connection complete with resolvable random on + /* possibly receive connection complete with resolvable random on slave role while the device has been paired */ /* It will cause that scanner doesn't send scan request to advertiser @@ -2143,6 +2143,16 @@ void btm_ble_create_ll_conn_complete (UINT8 status) if (status != HCI_SUCCESS) { btm_ble_set_conn_st(BLE_CONN_IDLE); btm_ble_update_mode_operation(HCI_ROLE_UNKNOWN, NULL, status); + if(l2cb.is_ble_connecting) { + /* see L2CA_CancelBleConnectReq() */ + tL2C_LCB *p_lcb = l2cu_find_lcb_by_bd_addr(l2cb.ble_connecting_bda, BT_TRANSPORT_LE); + /* Do not remove lcb if an LE link is already up as a peripheral */ + if (p_lcb != NULL && + !(p_lcb->link_role == HCI_ROLE_SLAVE && BTM_ACL_IS_CONNECTED(l2cb.ble_connecting_bda))) { + p_lcb->disc_reason = L2CAP_CONN_CANCEL; + l2cu_release_lcb (p_lcb); + } + } } } @@ -2300,7 +2310,7 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) ** Function BTM_BleDataSignature ** ** Description This function is called to sign the data using AES128 CMAC -** algorith. +** algorithm. ** ** Parameter bd_addr: target device the data to be signed for. ** p_text: singing data @@ -2308,7 +2318,7 @@ UINT8 btm_proc_smp_cback(tSMP_EVT event, BD_ADDR bd_addr, tSMP_EVT_DATA *p_data) ** signature: output parameter where data signature is going to ** be stored. ** -** Returns TRUE if signing sucessul, otherwise FALSE. +** Returns TRUE if signing successful, otherwise FALSE. ** *******************************************************************************/ #if (SMP_INCLUDED == TRUE) @@ -2491,7 +2501,7 @@ BOOLEAN BTM_BleSecurityProcedureIsRunning(BD_ADDR bd_addr) ** Function BTM_BleGetSupportedKeySize ** ** Description This function gets the maximum encryption key size in bytes -** the local device can suport. +** the local device can support. ** record. ** ** Returns the key size or 0 if the size can't be retrieved. diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 30e76125373..9da6b9d7a92 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1379,6 +1379,9 @@ static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_c break; #if BLE_INCLUDED == TRUE +#if (BLE_50_FEATURE_SUPPORT == TRUE) + case HCI_BLE_EXT_CREATE_CONN: +#endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) case HCI_BLE_CREATE_LL_CONN: btm_ble_create_ll_conn_complete(status); break; From fdb0dd23ca4d89910f23246eadf31cd6d6d272e9 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 15 May 2024 18:02:23 +0800 Subject: [PATCH 323/548] feat(esp_hw_support): support LP_Peripheral & CNNT power domain auto powerdown on esp32p4eco1 --- components/esp_hw_support/include/esp_sleep.h | 3 +++ components/esp_hw_support/sleep_modes.c | 14 ++++++++++++++ .../soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + 4 files changed, 22 insertions(+) diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 61579a8e4a5..ec282ab59fc 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -83,6 +83,9 @@ typedef enum { #endif #if SOC_PM_SUPPORT_TOP_PD ESP_PD_DOMAIN_TOP, //!< SoC TOP +#endif +#if SOC_PM_SUPPORT_CNNT_PD + ESP_PD_DOMAIN_CNNT, //!< Hight-speed connect peripherals power domain #endif ESP_PD_DOMAIN_MAX //!< Number of domains } esp_sleep_pd_domain_t; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 12d12fbef3d..faab42aaf3f 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -26,7 +26,9 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "soc/soc_caps.h" +#include "soc/chip_revision.h" #include "driver/rtc_io.h" +#include "hal/efuse_hal.h" #include "hal/rtc_io_hal.h" #include "hal/clk_tree_hal.h" @@ -862,6 +864,12 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH; } } +#elif CONFIG_IDF_TARGET_ESP32P4 + /* Due to esp32p4 eco0 hardware bug, if LP peripheral power domain is powerdowned in sleep, there will be a possibility of + triggering the EFUSE_CRC reset, so disable the power-down of this power domain on lightsleep for ECO0 version. */ + if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) { + pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH; + } #endif uint32_t reject_triggers = allow_sleep_rejection ? (s_config.wakeup_triggers & RTC_SLEEP_REJECT_MASK) : 0; @@ -2275,6 +2283,12 @@ static uint32_t get_power_down_flags(void) } #endif +#if SOC_PM_SUPPORT_CNNT_PD + if (s_config.domain[ESP_PD_DOMAIN_CNNT].pd_option != ESP_PD_OPTION_ON) { + pd_flags |= PMU_SLEEP_PD_CNNT; + } +#endif + #if SOC_PM_SUPPORT_VDDSDIO_PD if (s_config.domain[ESP_PD_DOMAIN_VDDSDIO].pd_option != ESP_PD_OPTION_ON) { pd_flags |= RTC_SLEEP_PD_VDDSDIO; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bd69a4b750f..f42632d595b 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1567,6 +1567,10 @@ config SOC_PM_SUPPORT_CNNT_PD bool default y +config SOC_PM_SUPPORT_RTC_PERIPH_PD + bool + default y + config SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 3072daf2ee9..e9be2e14ba0 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -620,6 +620,7 @@ #define SOC_PM_SUPPORT_VDDSDIO_PD (1) #define SOC_PM_SUPPORT_TOP_PD (1) #define SOC_PM_SUPPORT_CNNT_PD (1) +#define SOC_PM_SUPPORT_RTC_PERIPH_PD (1) #define SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY (1) /*! Date: Wed, 15 May 2024 19:18:50 +0800 Subject: [PATCH 324/548] feat(esp_hw_support): bypass rst_reason override for esp32p4eco1 --- components/esp_system/port/soc/esp32p4/reset_reason.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/soc/esp32p4/reset_reason.c b/components/esp_system/port/soc/esp32p4/reset_reason.c index afcb6184df1..b9cea8ddfee 100644 --- a/components/esp_system/port/soc/esp32p4/reset_reason.c +++ b/components/esp_system/port/soc/esp32p4/reset_reason.c @@ -8,6 +8,8 @@ #include "esp_rom_sys.h" #include "esp_private/system_internal.h" #include "soc/rtc_periph.h" +#include "soc/chip_revision.h" +#include "hal/efuse_hal.h" #include "esp32p4/rom/rtc.h" static void esp_reset_reason_clear_hint(void); @@ -57,7 +59,9 @@ static esp_reset_reason_t get_reset_reason(soc_reset_reason_t rtc_reset_reason, case RESET_REASON_CORE_EFUSE_CRC: #if CONFIG_IDF_TARGET_ESP32P4 - return ESP_RST_DEEPSLEEP; // TODO: IDF-9564 + if (!ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 1)) { + return ESP_RST_DEEPSLEEP; + } #endif return ESP_RST_EFUSE; From 6e1d59870369b334c4b4e1ccd970254080fb4d68 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 16 May 2024 17:54:07 +0800 Subject: [PATCH 325/548] fix(esp_hw_support): reset smp core state if the sleep request is rejected by hardware --- .../lowpower/cpu_retention/port/esp32p4/sleep_cpu.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c index fcc7e927673..e7756703bc1 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu.c @@ -528,8 +528,9 @@ static TCM_IRAM_ATTR void smp_core_do_retention(void) // Wait another core start to do retention bool smp_skip_retention = false; + smp_retention_state_t another_core_state; while (1) { - smp_retention_state_t another_core_state = atomic_load(&s_smp_retention_state[!core_id]); + another_core_state = atomic_load(&s_smp_retention_state[!core_id]); if (another_core_state == SMP_SKIP_RETENTION) { // If another core skips the retention, the current core should also have to skip it. smp_skip_retention = true; @@ -548,9 +549,12 @@ static TCM_IRAM_ATTR void smp_core_do_retention(void) if ((frame_critical->pmufunc & 0x3) == 0x1) { atomic_store(&s_smp_retention_state[core_id], SMP_BACKUP_DONE); // wait another core trigger sleep and wakeup - esp_cpu_wait_for_intr(); while (1) { - ; + // If another core's sleep request is rejected by the hardware, jumps out of blocking. + another_core_state = atomic_load(&s_smp_retention_state[!core_id]); + if (another_core_state == SMP_SKIP_RETENTION) { + break; + } } } else { // Start core1 From 029126957313a2bd19106c49abe88e61269ce997 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 26 Jun 2024 18:04:36 +0800 Subject: [PATCH 326/548] fix(esp_hw_support): wait eFuse controller idle after sleep wakeup --- .../esp_hw_support/port/esp32c5/pmu_sleep.c | 5 +++++ .../esp_hw_support/port/esp32c6/pmu_sleep.c | 4 ++++ .../esp_hw_support/port/esp32p4/pmu_sleep.c | 3 +++ components/hal/esp32c5/include/hal/efuse_ll.h | 14 ++++++++++++++ components/hal/esp32c6/include/hal/efuse_ll.h | 16 +++++++++++++++- components/hal/esp32p4/include/hal/efuse_ll.h | 14 ++++++++++++++ 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index 262ce0086e6..7b6cce72932 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -14,6 +14,7 @@ #include "soc/soc.h" #include "soc/rtc.h" #include "soc/pmu_struct.h" +#include "hal/efuse_hal.h" #include "hal/lp_aon_hal.h" #include "esp_private/esp_pmu.h" #include "pmu_param.h" @@ -280,6 +281,10 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp bool pmu_sleep_finish(bool dslp) { (void)dslp; + + // Wait eFuse memory update done. + while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); + return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index b6c11b8632e..a50e7bec68a 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -347,6 +347,10 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp bool pmu_sleep_finish(bool dslp) { (void)dslp; + + // Wait eFuse memory update done. + while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); + return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 0b3d5cbaf28..1f86803d493 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -333,6 +333,9 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) pmu_sleep_shutdown_ldo(); } + // Wait eFuse memory update done. + while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); + unsigned chip_version = efuse_hal_chip_revision(); if (!ESP_CHIP_REV_ABOVE(chip_version, 1)) { REGI2C_WRITE_MASK(I2C_CPLL, I2C_CPLL_OC_DIV_7_0, 6); // lower default cpu_pll freq to 400M diff --git a/components/hal/esp32c5/include/hal/efuse_ll.h b/components/hal/esp32c5/include/hal/efuse_ll.h index 8e283d1a7a0..414b241bd3a 100644 --- a/components/hal/esp32c5/include/hal/efuse_ll.h +++ b/components/hal/esp32c5/include/hal/efuse_ll.h @@ -18,6 +18,15 @@ extern "C" { #endif +typedef enum { + EFUSE_CONTROLLER_STATE_RESET = 0, ///< efuse_controllerid is on reset state. + EFUSE_CONTROLLER_STATE_IDLE = 1, ///< efuse_controllerid is on idle state. + EFUSE_CONTROLLER_STATE_READ_INIT = 2, ///< efuse_controllerid is on read init state. + EFUSE_CONTROLLER_STATE_READ_BLK0 = 3, ///< efuse_controllerid is on reading block0 state. + EFUSE_CONTROLLER_STATE_BLK0_CRC_CHECK = 4, ///< efuse_controllerid is on checking block0 crc state. + EFUSE_CONTROLLER_STATE_READ_RS_BLK = 5, ///< efuse_controllerid is on reading RS block state. +} efuse_controller_state_t; + // Always inline these functions even no gcc optimization is applied. /******************* eFuse fields *************************/ @@ -134,6 +143,11 @@ __attribute__((always_inline)) static inline void efuse_ll_rs_bypass_update(void /******************* eFuse control functions *************************/ +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_controller_state(void) +{ + return EFUSE.status.state; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/efuse_ll.h b/components/hal/esp32c6/include/hal/efuse_ll.h index fc687bc9dec..c7d5f4a0bbc 100644 --- a/components/hal/esp32c6/include/hal/efuse_ll.h +++ b/components/hal/esp32c6/include/hal/efuse_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -16,6 +16,15 @@ extern "C" { #endif +typedef enum { + EFUSE_CONTROLLER_STATE_RESET = 0, ///< efuse_controllerid is on reset state. + EFUSE_CONTROLLER_STATE_IDLE = 1, ///< efuse_controllerid is on idle state. + EFUSE_CONTROLLER_STATE_READ_INIT = 2, ///< efuse_controllerid is on read init state. + EFUSE_CONTROLLER_STATE_READ_BLK0 = 3, ///< efuse_controllerid is on reading block0 state. + EFUSE_CONTROLLER_STATE_BLK0_CRC_CHECK = 4, ///< efuse_controllerid is on checking block0 crc state. + EFUSE_CONTROLLER_STATE_READ_RS_BLK = 5, ///< efuse_controllerid is on reading RS block state. +} efuse_controller_state_t; + // Always inline these functions even no gcc optimization is applied. /******************* eFuse fields *************************/ @@ -175,6 +184,11 @@ __attribute__((always_inline)) static inline void efuse_ll_set_pwr_off_num(uint1 EFUSE.wr_tim_conf2.pwr_off_num = value; } +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_controller_state(void) +{ + return EFUSE.status.state; +} + /******************* eFuse control functions *************************/ #ifdef __cplusplus diff --git a/components/hal/esp32p4/include/hal/efuse_ll.h b/components/hal/esp32p4/include/hal/efuse_ll.h index 3032dd041b8..c287b964dc6 100644 --- a/components/hal/esp32p4/include/hal/efuse_ll.h +++ b/components/hal/esp32p4/include/hal/efuse_ll.h @@ -16,6 +16,15 @@ extern "C" { #endif +typedef enum { + EFUSE_CONTROLLER_STATE_RESET = 0, ///< efuse_controllerid is on reset state. + EFUSE_CONTROLLER_STATE_IDLE = 1, ///< efuse_controllerid is on idle state. + EFUSE_CONTROLLER_STATE_READ_INIT = 2, ///< efuse_controllerid is on read init state. + EFUSE_CONTROLLER_STATE_READ_BLK0 = 3, ///< efuse_controllerid is on reading block0 state. + EFUSE_CONTROLLER_STATE_BLK0_CRC_CHECK = 4, ///< efuse_controllerid is on checking block0 crc state. + EFUSE_CONTROLLER_STATE_READ_RS_BLK = 5, ///< efuse_controllerid is on reading RS block state. +} efuse_controller_state_t; + // Always inline these functions even no gcc optimization is applied. /******************* eFuse fields *************************/ @@ -130,6 +139,11 @@ __attribute__((always_inline)) static inline void efuse_ll_rs_bypass_update(void EFUSE.wr_tim_conf0_rs_bypass.update = 1; } +__attribute__((always_inline)) static inline uint32_t efuse_ll_get_controller_state(void) +{ + return EFUSE.status.state; +} + /******************* eFuse control functions *************************/ #ifdef __cplusplus From f3a5160e2cd0031d843b9859e3ec26bc563d590e Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 25 Jun 2024 19:26:50 +0800 Subject: [PATCH 327/548] ci(qemu): increase timeout for esp_intr_dump test --- .../system/esp_intr_dump/pytest_esp_intr_dump.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/test_apps/system/esp_intr_dump/pytest_esp_intr_dump.py b/tools/test_apps/system/esp_intr_dump/pytest_esp_intr_dump.py index b4cfd0acf44..9beab789844 100644 --- a/tools/test_apps/system/esp_intr_dump/pytest_esp_intr_dump.py +++ b/tools/test_apps/system/esp_intr_dump/pytest_esp_intr_dump.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import os @@ -12,7 +12,7 @@ @pytest.mark.qemu @pytest.mark.host_test def test_esp_intr_dump_nonshared(dut: Dut) -> None: - dut.expect_exact(PROMPT, timeout=10) + dut.expect_exact(PROMPT, timeout=30) dut.write('intr_alloc GPIO LEVEL3\n') dut.expect_exact('Allocated GPIO LEVEL3') @@ -26,7 +26,7 @@ def test_esp_intr_dump_nonshared(dut: Dut) -> None: @pytest.mark.qemu @pytest.mark.host_test def test_esp_intr_dump_shared(dut: Dut) -> None: - dut.expect_exact(PROMPT, timeout=10) + dut.expect_exact(PROMPT, timeout=30) dut.write('intr_alloc GPIO SHARED\n') dut.expect_exact('Allocated GPIO SHARED') @@ -50,7 +50,7 @@ def test_esp_intr_dump_shared(dut: Dut) -> None: @pytest.mark.supported_targets @pytest.mark.generic def test_esp_intr_dump_expected_output(dut: Dut) -> None: - dut.expect_exact(PROMPT, timeout=10) + dut.expect_exact(PROMPT, timeout=30) dut.write('intr_dump\n') exp_out_file = os.path.join(os.path.dirname(__file__), 'expected_output', f'{dut.target}.txt') for line in open(exp_out_file, 'r').readlines(): From 9417e857a883e3d9ed1458a37101f03b7ead9506 Mon Sep 17 00:00:00 2001 From: liuning Date: Tue, 25 Jun 2024 15:34:34 +0800 Subject: [PATCH 328/548] fix(coex): fix ESP32 Wi-Fi cant tx after sw_reset with BLE scan Closes https://github.com/espressif/esp-idf/issues/13598 --- components/esp_coex/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_coex/lib b/components/esp_coex/lib index 2363239dded..56d324c3fe3 160000 --- a/components/esp_coex/lib +++ b/components/esp_coex/lib @@ -1 +1 @@ -Subproject commit 2363239ddeda69523a4ed79e55815be21115200f +Subproject commit 56d324c3fe3fb7649f8736bbb3b9f00b7f612449 From f910f13de9f6a62c5112152f751b342428c61402 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Wed, 19 Jun 2024 10:09:40 +0200 Subject: [PATCH 329/548] feat(lp-spi): Added support for LP SPI driver to the LP Core on esp32p4 This commit adds LP SPI master and LP SPI slave support for the LP Core on the esp32p4. --- .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 + .../soc/esp32p4/include/soc/lp_spi_struct.h | 265 +-------------- components/soc/esp32p4/include/soc/soc_caps.h | 5 + components/ulp/CMakeLists.txt | 4 + components/ulp/cmake/CMakeLists.txt | 3 +- components/ulp/lp_core/include/lp_core_spi.h | 109 +++++++ .../lp_core/lp_core/include/ulp_lp_core_spi.h | 65 ++++ components/ulp/lp_core/lp_core/lp_core_spi.c | 262 +++++++++++++++ components/ulp/lp_core/lp_core_spi.c | 306 ++++++++++++++++++ docs/component_info_ignore_file.txt | 1 + docs/doxygen/Doxyfile_esp32p4 | 2 + docs/en/api-reference/system/ulp-lp-core.rst | 9 + .../api-reference/system/ulp-lp-core.rst | 12 + 13 files changed, 802 insertions(+), 253 deletions(-) create mode 100644 components/ulp/lp_core/include/lp_core_spi.h create mode 100644 components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h create mode 100644 components/ulp/lp_core/lp_core/lp_core_spi.c create mode 100644 components/ulp/lp_core/lp_core_spi.c diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bd69a4b750f..2471c52f275 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -239,6 +239,10 @@ config SOC_LP_I2C_SUPPORTED bool default y +config SOC_LP_SPI_SUPPORTED + bool + default y + config SOC_SPIRAM_SUPPORTED bool default y @@ -1243,6 +1247,14 @@ config SOC_SPI_MAX_PRE_DIVIDER int default 16 +config SOC_LP_SPI_PERIPH_NUM + bool + default y + +config SOC_LP_SPI_MAXIMUM_BUFFER_SIZE + int + default 64 + config SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE bool default y diff --git a/components/soc/esp32p4/include/soc/lp_spi_struct.h b/components/soc/esp32p4/include/soc/lp_spi_struct.h index b30c8192e11..8d052bf2971 100644 --- a/components/soc/esp32p4/include/soc/lp_spi_struct.h +++ b/components/soc/esp32p4/include/soc/lp_spi_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -116,7 +116,7 @@ typedef union { uint32_t reg_clkdiv_pre:4; uint32_t reserved_22:9; /** reg_clk_equ_sysclk : R/W; bitpos: [31]; default: 1; - * In the master mode 1: spi_clk is eqaul to system 0: spi_clk is divided from system + * In the master mode 1: spi_clk is equal to system 0: spi_clk is divided from system * clock. Can be configured in CONF state. */ uint32_t reg_clk_equ_sysclk:1; @@ -813,244 +813,19 @@ typedef union { } lp_spi_sleep_conf1_reg_t; -/** Group: LP SPI W0 REG */ -/** Type of spi_w0 register - * SPI CPU-controlled buffer0 +/** Group: LP SPI Wn REG */ +/** Type of spi_wn register + * SPI CPU-controlled buffer */ typedef union { struct { - /** reg_buf0 : R/W/SS; bitpos: [31:0]; default: 0; + /** reg_buf : R/W/SS; bitpos: [31:0]; default: 0; * data buffer */ - uint32_t reg_buf0:32; + uint32_t reg_buf:32; }; uint32_t val; -} lp_spi_w0_reg_t; - - -/** Group: LP SPI W1 REG */ -/** Type of spi_w1 register - * SPI CPU-controlled buffer1 - */ -typedef union { - struct { - /** reg_buf1 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf1:32; - }; - uint32_t val; -} lp_spi_w1_reg_t; - - -/** Group: LP SPI W2 REG */ -/** Type of spi_w2 register - * SPI CPU-controlled buffer2 - */ -typedef union { - struct { - /** reg_buf2 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf2:32; - }; - uint32_t val; -} lp_spi_w2_reg_t; - - -/** Group: LP SPI W3 REG */ -/** Type of spi_w3 register - * SPI CPU-controlled buffer3 - */ -typedef union { - struct { - /** reg_buf3 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf3:32; - }; - uint32_t val; -} lp_spi_w3_reg_t; - - -/** Group: LP SPI W4 REG */ -/** Type of spi_w4 register - * SPI CPU-controlled buffer4 - */ -typedef union { - struct { - /** reg_buf4 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf4:32; - }; - uint32_t val; -} lp_spi_w4_reg_t; - - -/** Group: LP SPI W5 REG */ -/** Type of spi_w5 register - * SPI CPU-controlled buffer5 - */ -typedef union { - struct { - /** reg_buf5 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf5:32; - }; - uint32_t val; -} lp_spi_w5_reg_t; - - -/** Group: LP SPI W6 REG */ -/** Type of spi_w6 register - * SPI CPU-controlled buffer6 - */ -typedef union { - struct { - /** reg_buf6 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf6:32; - }; - uint32_t val; -} lp_spi_w6_reg_t; - - -/** Group: LP SPI W7 REG */ -/** Type of spi_w7 register - * SPI CPU-controlled buffer7 - */ -typedef union { - struct { - /** reg_buf7 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf7:32; - }; - uint32_t val; -} lp_spi_w7_reg_t; - - -/** Group: LP SPI W8 REG */ -/** Type of spi_w8 register - * SPI CPU-controlled buffer8 - */ -typedef union { - struct { - /** reg_buf8 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf8:32; - }; - uint32_t val; -} lp_spi_w8_reg_t; - - -/** Group: LP SPI W9 REG */ -/** Type of spi_w9 register - * SPI CPU-controlled buffer9 - */ -typedef union { - struct { - /** reg_buf9 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf9:32; - }; - uint32_t val; -} lp_spi_w9_reg_t; - - -/** Group: LP SPI W10 REG */ -/** Type of spi_w10 register - * SPI CPU-controlled buffer10 - */ -typedef union { - struct { - /** reg_buf10 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf10:32; - }; - uint32_t val; -} lp_spi_w10_reg_t; - - -/** Group: LP SPI W11 REG */ -/** Type of spi_w11 register - * SPI CPU-controlled buffer11 - */ -typedef union { - struct { - /** reg_buf11 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf11:32; - }; - uint32_t val; -} lp_spi_w11_reg_t; - - -/** Group: LP SPI W12 REG */ -/** Type of spi_w12 register - * SPI CPU-controlled buffer12 - */ -typedef union { - struct { - /** reg_buf12 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf12:32; - }; - uint32_t val; -} lp_spi_w12_reg_t; - - -/** Group: LP SPI W13 REG */ -/** Type of spi_w13 register - * SPI CPU-controlled buffer13 - */ -typedef union { - struct { - /** reg_buf13 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf13:32; - }; - uint32_t val; -} lp_spi_w13_reg_t; - - -/** Group: LP SPI W14 REG */ -/** Type of spi_w14 register - * SPI CPU-controlled buffer14 - */ -typedef union { - struct { - /** reg_buf14 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf14:32; - }; - uint32_t val; -} lp_spi_w14_reg_t; - - -/** Group: LP SPI W15 REG */ -/** Type of spi_w15 register - * SPI CPU-controlled buffer15 - */ -typedef union { - struct { - /** reg_buf15 : R/W/SS; bitpos: [31:0]; default: 0; - * data buffer - */ - uint32_t reg_buf15:32; - }; - uint32_t val; -} lp_spi_w15_reg_t; +} lp_spi_wn_reg_t; /** Group: LP SPI SLAVE REG */ @@ -1062,7 +837,7 @@ typedef union { /** reg_clk_mode : R/W; bitpos: [1:0]; default: 0; * SPI clock mode bits. 0: SPI clock is off when CS inactive 1: SPI clock is delayed * one cycle after CS inactive 2: SPI clock is delayed two cycles after CS inactive 3: - * SPI clock is alwasy on. Can be configured in CONF state. + * SPI clock is always on. Can be configured in CONF state. */ uint32_t reg_clk_mode:2; /** reg_clk_mode_13 : R/W; bitpos: [2]; default: 0; @@ -1238,22 +1013,7 @@ typedef struct { volatile lp_spi_sleep_conf1_reg_t spi_sleep_conf1; volatile lp_spi_dma_int_set_reg_t spi_dma_int_set; uint32_t reserved_050[18]; - volatile lp_spi_w0_reg_t spi_w0; - volatile lp_spi_w1_reg_t spi_w1; - volatile lp_spi_w2_reg_t spi_w2; - volatile lp_spi_w3_reg_t spi_w3; - volatile lp_spi_w4_reg_t spi_w4; - volatile lp_spi_w5_reg_t spi_w5; - volatile lp_spi_w6_reg_t spi_w6; - volatile lp_spi_w7_reg_t spi_w7; - volatile lp_spi_w8_reg_t spi_w8; - volatile lp_spi_w9_reg_t spi_w9; - volatile lp_spi_w10_reg_t spi_w10; - volatile lp_spi_w11_reg_t spi_w11; - volatile lp_spi_w12_reg_t spi_w12; - volatile lp_spi_w13_reg_t spi_w13; - volatile lp_spi_w14_reg_t spi_w14; - volatile lp_spi_w15_reg_t spi_w15; + volatile lp_spi_wn_reg_t data_buf[16]; uint32_t reserved_0d8[2]; volatile lp_spi_slave_reg_t spi_slave; volatile lp_spi_slave1_reg_t spi_slave1; @@ -1263,11 +1023,12 @@ typedef struct { volatile lp_rnd_eco_cs_reg_t rnd_eco_cs; volatile lp_rnd_eco_low_reg_t rnd_eco_low; volatile lp_rnd_eco_high_reg_t rnd_eco_high; -} lp_dev_t; +} lp_spi_dev_t; +extern lp_spi_dev_t LP_SPI; #ifndef __cplusplus -_Static_assert(sizeof(lp_dev_t) == 0x100, "Invalid size of lp_dev_t structure"); +_Static_assert(sizeof(lp_spi_dev_t) == 0x100, "Invalid size of lp_dev_t structure"); #endif #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 3072daf2ee9..e9d9435d704 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -78,6 +78,7 @@ #define SOC_LP_GPIO_MATRIX_SUPPORTED 1 #define SOC_LP_PERIPHERALS_SUPPORTED 1 #define SOC_LP_I2C_SUPPORTED 1 +#define SOC_LP_SPI_SUPPORTED 1 #define SOC_SPIRAM_SUPPORTED 1 #define SOC_PSRAM_DMA_CAPABLE 1 // #define SOC_ULP_SUPPORTED 1 //TODO: IDF-7534 @@ -498,6 +499,10 @@ #define SOC_MEMSPI_IS_INDEPENDENT 1 #define SOC_SPI_MAX_PRE_DIVIDER 16 +/*-------------------------- LP SPI CAPS ----------------------------------------*/ +#define SOC_LP_SPI_PERIPH_NUM 1 +#define SOC_LP_SPI_MAXIMUM_BUFFER_SIZE 64 + /*-------------------------- SPI MEM CAPS ---------------------------------------*/ #define SOC_SPI_MEM_SUPPORT_AUTO_WAIT_IDLE (1) //#define SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND (1) //TODO: IDF-7518 diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index ec5571d9c65..dd159c8a60d 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -65,6 +65,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE) if(CONFIG_SOC_LP_TIMER_SUPPORTED) list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_timer_shared.c") endif() + + if(CONFIG_SOC_LP_SPI_SUPPORTED) + list(APPEND srcs "lp_core/lp_core_spi.c") + endif() endif() idf_component_register(SRCS ${srcs} diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 05bddaa68d1..97b8d2eccce 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -114,7 +114,8 @@ elseif(ULP_COCPU_IS_LP_CORE) "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_panic.c" "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c" - "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c") + "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c" + "${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c") target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles") target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments") diff --git a/components/ulp/lp_core/include/lp_core_spi.h b/components/ulp/lp_core/include/lp_core_spi.h new file mode 100644 index 00000000000..f2f0ea9f036 --- /dev/null +++ b/components/ulp/lp_core/include/lp_core_spi.h @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LP SPI peripheral + * Since we have just one LP SPI peripheral, we can define it as a uint32_t type for now, instead of an enum. + */ +typedef uint32_t lp_spi_host_t; + +/** + * @brief LP SPI device configuration flags + */ +#define LP_SPI_DEVICE_TXBIT_LSBFIRST (1<<0) /*!< Transmit command/address/data LSB first instead of the default MSB first */ +#define LP_SPI_DEVICE_RXBIT_LSBFIRST (1<<1) /*!< Receive data LSB first instead of the default MSB first */ +#define LP_SPI_DEVICE_BIT_LSBFIRST (LP_SPI_DEVICE_TXBIT_LSBFIRST|LP_SPI_DEVICE_RXBIT_LSBFIRST) /*!< Transmit and receive LSB first */ +#define LP_SPI_DEVICE_3WIRE (1<<2) /*!< Use MOSI (=spid) for both sending and receiving data */ +#define LP_SPI_DEVICE_CS_ACTIVE_HIGH (1<<3) /*!< Make CS line active-high during a transanction instead of the default active-low state. Only available in SPI master mode. */ +#define LP_SPI_DEVICE_HALF_DUPLEX (1<<4) /*!< Transmit data before receiving it, instead of simultaneously. Only available in SPI master mode. */ + +/** + * @brief LP SPI bus configuration parameters + */ +typedef struct { + int mosi_io_num; /*!< GPIO pin for Master out, Slave In signal, a.k.a, SPI_D. */ + int miso_io_num; /*!< GPIO pin for Master in, Slave Out signal, a.k.a, SPI_Q. */ + int sclk_io_num; /*!< GPIO pin for LP SPI Clock signal. */ +} lp_spi_bus_config_t; + +/** + * @brief LP SPI device configuration parameters + */ +typedef struct { + int cs_io_num; /*!< GPIO pin for the device Chip Select (CS) signal. */ + int clock_speed_hz; /*!< SPI clock speed in Hz. */ + int spi_mode; /*!< SPI mode, representing a pair of Clock Polarity (CPOL) and Clock Phase (CPHA) configuration: + - SPI Mode 0: (0, 0) + - SPI Mode 1: (0, 1) + - SPI Mode 2: (1, 0) + - SPI Mode 3: (1, 1) + */ + int duty_cycle; /*!< Duty cycle of positive SPI clock, in 1/256th increments (128 = 50% duty cycle). Setting this to 0 (=not setting it) is equivalent to setting this to 128. */ + int flags; /*!< Bitwise OR of LP_SPI_DEVICE_* flags */ + int cs_ena_pretrans; /*!< Amount of SPI bit-cycles the CS should be active for, before the transmission (0-16). This only works on half-duplex transactions. */ + int cs_ena_posttrans; /*!< Amount of SPI bit-cycles the CS should stay active for, after the transmission (0-16). This only works on half-duplex transactions. */ +} lp_spi_device_config_t; + +/** + * @brief LP SPI slave configuration parameters + */ +typedef struct { + int cs_io_num; /*!< GPIO pin for the device Chip Select (CS) signal. */ + int spi_mode; /*!< SPI mode, representing a pair of Clock Polarity (CPOL) and Clock Phase (CPHA) configuration: + - SPI Mode 0: (0, 0) + - SPI Mode 1: (0, 1) + - SPI Mode 2: (1, 0) + - SPI Mode 3: (1, 1) + */ + int flags; /*!< Bitwise OR of LP_SPI_DEVICE_* flags */ +} lp_spi_slave_config_t; + +/** + * @brief Initialize the LP SPI bus for use by the LP core + * + * @param host_id LP SPI host number + * @param bus_config LP SPI bus configuration parameters + * + * @return esp_err_t ESP_OK when successful + * ESP_ERR_INVALID_ARG if the configuration is invalid + */ +esp_err_t lp_core_lp_spi_bus_initialize(lp_spi_host_t host_id, const lp_spi_bus_config_t *bus_config); + +/** + * @brief Initialize the LP SPI controller in master mode and add an SPI device to the LP SPI bus. + * + * @param host_id LP SPI host number + * @param dev_config LP SPI device configuration parameters + * + * @return esp_err_t ESP_OK when successful + * ESP_ERR_INVALID_ARG if the configuration is invalid + * ESP_FAIL if the device could not be added + */ +esp_err_t lp_core_lp_spi_bus_add_device(lp_spi_host_t host_id, const lp_spi_device_config_t *dev_config); + +/** + * @brief Initialize the LP SPI controller in slave mode + * + * @param host_id LP SPI host number + * @param slave_config LP SPI slave configuration parameters + * + * @return esp_err_t ESP_OK when successful + * ESP_FAIL if the SPI controller could not be initialized in slave mode + */ +esp_err_t lp_core_lp_spi_slave_initialize(lp_spi_host_t host_id, const lp_spi_slave_config_t *slave_config); + +#ifdef __cplusplus +} +#endif diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h new file mode 100644 index 00000000000..95b97e13200 --- /dev/null +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + +/** + * The LP SPI bus identifier to initiate a transaction on. + */ +typedef uint32_t lp_spi_bus_t; + +/** + * This structure describes one SPI transaction. The descriptor should not be modified until the transaction finishes. + */ +typedef struct { + uint32_t tx_length; /*!< Total data length to transmit in bytes */ + uint32_t rx_length; /*!< Total data length to receive in bytes */ + const void *tx_buffer; /*!< Pointer to the transmit buffer. Must be set for master mode transactions. Can be NULL for slave mode transactions. */ + void *rx_buffer; /*!< Pointer to the receive buffer. Must be set for slave mode transactions. Can be NULL for master mode transactions. */ + lp_spi_bus_t bus; /*!< The LP SPI bus to transmit the data on */ + // The following are only used in master mode transactions + int command; /*!< Command data, of which the length is set in the ``command_bits`` field of this structure. */ + uint32_t address; /*!< Address data, of which the length is set in the ``address_bits`` field of this structure. */ + uint8_t command_bits; /*!< Default amount of bits in command phase */ + uint8_t address_bits; /*!< Default amount of bits in address phase */ + uint8_t dummy_bits; /*!< Amount of dummy bits to insert between address and data phase. */ +} lp_spi_transaction_t; + +/** + * @brief Initiate an LP SPI transaction in master mode to transmit device to an SPI device and optionally receive data + * from the device. + * + * @param trans_desc LP SPI transaction configuration descriptor + * @param ticks_to_wait Operation timeout in CPU cycles. Set to -1 to wait forever. + * + * @return esp_err_t ESP_OK when successful + * ESP_ERR_INVALID_ARG if the configuration is invalid + * ESP_ERR_TIMEOUT when the operation times out + */ +esp_err_t lp_core_lp_spi_master_transfer(lp_spi_transaction_t *trans_desc, int32_t ticks_to_wait); + +/** + * @brief Initiate an LP SPI transaction in slave mode to receive data from an SPI master and optionally transmit data + * back to the master. + * + * @param trans_desc LP SPI transaction configuration descriptor + * @param ticks_to_wait Operation timeout in CPU cycles. Set to -1 to wait forever. + * + * @return esp_err_t ESP_OK when successful + * ESP_ERR_INVALID_ARG if the configuration is invalid + * ESP_ERR_TIMEOUT when the operation times out + */ +esp_err_t lp_core_lp_spi_slave_transfer(lp_spi_transaction_t *trans_desc, int32_t ticks_to_wait); + +#ifdef __cplusplus +} +#endif diff --git a/components/ulp/lp_core/lp_core/lp_core_spi.c b/components/ulp/lp_core/lp_core/lp_core_spi.c new file mode 100644 index 00000000000..9ff1f8a2734 --- /dev/null +++ b/components/ulp/lp_core/lp_core/lp_core_spi.c @@ -0,0 +1,262 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/soc_caps.h" + +#if SOC_LP_SPI_SUPPORTED + +#include +#include +#include "esp_err.h" +#include "ulp_lp_core_spi.h" +#include "soc/lp_spi_struct.h" + +/* Use the register structure to access LP_SPI module registers */ +lp_spi_dev_t *lp_spi_dev = &LP_SPI; + +static inline esp_err_t lp_core_spi_wait_for_interrupt(int32_t ticks_to_wait) +{ + uint32_t to = 0; + while (!lp_spi_dev->spi_dma_int_raw.reg_trans_done_int_raw) { + if (ticks_to_wait > -1) { + /* If the ticks_to_wait value is not -1, keep track of ticks and + * break from the loop once the timeout is reached. + */ + to++; + if (to >= ticks_to_wait) { + /* Clear interrupt bits */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + return ESP_ERR_TIMEOUT; + } + } + } + + return ESP_OK; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// Public APIs /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +esp_err_t lp_core_lp_spi_master_transfer(lp_spi_transaction_t *trans_desc, int32_t ticks_to_wait) +{ + esp_err_t ret = ESP_OK; + + /* Argument sanity check + * Note: The Tx buffer is mandatory for this API. + */ + if (trans_desc == NULL || trans_desc->tx_buffer == NULL || trans_desc->tx_length == 0) { + return ESP_ERR_INVALID_ARG; + } + + /* Reset the Tx and Rx FIFOs */ + lp_spi_dev->spi_dma_conf.reg_rx_afifo_rst = 1; + lp_spi_dev->spi_dma_conf.reg_rx_afifo_rst = 0; + lp_spi_dev->spi_dma_conf.reg_buf_afifo_rst = 1; + lp_spi_dev->spi_dma_conf.reg_buf_afifo_rst = 0; + + /* Clear any previous interrupts. + * Note: LP SPI does not have any DMA access but the interrupt bit lives in the DMA interrupt register. + */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + + /* Make sure that we do not have any ongoing transactions */ + if (lp_spi_dev->spi_cmd.reg_usr) { + return ESP_ERR_INVALID_STATE; + } + + /* Configure dummy bits */ + lp_spi_dev->spi_user.reg_usr_dummy = trans_desc->dummy_bits ? 1 : 0; + if (trans_desc->dummy_bits) { + lp_spi_dev->spi_user1.reg_usr_dummy_cyclelen = trans_desc->dummy_bits - 1; + } + + /* Configure the command and command bit length */ + lp_spi_dev->spi_user.reg_usr_command = trans_desc->command_bits ? 1 : 0; + if (trans_desc->command_bits) { + lp_spi_dev->spi_user2.reg_usr_command_bitlen = trans_desc->command_bits - 1; + lp_spi_dev->spi_user2.reg_usr_command_value = lp_spi_dev->spi_ctrl.reg_wr_bit_order ? trans_desc->command : __builtin_bswap32(trans_desc->command << (32 - trans_desc->command_bits)); + } + + /* Configure the address and address bit length */ + lp_spi_dev->spi_user.reg_usr_addr = trans_desc->address_bits ? 1 : 0; + if (trans_desc->address_bits) { + lp_spi_dev->spi_user1.reg_usr_addr_bitlen = trans_desc->address_bits - 1; + lp_spi_dev->spi_addr.reg_usr_addr_value = lp_spi_dev->spi_ctrl.reg_wr_bit_order ? __builtin_bswap32(trans_desc->address) : trans_desc->address << (32 - trans_desc->address_bits); + } + + /* Set data lines */ + lp_spi_dev->spi_user.reg_usr_mosi = 1; + lp_spi_dev->spi_user.reg_usr_miso = trans_desc->rx_buffer ? 1 : 0; + + /* Configure the transaction bit length */ + int tx_bitlen = trans_desc->tx_length * 8; + lp_spi_dev->spi_ms_dlen.reg_ms_data_bitlen = tx_bitlen - 1; + + /* Prepare the data to be transmitted */ + uint32_t tx_idx = 0; + uint32_t rx_idx = 0; + + /* The TRM suggests that the data is sent from and received in the LP_SPI_W0_REG ~ LP_SPI_W15_REG registers. + * The following rules apply: + * 1. The first 64 bytes are sent from/received in LP_SPI_W0_REG ~ LP_SPI_W15_REG + * 2. Bytes 64 - 255 are repeatedly sent from or received in LP_SPI_W15_REG[31:24] + * 3. Subsequent blocks of 256 bytes of data continue to follow the above rules + * + * This driver, however, avoids using the LP_SPI_W15_REG altogether. In other words, + * this driver sends or receives data in chunks of 60 bytes (LP_SPI_W0_REG ~ LP_SPI_W14_REG) + * and does not handle the repeated use of the high-byte of LP_SPI_W15_REG. This design approach + * has been chosen to simplify the data handling logic. + */ + uint8_t max_data_reg_num = (SOC_LP_SPI_MAXIMUM_BUFFER_SIZE / 4) - 1; // 15 + uint8_t max_data_chunk_size = max_data_reg_num * 4; // 60 + while (tx_idx < trans_desc->tx_length) { + /* Store 4 bytes of data in the data buffer registers serially. */ + lp_spi_dev->data_buf[(tx_idx / 4) & max_data_reg_num].reg_buf = *(uint32_t *)(trans_desc->tx_buffer + tx_idx); + tx_idx += 4; + + /* Begin transmission of the data if we have pushed all the data or if we have reached the maximum data chunk size */ + if ((tx_idx >= trans_desc->tx_length) || (tx_idx % max_data_chunk_size) == 0) { + /* Apply the configuration */ + lp_spi_dev->spi_cmd.reg_update = 1; + while (lp_spi_dev->spi_cmd.reg_update) { + ; + } + + /* Start the transaction */ + lp_spi_dev->spi_cmd.reg_usr = 1; + + /* Wait for the transaction to complete */ + ret = lp_core_spi_wait_for_interrupt(ticks_to_wait); + if (ret != ESP_OK) { + return ret; + } + + /* Clear the transaction done interrupt */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + + /* Fetch the received data if an Rx buffer is provided */ + if (trans_desc->rx_buffer != NULL) { + while (rx_idx < tx_idx) { + *(uint32_t *)(trans_desc->rx_buffer + rx_idx) = lp_spi_dev->data_buf[(rx_idx / 4) & max_data_reg_num].reg_buf; + rx_idx += 4; + // This loop would exit even if we haven't received all the data. + } + } + } + } + + return ret; +} + +esp_err_t lp_core_lp_spi_slave_transfer(lp_spi_transaction_t *trans_desc, int32_t ticks_to_wait) +{ + esp_err_t ret = ESP_OK; + + /* Argument sanity check + * Note: The Rx buffer is mandatory for this API. + */ + if (trans_desc == NULL || trans_desc->rx_buffer == NULL || trans_desc->rx_length == 0) { + return ESP_ERR_INVALID_ARG; + } + + /* Reset the Tx and Rx FIFOs */ + lp_spi_dev->spi_dma_conf.reg_rx_afifo_rst = 1; + lp_spi_dev->spi_dma_conf.reg_rx_afifo_rst = 0; + lp_spi_dev->spi_dma_conf.reg_buf_afifo_rst = 1; + lp_spi_dev->spi_dma_conf.reg_buf_afifo_rst = 0; + + /* Clear any previous interrupts. + * Note: LP SPI does not have any DMA access but the interrupt bit lives in the DMA interrupt register. + */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + + /* Set data lines */ + lp_spi_dev->spi_user.reg_usr_mosi = 1; + lp_spi_dev->spi_user.reg_usr_miso = 1; + + /* Configure the transaction bit length */ + int rx_bitlen = trans_desc->rx_length * 8; + lp_spi_dev->spi_ms_dlen.reg_ms_data_bitlen = rx_bitlen - 1; + + /* Prepare the data to be received */ + uint32_t rx_idx = 0; + uint32_t rcvd_bitlen = 0; + uint32_t rcvd_length_in_bytes = 0; + + /* The LP SPI slave receives data in the LP_SPI_W0_REG ~ LP_SPI_W15_REG registers. + * The following rules apply: + * 1. The first 64 bytes are received in LP_SPI_W0_REG ~ LP_SPI_W15_REG + * 2. The next 64 bytes are overwritten in LP_SPI_W0_REG ~ LP_SPI_W15_REG + * + * Since the peripheral has no protection against overwriting the data, we restrict the + * driver to receive up to 64 bytes of data at a time. + */ + uint32_t length_in_bytes = trans_desc->rx_length; + if (trans_desc->rx_length > SOC_LP_SPI_MAXIMUM_BUFFER_SIZE) { + /* Truncate the length to the maximum buffer size */ + length_in_bytes = SOC_LP_SPI_MAXIMUM_BUFFER_SIZE; + } + + while (rx_idx < length_in_bytes) { + /* Wait for the transmission to complete */ + ret = lp_core_spi_wait_for_interrupt(ticks_to_wait); + if (ret != ESP_OK) { + return ret; + } + + /* Fetch the received bit length */ + rcvd_bitlen = lp_spi_dev->spi_slave1.reg_slv_data_bitlen > (trans_desc->rx_length * 8) ? (trans_desc->rx_length * 8) : lp_spi_dev->spi_slave1.reg_slv_data_bitlen; + rcvd_length_in_bytes = (rcvd_bitlen + 7) / 8; + + /* Read the received data */ + while (rx_idx < rcvd_length_in_bytes) { + *(uint32_t *)(trans_desc->rx_buffer + rx_idx) = lp_spi_dev->data_buf[(rx_idx / 4)].reg_buf; + rx_idx += 4; + } + + /* Clear the transaction done interrupt */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + } + + /* Prepare data for transmission if a Tx buffer is provided */ + if (trans_desc->tx_buffer != NULL) { + uint32_t tx_idx = 0; + uint32_t length_in_bytes = trans_desc->tx_length; + if (length_in_bytes > SOC_LP_SPI_MAXIMUM_BUFFER_SIZE) { + /* Truncate the length to the maximum buffer size */ + length_in_bytes = SOC_LP_SPI_MAXIMUM_BUFFER_SIZE; + } + + while (tx_idx < length_in_bytes) { + /* Store 4 bytes of data in the data buffer registers serially. */ + lp_spi_dev->data_buf[(tx_idx / 4)].reg_buf = *(uint32_t *)(trans_desc->tx_buffer + tx_idx); + tx_idx += 4; + } + + /* Apply the configuration */ + lp_spi_dev->spi_cmd.reg_update = 1; + while (lp_spi_dev->spi_cmd.reg_update) { + ; + } + + /* Start the transaction */ + lp_spi_dev->spi_cmd.reg_usr = 1; + + /* Wait for the transaction to complete */ + ret = lp_core_spi_wait_for_interrupt(ticks_to_wait); + if (ret != ESP_OK) { + return ret; + } + + /* Clear the transaction done interrupt */ + lp_spi_dev->spi_dma_int_clr.reg_trans_done_int_clr = 1; + } + + return ret; +} + +#endif /* SOC_LP_SPI_SUPPORTED */ diff --git a/components/ulp/lp_core/lp_core_spi.c b/components/ulp/lp_core/lp_core_spi.c new file mode 100644 index 00000000000..0def39cc015 --- /dev/null +++ b/components/ulp/lp_core/lp_core_spi.c @@ -0,0 +1,306 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "lp_core_spi.h" +#include "driver/rtc_io.h" +#include "driver/lp_io.h" +#include "hal/rtc_io_types.h" +#include "include/lp_core_spi.h" +#include "soc/lp_spi_struct.h" +#include "soc/lp_gpio_sig_map.h" +#include "soc/lpperi_struct.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/esp_clk_tree_common.h" +#include "hal/spi_ll.h" + +static const char *LP_SPI_TAG = "lp_spi"; + +/* Use the LP SPI register structure to access peripheral registers */ +lp_spi_dev_t *lp_spi_dev = &LP_SPI; + +static esp_err_t lp_spi_config_io(gpio_num_t pin, rtc_gpio_mode_t direction, uint32_t out_pad_idx, uint32_t in_pad_idx) +{ + esp_err_t ret = ESP_OK; + + /* If pin is -1, then it is not connected to any LP_IO */ + if (pin == -1) { + return ESP_OK; + } + + /* Initialize LP_IO */ + ESP_RETURN_ON_ERROR(rtc_gpio_init(pin), LP_SPI_TAG, "LP IO Init failed for GPIO %d", pin); + + /* Set LP_IO direction */ + ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(pin, direction), LP_SPI_TAG, "LP IO Set direction failed for %d", pin); + + /* Connect the LP SPI signals to the LP_IO Matrix */ + ESP_RETURN_ON_ERROR(lp_gpio_connect_out_signal(pin, out_pad_idx, 0, 0), LP_SPI_TAG, "LP IO Matrix connect out signal failed for %d", pin); + ESP_RETURN_ON_ERROR(lp_gpio_connect_in_signal(pin, in_pad_idx, 0), LP_SPI_TAG, "LP IO Matrix connect in signal failed for %d", pin); + + return ret; +} + +static esp_err_t lp_spi_bus_init_io(const lp_spi_bus_config_t *bus_config) +{ + esp_err_t ret = ESP_OK; + + /* Argument sanity check */ +#if SOC_LP_GPIO_MATRIX_SUPPORTED + /* LP SPI signals can be routed to any LP_IO */ + ESP_RETURN_ON_FALSE((rtc_gpio_is_valid_gpio(bus_config->mosi_io_num)), ESP_FAIL, LP_SPI_TAG, "mosi_io_num error"); + ESP_RETURN_ON_FALSE((bus_config->miso_io_num == -1) || (rtc_gpio_is_valid_gpio(bus_config->miso_io_num)), ESP_FAIL, LP_SPI_TAG, "miso_io_num error"); + ESP_RETURN_ON_FALSE((rtc_gpio_is_valid_gpio(bus_config->sclk_io_num)), ESP_FAIL, LP_SPI_TAG, "sclk_io_num error"); + + /* Configure miso pin*/ + ret = lp_spi_config_io(bus_config->miso_io_num, RTC_GPIO_MODE_INPUT_OUTPUT, LP_SPI_Q_PAD_OUT_IDX, LP_SPI_Q_PAD_IN_IDX); + /* Configure mosi pin */ + ret = lp_spi_config_io(bus_config->mosi_io_num, RTC_GPIO_MODE_INPUT_OUTPUT, LP_SPI_D_PAD_OUT_IDX, LP_SPI_D_PAD_IN_IDX); + /* Configure sclk pin */ + ret = lp_spi_config_io(bus_config->sclk_io_num, RTC_GPIO_MODE_INPUT_OUTPUT, LP_SPI_CK_PAD_OUT_IDX, LP_SPI_CK_PAD_IN_IDX); +#else +#error "LP SPI bus initialization is not supported without LP GPIO Matrix." +#endif /* SOC_LP_GPIO_MATRIX_SUPPORTED */ + + return ret; +} + +static esp_err_t lp_spi_cs_pin_init(int cs_io_num) +{ + esp_err_t ret = ESP_OK; + +#if SOC_LP_GPIO_MATRIX_SUPPORTED + /* CS signal can be routed to any LP_IO */ + ESP_RETURN_ON_FALSE((rtc_gpio_is_valid_gpio(cs_io_num)), ESP_FAIL, LP_SPI_TAG, "cs_io_num error"); + + /* Configure CS pin */ + ret = lp_spi_config_io(cs_io_num, RTC_GPIO_MODE_INPUT_OUTPUT, LP_SPI_CS_PAD_OUT_IDX, LP_SPI_CS_PAD_IN_IDX); +#else +#error "LP SPI device Chip Select (CS) initialization is not supported without LP GPIO Matrix." +#endif /* SOC_LP_GPIO_MATRIX_SUPPORTED */ + + return ret; +} + +static void lp_spi_enable_clock_gate(void) +{ + lpperi_dev_t *lp_peri_dev = &LPPERI; + PERIPH_RCC_ATOMIC() { + (void)__DECLARE_RCC_ATOMIC_ENV; // Avoid warnings for unused variable __DECLARE_RCC_ATOMIC_ENV + lp_peri_dev->clk_en.ck_en_lp_spi = 1; + } +} + +static esp_err_t lp_spi_clock_init(const lp_spi_device_config_t *dev_config) +{ + esp_err_t ret = ESP_OK; + + /* Max requested clock frequency cannot be more than the LP_FAST_CLK frequency */ + uint32_t max_clock_source_hz = esp_clk_tree_lp_fast_get_freq_hz(ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX); + ESP_RETURN_ON_FALSE(dev_config->clock_speed_hz <= max_clock_source_hz, ESP_ERR_INVALID_ARG, LP_SPI_TAG, "Invalid clock speed for SPI device. Max allowed = %ld Hz", max_clock_source_hz); + + /* Set the duty cycle. If not specified, use 50% */ + int duty_cycle = dev_config->duty_cycle ? dev_config->duty_cycle : 128; + + /* Calculate the clock pre-div values. We use the HP SPI LL function here for the calculation. */ + spi_ll_clock_val_t spi_clock; + spi_ll_master_cal_clock(max_clock_source_hz, dev_config->clock_speed_hz, duty_cycle, &spi_clock); + lp_spi_dev->spi_clock.val = spi_clock; + + return ret; +} + +static void lp_spi_master_init(void) +{ + /* Initialize the LP SPI in master mode. + * (We do not have a HAL/LL layer for LP SPI, yet, so let's use the LP SPI registers directly). + */ + + /* Clear Slave mode to enable Master mode */ + lp_spi_dev->spi_slave.reg_slave_mode = 0; + lp_spi_dev->spi_slave.reg_clk_mode = 0; + + /* Reset CS timing */ + lp_spi_dev->spi_user1.reg_cs_setup_time = 0; + lp_spi_dev->spi_user1.reg_cs_hold_time = 0; + + /* Use all 64 bytes of the Tx/Rx buffers in CPU controlled transfer */ + lp_spi_dev->spi_user.reg_usr_mosi_highpart = 0; + lp_spi_dev->spi_user.reg_usr_miso_highpart = 0; +} + +static void lp_spi_slave_init(void) +{ + /* Set Slave mode */ + lp_spi_dev->spi_slave.reg_slave_mode = 1; + + /* Reset the SPI peripheral */ + lp_spi_dev->spi_slave.reg_soft_reset = 1; + lp_spi_dev->spi_slave.reg_soft_reset = 0; + + /* Configure slave */ + lp_spi_dev->spi_clock.val = 0; + lp_spi_dev->spi_user.val = 0; + lp_spi_dev->spi_ctrl.val = 0; + lp_spi_dev->spi_user.reg_doutdin = 1; //we only support full duplex + lp_spi_dev->spi_user.reg_sio = 0; + + /* Use all 64 bytes of the Tx/Rx buffers in CPU controlled transfer */ + lp_spi_dev->spi_user.reg_usr_miso_highpart = 0; + lp_spi_dev->spi_user.reg_usr_mosi_highpart = 0; +} + +static void lp_spi_master_setup_device(const lp_spi_device_config_t *dev_config) +{ + /* Configure transmission bit order */ + lp_spi_dev->spi_ctrl.reg_rd_bit_order = dev_config->flags & LP_SPI_DEVICE_RXBIT_LSBFIRST ? 1 : 0; + lp_spi_dev->spi_ctrl.reg_wr_bit_order = dev_config->flags & LP_SPI_DEVICE_TXBIT_LSBFIRST ? 1 : 0; + + /* Configure SPI mode in master mode */ + if (dev_config->spi_mode == 0) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 0; + lp_spi_dev->spi_user.reg_ck_out_edge = 0; + } else if (dev_config->spi_mode == 1) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 0; + lp_spi_dev->spi_user.reg_ck_out_edge = 1; + } else if (dev_config->spi_mode == 2) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 1; + lp_spi_dev->spi_user.reg_ck_out_edge = 1; + } else if (dev_config->spi_mode == 3) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 1; + lp_spi_dev->spi_user.reg_ck_out_edge = 0; + } + + /* Configure the polarity of the CS line */ + lp_spi_dev->spi_misc.reg_master_cs_pol = dev_config->flags & LP_SPI_DEVICE_CS_ACTIVE_HIGH ? 1 : 0; + + /* Configure half-duplex (0) or full-duplex (1) mode for LP SPI master */ + lp_spi_dev->spi_user.reg_doutdin = dev_config->flags & LP_SPI_DEVICE_HALF_DUPLEX ? 0 : 1; + + /* Configure 3-Wire half-duplex mode */ + lp_spi_dev->spi_user.reg_sio = dev_config->flags & LP_SPI_DEVICE_3WIRE ? 1 : 0; + + /* Configure CS setup and hold times */ + lp_spi_dev->spi_user1.reg_cs_setup_time = dev_config->cs_ena_pretrans == 0 ? 0 : dev_config->cs_ena_pretrans - 1; + lp_spi_dev->spi_user.reg_cs_setup = dev_config->cs_ena_pretrans ? 1 : 0; + lp_spi_dev->spi_user1.reg_cs_hold_time = dev_config->cs_ena_posttrans; + lp_spi_dev->spi_user.reg_cs_hold = dev_config->cs_ena_posttrans ? 1 : 0; + + /* Select the CS pin */ + lp_spi_dev->spi_misc.reg_cs0_dis = 0; +} + +static void lp_spi_slave_setup_device(const lp_spi_slave_config_t *slave_config) +{ + /* Configure transmission bit order */ + lp_spi_dev->spi_ctrl.reg_rd_bit_order = slave_config->flags & LP_SPI_DEVICE_RXBIT_LSBFIRST ? 1 : 0; + lp_spi_dev->spi_ctrl.reg_wr_bit_order = slave_config->flags & LP_SPI_DEVICE_TXBIT_LSBFIRST ? 1 : 0; + + /* Configure SPI mode in slave mode */ + if (slave_config->spi_mode == 0) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 0; + lp_spi_dev->spi_user.reg_rsck_i_edge = 0; + lp_spi_dev->spi_user.reg_tsck_i_edge = 0; + lp_spi_dev->spi_slave.reg_clk_mode_13 = 0; + } else if (slave_config->spi_mode == 1) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 0; + lp_spi_dev->spi_user.reg_rsck_i_edge = 1; + lp_spi_dev->spi_user.reg_tsck_i_edge = 1; + lp_spi_dev->spi_slave.reg_clk_mode_13 = 1; + } else if (slave_config->spi_mode == 2) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 1; + lp_spi_dev->spi_user.reg_rsck_i_edge = 1; + lp_spi_dev->spi_user.reg_tsck_i_edge = 1; + lp_spi_dev->spi_slave.reg_clk_mode_13 = 0; + } else if (slave_config->spi_mode == 3) { + lp_spi_dev->spi_misc.reg_ck_idle_edge = 1; + lp_spi_dev->spi_user.reg_rsck_i_edge = 0; + lp_spi_dev->spi_user.reg_tsck_i_edge = 0; + lp_spi_dev->spi_slave.reg_clk_mode_13 = 1; + } + + if (slave_config->flags & LP_SPI_DEVICE_CS_ACTIVE_HIGH) { + ESP_LOGW(LP_SPI_TAG, "Active high CS line is not supported in slave mode. Using active low CS line."); + } + lp_spi_dev->spi_misc.reg_slave_cs_pol = 0; + + if (slave_config->flags & LP_SPI_DEVICE_HALF_DUPLEX) { + ESP_LOGW(LP_SPI_TAG, "Half-duplex mode is not supported in slave mode. Using full-duplex mode."); + } + lp_spi_dev->spi_user.reg_doutdin = 1; + + /* Configure 3-Wire half-duplex mode */ + lp_spi_dev->spi_user.reg_sio = slave_config->flags & LP_SPI_DEVICE_3WIRE ? 1 : 0; + + /* Select the CS pin */ + lp_spi_dev->spi_misc.reg_cs0_dis = 0; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// Public APIs /////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +esp_err_t lp_core_lp_spi_bus_initialize(lp_spi_host_t host_id, const lp_spi_bus_config_t *bus_config) +{ + (void)host_id; + + /* Sanity check arguments */ + if (bus_config == NULL) { + return ESP_ERR_INVALID_ARG; + } + + /* Connect the LP SPI peripheral to a "bus", i.e. a set of + * GPIO pins defined in the bus_config structure. + */ + esp_err_t ret = lp_spi_bus_init_io(bus_config); + + return ret; +} + +esp_err_t lp_core_lp_spi_bus_add_device(lp_spi_host_t host_id, const lp_spi_device_config_t *dev_config) +{ + (void)host_id; + + esp_err_t ret = ESP_OK; + + /* Configure the CS pin */ + ESP_RETURN_ON_ERROR(lp_spi_cs_pin_init(dev_config->cs_io_num), LP_SPI_TAG, "CS pin initialization failed"); + + /* Enable the LP SPI clock gate */ + lp_spi_enable_clock_gate(); + + /* Lazy initialize the LP SPI in master mode */ + lp_spi_master_init(); + + /* Configure clock */ + ESP_RETURN_ON_ERROR(lp_spi_clock_init(dev_config), LP_SPI_TAG, "Clock initialization failed"); + + /* Setup the SPI device */ + lp_spi_master_setup_device(dev_config); + + return ret; +} + +esp_err_t lp_core_lp_spi_slave_initialize(lp_spi_host_t host_id, const lp_spi_slave_config_t *slave_config) +{ + (void)host_id; + + esp_err_t ret = ESP_OK; + + /* Configure the CS pin */ + ESP_RETURN_ON_ERROR(lp_spi_cs_pin_init(slave_config->cs_io_num), LP_SPI_TAG, "CS pin initialization failed"); + + /* Enable the LP SPI clock gate */ + lp_spi_enable_clock_gate(); + + /* Initialize the LP SPI in slave mode */ + lp_spi_slave_init(); + + /* Setup the SPI device */ + lp_spi_slave_setup_device(slave_config); + + return ret; +} diff --git a/docs/component_info_ignore_file.txt b/docs/component_info_ignore_file.txt index 21b0fd9c0c6..fd09655d217 100644 --- a/docs/component_info_ignore_file.txt +++ b/docs/component_info_ignore_file.txt @@ -7,6 +7,7 @@ components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h +components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h # ESSL headers do not belong to any IDF component, in a user project it will come from a managed component components/driver/test_apps/components/esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio.h components/driver/test_apps/components/esp_serial_slave_link/include/esp_serial_slave_link/essl_spi.h diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index 32f0c5817b7..02cb462e92d 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -1,6 +1,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \ + $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_spi.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \ @@ -8,6 +9,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \ + $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h \ $(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \ $(PROJECT_PATH)/components/usb/include/usb/usb_host.h \ diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index cc131a1a801..8f8b08efbbb 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -160,6 +160,7 @@ To enhance the capabilities of the ULP LP-Core coprocessor, it has access to per * LP IO * LP I2C * LP UART + :SOC_LP_SPI_SUPPORTED: * LP SPI .. only:: CONFIG_ESP_ROM_HAS_LP_ROM @@ -232,6 +233,10 @@ Main CPU API Reference .. include-build-file:: inc/lp_core_i2c.inc .. include-build-file:: inc/lp_core_uart.inc +.. only:: CONFIG_SOC_LP_SPI_SUPPORTED + + .. include-build-file:: inc/lp_core_spi.inc + LP Core API Reference ~~~~~~~~~~~~~~~~~~~~~~ @@ -242,4 +247,8 @@ LP Core API Reference .. include-build-file:: inc/ulp_lp_core_print.inc .. include-build-file:: inc/ulp_lp_core_interrupts.inc +.. only:: CONFIG_SOC_LP_SPI_SUPPORTED + + .. include-build-file:: inc/ulp_lp_core_spi.inc + .. _esp-idf-monitor: https://github.com/espressif/esp-idf-monitor diff --git a/docs/zh_CN/api-reference/system/ulp-lp-core.rst b/docs/zh_CN/api-reference/system/ulp-lp-core.rst index f44bd3efa60..06e805e6629 100644 --- a/docs/zh_CN/api-reference/system/ulp-lp-core.rst +++ b/docs/zh_CN/api-reference/system/ulp-lp-core.rst @@ -160,6 +160,7 @@ ULP LP-Core 支持的外设 * LP IO * LP I2C * LP UART + :SOC_LP_SPI_SUPPORTED: * LP SPI .. only:: CONFIG_ESP_ROM_HAS_LP_ROM @@ -196,6 +197,10 @@ API 参考 .. include-build-file:: inc/lp_core_i2c.inc .. include-build-file:: inc/lp_core_uart.inc +.. only:: CONFIG_SOC_LP_SPI_SUPPORTED + + .. include-build-file:: inc/lp_core_spi.inc + LP 内核 API 参考 ~~~~~~~~~~~~~~~~~~~~~~ @@ -204,3 +209,10 @@ LP 内核 API 参考 .. include-build-file:: inc/ulp_lp_core_i2c.inc .. include-build-file:: inc/ulp_lp_core_uart.inc .. include-build-file:: inc/ulp_lp_core_print.inc +.. include-build-file:: inc/ulp_lp_core_interrupts.inc + +.. only:: CONFIG_SOC_LP_SPI_SUPPORTED + + .. include-build-file:: inc/ulp_lp_core_spi.inc + +.. _esp-idf-monitor: https://github.com/espressif/esp-idf-monitor From 1c95a38ed185b59f6095eea296da5b8e81e7fb8f Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Wed, 19 Jun 2024 10:18:19 +0200 Subject: [PATCH 330/548] test: Added LP core unit tests for LP SPI This commit adds tests for LP SPI master and LP SPI slave devices. --- .../ulp/test_apps/lp_core/main/CMakeLists.txt | 14 + .../main/lp_core/test_main_spi_master.c | 38 +++ .../main/lp_core/test_main_spi_slave.c | 32 +++ .../lp_core/main/lp_core/test_shared.h | 1 + .../test_apps/lp_core/main/test_lp_core_spi.c | 254 ++++++++++++++++++ 5 files changed, 339 insertions(+) create mode 100644 components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c create mode 100644 components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c create mode 100644 components/ulp/test_apps/lp_core/main/test_lp_core_spi.c diff --git a/components/ulp/test_apps/lp_core/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/main/CMakeLists.txt index d9084ea2bf6..0e152e7969c 100644 --- a/components/ulp/test_apps/lp_core/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/main/CMakeLists.txt @@ -4,6 +4,10 @@ if(CONFIG_SOC_LP_I2C_SUPPORTED) list(APPEND app_sources "test_lp_core_i2c.c") endif() +if(CONFIG_SOC_LP_SPI_SUPPORTED) + list(APPEND app_sources "test_lp_core_spi.c") +endif() + set(lp_core_sources "lp_core/test_main.c") set(lp_core_sources_counter "lp_core/test_main_counter.c") @@ -17,6 +21,11 @@ if(CONFIG_SOC_LP_I2C_SUPPORTED) set(lp_core_sources_i2c "lp_core/test_main_i2c.c") endif() +if(CONFIG_SOC_LP_SPI_SUPPORTED) + set(lp_core_sources_spi_master "lp_core/test_main_spi_master.c") + set(lp_core_sources_spi_slave "lp_core/test_main_spi_slave.c") +endif() + idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "lp_core" REQUIRES ulp unity esp_timer test_utils @@ -37,3 +46,8 @@ ulp_embed_binary(lp_core_test_app_gpio "${lp_core_sources_gpio}" "${lp_core_exp_ if(CONFIG_SOC_LP_I2C_SUPPORTED) ulp_embed_binary(lp_core_test_app_i2c "${lp_core_sources_i2c}" "${lp_core_exp_dep_srcs}") endif() + +if(CONFIG_SOC_LP_SPI_SUPPORTED) + ulp_embed_binary(lp_core_test_app_spi_master "${lp_core_sources_spi_master}" "${lp_core_exp_dep_srcs}") + ulp_embed_binary(lp_core_test_app_spi_slave "${lp_core_sources_spi_slave}" "${lp_core_exp_dep_srcs}") +endif() diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c new file mode 100644 index 00000000000..f7872dbcfc5 --- /dev/null +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "ulp_lp_core_spi.h" +#include "test_shared.h" + +volatile lp_core_test_commands_t spi_test_cmd = LP_CORE_NO_COMMAND; + +volatile uint8_t spi_master_tx_buf[100] = {0}; +volatile uint8_t spi_master_rx_buf[100] = {0}; +volatile uint32_t spi_tx_len = 0; + +int main(void) +{ + /* Wait for the HP core to start the test */ + while (spi_test_cmd == LP_CORE_NO_COMMAND) { + + } + + /* Setup SPI transaction */ + lp_spi_transaction_t trans_desc = { + .tx_length = spi_tx_len, + .rx_length = spi_tx_len, + .tx_buffer = (uint8_t *)spi_master_tx_buf, + .rx_buffer = (uint8_t *)spi_master_rx_buf, + }; + + /* Transmit data */ + lp_core_lp_spi_master_transfer(&trans_desc, -1); + + /* Synchronize with the HP core running the test */ + spi_test_cmd = LP_CORE_NO_COMMAND; + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c b/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c new file mode 100644 index 00000000000..81b208295e5 --- /dev/null +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "ulp_lp_core_spi.h" +#include "test_shared.h" + +volatile lp_core_test_command_reply_t spi_test_cmd_reply = LP_CORE_COMMAND_NOK; + +volatile uint8_t spi_slave_tx_buf[100] = {0}; +volatile uint8_t spi_slave_rx_buf[100] = {0}; +volatile uint32_t spi_rx_len = 0; + +int main(void) +{ + /* Setup SPI transaction */ + lp_spi_transaction_t trans_desc = { + .rx_length = spi_rx_len, + .rx_buffer = (uint8_t *)spi_slave_rx_buf, + .tx_buffer = NULL, + }; + + /* Receive data */ + lp_core_lp_spi_slave_transfer(&trans_desc, -1); + + /* Synchronize with the HP core running the test */ + spi_test_cmd_reply = LP_CORE_COMMAND_OK; + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h index 7497ff4e6cb..b044c34b483 100644 --- a/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h +++ b/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h @@ -17,6 +17,7 @@ typedef enum { LP_CORE_DELAY_TEST, LP_CORE_DEEP_SLEEP_WAKEUP_SHORT_DELAY_TEST, LP_CORE_DEEP_SLEEP_WAKEUP_LONG_DELAY_TEST, + LP_CORE_LP_SPI_WRITE_READ_TEST, LP_CORE_NO_COMMAND, } lp_core_test_commands_t; diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core_spi.c b/components/ulp/test_apps/lp_core/main/test_lp_core_spi.c new file mode 100644 index 00000000000..b23e99bd099 --- /dev/null +++ b/components/ulp/test_apps/lp_core/main/test_lp_core_spi.c @@ -0,0 +1,254 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "lp_core_test_app_spi_master.h" +#include "lp_core_test_app_spi_slave.h" +#include "ulp_lp_core.h" +#include "lp_core_spi.h" +#include "unity.h" +#include "test_utils.h" +#include "esp_log.h" +#include "test_shared.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +extern const uint8_t lp_core_main_spi_master_bin_start[] asm("_binary_lp_core_test_app_spi_master_bin_start"); +extern const uint8_t lp_core_main_spi_master_bin_end[] asm("_binary_lp_core_test_app_spi_master_bin_end"); +extern const uint8_t lp_core_main_spi_slave_bin_start[] asm("_binary_lp_core_test_app_spi_slave_bin_start"); +extern const uint8_t lp_core_main_spi_slave_bin_end[] asm("_binary_lp_core_test_app_spi_slave_bin_end"); + +static const char* TAG = "lp_core_spi_test"; + +#define TEST_GPIO_PIN_MISO 6 +#define TEST_GPIO_PIN_MOSI 7 +#define TEST_GPIO_PIN_CLK 8 +#define TEST_GPIO_PIN_CS 4 + +#define TEST_DATA_LEN_BYTES 42 +uint8_t expected_data[100] = {0}; + +static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) +{ + TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, (firmware_end - firmware_start)) == ESP_OK); + TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK); +} + +static void setup_test_data(void) +{ + uint8_t *tx_data = (uint8_t *)&ulp_spi_master_tx_buf; + ulp_spi_tx_len = TEST_DATA_LEN_BYTES; + + /* Setup test data */ + for (int i = 0; i < ulp_spi_tx_len; i++) { + tx_data[i] = (i + 1) % 256; + expected_data[i] = tx_data[i]; + } +} + +static void setup_expected_data(void) +{ + ulp_spi_rx_len = TEST_DATA_LEN_BYTES; + + /* Setup expected data */ + for (int i = 0; i < TEST_DATA_LEN_BYTES; i++) { + expected_data[i] = (i + 1) % 256; + } +} + +/* Base LP SPI bus settings */ +lp_spi_host_t host_id = 0; +lp_spi_bus_config_t bus_config = { + .miso_io_num = TEST_GPIO_PIN_MISO, + .mosi_io_num = TEST_GPIO_PIN_MOSI, + .sclk_io_num = TEST_GPIO_PIN_CLK, +}; + +/* Base LP SPI device settings */ +lp_spi_device_config_t device = { + .cs_io_num = TEST_GPIO_PIN_CS, + .spi_mode = 0, + .clock_speed_hz = 10 * 1000, // 10 MHz + .duty_cycle = 128, // 50% duty cycle +}; + +/* Base LP SPI slave device settings */ +lp_spi_slave_config_t slv_device = { + .cs_io_num = TEST_GPIO_PIN_CS, + .spi_mode = 0, +}; + +static void lp_spi_master_init(int spi_flags, bool setup_master_loop_back) +{ + /* Initialize LP SPI bus */ + /* Setup loop back for tests which do not use an LP SPI slave for looping back the data. */ + bus_config.miso_io_num = setup_master_loop_back ? TEST_GPIO_PIN_MOSI : TEST_GPIO_PIN_MISO; + TEST_ASSERT(lp_core_lp_spi_bus_initialize(host_id, &bus_config) == ESP_OK); + + /* Add LP SPI device */ + device.flags = spi_flags; + TEST_ASSERT(lp_core_lp_spi_bus_add_device(host_id, &device) == ESP_OK); +} + +static void lp_spi_slave_init(int spi_flags) +{ + /* Initialize LP SPI bus */ + TEST_ASSERT(lp_core_lp_spi_bus_initialize(host_id, &bus_config) == ESP_OK); + + /* Add LP SPI slave device */ + if (spi_flags != 0) { + slv_device.flags = spi_flags; + } + TEST_ASSERT(lp_core_lp_spi_slave_initialize(host_id, &slv_device) == ESP_OK); +} + +static void lp_spi_master_execute_test(bool wait_for_slave_ready) +{ + /* Load and run the LP core firmware */ + ulp_lp_core_cfg_t lp_cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + load_and_start_lp_core_firmware(&lp_cfg, lp_core_main_spi_master_bin_start, lp_core_main_spi_master_bin_end); + + if (wait_for_slave_ready) { + /* Wait for the HP SPI device to be initialized */ + unity_wait_for_signal("LP SPI slave ready"); + } + + /* Setup test data */ + setup_test_data(); + + /* Start the test */ + ulp_spi_test_cmd = LP_CORE_LP_SPI_WRITE_READ_TEST; + + while (ulp_spi_test_cmd != LP_CORE_NO_COMMAND) { + /* Wait for the test to complete */ + vTaskDelay(1); + } + + /* Verify the received data if we expect the data to be looped back from the LP SPI slave */ + uint8_t *rx_data = (uint8_t *)&ulp_spi_master_rx_buf; + for (int i = 0; i < TEST_DATA_LEN_BYTES; i++) { + ESP_LOGI(TAG, "LP SPI master received data: 0x%02x", rx_data[i]); + } + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, rx_data, ulp_spi_tx_len); +} + +static void lp_spi_slave_execute_test(void) +{ + /* Load and run the LP core firmware */ + ulp_lp_core_cfg_t lp_cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + load_and_start_lp_core_firmware(&lp_cfg, lp_core_main_spi_slave_bin_start, lp_core_main_spi_slave_bin_end); + + /* Setup expected test data */ + setup_expected_data(); + + /* Send signal to LP SPI master */ + unity_send_signal("LP SPI slave ready"); + + /* Wait for the test to complete */ + while (ulp_spi_test_cmd_reply != LP_CORE_COMMAND_OK) { + vTaskDelay(1); + } + + /* Verify the received data */ + uint8_t *rx_data = (uint8_t *)&ulp_spi_slave_rx_buf; + for (int i = 0; i < TEST_DATA_LEN_BYTES; i++) { + ESP_LOGI(TAG, "LP SPI slave received data: 0x%02x", rx_data[i]); + } + + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_data, rx_data, TEST_DATA_LEN_BYTES); +} + +void test_lp_spi_master(void) +{ + /* Initialize LP SPI in master mode */ + lp_spi_master_init(0, false); + + /* Start the LP SPI master test */ + lp_spi_master_execute_test(true); +} + +void test_lp_spi_slave(void) +{ + /* Initialize LP SPI in slave mode */ + lp_spi_slave_init(0); + + /* Start the LP SPI slave test */ + lp_spi_slave_execute_test(); +} +void test_lp_spi_master_3wire(void) +{ + /* Initialize LP SPI in master mode */ + int spi_flags = LP_SPI_DEVICE_3WIRE; + lp_spi_master_init(spi_flags, false); + + /* Start the LP SPI master test */ + lp_spi_master_execute_test(true); +} + +void test_lp_spi_slave_3wire(void) +{ + /* Initialize LP SPI in slave mode */ + int spi_flags = LP_SPI_DEVICE_3WIRE; + lp_spi_slave_init(spi_flags); + + /* Start the LP SPI slave test */ + lp_spi_slave_execute_test(); +} + +void test_lp_spi_master_lsbfirst(void) +{ + /* Initialize LP SPI in master mode */ + int spi_flags = LP_SPI_DEVICE_BIT_LSBFIRST; + lp_spi_master_init(spi_flags, false); + + /* Start the LP SPI master test */ + lp_spi_master_execute_test(true); +} + +void test_lp_spi_slave_lsbfirst(void) +{ + /* Initialize LP SPI in slave mode */ + int spi_flags = LP_SPI_DEVICE_BIT_LSBFIRST; + lp_spi_slave_init(spi_flags); + + /* Start the LP SPI slave test */ + lp_spi_slave_execute_test(); +} + +/* Test LP-SPI master loopback */ +TEST_CASE("LP-Core LP-SPI master loopback test", "[lp_core]") +{ + /* Initialize LP SPI in master mode */ + lp_spi_master_init(0, true); + + /* Start the LP SPI master test */ + lp_spi_master_execute_test(false); +} + +/* Test LP-SPI master loopback with active low CS line */ +TEST_CASE("LP-Core LP-SPI master loopback test with active high CS line", "[lp_core]") +{ + /* Initialize LP SPI in master mode */ + int spi_flags = LP_SPI_DEVICE_CS_ACTIVE_HIGH; + lp_spi_master_init(spi_flags, true); + + /* Start the LP SPI master test */ + lp_spi_master_execute_test(false); +} + +/* Test LP-SPI master and LP-SPI slave communication */ +TEST_CASE_MULTIPLE_DEVICES("LP-Core LP-SPI master and LP-SPI slave read write test", "[lp_core_spi][test_env=generic_multi_device][timeout=150]", test_lp_spi_master, test_lp_spi_slave); + +/* Test LP-SPI master in 3-Wire SPI mode */ +TEST_CASE_MULTIPLE_DEVICES("LP-Core LP-SPI master and LP-SPI slave in 3-Wire SPI mode", "[lp_core_spi][test_env=generic_multi_device][timeout=150]", test_lp_spi_master_3wire, test_lp_spi_slave_3wire); + +/* Test LP-SPI master and LP-SPI slave in LSB first mode */ +TEST_CASE_MULTIPLE_DEVICES("LP-Core LP-SPI master and LP-SPI in LSB first SPI mode", "[lp_core_spi][test_env=generic_multi_device][timeout=150]", test_lp_spi_master_lsbfirst, test_lp_spi_slave_lsbfirst); From 901158540eb12f097d678d9067b87ace5b1add66 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Thu, 27 Jun 2024 17:35:35 +0800 Subject: [PATCH 331/548] test(misc): enable misc tests that have been missed during bringup --- components/esp_hw_support/test_apps/.build-test-rules.yml | 4 ---- .../esp_hw_support_unity_tests/pytest_esp_hw_support.py | 2 -- components/esp_system/test_apps/.build-test-rules.yml | 4 +--- .../esp_system/test_apps/esp_system_unity_tests/README.md | 4 ++-- components/esp_timer/test_apps/.build-test-rules.yml | 7 ------- components/esp_timer/test_apps/README.md | 4 ++-- components/freertos/test_apps/.build-test-rules.yml | 4 ++-- components/freertos/test_apps/freertos/README.md | 4 ++-- components/heap/test_apps/.build-test-rules.yml | 3 --- components/heap/test_apps/heap_tests/README.md | 4 ++-- 10 files changed, 11 insertions(+), 29 deletions(-) delete mode 100644 components/esp_timer/test_apps/.build-test-rules.yml diff --git a/components/esp_hw_support/test_apps/.build-test-rules.yml b/components/esp_hw_support/test_apps/.build-test-rules.yml index a395b606192..b7e85dae37c 100644 --- a/components/esp_hw_support/test_apps/.build-test-rules.yml +++ b/components/esp_hw_support/test_apps/.build-test-rules.yml @@ -17,10 +17,6 @@ components/esp_hw_support/test_apps/dma2d: components/esp_hw_support/test_apps/esp_hw_support_unity_tests: disable: - if: SOC_GPSPI_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: test not pass, should be re-enable # TODO: IDF-8972 components/esp_hw_support/test_apps/etm: disable: diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py index a96369107b0..303f5bc685e 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py @@ -1,11 +1,9 @@ # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 support TBD') # TODO: IDF-8972 @pytest.mark.generic @pytest.mark.parametrize( 'config', diff --git a/components/esp_system/test_apps/.build-test-rules.yml b/components/esp_system/test_apps/.build-test-rules.yml index d35ca3820c7..e59aab60e35 100644 --- a/components/esp_system/test_apps/.build-test-rules.yml +++ b/components/esp_system/test_apps/.build-test-rules.yml @@ -6,9 +6,7 @@ components/esp_system/test_apps/console: components/esp_system/test_apps/esp_system_unity_tests: disable: - - if: IDF_TARGET == "esp32c5" or (CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1) - temporary: true - reason: C5 not support yet # TODO: [ESP32C5] IDF-8690 + - if: (CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1) components/esp_system/test_apps/linux_apis: enable: diff --git a/components/esp_system/test_apps/esp_system_unity_tests/README.md b/components/esp_system/test_apps/esp_system_unity_tests/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/README.md +++ b/components/esp_system/test_apps/esp_system_unity_tests/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_timer/test_apps/.build-test-rules.yml b/components/esp_timer/test_apps/.build-test-rules.yml deleted file mode 100644 index 748bc781b27..00000000000 --- a/components/esp_timer/test_apps/.build-test-rules.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps - -components/esp_timer/test_apps: - disable: - - if: IDF_TARGET == "esp32c5" - temporary: true - reason: C5 not support yet # TODO: [ESP32C5] IDF-8705 diff --git a/components/esp_timer/test_apps/README.md b/components/esp_timer/test_apps/README.md index c75201fb88f..351f5fdebc7 100644 --- a/components/esp_timer/test_apps/README.md +++ b/components/esp_timer/test_apps/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/freertos/test_apps/.build-test-rules.yml b/components/freertos/test_apps/.build-test-rules.yml index 83c48f535d0..d7bce90918e 100644 --- a/components/freertos/test_apps/.build-test-rules.yml +++ b/components/freertos/test_apps/.build-test-rules.yml @@ -2,9 +2,9 @@ components/freertos/test_apps/freertos: disable: - - if: IDF_TARGET == "esp32c5" or (CONFIG_NAME == "smp" and IDF_TARGET == "esp32p4") + - if: (CONFIG_NAME == "smp" and IDF_TARGET == "esp32p4") temporary: true - reason: target(s) not supported yet # TODO: [ESP32C5] IDF-8672 + reason: target(s) not supported yet components/freertos/test_apps/orig_inc_path: enable: diff --git a/components/freertos/test_apps/freertos/README.md b/components/freertos/test_apps/freertos/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/freertos/test_apps/freertos/README.md +++ b/components/freertos/test_apps/freertos/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/heap/test_apps/.build-test-rules.yml b/components/heap/test_apps/.build-test-rules.yml index a55adfc1764..1e3b8ecd8cf 100644 --- a/components/heap/test_apps/.build-test-rules.yml +++ b/components/heap/test_apps/.build-test-rules.yml @@ -3,9 +3,6 @@ components/heap/test_apps/heap_tests: disable: - if: IDF_TARGET == "linux" - - if: IDF_TARGET == "esp32c5" - temporary: true - reason: not support yet # TODO: [ESP32C5] IDF-9641 - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 - if: CONFIG_NAME == "psram_all_ext" and SOC_SPIRAM_SUPPORTED != 1 # These 3 configs are build only for non-nightly, buildig for a single target is sufficient diff --git a/components/heap/test_apps/heap_tests/README.md b/components/heap/test_apps/heap_tests/README.md index 5b39ff96532..b8fe0d892df 100644 --- a/components/heap/test_apps/heap_tests/README.md +++ b/components/heap/test_apps/heap_tests/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file From 9d60b907d59cbff74905785e6a2d7e3463e26c0a Mon Sep 17 00:00:00 2001 From: WanqQixiang Date: Fri, 14 Jun 2024 18:52:40 +0800 Subject: [PATCH 332/548] fix(openthread): register uart vfs devices when they are not registered --- .../openthread/src/port/esp_openthread_uart.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/openthread/src/port/esp_openthread_uart.c b/components/openthread/src/port/esp_openthread_uart.c index fc33cd1f93b..19070a7a228 100644 --- a/components/openthread/src/port/esp_openthread_uart.c +++ b/components/openthread/src/port/esp_openthread_uart.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "esp_openthread_common_macro.h" #include "esp_openthread_platform.h" #include "esp_openthread_types.h" +#include "esp_vfs.h" #include "esp_vfs_dev.h" #include "common/logging.hpp" #include "driver/uart.h" @@ -62,6 +63,17 @@ otError otPlatUartSend(const uint8_t *buf, uint16_t buf_length) esp_err_t esp_openthread_uart_init_port(const esp_openthread_uart_config_t *config) { +#ifndef CONFIG_ESP_CONSOLE_UART + // If UART console is used, UART vfs devices should be registered during startup. + // Otherwise we need to register them here. + DIR *uart_dir = opendir("/dev/uart"); + if (!uart_dir) { + // If UART vfs devices are registered, we will failed to open the directory + uart_vfs_dev_register(); + } else { + closedir(uart_dir); + } +#endif ESP_RETURN_ON_ERROR(uart_param_config(config->port, &config->uart_config), OT_PLAT_LOG_TAG, "uart_param_config failed"); ESP_RETURN_ON_ERROR( @@ -91,7 +103,6 @@ esp_err_t esp_openthread_host_cli_usb_init(const esp_openthread_platform_config_ ret = usb_serial_jtag_driver_install((usb_serial_jtag_driver_config_t *)&config->host_config.host_usb_config); usb_serial_jtag_vfs_use_driver(); - uart_vfs_dev_register(); return ret; } #endif From c60e627bba550a7d7032239013404d59a70b4f3b Mon Sep 17 00:00:00 2001 From: Linda Date: Tue, 21 May 2024 17:55:05 +0800 Subject: [PATCH 333/548] docs: Migrate user guides of ESP32-C3-DevKitM and ESP32-C3-DevKitC to esp-dev-kits --- ...esp32-c3-devkitc-02-v1-annotated-photo.png | Bin 385839 -> 0 bytes .../esp32-c3-devkitc-02-v1-block-diags.png | Bin 81043 -> 0 bytes .../esp32-c3-devkitc-02-v1-isometric.png | Bin 244132 -> 0 bytes .../_static/esp32-c3-devkitc-02-v1-pinout.png | Bin 279856 -> 0 bytes .../esp32-c3-devkitm-1-v1-annotated-photo.png | Bin 349164 -> 0 bytes .../esp32-c3-devkitm-1-v1-block-diagram.png | Bin 76929 -> 0 bytes .../esp32-c3-devkitm-1-v1-isometric.png | Bin 236210 -> 0 bytes docs/_static/esp32-c3-devkitm-1-v1-pinout.png | Bin 353343 -> 0 bytes docs/en/get-started/index.rst | 4 +- .../esp32c3/user-guide-devkitc-02.rst | 236 ----------------- .../esp32c3/user-guide-devkitm-1.rst | 240 ------------------ docs/zh_CN/get-started/index.rst | 4 +- .../esp32c3/user-guide-devkitc-02.rst | 237 ----------------- .../esp32c3/user-guide-devkitm-1.rst | 240 ------------------ 14 files changed, 4 insertions(+), 957 deletions(-) delete mode 100644 docs/_static/esp32-c3-devkitc-02-v1-annotated-photo.png delete mode 100644 docs/_static/esp32-c3-devkitc-02-v1-block-diags.png delete mode 100644 docs/_static/esp32-c3-devkitc-02-v1-isometric.png delete mode 100644 docs/_static/esp32-c3-devkitc-02-v1-pinout.png delete mode 100644 docs/_static/esp32-c3-devkitm-1-v1-annotated-photo.png delete mode 100644 docs/_static/esp32-c3-devkitm-1-v1-block-diagram.png delete mode 100644 docs/_static/esp32-c3-devkitm-1-v1-isometric.png delete mode 100644 docs/_static/esp32-c3-devkitm-1-v1-pinout.png delete mode 100644 docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst delete mode 100644 docs/en/hw-reference/esp32c3/user-guide-devkitm-1.rst delete mode 100644 docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst delete mode 100644 docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst diff --git a/docs/_static/esp32-c3-devkitc-02-v1-annotated-photo.png b/docs/_static/esp32-c3-devkitc-02-v1-annotated-photo.png deleted file mode 100644 index 5b05cc38b4a8671e42af3f131c7895a6a01d23b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385839 zcmV*0KzYB3P)F&^$n*2_ zeK_)ylanJtLPF9xLd55)RjYQIquPVtDLS4%fBy3v^R-&7i9;)1-@SWxGmhOwpZOz? zf2jo#i%_%>MU(Q&#SpJ2BqT%^y+3Bmm}$d?4g31J=bl?o^xAJNhIn5rhIlMm3~~Ht zErvMPUur?b4gI%c+O%n7{@d?7%+LSr7eq|1GpMXvmU%_;FemyyJ@?ZE`A=u+fAqPh z3-Ujj=>PO*o-W9LI#d6n&pq-5=~=J0J6)TOmEV4ikf=B`Y*qu`FI|q{h&VKA+88dE z0SES;LYa!?5fI>wLwk=vB9Wj@i~2aUZ9il(8R|D_gdIOkhTgj#>NKhWo6U-oN6zBf zjq`Z!g)!K)b}oDZ%21uH3#T#(XO7%OU4CEVwqy6MV~}#PJ3iCdy>$KzczH*lal?ja z*Red_7&jLct41R%s0_Am--c_~PvXS6ODGYkM7=H_qj3d2>Xi=1q&e%+rhRj4+r0Y^ z%b`cUAZkT6o_%cznm#iOv%Y!_)hm?6h9hTSN!MNM1KyqZK3r}oWc=5lWp9ia z)Df19G)$a19c^1QhTUYtM;|VOL%jtumjb4Od`$gj0WxxL!(M2?w@X$dAfhx}ax035 z$DvrMCI}96z-)71!iUrFF&88?^)9}izYrlY6=1fSv3u_Y80?ea?NtFa8kEGWuUDdO zwMv*beF4fmH=Nj`z<6)T`bjoPr7axrh(LW~_X%rlWIcN|C4 zO2JTSB4D=rk)rh2wQ)T{tAyg*i8I)le+qLKyK(NwA@uFh3!i`aE>54kh(Kx=x}%xiTeSg$siQ4~N_Bf}dK6{oj28FQpRs*+3IHujAGB6|i>KW^A7M5}ui`9-sE?fp-p^#I7mbP;=-S7_NMY@ajWxZsTG!8uTd_ z$q7hgc=L@3*nQ+6j_=utxnw=Fr_I2H%U4mQa%p7cdPA;Pqf*HnEL^x0?K*TtC>Q+3 zovWx>r8JOy3=WMK6fPNTb~{`uUo@*%8GHBbgG8Z()UAa==D^e`A7a&tg=pNW4Jrf` zM{>#y%wD-3QN@bk%8i>(#)1?Y{9w1*VJR#?rlSzv?m!qQOr@r5SgZyd+`Ah-WJ~XF zyN-O59WTzX29@Y1Pa zk$7{rI-%7E!ew>9X|=&<0}9CZE0!yVkkCjt9adzery?~a1Mhz{nbdF!xyd=CJTB^x zA^7z3_u=DL%%efg`S=ygT(AXJ_ceanofBp3-H*VZ0IcwIeksPyX*RFkxqxOT}dFVpjX)?p= z@`lZw4Y^Ydlhg|2+n`bUK;m?BQd5wboyj$mBQPicW{U-RX<57pN(ZS7=~>xOldlK( zdBb7Jr`DAYM}7`WR4_vVf~bADuxsxwXmm38lnH@^-1y6r(xytZ}Dumy69P$4!1;&L0uYQe*8uJq<7%5 zLp=U+F~n;ReL);r9VCW)sGz0>Lt=6J!frEyd<=zTS>>u!NBYjq$jdFHnhO->o8cGa zjeKJvZ&(4PT#E8#O46=43Y((aF7xzEUVC z54alqF~M>)v}K$q9->F5e$T_M3#M9YMNC8lMhtlaPCKuK!(essbNTpW$wHX;80-}W zU!MTvnw*gNDAA;86WHLuho8TP@78{Y%!CAl`T66!%{xi$g;XkhJm>kN|2^~tQIg%5 zTy7}!3Rui;$Y=|=)q2>?4sK$9T)KDxEtD3y=qyLWOc=OF^oj-XnD)D>EH(nF47}Jsb`fP9>z_MoJ>O)v88$ub?cT z4I`7nV9v*?mFH0?v%zVyB0oO^qlOFyrme=bPsgKgzrK*G6bK0~MJlqx?Qp~t@O=N_FNiDzc10=;G&9+V8|FfC zXju*gBDETa86_gZaO~6tJkzy1)~@>=x&S}2GbO^p!%#>&B0Ml0DzzF4xg3X&9^s-? zL7B28asJ{(l9K^ye?KmU6d8B9C|0s59#@D8!GLxR(f`^V41aebJ|F)ElJc#XvScel z3Kt+qrNi1iPSkAoF3#qX_i?xb%HzEWQ!#(h0^}NU5vq2=;Gm4l$%miPi~w&foK6?Y zSFR5gsovxWgjQ#P)}@D=a?X-}kJ3CR`vd<*1$VJ9qNLkzR@p{4)gbZw zC;W~9679VO`C#l|Zk9qQs8lEl+&rh6vMz%fnE`HTFzQyShUi-gtg|0N4sECBjfwcq zI|`L;PUv+mRA?89`A!lx@7aZY+c&~@eGs7bCa08Q zs8~RimF%+u&hOg`6Bm=AVYgf^|J{r7&=&*>w`WpaTnq^(-sx~dZkNGKbyzC(^=Lw~ z=gow}E~R@U2sv3o<8mQ0H639Q!L+F5Fs3^ZMvZD04K=6Df=>+9^MBatye({}39sYl58QJT&jv0}`bc-+cNS&Rn{MD1R+d%z8}y zdNJ0m`~hc9AH$T-Kg3&ae)v1-rqTf+yGt#p@UVZ_jv zY0v>vCQXGOZH(f@BXQ#NDSlpxkgy;)s2J$Hy^)b`KtymDWrotjhUD}g$@s;P7%kOf zBZAa&v}{oa>$Yu2?HaYn`l>>qo=~)g#?GBj~+dGI>+d(Ter5!%ggf( z4Gm43J$v?x;-}WES<_P(H|NfstK7D2+bu=<^{-uqQ)UtxF62rYcxF3o5(!jxIW!V# zFd7@#7^%i$#J9_qdaU9+YFV9zzmKGkhC#^*cGz8HN4`k7nZ%t9B&H_QjiH8`$1)ml zTCE-lcaz9!9Pn1g!bl0xvSlaC`20)0ABvzrFZcw8;`F(#h%6a~!~2eNk&AJck4C%J z)liV0joXN%P&OeVBofo+&4YF7bgJas1X>sD2C`Mk6D_H`Sl#v*p0EZtuHHfMQl$~9 z*FnaG%r{veNu&SkdLmL%?5J3|%&$$wfAre@1^MQiZ-$D$qHl@C5XWuWwAotp+JhM# zMaE6hd%yKa?U4(T3mbQ(gp(`fB$L5V6}CVp)j;Fr4VhYp^ps2l1_t8G*>e%|-Y6P^ zdZ=l*7n#G$=4wVWfbL3fEF4ka%nqDR+O>*iyK3`xX?mOAhQj0kcd3FE@XW zLcWl^O+i)IA$8OGr&V2|81f7A(XCqtJm0N1W-t35$OFt~ZVsmj?tBRs!iyV*%WajS z&_U;?+X|hJ4nqcxMPPIQB1m+?lCRNoJWg$xjKJc-P*VW;>Tlp;V#04t#m`=sN~Nxd zh=^qIVq#)qRMDIF7o_NgKl{-swIePz4sIU}d{tT$=8-SoxdF9IMJ+81^T{&b@eI-LT= ziiIH~@g}^)N(g0w2BDGxEDNbo7>6>s8Uf+quwOHiqGb5?hfQQ-f~8q8bZB?XU9_6! zs~jeJ6}+VZFj6*olf4Q9RnEWTSC7H}Ob%Wh|1wox87^&|1GQZ&xWpq9{d~R9hS&JZ zarf@sVjOo(yg-Tr>*b}_GfU( zf{4IK7_$<Zx;%dpFxNRU*Lp&FYAs(w%t$IfMiQ`|6hrS?mz#cC^k>ocr6+5YDruo> z{b4IG;tDBL#%r=sL#^m1p|MH|;)1wrGL+I?!HH9P?tC|5%E!`8BVm}pg6D@0g+wFA zvN`YYgK~INes$_Kh{mZ3C-3^ZXw_f9MNRwqhg<1u}#L`yrd! z$+@e^v;~|r;v^(@83L(2)vMo%J}zMG#!Vgzy;zVRjC8Feq@*#P9SAjzx3nA!!hE#w z(I`=_L^Ki-Z{hsGL(m7(QucLGfm5SwTm`)S_E_{CFp%o79WVEI7IQ!UfU+qX-%K5c zjk^xxLZ%t#4xfU~Z9}Wh9l6*B?A(2bnw;4a`=GrETe=bcRB3(u>!Mjzs?dA)VFsg= z`*tm7{Qenu%j}GWT%e5e!_sf3pn&JxuwoW&r6u6C*T4APHi%fYhrS>eE+^6-oIM1}bJk}cfR$jpXx zTspfSzM(NFU#BdtUAs#spqyS~GpaUZeBEZknBmRw{A+ixe91B_{ALnfeS0QWuH1~9 zd3lHmDT#OrYNN%4m8&<=cg4%$xgDGerQJs3k%UX9p^@itm`>r)2?bmfNwFp4P`mbQ zRB758cg~$a#fr62F|IPcm_8Pr-sq0R^zyiKbrC=L$Hqfn5GgOw$^-?sx)4elY)%Vh z1%+;q2%S=(%c)N8KXRDPMB(N22NRyTQ$szrMhUG9ITi;bR4uh+DK-nWAcYP!n|4P0 z<#V{qh@jEN-Fm|WmA(+C?_NQx231g@N)MiQ76$Ym3VXv|46n|{gij~ajqis(!-haZ z*){f!SMkQnBbb-l20IvKj0mOTVKbn8r)RKf{bu^A+*BHb3tvqw&x-avx>FXpFzNlT z>9T(bv*s056=r%B1O7+&86cQZZ z3l}}X#Ues!1Uk4_dYJQ)aq-%D)TmY-`wkp~Hb6-^qNR~$!QIPy$zmvjY-D?RW~eBO zPMx^UL5W!U#3KX)r4wHQ96J5EJlrb4TTxE zNx2fFr)J=0;vM8odQWeI$OQMi!X-Z}RF2=`W=7udihZHrN1mLyiU(-|IM6-77 zsd{U$Z~tzj_zp(m@lgyp)8iXj4!$+w=p9JKpkc$YYSAL}?NbGDWn=L5(G!fZ02N|= z@zvO`(B=7_f5LM74}`j3L^;^qIS7(QBcHp>->IRDP*LY+q8f#J@#1C37PNHQ=}0wF z$_|EYv-6p@!-bEm_fiim%{9SfJPf*&`|v>k`vomxIOy3FWJ*O&o{=JLn#Ok&ZS$sG%~O4K-orJxI?q(tnx#^og=7L zy8|sYK34=$|0nCC%Ox~282&zWke$wKkVZs=P(TJ$?K3 zT_GlZ@7}#l#G@ERuibn0KcJAc-!1#qi!8c;#`PLel4#Mq-y7Kf{XX;@LVbUKcZOw+ z2n-Fyx_x&rpjZ>mO%SI?PO(e7gX~0vY<)s2a1m?4>~2bhU>D4;%XoX@`v?xzqigpL zXuwTSxqKbSy`m6ToOVrt8UEY^DlX`I?|)2NCzIZSF#6fd)WoEi_Qe{?1{=B#?FLr? z6%b(+D7>L#PFJ0lZD6AU(V=xc%v?Mj_1^ddsWW$B;p{Ils8<)-zs90l`a_QookITI z)wS*N5}NQPEk+3+Tfj=qu~CyoG|c>Q<>qxp4I?md^2ZeZe#}xKYolLEp;gg7u~JRe zphn#W@YVT4?Zqsbf0@isTcxg{M_b+Ksvx2bT$^6vnkJX%!KiR z)tn2x#+U4plx%Xq5y%ihwj6rBFO9}RCSMyc@x!@zZR9Hm2-M<*7e}IZ`+oEzI}lz| z&m_9axR^|Dv(Qrhgz?B13yJAA!foE% z(X;W|n=hk5?Fu-&XD>>YCK@eM(%wp~!Ray@)DYaRMM!~9!jHh%Wicsd+)=+(6gE}gr9 zT%!q-znq2dwjRdYuZ_g8o;?v55Q!!&8!?*b#*SS(J@!t@mAzN_I*=}Wn+9!KHo@Jix3PHRI#ehhz+A38_=ox7#Sw4eh2hW9R!YXMUB}@i z_ri!#FW~4+D>ip3h4bfTu-EHq5zc#!SUK>6LhQdOhjLht)sgtKgXXj;yRH;@sR8gvYCu?l6 ztdmz0ie(%)Sd5yDkAbowu0(BUTx;MP5JUFZ1e3n~l5rMb*6{Hd{q|I*EJ=`@l!#O3 z_n=IV>GF7Tn>3n>Ae3{LgH@9Porz1N%JK(n_QY?me zkDzY%Rq@~YY|-o0t5-j@e*O9`_3G6-T&h&5YZE6~&s{v{XWzr|4ececsHnE2m1=U;L`e(PqRgx8-g$YZuj zPZ#9rg8Y02nzd``etk$AwCpqnjhi=sf`Bf&cJIV7mOj5WZY;KK+Xk&#i~9BJV9lbp z5E0iI4O&!W8Yxph_Z&yt{{4vJ5RX$V=FDbV=`-CsVjq8ko?Um9TD4gE=EjjDCs?JM zfam(Xh)vrzd2kvl5)W(N24=1^8?tSu76he{Vb{)Wh%VueU?$O>*nga*Y;H7Z-W=br zoQvR)GHBMK8Cq4XhH;BGO%#Qev9g;tvfuBEnj=6gzb9|K(5Fnv{V5$Gh=02o$8p{ zwj+Mnuo?rOAA|~V(HQ;mgqP{q{Oae^``3rmUS539!1=kb%!Mg z$=u~K+`N4bufK7EJFpmzA5S9eUJ{&y>L_G2?!Ns$F_|r!^@`*9eVd0gv&<{qFJ40IJV_`bnMm#wn8K84V5?`a=V!GdyW8^<0nkR>Yc~o zmq)-G;%mJ>x-#B+tAvM*DMb>v!v_r;6vw#>H(1XuM}gZ2KQAr15mV*tF+x10pF^O3 zStN5)XbA-+CkVpp@4SQj%oH@LQv;{sFJS8imT21vH5eUR?7yG>|No7Lz92?3cO2_B z3XQjkE5%}+G?u7&u@>A+_XDyZ*9NlGd7&rgcK6n8NVswm81hK+AHt?@rypj$?_;!Y2YM(_Y{DIFXgVDZWur_v`=v|4jdfuRQbx zvD=wh&H_$>TVi3+4XZn$b^sb*)`+lX{mk)G9VVVN|`IEX06LVcn#*jb3FA?l8a zHHoEIqb_hr+*~9laXPFH9sF5wrPHWz>-tqz^ZIg8_+>7JlcjPp9t!M5k^;i`Mw*Ou z?L-qwAS{Q$RRVf&6vq}$AuKG>?uhnq;`mwg8#NMB zhg8DS8F~Z}P2$C2qj0^Da-~icNcf%5?Mx15Elb!>yW(8O&rRTu-XBFt76P#$ARr+7 z{Q2{hgfo*hj%MMcJbLtK9gd^-zrcfsz92RSr-#ToPElCTqI?G-HLNTtP^ugVB95Zd z#p+sA0T!f3GZvqS+RfZE<2D+w3U0YiJYN4*x^FoZzNbtwxp zzB;5{&tU!HO*C)b9u!ZgP`@J9E&BmgDwQI9MpY!_-b9u1oG^Y4O&yWA&KheRb=q2IIEIR(>Vu;rt`hpN^l$gClW0Mo=f)IQvPMnpC zBB#jB%CfQ0Qi@z=lskzQl$%#b{C1+Xv5v#Wg%EX#0@|;9=~B3Q{hFtA+Qg!Njo>B3 zI2q>x)Mbw>Kvn6)MD` z_waGpuzJ1k{U7}U2M>KgWULDmRjO_ok#l5(px{#2h|eyd@f>Q}1_Yf65AZ?`D{KwK zK}kqRg*VI8?%qj2iI`}l+)afsFQ2T66i`}ARg-bhKj z&N@ghoIQF5ZQFLmott-AGs3cMQe~fRT|EUt64sV%+j$1Nx2}bn*p07#G{*z#dEsIb zv-7=J7fG1aKVdxd1tCBc`9IkdjXt?V;1-f5$Y!kk@#s~*1?`zTXxPsLKa~vKTeqZ`$zU1{1HKO$$>X|hTp$Yp0!J@%(U zP(XXd0-Gk90GJ069o-1Uq6s0j`#Q>YYl*Dwn{dEEq*IL*L9AJScl^7=5>CR0Uw)YT z?$mGn{>Z{S^aYVn|4$6gQW(N30S0N4@%HpR!SwO zCL)&5P)%F)B=|EsB3wFys~6=MH}+Z9totB>$k}DwEb5_riHMFvSn)6{`fdqoH*e$n zM;1eT_n|L{)J`-WE`(5NU1V3HYk^H+qA=A{M|E*gWW-h9jPm76KtfeB$fYDgf`SH` z9}`gr7MP3PJUemUiJhfY>M1W$arn$p z5QTl{e5QiKKinBZ2s6;>U<7S5eIA9~uvR zK_uLzQr<9WLU>>a`a%m`A*k94U$T(Igd_|f@+=lCT8tsXhLUB?hnGKLTq(?B!y}MI zwqzs9wSqE0$#Z%6g}{fXrg8#VO1RraUYRh^1Y%sHN|jiJI~6An?LfaCeTcWn))T~s zPoX;|ETkBr`e@q_^_zeacyHMaXr%t^sBjWp+X~qt$K{KcvHQ$Pk4vU!ueVX7RzH-C zEsh$ET44FIF37%F0u5WV!1W8qh>T|^Dv%a$z4{s}vBJ2u-Ea_ON1#sqk>Obo5nC2I zad>!mN)gVYNJtj>uv4Z?d0k{~==FM|0FoC!=I!lWFlf-AMJG?5ta148;d=k-0wiQR z8Up7N?bSn$5~7CsNKLR1oQm|p`*7jh`BQAZV!@ZQW}*MiBZ&EQ5$1jJ3h}KJuo6~0 zoS@2T_VCDO-Il*g7LdZ*~NT9p`r&Mm)}(qy~yUIkmq&$(cxK;qD+dStnmK*`!6dx z@vminQ>zd>;y)S!btiVeo>Ks{^T%4EIy`ETu zS&lR|2ng|b2pSC;k7|B4Qp8|keWHAu7jSj+OsdvwH*VZyj&Virc^0JT$-{V5lix?iM0r{lnQ8Fd$w-FFXu0=Ogl*F3 z{qW)V5Af+Hli3I?0!L^=golL@;x&}Q*TMD`8r)?8rWb+CDiVnQ!o~AM-sLXldjgTv zN2g*8g`hS43E#znP z4y;|j$I~FdO;#kKOFlp?fYWRU)DaLfeLF5&{86$@4O~052bX{RnhPWGKsV{!Z2BT_ zZs`L04*EMT;Tw!bDq(hrS>(jSub+nMWVM-cH2Aa%q|D0jJD>&El_`(W|%6@* zOE*3JP)@qU({nia1VPT_BuDyEQ4qV7a8SoD8&HjC*BTv#HC0|6DU?8cFj_T?zp#dx z(LfjF&UnFJTwi(4y9>sNE|BP1-cZ!Y{v~ z`tBq`p`cnl9i=%`)g5e|@yq29wx!Z0njwpK#A5vaPuzP&d`=ua^aUXR2}zo}GAWaC zBm-JoFxx)}XCv#=iO8Vm0)6`B43v&8gK1xVL8Q1yLs)WCkdF!eAoQ6Nw8|qc~{-q>P(DE+Mt4XoJu}38NAQCslM>;cmKD)*YOL#oGuO zs|fToEK`XqBYtq3-Y<~43CJ8(is%00#^FO>kRF}7;4=F&nF`X7VNiP77+J`lwTupm zE;=PjgrRQra)_cnKmOB;2#@Ax(vqPhT!xvfEhyNFc!+c&(sfckI)n{flGsin7I|!A zA-cHbr)I(ECLlf`ml{;9k9qUHW`me?RG=%1Qgh?c^kdK3=KHBaGGF(a2KLnr8tx=)d8!v%_7vG4vS|kKoWgqI_kaBL&}|K<0QJ- z`{VmG*lnL#n~V8xhvBlrz<)er`}OK%}TVR8-3fhjcC)Q zEp3r@SohryJU{XUEN7QD72#lWG6+n=C6UtO+@)t|A6f zKut`sV9yf#(ZvuadFTtGrp_;6iwa+2778_8tD$Hma-4>)6f@C5gNSRmpZ%TWbb()I zQxl7%%!je4EQ((JTb8k0S}K!1}9zTr-y&l%CBWfM}J1Wns^Kqy@+YuE0E z+}DMVK3@huhH9fiiu3$gR6cl}bZV-2{Uxhb!sJP>qFa|Ebnld>s!NTI9$^`k0|6Z_ zCiIVvhrS@R)#!TH5{{LsCDU?jbX(}itKIZr1v4n*v@i%o)z)0-VvdxIY(vU65ver5 zl0AK^Dpab2#jBPe)R*=_b_8t=JA*^pF#OdI@zFc4u>%hskkp_Y8Z&At%vgN%63P^F z;F~Fpao~6wdbX_uuee?q_goM7lr4?(@oA`6wKlf0duYSP?Pz;sU}Colc;~xoxP2#+ z*)42FMj2yQ-N83A=MmcP1p+nGQ%yJjkJFZ;YNKe3dxNc3@7$&mV8=~1zf3uNhMSIR z+n+EV`htjdMOI4zC!F3>vMDDwl8=D%qnc@>(Z~op1Fh^n<;9kIRAW_YFBme@(5PK6 zT)uRXPDeI>tWX{$;uzcJxvr+%qyCHzJm5$TOl@}3ZlEbi_}@Ikr)09 zDyx6O*^7l#1{^p`@Xozk4xks4DsHAEQMJB{&H<&c_NRTEdeSCkOU-J5xExsGPgsh3 zr+DZKBGW5~sY~0#pyOl{0G3uQ!AGezvC$Ws7lt!l?n}(8i)SyOc*%;MY?Q!=;uP)~ z#CQ+#bS)^PyW+rseW=RGEmx)z^Rnb9&k(JaJ~B1gjThyOgp*S>Bm@aZm$2QHc1n z7tyDyA3_%|!skRe{9G{P6Ufp}18bq1 z4Yvrm&)s^JjUi``8b^S#w=i_vFuXqDZG7_f=h(e+6&g{HPWz-6#=f}-Ter_ei%!FE zo}kOMo7Tj!Jx2*bRuzZn3|vK^%AE9M1TfUvs6hvO@MTp@pSJ~x3#Y@Gbj8!ftu0ek zZ)dEcN_-eidOU;v&-TUYGkx*No?MJGP2SfE1HH znu-QYJuMp-i;pM1k3GkdFz}gHo=nR|waTF*)0K+HRi=de_3`!BUk?-S6fMRtk01Qj zLtl{f->?473*EEh*q*wLt2g;-_H0yd)D-RyBxqZc%~`FIQ)BZYklCyBCNmwC_D5!7AoTt=_ET>~sttg%fG&T{Tu(bD z1w+48D+l4&x$}gzt&BOd-sU{UA&^L_D;NL34sypIoY&ud{LmNVUtL*tZX)V7A5UQX z0<>pqQ~D4Yh++l^lhwL&7b_SSsl(^q4BHkfRT6R0C9q`vQfgING-PB@=jBhq+?0M7 zrWVnN5b+Yx97fKpLvP+$RzWUp1`SG<3#Q;Nq_m<>OZc_eOfoo-NfdNATFeByB+GNs zldKC&_t-mXIy5Ct_6$*3m<)G~jV;TH{>Qj&ED00g%}wq^c4?@~&)RT;a!$rg@n?-k zx*#`h-yyK80nHoKWqPL#JNI9qChJ6l`t|VBkB6{q={&ss>D!1ub_&s9r8p@jlrC2m zUd5uZdC@{FT(TIiQ8K;jdO>2sH2aF-5D1Nu;UadQ|^}w6Q5Q$n&>S)xk0T;UhIyG;G z`OBB!?U!F(H?^UKr66SC3@i?Gex8o7tZ;Qza9Pnm4Am z*p1^CL2q1{e;HrDz52k&pN z4c~o#|5zOKqp&X;+cr_n;mF9$DmLk(kBa5z?t ziaBY(ee&@P^z79gA=)^6yl@F!@li~0@L@wS6*EeV?1Pv`HkOCB&AQ?0?a2ts4@A!% z1F&W1ehe5q05Z0;Fy1@}DZ40`>51O7aR<7SO6jeoY5K>wUGewN zSAKppu$M>M^t`xn!%shd^MPl(SN%hsr;-m1k8r$>(RP(>un-QL1cy$o$p~k{-qW~_=+BMgA1(1B6zu|56L`;9`iIFItRW9{;O} z88c?gG~t0=wrpAdk3ar+{4YUiiWWnhqX;bXrI%isA)f!y#SrKCOD%}Fp+7pNO`9gX z>G=Hf&tLna=lVV0e~P*IduHwFcm6gr@RVcyZI=4!jsBh)cuF9@XV(75-(kK#)xMuc z-v66R5SAH-pQx4>T@*#p35(711!T0)ONG)tYSgHiMdv(t@L&UugW~y?EnC`hY!T_< zB4@woGk=%Irv&ntuC%D2;@B%LPoVt^>$7XuuIt1`7a4iM!ND2gy@3M%H+5QljDJ;YIT50xudCS9JZEY2gWYEgvL zvuDpWf=CMs3v~{MLq2lk$XUYht5~t(1>qJEtt>cV#CIO$cuF9Ta`yklZx<1V_=vzq z5syV1U4TD}=S8Ea;HT*MfBGm&6a`_4o++YKQQ)o+JSTDY?%mD)({uc*&lTN65pjsm z7I`@~Zrs@Em){kB!=l$72jURd@{~Y|R^)H^SR{3ddf5C8r{Le-@>2r&w^Q`^eBi&u z>i%!8{9&H^zqyXb?Xyn_>BT&5Gw`=3ki5l9pKCsH%=`@E z2*{Yfed~m$OpwUp1*p)lIU*v0j7GD^imE_}*J%J!{TNY2%KQ$6-m!H5yo%-T#?(%#xRz zorHTics|}}XNe_itlc3#!G#r=x6R^F1M!Ur*j?zf*sLZWFCQoiZE&AE*IE=6)B9w! zvzS;Z=Y{_n!*lL?&VWDTbiZ~E*VyqZr60dD6dKLHyk<$|O6Py=`;X$azdeDxxop+^ zEEYlEx?{oWrBiW>XjeCHrJ!=XIw;<_E9J3SoZaL;(Zt5$f?7u zWciwBmm{AgOygf4jZU5Wdti9c+pqp&%P!W6UX6u&+h%-vHY96!NEo`4i=Sae3UF&Wfd<~s|;ci z`VfmnNDC($(Fk-QyNy5xlv4&1A)f>)2X!mEg*Y&T4a^iZjFdXyQeup<(jO6WHTHkami!^@yW`~W&e~3 zs9CEKv0O&LY087!;y`@90u@UTKfvOoil{&?F$4;Ukxw9a-n$FC4xB{Q8qEm&aFd`v z3ckvJtd4g0Dbcjg`*^2s3p~@d0ihRJr>}G%kahnS;>r*%5LV8Qo9AQHo>(_h!l4k- znnk%9-n*07Vh*aAHmaBc8QxptkHuz-?<1v(2Y&o-Pas;gFJAwQszKRk%wG5dE^Ob1 z4O=!K?Zy$z-w==Qcdx0WLR{HWa1tGM>8sBooy76{ z@G%GsD2IJJXW`^`d+^-6IZ&7lIIwLgPV6~}7v5M26|1}t5qtUatsM01+X=z$WVT89 z9wvDOv})g+jUBjI3guLfEF>yF__$ai&vq+&mfhpzhFk;Nn^@7Bg#hS47r((L4;&>5 zm5hi~auQ|%>{QDPY@Omq{GF!Fnh3lPRI5}H*Vz2QLYy}p39drbCKxn$D1r6dRLiz| zD#){qITSmsc)kO~1R^#fiQP<`w`(`95o)XwbOeAk6V7bq4~tQ~1mP?RN2wwHw9M1v zz>R#`Yn@o&tRRqviq(~}LJ}>A(L?;uxwF0`iohF!ryztEP&qGPTCno{V zRYXwvaLrCKb&UtV$RZEK!r6PVcur0D5j@I70Kg$%eCq)(4-AWe7opf1w;M!MVIpx6 z+FwDuyE^s8@Uv>-Pq-*Cd{L)GW8xUe2~y}!z{6sw-)bbm19jZ&60~d8lC5bDB7`=_ zE~481!yxA)fpmi_;QVFbM7XzX4tpLEiC;vHIT2qk-H!e}dSdIwlPE?Y-Iw3~6ra31 z7F`GTBS#NLsK42R!x!LBsGe7bqSp(rAT&CfkUJfrBC!Y+s(-(JNF&sbLau~`SW2fa zE6}1s5Vo+7(MiIQPGs4u#hgO_frD6nc?4-E^qfqNLC-x$DI=jnA%_?kzQnt*BfwXW zyI1nrGRGH-S5BmqD9P)29jiB|60QFvZN5`z-?9~c+PDV$Su)$ZQ#(u^KM8M5nt+J# z0AF6tV=f+6!aswfe9R%ls z%S<)JjkT**)3Cit;Km4cdMTtDllu^XI0Ii(in~O>ogbmXL)L?39~_7$1}jE&_$Q+2Kqka94?IYas#a zsB0UE<8l7VC45dSDI?)jrB)-{1S%GgcLFZeO;l##(Gqtf3|SVzQ~guWkoUniOTWd4 z>Xk9DX;qlD(b)fd3$(9O3rF^?N8=thabVp_v~AsjJwnJdsM1B1tb`3~7huPTA#fEG zBAob%Cec2PGWbA3y%%-}7F%n3nJl=MpX4Y%D?^=?vXE&>;y=(xNqP}fQl%uWCVs(e9UG9 z!lsx!cMbM!ob16Hb65xxzw(Hhvh9k#4pLc(Ns3L>{wjw_CXC(qqGw=4)#X8Z)H zZ4a4&4H6>zDL5xYAf<|BBVKX@vGdcY(rK{bST-!Xa*6bpjym1@BZGF(+Hc;+4~u89 z8G;0PgmE0ucQ~PaomfZ2rcb_HfWBQ?Q0x>7I|& zlr-Ov;84#s{U`s4gvz3%%07Mitei7v&WH!UCrS&8o(qBz$0A9x=(T_K_{0;4k^rU_ z8n+fpIyttSMkF^BCz^I8as8=Fv%Qr}MQK9hShv+cq*odAzFw$f*o2P`q#`57c&{N2 z^>|Yr8~;#6(omO=DN&r@a#})Xv8f!TN3s*V_t1V4nw18%pGRW2xYLL-^;iY1Jx(sB-b%%;^~W_Ph9T zehqXSmPDdWK$kwRl8i_QoDX{;VU0;m?|nLxeSpI7=Byc*@bT9;dUgj@(SM%L>?9x` zV?26k2#lB0u;S`5xM@)L?)D5p!znqb2AV7aj!aEdcom{~@2xA<#0vgW&wJ|G%h?b+nsp)~@3)i=dDOe5$fAnHjz9DYS?RH&9&TXIAkTxL6gOzI7WuDynH>o~X8op`dzHs@_{3 zJxdV3XYiWNpSyx2gFl{o;}dFQDuN)MBt1#+&D4)^;Lu?lyOhjs%tX9r?;;~1t3UbR zJ=Cq+1#k9kLy5~kqdJPvqvAJm3BwkHD0KnS?`A^l7f6ZL1Ful+$v2#XB|o3uC^c;} zHnC+-B(ozD8hXWCIwN}Z>gDlHX=%^d=_C-XHV^DShKskZ5zQKZpx>;2uyc?7ZGGd}D390JLXYcM@CB04b@UVf2l#jc2?ndLr4ai;D z!j!heiQ^|xjY!KmnYpOO^Kbd-N8*!5;%?$ClqppiF1nHhwy#R3!`v@EMG#diH>II> zAX~*L{876`S!^Ke9d{H$V=JOzeYS)%W?=cMMbzCDsNJY7Q9yg3U-#$HjLmu%&Y6pT zBVNXkUR~j;QWlwMxhUaBfMhx<%nl=MuN-V$w+7)s0lZf>-lF6&@wd&AT!J400Rb6E zv3n6*-`j(g=wd&Rom*z19wEEKqXXDWHiy^3ZfjKM0=(D?LSZA*Ap9!{z(QQvy!1>m z4Z5ePf*GvLGN7c>Q)Sf1wZv*nV^2gvlhfsFWxH;rJdbKH+w9SkWn=F|VJ}*!3VYnq zbPGQ&lLaPhb%1`?MpAPBw!yr0s-#nwwAjJJG-i@9^hGWH|1&kFHN1OJo*fsk& zs#IyrIXQ{a^*h0S=LA7R88IQVDjDXFkPtaOn79tjS~rG-^Oq|XbI*o52CAlHI5Ng; zq5=Xa@ule1xi^0Jem<^dup<%YBq=Y8%c$_&>*Mg>6Hg#;W_z0Fu+_9jQpoAvbrG># z$p)gZ@HM6IE{XIBe-aS8RM4>25v#e&M{M#oxiP+;{RQ=XB^uVOLW7qsUp9#j@X-_B zKc5ZZRM>khm3<s;2up6? zK$X}EgwiK$KCe$npl%zHZyEE%;r$2DxM~d~(P0p*3TNQ*CWD;?+>8E{C=7=3$VQ1M z_miR^6=>IJICfp%gNBV7A~z`yCCmDtm^vIG1bhuEQwRA8>Cii?Ge{XvY3RV`GiI_^ zbTk_s8S%rabx6<1^0aZ$u=%NjDqVpglPYN*s}>t#=k6V7)2a;y4jW0he-j%WS>aDN z^gjl#);)-`u(;@jNAdW?6NoUDl_t?~ihh1}K_v1uTo#IJ#yg~JrstxIR5WUpDQNie zJv*b{c~T?Q8%D?37)j(jImpRfwnDZd4)C-*4hsu_lCIa|)ZYUF{g9rT&d-Ae_BGV6 zRh!*G@)%uLQ35!SP7h3w*#~iP4pd|lZz~N{72U#ax|HkJZOHXyUKJzfHd7(-xa%>p zZbpmNE$RKD`&VoM5`ixX@-DGYJueW*Rzh`7BBc$*c!JcbC8swqa3{yR%l6>#@dKz) ztrkBkp{`H$=>db?LdhpomDQ0!&@=90W3W#mqV9AJd)hScCPa)Vi|S>tghsgSE+hBU z``Hhb-JCoP|J(%T74}zFRw7QEzd~=53;jBD!y6-?L$w-J*u%S!oxsxYF#~|lb?V8U z5W_qzq8l}-14B+BnzU?3!1!D!@)hXVyAM_`Swi(I5UI&~as0sdIG1o6{%UU$&NZsA zE|iQZ&U`T+-ir)v34c9k;4sWx@)bgS{W192QHyr&JhX^;V1jNR$#~)kL`BSS3B6Pj z83Pb(faoTdV!)VYI1ND(fs07`pvzHsg52~#iRPj-Do9N1-$jpAYD&VrjxxT%H0(`` z4$~zYf1PO_8aAGy5zc1r#iF9wM^%e3s#*bzVVT$_COs#Ec8=cD;E+8|aQNgg#y?0f zlo)!tMt%GOxG`-|F*s>tlPjx5#9gGcZF~s`Om7=)BQ-rf%-Zm9?DXrG8Q}9pP9X_~ z?c{`#A<|kLBt#eQ&uwsG@BUqAR<{W|C9^L%uZ&ws!mW?Gi<>cSVolbEQj{zRFR0(V|7{(mH5S-MV#; zaMXS99RJNRJK{okfyidLu#B41gC!PQbev{;9Z%5CK~E5)AB@UTTCjNx1zAnsi(GUL6+$CaC3kjMNX z_CchP@5?};lIlqcUAiHGAygx1-19Ol%ziy{>MC3Im8A#A3U5Zoh5hNYQSH&vi(|@X z08Wbn#wT>l$`xHs)k?NAr{SB!W@bK8E8h#G=g5mThZWtscVOHkiRmmsl$hN7Bow>V z#uJhWkg^vn`WBy0n#Kmsfyg#!*b&GV!S(4qx_OShTG$4P{f3)0YQ?D%fmI0`=|~to z@5bPq516~}vBBh2+g$7r6c$^G>Hlhc_}LivvyI`9;Ug%8*-VqYSZ*cJ6-!lC7}=BN zFG88nvOH#>)?LU<0X^y!t4yzz2^TNMBhP*p=T4o%%9$UcY~}h0Egp_UN+utwiC**u zs@UqvZm_ZiVkV`b3mHtMv9pa-GP9>6*>bQTM)6%l-^QfLmwnbM#s&bl7O@#n0IHR0g{n_xT`j`v ze6Yd7gD@~fze;t3Cfq+qTwL7se?Gf+)V_WDP2#BNQ5<`Dc^SlG(fNyhPrUYfhSgV2 z53h_|$3~9ICKZeYxXGp^G-{oqJ-XOLt~{0)#??nJ?SiMCqh{%5ffh zDnBjz-);-hC|;l_H)_;qzkm%AeauByF9CBT(oQ%wijxSuFVPNq$&w`lh4v$k1uocg z&po$5^f^Cp;6TH)w6xF%fAD7n^57d!%CTN}j3|=b^rtJSq6k-~P*v>o*9)II(_A6Z zQ*?;kMZ;JK7bDXqbWEc#kb~v1JzEM>LZ*K>o=rmXv0>XGwh;B z$&ttap@F^f0%=edWTtcR+(=JOpsL_aS1-@a+^#~ZTpEjw=Mlj$C3<#fjjcayfIiej z4(Uc}7TZ}f2BTxt-X`+L=(VvhUBrvOSFA!^6tM4~-NigGlP~t|I6@PGsuiQ!7TQYe zO3MvMFB3cUh)DFS1tv@m(vTJuD4^PCSMbIu6&YEeWTKix$>X3zEgf3|r%o^s>g7TL z&zHvzX$ocph|ZZVJ0%&3&6iDuk!{52R|a6_oTZ2gj6_-r-Mzd=Y7$I;VTb47I3%Av z4WAHtyXo>#BZNLLQs3uUWbB=L*`8hFRmZRr<+&DHsZyKQ^h0mNVt3T-)=>r?u!pS2rpEG z0aipD;(fvBi#=IcQjl#Z{}hF_}9RK%x;|vV#ZrBf4w}s&g{-@TH45 zfaw|ZXxSM-mh<-ugrOh8wn#hoU|`=~nEKHaRvY>=y6r@uzaLWbZ%`d%ynt$ygwjpI z>_;ipxZ2!^&*a(hMF2fq&T1(F!6^|RQ1BJlU=x1EMA5jG61?8 zJSi^@F;~ngFj>@;M7i*fh=P@^*b}cFflpLZ7;|o-M5&5s#}5?~Yx&4zo;`&F!j|$6NH!J)_dm zYqW*TK#$6-Be}o~V++-&1ABG@z5$fZxy+f$gFBCLrn_lK)S3}gtc)kqmuQV7Dy{*Y z2l!^v#?eEg!ex4Up6%PulVv;oi)q-LeU~jL1JJleWh7-4 zAUMDqRsuWZP%Vp&j`9#&nb=}XV6<|h(+*-nVpMn_vT`UPxDh0jP`*BtCdN!e#?@d1 zdKdgPL7tR~@}+CRi}uQ~BS)En9>X-2a~^d_)R#z=K8#4~kXErOv~(`is@n)-M-IYE zW8XzH)==C`Hsdmr9^xM|VN#ovI$-db~@XCbIu(EPb zwBdA|KMMcwVpMb7BRBlj zMVWvdR>o%3k;0otsm--}?Za4lv%GlC*RW;N3IvuagMu^r;M1rxC7)8lzel=5pLhb1 zE4&$f&ZW7JnWyAO6^v3KBO`@*U4;l@@7MTC2jL$QNG>U($|u2Y79qt|s6aj6 zO1G>(N=8*B$7C>*s#rE{qL|q7kY}DlCWC3IOws7lwFzSfOxLG7Sa$5YmXi6{CFBWZSDJA86p5+sRto%Y=yBr&~Zzkg)(Qp&* z+_{6V$=H*eDiGhZ^PZ%XGD4*jpM7?4e+C>Wk(vJ`0*Nw}H-RK*Q#n$o*3lEkbF27$ ziIQu<2ztt`EHrDvU?>gqLX(wt8&z6LO*ad(%=E|^X|o6yb=@kp_?a9wDPDo@on6*g_#2IALJa`NU#X{IR2qcGDR^^+~7~iQL#SJF|-Et&&l_@}vG88|8=F38^R^QW`nA zSCMCC|9GZ=Xjx5o>-HV0cnp#Ss}T_wh0M$wyks?k!qq5X_Uyt9$MMCgKJfQep&*YQ zBO-*zxp7N3sLzOYE@DfS^W=(Yd{)Ab#=jDQ*uVD}3A{RqIgx=*Z`u!Sn9Ir9c&a%H z4GEC0TBn)bG{!9y%y)?jjYV!IJ%DOEECxG5!%LztHyd^$uUMIp;KRnudEE4B+I9{~ z058_g>-_1B)cV1iMUMwPZfX`%2?!!5YuHtkGCI0@wSj6}x^f#Aj_*a=PVMzByHN^N^cGU3fQq*K@Oio z7ia{H_hMn8tTD0CD5Z8rHR0&~qclQg4CYC3;p{o6eHFNPYs<|@ z%}7N=a15d&im_lSfP|2Y(`ODa8eNCp0|TyKy}<-TZ>m~O5<(ur!!4A4w_srvq>YkI zN(aG=FD5aua4}uKES_SVVBL>DpmBpnj5latFQK5&1spnj7&R(ZL0s_?xOVp%YS(Ox<45;-ih}G+`N+#pgck|K$yh{-_MP|}R@`I? zy3X659xUpElyceh+#El!pZ1I|ROT#1F<>a%rJySF!~BsL^WIu+$|QX9#VpMIY%I3y zJ5Dt!8Z&QQglp?I4DQhb3#N4yaV5H$3vuY=A>^grVa<3tww}I-9eYWbEnCBnZr~au zq~+6I!MKlB;Eq=m7R+DEOxlf$V<;Y|dlxiZV+izl1T#L`7N6?KA#=nEt-yZpxkjA~sc;X4foBFMb ztuZ7Tx^!6@>LwA0`fCXba73b>jFEB&b#b%7NaK_01>+Aos$o)cYNa}uHUeuJsDAme zKuF@wWeNw&XsKS9DKvR@oF0O*P#dqgoCN`*Uq0qkQZYqEV7Ef8c&I! z!tq19X^@i0=rM9qB`G8)J%8#buT6rVf1^mJiDh^8Gi;w z>F}V}P~@ByPz75sYZl$;Y8*bXAGI0{X6(a`1i~tPIcEja=10;V(qrE04S2Ujb!0?E z;p`13CXD@nYH=R=4jxSnfZXaa8c#fdCcGP9V# zNFCftmt?8Pk_e5dgl+4;rWA-^D!PmKPsNa)ejOGai?PxRp!S!cbWk|1-^@l>1d|)- z-_K^G+?;ilwvrj4!TzjsX9g<+Y{!qDB2i>B(k)@W6N7c+#=_W_yUi$7sUZuO0@1!p zf7&o9@Y-^o=L<%!vGbUUZ^Yyen_(|il8?XKd~Z{I*Z@HRURb|zBU%i8hY6f29J}!W z-k$m`a0p@%(>DdO$zu(LIVmb+(C`Y0Kaht_h4ENL9Mu!T)Au^LvX$R56#gvub zGeo|h0B2aaa%CTp0#%gKRCKPQUMNM+OO`Boq(OM#%1bJih$hYy@u>RQl!#p(a`6ZDwhU1f0 zs6zM$V&I4o$j@f5GBh8n7B9u=_$(G#HAf#po8C@H#_gL)I6|9h?!uk~o>MWcB>*la z71pBqqGKZFz+xq^?D_>nGCNj7$RH65O3q3nGRZ}Z95#a9G%0N=4fg)Hi4xXESFZ{? zc5cJ@v$6Q(>u2bt5}Cze7&H1EG^;EYgY>B#Vd!DygN9!?-cZeH6t1SU4n+T0ef~GqWfKs5ksHD zU3$riN9j?sQUyc?#=z03D*EQ$g~=-h;eo|4>GRJKLJ9Z$;Fqvq<q~b~kaNG#EB$1b^1V zz#&uCsS0DG8X!@TN#b*kLmPJc>tUXq+UPZ-p05`9vTesd&GB|oIF&C}cwe@WB#N13Y zZ`O>?2nHa1?3gomA#E@jYSm`F{JHZuPTMBjI}{~COXB>^TTIER3~y}&nl^1tCkFWy zvxu9vY>(2l%VN*@1N5zhQu{Sx-|j=KZ()r;aRg*iU)F_e_teQash-k@4b|nV3^YytG71z~f;C*4ivZ!t~Y#osVEY2(l%S71TPg|l!{KdQlCrGx1= zIoWyer}IL_?-ZopX3iRI3mVL7ia}8ala-l`EL#fi(}+6N8=`iFideg66Osu(TFKWB zNtp(`(w{(YbEcy~Y-N`HZl`nYUM~!+1pU(J_&`U;<=mRO=W_A|> zh4(|62U8ByZ%DnWJOf?b0mvqVkjSTdoW|dpK&n-)fw5F6#;n_l(|ea-=k}e9>PBJX zjx~7a^(m-Tg#c$YBd{_42-a-cjkMGxoV|1zbG}}NsSB52$*6W*xp2Jk!A9nb<)D8|ZOobT zIk9eznMeIU z+n$WsU(IDvk`J!lxq&=QHaK^>fnv;eR1GW zJaomX;Lq|&f<3K2XYXWK8wn3+X^&7bJ zXxxT|mqK0+GjYi|ef6 z)YW%+!022SIfHUCoY}Jxty_G-w34xS<@FIrx=lAUlOff7uM~@oO2o0Gl_1-Pm`&?j z$`5L)OiIRVqC$eGYO#Qd@ftM|QB0JG5~^S6bR6hu^8|CZ1xEQWMv;jP^IoApAOh`c z)h2L)7A1?bz-iXkC|4mC>37mej1G)>aTL8~eyCct6nmab;$xA~hE#&!tgP-Yaph%yZC)(canf5{ADIvrT!A!Q7z6eW|5rOVSMeU5-5W)Sx6OvHFMVgzt@XiIJoCv(c#Y?1A{u^@ZOF; zd#&ing6Rv24uAI8xocO5zh4eo8lJIf^X6Z^#ek;<^XJU}f3H947ykAH@~9W!>F+<@ zGw_r^9`E&edUcO@2A&egBVK@~KmT~oz*7Qwyw~S9ukP3EkKg?8(>H$i3_K-}-#vAI z?Jo-Gr%|Iu&8$+T%2{!zQBhHeqP4)}$&<(ZweS4rclVS)em)$IvfBt->=;-JKA0MCJj9Z9n64yI-?%d%5eT1XD z_|2`2PFvyZyUseVFe*C6I?XyMN%^ zV#5opu?J7FY}vB@MbC?fLp(1c4sl$RlO&D>afruX<{^pK{@oD7AwDCBWBvN|U7mU7 znIEQ4pFX-mg$fs&G-Jun{Z+Vro8#J$stQ#KhbZmm3-ynzm}ys@`Iwi$Bpo=3m{0AP(_<5fsjY zO=3j9jH35nc;SV4;;-mj4@SU?Ui)tzMIM*<6RrD%1Y5m&b+4lDiw>NO#KM7qci zKm70v+b-vf8#ivUP^0S9sdH3F8Ic?HufG4^z9(|Z#9z_(g!B-EAfET^*>jC}6rG^N zqZp41afoYqN+4nu{)R*3K?!WAu&~fHK`>$p#AE&X^$%rcW(GaDq5p={bN`l~63G3j z`1>3P=^^e`NR9{ZT1b>rr%qLW@U_4D@lyi%yYGMp?!Rx}zAGMh`t*=9@RUHFZiD~X z3^;?zx@DPHB>%G?{1blYDS`Y6llb%$f87~)N+5sTwS9VLf5HqrC6GU15}%&puR8-z z3FNQ4womWuPndzH1o9_L;?q<7b!Xryf&6vX_UWDd2{Z7wCJ^_z^Od6Nb~#s!U2QA% zs*9KFlxDkvHtc1nNAapvp<-(Rxqq}_?q~0zUX{`Y;h$tLSM+)AHKUi#jj+&Qqgzsd zkH$}7+h?iqgXz;@$~GCiHU7vn6c7QujImjR_H0k>Fn+UQBRlPyMXz*YYsM$txi8+#Ds(ss*pfNKXffoVR9tECmLad85LTPbAZG(o1)E=bYgO#9A+QtNM)nnD zb5J*Xdq@r9!%xZ(bN;Wc)mf$1Il0^N*tmlK)&wFJDzJQlJ0HQWvzd!o8CdYuyO30>1ycy$N880vmgSyp6KuyNZ`_ zA^r@84SAid4@8qvC3~K1heUd>Jz9r;y^xle$~FlOnDUP!{)~eZ@8)^rs8p>Q^kG`K zG8|a6>@~!dWLGWHqLod6TD4%S0=Ctbl3`37*9=YCyzS|}bt~Zldl|mWmeX!_$!de4 zgU0Z;*m9fq((Bp&xO3|YN=28#(#1<4D|RnqK07)2T&qt%X2&ZN+h(h=X2m?Vo+u|U zvan_MGPLyE#pCne-d8FkwB$HsMw*sD+huqmgJ4<}CT zK$%jtk;>*e8ut1dKkh>~oD!^Dwh7f^TOiE|96P*^ovUobh;p&fW)SRV9pbN?K#swI zZ7_stqB(OLQ>~EfeLmT2zsa0wA>+olT9XAYxQmmM>5u@I!1mD0&1o%h5V9sP~ zHU;}Ex^VgOS$MO%@4k!iD9#3=nF)!o7MKv|Qw3+(fj2g`EKXfM44W@IXR)QW(VmGr zi88!5;}w+l55fz>p2G{HU%;FhGmxK`&KAyfk(HIiR&6RQT=)}m*`!B8_HgO^8TJCP z;oEN)VbStcZ1^c=enT29KM>K;qdbbMo{LF_;7bl{eOG--9(fZs6H&m9cu=9%yyhu;jTB6I+R$ zZ*^F(d?kVcRY=WFgG1_K0~{S3E*JKl&&FNzBDP%%VtcbBcBu-3%c{e6+*wjpz1(z5jk43Hxu<1UH9$}MJr7u!YeKbwS@tzU8BIv`QM^ui}u)a;zzchW}ift5^`@hiPeaKgWpD#R`pS(SQJ|?>yew8Llsep zq&pdyxpD_8R|rQ!!d+NRCP-xLbVWi=;^tkm^(?AaiDEDL0XHv-8KKL7F~)N0k1JFgyb$nowa8#6GtiS)t*!xF3*n0HAXBgvo zmVEEEv+v(~oDHV}%EW9}4 zldi&^Zz3nIj`*`AKR<6_ti!^7e@dm2{mSEzmd6H~5(jJrZUk5EiR_e(RJRPYiF~Qo zvpuKW3cXy7>nAQEsB8?B8ZEqJzEnr@JsT*$P>INL9gv+on_Xw)P@T5H#zn6~ugS-i zwA$FU@qKjb+Zh$>G-jhv1&;4Hh)(0?!ltrg&x|qbb?yV3-Isk3bJ#{V3kOe~!@*l7 zjO$a4ec)9H^owNAc_(u2<|Egwr$fL@HO&ilQ=X@FTZQVexOh7Y#>@;DGI9}8ER?FD znGHpCP*C+cdh7`HCFfyG*G5pw3Q(hRJ=AH`2;(MwiyKFF@o@{TU)+H4ufL4fM!o;ZNmj!T&O#G*o!pDsb=$EwED)p? z{R#_dsN3OSPx1)%QAg%R1gaw7u$!@G^#o}30-slnom<|)yYI|rzeQi%Jh}@hygoSz ze$t>?FdOpG@mmtRjeP-)sq~9U052C>H>m?HIfXa-5n2me$g!uBVYu1XFdfmc-Ei#S zOjIme4hoeo`!L=@=B{+?J#rEgrmw|;%{!5o84nfJ$U>@XUR0r~RjmRScbHVdZoD>M zoQ=PO!^f^5mdv7AvnHG~4XkXZ{qmR*w83OhIP;Kj?fPRt7XQ42zcqmfr>#_OK}r7t zwovBg)<>|vc@9h#1MJlMHS|D93+yP=xS_Y&AmRH~XByiV=hD;VP44fHl#E2$DkKu8 zF9MZ5xXTvG8lKa|oe}62h+H#}%MGc~d6O{g$j)*iA)5_2*<;=5lp~9sZk6P?O15P7 zqFsU5h3VNc zEhT~jz52b2s%0v}l$8%J(STE;flE?|>W!Mgnx6&@n}WKWO7?|UK&qyJ&U5HUL{@sM ztQI$~pDtuF54ldu7SjGO+mEAc<%*PoRyb^ea40#Y8Z@a{1AajPaIw$1Qcb&vG)p>$ zo6Lf`E9b=xjZ6+5Z5XS~N&-@|HMWh+hJEKrj1vB79C9)M8t(KS1_t{7b9X)lM}KPq zsamHA7Oz}@h?uTW#M*KG_z47&^L@YeN8Dl$?^njWj%T0mggWt8@WSCc$TDPL%=3*f zYUu0e*zrYVXQ$)GZ{{Pw*Bb@i-ss!!S*#rYJnD6S0h`wUh}S>=0!OyYhfkm!`_9_% z%BZ2(_v1Qvg~YH&`atBQ#bbOeC2p~e^6G`hppK>yFY`h{fsuROLL#K<=T@W8k_#<2 zxZ7bz8h_L2!=C02H3?G*tIG+C%fWu?a!RcNNBwdg=Hi<(gl0DTiAo$2{nl~&upSmFNdBz%=0PL z^m-+w0zX8_;AB_YS~Y94S33!br?Fb8l1l7w@%6)d4`A=s@3HgnUbLf^FFh}rUb!@c zgoWYyjTD51L?EVE36v@wi}${mh{J~tL77L<{TPiWo7 zP`6r1`1m+6VrVC18ehN}KQAkvK^(pjadBCc}f~58Z~c+y!^Wu)uT3E`D6*zlGkzM)B(IW{0)3Kc^>?zsyN+| zR9UWJ^vkbd?%dCC@p3%!3?_7F-HI+)3!F9`dNmsgoB9@cyAt_~9;MkzU%gerp3MTaWcTA`b&kqH{Duoq0A zIdHF1jOswou_;h`^@Op|04;fD)pi3Bz#iziG^T|iUa!RqFiMQ@2GuS8wdgU5`m_<$ zbg0VM(7yj58oM&8C34yZTC{8ZGL36W0IDoz#x$N8JO$a3+o%#;4t{&&q+0qL@l8=VCt8j z(xrS0Nrizp-nJ>iBEr$QadT|ld=ejj@fib@8Z__P8S9p=qmz#8K`uqUGXqlRMXXx% z9V%6*;5m1r`t=zcy#%dV4V9M<^iBtS_*|m z@n&Ch10*UXRVoSmH5$Z}jlj+8Nl<82>?7|&&6fRf^3Y*qrYE3xw~l!0wO7$$*>1Xj zcOw4!a%lWynEuHGWYS&>3{+y#x0|tk*A9HUX8ThD`7>w0YS2=bwZoWiC0FFiD$Pv6 zkV3&Qu*>R()Mck0%wU^F1&5j9-%V*k{oh7|_}D=%1~&p3v`7_UfXxVvng*)H1Oo{~ zK?6N6BNIwrFFwzNmMTwZ@zNxWT;!4CIvxB?MxmYbV9B)_Xz1N?TIkuLp)X<$cB(&Q z>(pLyNi6h;apPDD@{!MTm#JI@dM_H{RBZyOa#X5UhiZ}oG+$`j$Z+%W9h9p?JAvO3 zk!g?nlUfZ;11NZIsZ0&ufHJ7pwiS$dXVIW`bqw%H!I!-oVrymt+CgrlWtHdWTrgAJ z(a-^*3gpH%$x)_US$wv759Yo%65(Ow`gS=9mUCzn_7GJiXRh#2z=x`1p`RJ;2aJO+ zbvG9Ym@^Cu)hnx|fHqbnq$&-v3k%WzrB~3sQFGi*NJZz4?eM_|lhC(Udkknf0D}gP zK;4$l;JvAnslovz<3h-=?09d|S9k!nKuN!$Uq7^M)*S0M?Lw1I-J#+7JWk_@SFv0u z;9_b#DIlgoD>P7e=9eZcIW1R%98SVTciHK!(om$6Fl00|WlG^uVpQV%c}f!r3QR^C zl5|h1q{z)SATv7)T5fnF_3uzqAPGV3Q7cZJJc`gDx-)ZgD3MeoA_epTLEQBD6dE=f zni_hCxS^dk>gjS49wnQTT$P5kotw@-Py^qvaJok7+!&FNBUd!t>GPes- zFJu+udG5naA|qYUdEh3k(OV{5&Ln!W0MGUNnyjeFd%I&$!0elgKvIy^um#1+RKt+B zUc{93XXtvSLx7(X64AiltKOhKYz6~u7CQ-)2E5F|$iEctzWV}7ht|T8i%02oGoexA zmYlajSg2wt1N`Y_5-x8yPVL!^QMLWhX6#ga_~mEN@i*TX_yQ*R`9h)dC6l2mm@e*a zZ95{%n2&mG`jAn%v3Q-3g23ReZOF_NTn{CdFWZ1#9V=qT=6&eUrGvJtTH$Wt0~5qKNp0lXi$o;iUF0;quU{ z!;LIr6Dhd`%yp6=*H}o&Ly2N@LPxd1#?9?by_y;tEHsY2y>$rm5Amob{vlyBWKGo1 z9Y{+~W=@n65wS7Mrz(Kckd3&~)o|k2QBSBZZYVip)(Fi{7DU+V>z;xI9uvT6&1a4(yK=1DhYbFVowv>(xLc~N|wC7|r@`o(ghParrm@xBm zIMsSgcxNQKb$%Z4mv3YAh(YjWmcjF*Uc!6h$0Lhw-yp_tibj1p4~RMhC8fLPC(nIjeEw#`}KlH;P_+;t50~+PU1+|K+~i1ZiAAx)o_d zIJmhSBpM+(45St%U(?cF*VC2gB0C_mB)r#FU|z<|5Nd0!XYt zxl(0t^V&6p6^lSzTq)eVeG6qPmGi8Dl&)0=H-_0-Ktf@_k>?OZD^pWF;~;HP5=jx1 zV@0>shk)r+yQnfz@nXyc=u{&b?|l3zb$UHgGg6S9pM{umtq{e$D-*eQoi?q>Jp35H zp|C16)78opLA@J=R1aOu^9rMSN2fH6YYD!Yy8?^mFMxM=F|1s=2#)+b{sv{V)$H+( zsr9tzcrB$XR-k&Qfzz&oUQLPS<;1M1^HDFRJXUTLhQ5hvF0k~QuW{+z87OnELLFHZ z1G}~L5SWtL(r$XxTy#|z_h+1?RB5c;ehvwY;rLLhy!qnLiJqJP5B?K`AU-A4=t`ygl+kl5GhLI?(orTb*2Ass+;Fl0 zFE~GbLnu~UUy=>Euh1adbZmf@?Jh%3)zFm7m)f393xN$Vf}2k)KO$ zFJ+1aef{}HNT_%F)7_evUjP+dmBAswR88cJIaoc$yj&?~QX-9B>e^1)78S~r#WfOx zg$8@Anl*87&nBun5hU0=WZY$%3X}HKR7KP@YK3el5g9_8g4aeDufr~05x*BnqP$IS z8j~3B(nv4gfZjNf@}L=}rFot^fZM8j(lYNeN! z9NvvujauPwd;&(y`I1CLrbGGYA~8Fe4&yEL;~dkWAorrZl7|`%8hY$EUj{>R$#4>q z6PRjph`N3-R;^!!sx`woe>T)D7mQ$L`sQ$c0~$Y1`%H#I$B!_;nomheCPn7NN)8`0>L?Oi5xC z+D0{mMkCd)1akj~&=6$PPoGGs;_K&wY-YyVNN5hGnE2?qd8m&|$Vn3tlHl)8j!U9& z&^;O*8i@Ftxj4ogq&f{-F`jY;CCimZLShmLDa{j9%()&bpj@~^HKQf!LJ!vzA3^*EThZS-@ z&76~Z4eP?hdvnq@a?l$V;S)}yo*UbT5`_0Fu3xBoHmawhR>Y8RW=1jziFsTDhYUrB zUTsmPL@5RUk2701i;SdznY>2NZ}`(z%1l3iDm5xX&I@&$)S?P|j|tqnyGQ^3 z6Hg#QEpplQ-1IE`QE+m(`CXJ8auSD~wH#KnnVgrk3G~vq>2YGDfge#pMlMDT$@9K~ zo*8Q4D5P&+$3(@{j8t^%(Hra6{lLhu1->K#@d+taIWu+l45~jWda$Hqb_Mz3J6deq zun8SHc0loBC2{%u1#Si>s+2Fsjm%%<2Gi2JlbfAK`{O1`l`2OS>kKNEufm)!PbL)f z3~m~D9h7mx!-~@7o8Q|VloZsa?hltpp8N-K$mpVeb9i5>J2r#{M&O%;E3s_l26(HS zxOF`RwaeDQwVNj)r^l?28`z;RQCSa1p&^URz(AXX;X+2pgMy+kZ{Y&!{_kM_mBR=N zcA|dmA&iSuNA-@?aA5hz%od11T51BqqkUk`wbB{l3n|M1ToNw?@%{~r4f!&S#7Iw< zkAex6RKb2&@e{Axgb?2_&Mj47y5Ad8rMttNt(2=Nl%N*m?>Wh!{yhhZmg=XJ((-W{ zPdtH$3O@<;U@7%~Gu5bjyN4+lQfAFk+`H(Vp`(V9MDEFHaukqo82Dh8k4(hgceshQkTG_mqsL{_7M93T9kJ8M&&gs0J}iWswvb7LjJ9yY%Jn*!NR&CrcPR}5 z(6wtvMxxJ==v-*fq#3`*LLzR;qsNaj&4W^l@sXg=3P{RI6(r!v@+I44!IQ zXer)tS%ptNoQU@r zvk+7{Z|P?qk6N7uH8J<==P>BG7tpoE2%O#;O~Q4;FEoPpMG>rXGAE3lK2;P7vKiNr z8kv73hml2LG7_hi@g_S9stO$$NIZEBbs6Vq-LetwopyM8{6}OoTp!wSU?y_`C9|DO z!kenHnhqC{;_^6+C!Ror{;%TVxLC~N;^LWQOfeC02W~Pa^;;QLFH#B=76-jrZtBNI z=;{8EE7VkZTr5>B!)(<8E}9(K83o)Z78t1Jyz9 zIkyJq&z+|cUy16CjBaOMCp~3Mf`yIIbSb5XkUlLsHp1ABJ&}6j4Ei*zjn3Wsz(Tk6 z;F^o6%G^TFGS%_v*?s86D0RyY17X(KaMKcvLb_rD0)pvDN=3?+3ruYZgDhB1TS11% zhzP`%D2aAGUqCRucQ$4*PhWo46GabZEN1YFuOgSWn3s1D-g@)slj5fOH7AhhJlZg?r|#_jhS;OR5l$wa8%XO>68eLMy)1o!5A&J?L3d= z8&0D^qZ)`maf~*UlWH18Fx5I03C7LGyqrR)=zV*f#uHB7HZb0%grm&MP%6U(@*&5 z7-TCX0nl;4Y}b5xnHrOGA31UW#}6My-A0W_APgqb1TJ7!tzJzvhyhD7 zVP*j^MLakhA#v4t6HFkKWkX62T4-2FPYt=q&vF*hbzQPN<}aOzU|(O{rG2sXR6L%2 zVI00&{1aj;2zM%7v~(^g?QZ^VJ|arJh&aYZPXG87s?}?NnS>CH95ogf}QGi|N!w^81dQxU}NWC-At#K=C-?<4+ z5+?&XG~(q9h=#zPV?v%fA90$RCAOa^rGz8L5U(E zF+NV?i6;;_^&KO7EyWr)o=U#S;4p5Y0ERN#2*3vf7Fx_0v>x+&K_jrM-*Q`yC7S#-jT=8 znpk@4*_gDwNO1F*xX9#Rdg)kQA}5hB7$ca5ToO;teg$Xu3N^`rv*(VW(7v6=(N)=~)e!91@*{#nedv`6Mpi-s+H`KiL_#0DvwuG-R1CqHlavUzvJem) z$a8xkg+{7^X)Dpu1RhXxKUiEIPnML{e*I=mJ*tw8-k;qE_HwW2(6U8c^kl-|?)`hP zY4eY$SHBLuY243L;p{Z9g(L%|n~L5gr<3XIHpU0M?c7A%C=LbGIvLd%rf97A7EX#I z71hE-##Uk(WAPyn!?oLY5l7qO;>jIo(EJ%sHnYgQZPKbaB?p}YTwSS~1y)R%mue`5 z>@2wA?`ee#oVi>U5~UAQ*K@NN`=NVVDW*}6_L?|5R%A;v64n878Z-$6BnQiQ&!?Kw&M@4oU1Du(C~!m3N3)0a`M=O9G-o4NGBfqxmdk=FuWTCFl$OlFGUZyJ z=Dp-m9re-qdx%U#JeoAAi;UZaw2K@_QdZ{oP9wIg5orc1;w*QuqFS@z5O6AL4*1&kk06PNN5XgqgX2km}ug%A&AAgP4i8>;e29RM0m-4-QE9R{;x6F&AVk5#zLrj{u9+j$B!Hx4j zVa}R;d|ip)AgYOy)BFWq2WpO9oAEOEyCTTQ_(|Q`b$D$KR4!M68(S1OQQ*;uAgTdb#zK36@foT(atR#@ zw54?1{0~+UJnmE2X^T0TwD{(`Z*mf-f|5x{g|ma6J}PR${emGAc3EUF#`k%LxojkI?*R1b(1Z?z>R{_=Pl;~Z7A+nf zW&Gopc{@+`kkWTwj?$m+=cY3nXIV@MT=%_2@H20 z652gBs$`pY971$VG^L^yUQ8q`aG05N$yg76ku_8Bp`9QI{DX-vVcaVp(Dm!YxwG-8 zSg90zBK%lLmgkYGT1tl={a(c8HS_RX&$@VZ&oh$0O16MU`9gPZFH#Hol$u*6xuh|Jl5??eX#Y% zZFq6e08IGgQw-=|5oZsdL-Xo&@ydu182>KeTzSopdOYz2qGGzV+d@DCiUSQfk(3K5 zQrF$I8${$*YGus^{qh>22r!*Q=84+UNalv69ZT1wg=ic(OuZoY7RKn<7qMXFcX;d7 z;rQaKuP}0OA6#OkoKUR{R=+l6fz|x#MhrHR;H&^Rm%vwz%vMPhkD$W zZfiD;ZW`ELO6uFZ3X!qP9V;L@l~idgOe_?EM=9M-R@y|&ZlUXwu>t0cxya>d!6T|n z6kVzbG=!_5XXB2LwBbDw;6X;OQ60K!i-wI}F$Gm5xvnPiGmg*@XP}g7kEkKB(V#Jr zahRBWn`H@xFOwQo)c?Pkw}7cKjDY7*%Fr%S@Vclh5j;YP6DKa<%)YA(gc?c2g7Hv0 zrId>Zj^PCtphWR{Op#AxFqYRzG)b9+HXlo!6LSb;;S&J|8Hb;aZg>lgbaM{Mm9EO7 zGipq{9yRm5%K8;DBRT*FwlgP;>ZFs>T^AV2QeHc9O^IX_oR~*Eo_GSWnwdhv30G-Y z5l6$?o4UP}$HJi2v+msB&SP;9DM1+kn<#MNgp2ruhC03&H*VeJM)ksT1A22~vYL<) z@Jm;(vZC)i-W@j%2kBi24q-MfbCh)C(gzP6VX&j9k~SoAgBV0acK2)JUjjk z%o+b4G!-h*gO@=l)l+0DZq~UMVEa$UFlyK+dIrr{z2XoJ{6P3|0_J=@5y84(eDuYa zFr7Y!QawAOSDVgAyLpF&Ym6N+9muVvTbEukJ&9M&*YZhHKWWd4i*+ zC}R0{Ir&B3`L#!>#!B@>;6<_chI+lIr4ZcAOk7&=&x`I*GxM`lO6u24mJ^kAc5Xry zr3tqVnm2EQl#~RIH_61ZS{pgJhEeBtxG|KJLd^)H`PN5MQLbbxQ#bTzSf@U6Selzp zT`S6;i%t7SK`)j*m$i(9{UMM$RV%{haHHu7DCZ`TO6XZjO3sBp@u2bv%Og}9Vekt( zMFb}WYt~bmh*}7NDWy{fpnjXS_L;_^q5^W48 z?Hvh`A#L>F)vVc&Hc%wwIpvVX#KF6^%Lq`I$?;uKa(=|`4SA-MCqAR0s(0s75*jqF zLn%vy6RN6G!ke18IrXfGsa3ZH=fsQ#`#aE6<-|%lG-PsSBhbU01-(oDojda5eNEo>MCiWfZ{DN@j!Ulv@EepQ@5y0ijP%Tt>={&&U z7P{Z_Q~0}qoIg4m(pa5YscZ#`S>E6y9zP=xQI6QPYu9!C`}bdFHk&mC1qI&X`d)kO zwa*tXUi_@s_#7JrafsJTmo9yE^ytykj~+c*XT^#YeZ{7aiHW(DkdP3)Y15|mJ9g}7 zS@bB*_5MG`lqpkQ7sMgXAqeb`5QxjJCD$(`M;05AzJBsa7Y$Q6jZF(vO>E@2E*iQ5 z&`rYVx`bRx!bNbg^j5?~*8cE4;#jY-Xwf|M?>hir&!0ye+p<`{bvrYJ2|?Pr3Fdyc zmsh$M3qN@UiHWz#>3wKW18H=#ih?aYNlh;{KXrI7Zn8Yu9aeH#8Xum>y_|6p2?;Wf zc}sGQ1p$;MgkQt}$VQLw&`-f-c5^TvQ9`(c8X#7i!e5 z%hZoTj2Ju!bLOss+}95o7q6jX`_@>pVmYc*uZpzvbQXkV!#}DxJ!Q0r=q{F$(A~bQ zt|Vrdo`76jFu9t8$6!J5o-v7gQKST=}*M^iG$Vj<}0@kU>$fSJZ;`m72 zlu4w4tlzgY7DT7B$2N2N67GohnZN>2aozk0dYznBK*z%WbNh-d^FJLwBapFU$4+Gl zt4a_-y?XTyCnY6CimMR>A*!`R38Q#^;J|@~90!DC5K=_ECVFg((nprNy5r;H%P{R+ z-m+!O9Yv2PPoAtH>W0Ny<|-9PGEROG*GaCdBI25a5=PB*88cPKJ=^v%jzi9Fs;nOjC%M%b{zrV-_S!mxMqoHnX@32#S;I=-dh03Rc7hmPf1s`Rl7txuEYo-Aw~oz1b25B7-X?=ANBB^*Ft8X&_oIvy|Nq#-Ve)}N|JyTImDiV zXc3PACzy)JE@cP!F?aQIZ-22snis&yC!hSuz88j+Y-;|_KDWhTug#0Y-rHu2!(R8@ z*M4iCb?eq`lf5=?BSwsv)BOH_^I8i^Vvc$}zJnKSfheX@AQP6LTmq7=7UU`c6U2pm zZB+zgK&Val0*y>)u2_Nebkga7cwgpaY2gJKXkq56;SaKJHDDuIX7aNaW@G)wyFyA2nq+mFw6Ha+dTpsI05O| zh*WnBJSJ}?y-B(dVXi?-toms^zagf;b?w?+%wonAtYaSwYQp?Aj+R|}dZH2iFe_P^ zURb)O73+eSb3T>S#i`TSi=4;3_S=`8@~#p5u@LueMKq#l zPgJcF)o<&?-1=`WkXvrK<-vRIx#x~=zWL@T6YkCl_W7rG@7{O{YkS{)_uY4561!f1 z{q>8wcI~=(`t<2zOi1r*`ak~oQbp*B1NVGVf z0@96O|HhJa!&~wg9|`FiL6XKOziEj+Y0xE1Lgg21V}WIA=G3{GJ$1S|kuzRVUZeu@ z(i522ekN}lOt2uV-Xsv21k`^R2sV*Lkj{S=hv-O6sLNIqp?z zl}iN^s1+e79$up6e$XdNKyp#nH<3)o1cD)!)o18IJSnzr?>xtUsi04X7rH>mk$U ztDb@c0G+mMbjpPCc>{L5`LXpx=A&qrDB8e_M8*IEh9&Bs8c}rx5h9dG1hV9!`SZwj zJV9tiGB2A!kj{PgFb^anKm@ z)Em^ceLKycGmD)2E{r#R3>Pz~bGC+DbgE9EfmUX_Av)*W-|MRxi{Wj3A~$&>&6^il z8YVUrL-WTmhF)J9I*vuc`CTmPP$~!{fB$#3-~H})FCKmL(NoSn_ndc{_cu3T{P^*c z=gyrwyg4`hkAM8*!z}FL+S=M=$e!p~g2HumNzK1$+qP|fK|w*Af2#%J!!dWWF#7Me zAB782RLG=ks;Q-zSpfSR`U#asDtF<8lb>MLMhMD<7qi4lW@3Xe`SavwQs<2sssa7_ zs#V+8dUe9Py7}yL*(anm%NGzG--8Cp(0aNvwIvPLQex{U+OTm?x!PtXD~0pMp~bfD zETBpVnR`rLTOfyz8lkl-R%<5}QL-~ql}>OkjGdmGNLd_^r)oM!1+YU*dZ!|t+ht+; zG07~qB3QBo&4#u!DeCB8OfvQhF{!M;1jakxU__!pd}K{hzy~-M6b}E2#9I1>pk?Yo zg5s#9OTlf+AJ0n3P^aEK$h?fFi5rARVlXL0`0FW*mrjP`$>WdI2282VTZ^0`a6SuE zCb)I-DMzt@vk^Ac+C?F`@h2UNHuNYX)2EkTdq)r5^ROb!eJ|w9(IbZ{Yz`Wls-f-! zU3u=U4uwBTkvUuB8^3#vMab1s;U$8PVT=JUCZ#y+n;UOyYIexc0)r${As71_Te+nJae`EJU%|Y!3sER+O(;gX%PFY z*`KzBWNv^}JF(B3w_m*miQ^%{c&GK)7R&=2NvsAR5bVxfB}iikdvJsjsV~b^;h7n@ z+Q@{!4?vO|JX}Nm!-}oDb;qqYYx1{KbOJT2Vtl{+r}^3pt^Jf^kI|=J|A-0GK&Bq( zR09*6*hUCR7Y})`xC*`!5oZskS1T$emQzYIz+|tjY0~B`JG68QPCZV!ReUUM#Ce8< z7v=Ys2NGq%2bujI{EHA(O;WPjP|*<$h)nC5JAkT&OK{q$CeI`_zET5@t&e-WucS#g zX98{G_`5Mn$|L0p;PccQ-G&@-+l*v_MM*8I9LE>3_{Q+lE>Pjhd9+Wcwp!Rwgk2hS z>`=A(@Ec{FJX#BOtfwMNZ%xB=vI>p{4aeco-240|y6GZdaKMSfaOT~B9{mUR(oYsA zx$`!7UDOl9`h?J%g97{rcmMN(9-!L6OepggV9 zVQKiZZFd34R-%$%$OfRDgen`MqSq;hVr!=zH(v7>!&hRYnd59BG)I+&3>-}y!>fF> zTg-x+M3(EQspY`W6qzf^--UTcpbv!3h*cJ!N%EyDiwcs5S2sET4et`~IQs!A%R~2d zf}>sl3Lrh0!kC*iCC=%i*am!u_Cr zaxKm}W4-RD?G8m}-^u!Oy#LiN5TlwjQq?>T3ED)pjhZU*KCtUeLDyoAm|g8dx<^s} z7351N07v?$-5VnM+k})%0{X3`%1I@X+cNyDHJBSIXQod{eMEEU+LV^=SA1p`O=zsj z3B5ZoY0_ZwhN>%60aG=LbXe0!5hP?a57^kf-s%v=6E>17(TBhv*Mpx#Z!|J3s3{2g zwRYn&G+2NF2p~;J$|$~5hqhf{4acMP01ZIg+F0@su(9#6tk_+UB6&M8-4OjcwUr%- z1%i3#0SU9JjsbH>jDv+{igLbSs8We(Jvk?(b~xVB6${ues>8>R)7mA=wUu;XuMhNz zBhKrVqa%kMh$Ii|>#wFdW?dpe#elZ!et(Io5H_Zl-kms$^@@qcUq*zitRn_QohvJk z8jqQlk(sJTp1cE0fH6jEcIw@m#Sqq^zdxQleqtbi3~8WOjnwKwbg3MFBL+~BlHEpg zfBaTES$Ja)JDyTYiI|&qmY;X~)i00;lGU=%qKN1a(zXeBG>Z1H>WbFQHQInA1f@!X zA)5(`QV$&?YIZ)3yxIQk+fql0ITdQG)tc4ov}OGU?D(kmRM*jkY_VEnue&j&QUa6% zg;v6!NOcTuoc^#u%e>YDTQ)I4^4exH6^TY;CZOIa%Fs`<7R?80#++gzhe7}eMuwuA zhzqo>ILQ0Xj)c=9z;5|QeZ%wY~IiwW-!xaf%(z*L0VUQj~*H-!(FT=(VzLUc}p zZb>!Ba?)FYNTY`S;Nv8)*sN+{BP`_hw42^tg83J&;e1gYd+L$OOlhadQ@+9G$5-M0 zO-S_1f{sGLx$u;)iOble1l(Xe87c%uOfzQ9S2j?r8K_@>Gm)~QBtn7e6>nazt#r~# zf%Ir4lWc4&%PXB3U4-fC2NYSia)YX!3Pf9{Gmagn zU1hbJzibIb9}*n8d2%AC86%fKY$X|OlTHFv4d6f-s89{G?i2!e)^lUY!Uc{Q$9e@` zgWs-8u4Pi_`i&SIZ7;GK&_k!p2z3#Z-Mh!S{n1+rV4cRb* z#Z#)m`*qf3Pdp7AnxXwi?vH?g^3Q~~dcR*ynU3S$s54JJ({2zlB!%9%*cip$4nO#0 zE&bs$jV0!@lFBQEFqF+ajVI=C)@i3Xt<@&JKLzL6paD=OlC8YJu+O~wxgNahGI`R# zm5OUIAxpKGPEcL<>!!FMnj4?O9Be=~lw_QKoHm;{l7+`W+MurIKx+>gOMx4=&RbE^ zqrFsEi9>KKUHlV}dBB+lg&SvS?)uFngLPue&4;u|&(FL4>KDl9gNLd|hu)gEf0L=F+lS6A(m#*9TQrR7%9$t7?j`8D+zT zL=S*e^&p>Q`HJOAq)K7uo_%p@mtf0hVg68@4HKe%M;(3*jxc43jF{N83k!)B4Hg%O z_ifU%lmQ(v@-P-x1oPuN9eL7eEUpyw?y?{44%$1{|NW<5QuO&;L|wIh_BKiGUkQT8!FyE{a zV+I7frbsf>2q0798YxM}oTU&oFl-$vZSk5lI`a54HD~7c^zHasZ7EvaP=$0(Xrkpo zSF{GOY_Q5%a7k#ABF`o!CngnHgw_u+IY303yzUyB;8wbJ22EYil?b=C6^*GjvXo*;+d{lF{EshvWLjwylSP7Ytm`YcA&O9a`+T@ILF0k2502W^!NCVFaM`y1tg=yik?+6HnnjG7V0WU}II76He? zL7Kvr#j*^fBI%K|eja)vj<8&*{H~gbUqXwpJPqwLn0)GGTDomFP$>-B{5_y7QPM_p zRZ1~BD}+!2lI6xkNl(rp?*l*pi=duG)ZhMjd(Ni4==l4iz3v zW~Di|ZpVbc$t4vy4wKFTbXkdQRYo1&4C-?2E@MG}ZrP=$QlclWx}1eVC}Nz8GU@zT679S~2Q_`C#5Q6yqyV^|2hVqPmLD0X;&b zHGAM#4IVvKpG};A`Lt@8Kj3^oecXS3LQSGW%Dm{<>%*51FVRrBQUz==i7eu3#1|H2ZwKRN@dzG#>~FO z&q!g?1)->82T>ynngj6%qiTc<;lUBDgC1gATk1j86Dx6JhFC<|8qQ33;~l3q7GW|H zeFkgplGOy^n3%L-v$oK!GP04bIMbL9b)ZEdCR2);ZJ$F zNHj{5--SRL5)drVUq}leL&br=eFzJ(nppgpOnhcQf>k1En}P3D-hgI7z_5$K&0#7g zT16IsL5_v6u@{)shaGn!lpDyLK;h+RDmM!+japY#fFSW`hY}q25yy;&nnN=p#`BA> zpViJv_+}*=fW?#4zI|Jc#B*uecC7Q}Xa46`zd(Et0>eaI8<9S~Bpwq%E5q57creEE z@q;o2>#Z>jvHA3?V$h?AfEZ!@u~%4>*;Y*IE6bqi2``|S*BPi3nkL9rg)dZH9U zN(*c!L#`7oig!C&q@1<@!w2=(LfEXvsY*>JNQY132QqbWEna^EEfs?5)2Evb?B826 zrcTvy$DXLAOBOg)9c$49jT<-12Q%11@DamY^_X}Ej~b+=yTb}(LT~9gRM~BE)h4e4 z=8(bARhV+nSD>0O!!cPfA6Z!Wg*%;z*yaAYKC+&kFW=@tx2`Xd|~n^G{01MMDFK5IKDE!FP$@`1HuLSL%gl-X^-A zq6hE&la|b!PW`WPJ^$wW#D)M_EGCs<0>-C3Mdd&9lK9Kh|LPY=fSiKzJ!RCSLSrCS zvFepT#Mz26TLpI53^fku-p#Vb)t)?yhBACFlS8R4ByP0e5+5!z7HI&88 zV#a*3O7Kah3Ax9I-+EVHzCV$ocI6IQ*Pe=r?y3kuz!6YgD3Zs*2{A!)GrJHhZ9r?q zJFObL1Rzg8?ObRlsp>ssggVi$Bv?&tUbN`kg_~GlFqhF(p6ncbH+unzUzIxYsFTnV zRB&+<@umrp!G&&eR8o>~+R3dUObchsELi$9;tzR1>nyMR;;XLGi?80Tb51zKxrYw9 z$)q<|$Om6706hoYg!u-^6hHzHjLuY4i{Us11OJk?U;P4!FyX9KTBsg`1(c-GlfnZ? zhxY)b1in%-HgALpA2oV)3>rsT91LF`2oDi!i-$@5DHcl{wstMSLi;;_qrMH^)gFpX zM+kU%C?T|X$vmBY;>ixb>!dTz)sm%46{@YI@G}i~FsTL&7|CZd@MAEc7}Z(|VIOeN z5pca)Yuzg^>WJ~jY9qX^YRnPiAi0pf9u^U-Bqy-hl-fu}B2t-2WAvG2tCqrTidQxv zm;4%njZD1C&@y5l$1oAUP$VHwE}Cv;HYI4+cHAFeVo!QsRTif&VCMO(WD@bDI<&95ifqUv$cQu4v)=&z zuGRCeP0(G}-r;DDID?}JrZyOqPTw|0hm2XYdx$@#)BzdxlsG}Vy zQWhbS9SN0FFdESW12q)G{zW`NmqWS|fMYSVPR+tFz@EnDcR|>zgS?lTX~9MiE&^Wd zaw(6=Byf@G7bVxaiF}Qj)2BJC*9hjCnK6O%3@u!-LIY`vxnb>Mq$mVQP^qCuo}$IG zzad_*OT}DA`>q{`^4DrlZA3fBE$<9f99+$Wu?naZZyy+88@4Q}6BC!cYF ziZMI?1Wb&_u5wafXMFV`ahM~?cPS!B6w-n@(^XcnnJO*gslvj-Lc1Vi03#qx;N}#p@;9ue_E@^MZQDlmm;hQNQSMZ?3Ta90!8{Dr zn{)Nc*?#p4#6o@{BD5Z$QHy(qRi-91L9h;{D5lGvsx5*Hf)u5~2LVDW?m&T1Bzz^l z2x=a?JRZ}_jRV<)W0`;%k_r{P9(z6!X=pu1+#VcC>QI#w?&0$)e3^K4X`jont0+#r zAEsJ_UW1ecLR<9dKSG<=t|rIar*zs1YzHy2wg<_B+TmQUB;N3uUVZu@tzW%~R%m`C zI?xvj1h80Ny!WPZJLae!)ajN>?$ya{({#go&+3g&muTAevvgFKetKf!MVdK#ifRw+ z<1`(e^U%e5@lPkIrhJQzKJjRE$=Od|5;HlDY`~dC1?trAAPx_+fMDsyWyLt}Juye) ziO2NO0mDY=hp#?W{P0G-d(|;ov3Z5Az5XiY6O-tSPZorka3-wg&TTT)wgAuLLxV6oNq4eyZBO zQHPv(xC1L2&3?<40yK9ue7A`1IrT;zchorbA2#xrvpSp^^^3Zk|M!a_rwEfJ9_d+c zUWL={Al78fI!WgQRY`~=6_zefaX5fsv*YniVnC81%7z+?7B7U)4Y8q2Pz|UK+QUx} z&qIwZE6Zao)xva8N=nMphJxktfl~Rw>uYc>W7Pija*hVHixro%a-OT#Y{cxSWvNEA ze%(eD7VV@=X%ZZxMOwLjmma#~2CZDX0W85wrePIXdUY&R>WI{ps1gb40vb(Vfflf^ zKia$<25mZ$c#n2MrGI+Llj@Y+Nvq?R>xA>J(M31htF9!3jSNO~(G^$9Tklo};xR?| zQ`2WJ*VJ2XWD%u1TE+!(l|%#5l9lsR4m5n&_!E?uOE37u&iE2xEu21ETk<#2CT)ZY zrcHIsr&ubcDSbpfoir6rSDKDIaRU9!-v^D#(V6F7gPBOT*g$)IH)WPS{dOX$0Ik&< zVq+YA)E~V1kD9S=u69u6y&f3&7z%;+y5M4f5Ed)3Cl_N@1zi5}gSTl**#?#G+^oxP zx>w5=&-{O%1pmZe{OUDGFbE1ol8`~NRw*$8%o_!=HOfX1v?>nm-~o$_$I*340^uM; zAr(d}$C`l+p;g=@6Imx&k0D<`o7R5JXzdnFj-#`a4~f2#YKSAK{NcuN36ht+VZ&P5 zTe#GT==)Ae{yYByYWrW;6jzIRcjO zv;5FJ%svkSRma8BD4Gz$^h#DSQTDa@TgjUU>pfyAr=ER|vQnub%w#Stre9+F4tnL` zTlFFB%`UwCPAbcH)nKE?cMVTi++HPNvdiLpeRG-+6XF}}e7qtEA7l=P0g8~NhDJ0jzg#@?uYL-rG zOi^E4GSOxvCn>Z+%83#~Bv?o^9n;GaoKPr8df2Eq`E_K-xp82_yf(rgO5iiA;9=DU zBNj)X!pG8|<`UuN$RJ!z4e+KQ+-=32!2DKXAdTZEC>Q@GT!XF7@y*GPBgofe%|vmB z>T%}H-!KF#0(UBnYHpP{^~S|Af?-2_2_^>yAe5LX-+iE-**hsT9aXTPSmTdBLJwRp z$f0$F&^nVp{E&);7b>f9y`H`BAcu(A`=Gu$b4(xo@X?cKo&as82cs!1N{)YknV6kf zt(DWCB#W*|naOcF=d|%kj1=qj=NIaf)5f8R%k=5HZ)yKQ2dZuSJDT(4Cfcx#*G;$X zqHeHX4?py@8WA8~e3LSOkHJIsR~E6CRg^~BzGb;~6xTslC%&JA&;deUyKXg2e~26P z>5tH2NZbS~w{Ot3i`VJ=la9ohuhWNWM#chl;>ob6Y?Ks@AsxC!3H zQub0F8Zk2hpfA<|sR=YD#hiBhig-*b>qG7^s4<_Sd~YT~I*eKus8Obq1sKqVO`B-q zS*7+JI*=z0WQ-rOV`mA3yY?hLQH;*`RxF;bfmpiP#sP5FG_HCcM0z9?hxEPSa5gQY&5t#1b26Lf@=t}3GVLhoc;Yzo%3?* zzTEq=t81!fW>?Rw?&-CD^7ilWI8oLSR2tHHT5{~r;(v(S5)MxP4eOU!G=mOeab8Yd zyG)UZBM}tigeo9LiTxuG1=3Gi=tUc^=GFq~TKVk#Zs(mIYlGwaT#QvVU(;`$zILV4 zKLXo*6qYi-y>uCTe!T1G+Md&w{kmzm7Xxku!8wu$``*R;XXBTlRi%BOBjj`A{aR46 zvH|>jZ`0!@eZ9OSjX?v~OTH#cSX@AZ^~^i2)yAp#(+vfVNR0&)rGs3Plh_*)#+E|= z7H+oukct$4S_l3t2 zRGXa@lrf5&5dGY>S1s~pe)=KY&5T)FxL?T{ebTJxs1p#-V4L@(E}x14A0xkJ;5Yrc zEt?bY{{AGK>T9{<{X)=NH+fvlU940X@bz{s`f>pvMvLf4YZkPxx}R``+}1+SbT;l6 zP}VftAx8jOV`w2NU$iiF)RUE;OI9&uZ;YUb>J{1Mo`B>|(2p6RDR1|mQ&%WBFy+u5 z;F0s1+PaMsmBLe%{%i?)C5qQHmvN`T;*^~2`+%BxWq`m$)K$rOMZ@bC%^G{~;UkVS zXfTroDwY9uB57-1eJ4P>OEpHINkne2;oo8R+s$M;vthGy#Cdjha@VMBBlltHsuj@b zzZ{(};@2Sz3YAbb!hwp`^6CafNe{l24}~#L=!ty81&}6RqATNQCc2X}QRA;%BB$Pu ztbmsrl=Zv8qDqLwOhJdAX-Yti(a#Itty$8SqihvTX@`G7MWYpp##XlX0YRa&szkr$ zKCDv^E@y`gZ!0&qiWY^tmGWko-GXiSdju=dFrF`ISO;qzA(ct0#NIIh-JOsKtK}h^ z{<3*%fEWQ1SEwY9wm88H-;;ODvVm&5{&<0WbKE;;Gl8p4*mJLhgAgVXWGe=I22B-T z6wmXG#F!q#eRS1th0t@PUTDm^5?$@y!N5KD(Zq-BTnsTR2+Dk|Q%~HvvL4P3f;73X zj!by}u6ot5F3?Fr)n!@PXtM3*W}W%yuVSLQ_ac1{GO^@*=#rpLQt$63_m`r9jnXxL zrt%%_f5x;NujQf+^lz1Sdu;%M2E998QUcBt(^(gcKx`Vt|k7D&pooFC5RclKPlz5A3e;_ ze!%T8Jmvb&EYUWds?mo}o#g-KNgCk8@Tc6$G6V_VO}?&=OT`MAcRLFoqd05#ozT8# zD?QYUe}Fjji{DS}8KZLT9@ui?@wFZm14Mzox_2;5{YFVTikRcuYU_?1*4Jpv0hS_$ z@l#geN=eyRu>3Z0m15LI=Og!m6^U}-v2Ls6#vtyoKOhAQ^4!Rx{N5dVgc732>+^w`BOBAUo7xc0bW5x-H%ijtil9s}`PX6))fq#Xvc zLXS}wV0W^za5FvmNMpaS1KyslLKmaTDORYd@}feERivTLFW_>Lp1lzdfgKK=+Uq zBfQAJ)aGle(bfDWgA@3n2y?dCT>U|q(IPsvTejE$?C`x89(ul9Ot(71Y1V@{$3xK) ze7?lN={S+{YceueI_Vj|G>=PV5NxaQRK0zS;T*wQ9n-k3W#*e8K*ta)Cn2s6Z53Zk zsTqAd?gxllig&?8I=?2?+?LJK#t*@n^AWAc6*hLsvkJds4lE{U*BL@CZ)tb^@+5cQ z9^&|pT;`=oXVc@@cT9nc{Kg)flh$j$+FH`p!lItvA@xb+UMXPqrq--^t)^NhxZ(@v zf{_K@YEQZ?BiqD$&g4B}6I^Hc zLB;Jd3oK1kmL9=!8{5h>dCZMCV(ms<4};qd!Dg6&8%k*u9au%9B$d!~EL~NE+_q=V zg>M#UBU%$ZG?G-;vV%{&kr|R7h*NmxL{vRS*m<@2%?aEecN*S;SoEim#NQ|8B;pi~ z_FOGmfBq_OeKKTf7Sh)YIZ6$Ie})nctU^)EM`E@a(f%>Y(5^Zt@!Tb88y$}WCGsF4 zT;US(@vOl|%7RUh9#(=Q=RSdMnUHlhGg?e(m3J*it{`$17^KezY~XZ*dpIk=>GHC} z8dqJvc?mu--7xLd8`QxPk&6jrl83V(hE2h>uYz;z4Jr;bLm^m^OkF^?PL=5!`Ds6l zKS>rb0FBv1@TmVb^4TDMrJ|?ScMRkD5Q%rZK1);KfywQ-Tj2CtZ&0Iz+|aHWB6XXd z6c1uu!Dc=VA5jjyG{wX1=Gl%|K!Gx@AurOP*{&_QH47q4@QYM6GCUt#GR>e=+j0!r zMPi;CwDX@+@j?#yL*|YBAFk>Kh+NZ(AULo z5!D0On(5*0LS)H&Ve(p%I~tgGuQG3lgFIKiPjYgjC?2kNw}?DODn>FC1UQDIy%66g zpJT&?(%_N)X-xwf&UQ2)cmwl$o~*yLv7_1Id@aX=gAt9ipFo%H09CJ)$A}5i?BFUH zb)s%o{<=o|L=Oyw&oM%Rh;*pVIom~6DrGUiE5G{>`mZjzN zg`X?hBe$jqJ8@sKnDTj2+y2k(p%;kE*szkPc=jjV*bkgzK>wm&l-(T zo$+Z1`xC=M3ip_yLq2t-D*iljda%-zO9{%qltR0WvbFzw6f|J1%8|2L@^%m`Hp@5N zZO`}^>4}J^CM!y)`DXmjep&J zn|~}jUjR}Oq=N|`^mn#SO$*u#VTa}qe6wt}P|aF%){Jo`LtT+Kcl2R;^Lr_toLyF@ zeF&zLN0Wg2l(v)DaEw9()cGR zY@6Pntq5u;0{+nQD$fck_tr$m&9S}2%Y)7_OcE+0BNV?;gZ5vOl|SG2eGf|_8BEn5 ziMYg^&RviDljDne{viVd{n$~RqEJcMe~siC;he2#9IpE`<@!E&Fz571Y%=TS8`O13 z(W3Di%KjO(Sh{ptj5Yy=7UhWzKk2VuZ=n!+Twih@#msx~`B#&fWY)bJdm9iPew2Il z`lRa*lHC0@xIBHPCH*U%ZcrivUUavAC}aqqFPO4bt^Dc|Y3uKedWanHlbWOL1A5z>`4^J;sr5MCc_3}NXB zO4r>0tp+%gxeFqLd)|!sLGiZ};=UI`KuY|YFiO-Nlv1&Idgp@o2lEWN=W`p6FERY& zg%NF_;~WBUUM1b=QC9e2kn!dF4&%2*7vIxo5SSD7San%y^WuLq^jMwmwW%FTCi*Q8 zz@?<|<0FETWJ$KJ7qKQgL+bRK(?qWboF)i`&gqf@=jaj~MWwm0Y`GSXMs|zjegRMa=q!dtT zGK;_?6BhxEwv5!QNI-IJ`wK-Z>0d>%-L3HMoCU8ZZ(+YpoMz)w#gCuOM`imjP&q9e zO-a{HYraq0uPq@oSxtSP5;cwL{wRk| zIDO7j|4|fKA|mUnm}C*0J?2zb`0h3|26cBP>$X_$kSP;SQc+@u|Zh?_$7@|dJmOAK%3RUUorjT8X;Eb1o6a_ zI?)D{%!BX^`RrEeFKQlO#}S1@IO(F@BkO70t=UI8aM3UD$IJ`Z+dgith4)Q)y$j_} zb;ah6{jS@eW{wz>MCfV3I0B!gf3!sHMcpvz{{I#?Ijee;C8o7>(nsD z@;6FpHFB%15V9vTos@(4mKZT^dOJ+<@HcF^Rz}$FKuq`ZfubhLW_5n~H_qN%WHe?S z?yvgPs_|$49t=MDa-RBxZ- zi7dScW84@2J4`H64#Yq*Zx6=gS-j5@1|;cwoR@dsL9hEydi;?~YVq4yRT!6t4Jcvd zpB81b%Wq8hnJ&ZL%D^yQHdMA#7rGVEv6zazN~w^*b5Y@3&S9)rUuc}h+9*3p762XR zCzYHBjLxS;`c1=9JX(@6&VM;orKyNb#KC&sA6OogS%W!Fjh8zhGPf<0-G40weDkesLZJwdo#r=<#9R-j#UmGTADxG~H8iS^&xfFSy@=`jGlAC~IN!laB;zLjOK+nnp!Z04ms=CybLaON72vhF5&&SE#+x8u|IL3Q zAmpVuQ6gL4NKLWVl1QKx4=|Nqw8qJ`d=XYPT z5WJ34p$VzRAR@+0c(GH(3ZlLAuTU}0lVA@sJmRoW@wFk;)F>}GtVBj+8Q zt|SMprxp`A256c9UP_jnHVfYrRN25H-|k2JVIG~&wb_cCoL1CtA_>&`% zIMix}b)A^x5Vnd!5?f;;l6PBBXvfq6=9zi?Ih|FVU-JkJq1owk?ym0^PXwKdOIcPb z@8bRh7#j!ZKlb4#<~_!5-a$V5gnwM-2`6OeO27DP$>{&x+ze7Ff_m%&EaRkayn+Og zeLm*;K8|LADh6!lvzMPQ(|2{BA$(6dCdkKm1+yE!o^r9{=3wTm#a=-k6+y06!LiT3p*?IcLC|Y@mBJaQ~1QY0rdzh57JhG4{WE zEebaRr(wu^j|xPMeUD4(n2fuh`en%gcOziMze}@K#r=1X;UMb{6Zky5Yy6J~O8elI z(6xF~NwnA2f`TulGD0!5#|@*TT|wvUexep*31J{GBWQOT>z_!|xc?0QVfSsg=-c)< zyZOjB6R>dz+3VY<FDSMhQJ74>)8cfl! z3mNzx%#11+ChwDNF^7w{-PbT%ZM^8U3Gf=a*`I_XcJBY8 zsGy+G2<~z2_8)|O`t{wg4*UcU37iyZxH zI(+HbJbQlxHu7Zwfg3)DJ;R>4?+zt`*|eTbJl@yCctF_zMYG$F&&5;z!(Xqh?~jiU znQW$mVbgi6dX0O52aiEw`K8bAv-c~FVga>@pE$ojxZyTTtsB$PMc^c(wDywQ&QPRP zrU{qX5PZt|FO0t6)n_szGw`cOhO+8(DBH^S(6d@tSg8H*m}!;!ywRKY+12Z$NB&u> z(z@UKp(2xS8T6KiY(6ReVI7ZdzB{Q03`opB)6TQ&zW(Iez$Ug8D>CT`pEy9Td|f0}NK{o-@+iEPTXA zhFZB`TIZP^OgGJ2x<4O@gK%MPE}snzE>7~eAV+T6&c0wRfehWI=NWZs&v?DBwxpYW zObhTaGFB~cK%V(2uKTO~U2vj&ru1|d?Fq0kq`x^CBFzsnx4(*17X&$nBh z6|Yvb)dsMG5Y2$up1mS#qutA?xqfZ#{=q*N=8op)44H@4-R0|Z5rdTQ*byglJ2mpY z*uyo~^v`grKTPCGfg(3!RJ_x9qQLSV-Y~N=n~x80VCUY%E3bCP@B6O!y00)ZdThoh@@O&s+L0?+)@#`5-cav&igK5*8fY8 zpT9o#LbmBGuROkznr}Y7UNl|0eAI1Z=LHyT_NO-FOqHS+m`d*mWfz&;Ph}K9SlU zLkvmynpQZH-zbKMhr=G%N8`*9hZqVC!H!d`V7H?*ZnCa@t-kYzS!S$!OXvVas_$CP zaRMjhPTw;0*9P<3h@85w=PD~FnmK3qp!8lo2((c~u_G2W%muB^mK)})7Z(1fCg7u= z2YC1w*%!*bs&l<^e?|m)zWR-(V%IzJqs0Eoz%48nAPiqc4eEAk0+|6XyW-y+a>L)P zE)7~g!7nx1p6F=dz7aUq4C4FiO@ANgu@i=@P9fG+Rw}fRzg&;zv5hmZ>k*IGBCn8V zlr@%ltJLZpv~BpFLj73GZhUSd%}>jI1(N<39-l%M%%b3MHaUdX75cvE8eCCPq2)ztjwTb8yW6chX-WOy)Xfsw*HLu1{`u^_dJ>F(dA!Ut#OlZf`n5oAHW1MFfN)?)}%v3G)BhslXCiA3WVa2ZT}m zDHIC`L#x?OGWhR+zRXrS8|44F*8kUT=btx8=8PXrXTQOV1@LyX66sinzqN1a^aBp- z;&YDx8nUH!Ca3iyMB}Yg)Dawd+oMj=rwg0ww*Y{#tD}cfh5rU$N981ri@Z6M;C-3= zDR!g+OUM58%df&g@=jqK2%uZ`t8>c_Z%Wofn?O0QLww=6}Nm7~X?a|@G8-^Dk(wb*vRB%5o;T=1S z))^v7t)efd(J9&iL^2pX=Za*ve!C7bUW+)K-9?WKOzmGdY~xj$qd_5X$>&%-fY&O8R*8~8NwvL`#x93HdZfj%UE7adp0AA! zvg?(peI0teFjiBqmp0AyOBOWVfKA7A(@5QUHooj_GK`e(!RLLAjP*&e(klYf#dL6n z{jlAnwT!jO#B76uw*`hv{O*ShOez}hXgw}{AVrfZD-}D^^w+&t&-HtJ(vy;mY^$r( zqQ+D8f5r)?3XR~KZ%0+MbD5}!ymprcv>94@?4N+z>TY=L)$}_J z5_Jo4XWwPI5P9iZ$}}MU@$20Enb%%$%C0kpk{Kttrst*B8{XfK>fGH^iK-}QP>4@XM;G!;VUVkN8@#p1PqNnfafkh)N?`XmsBQi(VZ|x)aFE)84Z&si4^Yf2lruMSd z8k2-?q_P$?b(mDhqg(WApG>J*Y{p&pJvUW)+xb#2$E^ma$7lVV$YoKesc&B1;MX!3 zdbq8T;!k>@?uW}5-5)MxsoLKq!po~06&#^2^DcTNS^I7(cg*MzaIN{4iYr&@cXkI? zv_+NSx^}Sbty4Df%2fFZnFSS^%Z5sXS6j!k)5CWV7*H#;q6e>sv?p?WBGT&g>fT@5 z)S+H!DW8JxDVPm<^sRCLrM;gQvH@7yT5;*?i->p%4k zFE-;yQIrW29lcUs$%Nf3mcCUTZYe5rq%C&qh$RPV9$F}mXG_KM^UYnhO@t@r@YM8- zw9<<)Y8o0nwe1h69Xo=YDK54WZrT2hh|(!0hJ|gLxnuYuh0Q}2S_^oL!qgf#1q%D* z{zy@T3%y3rmSmPw&s~LJbY7&uUHLBeYk1wh&CN~Bgw{XZ-wnbmSQ6Hcei9{?!wO3B zUMYd}mnWUDCC>ZVUKcz1R0=98>PnU{KVcv{yT#*$Zb>Y+1^JPNkfA&HtTbZm9*+W{ z{A?z8!|2f4-o{-js}Ks>Z9P_p+ZZ&-w6&M$Nc~a(R8i5ljKa*aw8UPOsB1lnWC2$c zZbM~DL0^ZT&7)LqPY*=j#6wVp<7b71XknvnEiGF#4ugJk1GiO9{@RG1uQezkRIu!~ zs4NB;`FFmK@TO+0&2;nvKCkncSOg!x0p5SNl@H0ZAQTt2XEx>5D+~V!jT895^ie%h zJ4nna7tyVo$U=l+jP@8a4at$zTQp;QZM<|b*l5GncvG4Usu65!66@(adaJryPFA4@ z`enA_)c#GR0@l4$GB~XE%2hZd;UG27k8T1hwUE+m*4oWA)5&l-P`~Izwqfq!AKM~! z;#^kD9j6}-`mpqKweE3NT^S=IIMBI{{eVR0dB(Nc^o3`;!~TMnFQcvA}}1#};Pfq#p` zmN(Q=smCfBQ{gg*JZ47O_^7A9A4!*R(l;xd+vT%8v8`8{vCpWxxiCNwkE29^HURRqVyWu_ZA*@h(X8QyGWu zjzwD0y=uxc9q_(=JKe_2nU6USmwpL6wZ>-YA%A{MNf>i4jy%;Uj{lQ?F}>lfWMBX- zOU5UH^2)y}Wd{6eF{E|b=SK0M%c{?+wDWi~4L?2|-=t5)=z?tZ; zzRTBUGMHjjcmF5>9k1$DE$XToNfWXFf-Q}+i+|LheRtVLLYz2sEybi zh1{gv%1(;@_xXdiH!FF)>Zf6-U(2R_Ha{y;)SeRI>gNf%l0=i`((S z4AS?qFTq4^l|&O%_iMdWOZLJ`81}K9KVOvvw@ zpgw=wZ1IZ7J;ZG@(`=)!GnfDFmfQkZ)n{IB)jBPmRjp?!#8MWJ8mNS4(-D)+<1-%6 z$BQafHAfTCH9{58IE*EN`HHi2lqk!<&RP1J2b6sEn*9@h39KBTC9B$&ge$LaG)(UO z)Xww2ZiwSQL9a3Fz>$;cyjiHyM3v&Q@<}XJ=^$;d)~x6_7C6q(Xfa(ENI4fs(fvjS z;DOptFE|WfTCjvWw7x12$^53ZVoWMlpIgy*!f<~Pz!n9yotjb=>>x_s->1_D^=fmt zQgidQwA`R=#&(^?hzNwe#ZO#F6;E0QEtH$5eXgw!sW1|>gsB?y>>3_8y5p9TbpkqB z4^tRv{Cwv>{4!r`_ngGRO+B;#u2WYIHrZ5HYXBrGcCa|vFgOQz-w&G5?HFQ zI)hi-spmCO2n9vpd2KgG8omEkUTIui4S=)DDMd>HmbJ}s;~`a+3n%-iMCEtQc!?#c z8QjkfO#Df?2GGBM6Y`N1I5& z=yzgiIa$``w3^k>Pm+Cy^Ze_k(p{@R!)tZWw$f=|LhAn_Z&?i0wFroka9n8Yh`!&$ znmuVbG?DhP$6AqG9N<82_6<|aR1C;7_WeW>zCOawaULJWr$Z=A>59V_{KkmKqUEbx z+C3+uwYbReE2FeYMMNL;cHvcNXX{QrW>?#*HX27<`H&-Ervsosw2oNuI4Y(CS!EOT zoOathAF|5iO9#CTJHNGlz>0E*P|*NLA*uHbal2Cu~b73!}(aHwCdRToV$8|R8&U?9Q9(T zGhZw%v0Kid&<(qW&$h<_5xHWfkik!lx)Acq`g(T1kO*k9_Hav&4`ER%A#5#y!EzwZ z`?n%J_)Xu@3F9vA>emYbB|0dzl|IcLxVZVf3eIN7ZOZ)E4CS6Jp7&;ZDs8%4=!Eez zZXAW_%~%Gxg@$nAs!b#R_D=VU((`BT&ezDM{hEKM(71JNy{qMlD#X=IGJ8k+vjJvI z>;wN4JgesjXn!#}QL;z0BiBej_dZQk-Tc(Je{OSYalh7|&b`T%$@8v26*<r$oTC~o^e*bsL)lZCmu$Z*z>pSo?vg)EcIQXmCHb=ND8f!76h^}lKZ2vB4w$D zALS~e8(B|_*oU2rK_Fb#U!{1)-ui7Oeq9GpNT|zXXl1@RaUy4QmOtRQI%gqpEIsGE zOy0{Kg?+braP838fBJUMU;({YLEB5zR)$s9F5SJ^51nRMZKr`3fK-qr1*R&x#rqkp^E_9u#q&cy2lzpaI7H15*>Jkv1itbKoaDFbuY~SfV*>6);4*Dz0bs^f`SKl&{t%X9ue6Bz%hFb~%YOzq61pXp;=D zoq1}0yUqJ=WBB356ySE*da<1HcR3ISgr3F=GY07m{>)}T?kD*&sca$D>QMQY)6RGa zDHktDbZwAAtp6s5v3ikgz0RZCtEmo3BOo!;rPk;fa3;!=pz(afe6xK{Dv+NEBVX^Vg_xV(!ukxXVWg# zP&|>rm_ez0v5V){JYF!5*9oxU1`(+HYC}cA=$4ntCHHwNn*go}8yxbfAm<{7_$u+s z$a>#3&Cx_PZ~Fw)!R_E$e)9;@UWBy>-Jwn`1CPgThyA!^rX zkW}>n>UyKB^1MfoVoX5SjD56)LGQ3z%+HbIUr+PJLvqYr2W&=@{Z&c&B$h~!zd?fZOOQG`UQWrCKq^$pd3Qls>Y0pz-l(_ zv~6iq|H{|x+D@zJ6*VIvUByYqzd6;QLa)?yen?n0Q*I=&eT&BPulOpIUCLH(0bq(1 zxBmBG3$2emW`Z*2bfSW5L^4Ie8Z@~xC_M3PawG?BEZ)FG!=P-$TB@Z0v4mWzJ6BU$ zg4>lsGX`LZTmJ+I{cgtZpsLfcNL=zJ?u+`M4#d<`3l?b)mM=)bua zH5o<*B~eZYSvVk2f`MNHvokh57Wz*kIw?ZKP$C$T9)T_sKNyOJK)pc(x(O+4 z?_mhLvUW(Hmvywe7+V_t2bD24o{A6*FaoBzgiuqnJal+2e8eG_`hU|ggR6I2@aaw3GN0BdkyMn_MQ&^af3^HcK zJh0-m)I)qve>J%GW8+g3lge3tOwF&>tqqhcjKwG2Q&VF-)$ZuIs%$-}#ic_+A0SyU zx=rm*nDpsubur>pEtj5&v4@7y!1%K>z4C>MC=i5^1Y?ZIal)y#>Rt`V)L}xo#C&Np z+@wnvje3u#-Bq#b&T9T~4oh8DxE$E}CK5lPrh6H{rA5S(-c)xNE-FkZXr^S@+gh{! zC7RKg2)A~z(Wfd!>a7sfQo9dJ+xU%6sL^SWra}Tu7}1UpTEumwkbQ+Y*q_3Z8$U}%vDBho6B!mpWK>DLkxD4H_u*Yi zr=!E+hDklRG4-1qG0X~?AfH0Fq>iR{b}i^9gn^?+j2-e5&UL%yw8twZSWv?r$oXGF z%<1P|+pRe1S?S(FzN`A1??XXZYASCGOej1>#M2ZK+Ub0JujyPF11op67cF22l1toa zLp(S);6xAbb}c*M0FvGfZ&{Mo*$hgOC+GVYx>W(9kc~<1Vv$FI{>RF{Z*Amy?GSf3 z@MQtMl+EJKIu+B|p|W-^W!$OUJpEmF`-fXoy^--fjmXwxt3*NQ-7d%kqns9k3`y`0 zw3#+sEODe0di+(*eD`w`Mn>rvSaT;C@iE0_jh+^htM&`5&B6k!2=$g>-O$1}sU+Fa zJa?f1duWUe9rF1)8x4`eZZ){zsv4$wwNayThGk{7?if|Ba@|JyVts52?4ay&SZsSb z*i%HyXc;wu#$jY2o;oKpH>q`m-*=>NBRaf2O^shg5CC{RR#_!VYa=9kOiSV&)k;z! z8s3#5J`wisB{Fm~EGc@}88b+N)1w*L!5&54Dxw!(Q&ej((ckzShqTDqw!{~qvY)dO z-qeEkQN(w^Y(4bSSez1uw=I_8@UxE09j75WauIaAEnXD1RaITONc^bD)zDHFRK~^Z z5#6E`N|Y#9l9t6^@J@`}7*3ed8f4+@=--?}c|?*@mh;(WdyPB`jeXB~x~s7ROsXzv z`l#{<5Cej5F1{Xi3eyFAY2ofnN+FFnwAuBk&8c9j4rK%3#0RPAX~W;874lsO59Uin z&Uy!q>;!gWAH>WFbkoLs8N`aELtvet!nC!}e@PwWwAnG1q^SM39`OjV_=}x~#~_q{ z=keD6DyxIyj4USZJJu}xOK0}2^97sv*)WkMgBkQTAYWJmKYMVeuo;y^aK+r=-@||T zsK(jvZ^TYs`*^vXH)WL2a=JY)2aCh6-=4&DYLL05$QP|J@0zF2Zx$A{sB|;-Dvqn= zc+%h(7OkNMmLkOE(x6OVxf^x6*;IFSh5a6P-Rf4sRb<*szXqyE|^j!*8+ zmmayuhijbuka@D4PzTku?+j!z6p63LM}bwOWF1H+ozJgU_ZYKNjQN`FbiPsI6RjgY zYhS`=QWQ5O;~f4-$KS>ZvUSd^XCO*NHb6{Jr1DL*eJ)hta=(*CQ@qxvje2d|946Be>}p(u3ab zt)6W9X}{X8=fD7BNSf2T?{yb`Jb-34Y?bKHlRsH)OTXwibz%M`3Wp>RXI@qn*Y9UM zT6^-RhR6p?Ofpu9&}$?zs;)*yQVa4)h?HRFh0onDHh7 zEi?Av!R{3z#M(02jg5aH1#TkDHO1_|3KB$htP|C$U>y(bLdiG`HBnDjSiTDW&&T9U{u`sH zz-e`~DA&6Z7}DhDMwesj+yTFrz2f$Q)sw)C~ZSX=WhwL_()LH zLFRt-^$|4Xu$@+Bln8oEY-sh7d0}Rwo=x~ugAO~dY>>U6?g8HmJmZKixwEird zm_q?6KbNO@;&0$wdL=3RIC7siv=q0*@Sr0-U75A+i-oeS1LGUY zEVJU9dxFY^>fAqcL_tO;{gw0FeivM!T2zB2%CdQY0$4OrlGDGgBFGsL#|Gtf+vvEJ zUEhS!M6#rKq4~`*tbB;+^5MU%SYV3@v*{T372!|TD+JbZsH-XTi!NTHu%!zzFx&ol zH31e9j!@Gx;}l^3oX9RE-v}Q~E$CRaI!%tJWq**vOJJU)UKWp&qfCf!VBbM6a8H78 zgFIO~_cjyW&ADx=(*NW$x;7XCStpl;lL5qi^df!lwemXmrkBKvQ0D@md@G#S&4ll_ za3+p?gO&MDxpDyG`+EUjPfy!O=Uz~{*uHjF6k0@!yt||scO);PZipc(3IykKGj`!- zOrQZeJXZO7d?yiB8czJUuZTVE^$NpIX;0QTH~$n^<;wd*7Ex$Mn+C#uw@Xf~VTQ5n z7fAJnM2O*sG+DzNY^`*pHOHQp{{3S6HY~~YJ`bnaa>~+ib9(o%u$aZxAqPjo75pBU ze1!qkLH|`=pwVDMcz8-&!+8jhAFso!Z7TQGdj3XQ;QJ@b(408SabBZaKaX>dP*T8!u#*3+ zM=JK^pK|thZu1wz1ChfYANMERVtIhOxK;*RlRcpyLN=S?4FEyM74Dj!|Ce1xd52=*sQ2H7L( z@7GH*wkgX}8R^5@5|KlM=9RLE_zF8_rqcE0L?=r27wd2RDhM=U^$J)h5eFH#L=jMs zh{;Ik$Vul&X|c(*2&~=ZB2W*qSM{pT9Ua$>yi0tmqoM(`PLGI`udA2~37<0o5J>uL zei*=Ogh7u>FBVHdyD69-IhA-AQS2dP?HmR>#$Z1GBSRBsQ;YMpx~!?QhCh*p0bO=$ z%k)tV#n#5$YYyW}yc;1AT!09EySS1piHNo=aqlw!qcNY^WvU)zZjRH=X&rw$EZ-%( zJ#0Ese`E9OZzMg%fY9~qB7`8@H~3~A0s?`4Ehj}d(My8CYaAQr-lg4VzUQ`N zzFXqLF@e?PHA{HWJSPRRdE{+-Oj4#&lCsE)55Y>lZaa7rwyTJ~PO|qW>p6yTgeA0{ ziw#C9D5MK0t*f*QvfCTp&psz>cIYw?*mf*sD7ywoh_#*8ZHaKCa@im0Qef2j*{iH0&(gr{Q2SF#$}x1N5v zk3uRw4I%=U&dlOkON5GIppxBfM>{${23R_`epT&J5^!QfOeCQT54lg|$HWU+x8v66 zLYU?&jPvUu;&%idCSc|jj!;G*e0M!=_}cSu0lj{|1z72H!O`4P$W@^+Ch8W>?Wde+)?E(Q1?tIwP>E6)8AP6Yw?-`!jD#+y1B=(+CA_I)4K>nH9dh!`R<%1U z{AVSurQ{$4v4{6V7S&7c41*8ESnRaL!$MgIoQJE74q0>qa=3uwh#rohkw|82r_~Zv z;UMb=Y!|l*i;k|;w9L}Cb!w(HSSE=i$n-jO9$c3pa)HKCs1APk9`aEbO1m7?O;K1J z{B1dY%)?%U51QfKmM`K2A0%H!RYssu3j^O{w3LkKGuqK2z9JN8S1Dk^%f{gk=>GgJ zEnKeX)S*Iz$E*$&EHkHIp%TLRabF^Bn~ahTFWwq9b@kLOArcm zfpeNC_W6?OZk%f^C!!x5 zNq?PcAPWgV*Kb)aV46pScsj(? zx>mpLwHr!nL?~&}hL|sHSxPW$y@rhAWeM#AtYVhx){)P6b*N;?WPaJ;K_ee9bx2~k z>hA{z!HDiW{6m8ueb zJ2qQdV5gZkW$jPfP}Yf`?a-6Nj489rqL3RzG`gpdY4GIVB4Z(7AYxsH;IGm}MG)j* zf=q*9gS^3|F2SYmP^1c2K}%druI5lM*RHM&)>U*M49f54)MA8?wYGt+1Yeh2w@bT91wQ$H(au@V!xI59nO9aQqqY}C` zK$Ck>InTspe+Vo;(uV9=!51{9Oz5Gv^Qs7yW^p=d#=%Qri|kQacU7DO z%^yE1PbR8zFsU6@Ew<-Om8kfHesT5(d`!)pq2Z)t$(=VcXq}%(_y0VFndSYtREblC zFME;PUs*R7?<(mnChNE;0HupG5JIi6c08*hJffTNYW2mXXzzlBNt&OUE=RbU<0p)- zkE;+tNYFCgqFIU3a?a&<7A@@4H#=4}E@0wFo;T`!1_zh@lehwuqu|*!-gk7%+p~Ay z_cKoS(H7q08@r30OTzbN=h{j{_*~jiF3S1kq^u{RfdQf}smE?VPRnp6xh%HG0Rld8ou0O3 z8+-E2lFvk(_MgfjL77YHqm`VuKfo#oBc~1IE#fM%bX(ZL7bvM7Lzr|vP}R@lkMr&u zC1oeEc$;w6sd2qGX2Sk2(t96kkc^WmJ+(^;ij%6dB7ptK_>=fHql!8&ty75ZtI<55 z40{AxWPfQZs!Xg9dXZ&!C1M)`7Uk&QdjssTqn#Kp_^`W~L(!Ff!Bz1t;6gY+pghjk zT;|nt8IkUWFE=EpJ=Z}n#o)UO2Q~xSxjBjNiCz-g?tAK5G#+A$Y)b@UAxKvY<6>h{%?%jS<|fX@WYurZO$G2s{Hip@+ppv;Wgwc4m~~n;v*QO z>d?CRpVBbJs?F=g<0fDeoM`T%x>s3Ym1|Uo#~+mrGZI!1SczT-btfT~i?ki+G%#fk7&Y2%j1`#0!Fcy76v@a+)?eXPqPAD~87 zbY>1_iONr?^XN*9&{7_ZhvOV&1OI)%yM*ekYCE)?EZXQd`Eo|a-ZNCLmA=_>oCam( z`W?GPQFt!Uxss+iE|*ig>73LT#Vrk1U@b=a8k3gSD=-8;!=~aCTsnRmk|h6$?f{YI zT5z;JVL$yoy3^3EMjqos6_qg>$~!5v>&sXfeZ}(3oaT#p{biN1KMxSW8Jg*ozTsZN z(YQ)aw%<)QN_7R}fh!(Ej9TPOm_cRAnkJ@TWyS1(zJtI+HG$ux zE!Sv2{JG8k)Kg(*=r~Svqmn%(+NL|%SD!AD2H%g}dcDlhvjLXat4kz9$b_*BP*}45 z;>>|utP8(ORme00T)%WGvzR7^d|R`U@BO$7SJX@~sjCU2o{~;?By~$5&Fby%$OAoG z77*kJ3Med?1&$n}6ft4$>~wq*dVHo7JA7(y>c5$9!-s8NU1{f)aSrX+PGRftW@ zr6@#CA1fv(K{9Yoy}bPWi>FXJ`4@LA1qi%qe{!Oa@LdTqB^Lu;!JDoT| z5YNFyL^TmMOUwKYE>cBSA&M48Z>AavOb~; z%2I4uw+h+q(SRX?7{`bf&Rn3Bj8yd5Q&LvInJpF-GP>>F zWn`~^yQL5#u+8E#F|HZCfNx34hc|6qYwDSC>5eu7-4Jt1dYS zN{KbdjS|2AwMqK;&5u>ReKnp~RQV+hN*sL+8Swqot4q56bnUfz@WF@if^0r8PQYbl z#nn95Oo}K>b$0@8Hf6WOcZq-MnZ*Vd_G0(_q#x6 zzWfLEA9Ao>z55SPh9M+S6D=4nrLd=0haNsc#~n|38tB$mduw3dp6WfOgO)tK1a=@W zC@j5;Pdo}G3R%PqC=47g>!AT-jTsJAIbJo;p%Y_eI`)VmB%ZI$3goXxp6HiC>l@2 zE{!2^aC%vl1G|_dUxY%)X_cdhK?Jt2Q7|sf+lZiwv6!NiYp)~N+A2F!btsLp(h}VL zC~!-X%3&StAwX)h)(BQ^GKyf=<>aq;QQ9f}r(Su;ho-1}TIHCQcl~JPa!cm_;Sn zYAjnnF$&hX^71-Bjctvf4Qum;wXn!M95+>kb>^L5C3flRSiGy2Q7jRtubyN1uqG1{ zJzBYZId=;c72#olXk%rCU>pT9Gf6n)_$bB@6>}R2q`DB8PAPX@J;XE&j`LEF%8f$n z*{v6fY&%MkKsv=D*RCcI4&-Bn8GTrzy-_mtE7^zYBpL z)bDz_KK|ruwW1736>O`8JL^^MN>etT1W_~s=T*wcrPRpm&md*g zX&mrfGI6Fo+t(?jRS)7B6}s$_KWg$P-=LT=O1QtWstV`2jFlGTzht0Mqr1jYilwQV z*ceb+BNYfNtmBUBqON&k@hG{svcAf0-<}#=b*d~vkz~{<8)Jv`7rc);=h;Tc9f`mK zOdwF7nS&CmMyYV65&jDRd$p$2O?_Pn)a`T)KlXg8`|hvzANof1C3R|IT-;=mM@bUB z`l>5YJAS?S${PgZiE|NaE5Yz6+0~#8+n4IHi_S*TW^vn~F>o6d)VTYXryt$LL z$FptO{$>PP6v*EU$-njk%Q^63X)>XP6f+A;VJg)UG>)gtMhxpY4xwt+K5h&i3oLp(8ILcj_4y^5R$8XJ5NlzQ z<4kY|aapW{wHFVe1|bqgX?Qr79kznr4z1dxIgGGM0_-j%h6##NXX6k+e$2y$x_SyFRwy$o9f68sBhU>ui0cee(x3(5k zIdP{L-aw~beW=T|-GRpHVP|csN>*VNR8XdglacQz1MUTdYC&>im6?UkL)tr$4Ey^J zC1W0!g9ZM_6f+{k;;p+h^x#vpDw?mypMHWEKr3apX{Ua@Ix8hJq)8vV>QJ(i=&!Nt zr;pUV!%?a#tJM6tOHlUx_1@G^bn?(1dh4MJmEsLJ@u_HxXNiK1HWcc-(@)mNAAX{H z=WN!MC`TW2Dz$wY^CBG&vdSSBI23S$*c=3lSP*_voY&?+63`$<3yGs4ss{MtGL=$| zXTd$UOV84=$DPOV64bF%M-`Np>D1HCQXz&y1`}k9L5k#&)PyTI7T&No1-KIEGfdfj z2mwLHGRizpr1VS(C6EQ&*p!&bT#P4qwM;c7-(dXU9cHo*^QpcenQN}qoY_mEE>}?< z*sC4+MGBT|P)}kOL9*E6@RWA%aI1Z*gMnrfV9gz<%!K{bzfCr<8{RB&p@v?pAIJh$ zfw*;Bw|e`I*6-$0bv$+K0r&y&h@7`LlUKj4EL~-m=G>vO)iZEy`+h31Bivs!U z5&0MY9m89wr(9pe0=*~-#5w`cET`U2u-dY^%{s=Sj^vpgVMm^&?4d zm8m}c_9JG2wHM1q2>YSL{)AVOMFMi8Dq)OSVA_PUpO{8G7+5A6Qk^ zAiW%V_3H~H70^zS%MA8*Bgi{;?2K^V%a-!sO;`;i3k8L^fUcd}bMNsw=z!r`y>^?L z>dO?PpU14ZGeu4(iUvpxHd?fL583E@VP=a1pfR`{;6Xe=D}iBf%wKGbm9sgDC-VqNugX-N0u4=kIiV1@R; zrn0VrRh1|MtnL_fgFFO?DcIoHz_H2#M+sORtG)jC zu%BANM6e167E30eUPOi4)Z8pAM(CdeGGhpy(vl+Rn6>0KEJOf?)w5?`1R9t-3*K@- za?_Kvh%)YhY_i(H;w|?ihv27qD`5m-dU~R^6%_It#-zFd?*@u9{{h5l{qm(yfwAm? z$4U#f0pk#`9)3997ho3wXBTwgx;lg_!YDfjrNpyHFzp6bGYAi4;flFVpxFACRELA= z(|;HO@GljGAyaz;9RFbY*!TNv4di54qb{Stx_3@fFf(0^RaRZ>2%*|bJDS7~T!NOc)WI{U02Igde!-L#P3cWOgf|HFwds8St) zj=p>M740Ykz9P2LfnfL1t?TsTrbe|r>_lL+cl6M6Z|T)1A7F~WAY`VQlCb=bz24|d z=URwzFa&j6+E@&`C0i5+tzB{+0||L*i&E z^KflNxi&7P!(o@snmzwV9e>)D>X04KmTg-cMLBB3OnER0qSRumAuB#9EsNyUI#cy9 z@+_9;*Sn7ZiQ#fZQEYbrA4jRHWgQF6+DPU;U1^k6K^-evf!E~2C<9Av+5Tn(S`^6N z49UOtgAkT*yaiX0zGeU#{V|aMpBb#~M1*jd(iI3}bP4Pk>K4%n&qdyc)dq?X=ni37 z0?|8kS?oC2H#IC1ejAV1LZQBRD&rbXY;~Lr60+cCJqvuVUF=4fZ`10Po5{i^a~%fE zp<~C=cxQ@E8b4lBXHJ93L{U04N)xP_qWl611R_{1)&QM0Gb@X3cm4 zh9*$kcGF~N69otx)R5a+L2@<@9e)ft2M82?{myaaaZfXCYA^{J0 z@0A(L2*KhqLIc7j=cFK`j zGHr{}<9Dci$5b6QY78+HsLJH`j2<_h()D?2-)%pA|LtU5dCx?B_0}!we@u7AE?ZxJ z`6=Xrp!V-LL~*U$`e{wMLX7Qcr=Fu7J9cW$vbEI0s-xO%5qS}lf%hmJ8Qx8N0{D=L zlZ23UkwuY_qkzv4 z>TKm4FI2r*>o=8Y-m+!XAM@#?vyOM>&*I(1diA?SItFDmYV3)4OZ(w12bilEHy9os z<|JYtb`~{N^Brj(S&k! z<0)F4Ed?S+oCUm5gjSfcDFrGwRSI}i2=)-qpoi|b`aWVB9$k0+^>|km8Zl<1Zn@=7 z=AECu9^I6LlBnXpWTU-fFx25CM(Z#zXqttJa6GDb3>h!a7%);LjA0^4x7Dn{G}9qa z;zKPSh%-0-`kxjB^4BBsFaFy_wl5qkgtz5?)R1#PQWqAGQl%6c2^-lCcC`mUzga z$_X@kVLM?mDu2^9e&eFm=y(=YP=_3Hh$D!NJ#^2V_vnD3L$F-K+PGz-h7TL5@#Bwk z=()=gGS)Q^wT0kf)#0hsBb37gMss0ARhHM0VN8n!;uo2jtsILq4k~Lt0nHeAx?M*@ zJ$|peGkRqd?WDuta&_-GjORgyJ5W#@0{^btuhlu{UanWU-~10t zHKcbZ_3xgmvYHwNa@s&}*rl!r-rZR1hn{q%jyv-V$Ji(d?59GK5K|63oFb7}(gfe# z1kO!?Se(of>EPVy{4-C}uzsDjn+|?+ewwFYBL-;NtoamljK|x`(EdXP0zod<%lF+& z>?K7y{33Pg&|2r6d#&!c`v&4a#me7WfI!7?;PH$+ptHW2{;tkC={jwt!tbtKMKl%b z044V(m{mUgG<&`iR|x+sz+PrBeaS>V$n-^(JIRv;75t!l3Gh!@st~~gR^R;s0M%wUJY1Coe z@p>yTo}k1-UH8x~cLUx?T~)E3c(y#qw=?7@-O|w1xypEp$?v^<+~gpg@rFO!#_el>{PjyF;*k+&~qU6z1i7v-Dg99%E!x^N+>Poq%=} zL1noIQCLT9c5l*Sk6o!rvlp34A%IQYC$hLJV7nwZ*gn=7(2iMsVKUjRhK007=&W11oRK zW)?P?)Tv~g$6!Qd04)U(%*oVQDk$8oZJ!nZn;CP7`!R^eQwW3=FzG=lj1fQ$WZM(i zwS+KBj@-U=y_OTR=t^r>^af+VFWI+8*Y@;OFQYOqc>yR9Kf(Hro!Zm+uNxi<1@a8! zH^t1olAs0DhETyW4PgP-QAyTnktM|E?hPWNP)MKOo*UXuOER0Adk)Umzx8$7`2*WLuQw>jhtwr;f!yvno zfHEVEcL9)$#cA-mT;x%ld*(SLx<&D1n)Jr)*XuQ4N_#e*IN~py z*ZQzqwuhy*Q;ySJbKfwq@W^Y{1Luy zJanCoGKSjNkvjaaaSF6a)XjDSM2rMDJO zDS>f-&;s??>TrcH48p7*%Li%M{&oaf6v*F>$-ndyymU(xX2F6U1DTj$jA0cSbrSv} zg02FKJ(USeSdp?O)}<~)VAfBN+z|dIpok;{v*Ei|(9ncughhu)K;|M|EDk^fIEpZi zdTO<}fn)7|o)U{%VPV1A!pyeVMhOr}yDlAxOStv&Ywwbma2!dBz*h)8V|*o%A)QSb zk?jPfcLHM+(m!O|dOQsjQ`@%fD8&&Z=$?b6My!N7N9)(Fg?j2&eo-;~9Ws=HXW;h- zsOn1VT#EY{zMTjwD^x>&bozCq5D<^^x6=Lt4&Yvi(co5@@MH};&5BlS+N34RmvGNO zOSE^b#zLr{r95<;-&KqxRR96`_~@ns|N1S48Bp+FOeM+E7co?qQzf=WfoDhPUW{XDbbCts_?+;%)Wve4^k={x!)AhwV$ zKK=nMShP-&QVZ_aQU5IiIF1BTpsD!yF0lQ!Y6*mi%91_IQ;#wrPSoR7y#M~ky7R8P zHK2Q<4mti%ezR7a)-h*D7WLreJp24}&Nas4g(d=7Mqz3-VPN2jD-9;1&j-062<<#r ztOEuN1wtj4$<`4JJWJqh-z7`KJM_`!&C7Jq=p%IFt+zm$@aX)@&e0pMOpu>@a*>}E zWsGfu+4u*bwF{df^}S;eSGr|%J74@p|7lSmKl6k4vFI(3>%mfo2+N|zg{F8Sabjdt z4e$~ic&y(DpINn6Y%M2_;X;X!E9i9fgRA8z9#<@d-=KW>+`9fXvWSy$XJS~#M(K5f zId|)sq%%)G1>@VLYc9J;@g8Cc2#9P7(v{$0IE|uMTvpAufc%hI3l{23`ezuqXissG zQ}-x4-5?$^!K>Mavm_bn`k<6crOv8iqA!QDyHL+R8JvuOwilt5N|dpxz8g0;jP zDpbSRxM|kp4%6?#iS3|VfGex$gC6x{sZS4LI}JtrmO54u)B%YWWy}Z2$jlq64mfZi z7B|8_Nanv85DR{ssy!rnCgXj0yva_yX2jtqTq z$E$As^Lr=o&k5qN(Cj}_5&w55`ty;0-EUeH$j|)znppHm8b?@K{srt;TxkN46jY4j znppXCo34m|9BzaILe7*#6d{DzrN$H92g=9TMwCFs``~-_g;IjjAnd_kQIwLE!jVqTx(WRsYUJq)4IDrS2S0Be> zwko-dGVvp-A~CLWr$Rq%&-Fuz&BlVQ+*4o){ty^|e-QAXI1n9xl+dUiQzWK=P=q0b zcImFAswrBp_3L+%AG3pU9puH}aU_zT5F#FvL43t5S%bJN!O+-aMtyao@gpYiv5qZ? zI%6&=U*7%bVgOKb4_Dr!XSM|~CGIJ^_9%xvBA{17Beg;-rD`p0lji~;kz3JPd}yg>_pxEr)z=3yeb2x95wz{ zr8XAmv||ToNXPD~!h<<%WG_wnXa>ZLfQBA=B!v`XD49mapE_E^?`kNeV@kFGNb9yc z@1@U7K%c!o37v7Zs>ojoCAc(w+IJ)i2DJxfRUH)%;!?SP=13jxeEXa(s@}bYoD!hD zD4sR3wIr59Mm!aXYfG3f$*eDza&t4~ttaV{AbBbAu~zi9si9b;%arLJAWq0832{wo z3j`OdfUQQJOG8Gy`e*jjb+5gmsXtD$S7Ayz*t%o&a0q7{oDUD`46kOF#vdfdw69|r;rit%;pa<`{ zQ`;$beczMM>)A)|({sm6J=vhLwxpE#6Z>fV@Uot#jyZSAkM$%{7xuMvK~wbElI9+}459Vqp0d#rf#I zpi@{d%)QQ?GhJOe=TXwUGpK~0gtAhNrz@WiPh`c?#jssdsZm9LjZQt#vXuQmz(*18 zyXc8sMWMn*dT@8?N!Bq?Nm64C6jp+$u-lv@Kwu^(Z4UB5Q3WNvJLD;+BgKAgyX07;S`Ha`JX855hKso?K+wI~twqH^nmfy@@)S#60sfJ+Qyh)A>;l zVMd_b6lxPNi<=(nNpV?-?+Wf2Wd;^!$MlmV=djgK?n4GA>W2@55F2vTbMQqVXw)-H zK#BRYlupSOtP9PYJw?@cdC5SF27Lw_cH@Nsb=v=MOd{NmB_O)-;u<-AjCRL+h~L1k zqJfk}UQ%`0HMf#WQlS&iJ5^sTuGH`@aq<-HQcXfoo65tQN<*uIhqQvN)kbIi{wlTa z(1SM0E6MMPP`DG2j#4OL$PLw%z^W*}D(Jf*lxb~MkPeZ@ph%K6eaa-=ck4yE@~S7b zWy1<}AfKd~YSuB>Q|6LYV+hq?hy>cUra}VBhI!P6CRW;28qM%Cqj%ZJ<7!cCG5lxK?mO-@0Vw_O4Z5Vn|hVdc@gD zz*GK=LF1|YHn$c9@-sj83Ko6@liLfn?83XKXQH|Z1Xk9=FoLe@Mo<}LHC)YwB4Eur zvv|8Pmm(Ba3|3=7Gx?3N;&rE(yhhLhX<^kiVl_5lNrg~KN$?Rv1g+x`I6eZ4QP?UL zcx<5LL@_n1nxLWVUcU(ouv{mdbON49F^N_yVGXszBBjtCUP}TojZPF7oH}>D29p0V ze8g~-!)m(k*%!$uj#DNv5G$pgO98{usxk^8mZ%fZm=|k#2m956nWqwmC?l|)MTvG7 z!OxD}dvi{3e+nzMX5WKHk8++!A(Y`bk^=km8|2)7eqkYskbDs=!SocUm;be9Sbtq-Z!KLcjucsrHEXOAiXs({;ZpiwGp?#BQPVQDMro% z0<(m2HRqggg6{s~?HWG(5DXJ0k>PN#iei;DTF$r+I%KF*F`(yueYKTJyKl_y{y3z}--dEAd_vqD4C6#0&5S()3oj zN16T3&>om?x194L!Rit{=`E2vyHalQIII_WNokebNv()=tZ}l-Xa2BSH{E=xQ=&iD zWAQd(P{e3rc#chs(@{qs=fwPen0uZ+`FfHTE?=k@UVetsGDdR1AwZFT{L))mym*#c zr}%S`^67{M3`7 z=~`^VTCKW)eVUlyF({KM#6F@hRGL`0iR4Jch?5wc<%=deu@8f?tmS8%Szid~C;|f$ z)#(`mG0`wD0-t`!Ep?cyeimK~Yn4DQ^{Sd!kj5&q9_N)5B(yGeE`)Ad@a#m2Ha_+I zOS<9OD;>^$96@mtw5GGb@t%qv4KQzt`1js|yzZ$dMgomHHNOe$*Ei%!zRXaNO)ev}gY4(D-&b3>i z#MXE-1_71hJ+*_AGE zrIu3t_=jm9P|NCfI`f>f_2?asQ97kYi|)%P-NI9lP|W8}34;@6nvOi}X7_d+wP@ z8a9$L@IZd`Wm|zD=jw+aW^3ZxZ_`X_J1haOD&m{)LQn`z<*?GI%Z9Lb@m$Tj4g-z( zQM?WHF&%U0aS#DQ%p*J)yekg{MnT-PcFipH?Ao9HCmZRkn1knC!8{9KgPEt8qKd-p zcu{yfl)ow5yjoqm_tLGm+^zltdT7OJyqdgjJ9l=ptL zzb)MQ0tTGHc{VP4=bZC{-{3zj3gl;g=stMqSyZeIRk@T&dGQeR!E&%z8aJQ;5PFu3 zK)y%Vk^)m;j$j>G)2JGHQZ$s(@P`0+h)Shs00aWoF*zV04lI7W7d#IWBv#kRgh~(r zV4jN+`lG--$Vrq0G-2>}KbCG?ySR^dmpe=(D-~kd;W6&JeS9lmD(IE99$LaCV8J#x35oUGSAb(Q;8|g6tJ;b} zVuL3olf?~&Us{1h4@{H+G-t{u9=Og!EXQ(a5`g!(LoO7YAFRs-a2~~~4)Sc6IV@cP=~RjsF%QetMZ z4m)~`PCn}tp2Z`3XBa}>X*h*2MBStFV>x1!-#SS)|?;y8rR2XCO!X~Gn`_}D(W?v7W14yn>m zT1XxU9&YJQP5k6zef!-sCvPNLQV$C-o}!?A$WNK8_PzU|gjhngR=^R1DhawfYbK*x z54=!N&w zk3hRhamNvY5d?vi9PwGe5Bepd&?$@E2)><4_IH?tVZr7Y(#;AjA|9OpwwI2FaYp$? zcv%Zw+j5CjR3L=o5uk|yavPp~o)Yh^^}$DD-z+M4N!6$gBr~vo@(224xX5iO^fbN~Odszah&*ITAb& zAiG+q!%39V2o=^-`^hqp{Xj|C+PQrTEGwXzFlAW4>8-?y<$qYMuT-wFoTR&WViY7g zvzQ6wS|GN(6dB=G+gwV2psX4Q^jlJ4keH7TfoRo*gS1&SZ!ZxhRRn=$xf5PL3W9M6 z5kH84|K(+Rso09LrZ8b3Ex~jR$^vDK!12Kz!~EC%&rQ^QZ-1j4D&a;fArHm8Yh|&v zu6iF*KsFr?$Lfkp#_6&v@5OtBg=V=cVCo*@)*_URHDm(F&9gy6;pLD&!in$;QBYz2 z4(q*%ll0ja2zS&)5)HkYxc&(*-K(wZ)}WZ3 zloy3ns0cjw({DBIF%f&f!=8SmkvBz%s=%bHLW&6nXYwo0#mzTHmmRoLlaLSY^M_+&a^^Z57i(V5o z4?q0yA1}Dzf;VVR6g>Ovv)>&yY}mYg|9y!<)m+Pi)Cz#kkcX~dXO$Ro>%h$p$BmbgqkP?xU_-Uz}ggrZ5!vR)u~ zA$Tz56@@6UEGMpGeYE{1bSNAdgH%vP5Wj@@NlqK6qbSh)9hE2nDIKNK8ak|H+}EKz zEHA^9f+@u+vXlLIEPfQS8>>5H$$Z>z1a^~`@g+VDX7AA&%Ex!7h+#o-HSiR{Zk|gL z`8O2^*^I<2Be+=vLm9v&Q)fqX^n71Xj)O8o z?wlr_ef*JRp_fr{mb@1pbPf%;0~MnEUv-X@|X8CqaZ^NLI{0`VDpi^>U>pAkS&H;`A80KAyq zCRgQ9zg-C^jPMp9DfX$wF~TFM!|Q@5jl1pB_HW;l>&b^u_Aa_rcGHCqKFBlWdLwtD zUR|2_;&#B&G&n`!*T^XABPZG5Op6&&JB&OQ zBV{yFc+ro?-%wvnTjsXJ*&3XMR@?0uDo?Tb6;oa@IQ zf27>f*lEu^^UT$zOuqg0+asG5h_zRweo-x3vbAPxZqwL&E=$@u<&;xCe&B%zZoT*3 zdvE{dn{SSK^2sOvuQF5Vqf|2qNmRWD#a8-T;D^NU>9ZFA?Pc@e5(mfJcVl#EfpNuW|aFyRhzk z#E_a$R@O&8VnJ9k@%#ugKRCE`((__fl3atO3!sE`-ic0#R)Da7kKS6pZYiAy5vK82 zrQ|CoKpnMUb`)#8+Cy!!%1Uk9whe^}M8o}r@unhJ{Vs%ae%Wp)ya-L#HZ9-2l6!RP zmB;U*BF$d!z>knbmvUDKX0Fq4D=WWm*Jkk`Qz912adST8lhOjM=??-7$38BUKDve; z-C^1gf#lVQl4!?WSO@m`G(5@`8x$?AyDmi7^y`o5) zckXtw%2TL(U~#os-+iguo_b6N(unJr<4&PYHE|AVnnh7qDS@2-L0!iWD*fsEeA`>=sv!F00M&p-eCczfM6Wq&{P&_g%x`+4(wPsuu_#=masJ8VQO4&i7854{9CZCXa)sYhXEIi*C5y@Q|& zBN$>pGCmd;GK3bT2xKtYsO@Xs3WCS-1`G0pb$+7Y z$qQ$Ft#>~9M9T>HwuYUQ3buU#HHPke{8{L|X}aq23-t~jh`~>N>G-yuQYE-TSh+E6 zE3O0@$wlbnJy1Q^O`tW6Z0qh&e@lAxRy=tljeGVul+yCbav%*LEn*%9uf+(aCsW)M zhe5sydPi*D1jOS}uTCAbn@nWumKXu{umXB@Skg@)UTc929NH;D0jQ?2G0nlwQv(nU zuqYji8|>QRIu_it!j67||31d4k;=1%pVy#I{V;Pd+VO(OW~Qu#RrU=boQvrBZg_u1 z@h+4VmM>n43!5n(rBVxo<^$(<;R$Av>{zQTz?hs}#b zz@VGB4xUY18be2dBG1nuMerL-#0wLH^2Q}O8YSe$(_(*U0h}K3gz{|y&P+paSvSOB z(4H|$5pSy8dVYY}_Zc>jwe*GZxGuB8!(reeVrG|L`+K0MMs3}^lQzU$Bi;rn@Wk5! zPT;spr&f$_1NksL$mZ{+-u?UFZN$g}aRCAKP_JIS^w8sv>7IukQhaV3I`j1KJ$HL zcRo>T=gqOnO=rrL>ehBJZ4i9wjW?TWuwiW}<={x5#AD34^BJYjS>rsO-6xG!#RVs$ zsxW6-Dr zI_`b$ztMmHp#u4hj>o_Jwi7XBnlLqE1V6(pV8h3)RD@Nm&7fmn9X&AIE(9GV zth^8lDAf@bmV_1pR`O!CS@l^rR=ZOT)z{!C6kvMyz^>QwoNU!Wrwvor3K>k!2Lcm$+=f_75(~VxfuzYg-~j9G-hh<|tko%@ z3rrfnO8I>}7JCBu7a^3E^-+&NQw^YOa5x;AszD>kFleetBx^!YS|5=TGU5%|vCQ>) zaum{0ereE!tv*#0#cM5fEr4xagwMzWcqNG`aR>(j$!vbA>xBtpGoi}gZu(QrOYoZzIW5$e` zZgBt8Pd|OlXbkzGLx;{EK79CGgZ%Hg=bk$@Z{FN>%a$!&4m#+d1&=@e`1Q>vPESv- zU`w~ZEkt0*P;=P9pnpS=*b*8GCtJ^0{* zx7fMfdFP#T)~s2xU+><%*V=FP-C7jLzN7IoytjnFSc9drF$ZDwSW!f?TthIbnotgA zi8UE!kM&oFMVUZNDyt%D9*6N)4HBu3R^!^obM=kD9V{vYiwPpbZey@q8W48iBzptN z^|h2)hlOPNIEwT8J<+Zdp{csVSz2y7pM^Bl7ZM$+-)#_Qep z-q&CnE)jRvs?8hNrwQyG4-0Q63ggClj=S+%+z!R`AxtnijzmZ+9p4DE zYrp;Wb7-3xxF=OfcrD=f7TopGslt>rz61)X0ccIyv3@y~0?3NMOY)#7JY>UjNZZ4~ z@54}k@e7eGJU3oA2})%zbmcIy*b}!1@5K06d!LoAVa1s)N4rMa&8S9*sVwjt&-Hg zLtFj0>L-2u;kP>D;S6X7L={9c@~_N}qi_gCd#}c;*pJ`}9X0 zea?w2u>bvL%EMyKhO``TzyV8k?b?}VvEW&=W*uw_#Lh5t=FCxSGfmiEef8DP?0Z&f zw87|(xh!sM2+O`+DXwXjLI2; z{+{x%{aX}>jl$2k#Som<2`++F=}uSu4SFKsAhwgnq8|gIo;pDG%>vh)>IK-l6VTE8MZN~DeST{q$`nc}AyB3Lw@0ge#XJ^3gU z6HEYd@}o3jD6J~IAuIWjfI=`Ew~3qCy)&OKgHU);q?MEkKmMp;(0j3Qq5mcklr`2& z*x)-LDJ#QbcC{%yFHAKXFBc3n^9o!<^sO6V6OfXJM9uhQm$vNMq0XHIZ#fpsr zqm3RmNMBBT9U3hal2J4{lnJlFt4hcvXiRWEj`tR$F}kRe+0Hz2JV=DQl`Qcf$T_() zW;Vs*VSw4@!(%X7wJ8gqL%rr0=FxDEZu35PW?s8q1eE2WSaC@!drw6a<_9956Pn_U zP&wF-#A6B(n8q96nJ18AV}?W)_+T~)|G>^2^bHB2=0RDh6PpM&1~HUt7^o?cal80} z3#brKrPbTFI@g!R{dH*DN<}1RuHUd(S54B2#k=YM9*1X0&lm20;6aOZ)9rWS&BCxl zL1yCN_)rW@^c;yNR^vul)E+g0>*qO9LZ<5PZ*`;O>WkaV!(Jv5|y6gr3zvGR)q~ zb9QRB3o6#Asnf#c9&FQ#J0Gary#A zRL@R5Q6xcXAsJf?fr{mC{X{Yeo|-b z#|esa3{yA=q4}Gtm}bB_|FI4043*h%IX0dm=LTZqdHKl6K+SVrYInt|@f=`fp$zJQ z?C?KeYvFm|rCR@sXgvv{8NgY-Hq3=;=8GvV9uo{moFUA&S#2jhegqzsgSZ6AKWL4(_DVjlF;paT!kci&E9#F(de$VM}_R%)5vDF!q`)|HMmtS_a6F;#zmPl=@AnY$w6s8zGC}a;61H1&r{XW=j#GpiJ8ONw$ zZpJuvl$PRe62%(@8{?o6Wnmh=k?ZhL^Q#8-SUlrr${~s#bTRLmxE~(|TYcRw zazrerC=KH$Ny&KQA-Krauq*_H*n=|9FWsmK-%Zw86e6`T>9xNj*PU_uE&kJ@Kz`<@ z4yOm@K|wm=1BB`vILm~d3yaeO9nsC=^1*?RLufSytH^jpw%`ePU>P|u1Olgqg_(rq zZdGkf9`l7GFhZ96gyn|`4ZSj10R&b9*}|bZY&;}@2cgmyD&i{kHGSrf&|7y<`|51H^yX_COkaxz8u&c?(gd}IHMJ89H9-7eX5~Ukv{Ph} z@49x$!wZV41N}H^5oXC)xUHahnlK1ZHh%l=LZwna%k8JbVNogPZ;QB0A&6N=kUf_m zCbVXts7lI?WTjF311r6hgh?;d)BuTM6)2Zt>Kq+?_!ty!txh_4FwkBMx+;yOP`Flw z)`Xk~YusaL=wx1c5C)>cZbe}cuy`8;RYZgOjV2khg6r8uBPifAerqt*PMT_^1@?|# zJPOW(5YFU#*sz2iLJ$R#APw*k3|5K}Tj5!_ct#Br~}8OBC=bSJpKVwmLlyjPD@r_pgvN3!xq^ahG~G0^TvtFchs<95J+>t%p)c zfiY_;W&%TKK$)JJc>q30)js3#t|#UX)M z>?q9feCDN~IL*l(N*NXhvf~~L=~HiUm>Oa`Zpal~I(H#SQTp`D56Ebrpqp>KLtQ)N z61T%k;Cfvs9xpj5B35K@u@A$_L)^)2&kZQo+&5Pm^8;8g(wGC+fbrtvFs1PK;9Wyq z!GnQB&As{{!`IJdEbCRvMP~n0{TfXk7t|kk+Jl868`hZ(p_Yc|eQwvVN4zW;0a5Npy!>Zm!VRfaaK<(s?0(@6cTTWp;=$?2*c^xvf zdihEf;~`{b1=PQHUrLjt;icr$#+Kwh#wN}x+Y+a+%DWa^_YvR@h3KcfVUbQa{W8s; zGg-sOju$i~&fw9~WeYfNd)P>=RkpPfSTBHIz%wDpYrUt^le1v2q0pg&mhD-tfF~6X z2EPw$KZ+np0!nFwVPt*I!(?tp$&m>0YWHHaufd(tbu44QH#THjxgOE z1L;{@A8`>gyeaBuZDft{X0Vj?Sg}BRTmlLN>%OkI#_=wFxU5N@3=$_%J}@R4!CJ6A zu(W~380U>M*K5d-!9Yd^TLBA_)R{(E9J_{hC%yv&=OSrxr=vW(CezjzMWH2}oO{ksX4`zRwlbH-HN@cX+oZ|S#Ar2waR zC+wvIM~=p`t|r#x(V~^BQ1Co|%C#31OsBC{Cq4eqb;M1wot0>fq%4o65ii_L$ry`= zxPq138*`K_ai>}?3M`ifRwX4=lE!Q8*}fCy-@}w{Nzs7=`s>rTU)G_=AIDS00HNb% z0(mRpM4lzymY+FpC2AsQiDZnQaVMOLSHw_rUz~~YCc%~T_X#gNrA2cV=!)xa*O$}3 zR4aD|`8ydHSxeQrb0!8D&yQzSp1+-#UzeX*iu`=1Z&4sW-`G26jsR?Xuo$h3hS3VG zV_GeAMT1wIWGpN`nh-d`-i3u~=BbAwiwOwr5YSAcF?kSjR^uv)$6<+5K8T!ga!P2>#OZ1Kf<~R zT2JX3ax`k`h8P7hNQ7|(-lGhJaUc=K5>&xF#B#D$FB5!J>TpWSLvpb;~noq9Q<)AbzV{yn@<} zD%`P*f|2zajU``&0bbP z4wdTFr=tUb?$$0wr1y+ZiW}BYP-p zMDQ3hlrf6LfIlKFdi%i#G~me5950T(Et}{clg9W))TK*jZQHVy&trO;T#ySdyBJm+ zkR!h{L#K&~%yEoq1D{2J$|AH)uu?Cjm4)iry_3HEW;z}{9vJ(e8BpwQYPjvxsaM=g zTjAEqW?p5s?gUfPt9C>CscOwOlIwAMh#z+Ddw^Z;Z+2@@AV2e?Pi8{LfF+EV9!CVx z#VQTZ2i&q{ZL`uNG2k7CrkhCr2YPd}DiOpiVq?#+@(e;T7|e(JZ&-I7Qp=67a-&cz z0Pl3!!$MBN3kc)ZSf+X{0YsL!6D%!(Z(j*rxNE!i^wF51bI!jAoH|MOKK!710})si z+%SSPhkhSvshRrhhiM!;tVgNJ+MAZ9PXR%+#rr5BbG)818I5r0^Jt=E?Lv_scqf!| z2O{%wo#yFS$(2kpwp|FBq(GKx=}PFuV~9Z{*s*>iodeShI@iv8@<@OVEa$}wb0(Sl zPJnV{RcAA38s$w&rz2vSy7lO&85Hab5eFE1&ao{-Yb%zQ(uwP%t%PX-mDI^YBO|G&6GT{+i7T87dIMmcOB+o5hxK!f~ z?nlq?hY*r+Bo1!k`2fUawA0ds(>3~#aoVwShc39}3g8%Oa0yL^1wIU+eB{B0sn_6s z$|25V#T=*4_)LBK4AD(D+^ItDB{6`Yvs@ce;l}MB(3Lm82y~K0pqe-q1c;{|eICZs zQpU5Nrv0>5`|m$Mi-}uR#j1dexJM8bAK1N*xYteBU7?OW`)bqT#SVL`U`K%ph+|n^ zMHBNS9zw$GML(dd0@_LCi#j z)#*xtnrz2wfJEUp0k3nfC;j(xY^SpY1y0p*R8&qdrwWjsJEg#;dORu>ah3eZ=Th}m}0r<^sEehmk ze)LUX)c*gEy|aLGtHAdEFPS8hai8f--Q8ViX-k1poI-J@xV!t}&a$|>yB8>hQYuua zyN|mhGnpj+@4036b=ki6fBW7p54O4eOq1LsH}{@?OJSxjJ=%NcQ)02qW^KcWWf4sj(Hf*47F2b4 zSe;-v(T>Jp$OMRRP%TbnautlMNCXxaiBYRSFDWdg`rAh@txTW`uxaubHtW3sFBTGw zliY8NW^3L2IUE?x`i6}GrkO{97det`Yt^c24-B!7`3{A^OHc;L0U7zMmg?gArSoWo z(ot*HtD!a{s#M6-#*o3IVOEbTP zt7sh`Nuk$QDZ`0+V`LF5#`=TzXHeliks0!RV233*(MA2X3awpNq+S!JY3|aW)$2H5 z6C%t;as+R_^D*OEhwCZke@xnEZy*$+CvqEN+h^SRk`6s^nqGhN2|B^j(+eZg6(e-s zh0kFGGc{twC`?nlQlTp~kdH|qGWBB6sxZ*;6gIy4;Rj0NTzY8-W3Brm$e{yM0n@4c zFWy$JEliwjm6xwA727m?!~kY!lxZ_L1|u|#9x>d3*FO62J(Bc9s~8i)A*Y9w}8N+qseiEtNTh4oN+@w|y5~iZo4;)Yr!=(ne%w~7z@q27c6~Gr^SSd#zawN4B zt9AF47wgTp-`4?C_TlXY)rOL^sjz|s`Vfs8wFm7kP|73)mQi;xZrCubTEA8E7A=E~ z1e>K+>e{{o6~QoWNJ?8ol95SOG4I8*4@LyA8RbdF!^c~++=L$zKpfsCQ!h9gj2s?x z21e0quntPZ&wW|}4Pqc(BeT;yjx_504*FS^qs~K9iVgU(v#@9j%+E`3W^}G&R z`tv-LX);hC-B>Y9ZrXJuc(O3hFs(3N9ou!M#rfAx#FxyzZr#3B9oo02+BzgJGBSC! zZqtpVu%Dqt)UV)83uxo;i6b=Uqqo$tZzpZpQmh`G+Tf96;GiUXNg(fg;3yTKq;1et zBDs@BiX*Lpz6pXsU3~?$2W5^YZ%q^ZK$9Z|bWkf~wt${wUaLq4W-*4H!7&wUR%+D1 zEOJ3M)BW<)!Eeg6!N89zoo_Qe=? z=B;m_6LRy$?Ho4|DwW#BP@`=+-+~_(I(0)v0I=N67oUCZz*TWXz&2bd&Z)}Ad%+Oz zD1^jaAX>mB;d`7HidScmGZ;E*tW!wH#R^@S&k|+X-1YcugJK!{)w(U@D@F%o_~>6& zpyjKV(?}EOjVQqeXGLKddW=-Um-jnvy0+ebiw5-VrH!k;*YmHupf5lERHM4~rZ*Rj zAlr6;NZ`@(pO>i{5Nz+B15o-II2`0-=6&bnKdNXH>c)eLC*s%uRXdlW)Ml>VG;$jC zs&YsVWtJ+hyHAC5EJ#XfjxiuMCY7wx+aYq$!wB%yt5VLW=Px<#xGvKSsfY1vzp?u z-28UH5#&q2;LDoJpaWN-xbgnjzD@754!YrRnUf1hVZKKdQHvGtdHG$tNrUW{MNjcC zwEQT-X2=A_q^f7)n-`DUZQdgZ&;WG`DR`SvJi|~uo-L76dMQCsm1dFF0imDr8L~0h4WQ%O-$!E~Iyl*-QYvf{uerDu?)G)N|-JPU) zrb8+96G>Pn*_U5howAD_nKx4qh-FP&K!oF`&n z_KnB}qaTkWFmz}i;6ICYXqm!rvC{2Od0|RfkH#>ptq95KP3wzslBmtWnP?1caB5zR z%@j4Nxp@ynN@32G8OZ(i+aF^^-A2-EU3S)SnsP*Yh3|v_Fngi4EMBj7UVMgQug8Gb zYH@HCRPyysWETdywL(nbC5#tN7SXWHGx6Z4U2)Bw`exp@w4Ohdp>2iyoJZ@{Z`Z8( zOZ3?XpXk)HFVfpjKY~HC=p+LNAz!6iHfZSJvE8WgVF!0C7>|~xyY*wtfczhyewW~z zlXPyT|B@Ah#RGd7ypxncXwIYI$6o8#L?mJ;3HPCMBYU~<6HvnDt=3>Yno)f57=%PT zxO#dJdGMI+);FrJ7o|b>Vu!&59|w5MSX=-|C>N`P@PUi9r;Dk5ry!>lY^)qzc>3u; zG;vIYTdk=F9_9>3`ry5HotYeaj~%BM-+Wus4j88=UIK#YQ2;+4)(#Lu4i)I^1`L^M z1~dV46>fvMMKw3KUR7lg&!O-VB{flZVumdduRT5ug^jTZpga@Y4UAg_s<6U9tHKAq zg2>9TQoU}i*xAQs6s^q%i6i8hyZCz|hu+NZZc-E`(wddaF?wT(V1Sp3ifB8Yfx#j< ziyZ3Mein4tY{r;w!1LW>%q0Ez{r5m>%)2m!Nu&}1`e}ChYeCt~A}YeTBw+*sDA9iX z22jtjT0I8st;XCH>JL7@ZOdYy!BVZ9_nO)zcT&H7E@TSd28=phbUel=j>w4iFYP$i zPOUr84kncZ?F`Z~Fp8ojI_JtuIkr?HgLOokkROm;Bc4Jk^EEQlb2QP z7|ilJ#uj5pSY?BfVJHRoY@9L3IL>BZDqAvh+8}#I#8QJ1fl{0boKsQG@nA^YN#vzC z2bg3h2Nb0>jtywa_AygKxu8=g@jbWZe*31TefK_wonyuzSc{r4^&L?==R{>qB-Jy0c?^_- z(H7(ihp`0sV0ArYolnev# zl^6c(7~m|fg9roOEWcyTIAhDMB@i!1#$>%sTD@*LcRY<4M-SFACh^f% zo0cJcX(LjprRypBV}C8_p2=*Arf@x;K0YmfWBZNM{2#v}$3tS1eMm*=gz)w)GOLH7 z79YfMhXqtfReS&b!}P^FFR63Ckt(Ib@5m9IVCF7Yn@+uy4Zd#^>8!;)>Kr*l=>l9z zN7XvEo1|}N&Ojab#*tysB4`|fwBvO~2> zi4Jx==2iuL9B;Xx-B`oLo$Dq$-$tXBIXRU^EN47WS~+cB!iK9Sq-)rysm}Q@29ZUX zWmMH$jf~%vqb2rhbM<1bd2` zPZF5luui_MvpX}=wpcC{YE@%3kPsw=MCOKXtz=qX3H3UI>4Mx&C!T$Y9{9`cS~~YD zojCOleKzYprv*)qy(j91vo3=)(Lv{(exg44{A;!CGXXsBL888YsH^a!S%$+j}wjDjwYH)FIj_T-z<)zhq zfNLJtfa^aQXNmk?Gu;pPXEi{^+B4&oL~?v2M1<_2bP0I!2^^I5Osj-gK@@KNxJb>= zN2`n|kCr5y$Ml>mz5M#?I)ZC5llCgj7;+oYY;a=}*Ivn{6;3`W909)aavhRnvq-2q z2>Xp*TJcb*qfQduwisJ}ErFN;`L#rTQ+Q$FoJ>D z)+5Uej1k988X+&z8ro?XfVv(|eKIT?;uc5Q1@Z8VNo6^LM&3)L)k;%!P(w$LVFc?O zO`dXyQ*@Y`(MsXfrAoti6;Oxq@^gH2DhBre;PSXY=j&0l5!BC^mRYo4w@>LGBlL&@iOXI|%l0qFhWvtG*=vETI z;~nE`NqiqsiA|fVEZd6m+hNcWsR@c=tbM>>>21<9dXHh8E4+7A>XCad<(jG2xbee; z52F0;oi%La5V>Hf(Y%lA0xE2_o5b<{>fMRTZqoL{_8bj^iRx|Uq~w!>x%AfCHF_`x zg(x=;qh|FiwLqCg80#aCIRwUBCXr(b^FGL(Em`JVi%l5MW+F2$tye7Ch@#XjZ(?Kx z57)8Pt#Ebo+Q&KNe8Db^kV`UXE0aN4&s}=8wwABs`Xn0Rn(s&bM=CVsxXR7szt+%T z)Xx;hT1M?o(4Egds#=VkwJia;<2u11v3Bij6MI6#(ozTBvl%V6eOvGIrU8!v{SrAP zm;s9|yOco8fb3E%zuihd3Bx#UJmaR@3~1}#YQ6v5Gy_ZmCpRUFlM3z*-X2b*usYyC zP#I8o!(o(3J&$17>C|eJFeAckV^>I!+OVh$dQw%E*Me$r<6xws)Dff;k<``UrNVNu z#Y;p(a}?kWs(HO#Ib zfNmJFga_Wh6vQ}^D8<{>W4LSv92l+Baq0yp3i#jmKP6uV=W9?=d zc#Wzf;msed>p_4V*3cBHvQ1;nSnwltGR2M;906MMQxEgy8?#Viz-(6k!tYzpv!|c( zqhKKv(E1}TQYT-4d;pFD+T9xRIytX5KiLaN3%Cel)(rIHCQ^zc;!W2YQk7B^|Km6e`X8X&lkT9d|vdCmwx5ue|w+?zsIfJ|EA%_*4#gfGd!Z&0M2g z<8EOiecHZ<`{qQD#;$MqaeJCwH^R$LG#pti9Jrvl@F;jvm1 zL_}3OWD^_-i%4D8c775=ZQrfoXdy@mQVBi#zVDr$>K zPIHR+jd(`D+6P0x2#hmO3ONOIEbtY|g8B+SH<0B@>W#UD^1zVkn_a36zdCnX;yU86>u=XfKisOw>$xV10#*fn*Kr{1iJz!Q1@g5v=WZ7$`20qA@>k z7d6-D-6pMBy_Bw}$wUIUh8$BoFjbHQdSXTn1EYW(Fle^pNx*OQ^!6>6a4yV{%jgTR;zUD3Jn=F(3yVs{-GDnFBT8 z@yIuxPw-`j8pB6{DRd{U3LA{y8MRA znbQF~4%tQ%sa=5iWD!tRL%EhNT&CXr2Fp`}Ax90`=-NcvZxn8Tnx2D?IbAP&@Q?!3 z$5ap*Wdbpo=bdcL{Lp5V&}s{yxYoej`r-3g%1Rr;?3JF1Ce%C84t->aSW(O=5%L3{ z>#)NPAb*51gmD(64U9#bHnz8-7P3TbBCkEPl)-VR!dMW!hJ2M8HD&-gtKPZ@qQvBB zN3riH;4+*P40|RuLQT;+rUT|68>-)_+ekEec4MAtq(vOlX=hH?ORv0&txu%&OeX0UdWeNGfB+Y2-n{vc4HBLGJm%+L=pmSZH%{sIQ3B&R4Orn1^vh)nW>o5$&ut@AQ&vhb)SeqT)TcbwJ_w% z*e_QFZQOxdyLV`#`)|7(MO*9@oKX0hd05{Ma)UkT*5ei;UqO3k1>1|wagc;*SFOr1Oh$^eYk zXs;H9nCBOV(hJm;;%Sn;wD20k;wI~eUdE#e0cBAuf+BZ3CKQNyj#m5O!DFNSH@BgBS!K z)#+uj8|{)rb9Oq0k-ZlMp05A3M^-a;q}9zN^e@LElp+W*{P$Z-*l@+j~S~|59z0= z<9h0gPv+{L&z7m*m=Uxk|492!9>ulb(*6^3^~(FN5dj#KL(YoxaP@7s>gC5CgdMkv z=#m6F4nmOOQwf|rgF4G7eu0^NT9<9hMrNy?&&@5~=(>yA%K)NfEPjUKnRKBPz5CDZ?`ljhDM`AzG1 zqD>DBwcdk9I1%PPllJ2^*Ci2aJkev{9z8iXqlrkNVwY~x=us&;?d(&y4ly{DI3`J4 zhjb1&j0u9*U3n4tkx|sGBw&QA_52Gj>D+UVS9uY}lAKUHT?tCb-CTd;4VpFMZGAI; zoenr`3i+ctoQ5sxPlfo1G30f)TQ)HRWZ<|FI{3h2iJ+jX6UpqnSj7JImoIDExB2~K?w;v5HRqmnvVLB=LHitVppNF+Nhc>0TXrphm;u?fTz<2)K@!W&Km~5{ z9dQhms$-H`8n|#H7;un+JnN{6s&@XOM#V%C*%;RlUY~hwE|hWu&`B8l*ye1ro;uwV)0+un*APVN|qHC%T!x3aA zxQBV@jm#Pk;h|gMRD|TDK|GB_CrKzEixMIvRGB6Tb0|%-X3o)wapTmt|3JLW4C+C) zJL_FUR+b!H{?lwQ`yIy2AUQ8NpOQ`69PcuWH*ZLI6US;v=6Z~3|6T*NiNyG-m8;Z~ zB)q{+eW(Qhlp-o2f02`}c|VjmEH;Zi5`d|!Rl8NZ`^f3E&hTgnt?7+&8>Pa{`X^Zj z-4GE&BMclXcxy0OA)qrul^WuZ4p_oID zM!MeCC#qMbU+d$_FhUqgj&ZL^eN?!9KF2~KBJ|#x8u9}49jm16{i##N=;V{1)a6%S z%#nJbymr*}FR!NmV44OFC8EOMjGHim->f8$!R(WPd5o~#fWjxbt1m`*X8|KF1_rBS z6mJKp%{UKS0|_Wgt8QzAZvE(kcj*)=;ggYlb;UBSfgQPt4ckkgw+6I%=^CAM>bV?a zo?|A~3;$xJhBrzIdEPmw`$YP3J)vtazkui!BT-)oT$(};u5_*64(WhIb}QP}1RAz0gO>7B4%{CI z>uDfL3P~6Kq={qp(s~SdE*0VfxZch`Q2P>=*HoB18LcT$>d0u_$_6K5v0}wVD7w_V92hlT6*Jt* z19Vf1@$=x>`iQU^U^!VNg>9koADS!BVFS5|Rm*^#diEfXlCDtEc4|I=lj@NJShx>w z+Pr=X0m98Gdi^iY>x4=D^vMg4VU)cgP*c>@#W_ziNeYX&bbTd(#}s4H4NupbQ!s^S_;||^woQh z@q0vvQm9HVK5&B$-)}gqwpu;$(8Iu*>AK*Gi*`0p>; zN|-w+3xY*X&%fSL*Ox~$Ji9>G-U~cP(OxRoak5hrL>?)L>l))+6Dfs!kWH?lqYgdi z7=6xADXT&c0vAr4au5-84Q##++J}aTD;F<@jb>cLX07;Xow|-XP*>ga2v>Gk`T4Dg zgfSX821X2N0g)GTm*axiPws$s(x)nkOMT02m+RnUo?eo8Lz z_a+!@2KQKmXhhCb6nr)Kc}ga1HxzZm!=%Ny3>s3FsU%dS9LCQ!)*WHqfn8 zRlJ(PO*90o!>DC+=mD%lv}<`R;;Txk>x)CwO%Q$d!V7=v-FG#4?|qo-(OH*MPD6&a+-tnk&yCqeM&sI?-&?3tP6)^4*rt zwLG@0|7SeL49Gu2ivNpkbZ*sJwdG9|!*zt}3H21lO=D!UvT{2>-=#(Q)@^Y7q0^GY z?lGnltwew_sIA~y(TMir@PM;`cIG>Z0>9o-+^Jmjrm&(^uop2Aj`_-#JqI>|-NL=# zZnoh~7zQAVWcoVg5ru5qx|N1{8;E9HbRW%twrWb(q7r6x;PJ)#Ve^xp$cC0`kdIY_ zCjv25kW=W`r7!)tDz$3qN_FedjzYwIXIy9s-n^Trz=kl@^Ep2Sib1@~CZMc1U>9q< z(!f+aKT*PV3K0|9W;^r9qfm>3B=X~-Vg`YTs;S$^g=(CI5;O{HIk>s8&77n@AyXFH zwd6e}4)zSj3aH5PKGr+TzMGhWJaFHmD9#Wby+4(Fj~^ok^K8J7ks2^`xVCND=p=Ui zB=5Z>(i`0t5t4NEko+dEV}qEYB!sf_3TWTmo^G`X8oS@g4%3N5loF9d9~Rmkd+x`%Bf{87-3Sd4 zKZcSVYzS-98#Bni_~{m#r`5A-HJYAS7EQ*dwBcNB(Puwy(Y$ZI)vNEns|znY*MU77 z$U|-4UeESCVkD_%&zb?m6|bSk+(>2rV!2bg0V{3AsrVX3T!Z?+oSJ&XM0M%WMi*Ui zwNvSC1C)%xH)hl*WL>V8-}wmV!>`=Dbf!|KY2w(?>X<)R-+un1-g*6Ft^7@YI3sE_J0QORcURq+GaDa zB(n?c@U6}zksKGmCd?@tqGvTm7MuKfNu-NGCD(`>0)U^KVMDN5eQ4~MlNv|s`qmma zq>mOX`4RF51OXf&E}CC&;$QaK#@U{F>ZwnD_~D29+m9T6_~CD`9Nwx`tD-&j*ke}9 zbDKU0WDLXJAEYiQVe;h3pO}HT@WKo4vyr#wo_p>?)22;(jb&QP=j`#gE{9aPK7G<-9+1_*yrKeRK@K6GIlyxZ0B!dve z-}9qX>#L0I;?lVNPEazm(KVZCK$wkX!6~h;E5vwoWZpT&bttT=t#q^{^06t2Y>H?j zMQI&LPAB692a<>wXv7$-Qf5UJ`RBuG>d0?xA>O9cPAB0W*flM_C7%h(B9Z^jmuKlOOcr7t5UP z!f7bAM4+kGbTck0U7-oX`{~$6C`^0n2O=gfMT+kctw{q>%r?f?Lo~D3o?|tPK39hv zbB)%|ehMEq2nN4EJrBA@wZ&yx`15+*e#cGZkW%#8taVyj^)1m>4M*bQHv+07!hwIQ zt;jTuj>Zw-wJ3R?+_uzQKxxh3nCctqblb@IJqlz6Pp4?H#oqQIMV?-Ot8yt1*9eU!93v}AW*W!#&KSTTytl!3Q0CU=P3?t1F z`ftv7LGQl(w2nXSL|X5pB4hRmsHxcx1WM=VDMuepJN5GwBJy26>ovL4h_1_;nIluG zL=4$YS6!fw-~U{%Kl!+ZZyf&p_ur3h8CSdWa~#9W?Ck6^8;5HK##*g(?b>yXeebKUzMAmx!w;Wh z&s#ock2`OVIvMA{T0Uo={YRIW0r^KI_D}x&PhWjc1v0JHlPZ-)JBq4`FnI;&uH-Xv z{2}TqXtTh@zPgmgfGHFd2Dc~+<>-ZVvlPXdiZb%h11TwiwiESudenn>gRQg;u6rhM zOLL=N)fko5+06T>+}3Q#>68?IDC+7IpP1-jy!u+LSofnIz2{2x?%Ydz9Ck8nn4Y41 zL}79#ix(``qhQ_wR%?u})wq!dXwsp3X=txus%Y5Etm^x9;EBiUkmF9qQuuVic{i#} z`_{C;?xawLTMIw!Q^$VoN!qu9rny|p7nJL& zqb6w7!6#_JhfnJI7r#-zfqj9nylNNTqz~tp>8^(_mDa7+dAB~Qg3f&zf!hg~%dHE} z7^Z_y{z&^Cd8E=y*XgZqm+O*CPuJp~U}|AttV-W1z8gu@d+@>&QhaJl;b(1aR6myD z8F%WYN{n$sVy?nfMT)B{hWg~w>dh6{qb#Mg?XFcDOBJ6nkSNUT^EzNWx)Z~0D}W5J zfvC;emb^cAxd!#=rS$>i2C3o&7+BX`f4v@i{81DjMynxFL-yEH8w)FG&=}B!G41uv zdmpHEw_>${Wo85kMqVfr_%i_MA;@5^#1` zScXhNMqHE7d+Uh6T6wc|$34&Jo@ZymmhP2gu2=?=QY2*DKF!@Q`jg@#yJ{=>3bvtTmROsmSWgII} zv!9=8q>W5^R+6S)aDirg`?VG=TB22}S84v@`RdiCz0Tc#inj9EE(3HJ660q0 zjg}rgdaV5QPmLZu`umo3J3sH%t=no_&%m*!Uw?1HgbCn?JC>HuwLG?LgU;B_ftm4X z`RqUX7&9RMsKoxspWm{*&`^%weEIB)8DC#_{bhUlfWR8)5i%UIwbk&;mMJn31kxFzwbIfy8wE?)OEfvA>IT}249~GA39g<@RhZ>ykR}}fx zyH_&F`39YE+R=LcsSkmJNRko}*iyK*R9z0}40|bF_uO``zW#o#lczcQLZT#+)!wFb zoa;pTW(`mg?5RK9G7AzwgAUsNY~F_gx-Fb4)vo>hKdU z*HzbE;}o>L^49y>XWEf^@wrzZ8qg*L&)S3GYa)^vJz<m(cm8i*2oBcF87g$3^D@wFE=eAsW>Qu-K$0-N;c3g^eR!(NP zRkAL;<5O~XDMXL~?YI94Tq|k1@!YG)ozdHiW3Pk!kQkq*>#w_?Ay{iPV0d3(SO^9n zOav9cig|23q9?9ChgmCaw6f@14a{jr&M8IJak*;MJsTLV4TOhG5?Kjq*S9BhaF6Z0s&ZWwFhiwYrN#Es zU3#fY*S_R(ex_{%iG2o271fk8Z^We$%t1 zs~We6F+vjFI=|+UlX>^e=k(q?FFJKG=FO9l()copM1k09a?*6d)PqRx1Fn%n2qU}H z>_mzmBg`!47+}enA#FxMyV&k=N9<27$=F`WOl@Qk7IfZ3AW4J55~z}IK$$o4yIu@O z1lFGQj4j++rccV=rC-?x>>p$R;7lt5@j+d-5xUk1I3qKaqQK9gRnK&4ICaj#nRlU6QTh(V1o9|raxw}^*p#Ld13u-0A*IRQ$YyhDgKE_D=xZrZX% z?OL}1Hl-r~Y^->oyz}|q`_Dh1RjXF1V^#p7M{GuHn5}>(r~BpeVF~ zK5EJO{<}@UixjyUyAMLjk;fd0VLVISIt^7(SwwqHz5pX1Qs)k7&S>PpWA=gYP@=b> zjoYjq8yy^5b}fOJ0ok=&{_WRxZX+Fg$_c7~XaC?;H>qIQ5CsaCDKSV+0#DToy)}wr zFx6*y$P^zeFO-g(dXdIzQz0bBiCDaNzispTL5EF*ep~~DhJqp5h{k0)1&+CRp8mE} zpR=tZ=&?5Qq=6zlKi;WPN>fpmaVU~_#-jFSj)pO>8tKiH1{~w3WWIquAORGRDc*Eu zpl1L_7@aEAM5_wg(C6j(wD;b7v)u;u@0kXUo`Q*C|6t%msg}>qiPx$*?`d?ePAFem zYxj!WxWQQ(cX% zc3RE^$T=9s)4G6 zjR|=gFNX&GtCArpkAmfcUr=CWXyJ;%7?Rty~wTFap zerrYhj@PFycTA89Gdx$OOTdcNT%;uWbYgkVfj*2-+_6v*QQQFEdN^H2taDOUVki2b z>F@}OfL&xFCWvCRN9x?`qcx9Y5?wQ&d<)9)G@rx9dwN$qN8>M_$RqFhlP(1)EcV}- zygtXip`637Mo5ok!O!Q)ebPB{gq$K)p_i{C3b{4dNc#i?(w4xXn3rhQ&mI1k+Ie+eFSa5p6R zA-YO+--_zK8)Ej3Vh0o0Ez22}GYIZ++=9>z7Q;pVnf$Bm^^`OxQ4~$@r!@j27b?$@S(bc~pizdp;A)GFtaHQ?@MlQFl)nr9{>)9dqG+vVYmG zBlD)`_k_ykX*p);q@K3Us2|5N3`jLD-!f3X=*})_PRu8NCwDeN&Z)rK;s(sn?fu%I zo~CjhCSli2 zuoox%&`{^U$7&6|J!UqG^W?f-PH{fvYvNh=in?9BQ)bq`XwD0`(SWl=S53$+F1PQ8 zK{{6P-e0EuQRh(R+^u`caq*)v5^rTiVf>2o2AA!bnNT)R$LNa+t%^pI1`p6X^{3R3 z%_}GAyhVIY;oMZ=@PL|F9i<}HqsN>%X4RVBzSYo3{)}m41uXZBfRb>#7-GTqKj?y+ zvy6DU8ZxbXV}uT0Sn^(s2h4?*IJl+Obu;t>&Pu(vbTGT_{+7l{+;lxp1!yiW?kZwW zXAK7>|0exo*d(2~U^Z61SV|;a-4kU06BT%nyYP55ad+4yU@wIjrXDFOcPI6wO+)Ys z+--d$iMhGXR9g}&<8R$pmhX&dYJ_}qlf&hG9d_mRCp7&>Mzu%~7kgMMmUE6YVLAtR8^yBP!mj}1|V(o{eGDCdnG83KWl^bd#% z-dkzekx`a}N^`*RCA=I0n6cC{}!{=#cSi-9^J6c^j#N2)d#>8!ot4gS%Dx5;og!s zyfwD4&W41}OA$*F+Hzwj{8qKk56d@p;C5ZA0_OY)tIARcjmZ4dO`SS|H8bvGCKYMdc+$y{=GAS6uz2fMW1W<1zJqA zja}~d7N{q}>R6NgM4mJ?lUR2t{oi$PWFF|ggN&%XT#wdx2JUrZakDGgEppzg&;FY4 zbm}^88=*gdU@S3cL8C}QZco`H9C|Lhl2kFdZj;6<)fJ(F=Sob=ePRTy{^8XEzp$Od zztQKEvL-zTO2XEhHQBpzpwZm)3PwXeF+*SB=!oB???uGN&pWlC%E{spO@ykLdZX?` z@5hU9*Wa5XM{c)v)K~Ola?RH-?akK*F07SBrs&Mpwxzb_Rr#K0qetsPS^)1DvM#H| z#o385cj%Ex6z!6z5&%WP8?oFDv>p_W{ z%$a|ybz~a(9Zs#@VXuzEr`qXWyj^0jX@e&7lcopIJzCZh{_qGaHiF)zQ^y@|Z7Ru; zawwlV+xEh|7t;T9GU$0OYBxfuR5HyB=S9TjR`Wo}qk zfnlkY@{)!%gr{$sqFjOND9S0rb&IR(DU>wQzwKaNEq=z|!k`Z7ou>1e=g7xeior! zdnvH*zM~=2suy}XVkGwXlgLm7E<$UWd6?@}I;4v6P1)w%D1fOj@FIlCsX`nfE>U@g zKPrv~g8tT9M8{Ek`#+$|68RMXtr->`25GFXcsNCS-Kky=-(jGSQg!%PhQGe3K(}lH z3^iXh^G|pR%KLmuRpY_eF=!nx9L)OshNOPH$SeDvrMq`VZC?fUJ!?0rEJP99PX0y~ z)z*1GWR9r+W@SSE>5%O@A#k}AwkPK{BS4lnch z=cN~>v3Wjw#0P(_kxZpkW&di%68gZ_D)A>Vg(s%2&fpU*xY0E??K7+M)~bh-@TGn% z4XU6la<8T1wv{k8x6X6c-Gym3JK}v5(J2D$#m>JYFI66Cobpd57JS|2DInMn0uQz^ zFs`Gh?W0_xSgNoyzR(-07 ztI^Qw={`t|DK}y!%8|gZ5+0l{-IDsq&mQCoQ_-w4un%Kmpk6#?X|CH3iLRFwJtG~z zqWJ!t_rE0FkdmuxnMAB~TUojeFrm&p3*H-f;i;*q^#Up@mGV;Z7XC7jIKUy83oSf^ z2oYnE)}asPNes+>Bort3s7zDvz8Y|wXy11x`pmXZc$4?X?cbB0b(PMTBg=R#?DgQC zVHHlO@5LwB_1AkYp}W#az_T^#8IPn?o?8pjL0&^DH`RInL)p65E?0SW)9$KJ`Je;* zukYx6KuR~lTJ(TUHNww5H6i8sUtv+?W!Ej?;S2HIm&g&6K>6ps!2EWfHTv1y9@*IS>*L?@T|Neb@g>xqx@0inn!) zw1ApZSmR*@wdI3O<(OqAQe5uG?=7hH3$=ZIkG!GZn=R@-kW8t&JrF$701AFi=&ApX zIn>GTQ+Sq5@^-h|Rj0`%u1 zIR}v+zqX0XtAda0O-0>8cT@Az8BfAF}vF zReNY=4sK`f;%@FHsGt)VsojmXP-*a>!XV-WjFYREvc4Qz#7F^T_Ee)ptxBglmLwT2 zP{*nqEN6Y!`wzRSamrd{-iaLy7uc^i%@kJKueT6?MDS!qlyPLbUZ-YW*l}f9ve~ly z4Fe$J&fTrL&1@pgjj@<63Y~I%2^Mi&)LBMS4dJ>WDwZ>x@YF&e=7{XG5RpG0h%Te9(lkZR__J z=>4EZG0H7}kW&mxA*>fzpOr(~`1&IGCJy1*TJi&GFC10(K3U^6h*7WMzv1AwtUOQyVNVIiQ+L zU1P>;hk6xXLW1CRac6tC8&TxYjl9H`VkHZ*=}$b~*BLtf>)}hs#BVn=OR1ldMdUxc zT3{|^E`OWSi}@MQDz+%%xPMoRY&UL`CpKUf=cB6XHr}HNm_Gy@}yo+?rzT`2KsOJq_A*@}!r)zVu@V`lh$h_z|J5 z1pSI_jm#teJ+k;VnSkRtLV=FAkBN}kFrYqTu+i+-#Uu|*UK8K7ZNVw>2mhqm8CJ>_J zf!9P>-FEw4yC1=DA$qOW8YyXMniENq3myQuq*GNB6N)ua0?aAi?HDPYNzaGf^!UE* zI02S?;eeNfc%es2SuZcIMf&ob%lQ(SiCP48md5y#6ya#VQZAVfKE$0mbwF8-M}x>@Jln<(IZiVi(iT zEjL@l69Bxg?GF+wrclx%N-8)Hg(EQwAeIu8T^`Kn$6)UAD3#4VC)uJ4&I{oG1 zvN9SssL?Q_qXydDv~H>h5a#nq0laFlgdm^;6OxnFyk{hE*Yq?rQrCNZ?lhQ(P4~fE z+s5_v-Dh3di**L8X1^22uTGmYGc$3_ecS9-7ayTPGo5>@4*kS7!^7(kFkU?LsC^?? z;HaV)h|g*M$HN_Xax*y&wUy@0*_G0>$hWZSzJhdn+vm5RpC0ut@mmx*$)o(|`v9i~ z()XqVy$>@)L*So(ar}-MCGk07ACC#P8|*pSO4{nlw(mOR_wk21Oaqph>>xc{C{NdO zN_SimT_B*3U*}cVt1NlD?I6h%|8b2}-{Vm=V&Qb0WYE>#1fg}5%l_0;bzcAL3j|@M z?HuY`9ev`oP^GbU+Gy5zP`uj-$hv5d;%vIL92Y|exYhxHE)!hsOWSHn0JkW>i$hwi zUVGc<@81(mUA>eap$agsZeZ z_9|I`^XbAt$&lJU=(5bbDKYHUy4-T@o?l&cdcED+>kPW<8qYzCi)Bm2_%J>_TTzVm z?NZURy0=3Vbb1!>#-mBp&wqYvfAfI;{=tpr6Ipfey_qxFTsDg&?zYVNR(xP{JW#zM zc(koi0P4QbB#{5S)CfJV{)9jY9dm43to{6e7nobie;DH#pF1WOPkT`C*o;)hZH{|v zrql2-AaQ=}yS)L|jYFPGcdDwY)~Ahdi(_MB4DBGH{Q6N6yTh5{5m}!Ww1H>Hong-v ze>BT!>uEM%W%d$3n)kHTuGy^n*4x9t1pb=`;Hq&uPG%#3{yirdbN2mQ{)=lWfJe+I zKJB=1%?xZ)Ut5cM+wfG;@#r+5B{%=YHEY$xt!$~>POh)vPj(H&$ zBc$gRx%RaHuXg)2%~cnhVxWpjqLo?&P<- z8shcIvdhpw5DYF58db%kn8WK7M(;!D|BaJp5*oGB-x4u|5{Vz!JS7B~;-1?+Z3hco zN7Cl;*6uzV3TKI~EH5qDq7Vj~)y~%{bi2*3bs9kG`$>JC&;P>;cLL>&l#jTwWI{rH zGhv?$JU2t{{GfokZKwF%3+%E#No?LsfhKU$(0=larO3P4ITVe1*KWWL*XN>lm1ei( z!_9FMAfP^ad=n-sCztspTg_Sx3G8>b79uAr>ud+%*1TKPbLj0dtEmH@qp!$ca@(!g z_Fj%LIy8U$b?f&gcUm%{B}|6wrW>A_Q5t)!@BIu#M$n})h2Mt)gWzJH1Go{~aWyHx z+B~w<1o@9Zyx)aHVCyv$*7jYZ*E;juo$Z%ed|FZG~v=u+iper-n#f`{&!oHVi$eE$Y9AO4lnCxH+f3-ybX zX4qVw$}c$_@vwp%5}h#Ix68*xBt0PSYWO=i6w zf{@b}2lk(8W%3V}&=4~$J$Uic9s~hGdjSWUyIe4M;p+9Q=Gwr|!$Thz+S|Xa6Hk2g zs{O&fUBD!-efOg+B{OHg&&^Tm-{CQD!8~)dSt%l?U&q|Kt!DgCjs4OkzMh5TAW3vo zlx`+R`~GWksoAi{xQE{GT3b)sX}ci!q0vnIc=A{`@4RPXPEp`AGVLY}-O9^8p1EFc z`2Or^z5l2aADI2oa@cmgr*rU6;8JH}=4o0v-+qn@NgKG0Z(ra%1YaY$Q^JHc&vUEU z{6z1K+fSAn!7C`Pkdw)Lc2nE@&WFA1dSYno8i+Zh$$fqA>`4$R*xzp^6}WwEgpK3d z%Sexsi@LIv^cEHUaVtWWFkLE_-ulC6+F{+_z`&sCx%DZqws{|3tJQZHxayLPYVY+u z&C0(`sO{;M+Gyry7%Cxu-@l(%Bdg_hd!31hwmJ6W?Ro{>(97zMLeFCVM@+v&?B`TG z@_{0JPMTYT=yx73F|qA$$qHaDO0PHKv-B!8;DclCZ|?>`pH-Z>51Woa`jbS)@if&m z+X|uVu=R>m*EFU5V!Hp43^TIB?%AQY<+Kp8ZA38XSXrkyV4yxB<-+FOcAOKa!N*Wm8I~gTyGDUDPc8YFlhMj&{99md z|LZ*QJCQPg_vL;&|22Qd!dCA!s&pt}wJl!Y?0)~WkviBWDAS#WrDaF>Gm|#kl90{# zB*s=8SHNrku9mGG6l;#a{e*g0oMeqQP^?=M{{Ww^lN%<=8xPeQ9^SS?gQXVX_wk55 zW{MLrdgSrywKz!Fn8JV`Dow?P5FsOK*k$z3QIH+$H;8tQ@)oY zB9uE`v8nG}KIjwROn1NiQ+q${%s<@1|5nU&ZUiHrwG$)+OagzkU7l0Dfwc#JcB5&e z%tn90fRga@m)|Hs)WNZc<~KyQ7wAIw8}Fh8nF?(m-kCb$;NtG%m)>RB)ODJ@QRbUs zQtc&LVPt(p;Xhs&hmrBbw`a6Lxs=cpQbykvscM+U5puDxKkZU_F}>gTFnreQ4g0BY z@${gT^M7h-5N2d=+#BHcSLa7WLJ8@A%_U1+|3@g$f4$bff&43D(GmjmZO{tZpv@$~ zZ*ZY|U+Hy;=hZ>@S!(UvK;{&DsO|3N+n??RT@W8Wtj6d2_Cyiay&8IVwg6t3O9beP z40r?PT^g!Q9{}~xIvRYn9C@nuzdHIqWqX{GqAlpZcAEX$ z$ylqc|K+PQb;~iFOot!$&k(e}1@`7-7_+N5WHUDg`75vmF=#i;3ZVuLth1+9{V{7mZ}JF9Qb z_BpZlC)BAh6IOS%#Qb9GdUkc0by_48ZcwX`VCSn8!dHH-Al+C&B`$_Oaa}F+AANfI z;M4VerL1kOr^hC$T^CRTDv#&tVi)azjQLaLeSk-+o7)>VD;XgJuNPM{v)0tr(|skk zMCoRN52CpNLkqGBW7dlD(nuvV<_wg4I&LafdKX>N&OHQmy-y}yfBVunaZshc-f&v5 zPG80nav8^CWZg^XjspvCb{ddqXf0IQWq&Iz-7>dG-ipLnOQ}gmvp(zfMYqqTH^eU(d z3bNK{v?C+SS<-#q;@iZJPhQy|q^-hvp1t;MxOy+km=XSuyNTYLr&#mVR|E=xgNxUR z+hUtV_r~*)nBR4!P@NUjKE}S8+vB6GfS|<9M67J2^th&`wPn9A;Nfq!vj<*mlWSo~ z?{CVeNT*R@%Lc(ZPwI}pV~&MAgLx@!XJ5D$yKb&7j~9+N@^|98<|Z(gw)X4&_Rp%i z?^v_K-$yy*)?b!M;-uNB5WUE$ZBv+?ch(C!MLHL{Ds-+$WMV_NapAyL^S}JC(YWdU zDi?J)r+-Lv-i7Bm8sY(K>Mx22#TPb#qoAsp_BNJRMbf$_6;h^W8Dj_Onc<48ZQkLg zUGM$DbnNuiDWR@yfv33V#py-9Bkrbt;-bH?82)0ia^s2JRbQtB{kx7rc4bdF^6p*- z|B35(j2X{i?<+yogk{aIFOHNW*s8BXoNkL37IcM%U@Qt1?y$eMkw!I-H>ag6y(1># z+t|1uCZ6G0J4rT{0%3!`bR>S_h?z-eA&0i|wkp{GuS<94oNj~72!y#^4b`tnMR^qj z)>YWrcTGYDL@O5$hW;Z!`E2)uD#8$?OG1*rF!9}y{a-Y~7dC(NaI$5Q~$bQ8)sW0D*e2I$s0{aN|K<|Fhp~DEH07hZtAY zv_Tgsbe;&U=yy?-%*WB(S&17ix68+#gGjdZCQxT5OZPtlV%H^qB(Lp1Ids^fR@~k5 zzbCX4g)u@t?UX4E4BAVwKbwdvd)n~WYJpfrtLh!p3p!<-{?1?67OoBe)C~yLy>)~2 zC+Jo`6Q9P-JuCH8?2|kr%S{{C^##KQB_}+nFYr>6qqfhv zPYQ|8B?ecs(jDMm1&h$RYN>_K&gj3Y9&Qb*d6N8)Bg(y5GEIaWTk8@E`xhlr1Y z>KffLa57iwtBxs`$Y}S3+s5$6)ee1HVg~O@aW!|3YNHCi7vmw=WH&JIZQzdAcNfHFd0$b;`9qP!-^t>;W>VJ^xjVX6GBv}1JL2Q9)V%2mcevaI zE=IBRHP6&VhkKc|?szxo1v*bLg${hs2f*J^RGqB!6;&}j<0ilGtj6_5h-!B~bA8e> ztQCPlB5%;G8>SkuQJRulh;O#A%nwn7|5>S_%Au_2ma96K%w;+$FQ{5y^xjq6y-GGJ z`k(q59dmmcD@w(~zl0}$6P$Rt-G!S0pquwasn&d-o?c8eJrfK6*(?ninTJWwdRF7t zkzAEZniL~{#X9R_f(A2VjrsX%!}8k`yg-ce(4gEbN}v~;^62Sf)qVo}NJXtqs|0Zu z_9tpsYzkM;!wDX2)KUfjqmo6w4>i&kMG0y**?-i>%)2T233E$!c`^ zL>6$!JK2K6BzC`*+CBOEpb>4nr6!I@qOmFeg-e}*oLz))-9wlXX9*TIr{LH8GVA;*&<3iyuu}!@uxM|#@qP_38row z7jeSxk&l9YLf>;{*x}}Vhe5y8!b@LHp9CpBNMfys7 z-4@5huG`aUpur=<%8rx@oQAGyFvYDS3{P=N@K3eDjqfd>27uehAP*yLdG2RspuCVt ziqOL)a|$|1AN_|S_(aBkUP&oOinCjAaw!LLvjTF$3n|;I>IQU0<@sJ;x25i+=(9bD z5Uvwy!q|X3pX7DCBAaFfD(VX1>sytN7Z)m;ng|^Dw79Z0>4`2I95g%|W1~hgxOm{O zX>gO5<*`N7H4F@E&eQ5Ot!4Q;GbT@jkpxy?ze-&Hc)`JO(HA#CPV-Jl5iUsW=N~wt08l7EE5b)IGR%z8~vRktxz z`ZU4c9@VW}+Tr2GC?`wsJK-(SFvaQ(O2w-02lpW@&R0}@i=J)Lt?X)&6>`9AP*$dY zFu(z7il0#*;3<+u^$}5LWaW{OhFL+%xNJei8rj^J?a&^dWHx0yapcB`jU=`M)Sv_k z1z!iBT#}ys&j$WOc66o`Fced>vtJ*^qEb@wq`z-&cia>FOU-^t&$p~J(51Co>eE>N zu71jAodfiK(QrHb3pD6I(DkN7TCMc$r5W!(sg@6#oL-scZK%=0b|2GwuwW9W4bTC3>*94kpE70?BbPEg4umu_QoVZM>6-x-m_&=%KP$5NOuApxdxTOFX}e zw4naEaxf61YoqI!>pWb1!KfxH&>J&o`>z7k>_rjGgv1V2T1CMrF5a@NfzQLKzL))k zZioJA8mneOmyYnn<0$()28tdT(ZE3ISaMbsALnOFN01w|fdRb@C%*7S-QFR%&3^f4 zhns2En&Mm;tWO(Y+LIMX+its5W`!WHq3Hg(--4~waH0;jR=-=rhPz&cO#A3WkBIMO zW>D%FLXF&7)}t)^%w`Cld=$r_4vj0+ZuCxssz)o*M|1zY*tTtdnok=1Jy;>$Go;&S z*-Fuh8s$*4@DD(9cmT~54xDW@xtU^MMLpP0jdt7K#XX!{Jy%sRXibW&<5+235S!|+ z=!21}bOYwqbsXtKeY>-K;Z%%$)p@{P(YI?hhHcwgYEGXrVOuS4wY*=3utS3}{5XC3 z?C&o*_b1od?0RR}TVAM&*jRCa&7jD~BJqB>Q{;IwWryB>XCu7Ievu+oIp^Q`(l2-! zrvzVXI5<@!E=#N_(w3TR-tK$rcAHjfCM<31`(Pd`s;c1E&NQbm_8F(NY9>Q&7f80z zs6}(?^LjbwD-D9svU}?5Ixf8h_bV8z)2*jows&LY=0KeLAMkgRo+dz7`E|+-n3QUq zddau=l`4ah2f6KrgIH+Bt`VB|`+Id?SOuA>74(caI(1JAN2PM>xIO!cyINJsnc`Km zID#~MqmuON7+BQE*yVIG4=*KqADuSgi;_MlWC<$h)bblMWwlPNQ+{zhc<1-Jy+5F8 z?>0I`{-{$TR!&llpC53HS04x9KZsh*e>Zkv=~&OQ;;|y`*X|fJ)^5MQw9JalzY-T= z5*~C6>h4yZ(=}$(JKRaGSM}29yj^q1@P;XFu}Li;oh8HCxZz%~RcT_ax(S`Qgpuj& ztsI+Rn&t}Vl9O4cI_P#!MaN8oreh%C)@}+6I1OmO)7?oT*j18GW}U8ymD8dp=hDfA zoY!;rh8--4`7jdBihjHK+(2C<7!!`avG)maBTTaAFp%5Mq|%bo zaS%$)$cwk?wuZJ|(N5gj%@c^!@>H#KOld-`!7K zlbZd-MGXLUeu9j0g_|9y&0c|@w3#WheASB>g#1wvqGozp$#DWENw+I5bdXks zW1flk`%2R*wn^=I@?49M3wz|7qo>rBul`$?2>mnnVpm*{?RXhMn9;yWrGt&d_-I2) ztxe7LGr-OIrP7ZeDC0kArO*pb?{8^B`4_bmH`NPOrUDDi@ufqf zy4_|W6os-kbvaL&kT!tajWkKZMvFJC|jr0yau zPCcZP0vnzwDDxSTFLLSiXJb)>o0PsbTFJ2gxka&mL)}jacE?Kb9cDEwFvf+V(?}od zfj&LB^*uF?>l}iTaMkw`S7#+SagS7n-?rs9dOYK6(=|IS*f)6VYLHkws7Yv-ZtZG| zitf38RRs_srbENf@0M3~ss5-IhU=SnK#Y3f@cFXZoKiQ`ahhdzAW`khW`PX9!z<$# z54p}Xzkc<>k!w|ggsrj$Qq6e~+YDRVN)`Dt|6vbjA5~_retqv{4Yx!6{9Jv10Ts$L zA#4B1&eS3ku-s)zKnnS@uZ%r~7WJ-~tYQ>`re19zqYR&wRaU=At2gRFwN$>J_A;N2 z_eQ1O4Iai#G;2Uzeh}$e!^2aa__u(JzNdQuuR)dvOkeN2==$pg1o5R#tFG7Z_<4IH z2eWVPGb=a8>K4LE8*=ZepI z56_qW=p;&Z4<~;$1bq}C%g3$MvpfPj3zxTXBg9fY>Ae~4I$h_SZV$UK(vn$zm#p=k zo`Z=80X_C!-1b#hHCV5P599elSqqnE0fHvKbNwFTp%3Y8N%nv1ES`DZdp3|fn@t#! z?y-P61N@AYgkG|>ykEQfy#SR`Kfpb4z4z!)rOUR}$?_RZ5FjjG0{|BinF!mXp7c8w zI8+Kh>N5W`hx|c4Z>!*0>M*Cde!itRUK2I)kWRZvfS{hiP%qc_M<-seeDCdm0Fp*8 zTryHU??iQ2Si|K?iv|bc*u?n03bM!x<+5cCTg$(K?19?YE7FP&VL^#z>YIYv;$jFV zg=O>NwR&Bm$a?`LB`9*!pBXSZ$f?WHJ@2k}BfbL~gFgB^6u6UAui0aM3B2JlN6Y%BIV$EX)(V2Q{0>Xck%9E$k zT_et{t5v2}rT~&Ti=_gpVG9{4p^`2lA4KtI7D%!7Je7T((2-peQ@;8KV>vtzB}%*zR?gYkuOIoe!ayDBuHV-Dh;J1T|0Hcfr^M}UG+ zKi7Xh5DrtdfHPsKp=hbyd6p-at0ap+%J5IUaP#z>Iw4Y|wSUCx@C^Ya;eynqI~6|l z7mr89xMbX47!c{``G)Fg^ZYRhI;7ShL?xsaLUnS5i*@=EOyYm}+w68+>rqKIRleN(+46S*`zK~27p?_HK615UNmNQulX7-j`n#LZ z-{s#9x0U)d6_3xn@AKxqxK9nbuE}UwuHI@KakwXZW-$;EwW}rZv}&vCJArqzH>@3- zB{&MsQrByA^H4*5J>8DQPk3#sc!7qH1|~TVh9QO$ES!W@iu;q(i(imt^l0dg{E+pA z)UsZ$5R$6VNpZ{~13(oubq%wWgx7ny7Vk}eF`}LBe6`Zc)N?bymoQmYwEO*N=Ax{B zgElx^$w!9p;RCbMQn@bX;RTg~0X8MKn8BKEi-Df77mj1}&;CF{&%x@)F;u(~riN4f zBdIKQf>>)NgUWX(EIfKpD`Y(*^5W+-tJOVbXUO($A$%cPl`SXS_vPhIDg_(tf(;hF zA4`({cIyYTBcwu=Wzw}Q{Ri@KjA*8kXzwH^Tl~;8#el*~dR9>m+DsnK30Yy{8k)@0 ziL`m89bpmH6kKCd*A=sB#js?J($Dc-C-anCxGPtP;R*|#`||1+gHz4*3t8;jjDFWc zA1o~}Dt=|B!V+_%eWZ`dfhKy_cckbOyPS<@ab6K;NFZ0b{0=-io*ShFmW1c~>f-`^ zNFRbtG;mZbFtw0dZo^o-%tJ}K4@^?A{R`&G42!O_%*GC<)gYw)9bqxVwX~#sCl25K~cXT(h zHS>V>oAgw&rq!wmw)~yJQc_8w=(!W}`wF!y3=(>M5m<8^S1pe#!7m@c3f|P9HgFmq zVnBG26)#(Oj~n?cn1jiWV9TJPhO_a_u~+l8M|@!*6oH6KB0HMxe!g6ucZbdntY5`) z3X|o2P+0Zu12Mo@$&Q-mX1JS_E{~sr@psQ=nXnTun@sY{L5Zp2yjOY7PmPVm?*i+Z zzlc@sfn{UkHVgF#UerpVi?yL}2x5-wPjLL#Y?n;n*Mg#2Ihl$P8!VJI53QPc^6(fC zkBdL%$4cEhyc)(yA%dUZ^`uC>JMDXR&4~(8hSI4opnXdJaTYa@G2_v}9fF{5dr56@ zcZsQFaQ!{?9Av@#j5y7hJI2bk&5JZ@*)56|#E*`m_%&D~M#?Ln;6u#UWHWa!d)c+< zpS2Xr`sdbUnJ5tI$#8Nc`p}8atcudW!*3erJH0agBZEXgZAvtMzUbhH5eXV95tx7f z8jgKLpEasu%gE%4Elt!)1MOdT@}+&JBrIzuO5{3~#6edvUqz*MNE9lHQ@}Eqd#0fR z*NRe7wOwoXvHQR{0O+~*9`m1inJL>=WkXwVnkU<}d5of>(2zr=1Ov0a0$TW(-R(jY z<91=A>K(Ho1J|17hUiy5KB9UNyUx$7x}_?VBZqE9frYvJHfKK-sur86awEHx-BmpJ z0sls~6ck&ad8+wIaqsl?G&gkM{+Az0Q^?s=MiT;rzqbvDkf~KQ=%GkA)5$UcRwIyN*eM`<;cUj3~){oHfdGf zhki%7>v}vyT#CaYV=^)-a3g+m#2(3}R?5q_Lz8z&WFH3ZHPC4HN3M6jBB}G7_t!Qp~_AmnmW3ozMeR zu?Va}JM|WM7ib56i4&Tqb$N3V*qVrq@pwmK&7y4x=v~ zO=K4+LtHnl%4c62Ls z>gp(*$A9LgKu~rn1JInD&SR`O-VAkBb;;24N|M)&E1qt(80~@Z@`!FocqJIMm>11( z4Un7)YvY7(VIwd{FB4N7ToF95V*kaHnnTq}+Z>R)2lyzO;Gd|o;|!df(S%%+?64Rq z9&FM$t-^mG%Ifq)HUrtQ<in}r3u5B5w4>dMOOEOdC+>|-Ob7(d??*7izjp%zYP zpWk3w1tNz=>Th^3yf5BX_z?H?2OPWjMP$qP0PmN=hz1QL1iG?fj4v zY=+K>K)BI|zD6zIE92r|2wfGon zh1a~V2`78^giDWH(b%J+r1DN%{Dx-W_(8k^ zk|W(5vLo@!hU=VsS!;29@!$VnucleMHX-Tc0HGuwjaMWT+++;ije!}O{OI_3W<+2T zW#;EfcJ8rb-YeriyuTJgp#rKhpZ=6X-?HK{)$XBF7hdRTb;Cou?nU3VQC~2RI_Xh2 z6Np+B^mL}iFe3U1hk_l8m3=h*Y>Q_){mYw?pr#V`F=|>T3f#0vq<|M9Sx}v$`A`+R z$O}KZ5=Nzb{h5qkM5#cKaEZk$k|x?$d6B;*s^C$(zIKJbD=CECIM9W;p0R-6}0fTo6TdqfxFm*cCr12aDm&@#e=r zo8>>0p|dWFO_okFTwqL<%_4a<7wCGNR22hdQ)HVeFE9Wxcg+0v|u*pJ3rd|Dlh@2_(^U#mxLJD$(ho}~CHzAS!?U*@2}!A06ZfTlK`YZ>XV$SYQV`oic2!FOpX=h3NtgX%)Vi|Vf z?U)PSlP?UDvwESd*p<+5Z6c;s5=3v79B;B4XQ{el-1F?A)_Kw8DP z(wZ>PeJ`Q3WOu<3jS4+6O_X&-**=cznzhl?98eN_j%`qDL%a(hbu2B)$K_Y1aRo8lu|vaViRcRX7Y^)S_<; z5w&(=GKowWa3_>EgD8GW*@mgx@?aLmp`g0nOw@8Fu`?8GaYfYPa#{ zBl7YgD)z~}^@vi(8K1bvKRfBSLPri=-1bkh#rFUjl~Vo8x z8n(-&P!-j;bdzO(rZ?ur(9=*>#|Yl3*FQqpQOohzvEDEaLSD;v60X=Ch1dO=0)z(P z>5)wzVGqB_j>jQl(Ntdz*z58I#FmiSgz~=_Il%x)On@t@N{&JTNQHbPFGe9amtq#f`j3%WCoIu z>DTL^X)1@C-Dfl7q`u!hPT>5PO5D`z31P9$hXld^+}5*s)^$?GNz%fn_q}e{PWufc zgYQs4B0DX2qL8cqN7X%cIo7oe+b*liw#}4n+qP}nw!3WGwr$%syU_jAd40Iw@&1Bj zBw5LvGway)9n=+7+tnztXoZj#T#T@$3Z(&u%2#eDY)no-1`?P;bDDvD@gWZ@Ct68Z z2%vbCe=<`-OKz;N7HAlb&jB?>D5DJasomw7b_+btf4Jk&$L17h~so5mE<)$WB5;BH;_I?7cm%V z?oa(*Yk7H0h%iVrP)D8i^WD~h_# z6tmD;xD4d)wvF%PtO9V_jmWP+s3`c3)-5C7g8DRoAdQn?jyQ;Oh+TgXC5Jl#-w3jp zcJh1>p+X{@q)b!;3pN@pP0WtVdeT%s?P>`%0F}b~d=z?Tb9xqj?2=hJ~TFhJWXq3>@yJWb#;UKH0Cfh4{%DR42mQW1dv{ zn#G$jyb_u`FG<%cwu=a6xmD>qKaf#82)*cXZL!k7EWYiv-d~We5;Ch-?t2wCs|y(M z9RpFv#DW&p7*_Xs&2Srfm4YO3>Obs&2%@%%{Gpq(D%D585m1mdsnABfB~4i9D-o*P zq;47e9j7X!47b`s44+m@0eU=UU3=KDs};TMYlK|D2(s>P#?7{I@nz8MuwIhM!WU?m zQBzMW{x2~zx~@NL=e2wMIgxLnU3-E;Q%8SI-oZC^yaee_8?fDK8 zcpycx#_Hmyz=1G3+(6&4YjNQ*y33_92DE2rOp-c34JP>?H<#6X`bMBZHhF7B>*MqiXR%>K+ob22UNRSg37s~1@%L$27qO$8Zufr?hlE>gz1E~YoB zgvDeN&b0?CEYqVkriMOQbpO6nbyW_W-;h`--1Yo#aqzD(DzF~PTr#Fu&bf( zxlq9KeL(TSsADIY%h+*7KfK>msZl`5{Cg2mjsYTKq8&jfx-f^At{ z6l=`G;nyPW`W4p}B{woLKAgmPT!>n$h~ltyUDr3Ssm@yx&CsREu+=1iKx@;VF{F5UFJ6gX*kd*U@{K)-ES&l&i9Cc4=aQML4nY* z?RfLjc^ota5E8M)-135T=SjdwfrX`UI>UZ8C`XC>a&m5ZIWWJwxP`?3IU%HyYulel zepRL3forwbks{5hkmK}J=weU&1x=MY+cSgt309c+GxWh}``+aIq@vxfn<1I;arliD zcTK1D+z?BO5dvB$f$@hZ{N8|F;s1Wq|JbU@;r9I#uF$yk zd`jRc)q-muC@(K375d=1e}%B?$5Q}jPdOIf*ya<;> zW&AxXjR$@+1o|b0>ltCz{_Ggp?3CAqTK9x&yVVHolQ-<(9NPOeCA@ihE1{uZB8`9> z03hD1w?os_$Dyp0UY*P1t)pa_O)*Ft#pRS?J#mJ9`UF@PYG`6@aM^Bxb!honqToUGmoNwXBZj)Uaf{l&-kwMfTwj`HR^5d=s;A;(~BGxK+`B~=^!;l1S zS}8_&$MB20QZh+Pq^s91Ki16UhcE)yQp4eUNBHIb%WZ@SOBNAbUC^T2c<-PN@$WWXWs;M0Bbw-#3p)u)Us+LI+Tsz!h5H0mA5{~#bfgf%?RGh!Qrn^sd4Von zo|LvK%dqS68~>vnb}S1b={dRaC&>g+r+DnSv*K=bC|Gu$*0rmQ#oPBqS@r6|Xh(cW zQ^#1s-j-m zJzwTKD!N>@MR_Ii zSAW@}4B_9e`>!*8AX!xlUtG2@6gkP|b<08tem89aKr(;=GKji?)kknL2H{M&Z(ZFM z>tcOP#vws&38A4SRf_Fr0=QP&a{4CyOgWl`zJyQ`rKIfmC|bln9244%%PSjmMnQ1d zN>T6HXqOzzs_^VNCf=u5xTVXoC}@Q>NUeSh(_bRY&i4v?^C*%y9ts+fF6wlLGgi?~ ztA`Uk3k?<_AgOvN#w5%0YZCN)#!~liR+f%?SZ|=K}9cAFiawH{&TsR>y7WXfMNClNzCJH%mM2C0^oVeC^bBrn$y^X#b z6%b#Ay9_&%g{-1Ty~tFiARDLW3-4aLYEeW>gdIid)2`EaDL9I?J~ z`TWXD!Kzu*U6VJ}6Rni%_)-)7Wicc4`Rv5=&#dICzp1V;BotSuzltrVv(n;-NjwhS zMXPu%n-n+J%vYFKWW7a+z)XHZ1=6tS#*_ z>dJ0D=?=pRtHSBZBmn}|?X!rT^C-ePp(#(3Y2D<*7HgyvcMx-p<~StkBS7~9Q+1yV zx0Iu{nGjPW!J2qCU8=VT$tYYs8KFDH?Xif(cz|4t%wCm(r#|VB&g*%hi!}#dedtrZ zxUh#GPT+0c?Zb5e%26T+7Fq!51{-!N~1o`*NV-s7gW(|Satn%G~ZHwsvOo3%YW0+`Zd_z6{gPxqy93WucL=E4DAPNbTdrT~X znw%2P-bqW1eMr)#$k>`#w>g1SPj1HPDKOgzhQ-&ruK=$_mYnl2b$&fdt1Pt+w2I^2 z-!Gq?`)59>kb%q#9`PK>fO@qPzkXkJZw@_Gn4o62jl!3@_||4#{A43JULRLyg;cYN-7z=A-))1 zQ~wxGVVV`v`paUI*175^v6qDaLFJU(>(Qbb735}xEHuRg`zF9NggA?lfPW#q6Zt$Z zb9sB~CNhKA0CEEb?mqy;I}xTTrhK=Jw2w9oEWv_aBUzuJFzbV7BWh&{Sp*IlhK69Y zD`lY>N6bm^Rh);Rs$(zgl>WoFc@)oMu`~4d#k8_wun*XgsnjNV71@UIvqQ@I7Op*f zRPrXw>dy!r$Y~bX%8gv#Z3atd>vJf!^E_O$1=Ug{4)x0jBmsvQWun`8Rt5A#sA;p; zka*_H2Eyj&I?hDAO&UA6IjF~^6Plfqx*CqMvSyUv16A1(RG5TqnUybUA|z){6in(0 z8M9As6*BvDmcomiiM-sJ7+L1nD=LZb0a$rcp`lX(@7@@MX$*^T8jWb=>3q!a z5qlx%DPh=AZHb;gLxdNR{*1p8ej02;rBN~C2EOFsP|VeS3r1qC?&eo?0GGUq)hv)K z_n}D+z?Q-HdjwLeuSAc)uR#e-dyO%?SaFNG*ASo;YuElqF2{R9)Ftw-1SCGw2$5yA zUZ<#c98PI-J8a2EQ{XFhv(a~z)LAFZ30D+d*MBo#*IM*_3tB}qhfB#8EVrI1#Z;D3 z;+&x!2iUR?4o`(>>jdrJJS>2-t#FKNpz6R{Hy)R&%hOtC9{Kb(^y;O=P*Z1^aXXLAk!Vje6 zLTZ&q^924nio;)Zdt4?T!_#N2EPoQ__8V~v&a>I5?rAYz@%I^h-B|rlP{Po0fS6p7 zj)m!fq->BCkXKCFiWLa7Ew3s!>sJPuZhV@}mP^-SmJ(5!H->bbP;IOdspI=o*_-i@ zaoPGc{(5QP)PV(OBN{43hbAW@PUQ%UwAL(*9@w1^$L zHpAl(-;fz0GouNemLi1Mk3}?>1YN={Fnn?LA#H^=uSMNzt+Um#*UWfqfvqA(v@5?i zyL=ps5VouklCB79S%3!7i+yA@P32{uXi*pNj2M2u$w*f3;GN3MLOuDJF-_GF2S#tO zP2729x7)3I({*Mo&}P?MRX5-OLU2f_s*J*9y^7FpQa42U%hFac0LnJ*ugk$kf2Jna zZ8OO;U(F{&_o=0A=cnI_5o+v-X;A`-GRiW22XmbxdcgUu*Z!Q0M6ot7ZB@@Jp9U7c zUr{X1YGb^tR<~U&e6AZQ$#2LjxSle#=HvMP@AI~?$>9zWg-;11F-9FJdtuC4o*u9^ zG=q0SPUvJV2#sV}EL;~8CMl4l*F0EDj_g~m!sCscQJ-=tq(E5X029Brn8tP!*p(SE z`kNmU_5I5L@8c`EP0}IA_h|<)*BJ!d`oZ9cO@C|I$2j4U=daIKdn}3U;JF4~xNIG> zC|-DJbL&3+P}ze)jlLqUf=G%^3~yVYA}ec&&BUAx1P>Q+JmsfehwZO>tUvguVmz)G zr!5~cOPgm^(iyzKJR)+WtTfR_AsNH=n==H5nA6<05cEz@o{(*4+}7zeYF)EAc$k3H zUd@)5=ib6cn!vLe${Z+V#4C$ibv-Tkn56RIZJ83L2r6c70uRu-Os*gfE9^lLU;f!I zwQuoQ@WH~~(5Md!7(G|k1tL;#_T8qua?%_Uri=_M3&vk@i3WLv5TKh`X|Ao1#LwJ%1PGCZ{70zvDoL7)nqp6Y2kd}kvTXr~0RQN@fwtKdXg)b7)gfPF9*^?}`%Ak)6 zSywLSJF6zy3R1o~y`2A2M?F=(Aj?9{naN4`iNO~KuSUHG%3B5>ivAG~SX{Nyksr(~ z6sf%=BKG20+-lMX2_T8TV&( zq$yDr$^@-;AD_)MPeNM{j`w2j)=t_iDUap3H1B?2ayyxoQ0Lo~Mzym2-(O58?3%yM zve8vqP>mFa1Ppb+5EhqXJS8C#*CSTQe?36I97*(VHnXrx4T?E+T68UlMC1*}n*Zg- zMfoJx@w3y)rx$ljbf|spCudCG;Bje1c}xz0$Y-kCOR7vAnJ)VMoeZN;ZM|l%V&_+y zM!Qpq79$F$c?$%-NZ*!9T@ef@VruqBNP%IuFwIe3>6sgb{&>&2Q<1ceUY?4X`&HR;B#oJ zn&P~SY%x&(JT)mh#$3NnAIq#B2xi zWi?))p+{|^`bl3a`iS>%+;rH{i>)}QMso-uM0x~DGl%e5sYKIetF#6joDsSR+Q}Lk z{>K)rvR1tcm5{3NJPe|ChO1Q^frfpQ1`#Z`5Sy7M2qkGv6ZrU!=;MKjkQypD~6Wl_rFB>y#^R3PG}A;5m5nOUrhMd8E*#5{qqG8E#A ziy0Kz#jQ1)4G7u%wV|{ylF^gXNFP7YKRM2Sn#Tc#p2vZ&{*Tr1{%@9Hz~h*Sc^l{b zF8wagVGw$bPOrQD-|U|KADyYA*}HG%+@CRw{}Nb3w(kY8N|0AN_k{$?5isYJ?C}^H zMTzG_(T}aib+KeEwS}vYlhH``foNR;I9Cey+YifrfdVpIJ%(StjsmuaAK?+X`UUdC0U)5lP%VgR{y3 z-~MoU^l%fVEB+I0?Cw9CG4SH}`+zd$ummc6-&I=5TOH4pfZu_R z>dVVK+k*-JbgPSLgrT6ztdVzumefcoGCd(eBuo{Wb2KACh9fdO;6`_5wB9Sowpz^? zTs{n@j7F_a{q7C%o8JPVy{E;M=;vK-w1CwP;BlvY%`*G}*$pB7)kUL(A)+> zjIOcpzAJd-;jIbR`#9!)Hv0)j0pLi6<$!oKZ7e#%X^8`f3jtR&;MsS_%b6PtH~>>P z8oF6nrx(u+gv^PA;@almd@h_tA#AY%?bcb&YoOFLI`x0EW0q8)&9}X85QOFVVy`zx z^HxWhOM$yq7Y^DIaUi;3=6Qi6hl3XnN~o5Ky{gj`wW`!jBzk$Y|N4tSk)3(J~G@4#m*pu={+y z0dK|EdUvNartdgT>iVz7^Pe~+xZKm+bJzPxuhV9yYrelc{(0Buzdss_!=3Fs%ZadM z{&#`wN5)Z%{6^uwD=16Gftm`8RS@92x5F94EesEeFZE9|XdVqAnm4H$srQp9jhJ7e zw08q5FTv7)8KkfOl}mCbyd#dJz!*d9z`6!Xh?L3^g(e&llrOQ-(U5iU7JhIE`7nr_ z!KbdS3JL~61VwUE5!5$l{u4o_PK9u5t!IblNfI*Vt=hK*gJ|d{2ZkE=l1lx#!K7c- zl8*AQ!o0hVmRouD(S#SkzDNO69 zHH9fSgYB?lM3I*=W)pYaGMgHeH&{3UmooR5L|vJjfiu|@(byicR0n+_Z9ae9o-H5$J?elfpb2$NZB zTIY@qn>U+C1#?K%T8%p6Bi$uwD0LZUz5BkoI!@};W7U3LMyR=sBr8dkCRMsX6M|VR z2=z@BX`onxMWi81^cT|TZ0X=v1-ZGg2TDLMUzt6jPz?^d056JUTD%5@ze^fzX4Zram00Dcbs9LJaJVcrn`TFgP-e#0a%o zy-L5G&qV)+t9nCSmo-)C0CZuw=cJ6iD6cf5eGvnpm`c&Wv@1z-QhO?g{1b(14d{i4 zcjVu(a=S1?eU6`IEi<+?%obg};I5u`IsQu6Ym4D|zU5NRU_zlW>ofD)n$gW`9SG;K zS#tg5`>-ZTlu`t>MoxqzUh(-WlARE6ShX$Er%eAstRsh_lt7JABiM!oiWp;R`jM*OD?S4EfCG&V)wbuIUqElN8wGUE9!#yIK+$P7dM7rr$< zN7=7mcty)zPlah+c7utOQtBDGia&_lnC9$&93+CfDzuY^7#6l#>EQvb^W`xmg4eQA z-&w6TbV-&Ep-s#Y;4~9Njzi4z21p^vom&fF#<^KWUR+h`!9q`9#j7SZykI5?QMVt3 zVJ-8@&(m^(bcKub_}um=edz$FVZDpQKtsYhV0>wmI2#1kj-4@%V<#qT|rKIhII3Ye7*k*n#{>j+YlaA_ObH? zYE#MEdE6On+KgjKnMpkjc@u{#Q21LweEK2l*u#1R`-EKq>u;B};9TA4^m{)L6cBO2 zyUGZR=v!PHP8y|IiH<29*V5Tfh;F7-{_l}qrz>+V zvlZdzMe+248{#j|$#n`uJ#d#7Ts_an`pc!NG@C*FPLGO-{vRD5mVeogc@J3*=aUl{ z@KO_hwMOj`iS;8=lwbh#`J@A#G`u~?*rq4#kAY&;$BDJ+DF~!CV10;H4;-7-8tzvM z>x1ZZm(9lo@En&TFLz7IycnA&Q@Oib^F#uBhET2^b!yxbPVmG&+=@!nVjBiFHe zKQHg!G+$Iem%~Gz7EYi5usCGLm+y2KmS6X`H4co0woG2EgpZj#fZl{Pmgd?;erU|1 zUHyN|03(>k5RbuchbPS?dpEi3zWu&12s?W8XsBz)|M=CL1@zzwHy&faTB~i1`wQ-l z0sD!5I(o#E+V+pdm%eU1-d=mc z;nSSlioWsk3~JTC)HW@KD0)1{a`zhwWSwX-b_2`}=hRH9r32a{Rj~iVN`uP6Cxv|% zy#-tGJ`c6ka*`$_i3PtW9(@PBX1Ks~a63Yfvgg!SOWG~C*~X+AD<9VSPoU$(%&dc! z{IW2#l+Yi$^&bm`n6+sqNX>IuDnSE+tFo@vH7T8}8E4L*xk{EEjBvpDv`vxe&xR)^ ziWerCDUfqw`-nn`IjHf$4F$3%3n(L5=A!hp^J*7m7z^E%*hLAG@{ki+>GPM`KS4af z1-B1P$GKvVo(yr@9Ni;H9(Ln?YMO!f23&ZZ;i9QculgFmymmVh*_gAnvYkvxX(dxh z+f})Z34Tb8DJ}cef=OaTy7ng5x7U%x&p1v$SU%|kcCM+~1bRwM({%*(cK6%}^5ubq3BD4@o>IWWhpg=@>AzzN?e`tn&>&m2z{ZDD{S*98*^ zm6c8vIHo`x2a75@V_VjCarN?*W==`)s>_0Sefqh#CldY%ms7JC1H>wt_-%3%8Evsv zxSuz*8EAq~fB#hw1)>n9%ZkPFcvnk;M2a6Q7;#xUI_!o+SU^`YSEpvEpSSlfObq3k zETy3BQc>lEU0M3BmpJvAhXg?TK_4nDOVolbVCs?w86ZVpsLwwu5h2$@PXj}io{UJP z{@dC80J;n`e&tfDFmI?7f7D|STuYwO080dffU~>PHShcpMQ)jooo;2|XzX$T$6id& zCOz2*Y0>(wH@fL?;Zn8AA``2G-YmJ(osLjFNU_;E&$!)cZUL8_M`YH&7>Oh5iazqM zE^t>ZhaCSI7Z!RZ5?0u?KPpoo)hO5yB!P#LJKqOlPQrvBu{OgJCrSXg@l@^qAh@(C z`^HsaYj6y>_i9@fuCVBA8_3_SRKGpw-vLnz4(|Z)0D2zd;9^`U%K88TP^I`b`BIRP zu^HIi+or5w*3n8wB-Qr&{NG6;A%Y|9sA@*=3NX<){r(*bG99U?_QDkc#-XR@1Lx~N z6y5mdy+XWy5TrNF7oR7!^oy0TZl?qKp)|FfiUzd!h=bDcNB2ui<~yKDcKQ)>MII3> zA%1y2DOh-X34qK{T4rq_%7-iqkU8=6?Mc{?xDxQ@hi znr`iC^GLj+pgq@5F8*qqB<>(PGmuz`bOM*0qN`?nAFJ*MF~^3xb_eRi4aI6p(osmJ z?|jsHRA^SGs&dMPDT-rHj<&X`bTv?_5~?e(SbWrRjO1W&n=t8Qbvky~LDnr{(DTiC zp`X#_lCMeHM5;);%I)GO!7e9vfZ%g2OV%brh8VOWokKePVhy1V5M2uFG%z*ARy3fg zM>Y;k)?$QaOhzX;;d%_wc0IpPzo59}gMiBu`i{!8jy-QJ71G9Z_TE`pt5p89q0{b( zkX|2RU8;UK3jcW&{QS*a%196ieW9@A>AEt&;%x@tO`I30Irf~)`p$)`cDGRxW$cxN zL8Gc88iR-#7m^`?i8Ixbg1de{@zMwl^jA$x$2l051+msWK_Y4@uL903hG zRK>=bdjLdAusX`4u|jrO(EdNanD}2_<M&pCd|T`#7t11lwS;W}`zO=W z3XYX)yS_W#(`XOZMX~bB;L=>VvRbHGk6Yql+?Pm^_-k-yb_q7mDXCjFM-)MUt1NXG zlJNCer&Z;{(&{lY91cM2LX+3fJ~V?@ZdtG^330&^=6MZ}7}8?Rt|W?bw(^K6HhrIj zRn|s0uhGclycCH~ow{cgk=yx1hUaq3$>lIzf{IbQa383vcw6U?+p(L_da^hT428I} zY$QR1 z#Y#rBB1oX$VUSqcd-Ss;2c&VuoqQZdvo~Y35UcAu_4dBI1^OH-#FY2?T63;Z#Lz@x z*N9QX5l<72lI#%7ACCNTnI!tGvaT!edhaM(-_wFS=htxd|B`awb?A8A{s)ld^8#t1 zSO8BNpukDYX*OW!lGO&IJVr7VQ2H=!LfJc>A^DsFNtMIyutF0QsuqzFP{{0bg< zL~&H`D>7Llp%hdBRUNOO!p(?kQQSED_ld^~N z2PfMEBUNifLqLQ`Z^-{b$4Xf0$8+73Q$Zp#QP}7c1)NBCNEiO5`{}hqMEJH++=B#Txhq7MxQ5D7G#LkD05%mMca|-02Cl!DpHq0IG zy~mxa)3)C|&)PZQK&_(x6Wm44nLpqYa5dW)0swx$xTP17d0R_Lf zWmJOj4*}#dl2!R(TZB=BK=l`Klnh)^85a7?OZm?d6&=zAZD4B7E+>3}aVTIwEVxr* zP=m&mnd^attl7%>$}Kx&JF6x&#&@}~F^xb_k&DIws9H=sT|fUGE&UM*>KEp5U+-KK zUbJs~iwJ3~$GINzt8ln%>0c8@k)YMiV;kg+aa!o};t()<`Oe4QuhVa-bv>cbXL6`t zdcJH|bg|r4&G=nUj;VtQodO-iR*l=nI|A-HI zeI8_XoS(Xy70M#X&)$+5a#h>#{gpt&xUn)e1Fv!_E%u6kMapS`vKD`GN?nBwvYVyEcP3Vg@qQmRU9Oa%EJ)<& z`5&>u5H+#*SorTajtOr%FCxNS>gDHte`pEe{ehyx4mNHqT+2l&w2|}9Z@q3%5y=DX8DQ9sT)*EU52g?*c;?x)i z<+6SfUIO^hK>KAe2#@0q$vUP%DHQSL(P{?p{9t1*s>KX|lr=_wH~NGs8wao>h|D6A znv<>99dw^Eb>8ptPDYF^*%h}IxaH>R-NQipH#Td4#8|d%6}TQfIU;FV%{zU8`y=KYKRu=UnzEv!EANZW2g$HGV#?$ zKP?ToEiG3Q)3YUc|CX4CFU*vPLYOjoWQ@ZL@WFtg1rC@+O@h;HX3BH*J42ikig97q+3fYh*J5Y^`+|kdwq|IW>mc4E z&>NPFrq)xH8R?au?OB|4m<&THTIjRkS-4Yi0>h#+V_Mzb#B2uBRG%;Nwg`S@!sM~) zaJ=)_IFqbz$xS&HRla?1RLwR=2_S=hxDb_-1nm!oZvC5CU0AoQQW=1?YETDIBo&Z5 z_5obyB~7*pZv?W?h-(Pk0*YS!U=00QQU22M3(zO~%7jm>M!7R>O%bLnXxJQF*8tI|>eDbSR1`Lb%FPEP8C-fel^~C1%F$0dh zwzO;4xctnGIsisF!ayg0Pt2e`8mlR$ki2n-a+TSChmgtZ7KC6H)NU}q^}Z73RZSVp zNgS0Not3vE1NYZI3DhGS!+l>iRwg}2nH_n8p0`YL8T``4I(}7EpeTDTcoW>{TOw&NG0V%r1pifQGQRmpw?pl?JSCp$!^A#(yO0D(P zh!PahbBQYUYkFG+8Li-JwE?>qX1XLR+g}_G*i9Xb5w6o==i3b^ti+V)7Rk^Pq+6VN z#_ob-Ku(VVGdNdOxs*|nZUQ_r9%XQpE!4;_B?=s}qHovi5;SRaWnSC@14jHQ!Z^g> z#@Q>@E0r%=-4^(xzZmdI(2PnWM%=7zFNv-z@qO0FQNk1#9nCBf{Z--U9t}ZF&svC+ zs?=Fs=`RfSB=H{6wE7@65>Kx%b++?>faZ_Gx|L0_CBvA5V2U%cw}b@PQ}dp-O6Ve0AbZx z^6u=bnkyLA?`p`@<-We$PNU2?&R35b%|2K))Sk-q#B$}1fZ%<@^5w?6<%k8mjyJGb z&r}^tM=Ra=RI`YZIK$y??x#J_<6R*YbML@KUS=A=E;^G5 zh@6!S6t>v^Y=?I9q>`l!M!Ar8f2$8e#Y8_u<}x-Jgl)39iOY7Y+0? zqSC_IIXOvL&*VHcbvADa-&X#;oR5=wbUEJ^$kE+8UHs1IbqG0|P?=ntAL+l8M6Tuw zYkHaOvbPvz&s&fiDI{JdO1y{!Y%h8}7u}L&L8NlHl^6sxn5O?nQtL*Yv}t0!6nEkT zZ{e-VLlJj{zN}KM*%>|mipsRo>oz?q*Y+EfPHhvsAo|eNd|M{nEaaX~?|~#Wlqocu zipN9=ix|1&&nzIq4zmpnEpBl=S($R#nIVx_=acTMa4|r^*0m`s2}g@DROnV(W*y2ktiVhm=$6EqVeC_B<+ zW@5!`tHl&SeV74I7eyk-#KrB2ITE8=1R+7H-r5XYUKpwrXa7JF(~r@J0S_Mk_V(c_UQXq>>?2S3j)^Uqc4aT%eVqUDI+5YPA#$^voF#)f|&5J*AUnKIk& zOnP2-w`SY0GYgED2KM8;=NySEs^qDcsls)Ky+tI_nhazb!hxmiES4mjm+C0V`Ndw0 zjfJ5*8S&CIMNGHY9qn)uaPARx-LHr^Sq2T9aEik#V6+y9TKjfm_|Im!1iB;(o%6Ao zO5G zGIK(=k+nwV{!9pIz8T|i0?}k}0{Xqjxiz*#P|rcFn!Ru@nLV6`M$xu$>|XHKm2Ep) zR{T(2%j&kcyD=0T9jcfjOw{f5N=Ndl-K;ow^Q#2WZ|tij7E8rf9eVya5ytOdyIgMy zYsT2xt&t5$cAuS{l{Ys_;jGoE&QMo=5y`jXoQHOT@pP}^SOosj;dBot8s5tkP%=q8}=t?H2y#cqN; zBF!9wClzd&9j@4J=oPOnLq9{9>kV&5IeE#&;&BV=GnP{j<&e_AmNETi3G-i5Ww+qY zo3oFnh!?5ZB@9x}j8ojG_w3Bk z=*bm2PKT|H03teVx#-VESl6e#WjW1X#!#ySIRD~^66C%nhvi`U+oyxU9TSp4G#2rD zFXoYrh91*tjAU=&>@ii3km1)IYoK1E$y< z7CG-&(#OKl;6i2-P!r)B5j{KangXDv1SxlBT3$21I&d1l)p_PQ1@TASpO*o0_Ngj6 zVlmX*4s=$D6LKpf-}7dJ!bqfbfv2Iy>S8oY>Yxm*!|&rphBbZd>I^)Os?SyX1(yeY zqkXwlm!?pCs}4e|D&8@hJh;V1#Fn`E@{R8coUlLL)@m&c z-xjtDdwavHFj0Bvy=Ggj%$0QW4S!MX*P4no5lMzT&Z=zk+uoX^o6U4k1AL7Yf9ti@ zPXeIPy5o!7S~r*Nm_{w|^Mf*l$zt+U9xTUgi{9fy(GCbBCe48{MTZ>_spvisOh;oQ zHpa7g>HwZsz!p^DkKb$wHa>YaYGII&dBGo2A;_7~O?rVp?0{*zIwfmiOJD=N53bd= zDFag#Jz{|8M8$uL58S}lm-Wc`hTGGh?l-^s28)7B znQf$O2@MS$@LwyC#{vN2NQP`rxF|DUQidHdrS-Y_XWq}DzfOqJSUG745%82IqU`jC z)#*RuJO2G+>N;C}7q!~U+F8Y&NzOAMAwrSapB@rmfNf%(e8V6HI61a~aUg*4w}I1a z1TMHxfYWS;v)oE*)vZ6RZO+g`;vMhZ+ia*ier1nrTW6JZ%}b5_4B+&)F-R;dFfyng zh*}g7>kQ|as%wQ?iEm%)MHXNz9-peW%XT zneTLdzHok`neE2oTs4%0IU(L^p;uH*GD3;VS*tA@ZrS;(5(aSBoKnCYzr%0SQ{UKg zJq#>N1!$AtiX+pEdb{pp^=GGE5cLb5?6q6{ueH9u3y!~6c(bf2Lo!_d&VwC&_-KAH zwsj#2O#HEEY+w_+camk=Cng%+#(SNe@(;4RHnLb@Y_-EW4u1yfx{j2uG2-Cxv+i-$ z_lCwax&`@#oc(o^n{K;VV9s1;Rc4y$%-9Pz{pXw%SS4*hgIb>;oAwRneOXl2a$;^y z^y$*s`}$IxPDCsbVR#c*x+;fAt)oOY4MF9+)#}Rbg(Q$^p|!0CY~YX?=ZA92k-o$+ zsYXOC*1^5H017(s>vqmb?!X+?D%uy%}zUXtphhu?TG#1QZ2wIyv`^2p{P3nON zwA}GgqZff5B!4BS>|fp{H5bAhJU6xyaOX8p*LQ?_OEG|q^2Ur}^JSP$S(^{E5Nd8Ue@&tdomIsxB8;G#k?#KQ9w(!a{V`AU^rxMTc zeL+qoi}>(O+2&?I6P0-I_WJanSamKg3qchDFx zg959ez&hgi-^|%mA99#!J8>adZ?SiOUi)w%_c-fx<4*j2{CTDUvmI(fh*i0hh*z4Zv@w-M$niCK2RxeK@|)dRPpOISE#Br`tD#wHSyfwv1yrwdo03oZftwec!-S zI1FI+{AEqw$)E~xwvbUGpn2j5W7ITqiqJ&@8uUAvoFa5So2J6$4Jo_x_4&4S)mppqr$nLD3rr^~RhnsFnQF!Fr*Zy`=ebJVr_1J>M3i1fUxiMeeL$UA16B_6KhD?VHf|w z(u2p_^Dn(_Uw^)c+8g@__$ck|w0(w5utN_$(~ddeG`p&A9~%t$!JBBclmGFxJ#+Fg z_TY85*l(}C%AuFX_`41qxsPl$$gxx6ljF!#qmnL~iqrJgQ-k2@FxaAqgn$-%VOSB_ z5C{QPK|^=;FH`?fvz_FJ}e=}O2LI37MLPtCO4gkBuAG8t`@Oa|IJjx&+zz`?=T z$}i@gtjM@nHB8I2p;CtElex=0c?<`V2B}obF^r;#DOS zI)!2LFboDS<&P^YIi@t=-8#drfW?Ky-P=^fi+UCu* zR$f_Z&2>AStm4OK{M6ogd#>Z?MvfefV=1>C3=CScYL$hd)k>0HET>*N=rh1weFwmj z0{L-~W$dhpAWz~4+A61Z(PcwN4ssxryetE$P;~WhE``W*C(!XO3j=>KEGSS$2Rt7j zL!^49>JAzdge$ZP>M4Vequ;o5I}W&q9)ThJPC8E*BHky1Sjeen48zljCGkPB3{g0A_1(%xui3!BktRU!^#pJZ`<5#p4VQYnERDou=E)_ zZ01ZN)gEd@z4p_e-(~mT`55!ySK5Pry5HWq{{hSMZ?`1k0w#*XmN+i;$(*ic8)TMg@iW8{@Xos1!? zw)CqF)QC1(dD%ca?ez1}0IPQj?!?jT0UT_m(|NzgOD_<;89Qnap`0N09%MsniUnjv88YEm55x`XEt23@UzJyZ2yS61KIPsd@DZ{%QK5n)kM535t5`jXboZGvUAhuGev++cxV%TD7?MW z7NV0EXvYgyn}Sgl?;-ne&Qx#*Xfcsx2B(mV@d=`aE9hriC;CF%h(8YArtag0mqm_;a-Zx{YH#pP5ics zCOdDamb~GG_Xwxv$xMDdLK>i21>s91vX{hS-?siTyn(bJ^r9wa{N&irxx-I z`c5bP>|%TAv3u;4Z5yoN>w4S&sO#*wlXLC5TW+ycpFZK-=`I|gug+uB54hMaJLf37 zyzsYbPbD5|aK_aHGyacC@ ziU3YttTsId+NcSr-|ZN5)yK%U2}qDwfl^(8tbe#-kS*T6&3^KW)17)=VF{!S{=Se5 z;>-(wZ6Ch>9!_0^i?rpFc_?Vo_-1k}-Ve21SrP$;*mD_zu%OPB=RvEcpdt$aL(h;O zST&71-}~D03hZ?tdtR4s<)>}~o2NrK8K=n&>+KB?74iV5c!1;>BsG#CL-BMYB1rML z7udo>w3u|~6aD@7s0b(-14XTahf)!A3}#oBG+ff^el=`iFeyp;IVgVcxBKp~Q6ooMBeNLX&_9np_5=s( z-cIrP@y8ye*c-5>F6tPF(uJwr^h4exhw#)39xg#d)p=rMCB;18GBFqE}~$c zODB2~$3<#@gvGuvzdCL0+I7|jtyo5>6Qx`?j3~CUMCCX^QHx;_0r$v}X2=A6 zWM@(pF5p;xBI_9aFLdi*^k{ALhAFVqXcpZHWfncB0i(gpyBz1G8iLC=f_GAMM^PX} z{bbs>!>pvbkF8$+C2JqWDGeZEhuwn=i(orB^rMbD(vG5-o`KQ!d+HKCaQ!1@mD;oS zUCzCM;)m^?_5^E>bxC8Kx%GC- zy*HbO^?cx8PuSE6``V+=zkmZ_tP;`u19v^l-s?nHYK*N~cRYNKMx^XRcHd3Ex25af zvYlJ%ZRn_cTexVQwbPf9>*=s@<96DqXZ^_f4IXKwmt4#lW$dOu{NC<)_;yFQ@RKh; zxiiq>vY==44J`EU;dj5?UD=5 zz^OAD7h3MV2OLSJ#AoI3peQW`R#WZ9g)>XA@8$TF*9jKQ@NX}Fn4!NU&HX{^ABmT} zH4yE+J-zlikUg!+xAe1kx`S|sx(5c{4Ub*ldx?&CMsOk+L<|Q5KPajTu0c(gNDTUn zgD*?^T?W*Ni(#Rpe7qNfk&Y8%DYe1EI&$hz5GBFxqc6mTgK?k&BF+$n&m=HK9_*QF%VJT@{QyP-=6+#kP6<4yQA{3T*qu=byKq^3X2)>T7Br zmC!8HHg-%QSrDgzO%Mwz2{aJobc4`qHT09)%lM-XAm;0*oz&y~L`5{<(;a)G4>a3+$J zN#nRB>k+^j3;N>nDEuM_N%3934=^jDH%^pFRGlOfDXFCHL!_HZb39ieb1=HC%+ue- zjXA*iTir3e63C4tQ0flk-*0NRrK95B4pyN0-*p zypkt`++CLAE+N1PUxY zAiW#N2Ew*vOUj;pb*ok6w&1iAwsPyobYMs9U#~2+lYjanyXcH6``5=?ZBTrOW!Ag| z{Mc@Xoqm&De$!)&(EXZoPg~Ra9x?)sNv$mtXh(|XK>B*fOqv*RJD?b;l{T(6V4e9@ zFu~GL#ly(ZL~Pu_2U~Xoo$%f-_?&SJ%UWy$2aSL=l}msTfM-lbjRX%%NzI}M2SPDh zfdO9=onC0fzqLQ&{CgPNoSiI%KRZM|S6&v(Mq4P}|eMtUP*3BHOrkA)E$T z1{C)$vKrC5<-7~&g%aVy&t8d1_D4VDMG{S>!XC!4XwJyq*Pd5kuLIfhx_m1?)%@u+ z>A#|_Y&Jygf`TK4Fe#Y@ilFMx$Y`zyMRxUgq)9dW8247=}18yra+y? zOo{@H>2&6hG$61SlH5qF6AT~b6cQ=~+13MvxU;p(9(w#~D*>YN0UhK3`GooVoE#!T zXr~9xJ^&*NRYMlm!L!^8-hwI6<`lR1;7-4M~0{S4YMiiFM?GED-YPxjf$-XNntY) znq_r3k3@G3$EdT$)gL-FmIl_xvyD$-kGN^*jB|~T-Sayq>fXuwafM7C?4dD~y|sC+ zy?E_hdj{_vr1mCxnk?tiw_mkwU%AvO{X6WhPyN}ZjGO5|Si?t;v^>@?*}UCWzw)}R z|9pYfp-gbceRm_h-(inEezvGb~a$&OE(Ydw=eI%pMXl!yw*U*dHWvl%%A!72!#&r~s2~|bhCx!Hyb|DCw>31>S^}6g&tFI;!kl|x z&oFE1=6T8TH$fPT=^lEW&`@*J2`kAHP5R6WlsVLF75z2xnQ}dXnK1$kzRv(@Qqxgl z6r+w4WWCa4^m|`>UV*(1WY6pJt^8C{A$}g@B#mte44DVRAcmB(5vkZx;sB1IIHz3ngN8hN-3forMPo8U{ zp0d)uUQK2|x*t=~l88HjbNbgaFF+~XVC4fUtY1kL@DUGZ0rRT|k8q42&lxbm7Rwni z+O}=0!)W8=DENm%z(3$pEloQdM-!qMP~J;UM0Cm+na)n8|5a7@gQ*L&p;R`Dz2nsy$zgvAlC$(hh#~R_bBVAV7gs1 z)Zn(ZP8$GI%MDiI#d%=zpnjrnL^LmFr2Y{4&N0jwON_m+FU`ilTTqkeB#Y|9XG43Y z*eXeS%?wFokVoMjgvd}5Fo;}4q#>xWA~!IY81Kb_ct~l|$~ZCFoUN1bgm7X})+Qhrlk>p+1M?~K#JoX!b_vSNAxvP; zBK_s~1H&;P7?`JpMa0O$bxoJg1aJVA4b6K6rK@`qn@CqIl){WM^8x2Pdp4fh#FFa86nc_wx*KN z_JbdvW*1Xr>_k9uPz8~hu>R6K8<9WSj+issZr=1)=4fLejz0uA1SiF33X_gf_}#K) z8_r}9GA8XddD0kr{pD9Nk{CQ9V6mD8p&T10YF)8nqYX#=uUpUq4|KnNRSwi7imw~P z-HYLik-?M$S8U(09pS|aOVcZ&-j6AhW;lN{Z1_-&AQ=_7^haMUP@r$~KmWq=Xbe=Z zNg89Qailq@1&1)=8oaf6OC4EFi|sRGx|0!zMjA$n{;S2yFi>Nt9l34&^3|44?V=A| z)}0;9`d~JC3{9min}BK{sJf9VI5IWaU!^`$uosxQ?q0WgDOXm!8uBpQibEZViW_E(GUdq;xx?RjpH~5y*~@gla;=hi|+c) zPE-JL$b85o34D7oz{>K1P_$j_lQ_muhEh$FIXTq209keye`N%PlS%qRb+i<3>|xE- z*VBhi^%R*>8krE0F&s$(vMaeYsXF_C#oX*Er`SNILnVn*Zp-p=Ot# zAGAN;@^_2n4zW%vu~1nx*&E*>JD&qjQ*7g4zxOI$ySu%!JaSsZVe1tMcgQ|EC>sR1EKKf|P|hnBD>gY3aV zXDC&II@B@89LjT+LskhDIo4#4JLW4Ky~k}2;ok09QKgW#d| z<4g*P@Z&%!ZpoHo=p?R~ON1;2RtO5BlxtmX@M8>+*e{w9;h`v~Xt{YuJ6*ZIv%CIw zvjY_nk~=HVh!jX1xFjJeCI+(`TIib}F0e1=eFdHLS~8C9dG-7Q6q8 zMU-S>OoPj{_D&!GBK;6`20>PFU^FidPuWqDhOHJv4a+e!Ar(d`vX+!$Trv7Zh%dG` zw*t_}$pP~aJ*(EB`i^FBWPur?WD$bHx~P4K9Tp=ZJao2dHDoB*aOriu_0}gi9x^we zJ<)iH$q`tjUjQodp~oEWTo*YR^5fGSgDaANBcH`@4aPbFfvwuub!BBpS)#<9(jV*a?XSM^ z1$*|nN7ye+pXB=UAV{e9#Hq{h_fZU8kX6)m%fV=hpq~Il1$1eYHEwQ14xMZVZ7Uz} zSsWNC;USYl=BAfSFGlZ8oNICFNi@{O$!uNBeR0bXV(g{S293i?3kKTI5efQ9ZXg>j zV3tY?dzD!#WPaVfej7h+7y%E;1_gasn+&jGD^TAIs|Dg5SWcrUSxN}0`h8|m|KR*B zTR`y~C&9?vlIoGHbv@Z9487_?M$2Aoue|&`uDrJL^9cEPeTl7Zs}y=V1sSn351%o$I`Uwa+McX<1KM12{eRn<2n+n!_tI}_nL5%-I&b8vbI$6=?4*ifq#0}Co; zz0>yrq~huZDN>|~p&=yH5V*Y}yEM+n&CfK_HbIn~l|%{!S7{-o zFb*1HD@(k|Hpjc}ir?6WAAX2o zj9}bcu$^|`#Pq-dk6?iNmgnJgXvyn>i=Uz&0>~+gL-FG*a>;y}8#`bofoX$rD~p-; z<$Meu<4+M^Y$AH^YH#Lz=}jm_ngv|D134D_C2)^2EXu};;Q2l;-%Gy$4hG>xsqLyq zq=!y=EG0sW-DD6nxB=;CwziwK@KOBk?rDY`5VlSAHI|Q&9|)y4OcWk~^6DpYU9hGG z(tv2GMc52tb(}~VDMl!qv zO((JtB;&I_IS!^WCdhE;d#UbUZqGdRw$*P~Oh-I5A_CpZF1i67u^2%>$1d6{k@?QX z7K?Pm7`J*SHKq_i7!DREp@vFU(s808&QC#tAS_W=v+RjE`|M{wNA4p8EUMbc*4ADp za=-3(R|5HMwAIU3IWSuT8DU?to{fLJ#~yp?af;kgy2x>_)J^b7j&tqhfaGCz$6s!< ztN(DL-E=iggxoJtoL8(_j3D7S+fdg|CJp?9!!ID4tN>RQZXR^u@GkVQynHTYdmaI5DHx66qsG{$6g@T1LqdkPUw0i3Hbq3v zsjvX)3@~HLx4;GH5)s{v7%&VNXsKO!vqpeM0oK=p`*lT6l|Z?C=ahP5`d;t9uWbvcL68b5tMimIh7Jef@=<9cyy2^t?o9#8|JXwkDLjJji1)TU=8CsAZLtf_m|_L(Be`X(tZo|yv3o0;PZXp3`kh(f z-arLTPNab@+uYS;l{m-Z(P0}tEZ@q;jj+cbeIH6Lf`Yl#Fh~QogL|38nc^$B*D&K$ zH{tv<$}m_D2cTrV)wQqYX-7DcV1mYNn=$)9`}~uyFxEF)o2})(_Mx^Dg5kxv6nkyN z3`7TkZnC*FQ&J;%Y2P#KKO%+BFnQ4X0T$TxFB~K*Vljk6e1uZ=J%n zpZ<|X@U4?+qWtXnJ8a{+wd~h~^&Jg-$O$ErC3ejPJ8dF#+_uT%kl|ltAI)E3`|WoS zy+Vd6Zj+7dzaN5yU*SM-CR~#m8rQFBX42qX8#Utq8$au4yX0n+n^AyngD4U3Q6p>J ziF!h>4IVz&N|`d*Lk1NP(F65^d=!RPE?Z%xWtB*{bAQRmWAK3ckO7yL7u$v{>z$^~ zI0ddSI%rkEoZ7pZS0ecmDH>$R@X6zxUMk7$2yXuGum56V{P!PxZ@=5?K)%CUpFpH9 zi$SM!N>nPN-AnW?Ra0gr2sR+&&=W=V16dHhQV;RbhmfZEkX~M(AlN)ItiTevf_sQM zQ$&7gjI3BBY83SH5GSZpc+kX3U_diuEdC-445m;9x22orpGw)JY|}Px;K}j*uO|c!@RuLB(zO@GLlXkYfH) zn>A}Hm(O)!WIYt*Wku6GyX9yer74K!VJM_$6clR<1659cOJT8CG>G%j*CA*`-wzo! z$Qrs~@?el%IOj6{Hc8Yg2h0jX{~S&idM~w_Am;`I25})qtsx=}F0wW`cSrgJ1DC+C zC=*eyL$C)&NhT)h@CWnfIlTq(&JsJ~7nhPD&>&Y(W}V2M7oY zip)#Rn5+)>a98*BU8mgcKx`_G$Hb81{?C{?!Fg{8r=_eTk3b_vv`#6UERqi-NJyap zl?AF2OsBpdKj(SfZTDLL(%I(SG2d1j(<7Wvx^6dJn z{%l(tcG!nsF12h$fIW#W6rTmfgWeOYy4ZbWITRR}42kA13^@fE0Ynhn(MP-ar~6yU z}x~2&1+jXdFImnr5;0dE>xJyi zgb`y<3D}_8KQi?=L24hRcdcO6J^asJ2l8FsbgY+P zbz)hHkAfwLEO`Kxg#gT8xP(9BBxGc`Qv}<<6Uc+G*%jrhexjl*G%6lueu*=YM79TK zAOS{A6pZQjWF8r!WHlG6UXap5POT$>1V;kME6Lz09sl@aPO*m`dK5vzVmtfCr#cY9 zj2ZiYWh1L`&wW-?(`bGAR@kF|yVowe>T>6EG{x}VmtM31=mnMa9}Ke!hzLm)d;)5! zKoPED`Z$`1kaMh~2PO=7b`Mcvi0hL8VgeK8j*%&0RFyS-`0>Zcrwp=l&p+Qj`1nJd zO3aQv;#fN1aYX!$592su!gSj)_Z>$z#gh-}&-F~6GKH@=P?qhB#Vc*#Ftn)9MB2J# zvmJWK5!SM16;KnkAyki(M5;cq)__Z>nphoj7x~Dsbm0hDI;YknLs&}T*~41Pz{_O^ zAut5_x15Mzx*j6)99UrIg1;4dNil^TEw&q%j7MET$dk|y*y z;BY)NUUpHR=mb7eLA;z9C>#O=SQ(hvFK6-l6qJiVU zrI+R9{<>x0oi~y*l9?{~e6CHHJkwgCO~3cit2Sf+HHIXa3r<1vV(NCTvd>@t%&xiS zCPp8-ZT3{U_kr@hUa^>c2jnP$POfp6mYVFPUgVY>M*B;9O1e?)bcn0A6(E9FL0{2& z)2g?uaC|@ZTgq`BO*BbXRt&e6$VPP9N`WxBpJ1~Ym`_zbiGY*~E zXP5r+H;^v6t(ZE-%kMqMnh`oN6ezFo}=DzyLxJ$!G z(BPEXsg=1#iP2`yl6B&M4+A0UJrUPdhhGDOT4%^#?!YTEG z`yYP7>YH2awi|EYe5jwmD*F73ukENK549WraxXI@%57)ccDwqLOYNE){%Erh>uaOP z-ie~`K%z#mwY-d2E#`eC$hvQ9sG%8cha*n6oydIq<{FqpIXK7wg;)x`hHj~LFmcBB4VNjG&qedJlI4gwF-d?*L&CF9Y9 z(t{HdJ1&EAK$-$`kRr8MWoaBpD-cKzjG@lPUOJicZ4=FsT@-MKFn_y$zk$}T0w>A+ zi{Yel$h`beV~c5?bZ!`*EyFCeW7WJ?E&RmpdgDpE^NKsk43V^V_c-s!!&xL<9XM_> z3_8-INc+<(Pw`v5BDiESS3k}oA8K_A;+WI-n{4|Za4ZmBEm3tIEV&VulSel_dS}5v z2lGD0*{2IWwmVtpV(!5LCOPVUr(K=Y%(x#IRj>Ao_M8~ctVIv|5!QpXa^L*cP9eGg z;mBcj`UUseBagjcuPv@6Q;FF*x7=t;o_WZ^gNECEb7>MJ@JI%j!_jA?z4kuc>a1Ow z3|xCX$lP2n8{Nh1b!DePAkT)5ovbkuBoH?Oj9sqpLYbH>bpU-mc|(h>7g~2S{YxJH zHci&cN-zC&?)!hBqYWtN_h~tuNSB9rsKS(sm+ED9%?H$tg)$wA8doU3QfDr zVFruFA_wRbDJ-qB6NgQ-&p&_HTy?c56|`8x#vW9CORaqe@;6Y>hrkjXf{f0N9Xp(R z^L_o#UI+3W-uaZT89Zax3Ftv`XpD{nAZg&vc=R8T4wqDR!DiLXo$N?BqI51nSo~j> z=sga7)JMdIjvTNS--F+Kco^bIB2^eMDgNFa0{)3n|A11;Ct?u6n}KN(MARi@92+;S zacU*Q5kAZXS9VimudJw`S*yv>*{ZInMxG)UV@`3jIBb>WMGO?Gx2isai2{>oAr;!X zO&b{tTWrHC3T&q)zA>{yhP?zK!B|hH^(E5tmjPe!Fjr7a#l$0oSIBvy42;A{3r6@j zW?d)~QS;q!*il1Ak9O)mak3@#M}%-K@NQ` z0DMYINn6-R{5(p*KFU3Ia~=PB`Zb%kV6`n>^s!xb`PJ0N$V`1Dj%-H^=Q?V_M2H#r zHhj`V8&FkfGbc{7JD+&LJOy->vsO;c2golAMLB`9rFdlTz48hfZ$A4I84#RGITHCl zIqNcHPoA@zZfLW&ky-ERZnp67A$HgwZpKL@Xd>-KHFuSbA6jKQS|aw&Ywy~}bKi3Y zi$$TI=K$48Qe?kUMFZ`J$6ahqEj0uh$~r2XI+}Wc za>Hfphca8c@^gFYncHk&S-u5_4zm>-*8`!#DwIA~VF84UP8&0F0QU|lpJJc=hBaw# z?Ixq7?nqtA%{95*InFraVbulpgHwKH0|t+^$lBGwty`@I<%pJzOYGn|N3n;O;bWJs3vSC(;<4G}cEve?9bqfY|z0Ro<7PIkP(I zwu1k6&|3j5mAb(XPduLA(r1DbQb%qdY85I{U{Cm}^GeyfAADv9A9@(|iV;?`v&Qbc z??LNNgh>c#U1(P|)I_Oq6j&qrQ&|k>jvWmSyirCsdOccN{rXp!uecBf6ho|tcq6Fb z#!6+}eMHVgr5s9ydoKo6l-%xGy69m`buz3<1>_>e@2bY54)`eaO@~-Oak#y$17i`f zawOI}fJ~w=uCO0Oy`{FTW-GM|q*)>uD2^SWBfc7Wlps)2pNf8tVr>DG;V>{24e2C^*cET$MsSX5jPp=8$%0q)>4O2{{0jT#T3vlTw9%aw z=>o6kepLaTjT}DB4xT-mx$$+}7aSS)IYK0!@RmSI_@jBd>g*r)JnZN(g<*v?Bk$rB z8;X}-nIr4c%j$%2J|am7N>UF+H+3ejG6o0$ZVWCRAq)yrwn1j1rbQf(nliPg5)t}5 zs6%9-U`J?V4Iv=e*-pV5$2y#B;-&VrKuS1Ge6t)Iy_WKBPG`O!O{sxUq5GgC77BG) zNnw8^LlCS4wCv8%S8>7>H0wdS7&^^{Bf>fVt#>#Ff*Ow1TTEXNMtFO}8k;d|8pfTh zgPK!);}-kyy+w?-^;>yC30Xi40zoc)KE2fVI4;*&h{8e4ABF5N+)g;^6g%n6AKIs1 zd}X9a`3r1a-39_8?l;pJBV=3(Kq||s9Ox^7URx+oxhtEc znKYQnb(F0`%o~ZJgsdje_SHM>cs9b?t(&cEzyLdCP`OoB4zrhEe!(V9n?is?b0-YcIeiF#zzB})x3wRI)I|4(Ap-|0jHez5k5hO7=Jpkir zD%{NMkPL>(i^i4&67!*7iXm0W43RwKNZNrM^7vV01v9uAV%1dNg7Hz&x5%lBG(z=_ zbhp@wrAuhILw*I;Q<}9yQ8tmF_5`9m4+5DZ`f+N2sZk0Ks``> zyMPsPz`Qkd$^*Md65$mUWLA6*9X5^=O+q0?@zANUNV285S*{%DF4+Z?0c3?%l$44S z6wU+c{h%J;!?^?k7=1ZxvJ!QL<7IIW+_QYvn1)JUpok?0Iw8s(1k4emnXRJ{EWQaN z&h(_3t?O+bH?fuD1^Are%0k;w+hF}r0>1hDpL2~})K79b9yKA>PyH~GQs)%dCT(O* zVJk((UsTx?Ym*x^@@emX^QQGd2ie07hjI-f0Hd-y~sj+3&>g_?NU1vbz0(?8jGC80fkW34Nyz^ z(*;9qEQRtxW2V^PVdH4$7z_-!6PoaR=Fl|S%>DPVt?d=C@K)Jps}@0OD6_E>CfLw{ z6KwPL6`a!+JL%9d_S>5tu`B*?jkUD4FoOjd80Nu8o2fXlSN$|l25|6HjBtjm1=)~D z6VJTxiaq%3Q+E9EKV<(>?q?loIfYGCK%re!b;!-ofLocLUH}uYfM=i(#$gZ&dM-tO zFK}in^_B(mm)f}Tqpe@Q$39)O5EbRgcH$2Yvul3$S3CZI{i&sWZ3D>k%SR0+dmQRy z(?JUHy+FM=)W9S)q|EaB{Mze4zQem8X6|_}7`Ib2r)R_MjXHWtGX6p{R8;p7`K5t# z1Y>1*pgkBaIgua&iW+sQ#6U?jZzJ>Q!Fl9iY(h?f5*Qn{kn#;)JXD&0o*?3NhB3h; zQdZ#y;%VDaXL)2N=bd|j{q7I9VvNjw^^5cE&v)JrcJ8)cUVNTC_wt+8P1N4X5q&t8 zC!c=@sG-~1%%fh>i4rSOJbxd8 zA=L@=r7ma<`w0foxPe1CE4OYRABWP>M<*}Gl+_=bdBfL zpr9nMmvmbsGa`{gRiooD(7fQ^D#YV$sp|myam~44*e)EZ8UrocSbB4YCQdnoC{)}6aC=RV)O+RVeRTa3pHstuYRvjk4|gcIUL1RIUZtIL!O!jR zV~(_k?*5xioH)?x*4J4g?6v(5+Q(Kh=;+$t+(5Lv!LlV~_V5Guz!D14_}Gnx)bDK6 zh-tQM?OH1$s&>WY`1ovUEg6~}Te9tittHO2`0$h#LVJc-+Sd*8#9&B zvlzL#uRdc__BnvPguw+e>XtqiLCAaWzr>mqP&X(GJ-)3>29K@*!@rhmafw8H9?dNsOlCCETKi2uGlp zDI@C#mrqG`Rf2PzzZ&CmXpGaW4j-Xv3MYY!Au=aI!rJ+~WFBnvD8*kffb=ScJ1;Cu zRNlT6tyivD?m!}OK6gMr2038}`he?qz+4f;?xsjvIk2w<+q&(r1E<)HcRy+)Mh~?N zB8X8OfW!!sq&#CskHTPsJLdyqP_!&7r5A+jbh)6_0-LDF8>f?6dQ?&1CXJ{qEGgw2 zp#!(0>^gK1=Y%LBPNoIH$9x{r9H1NmQRuLRM7JHVyTI+;gSi$czhpe^{7j>Bn_Jq6 zu6@X`=Mljp(E_kdn*&)@0oTr&$_QWpou*5Si)gVS=HzZ8GB2T!{K-e3VO*fCVu<7X zkAe%U2>b!ND*!Cy;PwC258~xsP=F#*CNl{EC-R;kwU3f2G`_fg4b6J#Ur#x3+2!Z| z3Zv)4a0aNoP`<}`3w9JVdFav3?XX{6@S|Pd{MUc)zUvk{@BB+`&ARolooGblaGkD! zR+8dc*&kV_XNaH!cNUNmE_EdrpQ)_H$KKI?dE&+A?X;hrX0f7DduqWt8$NZGGqb#q zB6W}YKX9%WUj9d0zhohMq0q^4Hg1P8M}JbBS@j4aIJSEt(^c(*&&VvQY994Q%FQ6*3$@+`os z8Q5w0`K7QCseREq)3&Y4hBM%7`GQXvT}+*>q}-YbL?X!cR8*4<(eG0dEah2Y{4PJ6 zF<~^0p8`7tdNrgLF~DrY>cy;!_I-<0v3L9R>F+>kZh{jvqjo2uWmCt>QaeoZOgW6k z|KZMkzy85fviJ2}t$@<(U37Ad9VjC@1Xl$s?*PkJe}SgC<$%jJ0e2K*G!^}IU@VbO z1a43iL`DJRq5`@!r+CtxhtDU-3g?gjYVhEpGB}zn%p6)1+4My4uyxjNSZ|XC59DWA z+p)6&iR%b|&jSiIGQj+5^(Ev`G~a@RNs=bAmCIH-+Cw3VmLJYvjxb_{jUPUWG=DMD z?oWfkw*hGZRUws~%X#I1y$e#pA|tax{h|~2i)=;x5t7p`D=T$6kk$Mqam6GNe=!ec z2FN7Y9ko0f482fQHG88Q2hg>u^hMA& zp!$=WPI4=LpDlX?6tP6e;xf;Hr&{z1utzop=e zqjBqglQoSRIM~iU_B?y=v0Ln;XCAZhR2}cV{BNz0@!-6 z%lP{QdR6eQ94DW}ai$P;MF1SJ7L^Kwr@rQtHHVVTp>XbH<+8ScGXgQ?8T>T396vWS8lPvB>}tq7w7Qv zMa(g0srg@`1EK=AuabdPF{r>n7+!ho!7Mc2Vw9-e)Q*TDSSzwNV9qYiM@@{WY@Ne& zix32)UBJV@0V(LhacWRLJtn*dE*|VVn2joge2-sy9msch^V4JmO<=KE97B_92S#d_ z73l&A4#2z-I1xh9S`b%vlAZ}7+msLZ2P5mn7%2@k>IH*f)V5dLXj7=|Tegtiz4p=y0 z98$AppI25`ae1kgmls$)6A4o|qyGIWoWiCW05#*hkujud8jRHLfF9Z(!9!@eI5K5K zBq>f;dk&Ft?x1RCy;L-gkkJ$r2W?PMA?mkX04Y>z}sj(y$FcRk$36S|Rk( zMjY9Z$NY%3AWPyptNRRL9p~CG25J?Qm0@6jeB?a%+?5OF*~EPg#P{%TGMoTjEek9e zz*$FtSR^N-X^^7(9x(F=G@7~{NG=7mg1N#MVMybHaDLqs^gF44mBG>z`G6^cK%lw6 zP7bJv6LVqW_CMhlcF%ox+OcPz%k26!wtDgBu;yCr%g;U_s_rB+Sk8VxO_{Y>w!X&t zz4fNmHqA3n3A+d8bW>w={!IoTVqzC`17@ocR6{B83S zL1@;ApR6g5nwP_FRQAceDSJ z#Y?c%qs)$x01=Ao^*yZ)6fE+Bo>q_2;P3HkuLJoGZ+;5KR2sv9KL9G=M0oHugS(JO zNi#yy7;zV0m6ZVIQq;tP;s}xy%*Ct%aOdIX$>U)GnztMbBp!tVFufm$F8Xi;ij*8| z0wd~3h{Jpd5iv%HxWod|#5i?q7Z<{Mp+>N2{d!wV-D2UgukDc82Lcfk+28(nqdocb zb3|^^Jz8U*e!0?CAX#xKwU2k+qwx=gULTN9Q(Y&01{eVz=ukdXPXhd6u3;hp)$Bn5wTzDKZk!HJy@hc`yCn8U{ud zfxHM&XcX#i0p}gV7<2=532KSZ|I!8fOvWe|iyy^M`!QTTBF7BZ9LKl>;rqKN5NA0r zXWj`AhU6=n=*;drunzu=F(&~0b_>=!5(ueWt;>R5NO44irp2OH_!YC{1{#luX!{K}iu8yYQ~6N2H@Y-@L}w{&OPo_^+e zvOcnh3^ZcuHvpYDCV~V{js52A!!XKZ58OKvN!z{-V~El8(7&<&%zc5@_@Rs~k@>+C zaSCvjiFCg553ZT>S0fT@(u1a$4;b_6D=xQ-SywbL?eoXU4!g*HU`x4JZ^4Ehf|l1_ zeGJ@`x&imGSJ0lDS``L9*~>b3V>m2oePmU#z+?A2in>M~qjw`#J+KTL4h+UGVqIj3 zJP$eL{cXzlOJGx_?cwJhw(D=Y*SgofZNAfInXhz=HHuKdo+!eRQ4XLWCc0|*7Q?bOEEw!kNX{QLvd^hyITaq+h>&J9nSo&Ye5^m6w+{!3uJ>w6v7& z{@rP(o%YP1|NQ6Q-hTV-m%s4B3nzc|)mJnA{`bHC;$Q#z*H6Cw`s?Yt|6X5@Ip&x* z-+lMp!=Hct`BP3f;e=PFPMx~w{PWL$Q2*QgzQ-PW>}+0-&73*&3tlq^3>dIo$JFol z-+%wlo__l2)0>-{%SMbCvA(LRs&3V)Rb&7C-%FP+oup&jdh4xM(O2Qyecav0*mvK3 z7o2$Fi7#Jq#T9?~Pv^S(z5j22btOrU$+yEf6q0#(#k%s*#m)Y8AQ2zBRw`l==MWLe z7?DQ9Lh(~bB_JZ2#yBcb;bC(ViDL?Qi7}*tJgGPjogYJ`cvORs+&t9jU=Pu62-WdUe30P0p)SpA5mB|D$ye{=SmYDXSC zizqf`M;$nx>?lYi_zuTGTpURe&FUa#x6*!jsQS`nT~WmOLIR+lppG5^b;ef|(q}?v zbULYChXUX_KTus884++44{08S)etF%3_%W^#%}1IF|Hxm)(+h`$mmrVO=w~HFu;Qb z4}jy35-X0t%inwH(ePo&@~9mJaX{+1P&A#)f!@lxxT!^Wfg!Xqz03!9la18Zw_840 zg=E=tfNgSfm7NgJW0aB#GQs{66tUeH<98pqz{&yz)|Ae(4b17#e0de2HQ>rc!8Vi3 zacV*x^fHL0lS`(jp;H=$#R)jhgw^0HnGxrbpmybKa_*jw`&a}d7m3taX=n&_mli7| zqMkHvA8IRosecr)wircZZ+3>7tzp@__V`P$Q|2bSq{&du!;u`paH{Vk*I&$M>(g=6 z8cxP0!5>(ZqPHtTCWg^uQz4Sc-?7hJqzg$5tq1rn&h-dV)Z7>eclHvzY8<5-`#|qiS7x^FC1HfuLJ2WKj@$%IU0;b$Pkac{vg@XI;-S9d(hyTJpBZ_|IQoP zmt@v3{LYwqp>10>A9$0Q>yQJoVFCgIj@lYnfMl7vm4nF=W9lm^a5-J>1x0xXHx5PA za-Ag^YL+Ph7UaHZa9141nZ}9i+_-`utK3#0K6(NHfqHfvas`3d_xbf79Y||yYY9AT zwu;$3_uO;Qwr$%6(ly-s&O7fMvHN#F|M}1Vq2D(&G*rrY$Z*T>%XwUR<(0Sbx>CP? z;sBCBZNG`f&wB2;=T6Pd&5g)GtXQ#P{GvsRruOO6r~aD`1o-6Ikt0X0W3xHub>xvp zzWw;)kDsOUc>VR)kJD!%8?csc=VE;?N3&tWhT-4*x18Ct&p!JjIgrB+JM6vPztj8W zG!`sau5^a|1_mQ3P&SQW3Gg6Fw<<{ln?+nu?4k_) zA=p2nVo8}0<@2*NwGR&wRssW%QB*`UFWg&&v9hR1)H?V<>`6Svb zD@3-ToL&zkN{GY~JfQd7d#@qRz@)r`?Y@WqNd)J%k%NX{Ja7b1czX~_eCwn4?BjV$ zC@@w!)ZQwZ2M=Ab&c?pK$XU8>8oA#3{e^U;XE1;`#twuVfxDtSjH0KOQ=IHT+o*?b z?P_{7YMW|_m?>t)+O2{*NMU~(4{-(!2(@*F)#toX5 z&GfkAek&%O_Xm}ve4wh0h*d#Nvkq1?)dOHDWjr@*$CePNaSZzBfZ2PhNf$(;+#}?~5xW8@RzSV~FH$Hxzz(EH5(0;ilAJ?qNzq6+v z(m@rn`<;%gx#UvRWSM23Vfn0x%r7aGVW_Rju;gH*rNt>>*aNV-1mm&y_^fW2Ot;MQcHt<*TvO)i6r~9i;$%!xi|$t(v9~__iVk=;wG3rqrR?KE23$dw0HT^a zygwrf$Z*GuvvQp1*Nfh#m!tqEOI_8#n=*x-=S%h8R)Wrc6SMC!>AVS!X?d`st@X{p6ERo>5s@iBD;$ zy!hga|E6qZ&6+i%&ph+2$Ms%)j=t)BOm)kZWBA~M4-Wa;-~M(n@*ROoFTIpQ+;!>3 zjT?vEdFP#%>Dc4Oja#{S^X4IPBnKUI&`0`vz2u0FI_jvmcKvJDzxDm6pME;Kv$L~+ z`4?DI1OMH144sqyEhnU}-#l0S``do0mq7IiK?OBBV!-J6$tu!BoM~pGhj1W4jFf65nkAyATVj4GqBLbE%1kux zf#4lg(|T(FQYs>1(>!g=kZq)Jc}(CKYXdqefJ)olg(eW0K(JpKSbZD;yR|eU!x$q= zxa`88J6TEbq~rhF^5r#mQT%MMl92;3##|Z2RP|$MENUP69XMNr^!hkPqnRwi1@u-J z4q!~ntP5wEN0geuFsb0n+3xDVhqgI%P(RpF6xqT3b12B>QLJyIaWMeoS5%T~HFaXh zs2>E!3L`8@!CjLA<6zeTNC`=XGs!~Y6R2rm;220HA;c8MV&Rwc0UU53(K3RT&~sB5 z$-V>nTM3dV-Qf5s)P2J+i1IO@EjzZ@;m4n2#ep72%c=~5LnCX|+}O*cy}=mJc6;@m zXV6$Gwio~YAP$3C2+W~)6mTXjX9Giw9)|(UXOD0Xy<~2wZ>WVAZD9%0%u!HO`{9KLbJX7;TOp0$85>k z1@@1>{vD$jqrMZf4)mQWQ5$H2l;CHaY?O}cM0c&7aQLZ~`D6iI^E)V7Cv5b@!8U5Z z7<*&xn^sxf&wh5y4{YrC$+l(VN(c+EoyLx}Hr6$dbR-M?S6$qK(@A1o*=_7G z;8q+$kW4xaO!dmEZ`x@;I?K^a3$iz~u6QhrGENL<7$XDf#!v?#NCd%*K3KfYw&76O z@N~2ziim7o-qBHJkv@oWvxPIMa6Yu;Rd7 zB0wn6Q~eD(H=pqRef>uVf`oBQ##>8s%{ABDeA#7}-Kp$BSphJb26QbJgDwrskywP3dyJ{}%r9>HpF(c)=ymjk&X;5Oum0z}Zuytp^jBFyMXI76d6ayhl}_p&dHF$QzK&$P*gTE(9X62W#t1c?EN7I9(~V+uM1f8N1%~LH zb|dH%q!yGEtf#sJyI=IzZQJURnJ)%P4B|Y<+HhLwL=G|+6yPy#1+c2z&`~u4RyB(r zs>*X;d;y0GWF~|amXcU-3IkH9Pf1oFGkCgzuJZXgh7*IDCG!YC(evj#nY4pu9LwKl>_h=0W(fyRnhAq&~y% zrTxXt=eR(B1YR-NjvfM*mN@fhw86OTx?jD$(f?>e_xND^|Je`!2LHu!BYhV1)X|dMR`S|oP#of z-Hzw;&p)4~%;TG%ql`y&75z*Qm%c7vzI=kdD%(*8qRc{Ynd%_ZrcGOT(M1>C^UZ%J z66B=3#etr`XA0UoYU=TUd!YA?Y#EeXHF)OiMcY! zQfEn)yfSvePjzsF~V;HntuHZEV39 z|Lq0FFV$8F#>Ig&BqsR4y?4OG%D0uv*V>8=8+c$r7+_hArR!GBXsSglSiA=Lhhjd) z4`q|N3Q&D}fk`63M8na`8is1_#Bt+oC*9Tk&bq?#T6_N6AzO*wH7yUK6OfE(xLwd< z3ux$q&kr=9AyPboWK=SSzzJM$6I9$5g!;-W%YpSMY$MF5=v%dq2Ih*$^w#f079NA% z3xooK#lz0J!IH`4{FE^{@B$pp1Q}0=tRqDxmqQn_>LYNKz}GRtWL^O>oD{gbn?(eNic zpN~eGoO{T7db6pG}rYHo|q~ zxT|pttF3NplYO#miCur`ZlF7U;!rXSvOdQk1GNG%rP8@% ziwT=PWvH!~dn^4TeXN%Ingv=E`Nf^w^GmgeZ~kWN*s-g2|9jZ5VHyoXW66A zzF-?R)!3TVo9IPALgbuNt%8TLlxTB(N!a>OUkGvhTJ*3at1+mm$f@%r2(RNfy`>v# zZ9sV;#m$}AO_%kl?8k$iVpc;HPyzGOVQhuTOlq6zFp?DIaiS`Gm*DhT=@CehK~(qY z%Yz=XjazmCZw&&Xjyw2!29;Ws(bN!#dtz7+2AVYp5P|v-1mxMLC`(@qk-Q>N4~5)` z6DKp3uz+&}uHffVdX<^iaIFB&Jqf#wiU6!HZWOjY3FAwRb`ouL>wju2#BeIAm8-%% z5X@@rDNJJ+)4-9r97~0B+=_e!hL`{FN=osU&%(XIZ-9VH-`Aei%%+ z8i#46KaS(jsBt^+kh-Q70dN@h3v~k6OTYig1vYW=2wT2zxh>{wNbWetw9R8IZW1Gy zL1eR|OKZ;rN}Wb#z768usN9p`ex`AxAAIyU=fSM`dl$m+Lv{v&!TLYl>cF5Hk9_Sl zzjp!^ktaU>c%HSObCypxznWKFKvyC5%gn=%hXg=Y!u{&yzGu7Hy9JOS$RtxZgh!uv zf+Bnc_oxGh8-iL6oWveaka?QB+rIvME$2$44oZlr6QZJKun$^aF%;j6FgxL;px zEj1rmTjLT3Qi`epuwWd4P7BWiYXKBB;)Gv2>#X~}^tHRVL862M9Rr_vfZwv5ry2uw z4}!pe$~YvA?v0p@uU*9;6re#6=B2j>Zjc zuaG~Z1}8ZhMNv2kJ@}dn5(Xxc@y-yXiWQ>~xqT=?tB@^RI|bD9t6%=qwyfDe^kuej zTMdkrDyX%vXo&oZiEM*mFOvXw*z~cZ?6@Niw)ehRYUysM$QU#q19(~~#8-ohtLD*6 zZN<-=h<;VoPGsLk)1QZjGB+P%4rG%e^2-x+L}cBLHdhbWeZT$#_&1CkY8z3a-x8X@ z@_{wnMDvYJJDnnSf8Z5mWX(vzM{&A?2KK`_0w-a)g48s6qBsWmM=}@5a|g(HXk&KZ zBQM62-vXhi*9DWJf-wC5BRF=i1Q>djCu4{8(v@(oT3*3M+;5J-EhhV;;gIVf1>zE!jX`bb z2Z!uqpMANUnnJr1r0813&=SR1Of`Il^S4Q1XnLuuo$DiZ<2Ve{;vTE#NK7$x<%@~r zmS@rh@_UjjM^Yxi2c-yR{A6mm=@zT)*#?P%87EC$$l4%T(ok<3R|GF za;s~JIu0}k*buHbEWL6*%WK2VxPs5!_0kbWUH)g=e&>~rvv=W`ozcwflO#?h4n&o8 zby35?aj+(C?pZDjtPuAgf&f$Pd+)2*C%@Kph1JS@*4C_=B!YfAO7%%FA9~JH*eknI^OP|DQFiWr1HX^j-`6I z5`aDZZm$E`)2e(+Kf}yo8JKO524Cf2Op`4nc$lOL>vV#Xj<+%T)F);S@J|H1JBuch z9(+g7ij+J+SGEiOKRX+vB=|}cL(GcsTbzUs{MQW}B_kjs<0Ct9i4j9Ysm4VgSb3y7 zPSal}tfVsAZ*rLbO~rwv?amvn2 z0Q;y*K2D^aN-$Sw=w)^iv+hd>ROvTiRf+AX!0FU&hd%4thTdh`cMx zhBu5^qLm)_h&{|Pmd&h8Z13Wfy< z77y3iAy^L*f)B=xq%qvOW}qHr86J$ZGBBN=>bF~VY~>pNiA+Wgj;sX;1bO{}Vgd{gK`sVajf!#(ak4?5j4JPSLk7r) z01%<6PKDSQG*Cs{dZ}jw^oILH?FZc^FYGK040C(JtQ8;`=dJsQ`$aD-=yddJD3e%w zcmM|mlR@)yK9E#x2`T{rGE+C#ERC^#qb67{4S4Dd)cz2mf}=WFj40yH|KTXz^d0Fa za*k3XMmz_aEfpS|KW}3VfXkrSW-zAeFVX9g%P+G$&D5ZHEq5Y4G3{YF77a0LgD$PY zwTqq&51sRAhU~hzCn45f&7B2ma^?R-@X&E{MJJ|+?&_jLrfUVgHQQ`SRi%{%Gq!Wb zCN!$vvH%&(jOqJXbmn0eD(mYwPmCZnE3!G(!X=Ku@st10zP&+j zf9*j1*Llq_d*y#62XQ@q_mA919`@Yszx(&EU0q%Iuf6u#@w{H!ZL9|l9JuY#M<4y^ z9e3REYY~QCdF7Q8L=Y0NK@3YT7U+SxlB?6S{#$v4Q{`_x#-RnTUxf@91cRZ}=Od`jjm)^_yXzH2 z0$p&ND}sXop5o-mum~L3Cp~JAlL9T-WQNGyM`KV|!%F-3t&bfl>!71N( z>usDX*%HvA#3_Rmt;staDl`6xy(8~{V;~6dl1YgsEhsA`@&Fl@bIzQri_eoHvEHtE z8w?h=Yc9XU{&>Sxwza0!2_8J$8?|t)ShvImL2n*0WCRYq9;b&aPodkYize8Pwyo69 zYN^@e)1$*GXqow3^eb$|hDU!00Tet!4o|9|uK%rnn? z;@7|a^&Pv}uQJ;0?d?UX*{Z*7)22;B#ZW!vlvAEpZCGqqeXnd{H?ws2@l_lCCUaH} zM4zi{qO`QMW%v7(b*MD3c*)`^YHyf7fBt@Ix!8Ryl@8SVxBLD7{*@Kn`}(d{Kw3I5 zE19K0q($?ZW`4w&)!-pImq`-N??4zlqmTnE$cFXvP`VYF5p}wNW!xCn1YcDYj`6Su zfmJ*_+2Z`C(8x;CJCfjY{S=bBiGIC25aEyv8K134wY%Lh9Q%wPW9RZS~*~)Nt?S{FO0efTUE5 zkW5JeC`@$A9Ez7o40?HS&<2m5Y>SqyvIzsn+GmTu0%lT1LBub{3{ETsoRvh5J&dy; zU}nwuj|@53T$b!X*_gn3M|+Fnb{oAYe%}m&bDRVJj!|H!L?0`R;Z9?)WyJja+)Xy- z2X+*DTA2W+h%v{wa$H69!t2G5O3^&0ITjj;tF%JL(>;|e4f>eWV{r1ME6%h(?hj}S zj)1~D5Sf!0=sa0|t(TvmK)Hff*(CRtrE^B}rh(@~L-tZ|mn=tu8i#s$yuQJ8hI_w;!E#91J=jJk~9R?0GYWy$cb; zQ%^ga=0ti(V18w}C%Fhvc5G{#!W=wlvpnx6(?oR5I-dB$6oEk&pG39FLDcLfIUT8utyh9E?HT zzYr8`t)T)y?XCY^FJ&56U3Jy1*Yn!_ncpP*DBF-hmow4t`}XZyvzzIvrs?1P?stC@ zGnI@s{_o6L_2r3G%N}*@t~2X1c9WX){qW(#H;Ab8{`>DAs_%6y{TyPCQpr8O_BxO~ zF3Y#`!!+H*L8z<|`0-(i+hX8M+h>YX>xg3f#Ho)GsYYpnD-0nDs8k|RSOu=r6!a536Gdzh0dhFOS zwwCVR@ngo?q%p(ni$!19q3v_*<~tv9BI@g|zKTxmIt(r{*vt-p|AY4(gTDXN=@?HW zM2PG|IFB|O`U=6du|lw^I<2m~$@-Nt@1wkrxq)gl*F4U|yj~m`?t!cZLmE<@qZF;K zG&9oMI3FmeJiOgFwj?qYoH1&*Arx8VbZ{QjM7mjrt(&*lXa-Z|xO#xSXbj_l?j`b1 za-juukq0!lK?A19@Pj}^Sq!gg8$k?0lH&`fSKmvJj6{pGXxSQjfAP)0WgRH`Y3>kVq`*2&k%-9jwH)^s)*Yg zC*z_INQ13Hyr&l{G64Vhd2j?g1*1UHW_c=9r5IgnQBdjgmWNThq z#Bi;Ah$odc1om6e%rP{J7Lz>|(q}W))-b~($Z?cqddaplCnQZRCc{0Lx!*9y8M^{y zWCH9xJbqD8kzIeoZDfM|_#K%;JI80AC*x3~CuvScj&0q(oj#cgi=d>O1#U~_WSo7g z`cikV*XAu+O}F`2$PWB%ewB4{PxA$z0jo(XY|`Lq_LsY6!raTJo>qyxO))Gz94>pr z%d-+wk(`Fdx|5EQ^<42y~BfxCLLx;9LK;tQO(Lju!awJ zzPeaPmj=9%B}q+LS-h07|989uM~N_W>ZzwbxBK(nc;k&@tE;PP)hw;H12ItbJ7ovT z6m~OJ^)oq_KmF-XzZ3fufzdqu?3>J4u~Wr3rS_KI4R@(sLhsxC`okaoaHAlrd+)vX zSL(^z{qxR_&H^!McmMmFU;p=9{Wm{x@Av=9D*!nbY&n7vgb9VgPZ7C(y?m)Ni7y3w zkqc8r#>kEFXb&`D_+>08$jTAObn#0y1crbcyl~%hz@(F4$EtGxFdzlNLq}$#LZ`$9 zohTT9-cLXg0LJL#0W2?P6zH1OJZP|s_{cXu{1hrBXGDQxxC`kO7?sP^H!;R2bSEk1Hn&i-03IvI z10V0Duv>{m79^ukn+UK7-K{*%!G)3c)3Ddo)rsLHs}S}Mt16L>*!CUUfIxy)f%0z{ z8Tc)$mf~O`01)x!AiwToEhH|ehdZD5xiDC??mGrRGdy}QD42d$2f8iIi;Ac{7^lOJ zI@W3$TkYMq-;|t~b>WOl@=91c@PDqM6d^t}6b|e+gn}y4^0_dl_$o)C8ia@I(*4jl zTNT`;u_uU8lutf@dI6C!21*Yc?gk^y+o^f6ES$Rv()cW#i^Gn?v1Ryy^3XW@K`&}#jY$5U`P`BQjT_< zB+809hK6H~?DJ2A z{LsWc4qM00EtYAAiAax7g3MLw00A;|DHr4MEDQa-kl7*lcqeG^0MU6lmUe`Tg1tl| zT?9X1gHEk1L6C;;M~D$Pk8@F)c)&47kd;uVa$dlv9Or+>Yd72Uo7ur`CaJOk9b(gR_xS&XPxe5tnPllzK$L}dX2vBuEXg2-N)DW|Nh$RK>mG2 zzQuoM!LQs%StLlg)fb@I94-ojE_Sl^sAgs;rHIoV9RR*kG29D8(TnxTr`Mo|<}PVo z@eJ@T87)2oqvjSQf^qVpnT2wLrRW&X5b=76#APhIVbEZ{9HSQ|V~B$Pr=lE-W88P= z9ee;riFfoHP>xaJd(KO6k7joWGP&&MKe3lyeGMo8sD=mV#3RPr=Sx;v4x?gg>KZAg z!oH#Y;w9xz(}1-TIqozMu;f#6q2%@wovPU^4z>as!ov;&s-qK!$rM0AcsKzSiNhEj zJ)m9a7Rf=1jpffNN2qWGwB4ajhxsN*1~F)``OH|?HFkoFJBFByD9PW2CB4Dtc`%r9 z9H(8ANQo~_F|uH2BLHN3-o(IRtgM=n6ogK zWRyc5)(u`a_K(^RI|F#fq3Ys<;=Tmg4iPxcB97DOpl;+LSah>5)a#+5wl}}R4mtiz zu8;c#tyjH5s;{Lrgo@8}1C46JyG!^BP89_Zd;7^3?9FtcMN9JSNoq%Z`t`N<-}}gh zjT&Rk4PExZd-M1V8a~-;@i>_o*C~}+KgaX1A0K}Cb$jxYc|dZ?rr0Y44Ph2Yf{1K6 zy4?X)JsmcF{0M8TYh$0(&=(@MA%2D1;G-Tx35YD4=$?J6{ZUWf&5j+lcK??ftjAMe zpS|;n-FM@ONZp@oYd&}piti#DHGB{wj0bR0NuaV0SnXtRbg^edXC~{TX$m+JLIyzv zzR9`2PTvRFJx6sQU@r}xdLGi$BRO?`N|vVj2&_600AgK|1%my?z0Oh}aR?{Oobi%< zXPh)ncl-PKVwLv3zN;1B@k367hzxVhRt9DuN@CMyusm)RgRvlf9(H9Q!s;{12xN44 ziZfjpXs}%M5{UGf2KtfGt!Rn-mWY*3Z?Y3Ftd*?hgYelZ21bM%0j;R3SQ6G53{??5 z8{`!Bz(fB+zGJYh-@JiFFt77~3r73vy?^8E2+KLonw|BwWW^GsHpdKFn>NL5fh`J|KV_jlYw)SHiiMdU9`GaM0V z8mp!*Z$IZ5#=)wt9SuaR#9;jZ7%xcqd@ zKk>nb=zsO%K*Jbn8ctDjc4IKR8fu|8_XP$b8{@nbJ!h#^=z(XaaU_BU>S@o@Q9pa% z>GoBtqG}3qkR;B#f36)|LbN?|4!uAdY+K7_hqfEQ`>NQ#3lit=N!7SwL@&*LdB&+6 zBW*)RP2>P^D+XqZsji1p=;i*A)UfV8isp?tcHk|4o^=si$k*n$^Brn=0%sZkGLlH6 z2WRg=m{Zq(_x*q5+*qmX<@Uu9dR(z6qoBs0V>$=^Qg}!P`1E-|3eb!l?x@vn zts#@mCs?B|hkN<%@-I;kJ`&=EP6)>=n%(#K^}W9M@A|%{n3o+yxiv}jBq@(1blxll zOh77GDRw&|gkZW+DA>YfQ;7}-cJS~JtH7O)L2CmNkcfp#{Q`OBZ#<=6bx`t_}_^DaEk{_)SpY~8kP zcFWb5+x36Gm)Q$J$3d(UiRMHSey^GMC2b20r z3A}%Go~Jn{fHVv$lmQ$~0S$pkvJOdv=a6k=g&T2A%`GitA|4w)VmO8YXov3K{uN{< zP9uDtq+^Fv*_ZE;4HD^RF_xOW9>CZL>WSjWUHLF`a3lpl zj{zd>2<#_6UE*0q@faIPmB)dwWCXKNck@EUj-u>t=dpXgUDF)5BQQpSa@0MZbZFR^ zb^3i0324*6c8P2|dji4)_fLH&nhh^FB^RnT7z%$&K;ezr#iyKPPyFR}uDgeTIiGI$ z9INZxVNcxm2D(%C+q@+!xD{kvz%nv**iGj?q!S)s3XTQKZQ{ITyHCyeTE@On0RGA6 z3)myV+E{CTkYwK}I~5665-=Xl&&9uc=vTVnhDYp{OHQ@fGp0g}$XF+iF2ph4e&<6w z{p=HHNF{qFLlU^^C#b2UF>gI%eINbDBX;90H=@VZfIX%-?L_`uDC=AXGq7O9P`mt> z4_QO+N;~|ZL+y>F+ilW}UQ}^c5KwSx2qcp4Fkj?$yXg3k^$?v ziIQPx_KwPP=p=GEoCT4X8wgG9p)QbsB-fHl_dFZLdfRKbLV^ngS@|^bqHQLDN!6PA zGKMPOk;1 zCEt!YWU@W}`g=HE3{Q^MF+iPz9uT5*KlKJB3po^91@mReEYx_1UK_@gd{2g%_dzr! zBh+vw3j4rN!r=CwQbA8*dD#k5NUSLUe4L|GzUUY+R5 zlT@?t3qs+(OBO~>P0S!=I=MlxehS0nJlr?v%a#4@SHJ%SKVvrlbul#$m@mgp|H*Oo z^y81&Wxu`L{`L6dHiB$Z+1|XBYwbedwQs(TJ@y29>A7cZ!h~sLLQz|fGzzBy2>^r1 zdHL}~O?gnj$P=U-d>cDnG3yRDG@6(uW{R7g&c zAc*4m^!;Wd>?lLu%HexiSF$$JIFB>8h5Ze^`@@BgQa8)9KmB<=d)RBoe{{5yNqdm= z>EEvpK?p$u&%}DNF3H9ub#L;ycLV_*Zk%88H9(2lN0Kv1a*xBnWMX5*xE?=@t_bWw z4_Sv7n9fsx4%()Ai-mCBS!mIy50n*iFMyDPUG?_G$6wkhKRJmlso+7+()ahZ*MWS8 z_nsL?PJovNTJVr&13Y02kT9X>D#ckhwTlGCNEAaa(NK~Nu6MbE7%fGEKHkUk>=c?Y zRC;j45Q$Or6_Q6<3fPwFf|5!m>G1$k1lZZcXj^1h!oq*p zT|rK;p*`*ti{m`qei%qDpr0P^GIw#FOWt^Au>&L)%^xqQ&S^jX30Fr96Whx z3`iJb1u?+g1!HVIqJA8g-+OV8Wo6|U9nSFEgPMztcwxJAq?rl#b3j^>TmVznKhG!*yyF3 z$q~(_l%QJh{wHLx85;G*+Lue0up`(-I43zUACzdPP|i7Onqm*M?Af!X*s?`mS}XfZ z`^!Zg!Uv=5-iKbcLgsYnLevndZJF!TzL+~6S!=();aZz8wAz*}+sQfcJ{%&Uj#EEU z)+Yy=LqV{qrIBNjb+Km)P(;w!=OBv2y>#w}A#CIq;oUqNI1J~hz=^*VOr>59w+FgA zf9J({(Kuv*B0xa)N(9y4Ug}r5T?8*8oaBeBtYoBO6?@^im+aCjZnS3~{3{KmNjvPI z0|_Y1YM@?Ua_k%eI8P&;y zt85^t$O%kXI#+R`MF&0rI#5HHD+;2YOQRYFHVsUmra5OM1`ln90=*(F#|cp{$#6{d zR(Pq0Ncb*HG`!^9uGaq9D{Q+Ij zig{cSFQ(8-q0>VVJGTm$44+Ygq4(khlfXMU)IK`Nc=CabHa6CyV^xf7e26HNtO7^bJ#^7QvnB%>lee%wWHe~F+*3dy=mh7dJ4rWQE zSHUtWu3%WyN3}Q$)(gQ##Lu1H8y`@Zms(XbPF&OXVk~YRStI}Cm{=PwT<$=DKpOZ) zEUyI7ahhVhV5vYlV24%(Y{|}c`)U6i?hViy#!K*u9zbOgVX`Yp+h|?gT(soo)6~4= zOq4NFV#oRB@;6AVz-9|m#4o`CP9BA<3(!gq_c5L9cII}Mmjvy+U*2HXU;hUpZW&R| zl|Z3@La>``boILBR==ac4m@aoYE7+3#JKFA6NcKGJ2%;tzq!zof4SSv`0?@f!2J){ zS4$T`gXXw6O#Z_QV~g?hL0|2Kw2;Hk-2?_V-E@12v{fSf`SAyHk#Fw;5-eh$s>@$h6>b)eMm0Qj{YRJ{sCAae zrwAhrf=W>yh-b)@letLcRG=2z4Mdr5J2tN)7@>O|{VmN$>BZ@InRpltkTr_hyNhK4 z;UQ}`-EuoL;+-4|mY~*18J3FfGSq{VR%uu&i^*)|I1a}GMd?tAJvq)38x*n#`oHb$)W zP%y8mDsxtJ8#B)}iO-MW@?i8!aU4O6P81ePD-#sOv9G8oaYO@)pbBRkgN*UT;Ku2J z@!>3T&`**hD5OwbQ^Q~=V2ob=K19SlWYoS^j%0~yJMX{$HpgWBQe?4|#s2|tDa4)?I z$UeN(Rm4{ggvzanIty{IwYEwvKzRs;vKwbf4};_M2^?}Lu*3J+1#tmWx#*r&t)(A2 zW%rBah=_293i|1J+ZYkTOR(%rF{aY;o=r*9b}%Cx{TF6+lEQC<%7fi&MdIbH*6+ zG<#M57DG*Xacz(t*g5Q1ks-RB@yV@qE!NT)VUI^_##9RPG_U$OCP@hAM=7zb6P}B3o8W`2Cb*K?AzrdC(T}u>R#Du*zE1@YXfq-Iw&)>FVyYq0>*EdiXDYNM__ru|| z+I5#*U{AmJh7G3%q0zT4pe@xD+c0JbxjDL4?fkq&5i+n(jH;)OnZPNQQ1sT+KlP-9 z$y(GW5S7CtS}!gJI>J!p5!|=17M(D!@{r=FqtM^46u1coyKenzo8QRTS70>hS#|6E zFttL2k#1Ntf?BX!IAvrBff-~dLck%z`VU12Zx_V08G=BDHErD4#QT}uzU@n#s`_Ta z*2#I7RS&|Ui7u;*kaZ(!4N(_KXWDU=6uhGiR@JWv8ZsO*3ahn9&FA3cH1}M!su*w% zApn^kSr=<8OmF7YDOR&#yVZi%FJ8OaS&sm9igZkd7oq`9B+Id)z{*tKd{wHR^hz5Z19*Wi$G==GkTQG`|v|Mbj~dM*UPU1femEp;SN-xAvqA0 zYreb~bYiXPl@N1Dm>Wh~rRWwM{KqTT*e^~wnY9Emg87#K(vUlZL4jz5NoG3mg`J7v|`p@o*lC+DAh%v6eMHywQhxA(Z#wo(%TWR=K2=i zl#<%EbBxVfw%9YzJx`W~^Wqs|Td~z)-c{mYx%cXt7qKIS3rdnzOGxyYH{Y}&!v^DM zI7jXor;6Hc5hM=}RN=$zf?xd7&im;JcG>T5gMmnD$s?(TSQC1~$La+-j zKkDGhWb7tNyI7kDU-Ld5F$_uo5vZs<-{lwDz)#WlWpwCVZci%+h_7Pd*rECfVsZ1i+**HMOqsf9;HYcS@yhQ z9!QK|N8I`jO+K3SID4q+VibDbj<$?7hs2BwrO5+ga9GZa8{M31t zZSJv(k|K;`jM2LV7K#@*ST-KRTIzOM4h8=nYA-?7E05?kMKqj({iCjD4-U!CdXT~Z z@lX=S_|-RTwO(o}g{74g;N@^x7yfSQv`KU_mr_&c00ty_#h^)cJw^Dd9u48#$|hvk zdg!5X2l~->(QLzq46=*Py#NS~#!KG+)Jt#LXNwl|xj=&f9GfFTJo@TQJ87tF;~w}4Cj2&YpV=0m zCX*uKPQ`+@V$~)AKF<0PT0_1F+VFAv+Wk+zV9R$j6G(7i^>468@;OE&j=PzLKQGtT zi`0309ndL3%0`@N5PhewmacZBYGRNyBEWR)LpKyM&$ez`yL>ZQtjqchgf&Md>?8Y7 z?amh^*a5apk%>y^5urcWc{~$51HrtMZQa@f%jz;a@drmbu%bHqd&y)stZJa>PEkIb zXFomV5bi$&2zATjyj?s~B%ruAToLbyA^xerEKE%#h6=={6>HG%`m6ow;tRQFypflP z3wnL}=B?BKySe8XL^~NHOtvQ|u>YtLOoG(p%ObtmdGGi6KYJa>cX;6`qkIa*3dyDPPB=I&V|w&#ffNCuV1uS7(HQ!@+zZFWJ{J2 zL(uSuLk`5S_So{(>o{f?eFJVALqAFZGe%@=Bgj;6b0i}YZv@&|YW15x z$6!`kbG~MlR9NbThwSqY-mrqAN*gqGf)(fI()moLMXhMi=v=`2T5H_0%KDEOhv7`v zj;(dJ^6Ldex=j5;G%%NlS!94-GO;|?>9R8pW^L%n$t#Dt47&*y+qjYaQ1k7k^E+fc zLG;D?Raw*8J8@Y=`cICOhwwwR{00tBX2F3ZcH{ap&vsSmG31{U4 zzDgs5PF6`xOspwf7x6j8e0p}?`0z8!#X+YX=RpR>0yLAAMV&&pf*#fcg{&i^lZb6i$AcmUn+?1y|Z89}9D9CB`i z5Kcx>45T#su%qq$k6$rwywz^I_J{T{@M@B0B7uC5&Q@ZQ0i2YEX=&tum|Gt9o}LMw z9KMRxMm89biiZ3X=UkM^hUwZyWzS& z5`0m6!QscDN{=5qj{YXWv`{nB_R`^pAO0Bs_};$uI*{-5)<^Bfr=4s&YwK(n(OoZw zem+c=d?F}0fpCG+@hGV~g*&3P+MTslT$P9BRD@Bbo7nUqu)IUvA2Ow zNJD}cKQGb0oQD*CcOIsB6Qljck%`%5&Mn6fA48e^9ZATI%1SHTy6d%l`z}nh@@gXw_rFf)iI;2N~ z+OP%b0t*3SB^VY}PT@P!*TT*IbiB6J0$Y={plmDLs=2v|wPTDf=bS;iC^kxm#a^qkGRcOupfa>Z9 z4-m=6!1SXu6ZWkdLD%+pXMNxLe1qKplS{#Al8nq#IE>?B#u%@9(+ziKIAxz zAD)O;D5ue$ed=Mm^@h7_pMCeS9N;z zJMiFHwsh4p)_^RrqLO`)wnGn{ZI3_s3`P`4m1~_geT;qi<=0MsM2hwEDZ3HF3kRyW zCBbnOt+R_9DUz?&E+YWQwIh%G0cIH5I2mM!Y)DqNknFL9;a?a3>QB@ad^BEm*_$uE zY`TzxFzi z?{o(Q?CB@wQrC{z`~LaZ8WmQv)`o$I0x4-WMS?~zFIbF*F=}Gp_AfR#lI&hOrn6Xg zN2!%3B*}v0exhe*Y90@n56n7^rj+Jz`*Airb67vKMa=D2{BBcsyWx7gOw3Em4d5iSg) zj9N#OM$H7Bt6b=qCHyQ&QGH!)3z2J`b+#7+y~t6yiLikuc+i6w7->@xTsv7(I~hd| z&QtVTVd53YMZ}ZTekdCEv_+77XN;?t2oqSUe84ozEA4CV&ijlaGqcQr<^wn)v0|35 z-(c0H9pK^6XrYY8nB5&C_e85gR z{WPwfYvS`pF{o(yx(Mq`^C3;2nnI_>%XAPp4F*w9tljDw$zpK7=OLp$~N;zq`;ON;Gi4 z9-aH8^%*dhh_?{qr}{(2%KB6jOwce0Ng@@=T3F0H?s;x5nGxAv4u(BkIM5C{;Sl<8 zs2wRY;$CKHEZw+iz0;XrSy^HwJIlz>YWYl#-Le5gN`{ByfbYke_d3Fz32G-^?gz*t zU&&Ztm?;fIeFs*R*nwmw1RlA(Vb=b~S*W<0YeY8;hFk<=+{^n?)N)*~`_i?IWVnr} zDZp*x9$oe4rRY%Qz^LM!$-*V0E`zLLS}L-8yLZ}0i`UwfSN+n?I^{IWE%(`)^&71a zRp}f$!zE^zrM3}Z-^(d@LzPJS17CXBJ9M&pvq49_Al1qbpRa5QS>Q}MmMt-(f( z7zz8N%jSRm8LFxn9;8P4_3vv}U3vk=PYqOV`{Jult&2#}M}ht^qDN*R+LZCk@}O(| z&3E5|N?B;_%^aTxwUoIan(?r+wcQ3_?8-_Ci1x{XfR=(fXW+6VMoP-PJ)D!Wlpb$` z1t=PaOG?N#7;Z%$K?390+f5ebW*8C;j1de&7Kp2sD0KhXVMg1c-rItjYjG)3;eElE za&7Cz&75=Gc5Yg1RYRtL{i|L?1dcOZuy6q)bO+-=VR^yi>TDW717ffBp`oxJu+bB* zKf_4iI67Xi(~#LnlG!o3iLacqQVHCeaQZ;1iSJ$Z;oBeBuP!)O$qled)Q&#p5HiEH z4$cmqXQ>uqU_Y=MO^k&M#L}y+aWn8^h|GwFz^+!CP7Nf=z4dixoI-m((2|Qji(Cxz zq>&}IY3XNHF{qNJxB@G~VTyJ;P*iE0U_y;FkP;-<;-?s$ba4#+9c)==pMCnd-F(&c z_R`{&Krl#o-~@|{N^C&?l+ByBfEpF}K6|G%Mnq4>`q_eo)TG!hIFJC&Z_Vm0+(RHg zGBMuhIA(sOZylIR*P;wW^VlOe^f%_dWEcGW=V+N_t&^D?UZQnTwK7qHjXW|=V58Y{ z4stZL@(F(05NX7}lR37Kd6tqT2wWmt;#{=O|NQ&C^yPHhtZ_5#mAP-*whdp}Kc9M! zy%4}*LeB+G&7ncmM@>Unq-MYbVEx6QpZmGDda>1@nscwYXU@PcZj_t@zSy~D(c^Pz zl5K8kvgrdxQp;+$5(GLwf9G{ra}@9UmOyQfpb*_-spcLVGIY8VpaE%}i|o*^or8SO z|FhSDe3u&l*g+4WpDJSvj9402dbz;CQxy64Vy4-wAE~DbRx?v(cYyeoo8QtwZx7+{2-hA>3k%%yKU&; zK{OM_(XuKf`$6`6M;#I*g%n*|X&6X8nG{hd?zV!8zVv`(ZN!vv=N{%z zbe1Bo--;blfg>%$Z}N(&F-S6=6vQV@x2;=NFkP{XSspqM&WG!86G@L4F~&xg_qW-{ z{(u@yBMyo>6uml;?oMDK@&q{rj!}$bg1bjn$KJr9_*m0T^i)I&`q`&YTs0LjK-Q*7 zj9+}U5QC4C5c7h!t0{3PtfGa8U9Mk6cA|O@n5eR&7}=z#yC9uxNZyGPRn+ff6s(0D zhf6^T4n^Yu#*7+m*px>~qT z^^gdPk=^lS%WT5r@%Gu5pWpzqHg3Wgn=xg)U2@^CTElt8B`h16Pco0)csWkwcK-Rj ze(iN2-{I{~!xqY5*a&xMyi=K1FbrFiqID9eN!WHa(Mkc8S_sACZX%&1eGwWgCAy}c zpQq?pSDyiR4L{={tdI$US@8Z&r}mt-&D$D?@W8e)`dttKigF9B)7^=2rhXv&n(OhSOsnWINYv|v zJ{yFh>7nkU<}o?fE;*b+FnI9mcKSHn)F&D{l2+Tf49Sy-&DwV)1zL*k;2-Uqw^>cR8DRtq6Cq;+ z#Dakoab#RT#pnZ}kANs!kWojA%lZ$W2;@Qsdw(1#9+X50LWGyK^jY7LV;z=LX))C0 zQk=b<0a=z9L(FRczEq8YKTtCac|npon8+06H0vG0wSkYuH%3~jr0pu}zLsIgMz_L^!AX&IkJ}9+rWLvmej!6cM^TZ|LYzb{J z>JLBignbCD`1vQFwwf*Lo#9>|FE|Y%1!@GM8}i(Iv~UF@0mj;Ej9Y${EG1c0Vh!xa z#FlN;Lb`c=$n?0@TxGaT348R8r|hEZud(0Vdnp2(Q5)X>V9FvyHUwBJR&KD{ZoS!F zd;J|7Iqhf&1mk!X@@>V^Cj0FDd+iUuzo}H~Qd?g;mGRR*?rCi~cj%b0dmV@tW$){| zS%El?LN$&gBTM0V@L)^w8jPI?6G=p(V~i+Sh;%@b6#6{$c1VI-tRUh$<{)%{cjuF( z0C{1Mlx}#T;L3@pmZA(beo;<&6Ckc)b;*8ZhlUC5edo()0&3dKCY~5s5USQJzd&}t> zrx7p1d8AkeFTs#xN!W?}4H-52+bgk4&MSbZAv>47Ej}O)&iP-~HgDc)=lAKh%ABPI02*z%4)z$0cRoUhOtG?1LKon zPKTf-7c;Wey{+P)m{;mk$f5Y^RpFcq(6Ff>8A-U9K|aEli5!J5#7N^q&@q+i^wQy+ z0iMV$2GYO~hUrpv@qkq$zxw)nZ`;9hj=+#;=68Y9^q1lRzv#jXVSUvj@xIe}NV_}Y z%yU=|br;>J5&f)e>}0YP*gN!?6fzJhpPEe1~WO=a2;$ZFpV3#P@ zrut0ZU=jLGKn&Ca@|c|tFo$t0B>E#_#fTK-Q6oZ-4?9V*y~n8!^(iX`2J5!f%jQ!& z_0o0SMSY}_b&1=SbzhKqC9Hp+0m!Z3v|!?R5iCrjuO;|p?4*5}ruZHXtJsQ4=$;?;EyZArw{jSz}d+W;uHvRCU zt%+iF9~vif`obW>xU1GIl0p}C9%*fbBF%I@!>-~!DZp26h9ARU$eK|0bsWF;phxf( zFr}RN`sH7+7G#=o+BA7ON&>t!+Pxhb@*uKDGAEc-8iO1x^bY3H&4qI1W*Ta1Z+^K@qxx`>3o^jzNnHzV!^NFRkIIBJJN>?U@3%`Xz8Hs#-VlCoi;1Q_YOE#>uBYtp<%^W`&I(L(;TepEsE=0y0vjdMl z-=2T{Ba7Frs9^qg9yOM3 zi?-sJ!ZqJd8tj6saTt@`g17(p4k6z8l_th5QTR=^+_mkE=m z+1i!MD0&uHV`D9n9$|(|0SB=b1w}Xr3ieAEe&U!rFO*U#46C1IFrDM&{l{2i!**+7 zW{H~Qh7BKJ3l^=g8Y0pp9c{fhAL&1($^6nd=wgOh0(7K4LPEv%@r2hobE zuU~4x*amz4t~=}(mp;vUQ^aPSGvMxdxkH#WLT!rkZ=%lBmwT{k)%zB0+JWPz4ns5G z%!9ACnvHeNese*4PLe6gfbM9hw?Tsj*^`eyYzt9Jb|v!ds2>ft!w)$ZV@rmLu@qIT z1>KT1^~%8Ba^(J@X$M%V7*JMTQ8|vJfqlTf!P#cvLnjypm6wYXrr$`;QJvmN7-|9D zuO>|H905d#W<0_edUG^G#6fv*AW;hBn)l+%rz;-kAEovXq$Z)cC~4|OVgxE%r012F zAF;#+_Mv(&1ljSGJ|3~Gq^qXPMNU-nINW5A8u%m$7&%;FYMSSvv9vDEp)jY&aV(CQ zCwX2__=zOk{zd3N~6-q#*hV6Ow&!=ij!Kgz14U@z{*iU9)_2e-!odba z4(XB}HNkdZ_)Bn4HG@#avRg=rMyf$yr@VME4@w55v{;tVlJVEmF9(TtAnrh2rzx~;3ZnOedC3f>rW zF#E+{eTCumS}ToXSsaXn{j`w9<$dXaDS_tN2xJst{X7(>gEpj^%m#<(;`$>UF(|<} zI1HZVZnzZ5(-+de|4d6&O}8QAPIP|8JZh(o)6 zar@b(?d^;&-ex~M`4n5XeWUe7K7MCiGi!-4XAepgG7yRrh?F}Goqh#0lo~QLduke> zS2a8`BT4!oU0v`woSs)}2`w~8slT|ouGS)4h?DZf2dd;@gbnWd035w%ag_zWjzcEXW|f-}?DwtNX9 zfn7FnJQ5joUG#3$F!U!#)CvpN`PWUCvI#FgM9jp)$Y&43&BkInfQ(c*%A1q%l zl@)wA+}*Dpw7?3%&NIEtdg0o9zA$S?y@NLh@{y!WFGYQcM&<$gbvsm98B8EMWI>{_ zd@DM52K#~gj)99nZiqs0&WCa3B16liPbeP&O5b|Pli+X&EOIDJcalkHPDpN$d(ORj z@#R;oonpVo^>+vi%)B7etVhay5ZRkWa&065LVI^H>c#mssLwdowE(zmkR5lyJ@(*V zE@YtC<2cu`*0v>Me}DKX8@2C&_D`5<|9X0^y|#6mJr8u5Lc?oA&N}-%^d$ia=ZkEP zq-7|Lll`F6Rhfr84(kACw*uANEvV(XiSDy1aCgFP<6cPgP|if1=u)O8n!*<;n4lvc z2A$Z3%53Cd$fNA-_dc-62OmSDA`lo~$b}T$XR=houz(<{B{9f=IXrdL}S6#sR2?j6tx6Qu;g`ikjG>G-mnH`^mbxiKZ~{ zk_6{j^U)U(0fP@HyaGOPD8NMQ8Y(5aX0(SQqh!$wP;?FR0H)y4^M``H1Yx;>7Ti4C zwFoB4P|_JlZwc0xhgWq2w;Jad9V$xfp8 zUYq+qFv~2PGI6pkV@|rn9&__5a1>!X;`n17p}(3P^lEU-5Cz)~io8^Qi1f;6-eNQ> z$7=&Z`r?auP64@ywr&-CnSxX2@GghC-S4nicz2#CQF9MjM~XkFlIS4T2?bDF{q+3_b3kB zc=%yQ*yn7kanmM~X;4LgdDf0&&a(bqV8)T-Mq)*&+py-jz%FmR`mw$I`~h4yy(d6T zF`P*+bJ?L?P&V*eX-PleHu_3%8X1N$xyjy2it<>SEY6DiLmfjUk6hM96ZleibJfKT zKk`VL5&Kzr-*P+ijI*sAN0$pB;P=1&4LW5z?Z)eG$5E2GVSH!qw;v;pbJ59KYWqx? zL`RI-Sr^dj0R$>Z|2&MZpZO*+iq%P|*cq*{dX+Hj3RWZ|LpvY$nmyOcltLg-FGk#r zlcC{;Ysda0<{9MwRLqcIp;UR()az8U^WwZEouijB<{%k@vIF%Rl`wE^!DmbC*H`__ zE<68HJMyG6fy**>!U0FaunOD2QB&;?H(Uux05Qn&3hn`L9rsJb1T~y0vG9<|q#+1I zsSAd1yi!wE7Ltc*u(aQ#8JCMA5s6{%YtJjN*MaPLUA~o{c43%!qKJgMoMIy3E)N$@ z00&V-AzA9TYETO>Pa{CYDcNoQ!~aK##(|2MuaJj9Y$xIl;!s4pOz}WEvouoh_<1Ph z6mp@yX7u3r_!}DJRM2$eTmZnpoTC^FY8AjK9&qf6!eX$741=UNE@3;U8cC9cNhf)L>-Inc z4u>+<4n&g$=IPtF($+15ZH0u1pG;{pMbc69BjnPIm%!jJrN~_b)D|OpcWOdJlP)lQ zvD$)s?WI`)LFt8A218193(YAZkD#b*WOExWk79j8O)XvMmDWn_!H&An-g)J9oRQg% z<{daVm#yNQ`&JF$z9K{k#dpn`uQ8rs8`Q7dMh+iucmMTHJOBI(h?J!fhEc_NP{e{t zU1Qr=A5mhVqhVOdw6Mq$i1gAoqx6zK1)MMB39>T@RjN2%fzoUy(+WIjwxwnbHKjUh z?np43g$y{*ZOz@=$ebW7kRhZ(WMAx|TKXsQU~6?oaa7E3kw9kOmq1(ZMluAbwwY{10-t_rB}wW< z$QU^6I(5URIEJPv3Z_%jt(r3<6!z5&sN`cF&5L*b=}}-ysM2Jn`DF2_`W<%ZZBIMT z?@!M=$tp+o$8q6!aX?x2qDTN4Ahj5UbInwNKxjUkMFtpI6DC#kmvXa|5c~vja#*zB ze=GLj|HOmrbs*p2T?4RT^Ao{?^%D})`Jr|Az=l;_SIuR#tp25Lx^BN z$TS>UCDCyNNF;}%veZjU>Edn!ev;^*i~56$ltxi-FA+P$eCq(`(qO6(jzTOQMO$J? zNuLU?E$KSh2u2_YYe`b;y*Qm5sG)A8MAXMoLN*WqhFZO5BXcGSZ2|MA#rvQC#mCMn zcG9#}Sz2yiFZh6Ftob(?&(@vaCz=jVRV)fKBDswBT zJLEAkcYqyo#PJA3R`Gyu;Q@}3Eisu80~l*>!qKRvgV5fX3ASeK8XGWXifvr6#FEIQ z9CzxO)Q;*gNF0@8Y#jvufY74-=$_Q?O ziB?ch!Ftp05Tg5?b;x+gz`_+acEV%|*7R^7Y*`GR9}KW=MBN*AQdp*mG7a5YgP**K zl_&~$Sbs7V>N-*P2UdgIJmj#WxX%?BU$PAv=|TzEM!)wH{#&@#Ylv_ zgJT|PPrh)!RTZwVoQj#&&J6k(&`WO?W?cX{?XDM)mf>PVRpmBjXnO3%y5nGh6!p9*sOLNLGp2L&fVU#2Ej7^H!fu>mpmjo4ojM(pZp zc8qTq5FmLNQu`<*FoR}$CxV)fJZ&#N@h`R|kSUpt2pw%?un+#@VY~MI-!r-xrya&H zlHK{}Q7VL$R?`@> zfn%o;V7P4R=tFT(I6Q)goDt*6dU2>gmj}!`#2SG+LqL)NKF>>5o&rjY6Nm-LLI8?+ z*w~=C9EUm?hsIZk(!nd;&98vpcuxvvw)eH?71--Q_Pj3N%1<#}2(-~<4O^sy#wr(( zk{^RD7EOxz4QeV3=OWwS>S1#WHwIaT0Tag1kQ6$Ah7Y;#7Nk8SDhqkpeG@0(}*ijw&nI9;enq16`z1J_`fc3S8sm zbMgr#LUeD75!Y)224N(NT50$MYP97xB3Me@1h!Ok858ozS}}bIgadudPH~_k?N-(p zpp#B?j}_q1Qq)E=oNq7AFhnrnR?q+w3tz}NYU%aaP>Y$|Ck9rOfmU9Pn#Fnau+|Cw z)(fKxm*Buh8Sa6TIsvcd2MAPvT>H>0c=6A#wC#v|_Nxfm#~&@$nb_#@qY-aR)Ae0s zfl{0&8?+}*=EJ!q2x>%ECJ}NnH4hm`2CPkW2p{hgvrvMSKGubu%l&3TAmxyt5I97V1Jk$}z5{u(lm3IV5AEP+19C~+>(9Lrgs3r#4-q)U2V6Ow&^SXRHKgH4{ zDWr!(G`TsHS00ii4?9t@I?Qu13f*K1Ido`ig9CFj?^;F;UJ6F19r#D1X?uaKL|g5K zBkv*ONI-uibO&l6tAUx40~8>!I_jy;!=Szn%E3g+)HE2iX^k zUQ?4@jE6F&{uB&H9*|ZMQF;=dV?Nk&6iJT($frv>MN%U^ir5*V)@~yEEU-icozT*C zO7OjAjPw%8aa0S#|Bn+fYd!+uF;F=6TH(m$FF90@6*vTi%U{=T`AQz~|M4g=!_Ujt9 z*f1s#CRxJ-|IP<$>jL-op)aK-#CZ$8v@@$tfG(P{aTAB3h#a+woN|}2R?l2nU{#%^D(v|$4UFSPcq20P<4NH!8vx$PtUT04?4{G?DYs34y11*NUh4I z9LWSfpM5cZv4g7|!9zePlQwxj);J>3!D5;z+vts{zm%$j4D z|NdH=Ib*8T?A+`OH+$!;xj?$e+ZXh)A^l+nQY(wX2IQvMwbx$FIwzTcS!IpPSV`a@ zih+cKg2p(0FA%1J6K5U`1@>O#bkYPw#2>sD@`iBEy{|p4z+MNk$7T6;ei#UaEf+Zx z&HGkowrGPSAx>kK7emkmvq?HbF*dw}-$G;-iB2MF40&ry9hrg(#R_*REYe->0s>2k zWr8v3pt!0mL}NsynwlYVAVDD+>9wi>B^Y~U02mv=Vf@c1gu49{>7fZLtItE0f-uw) zMA;z~oH>l(9zR)3ghDcJw5p0SYefD$AV8f6RSYH%1yVndi3cN?0+&w$%}CZew>qEf z1sH;YX_ThA0B}V>pSY;8 zlp?;DjMN|z-``qM`b}_b>gIO(sXt^~>tY)@Viat$^=M3m?DoI?6T!qbTS7+j=F87u zYN0gKCNB6&lLLDZZv5$Kr`iXfyl=m|@^<^@(@)}XUAB7j7NC$6b5L?=Y|M8s^9+vl zk$*mCQ)eGa@i`Y5QP?cBi?2g;-#;KP%8Bhv1B@iyR)x7(? z*Iu*n<7b$sC`K20u|+Y$9{LyBI>UC|)z>4}eigSfX5~1G}3ACJ1)3QC#j zP4pZ~_RuWZK|QF%?)%4I?e^PmW`d+By-;VlCnTvD&UU-}l56eEbNLmKkmHM-WxcK=b^^>R9D;9HLI-!>UJQt)K>8s8ZMTFoKRX>LG3DLUF~F8-l$de zFQx&vFBxa473KFKGwQV!K%kX47al*vMcde8Wc!dr1arB`-jdV@_rCVL0(%|Ep4a7D z`6=KB(I!|dqHr?ijt~+?I|Ia&z&RwDnwB8C*L-s?LU~Y#Bkd~wJ=K~Fp{g9&PLhp=$>^RQ2(oE5+~Tb4t`dK~@q0SI;H$QB#-~$I+eaB(vzU(Idyv zD^LR{lMg*vMO$Q9cu>_OIk0~juuUH{g&HWdHqaeDnRANS!mq!w@`3&A)i++ncrpZv z4*KeXGV5THUW9_I7bidYPM{)#Yl&@r7-bCtzNp*lfF3g zOKKAUpH0rtrUUn7V)5SCF6jvFQzu+gU87Op2^>$eig z13$ic;eIy##51gJ>*u!bFW1Z-DbRZ2~ZJ)Ld`{%j{$VgC}i%s%XJ zdjU9d)S#iL;-HD zJjaHQm|=c2+rD1@rIiyJ3?krGp~@XHLP2k{DnveEn{E5u!AWIb&>bHW?rm%|h>nX6lF4BFXrQQuMYY zC4x)@E(^E~Sc>Ak$4k0|<0EjxAW%G})-vmWefcaLP0I>rjzwDs=KzC7%p{Eh9W!~l zz5e>Ej0o-Tu!M^9@+tb}VAy~=Fct^Qn8;A6HmgK=Ho-acG&fp7$sp@n%@8S~!(Mk6 z4%A~`Em?ts6$C+zg(7SQXZiNrSBcQ+Qif%-b<<|f-R#|WU$L(+!aHdwljx+T_9bC1 zb+t4Rfg((D%gme28) zvz~E#Z{b?I`JSijgZt04R6E7sA79SBVz3y6<60c_#G!rdt@iEq>pQ--EAD=VY>wIh zPF_r>ho(%m)((b96`*O$eNPizOIJ#L6rqxQtK}Z8-LMu2hDJ<&UW;r?0Zw!KmQ8l{ z&(3G?A0%|9bKjJNlr5 z?cL|zU>$(?H}0O*Pmm5xop^o;kJIoR<1Q_uRQ&V{qWS&QEcwC zkLP`9&pi8-6%pWEee+cg{8xoyF=SuM!n|v$U1X^`zqRhHvs?c0nAPoEY5fT_9Q}4y zpND||xNXs*x9zce@3aHvoM`ixF0^Q4#9UC^d*~~gG=01s02TO3lm%uTeXx!08?a3{ z*S)VjufSdhvgdXAR(_gJH&IZHV(c;a7%dmkeH509=pfP`675ykwu@rAD+yLh!5|E7 zuOUTQ45yz0yk)Fqne zfG2Yae;fJruF_%LK3x*!Mmn5fuE!8mJ&9(xi-DPcpHm7Yr@V`o>3)zt35sBrGon6toC zwe59QR5H-|4;g0b*RMe`q|#xSZDJH`lJ0aj2CKLz7lu*B_M0$?`i~D5)^dKHVPMog zmQz&40&tErPkz08qpe-C7;(o^+d*`j@^(=qrB0xA3_+7_>~v}w!NM||Hhzp63cF5EH7jL>Jn1AK7W_EdrwWp{D6jm^c14zii41;+zB ziv2Kd`V8s?Mf8~D+r1AwNS4E1VLx_~y@?SO43Xi&(ravhA=li+CueL-*+_eH$y$5i zt!FLYwb@E4DuAMp3+bYc!QZ*$#JkvIunL#XpKpJt+fH!628C05(9s9jbyr&tGi3(vZU&xSh8 z=*DGr5m%&0M>=Np{DZFeVBR3M8K^6r{8 z7(o&w7v~X&x>?E`iZHz#8H`RE$fyIy;pX=#3g2Qd`GFXsM1BdnvI7{2B=r#wmR<_J z0glrv78ZXCW1fdh@EF=i#ppA2t6*7VWfcQp8__6P9JOjP4$(!|tXbjotSG}#6gz0h zXnIb1C=z4bX8_9cHC?dO{VO0eB;1DA;GIlWN zY6lKyoNdFMnJVEGJST&?EM%R#q8BVLSA z@ljiH%u%Wvsx!5ZLV@ozZDP3Pklmzn(uhjL8C_qS|O$Y#y~cA>zW0^V~0J+`%7>o|=P z)Rc$y9c=x_(Yw>M+5&?nSiGawCQPZa&lY}VL8NVhP{31djcgUch#{n5)b;JAa9)AK z4%xuIRknT2Yc^!ki8%ZWtgxURbMzrLf59S3SdwGU*wCS2Mk=o+Gm6=ynX{>X1j$-C zYZX&oIuIfS?uLTCrY=5y&mA;=wlQpKy-l1k-5#ON^V>h(V27W7g%$R^V}H5!*LL6I z@7T_rHFnk^6Yc7sy=z|*1mwK=z7^f_cdOxk?4Q$ZhwZno-SEf1;DADQ^btps>9rC) zsOKYKAI$y2zW(Z5Te6hd@$4Z57Nz+?98uEFyZ8co^vUO}YCTP)?Ca5^AeX=%EP^`T z(L-Gbdh#nzJZ+a;b%{gkj`g-%EB#0X1=R#iofP-;sU?-!^ciDuyncJ+{-t)=syl3B z(?4zUzLOlPa(M}bcAV0rekHb@@wLQI+z;pB`W7w2|2c=+>p;HCdj)M1^ob~nCrfvN zK&gW1dV-ZSg)mF86T7tw1_64KoC6k(Xd4)W?;~*S)%fHGwo+uQ>UR)!)0TBxh`@nc zfVi^Y+kWPLBq$K1RP&%nodQ0Q29;)Fdx?N)rNc0a|4uU%k!DACD<(}fbVk&YDJT+D zp}adv*ErqKl9Y&X?#@i{43g($7b=*$f!Rd-+{*k0*MK2FSTt*e%P@A-K)~hJu3qaD z;XSazG_+6Lq)Rw0#b6)+=0IZ6AI*4}(HK2Y=_{+9Pz4@2IPXRDj4} zpoo5wW-_-Pru3nN34Og>d(r=xoWMf%>* z0I~>lv~VD8Omz$<@-VzUd-v53tgJHER;+!~_CNSS$PTRxGTLHqEql*?%9{3Y4;mTs zD>daL#dYaI?K^#6oLSQLojT3_blcy!RvJ86OG$3b`*4#bZh>q-t<3Mi>2;`Ku7d26 zp;Kcg*+b7hZ++aw4q3qk5yC~YULqB?c4Y5cJ-~fc`{8t5C9A(>CrNcUPh$fe=W55ZqaGad+3n-QAraK|;_FAOxbs-F1?2_nDUOcZ!|&&9dQL z;M?6lQU#OluCA`Sb?&Wuk38o&GYF&u?*>{NicM1_yT5|l*EkvU@zk90kXTyHWP9Zm zH|ep5AICC|X8ZtcB{miS^Z}?(M_&BCS`S%9v99iVVy~OkHLU`jm<2yem{$cZEYB%o2nDlcfouZg&G!H;%E%H=r0|u9>E&%$qzlj6 zR|kwgQDl76i)%TDY_LFu59hG!AYgTc{eVaW`P~G!g{&;k!>y%OV>Y z0z0lp%~Gre=v6@I_~J5XFF6rRJQ1!NM=g(S+c!fkQmG~1FHn16o?UwOM8hWsgE&fn zT$5Bn>~U!J)wo{j3FI1j#{(_<#-&TO7kM1>zeZ~%HzpcbX8yKqs(>Id0lujUCc!um zVoM2FSE6-V&Wur9)ZzMjZ^{%h>4DpVN^4+2^Mcr^#~P_1Su#C6l|>Wx64qRZtniBb zQp(`Q64R(tW=uNQ*rW=Q<604CNMNzBV6=~bdo-@QSaK2g6%;2C9dO{$DuJPO+ZSJJ zJ1(b~R48T03+dE%6st}^t2g~X36qEwH-E-+swMVNUs0)EU3NpJ(zQ3uB2ZjAw0`DfeNhT88SXG27H4k804Dq> zO@8???LD{;uA>r^k4E;f@X!z5aHaOzcQl+`4O%ko8FFkoW09Ghn;=z82gR1DV-7l8 z9TJM=%llZBo7ZT;`t7>urfc=p?3q;WYo(XpdXEf!2on!FOE10hCOlRN+FFvQ*I)Y> zlFikcJ@I+xehxTrm_k?sr2Tgh0I@~DTNkbbE4KKef0_0Y|F^_CkHodOpdF)zzq0!;#q zO_-7b#Y&`dV_R5@zx-x}+PCkCb5*ic2} zCE(C!9Ra@Rtq1kQ;3qrTgXR}xQuN|dFikrIlWh#>5Y>UM!UC~u-w*_HP59-_c8EpO zHdjNUO_I2NJmhp36xi5VjmjeqcYzhEvLw8O1nPF+J~B6k)dlh5E=!?Kc?0gNMhZ81 z?4e_oO2UU8V#2De1O~|>RD&zYvfCXb7&v=Riv6A(5o&sXE+wv#1eTr!g#fe#X(JSI z+GFqic+Z0i-9!NGkybeEGG3Pd(aW zyaJFNdawW*Omjxl^kG3Ic@q_F`6YCm)$wSZWyz5^gpf%^F^eCS5|cAikd2>-rCCJ; zyt6V>foBpE=$x!Zvf*Qhh19Z8)^eYxo%R=fGxaqnNV0H4utX5;7KvBsoGC+N!t1R?uE=O~xnfbyZ9Mx7U=6pyWhSY7q5c;j$8D1|uala1S zbEG!l%DeH>Gc|VPVYI1C6?tXqvikv=_w6Uz?}S^_y?1wq)Xz{*KE^>is5Yv}843Zv z4y2MSn3L|HnCgnQgDwN<#&Q&8mBcs(L;`Ns1>dXBk$Y15Z$1CS zqa@aY^6J$Cb_3{7EJ#mZ7=@3Ym|BSbdGf;j>Gpctge1a$!x5kvjN zg5$@*#FUJS%Xyf{y2To?AaoEd*{B%|)nyBj(PvcR(kfWDi6lL=SCSUPSSXeeZ#-O9 z%G8Pr8L^_D2{nj2h;_h80<rjy| zg$|_~iD%KQtSe`JrL34V&`rf?`_PQA2v=01_4`3MF_A!|0oPU!<*i-=9JHK_d+6;+ zQ1fTksLB>+&|Oi)J?vVc>K#hT&1G_@lxs;Li^!1-s%I>}Q&G4n_dn!N-AK~mz&%E5 z_5(+&I;vD%_dQ$ww4QqFjb}*k!{x#PSy)u2${hNETZ{zTNvi+eJRTdEoO`A|nD`J%2?U!^ z*DPK9waz)`Ts`&LQshqE4iXM0FUP_xejQgE0qg3GI{BSvq~p%fVkYj>`j6A$myOq= zY3tRBVp3guHWI8pRM%AB?$mV2D~;hn5^N4oS@cJ%B-otJ;wrQ*joZ6>;v z9gPJgV+m2H_GqB+9g)9brn}YGh$erdf#OaL1ZhJMKpD|uJT)gQ>$VxIB0U3V5)Wtt z?lEI!O=g0&2_^xJ&kFeL*pbIXPQaYDnoB9j!jnkdjVd^?+Q4$UX7eVjoMg~oL{e}U zb?-ie?C&bI!wnY0glb8U73C!`)N+3;7G5Ti3NnV{`WbZpm7hG0)(+i1}J!NZ?+ynjO&2+X7opz&wuGJwVc;4`zWlqP{UXIk5cJX*)S2=2Fba zVNohrsjf6@+1mBmwy99BPP`LFTeC1JTGXRA^dPZXv3{k7k3JMDp+I$UcWQ8-E_(gm z+qCb%15`kOKAKpEA3?`}0IR4eC2*eXaD0WBEK{(m>H#-6?oAW`E75DN$g)D{Q!;P^ z;?|51h&E`mRVS>*Qp}*O_uqAkT6gN8fxGpm4-;7cadk!`4}XpxePNgrTgt}m6@|q) zh%&}mDIFLOIcnRj8)GewoFH@S|Gh;pvV~K^;jmvWfB>;g(QpmeDI24rPiQOg?M(Xuv%AKe>-o(wwG(f zyPxm8>mT3W@rGtOdw7ezx?vc?;AgU{HMKo^;%h4TAEJn`M9&rI_qist$oLK z`HL^U_}7->T3*jMB6Z2vdID1?@l#ESF$c2i8 zWIE_2dZo2NE5zMHrg$0k$PG2MWYtC{H*<4gp|EgRhPn@^BM4W0Gi#m>nQ#E-$zVd; zq>Wp)C?1#2jwmv`nY=5AuOw0X!+5buiu0Hxn2ca$P038ht;K{5dTa-E#jBaLqR{-Z zs9czgTWm|-HWngYH*X-w-%Pf88z${4r>2Duw_L1gzy!RNo}-$A^-kd`59UA}xh{z? z0k7SH=5EJOW87%k<2Y9Wi$o17b81#H)>RG+wri9L`>&07D}QTM@tpf4dE_6YQOs&P8g`tz_3ov_+&F#v*(XYC)5d6rL8HMK z%fw^>Y#(mFFs#1;Tx`)W)0P)iY2vG|>!2|MHU8vBvBrEb*_L3@bk_Q%KypFF4JCf_ z)+6_;@7{Z>bKMZ~Df*~1e=Sx}M_T)!Rxg>y!rH8>FS(3`J6(6y-^gT7aw9sir)i2( zPzE+{%u_!S>kLsCm6HspBty;TnD=4%$6>+ag ziIupZ;`QiLOMb8#Sg<2cJnyXQ=bUncN&!YJS<|dsT$OK5d<3hf6AA$0!O9I_H4PfE zw+8HU40JN|FT7|GfC!eg?lVdr?lXuoRalXv2`68uNzY%0W!a8#jjc^PswoU*d}-#M z4TEBQw|7S!0Zg}Ldv0(qeb=V714Qw$(3$JBv3adJp$v6s)mFDW@(K(GnJ6Gua1D!` zLT`Cn3TroSFHUGV$A9wm%rnn?2BzScjEszu6HYkcwV5+#j(qE_w~pEQearQ2@v!%H zy#4N@k3Kr^>8GDQYtEcG!)^bH6)Sq%Ys+zW+;PXXE$6fSpMU=Oes;_iS6p!~+ZDF& zmu~I?@=GQ5Z#=%NvKW(tB2Hx+iEl8F$&w}X%>>KC$iuv~Xq#hk5KYi5_?moZpLOL8 zP`$U(rVZs| zt;97<^G(3L6hlzGhK%uOwD*1X8l;)u0pA3tzh=o-WC4HA!jZ^1GkK^v3p6Hv@*0wv zK&DL!{Bx>_up`o;*98pKVQ)KX~gAdpkvuil`39Xe>{oS7;hE>PJ}fL2fZ z1sH5N7E(!aRE#pl;whE~5RQmnE%4bUha3KIth`8{9)*ELiGTqqQ&{ zBzRM?E}?sY-8mX~a{JsYGPZFKWi+XxsT`VmT&Cm=p|jBTS|wqcTZ(!N9 z!Ghw(cwprN%rdDcE!3iwYa!}P)&=LCsEMyXMFL<6mQ4=sM-~D4z-UI^fAuU){pb_< z+IH7_kKG4a%Pb>Ypk_T16O5xztYFvv5;1Re@aq}_W63M&r z$71&Um$qk~dFD*eYf*5yRbP4KmG_us@x>QkjO*5|+uD}*#~gFaKUgv`F)jW?c0LePW)(0s z@Q~q#z=V(BleZe@Rtq6WP}bN=ttLeRfxw35LI-t~NIWFW1ZN3&1~tir*su_uARlNQ zt4wFP9Uc~x0FW3wPtM}fg!K{+MMw=Aepy+v3O47H;8jGCA>1M5oHwfr!psA=W zi9jvB0@OtSlcgMv~K_ql&d;^LAP-bpnrHz+~rV@?W)d9``^Q+rV4` zkU&WR33!|Hu(~QNR z$h*adTWkZA@c5~*I}%plDuTYEYJ0si;d@zhwryAl6*#<4Ai?U0kA#5X<`M8{uG*ry z70a|}(HBscWNPW0FKI6^74lOGw_1@d0<(mGCG<} zD|ya(Vi_A)>{5UTuLky8p|)76MPI+8j%hg#t$!7klZO@G14J){ak42tp!=Ts0LFsJ zDz4w5!9#{?6BBrRG5`XCI=S73sc_>uTy)iXVbV=XdB>gb~TE#W&50b=el1#LsgAN^hD{qm`ykvyh z4LeJ-zMiQ=58aF6OsN`9Mz#-brNE*OwF;V(RZC`T+Lo2fI}3-4YT#T zxmt&5P(tQ&84qCR%xHZv?G4>@_aq*?WQFF<&{F6!ES6A93?RMJAj;W(p$W%5#)MF< z;o-G-lWH_f}4b@{0o~2jcE7I0=+w}eiZ|fU4mxQmswsZqpe6E(ydrn7R z`U-A4zbE8nUq3pc^O zyNQJdniJv}<_>xF(v| zQidV4?$VI{npzK;)tvuNC<0G(6^Uv+;k5>ijcOgs$`
s7<>zjD`RFW{W|O9z9m?e5DrmlkMC2 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 dPKe+W&?-aLYyMn(J@S zs7u@F^A{deDv5eeJ@P2XrZ)O&#$3(D*E4kNVCAna(XiuBl=tnA_4?Z{tHU7bZ!Gv$ zUtC|I{Z7A71^sr@b058?%*?jRfg-=}!6(29Fh}e1D>b`5UW->RhwZmYV}|UeiE9_a zkei|>o_qHf-61!mv`k_B;(vttU07qET6YIZj`_{=CjO z>kK{o**7`_+WRhmC7O2Yr7ItK0*H5O$Pe>1_>_}0;IAj+rrbmK+;yJbobipu?blP! zJ~tURU9!rsCYLW?she-RUB%p67^ryvV~^6LZL78awU_Jj_om4I!cc8#D$tZ!AM5B7 zP9g`Wn)nZHFe}gooVp&y=w3a0k?`24n_1+VSmeSmNnd#Cv5Lv2lmY;c(r}XQ{QM(G zF$ZZ!cgidfJj*A)CsZBQk-hu77RXObiS7dO6N34p?U8Yk`^kq3Z1&VQLEvQQ*kksmFjQwI{*`)w}>349m5g)+OK5Enm zay|eu5X{fa_3PjXf6*;>T&^)JZb?Z2&UK-_`EItBEM2TFWVDy(6#_9PMuo-o$gStW zBwMcZR+-v!ul=DQe@!X4{PLD>)q#hcq!*vwMq*waIS=dg_QaRfYxmyz?vsy*T~ugb zPpDKnW#}8&fPEm_>apt5dSvL9z0T2eDa{^w+en7m!7t zs70&SY4St2sdf7Z>%<8T|dtauUcGR}X327O@^gg?_Q}4ceDL=oO@vu?(TNh~3 z`%}rtC)>Xe#1%oZ1}vjnuD)512JQnw9uJ#tK4T01I1pcn*b1>M5W9`sO&dN$;pqym z)wa!AgIlT^_u3oJKd)KKm+HYM9@m>6Ox8)Kok-j#0GVY#2TT}_yR=EG*35%v%(B-3 z5}*ie+`7e`Cx2o>bOrMhg88HGt_9&^TM=0NOAk9kdkycaF5QRev`hY?0(|y(j9CmQ zr%K*NKa%qr@ncVUb2h=qT4nIyKXCt3J*i%o1w>GGOBn&37Xc)_DRz@owH~uhu z%yByEgoAN)OaytdhW$%fJVNc!TkoQXlo(bAjx%Ey|i{k5y9IeTxF#| zObyiq+iO-OHM5V_$dM=MixmV$#QZ>4nO8-7+4#$XyF{q z{&psT=6X<8WSg@<#-tO}2G)AfWq0fQ#q*&S=>`E}AL1qHxK+AqQ}tr4nlViypL$Af zzyFaQe)MIk^?8)txxKouAo;2FZq@#>bK0o5q(XZS8luOZf@YjNgv{18Ag8Jo+e}$v zte3`k%FL38nMPLlHh+pHoOGPNU%y?w`u29@ot4zA@e>ZmiXpcFH%mh7Q)EBHYUp0= zS@_mz)JT|jH*LY47$hmMQsc)TtR*W~YtG`C(4Axv2POtVEG3cRS}}1jAh*uc(BVfw zD_=nteHDp%D|GMy2WbAhl{)^oGt{P2Kiz--G+liC>&W+0YMs~VoQtke+=_V`d(sK? zCj^W0zjLz2E4hyV@*lD1UMw46m^{_ga`8KSQ-Mg9R&AX{x!2RRc=;^tK4f1#aQojh zbYLGXAx<=bd$Od%Mrw=n@7-4iP1sLuTeSk1QKCM3^w98{RAMN3`pe%g)8scN>$SZ1 zAfNa&DtXpLiJe7ydi8*Is%7N|~-GH`{U9Mq|-5x$~qWnScJr70f@& zwXgsiBD^t=KkNSMZ&3Qqhv3_VB@96o5H( z-kkU0QhHCHe>GS4KJ}6=J@;&~zuObFjHbvCHAX1O8bJ%J#@8QBZ4xi;fP_Gqo_**d zH1u;d;V-9XA~AsxqlZJB_@TP@AL3*uSJp34-~MgYIx|Nl`Gu;=FJUq~LPv~0O9S@U zOYgn)njXKmLdhcrI`NwH%xtHodOE@7jga5PCQ;}L!p0b=DH1YLsUuGe#xkfO_4E3Z zwQ$9^+GCG>fuhzsLFDA*Quc$|!mP5wNrNc{bd{wv&R<(4fE8p%iUoewvh#cI4wF-&~zoxu1RXB@6}J@(YH9WQ9}>NTK; zpwS1gP($!JEiFtPkP=*ie%wgeB)|o=c;!MJNnpE~Iw9$;x?wR;vxIsj6`;6s;UTMG z5wooAXbLwO@+(YXrSDfzO|MOsvRn7Sr3an<7wbs21O=xOGW=lthqnaXP$xd!068)eq0^%*ASMKR|ipcJ%JmLGk4N#3h6^{*VJyRR!bq<_Z?z zfXd^lwOfZiTDNJbgSy(jokUV9KK35agGFir7S*RJ2in^x*WC1S5X~1e4)IZ|R0&O?l`s*lq{O3$;rDwC7bosGV9TWNurtzA}(?zRgFxC_WGgz{(DRaXz+2kzq4v)|Jx-@KtL zlJn{zP4pVs5GH;yLDOJk0vfiD0!9Q?al^#o@@c>?{p!<~t9I)WJ$>IpI{(s3$#_mu zUjAZ@IP5$u3D7|CnP`z=2W~rQ>ZhP*Jo@ha*EOiu5M6)4(P*iuI{B1S$m`gwy~gbA z6;|3#b8~uZ^H!YSDD@ViBjfR5x6AvCcmGN*;Kh<`Ro3<(L{Wu!k~1HxqLi zIU-GSzMJLbQiNFqqVba()YqV!VHUAq1Q=+tUs)6evRo9)o=-*VT|-&mMsi;)hrw!g zR9cP%_ghDv2h%FG)X71CTrr7PODMDH+ww4~aiz4O#B6cZR`!#8$zmL&f|6xCGZm`3 zC{KHj-i!D~s*VQ<)yN|8`R6m8VO3RZbR=YDll^V8lC{q$J8DU&%mL7F;W<|@k&(MV zenUFh)a&uh=Nav>PM;8kwYKUvPE;1M=WbgO$0{X z6jk81i9uWU(ymQw)}z6*56Y4(EWFO0dtt$F4qF+q92!aV41;1@@cmk6akFgwoUHc5 z0RS%m2hL3QvnZ1T0+hE73v2U^%}lh3%G*%s5Jg&!ke}QaFR&(#r$F8rB0jTj)ohg) zu2wP@QTN{Mw2Xzy7==B+d=o5Lm40kMiTScyt_E%@c4Tb-1d(Ygs#~^#Pwk^mKO>ov zacOm3kVgfHmL77I!rXH-eS0WM0(KUEG1{;;4`rj9-udi9ELsu}S#)}KG27AIb|nFK z0oj#Q{sjB3zWU0O2vEG^!F6H}uDNh5*)EXKSs#8hTVqBauLc6KMrTq69Cy|iOUXL7 zdJws4+iySJa_du0Rk`Y_G97UEK3X`ZPGk2d2c^@Egfz;k;zp@2u2XXf=qfUQFFf}O z^&PaImamwlvExVRL@b^;-@K;%_HU+!NOvYflF=YjGzyjW)H26Y;c#5_9x$FD<^qiy ze}b}78%SPj3lb?>UGTFT4GJkI#4_U4sRy|apMT0^iAEb6Qhf#P6eem*f{P8L>+_F4 z)sP_vsR-C<4B6QheBZcwDcR~w#@u6L1#}`!l-k9bie0V8RE0?D zi;nlIm`Of?Nw*ox#b{+J>*ChFllJYX3pz%XY*-7bb+Gx)AGoUWP-NnKamz+hp*v+_%uzDhKoF^8_bLz5m z>g~jgtWm~0_3hH>>ew+&g$3KdSHT$tyto2oCgX-gq(PKH|y1Rd>3NCDgcvd=iac9fR0$aN!6XtopANq{OjMEetf_~w%Y z8G*tb5*BB{jD?W1Tc=(cGO(vstlFxmfxAP>Nx6aC4tnC52XL>!l0dFW73WTd*wa$s zjTM?Z&<3Eo)t8^9#QUCCbGvLcPoJV&AirF)WRa$SIg4>cT@X-(9u}%bN^&;i{xh1B zXyR@A?Q)o>+uT^NX7^|E_L%Eq!?P-&Y{o&i!wovQ9t2jT~l2{gp^Vb;$#4fc4vHQdb=ci z2Oo`J)GWE*?mVDaT7-8Y4k~%Cnr9FOqY=U~+vk21g`HoT%bxmxy1#h%TsZH18wn>D zIP`WbfHr#yIDB(FN<*AX`FnB{PzE7HTD>^dDB7w$+>a=(?yfs6cAwt@X{c$eO?U8p zRK)5pH^fQ*&B?UscrC(1nNc9)c01?ZWz=zrAJgs3=gRmFzKA`3ld*`n+bZEp^;|<7 zf%o_qZ^0Sfw`5|yGP-DYmn+9n8Nz3Qpe<&5-9z5CXjyf>q%R6d1TD|k_PTQg+Qd`baS@MQ?q_Thm#6h1mn&sz{TVpU z%%ZHgJY(vj0k+Sxzx96m65J6j{T*|q6}sF#rRJYU=k?AyK-cqz+o`*3cF3vjB~;Qp z4miB1Mz-i1>f)ff=QbJjbHrhP!73UrdMx-Q-b>`V&mxi>pERNL(YqJlk!Y|!S5rKv zW@is7jwsmih4=8=1);n!r%Q7Yo<87NGc>o&;pS6Sx6s7s17p12%=1Myto#DmK|)Wx zSuF&jfx}fhVw{e1BIK<~N%Q>`Epkz(3ZOQ{xoJ}kWaste-)Lzc6U-Dy(a!V{A`O_s zl4cfYvEQWULBMLoB4u0fb-9L9I@JD*yXSz@KL+~|^vXvQDRX?!@L<2;dH^BBxa+fg zKjab^!98gB;{)^S1U)yRI>_j(bHcs-P-2GN3W9vRNhMh~=>ofM4dH#`(;{GTU`xh* zm4aCR>2t>zCb>}e3R`6I2G$F5fiv87aq`ac?r)bND3E^;s^F#&VUD1LaEdXl7T=6* z^$J1nLq_XK*Vo_awG+NTv?*|5d_}U0*vec!9}1cIktsr(?;rOW|aWRG;CK{g~kALR!wEGsIeT&}m`j-%zXt zq4Fo%XmzR_o}yI})xMgM|)dRNy#TExxGvB2Hk z$3^Pj;KmfD$7)CqPdDIP<2^VU^(eWZbbnv4rSWC`gZKTv-NF6W9n{=V-hb~{(R_VG zXiKvq)gI@|^i7ZM@eI<9lf8q_=HC}YS^+(?4LOk~+K(H6@Yxlqm6-?OC-1a{1--_< zFUYYzglJ4)KURD6Pdl9c`V~4}sM1$gcM-juugH!Cc<#Z38-~Wuv77bet{C2}$%r9D4wNr*-f@EtGp`(6SP! z(b|dT1fh;()Ek~=B0CG{MnJeNryc8|5@b%30#*{kX#y^@Q4-{Q4D9Tcx6Q|GBysWa zswT_L5DGP5n?LJ4)PjxxgR4aYR2wZ$kD-<2=b)jL4X8J)!5mo2L{G{DoJ~2Y$K!939>M0ESB8 zd4i+m3S=+Flgt2_i<@z3x_tfK$2MT>2mXDWld+(BFaE~%cDF#J-tBw~3%cmCylFX8 ze&~ELCIR;9##37uboS>yy@wrxLl5tDxLr&&2yjg2>)CPTBFw6ysK9Y4@0fTqkCSt*LF_#z9N^KJX=ISt0M9C}>rR02sr<@>Wu zeSP#npQseX#KbgcD^ST@R}^8K z`*?s zn?WS|o6Uq}UhlhWIRaK)!IdLmTn4xt!OP2@=fk|qUyrRHn`yjvUV;Lz*Q;R)Yul`I znLax7bZ%iGt*orPF~jN#?M4o_R|R4Gqn~ZJWiW zva*tr5ZGD>YmX3g!J(kue1aCVH(3M=C*s_))DrxV6*+?+BSGPH@%+v z+wJ6hciIcKfnThjJMK-IQ)?A$ZJ8hfFiH3!hS%#x&i8_*Bc!1Ps}9af+ieJmhoKZ1 z=!9=btsr83W$(Ye&)iK0@>Z*j$Gw4(9i6|Cc#tY_n~>#QZ28(BeP8z{vAIVWd^K-L zH#t4sQ%~A_F0A#_IdAOYf0iYxWzI4g!d?{)qe4(Lh|gI+9k}HjiYS6^xpUOVuw*)8 zR=4Be;8(U6+wEo;)>{j1Bh& ztI`8|OIzDjcf0NU$vQ{DB5mlykBm2}s;+(xzS&9{bJp8RuJ#8lG}!6Qy4{zi0Bcpl zW2yC6kLGcTU<{ClNJ2uAV{N#%)GBbkiv4>dO|HRgEc@HlT#b!~(ArPxrP_vX=4<(J zkT=c)3o zDm{|9BG7Rh>#Va)gbl5|-NI^F4;Lt}^z*7*_K@At3PR za2(VU0+YB&13pi|eY`aS5&XoeL$A_M4CL^8_9>lQx@X@A0nhW!8m;HgQV`2ER5w|*ScHFI6DhI)azTaH0N6_8X<6}2(ft(<7 zPIV3>t-7GX&FbzjKz$&I)0&c9BPHYzn9AOL8}9cv+ag!1ffVFcy^s&4A$JLS-i;9q z&schA-K@qSHRejabbu&k>dubY#m}Cd_;Uo2-s01Z(b@eYA%q3m?3=IU;qk9(%mC*p zi|@kO(gGa z5-8qG1#A=ObfA#Om9{awZ~FLVJ40mnN{eJDnTsH+c2GNJ`aa%BbB(LcHIeGXR8LUG zJBXX z1I=&lOud`{jI$hVh8_Ydx!?)&`z3qy=WGzzetGke^Te#y)$yGLe$4MU>*W#r!2RzK z4JmL16u=PJ9&3Fq&_qrgHt8Iv{b|VH;Gh!A)x`I@d7wNe$gC2{*&DHy0wTABSz1`& z#Ix!xnQkvP9Q%m;1!8h~jVu6&r9}H~{y0dzGqu&W%%s7p;IuaczFs#1umONrfHfZW9#Ea-Lcl+0U(fP@_SVn{2>(CmYC`jXu5;yfBwPQW zYuy97)-Q_K>_5;F09{k!9?;dKxyL&3A9RJ_oJ5h`LTs}Bea+wO;(>(x#b@r>aBPLt zeGf0c|Ds5LF_?PR z$1{&^4xv$y5C2l9e+dw9qYoik14r_l9|G)cyJQqwZI55{12Pb+^+!j$SdTl^@ie zmpLEI+D!n6<G}as3Z?Ic$O9TvNbxs?gYZ@mW zaJ)T~#Ikp`(x_n3X+}p42EX5mU)Rz_s0aWq?c(BGKWyRaPT=3lA7pI7lbqGgz|q~Q zk{KzOjoRTIfb`f)0OFY{tEti1KKDwwdJVR#Hdk|te+`k5Brrtx>hRsA zuz#j1C(bpvWf2(_OZzKkS!t;Z&*)YCvUjtDo12>jAkk6}kc2504K95(FoL0?jm!hk zFp>p;%BX>r+YmC-U3T(8CoG^H|#2n-{;}t>PiLn=h0bH4-iU#7YMzrwH}U-S!vcupy$c{ z7BEK*mvuZ(yRo@>c*I9j`5bb|jAnkVqXYEN`wo&WUET4$Ss{My6YlMNJpT8D zML40|F@d1Dk}=_2t|QZBT9CZlT;&?BlO|vfdjRz|i`icW4nE~-%jL%C4ugEo-is;% z2Oc39K(~<19FcOX17aN!U0q!kNsnq7Ekh0Um|kz6E;By6tR$>3Da(cE2gD0t!^YqOd;X zK<=GyeBhq~K0dPsfvunyW%$T_ZOtbg&na&9^$@pfBfapY<>P@D!mxwt3=ZV++x~11 z=ZGt9bqa_po0&G^9-bhGxC6?V_Vi5G_vx#lxX|OCY5MR0lu1EB5^Ue~LEtmuKA z=H|aI*Bhny%odkd?^8*@Gep(p)7fDV)F%P5Qy^|IA_GmnB(EYqB8R={K zbgku#GiOe2-eZx?DPGWVxjn9?H*|d_ZFJ&nF~WhGxe*48o3{WZW!Bckgq%%CwbaYr9 z^*r&L>v1bo*C0cyj)G*$#J9%Nw1O_pah%EIx|VPrf3s@mr;rPN5{J>BY*LdA%{M(5 z*s#SGxATDceL$YtaR8un_U&?Mz4jg$9cJPYm#Ysp%_d+3)z*`N0(v80b0fPzhiN`c zTb5{BU<&_@aVyJ=-+VR?d7e(hdMl;20h*$e@pSrN_KFfWAIyPs2Oxr>IW5Av@gQP~KBm3MkmO-8c?DW?{pwU+dt*WZ3@o`#83u6s2A<8}K1>aOESffaWyfo-d zwlg1lHh9Wzv=|!o7#W3`=ZY&NbFLC!hkbpS>W#@0;-Lx}9OFiD#EjceV%2iusX=ej z>Q{MDKP=)bU!6`WzN@=A=+TyxzUc$BkBr+cH~)2X0T2nWEYemSqLRQ-ZOKLnC=X3^ z1|K1)1I`Zbj7G0VdJpdI^~4@|?+Kc09C)USba;duB$~E9Z3dwq(BBOZFc!$j8`f_82Ptp^amk9Q|(oGD2=+DA(B#yZkg-Mhxwmk_s zUwD%qLZ%vrUTf4^sL1)T&bti}{_AfGakE!ak#5FYY0w!kg0E85o zUV<^05fh`NzdUzZr(u6l*-H+~Co}Dz=;W zwPL%LAk)zaRVC+%Q3gIDq&J;lo`6tEo4;8{b2Pxa4x|{5g#W|YP6Xn8MF&d%=nt}} zb9L?5hJ=K0T4&(#)ObGfKmZ?@`n5t8yQ}4x<%V_33FHRi{>)4~jzh!F+Q{x-OUM+@ zq`yu0pz{f!_`b#Q;_%-PCqnbEAu#ke!2X@!z&trtMvBM&v&P3uA4+qWB09ci3@Ylc zJU=ATsd)Kl_IRk;y73XqvQ}C+aFDYt-Fcb9yI_$|C^Iq}b-;@kv=q((7$-v-_-PkF2Q%|Q&C~z z=bM<2->qH`{dX_>*Nri+7bpG~o(eGb3YrIO(iA^>`R}gy_p#hRRQN9CFYKZfZ7TS8 zW_?4XKIxDXbojWDj|vKEx``$c+D>=d_c@X}N|Hq?Z}CZ4Z$C^}HUT%3-EKboy53t( zD8c{!cBzMTT7jDiGu85zcl-Quynn* z4F*Egk{q&G!lqqY`muE7FK_?eIA>pJypF z!oQ-`y;~G2> z77?9qfyCB#H=Y{Ny*akI3c7M!Rh%BQYb`veDauMp`9KJ-?qGtAeDeVo`nithhwSg( z70DZFg^i+4n~G9~$%3mW{?~1eT0y~5@r4ovpIWbPy(|{*-@COuF3{^Rcx!qLILsv6 zgn~bHSXdR0&C5zVO-9i%^1oH+w_~udDvx4K?IQA%3YJrS&8|AN=~Tm)ssBsEN%k(B zM?!6ACX-xv@xJQ~O`h{+s@=kOXyE>=aW>Tg1Y60No>bY`IIkycQSIA1Ffp;^W=M#t zm3C=z%E#dK1r;aEk^9h4(i=f+#@{(R`BW;gr7F%Pj;;KslACozOcjQy9yiM{ z`=juXfGBhIxG7`ecV@nfBC2bnM<{XloBMs#5sIR^c}SK0#nz#UGTPs% zvVOG)XE0jU^V?fz%XwTL6#@I&iB4=Xqf}g+c7YHq&msdZzPADv%%|5YHJZ6^4LK+t z!AIw|ms3dQJeOW{hH>6{-&oMl(vELyGf|3PUd9D~7#Y5F3jUGPFvC+^UIo<^m-4%+ zm@h35BC=@NsyNGVsS^xUAOWq)N5a-ELO)g)9Mbd&`A072TSK_qJJ5<5%hggvz6l%8 zN@&26%}sy6K>66obG;tn(B70(&okahCOYeo{4Z%Z;nG9aR}!WHIWhsxWZ@1xOOV;> zO57mV4j9>8LV%N{Dg$jBauphTIuY-#@FvDi_F0Fa%BD&m0s1GwOKwbE5XbNd!-l0| zVUe~Txbq!oQ9{AHxh(iQ z3+zNWPrjvL<$dSxJXS9r}rmKq;NvPKp4jL>-Pl zM+L^5)VbwO5o=Q}x;{!uiiR3FVISKt{1Z7 zkUC-qcCk#HhLvK0BQpM~gpOKFMsxJyTu*K(q7cSctU1m` zmfTx(`Y|GSjv)k}T$hrS5l0Jgilq)$7LpRP*1@w5F3bvAJ}2G|>!VNkcm zv6r!KUxiE<{&**q>EOMcrqkC*A8cpQBz$}QQRwC_=62oB<`1mHF3_NP|hsBS=JP({V~TXxO|bbCdmEhA*2vmV}} z(uU8KWBmieGD=T-)WN!#O}itz`F(DJOEqR%{TbcaQtS9TcVON(A z@F85{>1ka+?ZHVo3<>(OA;*6nNqw=VQ_s+rUyv*-+WQL>I%!mz{k4}(7=7B_9(!HL zaF3SQwRD=99ym(NIwQV|8+}8LOrhi@4DT8H`}T9S4n-LOpDLIf0}_pRgsdm++1+|_$$gS|M!ix;Fl+_bd5C{=N)B~ zpyhLbxZXEnK1bgz&-2`?CB%oVD2faH?YT8#T@P|2p$pW*ZiOnMbv_mbU7+F@3RaNG z=GPi=1>SWIDdWvJ#-cKLq>l`~R@CY`l4zI2{H1AEiyl7|t06`Cb@G>$ev!Y~yw9mu z*}qt&a2_*ZlCpg`CHyv{?ecc?*JY3znnHguz605snMJXZs#kGE0;sN9;-)3^&QFZVuPrfjswl1tSYj& zDNA~qY7sl3jgtjNAgKgWkAKIzm){rELMe=d-WKN29h3nsAq`_1lF2$a8%C|nHU|&y zomW$4gloj<-uOF83=#t-5mI?`G*Q!JK`Ew}XX9mkWaI3+MO>)4qfKB-= zc%WDar!nS!QPbSoubYbPiTnl-trFzC62m=$UJ1!0P8a`q7viq(S|c4HRK9Db!EwF#fV%6E zMN12_?aP+B)h6-oU#u@6dP?BJ$apR9f>Bzr2jqQWH^pXZxTgcDm=XlI98 z3%q2JRL%|Jp+sdJ$Xk>i3@{pNEEphW6`%U;4)5m04dF0KpPz5id^!|)BDOlUU3W5s z+KETMSv0Q-O-paJE9NOn&c7^)r{{JqQ9L>6T`{;!lsU0a{-(b)h~M3WU*XIt-hSa0 z!tHqd-s}7l=KA&3hV+*|{xiDevx(|yKC6xNe7d-mx@UA^MYa-;$9_0lbR=pv=gFr* z^7wVN!Rs0k?@)56S#A1TF1C=k?c&t{h38C4{1ei z&=t{?+7vy+oSiVk$qD_^yI~duxHP=C(=x8;VcPbosG3TOZ(Y4fhF^yVLl>f>UeyyW5a`k2Tb%`m+L^*HIxkZRdjEV0l~i-GuI)K? zVp~5Z!eYN<`A)Uy8$(8op3^HWa+8B>@#X_Q9=*vB3^(X<5K>2HRE>f>jqBYE2&lgs z5g>WBkP-I$+{B|*;p|mbvh6`qvXD!Yq1#&*D~*s|;pAQF)-WXk#~{Nenu--VCJhZ?Oh4fxnUj=rBWv!wPlL zE}|0XCAvuB#n`2#2e^z3TF)$|cR*_7*6h+$uglB`P{?`V(A8nxjm?F4iO#@?sYC3= zP!3id$JMZ=n-K^%6n1mANh{5*P+UQ6h!-?=+M8ZnK;A6T_DK8#-ucYWC1Q>ZuG;-S zTD;44QE%Tt@x_Fk>l}_UZhJc$%G6tRRgC@lcQ;;fd5l=GXje_|_R7-KYSYO~GL8f> zGbR^ep&(;N&cAt6sI&cq%wdv-u=7)@r+N6P0aPE_h44Z29u4-OE9~FWWA1Q&S@vqw zhLO2G8Wk(8GD_^66TUIryGDbl6zEiW=?tBKHVL>1Zl`AIDi!4zMS9^j29q_VtVQ z6jiljW~;($^vYS(PN(+Ag1*+CuEmzMX5Hvhy!gAxk39-AGZi6qaeLK8dOP2rfBDoH zVfInC^1HDslal-Zy9tj?a=~nkV|U)#qV#D=Wy{zcXh52CKqj>4^Y33dvFei@5hNVy z6a|~-gS9phhL=b2A<+ammPhW|oTjZs$$-#?(>)Qt)tv!7*H}1`vVY*cA8USArU#dE zs2IB^p{nb+f;~pv%ST%;KbW9|oPMG^)f`<`eL4jx4CTTC8#0^mN)c4{5qs zOf{c39sMY;zfU?V^ORgcDfZPj6RTy_OqKHjMqw0xQnSQeL-y0LrmOtH$ zxfXLxVTHS*xTTt=`rc>L+rb&WqVg&gBSP+$dma>Kca^=_>S8$_lSSxH?U&9}=xfLi z1w4NV-+D5#z024Ok=_6Wi{1nmqOo-KW)vBV9u+i_)4cP2`C0F=g@QtnysOZB3xo9G z_`KPg^zrUaO!)K}UP!IUrG1%Z+ZO^o@23OCvC|yhO-_foFLEiitcG>TRj|pVNxXB{GvdK9p19j+P*WKLCL6;cXt;yAC*vWrPIX7lvB1Y%VSiEzs|tGtzkXy zG7e{LDg3IctS6PaS7-An>G?_+-CB>(oVq2?M;^wA9>-^XiXNtJX zT(#CS-zxkDMj=~-`|R&gg+5Kkmulw?Yw_CMt2-Spe-zRzu%wNA1HxH4VmzY$#vb?~ zm3W32j{jLvl6sUf-6qyXi4?x1sy?D~dB{sqTw`0^bLdgU;UJ(tD+E9mWi{q6_|D`A4B_?;?UOSv;#^LC5*g%l{HF2cnn|}5ykKD_3 zjZziW0-bvq5aK*7guPs*QZiE{JM&nxN1dfyG=At~5&ha`80HxY90L=~W3`<9 zW+ZBnUwlT_w!Dr77GO878uShcLo*3d%#9)&$=9BaLrOweG?uzP0A4Ixk9en;;dv3I z>vc-TlHM44A4Z3SQ)bAy#r`HI=@p$1`&0U22_OxY|FVXY>+6cmJAEX^3i`>uMX2dQ zf!V4of!RtNv`?#}|i|)Li=}dz*e|LyA6+6XjAl4WqFqLKdtk|89!3 z9Uk!vMBSss9JO_z`VfhpdiES0HzD>nr+l81B@aDa0UlP)2*Q>o#E~E#|0SQ4v8-@P?hsq?+GjnRNS_Fi_1e!bv+i%QkM6$Uz_X- zLrEjwac9S7!M~Hyjkg~?LpS;P?58=puwZGvjKmab93fssHjCxSS$TBe=lu8(SIK0Nrk|?%`%h=T46nyy)qhnkch2a6(c3W{ zivNt1WK;MH6Zls9(09>;e`6=RGhjc}PUzXAtOYEQ7kLc|6eGF;1#OZkXVXRQ5ck^O zeK+pnc@EfH8r*!zS+9^W@`9Q>wQ_oWm%``d zTc@cSxn%_y)?y8rKhwtJvyNITyY~`bk&6R5a6XI`Z@0Yk!+F}YGYC4r*dRFu3ix@o z*GuJbr~K6BDv=xY-W$|gvLQKbp)Gt&L=bC3H;+sCJM-mwU5Lr>ttusMZ%;C9`76J( z0og}#>|F7vtj<3~IK8bbf9gkzuhlSsyKY+CV6-YDURoaEeBzQx?Xf3!E>HOJw%YcH z8862NM=ghTyyRQ%<`sUCid7OnWm4kqHoibzvTMfo!9V3}h;ke7y3nF_mi4VvP}0jg z`<#7NH~B({F((Dj$kl$hP;lLmiKz z+ata&TGBI?RtN*lN~>@2Z?$p@6X{jXQ~ilhhY7Lp-HN+HjyK)M`h zr8pft)7PzLOpgq`ndeD`}C@@?Q_Ef+ZpPNxYNM|wN@=ts;%Y29He(ba=UP`^i&<{Vh zYYXM?=h-S52BBm0aR~`#gW^4A(}cH_$*Flo`1>oZr=|Xyweu3@1JCTVma?E zNj(qh3Mc0N;38z3!ULKu#3Gxw9Gqq$j3I2d+VV9oEP;p!vyXAVCk<*q+%Y})e!$U@ zuvQ?PD)R~c+vQw%V+FBKk*2Zp;`!*xq@`)YE&*3#)zr9S7y^<<@s zPXPgs!2+|M3Q}sm<^(>A3h&Adb-=|0`q`W5GNuoYX{eA&^B#-M#!7NowLt0F^Pw-t z%-frjUSSVMY<5y+s|@2wP>#;|Gpc|zWNY`DioOUk&8nnnUxiXH zITKnY-A7?w)=`#c5nkT)>y(~}2^GUBZGf#t(5@Zq3nkQMqNVlo2z#tMo@scdT}Ked z0Cr91cizWbYSHvK_KG!n?e=YVk}KZg{;W0}=>ScoFq>IZi>E^A9xIkKwoF`v?Om@D z99brx{39K4gE~>VWX;#urmvX}`X{GnfejVI#*|+57%c)(Ig5dzR2j5`r_;$DCl~v# zYDafY`$|MX-e*xbKNT;JCJ1&=##ll_>Gh>jF=}y>xO3ELx|3^SF$8JQpYmaKW^pdv zPQT9|upEjRzJDLzmdvgN3;%c%fmWz>{4KQLS6k|xknSAE6kS)bON6i{k7<^1bmp%} zW|ArWUA#{wYsz8Y%>RH!V=^zy(t32cbbQ<*&1K1-(7ud~>tuu4ua;gn#rMuXDh34O7rfIo z&MMrjptc`V&ZCdM-iH$+*D&>o#P3)VXEQX$dmi+@urRagYB#UIEU9}0O)fg#u9)yP zf-1*tcEm=fL`pt+X0}v#>NABzg_AOUC@)qZRmL!zYd@k8Fcu@u;lZV<^&+PeLoDQN zEN9)iYu)!Z{1QfAxqJMTzi_xaN`{?HTPxbYNXzCLbdXWPvc%f=cBnsKBd3_)s3hSF1B_UHDq_7MnC|jR zo&D4?DgVW0qXT904!y`$-|O5O`)p=>49zMcdOCz``c;wYhtKlrD#dY3@x>fq<^E4M z#7snig5b)R(#5Fwk`+&P!Th98@!89Y^g|`^UgV+g{Wd+Cid@RM7=h`TgTbL{_KM-2 zrwYVVISEETJozn~>X=hkuA4-`$NdWp~>&E4KaCM?{I{AWZMEte_N47-MdkVxbj$^ z@b-b+^5d-Di~gET{++@we$P8sYZiKCS637Vg={INff@_xHk1SWZti;exP=Hh4#8}c6IjO#N*e5>Z zH9`6#pJDU@k~lCpO1BmpKBRa#MUe4Ab}kpWH)5kvU;I&>X;r_>L7?CDBd?lDp@a!5=Dts;qQC|tcMgeEA&pI7t-+vGw|E>q zXR)^Mij>|cy_&mfHejhX zCB&GsM~d-J;l53idJa?&H*Y(zYl$KoRgpaS>a;hlP_QMqF5&`1=z0S=`R0-tBix;) zBj6PUHV;W2H-AsgMJ%qEVslA8wCpoqNW4hlaR@6^PLoc@^r9&7_`%4N6 z^owz>jS(Ujg!+t@HTFxI`XAAxg3&DRmi(Ls^jJkDCC3(?Iyk~wp?k0j@PrUFwR~Mp zPze@FlFyTr!(HZ?a|_-7gk;uI-gb|KV_46}R;#MNG;xxSB7dj(c;9TMtU1~~#<6{D zBS{bzTK6)kka<+1sDHeGLXM74==tWti!<>Jzu#gb18p#h$1SDbwZqs3>`hyG8i4>O z4b3V?G!$djKpOKw=ab7I$-T+iW_;FXi~`hZLi2S~w75OrTQK!+b|pZKC|F0w8?09I zHF%>%dZz1e*+*@PnhHh73CvS1MaM|1<`H%;%0NLTUB^2pq50|);N&ciV~xrwEY)){J9{Q8Pxgp|R>Q+*0>r>Q*N$Dn@4o;(`zZR^pA z=M`=FMH${ht@zWF*I92N25{t>z(XC&Fg=_{O|p2(j7s8wR}SZVA=E^=(^ zPwQ8PgzkXG+KL1_1EDhD#AZ^3@K|%1LA{&Kmr&W?gO#FLgUn<&jnW0Nvdvz4Q#^NA z_>C(2KAa4%*}0WiiYfL}>L0;f^7JWj!F3*W7Id7zxg8ppK{Pt{_ef7jjNH4)8PoW6Ol#)uhEfMx_$;}2-D9wV$C>u)dfRh+xA zG}E%D&%{jOL1sbT^3NkP!e)YM;gu>YQY%O&9=zq-bj0jD5rWrL*TViNxGt@LN zJaQ;Oe!EG%SHHazwKvgRfpSTCi{hZ=z2xrp^Yz8vn8G>1TLp|6twtLbsV31t`$->p zP-5Kx`_B)bT>3zdig_(Y$KKxxPYR=w7LPTqJC0gI8Gfhamau{~34|Tff?pl&nqr0QlZ8QqQ#i!Cd9xN@eZ`#?QJm2jOm-&wrp2uZ&6teF~vreqU|Rg zVp?WSDxhp%SsUlDOZ~dv4bA@($ZBzQVJ?`Fci|>))B{wO@;E9J3*pr_o7|ftSTY=X z*)5%^$M&;?c#kc<-zn#q8FlEjg7`NvU%xv1mkLa@;9RVn*GdE#?!^`^Rx?8N%cZd6 z7SUF_E?oRrdR9>NIENy)MTHR8F>LNu|E%ECY4+t+vr;S)Gb@p)B=V@55etg8U;xPv z44tM8oNf%usj9sB*5yZD*WISS-2H#H#}yHN2ujgw_;#~r@L4c@Olza}g0jQ#Kzne8 zS;1ba_-e_8LO<>~cc!V&^iLkmTJLzOcc{sU9#-cDPe{(=n}I+RAixSUGJ}Z$3REff zd5z{O>tHC25&KIlYFv<;VAL6x>pZoVeI4m(*C5rLxk$^Y|qR!}`Exk>KiZ zQfFH6_O^KkGt@MP?lMMJNN!3+iz>yETObzym0-93;O}Wz9CVEI@@FR#xu5q(<;=E3 zZLDmD_&3Cl++U_d7Qb83e!g9yVEG!=a;8j83-|m||H@SE9*2L_cYUs|nHw4HUV1kC z&SE~Xf??FVyzA^IN3?t@K8vEZNu}oc%LwYE7V_hK*>IE>As>l8OND-Hq?14{R68H9 z)jXZ!itEUqh+2s3yn3fhcj)vZ-REnIAM)NV)a>tx}@T+zL3M9 zAMp}Nw<}Zsnu=wte?qHi^B4MXN~gZzA8y4#-K3jVgBIP$NrjqZd0`7iiJzsdG~(7y zgZ1tbKH`EY<;a|mi%TjzKKC9i>#fT*ia~XKT1Lp56KLDG(MIXenwfmvABCM+>Eo4Db0EKJDkUtI1_rEUbMK{l$OlDs5Dl)?G#X(?_XpX7ngE+_dP@ zp?v1hA0NbwhHhVz&q_^Nyb}K`CE0fOi7J^yDAbQS_D^w|>hHQ~RO*$n(V2aJ0^L82 zy%f36p~CVyLjCUWL$yuOC}ozY;6sv0p)!&eiHfmp_H?Fi2xxQc6Jv;rll$Q2(^uo> zgbpk4b&lHTWtw;b#*Ey!yot846bjjCYB`ZC8#4aAqy!VT=^)ZSGg`lA_1p#z=M`!+ ziPCx67l@r)3#PH2Y}bK~r_SW+OWZmw!Ymdwt?k_{#sT$FLswtRsCpbS8VWv~GPdZC z^a%=Y-WHhVBG+2JfuhF$>DvY2s_BmsyUxiwmx zte7m9kQ;uh9{N~0hnVVZnL~52HG9-Iad31!wbq$}=BXeJY`}3?EMZ@iaPF)QSHIyz z+m$%=ls|LgeVXfqWYbCylP%RG1HKz}pj(;Fad>jes#jSFs~T#y(NqZ!9~!KP!8{lg zOpn=QcD%=2yLm6WRB0SH@HAREY}^~(ov^bHD%edqHr)*&SXMOQ@1La=x)(X^;H))S zG`ZXr`Ap(wLMsf5mQsyc(UIlg9UJ{ZICJ>1vY1Ap6`e4;04;IN9i!Da!(fBk^5V$v z@-!OrJ*H(X*6oJC+g4>icWgK;#xkGh(MKx&8$!Kfuk)lf!y)dn(TU=w-M!<((jYaV zT=><3gi*g-BKx+$uWG9<*|FjTjjLYCCSe}jTVe}Q-#0hEHNEHMS*CJ zrSPo9ezsfDgD{rF{)pmy_H)vt=M|cQMM88=r$ney$$_@4xXo9U-3vQGWOYSb;Ir~oMvD1Au zQiiC0|LwO<-+i-kzb>_6`uQQBDIjv;BakaH_9l|wuq!+#Afo5oeBk8?IrfqxPI9L! zZy08uspO1nn9=7d9vc`+XcR3jY@Yax!*~DMaBZqj4dQ$A>6?lk_7G$JM*>WUR|B~Z zoJHlantFZJdw=PfkIT~0^e8_FSa(Zegr|OGbzWX^CRkivS-)q=#nx+q_#zb}O*mi>P8nHvl%Uf?P@dl#69THzDeG~YRP*O}mNvhb2Iiy6TBK$J_*yFe?%TIi_bdYt@;1!mFTx>`EGD3#c`&2mn94R&ajg-TPOTJIp zr5N74$E?2bQ*=jo8EvEm8=q`m!tsDB(H<|U;iweg+!pQ6Bed@j8?yxet ziyOeQO`YBu38Wa~-cBp{5PNp8W0n00J%`p)}69QNQD=GU|ksr`1>S9y;> zx=#$+qg6tJzUS`5j0$h_#wBWv6?Zr5XlnSGCNI1=*``Z(iFStUYtWhBoeHEYOUW>m zT|2WUx}0qEhq*fq1P=5`PSz&q6o#*iT1qPFg57x<-+D>b$f9cC*q(u=ty#ydaLZKm zhaQiuz@MTMXceS7TXVawycZm^tg#)@)Tx@WX|g~-$Ua9BMfyX2sz-jAz_rd~Q2Hn| z|MTT|nKYf#(Nc^sHnOC7o+^FkK5vDJ7hbKgexOCZ!xG$;V~mmtYXgfA8E-MKGDjTQ zExE*Pf7*OjRH87lZ*(;a*YRc*2F^yGdJ0 zi`9$*KYiJH?ZD6r16d3N(ik7o8JFFn4_|*-869fvSzpYryh;GCb)v6=s+E`kv zQW|pkxfg4{y~ZgsqaCol#d_(3MdV<8s?WZit_N?pT-RNBoBsCH+nT%SdtG|c=@@s< z=sjSa{y>8|w9e7d^Gxmoc*pO$Rdr18T?>Yf|#)XA4z1Zl($9d*ow%pYEzf5&rr{>BS* z3J|O-?|4vUL_x66h}MSn7~?KJ4k#$|a4u1Z-G}UsAp$|i;ziVUNmFrkCC9wPd==If zSmb=<8pYGLYcUl2^zE8MYJ(%APyap`p|gQ%dR3Q{ zu2aXh#pAR?h19$0MExdrb0zR|B;Xn#KSxULF|GvuU=mopdZqHc)T~JGgC&o_a~33- zm_$iavVbmup0TV#AS6JcfRUItJ%|DnB+OrgQXC<9){mFou*Yp-oax@{Agznd9SE~k=8O#9%!r4HEjEso74^bpkN64W- zc?f#a^zrg?r$Av0ieovEm^Eej`u^ERi4qtKPLq~=T23NoBc9nBq9YCDet;E6VYPY% zW==Fw#P5h(uOT-ALm`QKA;J(2LwA~+pp)*n7A1{5fMkxx5GX{!+KAV0?$S~)+6j)Q zb;H+-LxW$Uktp4w&BS1fg2CB%hqAnJ*94A2I$bE zCg_c&8_oBOK@ic#eCl!BHC1`xGI`s?DW4zJ))c8`b&00kaj()6(^2|*lgC5yaZ*R^ zIjE2F${Td-N%v6mzL$1@7!e9|r5+K^+H;)t*BJXx1nSX`=!D}azh+G|to z_ln6*))s0hyoRDR2{M4a_8g~cufNHOgjF!W?w__mGrs;7;|7DZ0jg^92I`@#4#z=N zOb*ccs6rKW$W$8F_%6SkqIm)JXWW!kdvwn&SK{@L!HDpp+y^w`!gKW5N1p;wOm!j( zmLC+fv4C>;Y0U~Ei;GDvCkhEftPBIEio%vr&1Fi?h}F#xJ)-o{qg4TMz++R_YhZ>~ z2af8jQM(P)(c9PPl~*=OiQH33P&;73iosL<@sc%)%}mu34?iH^;PIH99kiC`W=+1d zZfnpnVDs~4YG2?x#XO(+^#5P)yic7DI#jzIdxVxAG!E+9tw8K>+#OdU8;i)K1jLbDlD5ZQx$<$+E84q^7ZSqH5`Le zVF&ci(Xf@psW{D}37^i=1LvQnwVrL7yrK}Rs!G?tFnrq0FaB|@6ogK<);=~HH@x-v}EfLta>F`Ani90N8MI_MJmyxvcA0_M1Q z$OHDi;6@$!w?{R1b)N2ga@22;FXL)<{S4B)mo%+BdYEC8Bg=khOw9xrb0te~) zr9{B`kJ%mOw`D|H(v^_gN~<>jXQUQT6Fg$Y#f1t1S$dzy#~nR;=(bm0(QS8KtHWEg2vY;53FbFr_Uj5u+g2P2w|_cCZ~WzW-3l|?voGAO@#h_`_dcAg(|E>WVliAW zgcsfYG!fJ1bUTcCHO#*$T|27`n%!k97wXV4dunuMwgN*2>+GwZ(!A+kVcgaM*$S%= zsM$9!zX*g45|K0_c^NTE2lCZaw2nFC2PXlKoV&Ra_?HrJ4Um5+BKH7S0)IRSfQV<| z1w4UL<3XACpl4^}^(nEfPRbCELExHa`$u-sF zL#$beM<3rJ@Bm1dP*+HxZ6@&%>PN${{2F4h7Vzr6zzuVQ315 zO`IK$2N~*G6u>eRX-n&f!{DhSy5Zz_aE>ydC|0b_Dp*HhAl2gajYT03{vBS1Rf6}| zsygFU1xrq@ENnwum&D=N_*fRxXcA6MJ^f*8G=(3^&1Mpa8@a!_+9Cz>H$btQ2($&5 z8vhx)6m(PO#*s^eT%)wvGEshZ?= zDjkzdj~5sNERl$mL0TH{l0S0)D-Oh{x~9@$9x@qI5m`IH{Rc5N4YM5tvO^+?Qq0&v z<+01eB@=~OQLGnNf2I4NPYyO$(l34mP+USNh;fNP+ek}qLY7e^`^NH}7dT4^Fqe0~ zSVm$qUH<%Cz}=vt4In$LOusJ&s9zmXFN&m9VL-vi^YRnVXu#l+I^yVKRKH>pMoqCU z1d11pLL0ewjB~#;7OdBCe>qA)pm?@fP_CxBN~`%>yLN@9OqmRELJi*lW@6wNvsHZ^ zeZXk8dJx7u7J|Jcg{X+SiK<-PDy7n8d>n@!{ zUc+@nkE$7?UaeVKq}(2(b@m01=yP(A)^7Wb!glmuSx_T(-xF9Fqz)XH(5ekXtcm(0 zu@2m)35C}~O_3h#*luX@Lk%G}q+BeKb zehT_|xQ}KZN;3v~b5ki)xIi!CMs8h9HSjJx{!|aCYZRL2r2pX z%5Imb0}mNPq_RM`930uT$|7P?u?E;B$ zTN=?nS6^?c)Z~{IDLQ{1Q9@vbnO>cI`YEa|*dQ9AXMlXb|UC&N5e3xzXLMe?l(ZUe6kDIT`JrkW;Wif}hq0zXRv zOy%z8O2C!CpG^YA`T0p+43J&4gywuh3<7qUC#smx$GX^{;2F7M%n;8!V zMY2P2BSrW>P_wWZsPm=bqX62? zdQr^7SX&0`iKd`n6fifhFU~Q>JQy5yj8%*`9^3#FPf;kN0SfS04og)KBZ$+5xj%Zz zI)b)xD8^QRwl`oL#h@63VGpwU9aiWt2BsbBPcuI3)y^AFE{tupwWbgnixHoZahNun zkrRkYrS?l(s)ILb<%V^P0nUkW3Jm})9-vm-pT$Nf7lV)e?S)% z0E`FtM-7j9r@f>k(M$*eYz)v3R{z41_pOuh1tWjPPb|skj9rsW1Vz#MAq;UrG{&Pb zqWPjy6tMAw@#Hg^z#QfCw^tA)pWdQvRTv|Hy)fb|S0QW)Byvo*%&iwjRZ@oH`btIkd1vr5#WpXOKfxr91ArR7V_klID`@ux$u%p^YU9 z5M{7x;tg1|ewfFspkR67CdU9TMJYE~*)w2_WLU40it34Mq*2=@3u@gMp2w{0Y#6+VP$g1CFe;7b50$wALyIvH zp+=35V?0C)D}d%4e&_@sX50tQgoj8_8uQHRs!DtW++S@Cso+2-nP;+EXF}x^rSrLAi&y68K|D0EGwmfEPtQ zM1c+`Xu#rBRZ*(=#CWG5UXTcd(ZhOBgbkBy3zC<`-Ih`;1Qs(2{Hcb85XBeeJ{tH> z7zNf8JTH(Q)+m^VP-Iy6?fm9Rw$Mg|h14P%e9aQbGKf-cbr|eByN;v$qwEAxWYFW; zSYT1?8mVUx1RLhTkny8jTH$MhsrYG=De|`Hn{i@wDnk5O1R;bHX$pY{<;So#&Gs3^ z04Lu7chU)ERQ07sP%pmgueTwBACJ!&leqwSe?WuO6N`9*Y62-a9 zu)&B362Yh?qF@G<#TxuTh-%D>%`x#%;zoe5HKHs8oAHWcT$nM@#Ba^WL0s4uaq8T& z3lO<=e^>TVR8T-n7G_);bC$igzDvP#9Yob0RlCO088EZ*&YFlqiy;P2mbLCPD_+Lt;@FOVQL@vAPUlu=$pwkbqoX zdge{NH1R|2F?_r#HblU*1M2~9vVPWEdThoAdH`~S7!0qDnJ9(iAK7MgIIuVz2BCVq z&D;h`IR+8KD+=#@C=BBeMclSH!5L@aU?MD9j2R#{A;u!Ng>hxRU|>BkujOQ9 z>%Iry1SYl(s^#5*&8_4z+W|`Ce&VU*o`8`E$`K_PqtR}}9s(Lg^SF+U zH4Iz~(+C$f+1c~qR~qePMAermseLx%D^5{EC#cKm?R4p}d#SptL6!8Oo$vk0Q?#6% zr7VE2|bo>3^l6LsyCe^uXshfuR5N;yfG`#UPtf8-d=`RXgikz-Lg zbA-u;Vmm}ki8eB(&2eG`09J$Mld02C@`D&X@ffZlRWP50F%YA}C3yB@fIbCu*VAw6 z^y7}upgoVJvUdr68e$IQ8S%Bz2X8;G><+-Hmd+$UiZR7q*?hHa=GR(;;b6~#!JmRS z1`-%MR?N{yv^EAOJ)g5}pmGZt(3iDaZmtA=rUYCAvJ%7~>FMQ|0~MieNP84sA{DCj2} zS%_?PNlHus+m3Q>@D!j1(RkG@DqtR2E1u=SlbQtFCyGV1-aL%JI->EE#zLj)_XCvx zYsJ!vLXBcW;k_EzfMOiwALR$wj}NcE4<#jlR~5|#Mx!PSpc-ef4YIJsPz5*;A5k|F zgY&m;XVIpzFBGK)Me?Ae*TTdVLeci4Oa*{;8Fi_7k`1~N&w_5%w9O!jMKNr&+6*WP zv2k{7j029fC`A;WyX^Q3?gz&m?G3U&CZS0gDR>~MVG<$Jeh1Nu`leb3Dq|JTBSa|7 zqi$8i6A2Zxg^t$pTPn!qXhh*iH6@J&xlLwkyrXOIj#DrY&o!13%C9Z{cv0~TH(~h2 zz$zAvkVF4cHIt&U^nCTysCxpfC8tIF843;noEJ_H>Mp5jy z8UtK`B6Pq<&{VeqXQ|;lMxhxd(cX+8N3BFg29YzvA}%%=L$85ESA4r3XiYKjEa4yh z3#EjdAXu1cfdz$4f#SL$(@de6HCx9vQ$lv&hVlGvm%`q}YF^CRt?5F-VXjLjpz8 zqD-bxGREn1A8jzj)qWE}88ewSn{~}*z2~Q$2CYk?ubVLttZs=#W11P$71XWROoi#) zhYp~&Of5=%grw(?u08vB-Eqk&4h`({ufDHGAG%#}oWpN9QH+U3lxRQqYp^jt&s`Mb z(uqK#*x7RwLb;CO&jOD@n7_90yN_0H)BJB&tKi!yy5z-M6;1(~N1!dy#y=i@o)#7E zC`92W4+i;I|3o7JGr-I&YvSHaB8@P>`7n?XIgu3lhP`GGS;UZ(B5pbf<}wTnqCx52 z6sMo6F(jJem>U>>UKI8K-B({x7$L~i_kj82|`5cxj#*$i2Wm|CR8`p4?p{9qJdkTV|`Oe=_?5I}j4 z;(LNJ7`rIz7!ox^6OkOo3&t7GwmsM8C*kpM&Wjs^`6^E7M1gDR8zwu)2=$wR%-Hag z+>X`ExHGwOV&)Np%UT{;6eqEWlRc(pbQp1im+@-#Ky3WmJj4%a6JwS(@`>O55TUZ7 zp!VFvF!sz@L1P&=b~tjwc=Is69S0C!1(^9CJuXK@oFVYZJ4(xf1x75^xQW ze<>pO09OKkJPE|$eXVcYfD%$f!QX&VfDK*p*UlQY?|~=`39Rd>PF3q*bP9$*Iv!x^ z5>OxGAvoe^&t8JU5zm57f;owa27Kw95!C$;-KFZP&0x8!m7JdDc*L7Xv<;$QczkW~ z(5FDJ`YM#Ut8ifZq3~=?Vm4Hg6t>!@Z)=U+Yfp5rd_2qOVkq|Uu{n5hS%BO2z+0QF zrAxQy+6SJ)3y&g%!4U{ib=X_1Y6|fkGGVL^JLXXIUKB-8$WeGlN#%e}w+d(j_li#P z`6n~=;m4n$c;eYaajAjD$rjd4jf-^GO{b}U-_BIe=A1wZwj1>=So0bvhAW_#j7y+! z8Pun5y!{bM0R`2F>;&=7Te^GQx+S{m>hsZyP`*(JEk~va<)Rjk@xG%wJH^_(&58Qt z^UsuDi4t$CJ+PuAGfav$vUoS@taBz%;H$<-0yjn1F_8S!*1)T1xf~m})a%_T(;QEJ zG*!VPF#81Xgf>UYG-9`|>feDV0g0)edLmNcB2`s~sZT&3wU1RPM%46qOH>C`$RIeT zkT+A2-osx61LLGa_D4CaM#(m2B?|FzObv!mVWAl?L^S+eH09gxf#{)tU>I7CkBeU_{?2fJ`P3~svu{@qtpwX3!fXjZS(PcB1zH41+ zdoqWJjf6P!wp$wwI!eBZ!N#Zn$u~r5iAMflR03CH4Dv$^1A8Tk%KO-4jCTGrgE5}y zqWu)dzG};g=+77@(qoQ;0ETja`?T+Chzx{~s~=L0Xp9e&kHI^gB7cnCW@H>;9GLMQ zpnq)OS)T;?y%`Lq=6eGeW%RvusYN-1oWmfaKF0{4Ma*9j3@y^acD%#ch{+o3uo+y#PRs!C3DBk7DD{N9uhlAxMAv#h}3S=pOfsyKX zI89-(NQ5oM*=@d)sQBDSZbfvfTxt_6QFVEq?omN%2(~;yMkc zQg8sc(1@BwJ@xEsK!5P)R+|b-Vmnb9UuHLT-19`I=wSo3DAsRUu1D^D7`Zg-up^Jt zgz?8{0JN2Xgls+Z!qbj&=_UG8O^tLq;4Yf|^*j|66)FVeCIVc{6rgAi3K9j;1|NEcvNCe1`klc*wI~m)Kgh8b zYGaF@Oh4%yRp&2vyrQN!G+`7r6ZvS@v8(nv=@xyxa3z$d(1;Q?m@@HcrKG3mxhE%4 zT{)G=PraTWJeWjkyu-0XxPb5on%Fo~Y*7}Y(72LNjKe6;bv1a189TN$bAOFQPdpeM zrtAgHOKQ;&6hVVCMWM)hi3-^k;m&q)`}t{i*g$xS*i)> zp+SdI7`L_bS%R|Em_&u@(rrZV5~%>*U;T#nRW5YDrIkB~oJ4EU_Y0Jh+lBtiq?qVt zt_bBc72Tr(jZjp#r5|EQCNI-G>PVCp0JC!_tYMp@K1FA!lehC-Lo@e-=@5kxQ3I1x z0HrgXf{nq-GR8!m6BSCP?nxY?BS?p#VdfW#YI7+}c{S=u(Z8at70SYR3G$r9Cq`+H z-TK0YR*ivNj$vL#{s8@I=1BwBg6%Bv|6}hzz$`7RZGUvGyjIn!oI~fFyGadA&KX34 zih`mDW>G{jZ573=m<0h54CI`1Y?`KtopY+LoU2xj|KE6v=CD2P|KZ-}KKt$?^(kFd zD}3RNW6U|`oH!|D*e|8u%LyRwrW(7qgqR74O&y@W$oMHG4fr7OG+Bs-D#d51eIi+q z&r3ExS|1zHJ!{`UDn^-=Yps!%Nnc( zgG(o|I9ZA%7P+1zcmrgZDnphUt}ds4k>Vkn(;VXe5Ia1?cr%3LJ(4&=hO(@iMM)|l z8A@I5<3D*IQjmHLI+2MHyhIVkh6q{#(og;f`dr>i3R_NTux`>6fAIXX?bkp386K%9 zd>x|!|MTJL5Xl#rk_2{d;lDihEWb~hu^rO<68XRr6fM;~(=SNAG^TQlNqL<;v{#5{ z8>VK6OB}*IYyK!(p$GCL0wRx27;kNi!kp#AXyv$GjEPQ~`!)O$)X zheH(D96!ce;N7;s*iP|oKRy1r@fH|wfq#n@s3f+btA8z4_mF+}h1aogt+g+lN*1Yw z^=!0@*|Y$6Z0}xBmZhno8bPbtDl8yc@3eWWcN;<85%L`W3 zGTrKCHGxQERjquhtt7=L*z(s_+wLw>O9HSW{!!bu^A+m_FihmTi50&z-yscF)_kA^ z>LysrKee(p{M#SD4!}1+Ksc7yP}Et;`(hzW_5m2SZzEuOip`!)Me=hmcAM=xPqCBQ z4zI0v4l8y9(iG*{cvh^zWvM2sOSV~R*OS(;^aIpi;I%RUA^#H@nlgFJin(UpI(wZ$ zWTm8i6=+TarsIH)$Y`fcD!yW&k(IV&?nyki*Oo0^Y9BuP0)QmI#2rN}>`A-hfyc1K zE8rYJ1UXQUZ%1dRWp)GG3PZ?oF1M@y@V&8b(DniZI&uJsuU>v7KPw=D3cgm{4bmEb zM5?cwD&*^J@qz<+CM=?W+$`tT5yUzjB35P9s?|0?;Xf}$#Nq%y1p!wf=LnJsD+VZ; zHEE*Fo-*A57MXg#dhrGB`-%w>&VKUwS84NFuFIh;V1Y`mAE#D8h@Ag(?b)YRQMJC> zY1b9VF6*l@rb$;$gSd0)pAta0ybfNx0@cWf{DA3DlySl{_2a1;93HktvTOwj!p@ad zQ|}_qFa$*6jSE6Vz0Qh{g_wI1==Y~+#~^|Ic%DisWRXXbR!)3Ef6QvgXypr5SS=Rz z#^y5WPUI;5NSar?MwKFIv^@|}EYg8~uoJ*;fPT@rvFy^v7?fSCM4TXL50%biLm6Tz zs*&b(p!hXnCC4o$A<=Z3<6>UM2YA0yu6PZ3ou8m34nYUnNoz>F=1KV8Nma{0RzJYDwGz4N42JE$xn(1WXqH(s6A**2yfWDRDk_kKJ)HCc=YI}@s z--3q$&&Z5fkn?KW)zM~Yh+;)$#L8=<)-VvT1hsKIEnDpCKm3>-G;e|%2bX;Pm$vBW ziFV#8XW%s}*flqCJ{z3$=Jox?yIEX@ropgJ7_$h#Cjkqah`eltV#CT@)b6X z_h&4bU~O9&9~2m>s4BM|n>RuP2$F9qx7OJ$+(!v$!N)(W}VcS$YlNz%?cY>us5`HFq%vzJ&E9s{U0M3iSqGhYa5lMKlN(UQj^ zK|j%~5N8hVTk|we5V`vkFP{8GA{Blvs(2S)IA_Nkf2$dEEPZ`CFu|{ z7#4c8^`*!{av-1xo5~PrK;yXN>${N?;Bn9LdDdXJ>68Oba%7=VpkOi)a2ak!v^WdV zVWBF=;#tYYQGv85g=H{J@MS?RarUoaX9dQ3hKs$9f>622u$A$839^C=pnqg&5Q`XD zrm#i{jO9zggaD=%^7;!=2{;$g759$}B8S2P&ITqoe@KCn0H;c_*wkZ1EDY6~hnfJ@ zfhX;;M{c4v!vyO|mRlX?^JJA zQKw;+^o-4bu{}Gir4b;(`N5A!GIDI@od6#nbsSdMuI}B)VXApYDR$dzX4O_Q7u{#g(+;<% zp1R+TIC2s}os2s+_9TI*?HwJqb@ygFkV0tNx>i_ktlg!;^<(KR9Cj!`W_{HYal|5OuEf(Tl8bTV=x{z$w=PtUd9}Q}*zqkJ|UY{e8Rg`#-iP9=p%NjAvz&I`Z%n?FZlcp8es@ zM{L&o#dh$F7Gy78+k*@*B98||rM3hB$=vS8qm{v|JrNQbLq60_fbiDN1VEEmAf9>u z^Ru?BrJVQ{k3I7E3j6)9erx@`n;ZvA$%Vq?_TUL9W33t4k|IW@$C0o7_g_No3^FzC z>L8{kigpcZ1Ss^=4pG2l0k=sZCCM9BZqBX3IUefS$jcC;j>RmhSEpiYZR+HJefh#K zSzpgih-c7d0D4O%F@9rIf+yg46ggqYzs*`3n2pqrsH>w`CN768YnY^DGp8-Et=$Pb z;7Eep0k3t`V$o3p=?{(ex$EC^|60};BysWdkvu)P#+T(cYDr|nsd^_*Ng~&Uv0eJV?aMEM# z+@lW3tpv`!WNr$veyWfpLxMg*2E{rVB{qbvv^~$(5TBH_mH%kAZ(jNh06*Ra=Ap96 z6}@{}uudtS87j1!P|+fw77`?qU>e7@9o%u*`llD))( zE<1%qRitAMgaD%}n+QNo8yK5SUa|}}t^h7-S>y3)+vGZ|T6hTj(*ag&2qFb8%Lu{R z$|NMcymafONkM9K&1`}Rz@4n3Au^RDWFcpxs?+9Dsf;wZ&pCeqkfO~?LB@G3Zv_v9 zvdSy17vfP#5N2g7dnn|i6d9BPy+^q>57#Pq2o%OrT$ChNQkKd_%IsD%kwvgU?vY%r7d-rzNqT`FI8emIjcC)P}ma=N4-zbl7NUf|K5aj|s#V3~$|T(+_DxmQ`k>J)3Q~2Yc$CE!IM%>L5ArLu|mF&=jk#^VkTWLm8ba zE08yFu|wGO)16OPIeF+Cu%Zv{-eR5HPXr5`hkGln&ROg9#XOS-xrv%<$XTBY0Bt{Y zB?1P(1B_QAZ%Pm#E6^bCLTq%%(jA+u9%)vHja@~)3Isd*eONjHG)V$~2iQnE`yet{ zPE~1K0rpcSHCYT*|#IhcNs9lGCS+wsPI z4ir>YG!l#(v`M6AowB&vc{1vWjp+w?0y`{5u(;w(M&c#5b=_Sy^T5-nM-YQ>NXxCU zNX!DVi2!=|P!P`r@}y8$`t1rU#ni8iPqZS$?n$d^`ixC!tgxZ34M<%Y+%t!e=ahS5 zc&ULnb3Lb~hmN0(E+C&k(DU+t!sux~Dy2e4(zdPH3HGf4}x#+p&AM-FNR* zcwoXvff$?|X`U~GB(8uA#D@v`fN3%6Yg}t5omOv$AN@@?r$w0CP&<4QzRtTcUYIQ z@}OXee(9Ap7No{WnDu4XzzUlUSlmc4P-VgD#fdRW!h(1$a|5ZG7q7seS){TzB;CurlPA)9222<6)q?$ND-jreJJQ4VRfS4~2Ml+1d>Q zcvGLXx$_URL&-k&>MPIMnm5-to}s!sdDcoPMnl}6m$f$q2~ps+WTkOrUkqc69|Jam zv0)CNdxVoGnA`Gzj9_Rea<4L?jL^m*B|PBFDXrC#8q&rYJY+H&FyLGaM~eGTUMeBx`Awd!~h|)+(Qi7ODkWplTT`eaEEP(8Y2^#BimNLV%y$$1&>L+ zRU*6m!09L25yzcw+t)v4`yP5Bm-N}UzICZR_{3AJWtD7v4}=Mx?$WcdkQ;T zdfTw#9xA8tMY3)w3lRUSY^}6=cU9Tn4nNBV2Rg8xB8>vkIS&B<*+*MvN9ZToN><4U z(`I8?6%peeuqF?OTJ5Do(Dpmzc_EMh%u*i30c@*gO693@mIhygPNUJUK;UOR!wK`)Y zVnewl_VFud_fIW^4$yAW!PB=vf^^I984V`eAsPT%`l|*xj%siO1AtfL9m*mUs+?k% z|GCpH{p~@F8O8*6Rq%d9vDN)2c7ir8GLOoJd#sY!pvhRSLs*Ih3X@N)r-a4;W3=h*l|@?gy~ilEEGjF?ZTf^M z7Twuruk3o+zAj_8)9%0JVcW8O17J63wOG&ROkHM4=4=2DK|I!P2c2+;UHhj$yRRzog3=Z1C<93l{$y((*<)3B8Nd3OPutRc4z$TL7h1!VT5BhUL-R&5IU1X0#A^aMaG903kOGa} zy!H#|Q#_D)wjG%i<_z;AkvjdflkC`oPqqpB%pu)xi@UXVN&%mI>|s0b;6vSWl{Yq< zzjl+o_{!_%(fX(Lj_1?-&?Go+Bxy%*h6kT{%ATR1;fTf^0qg?se!K}X*2pU*DVDM| zX~j{qXVN5&sA{%kzS~L&cHi{eqr6I73?3EVAYM+AQJng|<1O6SVxOW~_k_A?#v}xZ zwMs|F)~&V^N#)X`kFh78e%fyO%Rg-Ms@L#Bq-{rWn=>+~&Wz@gG*CX;M9bao9SY2b z#Bz>Oq)N)_CGw~w8~Q*3vgi)hZw~~{gIBPeel3yri9(xEj74)7&c{$eHZJA?d>M|a zwl8;ScU61Fk0D1yklv+lNcF7+oHbi99!d-#Ql)hWofSh7YZytkFq4Wby)Q?PoP0 zeyh@Inu7NHYb!C(4BPBkGj0BydA68J?|=RK&9-UNW_O-IO@ke_?;_i^bG!4lpLoRa z_8Yu;i}pFro_Vp$79N1qjCtJEg^UqTSBL->KP=8ey^y}XUYjrhPx$yT-U9EU1^(BH z|1Lf}{*mz(_;+f7p}~R5Y_=XiL^?>oYLVbNzcwd#_QqlECfNoku{(1$yzBZ9h*2vNLfTefEZ;w$*^H5i->gXLuhB;#!7>DJOng! zJ|s>hvNCgh1rn+OLp*{`QLGHgn^pBhipr4B8SZAsD%1py;s zAiy<&Cxc4b$Oej7!+n6B8q#`MEaUBP#ml=qE4z6on{x6_Ws|R8d6p3w&{Eu0iHd0tiL{S_uo+;t7ibL`YAp zU{tk9K7<4cA`vHuJ4`kk)uxb?M^^0|z{V3H=ol$XZDWno`M>|{v+#-xkS*(Bh!o(a z5VdMz2}~2*h%-^p zzuL_UDHs_YAiEc`Ee5tfAkT;*2?#*#?{J29+TH2njrDY)Kl%b1F?T1K#S99X__L6G>Mm@iUEXe2uLk zLU()x((Mk$_B)R#_n%pZ zMXTb9#QE`@2kiC>XFf$jZ!Y~Pa)LHaXd{YVYf71kX|Nj1M<&|?;U8Y_YkCIs;)_9OE{3Rz2xl-gRUWOG`d zSPLZq67UWYHxOrjHIfM{iveS3u+IuD^{hE0UBEk=4NSCH|2F&jm%n5i*1usJS3Pas z1^e1I>ZO#B4tvQ0B$^OSFEYw3Y7Qq8dGfLW}^voiaBammUFAQQl9mHp`wrMnu@?JgOPSw{b zA#Or7UcALo$o+Qv{qL_KYgyDj`?=2$+ZJICllhJDlII*g`awjo$ovYj7mN@DueE&Y zj2TEUx6_3ln~VXb9xs{?%gzwh>sJqwQ47ONeceQRW96$h2;nL#3);yaJeg;hU|~{t z|N7^@x1F1JQuTa+o$&snY~I4p+fz@zVyoZSg!gmEUVh^?Jge2LIkZ2XQKc96vL5*H zPP01myW&+6Nbls)MGD3`q%}>kMHhYI6E=B5gT3Xp?4NaOx4`mrRlk>t~3pfQMf8SKxdgSCfG zv30Zg5;uTlEsPZ{gwK6baT}nhrdH{g}^a4Zff1D@8=N$4%>HfHuKpYngiJf=5uJ?z@C6O_Ik1WZ?sZ1_-V# z2zaoe>p2Sm0B!67rII43sGnqJ@|1X7n{h8(es3C8c1qfm%tOS$=)oo3QM6*z^_2%<>Mtxod?GSZ9D%4)Q&Uth#J&S8w zwYjd%=lK#~o@;R`wTs9nMpW7mkic__j0G51O6B>@%fIc$j$eJqv&m!N0DM4$zv5|l zw*R>NM|_7bGj1Hh<%}YoI>++oR_IRMnB^s|BiRmh7DOC)eQ)L_wU_QMg$zTMVzspj zr$vxnxx?KgX^S6w!Y=vRHz+?K*$MZ7%!1hf0mX~wXRPDhm^)_)QlsY_7*}?mFd3La z0zSHDI$}8D#X4`?+v9fZDIamqF?Nx?|LS66hq_GzPR*m|mF``grnnIIJUoYMHu^pP zR6eg8TO)zo2#Xtld; zd)n5mg*-ys{WTez+FWf%?te0IIO~Y@fV@Th_Q;KQAcORfVmD4T@m}*0)ZKvvyQ!jq zB742)=#?QXXU)XU1Uwa1Q4+UGg6)qwaJHR(>i29tMf{Rj=v$i0DOy-=udUl*#nCRj ze`In(x+4meg@h`8OU3e%Zmf~=7gj^oW`g&Tb*8qn77!ms92e;bASVE9-@`Ms1M!=e~pnjnmAt&RGR z_W}^-_T(NK7m}-5A+r86VP#y9B*=y}-hI}?SeDTsiC3n1&NSlP0yc}3!?ooeTe~qv z99q;4J^VP%?jgPIsI@Q#8|#}$Mlft2z2t{>(BggU$Rqc2o}>JTA3%>+I1pt#vtBZ` z29U{RS$pBk7-p!~GL%R5gfuIeKpv*MM*527D1&TKX>WU}#=h@9OGqu3n+dAFmLnxkldIg3UJSPxi)gIE^ zd+5n~ZRgHz`}r?^i*%GY7}j@rXxeuTT6JZmz54oQdm;I%-EhloRFfw?_E4{V;d39b zlTLh}{rJ0|w?@eE$roP0`2tqjFwGu%=ux}l&hO#fSZvo_`wzS2_9yKA+gI4L&%aKb zm*46tNp(#2F}NPaFU?HGDaI6~hL+S;%aF*Ss?~dm7YmTCS<8jUZ4v{GkAAu9p8F}k zgC`L(`T0+O%wBro1)3~qA360Dt8Ds&?cBP_`baxIY36L3I%%$5f6cA-*-w30oy$HD zwvT=ETwD9*M&=mnZiZCM3Fdx4V?S1@)*nB{Tj1TafcB;FW4s04lPv&Hp+Gi(pMYp( zMarZ{T#k3A=M@0OI;h_Tu;ro9b{vp9A7CSJp+#Lsl)!6Gp3k%R3*du}^brV!q*biz zY%F=?Qm$gQHh9jh4PD@tcuD6WNh9kB1gjw)0Dmm2k`}1O0v~r9DEb|)f!BqN-2p7X zCHpFX1TP7|&x5{MK+WZt*RAVKHl_fsaRK5O*9!=7bHaW0-xrdQB-UY&=f(Sx036lJ zRX{#{ESJ7g5ip*SXBIJ2wk0pu@glp>0|`*)*`T%g>V5743vDUa;kg0HVf6ocW^KZf zjyNEw2u;o>OQ9rg1sH(?-JC0f_a?xz3T!ICGm8b%&riuIbiX_S-&Ia}S@qa;`A&{= zyZrlHPyHj{nHO_XEATbRGMojUSKPS(VQ&MC|3SU>VXEcI#@=b7M(I)x(=TvvVW z=U&CrTwn7+0W^I<)wNwAL+(XjJHTeI_SXN^&*}{j8P5`P@{O#sK9Y(Rw&DnqJ`TWC zo8|e8JUS}KCJ?9l7WvT4I6%#Ps2%lL5f&gH2@W_v<44574K_UlZQ@~kxH0(Fy=W}T zOXn>4#AEm&8NfOEA8<qw z|6``O^C>;;Q!Ah55=p!}Q8y>lJ|dzatfgtlR0SZhf=5XY59yBF^YBAG`u0H+x<}A! z$_z%UxXT5S2-+on1%>UFd8hemD5jwu+4tXu~37u1i=AjpWEuzRj?kjp-(#XSz zf7rfxt^M|jpAhTtkkv$scK_3N+Oy9*ZoO3cM$7^j9~&PbjR)#kj0__!1Vqm9?6mk3 zzp-j8%w?KO!75U#5-XBx2fRk@nP={`#rxkzrm$u_WkK6LSg?`4oW1|-kJ%p|e9eAw z$rr7uu7oibv(3c0Jo4~!HfR3+*0cR}SF{c%rixo*`G*uR_T5~-!%!jul4V?_@iYPc z7tEP!J4m#U_BIh)QA!%>jd(@&g~UV{Qz24qms%|;u{%4~60^ftq1fYNtaFiKnTzl7 zWGnDy(&Dt6=0HlaK{6eIqA?PvrI>oGd|9mZa?g%3SG{qBM`}yFeFgfSxMbcFImDyL z*ohUY$;gC(fw+kXYsTv5m%H^Y#dzpM>NSB%@E>~r7vMNi+a4>irs+#a*}TI#H$RD7 z5U&I=G;Ld6w0j@anni_gypZa_B4}H6Wl9;R)m05PN)iyNTDmcuXCaN^`ODEa{&b&B zn>L-ei44gpdRcZDhZs?|ZQo;MB_iBB5o@BW69b71g4kWX3kJ(T|B&@gsf6VE^;X=Fk62j+HA{E}N}sEO~wJ>;J#_`HNrt;?mE4_OrhyMK|<$?D$vLpFDZ;&YNz!>3k$@ZF@iWuYUgX z`TqIufAyXJDX)zakpC$?F@7Ka{Vm`tXOR}R?PpPE`y^;POBRv<7Tkge1q-*Vumaig zC{2#6)z)z5;hB?2C*Uju_>S;YR4;Fs zfEAH`0tAq#tghngJUi{Bv5+GGxT>jzI0__dSR2!LHguCB ztR={>VpwQH07DTpfudpLK8o-0b3gJdsShi#Zp#ZZR-8=Z3hOkmqQHxOEY&HzJ(5BN zAck?CT|+D$&pJYp0yw2ek*h#(QW60GiMJ5>;we?hKGn@2<31y#_>{a*l8hM7GSacf zify|gn_ixmpnDM-u6p@bK4HJV`f38y@s4m3)vG{s;>J*($&uVW zFfmn29U`Oq=MFvCUX+S1AV3S=A)W+grapJyd7iD6{TO8 z^ITjW$%ZQWlxg|U8U9$kMfNu7$L&8fmnrXWV6kiGm9?eJ{6}{l3;G++&rq_z9WrcThqDDom=&A zI$nK{-<1dgk8J|O1Z#?y&#Q2`ve9{oGti;7lvgLgoC+iTD?m01F@Dm2@&+o2gpc(n zh!^Nb-@C%D{Nb0WhqBf3fd1Gp#-7m*o{hdovg&1Awbr-r95bvBX_*&Khi1u?xicv^ zn6#>BCH=-~$y~2T4&@#6*%!X}E1OU@mBbRAF0J)Y&lco}X)BMEBgeu!?bbWy8Hpae zx^K=mW~9M*!ulX0P*WMPdg3&WIb=WEck)zZl0z;ziI+<6^@@qP{2MlV>EY(DpK7;0 z@Pw;5q(E~&06)dra@yu?cFy{pu07uQ&*r*v``H2eKt0&2SR1|CD@czUhN)`njw|wx|zy9?X8He7Fee7d@`Shnh{YQQ0qKhv2)4Fx*<{_6I_}=%v z_nl*pJ@)Z`^;w-m?>+Iv6UW?n=bdL>cinXt&Ye4Vy6M?d;{V`F32KmPHLbKiNsFMjchzkcW6Z@lrw;@|)N_n*Zx z6+PydW1jf&kAHkQ%7CoS_w>_GAKBH_)u_)bTD0iR>#x856Ol-SS@+*}j1!RmzP28} z(*Lj)Xs(?=Fd}+jC%a+~!@`%x?B@lP_yAQ(dF#P~>mlonh=;OaY4MeJp`cvoSp4+2 z0E9zG0`-7Cfgl~)yi`j=fK!V-FdZPkdu)_NK*CVE(`{0+*2|hqt}0F?aK}&N1YtnF zjy%MM%LAs^h-Bdc4Cuf=0tmoL4&qW#xgu82NC_y1EIOVbK$ptHNo9b+l&a0o58%ni zNk7U4??HN#1o#HAT+8b)I^50~@iwqA4G)to3UD%lyrjG$Vgtw`DoOFGEMH2;C_Op( zkN_xS#7P#?3ZY;?yMTl$M+mBZbi z1XT3&tOEoI2n9)3N_HkPQe{MHAV4M3!Mk>V*a65Y&}1j@fOrWo_oB`B;YCUyH;Dt! zvXBnRHRQ-D0c?xN<*^c06L_4$bQtFQK^Hhn@jOUDFa+R3f)D{Hj-Z+La}VmbM$$~m z>K_KkhpKBGNGs*L5xiBRhXSc_zF$hU^#B%XJ?kj#>f?1;JK+uhUVs%KCrh7~Ky;Lv zHclIN6T_0mA{>Fp1}n>5O3%`07($kEF*0e+A);9U0G6CA&HWctAWa3psBxjn+Zo1W zfoJzZJmV0xv9TD{ML}$gCZ7!-?iLHZE@<)m!9BS0>xnk?9=n;B(#tbKwr|q4G&Lhv3i1ESG_O%Y~>%-@qVox+w+7owPZ(slPxpw|1E@h02@-?r8 zD{C1K!?x_8L#gXQUsQQ*QS&rga>4O7W5FUoFaRvvipQtgicddfn^*ptYp3kELr=9U zfAB*)@dKZr2FVVBypz^Cxxuc!<`4GuZ+#E>3++k&h)9I1v2K%+x2Cd@YV|b$*aVr= zDs6xudu4=*N^XT$P@c>@W2}N$s}$=*8e_?v$<*~Afr6wr%57FCKxkOg3e2xOaacaS zBeLwOn*$aD%-KAhPpi31Q+Z;&H1D-e$&(l<1(3R-0|`OarNa+dtMH64ACq>#;Y;iT zAN{mF`|v$>_D8-zyh01DJl5{+!~8RZv?t0KJN}$AY}>lEWZa4n>x7q-G3Kd79ws9T zZRCs-njpl@u?i5QKuj2bSwup^SL2G2&u0tV3GfK^AI5#Av4svS6ACdK6Q`G^Z#Iry- z*#pQjh)2lJp7Oa>uiJs`1Mhr{w|}46JA%CK8T-O1M_Ph)%XvhY2O)@b8ktmSbiPL)ef0RXYuC=#d-DGL$AA3C6+ipg&o0y7|6Rv_o|XSyR~^63 zcnkawXo3Er4r^+iIWk^jBC@27~phNZy2Z9P@5z1pJ6ev*{YwB>jOJA?liju_S z0gMWKmnTD(Zb>7?vb$hm24v<~>?Pp>Un8M{6mWJ~yk&`E-(WN2YRD0|EeIySkFs)E zg9FyJZ9BjQV!{1yYujj(C(pEIs*S5JOIJ@mhUT6T}CSiltaY6KY^Pcn;htJhR{CEZkRv z!U4`9(wcS?BwQ(y1&Puag2&L-8s$7AWBQlB`<;{OB&i^+VsxNgEU5yC4qM= zj)$!R5~zUO7{3RJ9ZCbDCB-Y}-g}0!cFg{V@8uYpL3$hjFF;rX!p#=u2JNF1#*)@4 z_G#mW&9-Xedb0MsY|lUWjD0E4XczJ6N1uArUTOb{O`3#u{`4~;l?|K+v_)ULgZmfp z-TOO`RTEwiP%U*tLxt(zC$&lih{r!}p;9cEp#T8s*; z1z0wQNowIiTI5gG*h|DFys&z^J^J|LcF%)P*hL@xD1!|mfZ<^M&UUhFt+xlCy2Fk? z>KM{UFSKYwgOxY5klMI|8W~G%#mcp0*qebt!b|G!sBPZ-rhWTcKeZoRdAY4w_on^+ z#=qEykxs4H&|^m|I+*+1YPa70u$@gtuf_(v%8W%X8U8e%6jL|~nGLYsM2XAMI$I1> z&?Y4|o7k9+U3h4C=17^OlGHn)-AnLh`0zFbsEL&3O&P?zc%vr7w9^0AhnD+qJol2d z;KBL-`ndn)|MIIszgK8bQEP;d{kJ}+9VhnI?^R~=jyPNapvu45G?};!-D)qkiz3-lxGiPp=mqVal9t4q*#fulev3~vfx!?NMw|;Qx zrI-Ffo)VD?c}MWD`~LZ}d(W$%?2YQK|8(g3fBMs(w8Uv$@rV#yb=6g0BEB+ET3Q-! zZ*OnWdm=}YY`s&O_0Q+i-@0cJC3$r?5+Wz9t*v`>4jq-1l|$|q{$V}D5iQfvfA7Ic zGk%P>z1brxS&hl2NHjr9eQKvBm-qNcZ3WPsct0g%!G!$xq`Lu{~C${MQA2zW^(l>sob zZ)3^g+?+ucJRh5~T=_9P4od5qWmA^&8Z^m!oR7^bz;zR7xx#u4t86I*!C8-aFH@j! z89#N80&8G>Kqgjnw(@eG&7+tABuFZ<2&x6xKu`e05xg#0$;enOlvY*6wF+3_g>d?@ zAnX1r$i^Z$Q6W1-#wP-4ArD0ejso$snIVXTi{x2~ zhGzo6C6Z9YVypo4LBPqxmR47jB}1{sHVBjK#^p$ShLgw_xVJuneoG)Rs!dPaFTgNBvy$KQNN~c)54<(B ztt3ihL@K2+cM!k_q7!X_*m$YX+->E^$g=J2jznYtnIfJkNw3JPBnIe1)>lfgNyV=e z@z50TGQe#tP2COw$2{%t1?1$h_7*^jvC$YFnISw+bxs>zSyfM)a$X2;g4DD@u}q|L zc}blVUqW9>DkJIF2qY~65r|OtfgNrvP#Ni)f@USb@j}dGDd!eBAg%yCSwD-AH37f? zGPM#iVx{B507E=Nkg8W+e94v_vdoeL5Iu;hB#K3dr{;z{Zz^y{s{pv5I*c7Z=|?5W z^Fsi>najRue;Q@Hx`Q_5 zIQfO=?f4bcocP6;G4bj=A}lnjP7L^SLH_QOd;j4A%vJT>-a~WZr6*T2)(F;y;BHF* z9I@0dp1;6OJ@2D7$hjJZS$WVn;@Kr4|B zkG#EP*pgIFUbayxoF8-S33l=)PPY%8bv8v@%k99^ma;y0t&Ui-OU^%E7F=7t>J>aa zY1#*Q4n#L93D*dcF}$uBq(?(YFC+9TD*X)G1xA$!KB^4@&)@26jdJO zS9Xlp4fpS{>#w@X79To^rPM=_(LwqJ0}2EwKEw)+*P7)YNgit%bxsc4cMjgKTkS{R z|F*rhdY%2`=RY>oIt0=~dzts?QM|W!f9B2EhY~>$`}STdGPk_)P_Rb&yyf5d432{9(V@_6qe{a(H00c9zk8BgBX@6scwvy8}OwZ8C0ScrTkN zj@d|x-hCI$amF{k&bC5!!KQh(-@b?17E<#5_&0yDCm+3y;<$_-I!c6CpYbDsQ@IT?nER>#7f`SA!(V2)!1MEegA3+8b8Kc;62#_zQ`PpFWn&Ou^bBgjLAT-AOm(iWMK)i zA*9(TgIMI#cv8v%kXZpXt`+23UQk7rwM5^`u{nfE|Cq-6q0cDWPZ3ZoO@4~|lSSWo zM7Y0bffy1t-VC772Qg8~Tm`F_0amqPOMVi>@>v2{?uSSOJSBKt0I%G)0;d(Q+|)7w zu!`kuK$c>p=Pk0K^$+$C)Cv4#qmB0s zl2u0*eqvexG%ChbU59iBAX>)v5$fN1ONM@R>25_L z0aW4yV_BoJRtG7rB_LcGu{@Bmrs)gUe8ILHo+cluwIp2$Uw=HL|4m4Fb9%5x^j0HQ;1;0!Y*fp^`ef5BK@7 zq>S!2po{Z#yhSQ_rZE}Tn2d}GukmMDhlK5y6a!!m- z4(T8yO(diUsm&17&G6?xh$^752}#%VDN(!Yz6XdU%d%Dsuokf1(EI}KAyU%%N%vYq zze(5$IHnmYjsSC)kE_R=0{((EdAEK7_vx0bn-+l97-noB368_9G;V;+6% zsesvGq;mLD6-8P!-P*R%-(KpeaBs61pHs^hL$0^ktFOIc^T;5zYc~>~ zZb(vH8$H4jN&tQVnNJB6HUWV~f6n@tWG>**#M4wr6q&o_NS!vaZiKCp*Q;8~ZD$vK z9*9{LZ5U_%=aC@7edu=xKdWbUAZByt?vK%+6z^xq9=YjJNF(p1BDP@0eA~qulh3qU zVsMWwf9gI)3Tq|nW)^bT#X6KHu4M9zDOS^7{7KP{P-E_wHJEu{h1Ysm-ci=?F!Ns79EC0;)RE##T+-}n7)+{@W)Xh6spUIxZT8~`^@Oz%!bN3@Q+S$&Uh(r_*ZAiq4sp>(3<-;qQ zCkaOYV?Y5?@_*wYA|UzHJMW$SxHx%(=cV27n>+k$2f^*bSM?Lk<*Yx{8pYNal-WzA~&hL@^Y*hd4eNFKs zdw>7${5iHe{C8e){95BJ@IRyl%A45KNr_0cKQ=wVBUV&_6gGo2C`}ng(pboHnPJ`s zfMWTDo&a#itl1Lniy&y*a~YtN@)1DeQ(8z!Mv4@;z98qq+v*{uC)=F+FNO6|)?b0V z3_HH7o(>Ff>07lKb54(}z-%57SKgS z8z6#B5IGF74HQ2c2DM~(&!uxk$FA&DMF5Ke;Ww>ci4D3zW+2nZ-Zrb?*MpkVtZ(w3^Oh~!<8b_5|K(MW~$W5urm%;Ay-jALod$6Ro@ z;x$w;TLJ2v)&`Lil||V+iPuoEJ#B_*+NOdE;A%gm0xlp45y?}rxLRru6bL{~Ljuys zdWLuoN#ztP;jHG!zLKMZ7DPWkq>N8&v{5`6c`V$eoL{-{bThg z!wVs73gIa5Sq~tZs1#ZhPZOK72m;;8+Y!7GybfR$38|n)$0(p>(xg@gE_l(68I2pY zBfSN1QH|A`fk&UD0TuvBz=8mVZdRkX3Vpl+_OVM6n*v!TMW-@T@d(cAqpV=+098{j z^;ZydJAxrR3L(KtE!hlKQ<0hg;3}=LgJm|Y>}BhlH{Lq9s3chFrh1o!PN{VNboGyH=f(}L)wlZ=YRMU*51`-_0?nqf=H`hQxKD#yI&zjBW=6e+9=?*&c6R2pJUFFJ*;6WDPm)G z=dCO3+M6%2tvg<0ybarq_D;LtOPAX>KK>hn zO`(QHu-UrsuBlKSK*p^LKGu&cQmn8*BLgPR!)#gorfuB4k#z)P1^pvuX@<38Kc4lC zO`EK7=1kk!KS-eZE*l~hYbl_#4$?j9t8nLyPyo;e$jq_E!4Da8fM(h*F${?YMDKMN z;aFq+V9sG^0k+x@f%%0b#t+7))}(Ucff57jt*RV|%P_2|#Y;i~Q6+hh*QTPi#qNIg zd8=eiDSG$t`Y89wYKZ4!go2EUp^9Q)U^ct;LC>gxAu^eV6t^_v(ZKUEgvYN3Z)u3J z7W70JKX|2)hRWlq3oAoh8t-xvuV)a+XOiNaKyFACmST)|C zqfa^-uzw~bXNQ}E`BI;4*uB$62APkFQ_1(++TQi{tsj2JK630wY{x*#>WGsmW8S{9 z>N)PyYilW#`OR-#iMMI1Tjz2}L6v<_NitMiQ$;;|{Av^W`r&(QX zqwVh6!}p@Lj-s8h*oZan?6D7i=!16oH@?F|Ci5KxvU zHW306{YV;AQQD)TOIWzPY#7QUq|L98q9_+gLQ*NOQbS^y4kBwv;hDf#beRtOkt&iG$@l)-^hTqOlc&> zq#uwSz)MlZxztviT|x8!?258_2T)?M6tNt%2>`diH5A+^NsBbp2Rr+T1{axuKyEIuYGGI&)bvYY6IQZ*|W=Xo?FAk5FtdDMFS&-~)i@ zqEJ~0S*;ZRQv$fmBl}WNrLtuSAjt!<6|Fvz;B4N=wE&h?DoBSlx~#k$t#%!939bRj z7#T^}&_Is^;C|X!mQxW-N#;_+1GfK>$KpL8bRV+Rws|XAcYq3bRCa9J%)Q8a7QwU8 zWlNSG!nGNg^p8-mpP=F(@`fVkscV^P4G?+iE$ycthSKh#D#F+F|Lr}}>Y;NU5Td``n-S%{w4P*vv zq%&rDvY?faA??7Ej<>BVHrr809RvBRx93*8WV7ZELn5}@rj38L?mcUe2C9iO)<9Ob zTn_7f*+e_{=re6sTeqEk+Br6Ja*eZ&Cz)?&U3jrwaQb1krF)HC`h!2(aR;7Y=YIS% zHn?Xe;|Jf4yl?cG+FL2Q^CRU*-a=MiHHq3H6CgsHSVO{)hoYT+#=*o>joK3{o^x~S zoed{X)7CX>tcD8d8=3RJ`ps{xy}g5B#@fNTaq1ycWIhA@{mg-=7B1}NdQTb07%+?j z8DH?Mur6ukqQ#tNF~Yhi2dtC7@q0GuV;(WCs4zZp#&kR5(1UH|#+|mA7_G)wpZ)sk zKUx>T{h#~rC*OIC{9a_uXmjJRvbM&q_~sXF!`30|9RMsV-i-04EP%x{#s=1l0N2Pd z@8ft}15Q@Ye83Rls;ZNGV-zV}8E#hD|KoU66vvj%M5*00WIjA4GAxayK>Xx-H1frrS$oIty3$ZD;!ivTIe__8r@p z+XZ{!$>$;cUOVE5{qbr|v_lS@YU|e!*X4~{71FLMh|vzR`XwQ8VLWhJFL_KiM_n3n z`Y;3e&uM*N-fHY;F@UKsVU}bB%3vrmqIEophbl#(%AtWaJXJHP&vP>KAGs?M&nF*y z&Jm+S4?WWQAtSrDXNkd2+u?`oL%$DEP%&U@-srZ-gnIkkFK)DbmM%qpg|`*#|8u+r{`VFbCm{cOn~cBm9%+Gme$XRXOBS$JBrPRB+-4ib(=nDZ7k4$@ z0Ld9xec99`O_3Ffg&$-f5Edd~e-d0Ta0yL7zl=wM%|Sup`d@?%!N&%G(TW2!fwV~J zE~VQqrpe#}3CW_lb{Vb!x*@&?3v%C;)l-&zeL2HV$uZ=4klaMsw|rRnL{8HFQMAUg zK;sz!G)V5E$i_UGT=GPo=Ky-zAO>RH&T~>Ct2h8mw(35jt`!iyjg3*6l%!jaVVReu zKZyH(n9MW+b}F00VgtnW?D8dIwnP z!xF1aFbk=wBK>SPMbT;~(xpsWbxjb6Hr)HfDM+@~NP5iDvJ&g)=yYTt#l|)y%Qivc zE`9~j5KmCK8ohQkB%qfA*U zahgD&Ys~A@K^%v`QS2va(PE5c6d5Ng+Rx zmqp{)fkap+vGEqEE&+hz9ihrRzAfkV(x#ASyaZ^+x_XW2QEFe1?;i`R;t?cOMCgM@ zBx}1!yBa6Su2Q!KAcmv`V7!p+i@5$;d^ zR;DKI!aO(qo^IkjNRaK^<>HhIjc)~=^DLT&vf}Ukp3Wms>47+p)r`?Qe4k0n^l^u~ z64R<8Ty0Y(OtyP(y}|zR(0Y4e#RjXbEwfQ#kq$ke$3ZLaNj87qL#%D&RlAbnZe_$W-F5e)_R}AKA21)W zPk!t|yXZ4tu&3|7hOyX=XUs=2zC$7CA$#$)&Gzc@%@Dl~>jE@F@&pTPSx z${d#DknC>sZy0Z78J?(N0OJFX-s{M=FVV$#&)Hn=FWcg=o!d8B1A)~85OaADL?W~v z^+6&gK<*bU*xxp;-pcdV0haO`oT& zS^JdAxVE7c`4V0m#%%#vVgPw)fb}tefoJztKsJq@hKM&&+%?Pd9=Yr=+pytvTlLa% z%R|8BIh!$gipBAotlPNK4nXdt)a9=d=sl!(FgynystyJqxCIP9ImT?7bwPcp`|~r& zTyatU4zTu(VrWsnm(s_EWVDo2xg(5etydA&_Y7mi%kK>o^z-?dGe}f(#OH;1&T78z zCk{%Ul`6)}C13rv{ra~*w=2H*0Xy%^LtQLcMNPHs;$CjK^Cu9(@7e`qP8;rB3khWG zaczS`=x8_(I+3W31rFIbm`YDHIlbJBwg)D(jvsZRpJR_5Mxv+VZ1!T z8WgZY4n5T7E?#B}4`BbmWfOvYRlK?01~HlhkU1r2uj+<6x84q6?1>^3-neCp%Z!)A zgQ@rS-*o?UR=r;`W(e{o;Do0AhF&$gvj2&x4Df-Oqt& zHG>zcTat~>4(n2SC$R%a%ljVD|vxZxIl$GTUU4 zE|5v7Vqk@R{cCe<+J)D#nar{jy62dxoC%mBeGu^>$b$`pKxFP)ud6yc7bYNj*hZ=D zObQMxhW(`KOwvol3uGR$l)!rvLnB@Vu~Lf6 zAxKJyO?#xb->T}XxE@{@2xu9=MnGLLF?6zRU$@nzb*`?j$*Q7wC<*Ea2Z2oFSq&22o3xgog~P0L+sG`mBVfwABf z#`W8;@|HW{TOSfA09Pw zGpTmdBuTjaufMmM^QYSNSKrJ$%iE>@@k{&k$3JMl`|<78wr3Z8U2VPjZ4^Z$#z^re zkiaAoI!QYNNZq_)H3%_Q7y?k_nYXvgP9d(~_P_sxHL2eoee`boBXKNagafY~|VyUpYFt#B? zjF&V9kR1Kf$C?lZtV-VLCDWa%pr;DVF=}qO$)^($x7E$L3OhR8SU&jR&f%Rfd89X=c61x0Fdv>25VXJdm9P#H+L%Y23W&)+>txqOejX zTrDot?|tdBu3fwk$&|cvTtC9dOEBgVoU5GsS2nLAV_!x7@)!r^PML1&-dODnP?@fT zO<6KgSF-lrZPq-o5+h59+8*-w#_0D5lCh+d`h`jhwqw^Od*QJs?R}@7Oq<}5#<T!%G^ zwJOn-wbAZ=D!;F1-SF7-3eLrT(?#5tucF#Q$kpKC#J~7#{f6Ck^pOW!ee(oc{nT!o zHKW zGcr6Uu(-JcnNA@OFpjdpDUJh;fvU)=2vZIjiY(Ub#yB?E)d4=rU+-lz7MT&4cEO`q zjoGcpb^;&-DC_WHiBtN?JQ`d91qJfSDjkrO8PlVHUI9{~VrhaK9yWX(`mA11p*>gp zkWEr@u@W{r^H#bTl_VQ*79buXFtCqoJ;_qDmh*l^4FmMT=$V7H6D_%$;Bhw09QW9d zbv=wnL@7`UXvkDoBFjdS2mIF}fhZw66faqZXKrpp`wLj8DPyC*kLq2>d*dO%wSRQTn$X-=5@V3W%Guez+eYw;lu-z4TRdreW6(do?bz31u zDI`vc(dq8!aP26Gmn$;K14Ri6&fpm+Cq*xu22Tqad}=Fb+=$KOx{ANap(o$GfnsAt zz&EiQ9`3=9)Geg=3c4bIMK}$)$^pEK#KsKu4ZA)9hS=(tU$$NdiwEm#h|E&^?t1{w zg4c_?>_ql5ioQGpc%M6eAp{HWggk4I33V}u!F`SaV#}Xhu_3Iy z0EQG+c1c!VdihnGIB^n1)&^VYAx=2sG}8Glw}q2x8JA<<8y-de2B91p>~@~IH#Tmy>+WA+hn&CI&OiGUQY{DV z@DE&U>mL1^ec&V14C&uUoQB!}%Qt;K2%s;eZ@4OxacNX4|5g11;7RvSUs<4MkU!l+RObh%vKpPPOgXxt4iN)$#}uBM9fc zcie5yKlUj7rFD?;z(noX1>sW?(H4j9sh@RG?RNr`#G$lfK$5N85 z@jqZP-(y|Ilj`NCZas()&*R~5-Ye&OYWFPbQLTQw8m*uNu1GToxL&U z>L4;+yvuk&T3YLnj^Ry*koc$xvTJ9Xee_co+EGUz&-D=A(myheIa18pCL@%{lZ-FU zE6h5iH1WzdC~}#H6czAL!dqwq*6?}6_6>BpG36%{n54%OXH2$(4>`hayX_9vsu<^k zFp_*Bk2fQRR8I414+%Tcc<}GK^9g(XwQaVxtKGIyi|B&Wj<?e;yBJm!tyR@{ zj2y&?R2rE9$B*$AcsDJeRb>1aZ-Mt@3#5wO-ZYy^fSo9*&4i6j*^^`~OS9>*&zrxL zO&DSVPa(?^RyW-4X#ld94Tz7CafV$C>544Qe9&3&(g0<4GXBF-CD{Typ)5%tDqdrc z0@N#xAV5BN1-YlOIBG-X796l2v-)aN90M`RfuG?;k23b@6e{S!FJ6Ek<~1Z=s?!l? zGt>1&Rzw;Ia%K}9Deh+n9Q$pXJawiuRtN3%)w}GkfBp$Fr+SykBn0_T97`EsB~GRl zU8fR2){B*_yHi=7Mv1Ygch<2af!!iF3c~fFLFcPj)$#nW*~M`C&md*#j<&5>Y}pL4 zG$uQG$^B1iN*YR%s(uQl~p3Pm>^Ei@+3<2lzNL7&5vy6C+Hh}s> z0=$EsO5`k2bn9EtS(Cj9KoN$V2>{GMGry+C)gJU;5BD3u+FyltVNigH%~+XeLiAOU zScegaLj8I;m@us2D~j~Y__4kM4k3xR%I z^(hpOv2$mK)iy!S0AziD(Q?jHLq+gmJSI^ZB?viCTQx?p`1WGCB#p2HF=! z$L7`8`T1Q_Q4Epq^DTGirMC}#oVP!A(MPS7*rE+&S^E3$zX32Ep^`H-agbH122U1Q zq0%oa!&>|Lm#qT87W6XqaF>ag=4sCi(o1I;fUwp>u2r=<6DT94YRp}(vAM;Di`y+M z!vt*|V!e6avUzsg0W+<-q7*q|#O}ZDJIrO;0gqIW%v2cwooZU>HlwtIvX^DBG?!@1 za-BF;*R#P<UO5kx!CpWYM!Q+~4iO`A0fDHU@PE4rjX2e0cjdt#MMYn^P3SiIXidmt;r5F!jL zfN(DaLI*Pgg8{`eX>55gqIhWrbN!4TGL=DCBeO^ii)Y~Xf4kWR{Hv`oP-}7KeKOY0 z>m3&5{{v)S7TgYYlH1^M29} zSrV3blB~m|j8^?2rAZDzUYG`BYYJ;#n3V9jUI-2IHj5#nLK*Pbl!jP$a`_Sr6tAh> zj6{4r$VMv^kpT?5^q3+$POpwd4{45%jXa&k;xA;%wFLSkhmbDYk0mg}&X`nSH1en- zfvf^;S(l**5rwRN090xI+1UV_(*2HY;#oGsl5n}s=$z5xxmOld;@V3mEJDY12>}5cYSYsZKQ=V9iGQ187ZcdQ>Mj6GZ#peiGmV^X~X^@vGh-Fl% zX-h~CoJBqnM31jA;*b~MsDn6%exz@T0m%UpWQ9~J;vi(<#P^@WeKJM?#KXkttY5nZ z5?5szti`hEigftsx7k?0a|D%2(&D5@0{MVtUBgHEWLGE?Z%(uv0?c?4NZ03D0DHkG z)!-o-Ate~#b$P)8fX*n^U}^7_u`EIYgycZC?O3+~uTMAbBgP^rJX5r3kN{x~!JF*SXTEFeUv1}^Bi1;nhIVO0zrTQjlX1o!fEr@| z@C%#l=|j#X-EIu9SFjnA>ZuN$vgZ2Pj{9`>0m6~`t>4(koNr;B0I+)FHhsZ?5ar2u zB+IRi3}idky$mStv;&FBaM|`0>wq;|)^=I^wJwz6iS;4B5)l$`3`XkcH&VXR#?=)b z`@*L`Xs4dC$o}%HAK6DQ{xY>lhN+jc#}arXJ;Wp^WidDD2zr!x)ziBRd8J~nTI?VH zxY3R};W#UhV*Jh5U$+8)H_jaOkZ@zlAmfi?G&N{ZGSIa)%2QiKKjm%TCHrBd=yF8} zKlH(K84GKzuNzMo{T9U#q2T94qL(W0ZT9yoZ*b%G;8~L`|GrbKk0A4Yl2Z%};B~Bn z@Zi;PvOVUhGDao%uMUq_BGYEI$gL(#Yr(@5A}%IvH~;xY+fHH##YFhX_SUy$C+EgX z#5%BN+fHkpSdSEtdnV9Y>xp=3fVn-5!0rHJI>5Y2C|eY*PJ0r0?F}jyUlQ3^9-$n8Yq> z;RKn#k3D(6TaPzw-)0k9npmc&L_S1tJ~4bUZcLpzgZ+pH=U&H(dop&oe`TZ7-(B5% zY(n!y2oy#t)&&(%En^LL2Yr@-OtA{^EW~d?EU0~f5ybBdK6?GCtFO1e-grF{#Tu)1 zgpTou2rZ%gXAp^U7>S}AXa6)$$F4B`?|2LR%N7_XApf#i#$S9dv_J-3v^S_MFQsf6 znhN}fHr~|($zT-(6vv!-4C|S!&>6J&Y`z(4UN~t6Yi*WAf0+Mre6D~eK#RKoHTau@ z3_+6Juz>`TR!QzvERMPy`p#t!c=ZEFm4PS+h*f48f!sZ0IFeOWOSzBS>H^3LR(8d~ zI5F_m0ZhFwLXah&ehAB`K%R;dYBL;(>3aGE8zEi=;3pdqM1}ti5%)j=5H^{#4M8lx zt`I6T^?`0=TKuh`%^`@2s`ADF=K(f15tbmJUq$Nzq|co| z8erYiFmj|Y-j4z<{WLCnA4K4^Q%|QRz^mqK_S)hlON^pRw&K;7Z5kQ4HgDN#pZ?Tm z?S{Wy515;2Jy-=3orBK$Swp;qQl&OfWw?_}Q6+5dg9NmeN0ADk%P$9n4?}cR0C9M@ z7gf|DY2KE9`5U+J^6 zfH--*L>P-`KRifG#@ZE6k%~wnXNl5o@-h^Vjfu=DHe--1VWr%+H0X>5fROCO{0;yp zCqozf(MlU@v9v-iAqJ8#!8J&MI_iK!7!QRitfwGNsu-Pwa41QD^RxkSQdqC^a+z_Y zdDbkRr931>H7&A?IR&BXL>e>7#Kk}aPzWf9s4y-dNIvSq=zjc+*8mxOa$a=&Sl;_c z5KxU(SqTARsXnqoAuG|i=llvF&p<-5c+0}!oK2os3z*!+`MG(ntD<}<039}Tt|80& zpuy#=oa|En>JX`Z`;b*y=b>$My#3yPMK<&yt|8F7_i(qtIrY*zPrdhj{glT=Gp%jc zus!j@tM-XcT!wcr0`X!V#CAeJ+o+DsoMkQ#^cT?Vi;zQ*RZE7kUrFMFa>m8L;5wTz z1;Q#2TkN&Y{w%~l%>3|L-?~@rv|~?)ynCtpleKlPZ?Gc{ImvE+`4+qKs$bjBuKbc6 zdhU7l{PGt`yDg}hw=>WEyd|+V`vN^&i-2$dagLuE&X)z$D(*@5t!FDT_HX~&(^d_r z>?9_sr)-YpkNv6@TNYaLEM!GJWP2OT+pfM*d*Hck0O&q~#M>b^n=H~&W1l#f!bw6zF{R4LT1)sM*WO*aRHEI4I@#+e*AN|$}#17ne({1*|8(Z*lR%1{IIN+|e z=AqX%AzNE&OHUz%Eb%UqbbaMNZl;a1Hhca-cGlTnvJzqip557L8yIh2x%_*0AoHXK z26z($eeyo@@DlrM`Nm#bxxU}xg%Vr;*jn2`J&xm#nPm6g|97Nj$ezf)m1Yip=tJk* zR~9WMkUU~v{n>SP!tux18+a6l@i-oYVW5O`*Qr#{rXoEnvR*0q#>}R$ttH-JJ~3LI z#Cbits?So4X%XH4@ef|4Y|~q!Hle1(Uf@1%x${}%Xr=Us3@aK-fNlC9$QV#$PJy{v zLOfcOIwOj=P}Zp$0{;6U17W0UGMFe%P3w=7h=nm=K%mM=pFOK_q22dVk8LfyX4_R4 zC0lM&ND`pfw8`~RBy2N|VCqwF)ExY#;}%)a*Bd+hvAyx$g2 zXKu0%Jj}T|dN$eA!2P!7g@;J4!J5V#)f((YHmrS1Mll~A*94v$F9fU)NnCYRC7T!Z zUGQ`%&dyKPGG7Ea9t)!1%BasW%yW|f1M(DNe=IA9ummeD&Rqwv)e(#U-UeVB1*wSlzzmi` z{t(9#LChcKs}5M8-t&P zKM+on(iS~6DRs4B1jD%cVFJ?a%W^FFgh+@Nw|PqXZ8k!%q_fhM0D?qR^gj><(wht$ zMb3FEf^1}Y3YmGxHiK!J4U^Q1Pk*aC#rF$vYCE*q7=F=vtD+?B3I1EiDaXbIPG@MjBOF z1L;U1*_dp*+Og>JOaV4Xqf3Gh`b!ueXzr zKZRiT2F8f!oFTs&hFBD=qdjZ;E!oE^Cr@|4K8baC!fcL~+_QK&s$LOP0opAOPs$^%sbQu2^eQ<4uQ9f0ccTnRiy z?bbjML2q4w-!7|1=*FyH?hbT*a zF~YN}CIM6%2^QIi0N;z2Hjunvj%%}j{^zZkGDa3O#`OXB&)YnNF}~NOvG?2hfWFC` z0z|$|RQA5@-g(C#|MaVySFo09q+|_b0m}_uRY6_1N4Wey52+lg*OawA7NEtvWo-?K=%{S?{#30*YTv)hXI0| zzm9BjJ9l;1X(ydw(i?^x|Z)E2D4o%H~JBSiI9?Ki&8= zaUzgqq)i`s>Lyo|4l{^*-ppXu%JBp~f8Ir|<>D9v`moMl@ZmG93~69pUAZk>w9sB& z{y0TXOYO!>dz}%Zv^q+x8`;{(xRxPkeeE`{t-t4I_7%Xm56@1H@$r*Uu328Ni$3-t z+d)>R^NxC$+81&A?j6tAtAG2I%>@|8V*QM{nEidLGTLDf8KB)22f;dd!!LhoR}+6! zitJFbsy{w`7q18LN-nTl@3@{ZNZ$o9EMY(r86SpF`J#C3$jT;}YZA|BJTZepeXOB? z=s2HOtlrBN0^&40Qqerd1K>J_0s544D85PwAS#eOMS|sc8b;jQRq_%Ek5q-ezo#3b zILe6B`Czgfek7Vn=95xb_p=6_vg`=^);GUqhaYpeZF%tyBy5abq-bjx-X+AHW$}sA)HKg#-niwDWpU3UD* zCo}e_H>5j}Tv%HNWVxa=WT7O+6N(Z=oA5#to9L}%k3+6n5~?EobQxrdr}6Jb0w|hW zhfP7AQ|1`tVj$ZD5%F3XYloMr^)8VE?V`BH9I`&>%UiLNxCqCO@fLWOEig_%-ep6L zf9&6{1^jqFQeArUz=~B%R;4V#*dAgr zJ&BYKPQxOo&%Dhb-0#|HJfL6sw1oDtfV2Wp9 zXM^Fp$_N!EYn2v!5s(5PJ>UocV1fGyc+vloWk)*hwA}ncKWuzXy}^0&Y&3DsjiC?B z2Km7oFapSCo7An@vI7pFLh){!J##i%@*dK_wvBBrfIdmIya2IKG~@tS5DR=dPZ2`A z5lO&R0Zq71u?dicJatfF1aG#Ijj9shRD=YiAVtasmct@`-L-!Nr0)lCS!{2-{)TmS zba6jvd*Hr%ZU6lbu$k!3yLe4$K9vzhmPd39SXChxk+|i^1U8Dc+=n)~xoINOwKORo z2MBtk&cNLHHq0}HvCyT{v^C^nD)K7e99G8&RhsJo6Y_4Pt*x!o#Y!lHPC(hFc)gTO zzQ3ynViv}m(r80?Y(i+XeWYeSWZ9wgYuc7B-Jj29NL@+%2415QBpY$SWK&BE8EBBA zboT(H1Wd*r(cTGAb5Zs-Gc&7U9mo_rjltCklSq7xETo`V-Jh6WH$<& zk3m#gnkLcVj0s{}GT;%v^J*|E@R&7Do@Vc#GK)rn#6TEVE`Jtj8DwU3gjfRFPb34f z+&X!NP4dqJsDnrWRP;LI7J2|7PG*M4WK#iDp^`bEr2-%@|xZ zjAu+)*@_U}JXU5Oj_1Q|3&vPjSDaeb3q`0mRL7kHwSMXa^o~oV7rny%4JS@Q8isLo@8OPh3E(&lcLY z+y>*5?eeev#&&M)#&b$Nj^j?WZ~Wi~cG+c@*mFpmnp;oW{ z*92_E@|Ct~`7^d)zk}_bhiCLdzRnsR?|{sbB~PBZ&d%L-;Nm6rV7Lbe26hp=cB9 zo9v7ae%=`@S|_(!b>jq}DDo!;T0)iE8Nb^%ZFSz4haS7rK6Bw^cKP?OAVb)#q+H-|~HtN9uz(|XD^I@ZeG zLM$I-5leh9N_Hv;SfCD12J=2q4k1un2|EO9-`G#TJmL)PG~_aq zMT*K`A7%`ukf$AT@IH3)4foq8KYbP+?F5FNq8+;Q4EyaLuEi_HT0ui(0Qr&7s2y=Q z5)m8eJnu)w4smi~>g$tq4D2ocb0804JgUVq6-=RqPPE3LpK z+Ypu}Vn-ww0uYC^VF~POSK!DX$?;{$hQ($h;DpzlMSjd1A`+BiV+#=EsLhx!vVjt| zfNMrE0m^DcoQlBje9!U(1o+X zvWcWhXsmA7KI}+i3$f)^Y%JvXAda zvH15}6l>`4z_645_(ZTIX8}+t81>+TmyvztU?dCu&ZDz?_b%!dY_~PU6hz4wr7W9O zw2z)~B(4;!gIHv10r#{QpuLLV$U(@CKSA-l*>hb`xr!e~@G1?GNoy1`5&@(H$^%fQrX)9q2&B^4Gmb0*~9_uX~=+=jaWOe zs(-)VfF0q~KD@hbq7_>}=OBMQchjKzAlofi_u6ojEyzjUI}eOPz~RMJo6mMz9bp2hOov?vQ#OA z1+XjmU=c4}5evT@d&)>upzvi9Vl@Of8X$v`{1f0S?gRP&SZ4Mx&Y2Ss%wTDYJ@C@2 zcIJ6G``(QY*fS5@iY1xCl>WGV=3^JzY41Oss?)R&5`BMl!WlE|hF{!b8(v)w5JTU-rNe&rqhHt|Cmu_?@XUZ%AA?B5 zN}jxb+C~G9eKSWOZlk?fyXQ}LLc%iktKa>NtZEn(Ab;P!?85-K9e~CPCksMwM0X*n zq#uJ2DIc|csFDMrV*O#P&a9t8Vuli);W6d`V~f5HAo1DJz8&zdqMZatmlC9`F^Mcr zF(^gkG;}7`4`lm*T>;GbvlakIDM&hRo-N#Gwmtjka;^&rAxoPZp!yeSCtTFR&Gl5~ z-e7a~n~5B9vZdM+*0S$B?vWTbtoKPIn-T8_p4@U?gBXR0=jt3FeK)eM-a)(f?~mDu z$DV5+JMF`E{SDV6QKZi!j4isoEKST9b41p9580IR#9=A*u64O zMnmlb9M?KdOq0CWN|nv*b@NTNqLg$XFLI4{#aWTGRzr}g@GiuOq46`g-D#Lsw% za}+@md2)x_(zJtdPLT=zrzciiOhT`z?O2D$is?f3`OGL@^a_Zu9xcmU4@2-7Np2_f zBHK$PSvSUy@fLWOEx;}~evG%kd$R>Pw(mx|#Nw&oXVzqSDBOf#gVu(Z18B+$sBA$l z#)4*&%*C7HQ(AxlesWglcwfPuIjp0~oMQxxhN(y4XJghT?+5g8GG~=8NRolaMMR?1 zUj~*1b~$o@wOL?K7Be=05G#C$&nSad9uOjc8HhkASnP3&xDJ!{JOxk?K@nK>@L73i zvTPrDtb!`gmR0e-bO`{MjX~M7*Z}KDqw6eqJVcqi0Gz%X&9&0zX4!P*F(_4#G}h)Y za*m-9fO}bytW@ZWIcFN6ti8Dd?R5Y^I!Ihbwdz8Y*AlY<$-+a_x3ddkFltk$Otpco zPW!-z&a<2U@mIU|&Te-OwsEdI27=`7kY)S*XP;w_JpKSN+DK2>$a1`2jSNaqD2aDL zh4_>b5~OB6JV_OG%{HPG!~irU2N)uLqQ0@odbwUT717-@(obao-Z-)})#y+?jj|kB zq$E?Kw~?)5ZN%aU*bddu7PR%2?OP#rvdsGI$tRz20h%Gms1HlQcEAAa9jd3FIaB_0SPnHj;u)X>swC!Tn!>p#VQG&if}aeWz7OyL~zppq%=glrG>fxtJVNiN-Rj9i*PCUUgSzv>pb4Wf;UDXy7hMS z35SuPD{uA6rj-cVC6|8Mnwvv*^IyLOsf^(5!K;PLu?{Z`aM6Bx_0LG@+~NrN#TWP3 zbb_EWeOv9G>o(YvSa)MQcX=RgCmnr?O~1I&{MA{z`Oe?cb|a82JaR~DstNR-J9jbO zh@&Z3*=Pg2x8Ki}QkbvCCSZC03^JfOOOLTne)JQ_ni5#mkuaVADO)gavHk3)KeJkr z9-Q(1vuwfidW%$0*_!N939`Z^huZCnU%B1tsv97UB2RcC=${EKrM7J|1J0Lp)#cU6 z>o%=-ST#=j_CWBSdHzLPzJYj$S2x-jXB=cRAnIH84A`%(xRJG>(fT~yNbc&$Dl`ng z#G;OMU4<)k5?P#O!pIdB%hck=P^Ntf~WRJ-Y>yC4L0%z+rv9z0rNsT>Mi zu4I1sA!4QVjkdFEfTR!gmY;W^J-uZRZq{ahzWG+0Fnc!RiJ8qBq%2u^$V4-q$OK6k zl6au17fxi}g{aTN`Vxv7x$SHZw2IrZZCL0N7&KCNE~>aTe{vq;D0u!9>ntt7+Jfh? zoMN1;F_MRB&6fAb&wct~&?%lRM&>Nt_p)WnZ1w8ZHi5OQr>n!Qt6s)T8TTQBQ)kCE z*S29Wz^H?C#Fgj*~_QYVHDv>Sm!IN=Mx7v*}n9(-`YAd6UGLTc&H*aZEgvP zC1ydiVs4G|U|4Bsn#1o??W#ZA0hxY*v5>a|4wz<>r|d^D!zY}#sdnl_H%2ndLl=WZ zySP|Jo<*M90DYLkv!hy61=c4WT0bhxWvxyiww> zY$JoDE!JKcl`N4I>3+N-8kdrFDINLvG2R02wgoh{#*gt9cu%%KCXSn$%r)5&Ey6^7 zu+ilJj6OUC${>^_HKl-QfyFn6hFJmTMR`N8JQo$v$4_NP3bC+j(*ugSzvbqRqvJ0{ z!r=)3e3Mv5@en9GRvrttJ2ybrE!FIz`mS?@v-m5gz5b_NE(e*B?ygk}h^mM`j8<2XDIm&O)$C&^6Z* zNWEp#Ha5W#HeO;2$b?hhSdJ`eHrBcv(x~0kuGr;@u!*hc9y_|ov_rAMnKPy$|0=OP zZ9Cj%+W?p@rrE?vo!izf$s=8@ME!N7wv9liD5$8-T^3Q14{5iRiN>|D$PBL?bEMz|KD9_3B(caEdUB>gvE68_J z^iKv)h9p1{Eb|%SPc)7zt0`WFduZ3HrvY>UTXy8xws`3Yv{4pR`OYxod6ujCR@#(!)G1qL)|pAQf1w zgyi`FwFQ13ruNLF7G#42(`sCFZQV``)I?Wsvm{(gY{I7@6cqqp2pE|1ieLQJN|9BD zsdbT{HbN0|d1+*-9dqhOk%kS^7xfU%6#d6IY6{RU^~4eFA^^BXy@c$BuA>%8?|@Ra z){>6fV>2tVHtXma)*SUi?7TL=vD7a8!U0Het~DRA00f6&k!Nhs76O4`Z;6dEC%jna zT~<2CNggkVj>$*>`-nfNuBfm-UG)?D^)CV0cxZq5;tEHg<&P?2cyJOSz_K$|&JOrJt?qS^)6JCXz{{1wqf0Rw^o;u*0`41Jww#5812Up z!y3p}ToQ_h9=eMfDAP%)+>0RuLaerAERJS}3A`S)6rMhjqzc+?l>QwRxqwJIQm?Fb zv~7`qZ6zBiC^mvgr+FQd^o#MF%S8y<=0mit7qXYk4ANiB0nulOwjT?P)~SKcJ{Mz= zA`ax{J07v~KJ*DY{?ub_^-GVDL2ZY%Z+V7iCO{n?mc=Xf(lg8f*2@%Yzemzb=7y3z ztls{NZR>myYY9bES(Bf+AEOX+-;Y;Ap5g=cInXw5Z{ry;e(`-(clYsp?x0OX@=ED< z&8a+Xsd1%4dzHNOx_24d!u-CMc*60MO*08D*{zm-wT7b5lmd62AVAvP#(K`2H4@_9apM8L_b z@{joXN`*Ct!AXK-smT)(*k(uxYmvAYGts`v3>EwUWK1kZ;843&|qz zAOLP^2m+Uvq5@I?1#q5)xXVJu#t*2E_{z8@wP4ql5Y&M7a6`fmX3btmMZgbX^> zjb)q<*#ZC~NYHsdS$VwH1CU5s16~LAS|kj4JN9@L>|p3xV{+3wBVWXti{S)|ZS(YGQUA_G1$YDw^*qyw_x zW*{E&xFjK1N%Zznh~WqxjH(*OqDZPTFd-QWLj=^18k2bu6v#!2zFTzg;f!A7A4pHS zNsp?e2qKDWu>yNATPkrtm;l<*iDtso``l0qL8L16`S=44Gpx>f;5#5#=SmZu&|F$(Ak!XSb?PpQxu!%=B#d3=ap z#!`boB|kv1yb5qs>h3R!oK7CVay)2xJ|j7jj^S9^-h5>@QXdFWNrQ?5kd9QjY{R8~~JRhF4I>u-zUpDI<8ldpzfX$}DwY*$8(5_;LWc5~{ zvSOEFc@VA7(%qs z_pZ3sK61es*4RM27Wes~b3RGR>x}?euh#p3DwC z=q!8lwMQ%)CjB^l+mE&W9I|LVw=QiB6;;+9&)Az74r=F|O3}M=J7E8rcH3jC2r|cO zyQqw~njx!aUC5BVE|wd%vzE@VYkv6)*4!bN!7WP`E>G12n{nL5pz&rb`G9Ra4dLN# zJ9)+gi!wI*x?i;!1j1i^^|i!mj9QFwqH#pyI}%qWk1XkPS$>fhV(?*3IqD{(Hy znaB&z9+0jJ1C%mHC3!7WiC1N0$c{Q}DgD<-QOz$S<*TuzubT10n!q}*bih+nD=fws z8|dF|rNsN~Z0oW9MAT}gH(`vKZB_m%n+Ty5Nvl)}Z^|o<;NiOKz6b5LyKi6(5>?=T zGF-4exV4BeDi1~?g;$;D&>pA#N&AoX7`7tjOJS@Y5euJ;1)4BQl95LpAkyN93O_|$ zLU?g>$k3H%TuUL~N8%`ntkTGjALA|XZd+h{w7lDv8voqCT??=VBU2$$2^MA_n}?4K zE;%-RKUN$cmSi2s>e;xlWU?8EWbCyZX_+5m8@Qg?xIxamg7u2;2n4A*uB_;iPYts{ zDW|%ucnK};98QnTPnY(U>&h~(L#cA}WXsat5G3$d7cT(JvhBV~7J0@BJ`y(;Dkw%4!plZDsmll^`JSY3lA0V%OoTYGYIzLzciD=U zUj}40k}L-h!C1yX>!fqjAsdpn;fiurT?w{}l1K3T8NidkjtHzWe}Tzyo&l&BDI;jx zRdK$OwhZtY5SQ)0Y?Dah+>7u#8Jo3S+`nmS~UtMRHeCukegM&=DH=3NW3t{E+@pLaTBQgR_Y9P~7 zsZE+*&Pn1Hj?sT;=gVeJv2@o?8_D%q8FHSFf9aQ`DXxIH=4?>4D2RC=Nww^{qE{3?Z>~m z!i~pDq@9v9W%0BKkiKy@UPVa8(LH(l5m)RV++ar$uwNv`Z4`q|2!o5pOO9ByBJnPg zKPq-gK;IK0&O!?-p1KO==udw73!8S&b9VJ_zHh$XN368xb(@T=bLTVNtSkMth8}Ni zsl)RF;pJQvzB*)7cq#DKg@Y-3{FXo1aJt`m7)t}J4b3W&3g9inbJ6}fvzOtf_St}h zl;%d#MZo@WKkZG5?w6WaCu9UkIIm!owNoVf@!xz1uO)4Qlr~3OO`Jl3zf$HLldEU* zR(o~lZjwtN9XVpk{QRzhiZW`+5FrDI+w5p>tt&-& zM=?w(24?&iZ-IB)0*s>ZW4s04n=O!nROHyawV=ydlwqO8NzG3-7*Z-msEr`xSYTln z9PnecE(uit;!;=(k*NT%b%aWhKjEeanYq732DG^dMr!qETLAEBafgV&9Aq8LA=_Zp zW@-cJ^*W;W;%vdq-mJ&!&QNm9yJEW8u~lT>Di0L}{B>Aln; zNTx{1N|C=)PJJJnlB8f{>q1_UKn`)-X{R79B6TC46X~rLFAyh)TSfe2dHc)Fe{=Oi z;xTmM#8F66zbTkMa||Ie-VE1j&!2Wv$H<0B{~aek~XXsSF^b9^ltL z*bgbB71=q{TVpnD#w4UTScJ*Clo$kjsZH5%lUNUTkiJ)a*wZ~^jno#=_k55OW&Ki& zg8)J`GNxWCUB}V#R{%<*$T&)`y=aJasavh*c@&9tb#QQ|}v$LkufG6Oac$rTQAQ!1)A73C@QMNZzLOxV*zq z!g2{n^ODBKi&x3ZJ*##^0xy$~zVc%ARLzzWVjmb<0DO`zNUDTIG|V{g0#wykvVJNv zRR%z;VsE?K+AM;+svo(Rs;%>eRT3Os@YIlgGvdSgEzah8zNb z+`BHTd!eu78C7C{Y=U+wMtLu4Rr0RzJOY;@f%1T6kjjW;>X3(0(odiwfEG_BGBJ4% zt4ird4J-Ojh85L=aT+FH71^Nha?xf=POdlyMu$Gg`p5nAIWIu9Kr9ssXd()T&~ z(HUrHdyz>Zv5`ln?c}5O#rOhA8`xn3sW$t-Sy$QzX4c#4SJv7-2kmPc*Y2`K`^~j4 zed+Va;zo({f-r>0ShsDL?OMMX!$OUF4smK#=KkIvZYQAqFZ6%E)s|MK$=@NE+02+U4cLOX)s^LMKEeTB?tCJT(A`&7z ztAJ+3AIK`Dz+|PERDmoH8=!Ri zn7Y`oBrigPTvY-v=8o9>{9Ir6{^vhm2c7|J2sC5a(^DtV>NgOqynytjZNz=dnYX|? zsYNgfkRCu5FqKrCT|H#J8T2DZNx5M4p}`?!P&oik*h!YkAOSDFvd$LmzldN|sA1D=UA-4z%WZ0HJzZ^LTX+1gjTI5~{z(xk|LX6;N zWi%5}Dxpsj=z*#5CSHOi0~+~ws07`Z+3{W z#I<}_X|bRy=|TZbyksRx$?0|4a!Hk_R?RajeYHr2uAhXE=n!ZP@XVA~B=8ptHf@iJ zhwnmP=+hEpRL(~vd5AvCxHT-sKC%ks2}su5l|{FJOih8YA{^=)k$R=M_A^g%7!~B1 z%re&8+~nL5w;0(2THl2EB*Jd!CfCo%oItaAYcCo|8-j2Bp?87p)Y?SwTO z<479sn(m2`=%8?{l{~V@Lz#n^S|UsAxzsLC8ZsEdoiu@)H1+>e+2xE==tqkl- ztrNxs9x5MRuY}fQ5hVhrTS>Rft9JFW-`UOgKWveji98Q$IW;&+B%dN|-DM^kwu9g(=DYr}(GsYuDNncdsP519g}n6^9>u zf}MIo1zE|;kz$2y$IcD*;tMNnJMl+(#DU%%SBwF?7G}=k9(PUXXB-u|ha#Rs%?Tg#AeY6<+uGpP`%(-_W#yI5Yw}u0zrDno zUCCOMK>~REsV7^R)&vH831nq7*=4KW*lF8#v|INur)SL>&2=-s7{8Er%~cIgFCHB^ z=e?yBT!R;wgKuYxbayrW&v*;`zqi0R0r`J#pYeD9om)VKxrzX8-0)ga0s2HL4_Alogl#*rkF6fcda6=kh~iBn8WptcWhVkgTt4Ad+0Eh*UyVX4&Wj z@SL?7P@q(a%3!5TLj^YHy+MBhAChq>jc5dOYL;v?A%JNbP%gmciXUQmB*!Op8(8dR zT?M3g0icpz_y94=)KUu2WS3=Um|)j#h}$*G&XD1nD!?(U*M9rWAAjz8waD&KjR!)N z&YS9+2{hl06|PFZ-hTI8wiB7u3^G6w15I!-MbMCz958{r1AEo3U)x*re7;=<)%*ppYD_F^de!4|$0vhmg7XZE#e9 z;6755N{3H%dIIVzseC>Ps8(UYD!eg$?N}iJuoEXvw)VarEO?~Z#WND%+3IVXh~Gd; zf(#@H2`$BoFic9{1R0ge3$0{=w}64XNp@VupXq!`qIg)z^|aBK*>Isv?lVIP)S1*I1q zSm1H6YUYrYNOmPKQG>K-^{eX$?ylwDJl2TixklO0L}rQ=V?Ydx>nLO}k8Cl5x5nd5 z@VvAQfyc2pZ2$;~Ag2jJ1O<5IiBLPqY^w_F5rDD0EP2{7OkEdAy^6G<>JRwvcu59B z=Msw&*Q~K}`gjyCmxxyiGN-EZDu|X<&^nhDsq3cpL4?AL0&msClr%@GFdE=Bk))8Z zC2T!{S4Zn7t@2KxrX9-1I$0UkdRu5SX9?EGfr7E0EBcsb2{YiLv>0-E+iXtgob&Y z#*(b{r+^0rzRVf~sYoOL!b|Ad3h%12lX=MsCHYf=U0Y&L{E4pkrsBioy<=AJj2Wx* zPas9|pd$>jUI$puaw&)j4Uu6CR1}a4GAaOaK#jlhc+iS~PQ{oMQenm#L^DEvApw+! zF)-9i$8kRle-HhsniS%G8iSe#S`XBwD!xdE({_M#-5K-AF%I=0{cWB&=Z)A5ihw?F z@16F$Kd!Pb|NKsS_Qf}C&YW2`ZF;pe5CA`U+AOT^c-{()jG>J6mD1n!Q|;y_H`)kE z88+ZM`; z>$h#jqe{?z55^aaD+$P`!u{$nLgaX+I58ocH@-nVCgi6W6l6qNuyDHNAvL60U@Ks4 zWbUL%?2yFU93fS@v};ORUXLfY2BTG3@L=me0{ils=k2sZjwda%+0IzE{q>GJt$)`Z zD`#$$^SRp}c+nnz;bvSv6}DpC{nop4z?M|)M?ISp?W$k?6tX<_yn1GgG|lVQZE8=% z2W;s<2fMM-xqXX$=Zdcrn>TOePp`b;tWK{vRvd9A-eC2>}02c2# z`3ReT5YQm6g%{waL!eC7Qdw;!d*PIv2P6f-k<4QlSwNU{uLWG`#X=36A0MdDMuzl8 z7AOUQLw-WR7B(TS4-rr$bOo@x;)t9_pif{g3rO$-lnUHq5)E@%v_C(J{BtWD z*eJ&`c-mV**4wx4Cg7Pm9R!4?aoNO&DLRK2Vc5J92}qO73G zavub#k(9Z2+_}3eYM(9uY=zAQ+Et@PmBv>*`=smRFYPeDwF)$!EUb$)J=$Oh8j)Oz}kv7B2zl;x!|_MKT?Eazrkn2gK@( z!2KeOJBS3}lA&Xh@n9tY*4z{%ml_!8^n=JZav_m&fG*Mxe-?c?_tewb&R8J#TXB>+ zFvt@D?UMbtl*E879t#kLCrLobT~{EV`9aK-2d`5A(&M}_^psyQ1W3#-Sx);%7A-&W6rQsL14ex`XEU3;cF>Zk)9h1NzBAhpQli{$9l;^}iGYBO=5vcEz|;RI;mdE{m+{H>`%^^QII#-flKa- zwGsb-Tf4>_LEOIxlJg+zzKL_mvR4c^^C4 z&OZBm+d!J*{+hnK%D3VJukFhS?{I|c64tm&Hqjh%m zw?DynC-n%)1>W45u$Lj!wT#D-l14l9;}<~O!uIHs>sg11LkW{P7EYitTexA3U_D?kK!%( z)R%tn)+=UTJpXHN|NcMYmyi6X+qmc>pZ`yP>yNWe{jz)QtRp`0pWZu)>|SpjdTfYq zfK7LW+Z$|dWy zkfZ<_D4k6ez>vjy#&)V$4a8Jr^BHD?zmqik==;ph)1}|bo4*Da2lNcaRpmK;!UuOkKat;;0()IWxgaZJ`@2CTi zSR?Vl(i_A&t&B3TCTI2J(^d?D{sdq!ElZw)sf>(Y0CQp%YAfn-SSW_XYc=J_cmOgj ztu06nV%A1A@-QGkS*k>^Ko%BL+FAhAK?g2mBc@G|H&g(q%OEBy`qzawLWeZKOP9_C zC}EX@cx>CVoy=AZ08wg306?2sCfnf1h~0YKwYF&CY&+!m6RjEG|Hj63HfPc_dvVpv z?)iMgoJ>Wdtn|SV2-MD9+X3r*KgRg3H1PH;xz#09hqLEpd_stprU(+1OH$~ z?mKTyb);GC$Pl+d@F&*n9y~ot|5^nJX`V5MI1}PN_#5bBJF%{oP?CiJ-t|VC9`2nX<%5K>c@GndQ%x-jS+SMWAgrKq zS)uv68Dce=Bmos=kP_0z21II!DG96a7|%3zFp9C-EBLvfAXEB0O&o}bgszuP573S+ z4k0Pq+NxJp+HpspKyWbk4aiL+4;cc~i$sBNv1bG1B`<_GSCtfOT62~2R;W6CNLogY z0;D>@m?_}dDOELQX~F^C@<`~p6?=i(j8DqH5v1Zf5ll$mirk|YVyR-0A=-NR1JB!r z`){;LKH1;C96~s3{jXC8hHE8LJ@$}1eT?NWLEakraXc8x6cupb9r6PpcF&L+0$7%D z&!qYV5FhpU&)po1WQK{`sfKLvWoB?0z);>gCL+L+!0K=haX}DL=0`w@3n)IQ8YA3_ zy-0wxsz(PED@K9`$&dn3>f!)Uhlgla5+O8E*JSh7br$A%611P@B$N-r#ku+2jRU?b zPpOIxiVXYkbSlh8mAyq23!)5~gNzvu5-}gwa|K56l&ISL$Id_BKJ=jr>>u~NV1K%2 zqjhcSvHHl%E>6aeg51(6NtNU4lyroFlWLTlC@lf?=C)kGU!S>`6+imKk{aDD- zJbxdxNj`4*`ib@<&Uw&Fuh}PQol3l*9@fcNo@d5t?!^OGV65tp^vWG9hCVS^x;syQ z=7{I=bInT9kSDrV+tKHqYqJ&}W`FzX6&N|Rk`=6iG2Ts^SM%)3F1Us{IB)6%yYq$h z_LXbzvu&$3F_R`)3t7X8NPxVFJINXqw*+M0mus+lpSs(+JKnVJ&aF0KVv}8Y&pL}k zj+%NH6AcsGJe(Ztwv!Giw_9(%+a7x63H#1fKc!OqGpwmvU0IE}7a!{&!-XpFX$Z&< z?B>Nw8H0?kD9J$}Dw4)&l`o{VHfQYKd+u{%>!Oc-&c6QT|G*;`r%2|Zwwv)8L@ubD zByDZGNjXiCLJTT{cw3c1IEdlG6#``qb$bo-P+k#Ndk2~0TMfx;v<~m>JtTc|lhnPy zo7|1={(rs3Uwlb>#NI=H>loXoB-Yb6FpaSmYwkN0rB=Kt1S;vp@7TDVYW4p%Qzs7%#x4?U-1>$4|(MGD&goRQ77g7jqu56`j zh-~(<_BtR&Mj}vcu^@m7EYO|~1T5TTGYGzai?yD$Q4zfx6U$qdWVjgDJh zkRon=Wz_Lv@%FP(E8~2a1zqOnY>JHmSxN@&wF;?)0d2rGEW>Pm06^)0!TvVH?~-3D z3zG-ZktDc0A}NbrWOE_0EC7(8M!wHk9D&isp`wJ@1nFe4j(TRzq%w2ZUc>Xz#75G- zyUURhFQ6boHS#ytZ6%mFV*ActU|;^`H`#*#McRqDPB%fkgi=2vFrdl4et;^2}tg=|#$*Y*3|Pyd;pONCiRobXzZV9U@rEOFhG6 z-Vp&y+leQfM1P^aIZ3lbM1V5=0ol5|aIYO!{_8XZ)(Z*6J7(-%eNg{J`7pPyiTWiL~*g%A>s-WM}1Fr)ch(NiOBJVrxPr^1&ck;#ndP8Jd@SCNRGo z=7@e@^-V^pt1#5R$9?9PKmLv#b=1j_7;c^OWpxiAbr*L4C}MIj?wPgBLC_H%B;;EV zF$dA;D?f8heWC047~k9=J;5IwN-wMm&x%75DWb<5_*20)d69tATn7&%vM9}26u>sy`H_~KjIpKouqmZa$NYTP=V`zDcfT;O(NQ$NO&N?LFlr%9*Ha|bl zghI|Jkzze-p0<;Ye}?|ad{cKJ8RqBYT;CkAVvS20u>n|v^B zPmP@-GN;bAS8dC>6_zF2RcW+|0f!8ew(afdqF=BgvBt`vP}^8%yLasXsJGH45Fb*D z`yq<7D$>(lJYIOtlLf{X2|qB3^szoPW2C7d!`aAy3|Sa}B>!WjP+X6Q_%JbKRVv`g zH5=*)!Y77A$v4)mU+d(IS!)06q%M<+q~_?)3^7@gDA<`Kfru)a53nxPQ)@}&IE(@y z$WIZLWGs$nwx4yIF(YEm=i4c^sQ3?>&3?0P4Zr8C?5f)s+r*xP{$M}90i)9a`|J7F zcK7ytyrI6~Wj9#H|9MZhz&HVUPj~-&`{DhD*%DBZMxLVVGRiomLjkK9f@=MeL9uxI z73>O-Q>LDv+cYI10b~IVWI@Y8DvDZpg|+}BDpUwR;cr<}*%GieWwClGcvseFS&MRP zW+F5ZfQT~u2>d7jQ~*!mu%I_K1wbON52%VRo)rbe0*@{1ye52~d+-a9VV%rk5mq5B zX{e-B*G896RlqRvmij zD&$5YX3{+u0fK+O?LnS9W2-l;vvW^B#a1qV(GEZEV0-APS8ewEX*}yr2m%4lqySb5 z-ytMI6B`=npEN0fcUkjQIyUIM$(4Os$j&Bkq=He=EhfqfP_TjL2(E22zdZ1$_Ax40@=Dn)_nB8BvX3*#N&@+9C?UE7_to; zH`pNhdqxKtxfoMeZHJH$l~e3(zr_mx*8p+GmUQ+ymk&>Zh~+a+J#NFuja2VspdX1F zgjpHBO6c1ok2soCsDNJ1yLSDX&MUwzad$guV# zwH}T?=Ka>y)y4aK4o{vk9C0T8W`2pRLa>#2&Vx510`XPsl*oqSyhT3f9xh*GT*Lu> zgJiBFm{{nU@5?I?qJV=^8zm}8Bdd*vTVkT7I{vOn7ANIBcFX|o-7;6{PV8SLqeImN)@dby%EN;7TpjY8;|0)SeJ{evr1x-WlbaihxHeaGv4qZazt5zdXS7= zcKO$cSKHqf&s}7brqt4BahpGHK5Mbh5)^c-sG4N)z#5E6<#-M7m{LW)hx1AHE0 z&s({S8cJAD{PiU--AMdRe z7$+d_t^OW=+IO^o7lB7EH^A;Lp9gy?!LI_7$^;~k$-mCpsn`J(#q%M@l4S>+%fY+O z(v1b4oy5zk>|EObEd^^zLZSK%+UNq_a(w}-695AMlZT{Wc(X9qC1DA`Ue+}vTv)B7 z(BV^jACiJMB**3~@R(qOQLU0J04xjeB`}3+;^p8z{G`h)vOxk_(1;HM#<1QY;VMe| zFAAer0RUcJDH^#~rMOj=B0nC0o-I3xohW1D!J36;xjaJPZz&(cyK*+^DP`sT_3y3$ zKV@xq$4>j|SHDg1u>sDXx7+S~$fnJlhLo(sjwGGt*Dt@^Zu;||t&Pk}Gp0=@qZ6Q- zqF$4bS9MWI{k#vK&m9KrZmObhruK#pYuj@x*Ky8IPzBk@j`KSAmT~bIemoUXz-WxP zloBk!S%69&i(LjnvwcSgq$r7n9%zX$UO|`BCr!W-U$B9-{VpD(y^W0#&^~=qGXdox z(*4%hXy33+A<(sB&u-#UuuyW%;3(;NOYjH)0E(a`RcKcRsygIb0s~Jz^@O$Kv5C?? z^NEX@HFp7k6;Q=zo`3QQXI<<=g0SD*xi)+DTtKWW>ZFVnP@@k8a%C}hIrIr)_Y0wznj;&h6DP!*6|zwQl)V5^Pbad~si zYcB9u{h|PN$-g8YYumCJz%*sU?{+s#WbBKhGrNd z$_U2-UT$4`+5ur``~l6?HDwf#+h8q~&43<8Jiw!*j7sPJgw4cb(GupIl|Hf;0qiyU z06(fX;uQ&(M*)(n3{D;ufMdiKu%OF3NEhN20hIHi!s>m>?m%dMs9fH(ghe4#s{0{g zP)bE}@T44XBol~&`+~N5%LY65f-@PnQQ9VN`z~2zGp8?d=}6aaeA5m;=2+`~b2AyO zVm6t&Ei%?uQR|_$wh^ya2_%6ac_y)9gSvODu_^+7IT3O!>d=q{Nii`&=B8q;`n&en z4cGkz$&%NmEtrRFsAv~laG@iWdVnJBucv}t(pShFd2Ag)EbIZ~Uj@LqDr&pB3-rJH zNo-J7b5>2nGZOC2bB!4}l!*xYwTn;DdctW*%}csq?oUn=#muPgOVi|Kb}Y~7RWJ$3 zFb0Ta3nI}IS9<-`HC9J#Om%gglTwC>X(^@O3Nh9X0Ct2Jv$Bdt+Ej$oV{1pc@OZw& zoLy+05XO4Ooj~$7>Q2=1EP0AfW+BD7Obi*9k{Gadu=dbNJOE>xHBID0Qh_K zwUPGizwiJ%{=mcRbC-V6UU>dBn}Am|&-|Yyc`N^y7fPD|ZYCqEk?M+r#?hz6$FQ?*^Y8vo{a{n$t1DVPSc$t)7YA8YbLrx=* zbH!}sV`TOsR!~9tqAn<_Y}1yPY~z*{ZVw634*h+-_S&nj+a3%xUJ_KqdJ@(*(gQJP zv@;(vkWOD2;|~&Cu9Ue+JTdYNLVSiuo)Mz>lq!;!R5oJZ@=+ufZ!N_#N07DFFc+b$ z7#jMqJ4w36eXxm)&>MC2RCO1D;q#I53g#7km7qomYiC_mouxuIitO+s_i1cf}iSg4<;ud+8qvf^s_nWV#IAXaCvI&+_ zz;)-gZrh#OV-4jcHmQqr1UrFqrH>M~hr)6^yl;P4@_{0Pf3)tw92lNMDin(bw_V6mSKX^0qWa#b)g|A<4JkM_B;3>u363onY11@#y+fQ z8Njx{LmOTNS)BtW5- zK=eHFvJy7m0vUa(u&%Z3*on*wAR|zXse1qtp=>(S$egtUS%+jQ*^X`q!VIk6!$`WS zX?%5%WNagr>7n)o*27XHC{f}-l%hC89hgpJ1|K@}boaLcY!yH(*@EhU2(TV@)G3;?b{bq5AU36^^m&Fny4R!N~ZKj+Kx1;sC2bkT+O&;t+AR%Bp8I+f0n zF$WNpmc^Q}I7(ZK2x!jE4qfElE5@-AG(=co^mVX{u|s`Uw-QW!`}_g=VKRS4CZ%k>X)= zKU|a)$y4lS`yJ}${@9HpCF*I1MBj-;_k(!C$}LISXnB{o>ackCpc9bK8j9xeJ2>F;CN{(oZ5&DVsKNqI=}F_AX)~;0@F)N)Z6$ zm&cdCb!e>13#*^pE(D0N%=37;PammnBY1Qp^45~vBgo(P z-S?0^eE0pPIxe62SolJ;%%)Ub6+KEbB4LBShW$n zT1Osw2n07o%nlg_iNPtWCY5&`;~H|NIGiaHl2lr+ww~P?11H;l`!BVcmP*&g88YZ? zq2`E^HFV*nXsSNi9)9TI|A)Q*fU~=-*1zGkdz;=%W+pu$jSxbpq4y#JDvF8~M8S6K z-D5*ktSBmiN>@Rufb$5UE`bi=V*?0j3stOzN_hBe7f9PWs-5bYok-l|hqmDGQ(Zr*KV@~Q29Tmcii-CWy-~P9xpX1ck}`~Jm#0B{4)fZe@{q_~ zQ_j!cp{#X}4KRFUAmAt>g03+|-FK3pQmE;nnn#493CB)`eotaS1k1Tm907UmEy$b< zLuV~T6`_9WG*`v`YhV2$(K_0fe$(M&p$+quqW>fGjgkDj09cL#Y_th$W7g*Fm6sWSzW)$_a0lNqR1g-( zWNYBNt}XZj@F2Xdoo(Vj{s`3rRHC|q?ntxQ$SbO(ZjbXO^A|_^1$YY0dRorDBvni()foz zdYR*gX8`GvAr_PcgCgtO4UmOj-c$kzM)Gz5dI6vz86V);9ptuZHpAjTm)&~%t@iGV z-wy!H+WIvw+S)ZQ*@A_ODJqzsD^NZ23=;uR=pNs2X$ms<@R!V@S8SD467Z+|zN zH+_k8z$jgliSu{vcK`}kl=hU&YcF2U7|L6FcK47#kJnQkU7lIqQF-bE7@aga7+atV zZn~0F1+LlLrS2pnwkTkUcT>?a0cNlgKtJpvXCCq=B)96}?@E+c5l9sm6BSVO6G=HM zf~C&}091;hxo4qY3$&fg6rE7iERCrcpvb9C@fWGU@*;+UmUS6Ij1}lsImWFDq7@jo zqWM7v!hS*p2=8o+@sNS5?uS2~O$=EN@9)^#W%Cc3Np$KtyZhmXpbp`Ih9`vjCy^=) z7Opc^(`E%K&W{7oya1ml(KJ^~P=cBeh!QpF>Fu{S{}OrN>26G?@yaLS!Uxo`e*1sZ9Z_fAosW?Hw1r$7))q+jgRIqXRkX z+l72H3UNKV%w`+~*dk#)PLlcK8@jExquuhO`|N__=R!fkpa!g-cJwl$EXy%&0QIaD zE?=ySH30fu36qs>v=-E!cB2T#;AD=A9wvj1d>v%xh@?E!Ks*6&}pe{Jj95&j)o%^F(uBw;3XmGtil^tM0zey5dFqz~w)) zEwA)g9qZo^>sU^6i}$unBSG6cACLbS>slXq8Ew{p0@ZlD$3Ah@HFoHshceHT_SEWq z*34S5cut*7sl*T>LbatkZev(%?L$zx5^3w$({77q)KZVA%D#W~Pi)irXNa1nZRN(b zNX%}v7?sw?hL+pos}(I~J`kx??U3SF*e<>7A{z|n?Y);QvD4pjsa^8k_d~hlImo?` zgFw#~rC&XW5y*iRoIM5ulhN%bS}0>#<2?uU>&}~gV@IBIg57%aZxQBb zVE%B=^mQCypQW(j@Mu5ATAam!^%}#huPR7B9BV-CM1PO7v4oTWx;Z99ukPmUGIK5kVa*j9Dl7A<_DP&6qnArx$yS@|!Tm z6v@ByclX#aho9ia+2lV5UJGbNn>;34;DBs_62j;z{zP^Jcun42Hg+~fR&xvr^sR^{ zcvy60c=*|bi)>a>q0;V}500}@3d)g0NQ5H{=QYp54mu!ez!^EW62Wyi`+<#C#*GeF zshIPsz@bP{40F*m>|-ekQ^=T!n=0Tm#5$b`gzmjD>NQh498;@`80 zW!X$)>~vBAzpN>)b(@42EG!zc{xL^od)iCQ8IjZL*S%EoiU zt+&`IC!Gc*E8@cc^7glP58LxAR-ibw%Yo%ET;ep^_}ln=%aj(b4?O^?K#uk+BG=kM zVs{Ms(r$`hU38ryk_|$Jv*Ebc4;FI~z_ja;|{XDw5(00LL1P zqt31_Ky$#h?%09nlgJa^?O9L<1i*^95m)_q7)e|Kf)eUK3_~wdGNr12tM-DU5>elR z)}f7aY{VrNAEWW0kxge4mYi=>Tdf0mQR;A%;2rPm8nC05@ENZA)U!|H;l$`-vka39 zF$&i|N)#gj8pkfR7#n+rC{6^*L59940wxs^)A%U?l#3FgQDIF(||2Fv!63V$?{^Il}eQNzO~2MUb%-A{wX2nj#L0=%~P;z(F3* zbBy9`v5=@Z6gMN6#s^ix%Xm>`a}}HvwXeXKQWfw@+C@}4h8sr?z|n7usG%@I?vRT2 z&1suu*?|msG5}1B8Aa&=jIkWlj;R=FaT(*9QW#Q!Ip= zSqt+K(Cwt-4<%W*m+Jwf0D`GRzlcm$ja=`lwJ$jtZ))x5&EHD)lKGuSP610O4KG^#DJ6%pw z73yqiHr4u(2fhNMc_cw~dD=(Ep589#YBeb60bSK3yxGI^DsN2rV-WK3ItaqjwwNSR z*wfs{bfpb=ndoH3g%*syf@a zb-OL%*6T>9P6Kq4I7o7@MXDs}T)_Dt1-}51D&@MQ(?lQ;EbyY{r!|fLF-#e2sFnTb zN8hm>+y9L5P+_m^YPWe+K3ltfpIvs**|r|RiU^8&l2Z;4@okt}XM1+UZG13qw_W`? zTQL=txjkEK^~P;Pxo|3k%UP2!eu=!uK{3i)P7L(0E_$G)EwcxH+etf;y8%6Gl==15 zE5Bv8-gG;86kBYdxYCIs@}GoVy%aB6sV{w>y2Hv>svi~uB< zC7YhZaP+dK)15ANDv#0QVSf5q69cIJsXmPiokD;bLKtp}>}FZZ)bT|OVM&90?W*tE zjeq=ueeJ8?u!H9;vxd4k_McC^>>Ng1%0&^GsW@SvJ&~W-*}ENyVT=?1I*U=yXZpO^ zHV7xI8%IhM!=J4Sx+!ZV>)H_2+Lid8uV$rV4vYX}DI2CZXP2X%I!RI06VOnwd}{HyTkFMszt zjID(G+vGn7UJEdUCy&V%I51lv1h-m6-DHC3a60xR*~&|#V;mKtAPcf|{8iIJ3E;|! z5Us-xg@En|_3>ZL}tJEzB%Im-qkPN#u zg~jr`Pth1jajLR#27oM&yTF#4tQ5Qo`bj2a^HT`lf&#trhI7sgiPQX-b%qXf2VB+T z7$Q2COH${07Q$-_-&}{(wK||`RF>D;Nhd6~Cx}3ZJ3Kbt&!#YJA3_6O)yO~bna|;& z6nM?psiz!e$1a;|uk!3GR;{ynR3~rmA+ejBk31m#nJ1sKh16%Lt*?eBEII+yDRL8z zq~PGmZ+??K^7KlIW^JVO^b%Y5v!x#vbU9J1&S?GTL2iNC_Ke&$-xV0D-z`UBd!2o9tEK>iq$nw ztG75{Lv%0!l}r{;0od;wBwE8pJ&uO!6d#*7O_Ie6p9Iv8;9X1;k?<=iQwAXY3G}0> zsj^;OPBr!(2Z-xQNRI*ROUZMI#}jzjNyb;v z+|%8Maf1N^a4ExUDPu$h5l1lk$^hJ1IOb{5Z$@I)Bd=lo@V6ZSs<(b#e2@u`kTu}@uC4MuynMVR!6Nfzg@(eR% zY>az|3AAA#sQ_Re?l<+8d8RSOR1|~E!FaBRahafvE2mn4dro>5T3@!8TkW^$bCAm& zB4-Fm(_R#OmMv(qLa4%SxZxMJblKtdrZX?F&wk;vs0@``@4f`ji1JRk*OC~4aPREc zW0sO1!q}j~^W%5jVUIrayp8m9I*@zaSKkR;5LT1Fszei@LM z7ZdXs5GLvlD+&t+MkvM{K4w5Xks{i#l=ViV%}Y2|Z787$MN0CVhvWg)0nUSgn`Ueu zd(J3HKWV$V_t~>Ms3&sxay$Cm)2*KxO^uZe zI1~DvDqoy>HN7PMU-r=}?2bDhrmxIqFPUjAGp5*QzxXZk+kp0nY51APKfC50+p=|? zeg6kn*@r*>HT&TWx7f=MK4P^{!b(%@28^Rl^4B_{U^dUHCZfwYVyt?}uk*0}%GgkZ z(!)ihE?5}Xv&*Z`+D$Thn)O%$6w2#iit~946WX!7qSAKn+-sM8_ydj>n^h!Tkwc=_ zCD7YSn9njiMfEJLp?D~Yg;8jMe&olS7tM3ICFAsKGY%pdcX6Uo*~~C>z8rZnWo~?p zK&SQLNb^9g3o;%F@)L2zc>=vOkwD;swWX5i(fZZT+tk_fZR0PlV@zXYV@Ur`jvOZ} ziFT{eP>vT0LS60K-8s->U=cq#CR-lgP8Nwj*|f?_+9dMC_uCa@JjB4AyWjl%D33vZ_uDM`F z8_!Am;q@Ep8wRLQuntPr30Hi`e(=5TV$hV@=_j4ys9p2s&%>iV3J42Z=Or15qD{fBZQ6h8g-AdtlH!MMZ#AX?#NOiO+`NMEPuOGOxhdP6nI zq!?0hK)8N=^_7h_GO!D8J3y4m++-LbhR{ufErpSX0ggeWdNmqr;=uC@Ul{;(5>Gz{ zTpH<7`d@=O=%ej<*;fR-$$$r$c?F2MACMfP2V;N}#w13Eh-Wn=eVm6ryOH(qz0I}gJe<6hAv%^TFJPykYqP(>92fS-3= z@P70Er|4-i!ucPzEiqe^Aa0k2N+NY(3P$siSYk8#gcK$^&*ArdG3-1^~7J>t4Oq zyi1O@`bfR?4^V6{v4{FI6o+N)8z<_yW9ue6oWgf9mIZ=iv|%U_v^v(}0y!|A2qF`B z=?fTiQH+c@^YQ5?A0x-1m$qT75fvQ9ke7gjoIf6n+!T>c{T^gLAfAR(V+3QL)`3=) zCI6%Vkj}dNC`DY!t4ohqfVsf*pe~ zf)P6!@8cQS-*_#9A>NM>B=tk>Q;{fZ=9ETjWIR6n&}~S5XKl-#^$eAili+T^AoWGr z>lllv0oDW7gk8ILasCkso?d8Q{>s-mPul+S;4kcq{CjQj31={@MFFOb7{`vL%)AcM zo?F+wjNyZ%IMM1Ml>QnhHd|mm%7DVMwyu3RKUj+CJm4Sv)?D5nij~3Dxf4$ z5`5Xu$zK4t0M2lhIZTohFp?Swn^{qt1`9v&1QvCGKj6b100NJZlje>|knzYGmF zS@FbG7)?M=1?v2~ri$o(s4d#iq`~jQEvak)ZT#Zdh5_Aqt}SP?HV17M1)fd7a0K8i z@4E~m@$Qv?p234BLnKJDyeh$a*i4!lNZ{PJi@$RZE)q~fxV_tU^p6TIIin;E&>9ro zfc9|7zT_QbG3uJAKXLE9ciAUC_4x@;8*TT>ibt(&&KcYX$;~9+Zr;1setq*Tc&^Fc zAOf{{+jbIcr(sNBIIy9%O@|xJMpaQ$VF{#ceMD~*=5GRQkCXs>Fy@qpqed79KsPo_ zv3)&5JRx3Lz{UW&`8GtG5}l|f3BD5bDVh@M3tmCgVTu5Q>Z*DQD3TAt>-B&LMH)(= zfek^|87I=A%IsC87^)};fh-1ehhlr`jweUg$aLfQjegB^9&eQE`xz;gPR`c2sS5{P{sBP)U-s|6((z zFSf&%*4YcsJwgKf!GQTOd)H+ju}vFZw$0COv5l|x*e^%#fj-q~&!Bv@b=?>2COH$=Z=X|GNUhsrkcZm2EP%{uGDp%B0bEFiQI zK=7i-x>ZwMiPK@9GvYlYZzmZ1X&fsOv3PmSI-+XxtP4j^15r>p%tW(IAWxlRTvvoJ zq@ZDj$-!x+ux6M7v;m^xS@xDpoEiAqX4Z)6S(N#y@uNLOfSa?43 zk2Rl#K`M4hDILmi#YyKSYM#NX6vI%Aat{@y6?7;$bF4FrC^rV>geaqa6rXUf<#Uqf zPFr z{!a@;@`TsNhS*4I;La1N08qN(W&i*I*)o8h2QQ?;&f3@nV$y&n86cE;0~|}XmyH-N zp9ha_3fh7e_7IzbKuIu&*N_D_of!nE5?*Ja)pDK0b5>-dDMX+d$P3Q(RI@N4Nlvu9&$zlBHjsl`#Q85?$fL#RO3Si0cOCDZy26D0_9_10wh=QfhIAa5^HFSm$ zpk4{&VK&emz3q5Dsp~;*N1>bWJ!(0-+uLnx#|{7>g|Y@lp|1dXk?TwY*nj@LZ*m`b zJOAu60VM))0XyojrFQJ$hXd$`op%oc5Z>N8n+H#M4CR(6^rc>s!pmahNI=b4v1$Wq zR@Xak@btE+_QyN!LgmP7OBWr?wRhVk?>NuSSbmh<{-=A<@Q<>Q`duDM7Fv!ELowov zD7>v0W?`Ol98UB=XWAO^^h)ikzPc6)#vqXbfHdC5VV*%$xF}()p^+ip17Es~hz9vF zLA3=NY8lDu>W?zyB(v#>93a&Kkyl=udj{|4)_t34JFk^jmBEYd!f@!vNT{+FBrm&2 zk{69h24q}D5zj*>aqS^@pZiGWuB@xXsDcJXo{ee_^!IiG<}vDoaRGS4^nVSNomE&- zxdc?OvtE+zCG)HP8OAFqY8Q4f6fKQUFA1PXa`K!$B1bBW7lP;QBj2FN_=#g^Nr@=* zn(?BX6Uk}v$S%SVCl`fbMe$645dA2>ZW0fE5TLRbqi_1G8TQZv_t=}?@)le9)Dt#; zb`yXHP@Es3rGOV0*inF*RLC^myfHkysM@6H0~Kf#$aS85&g%}wb%AFq5ONFgS>aXD z9)n1E=85KI0XJ!)A4U43z}P$JP^40ck|_^I5rF_8N(ImAqLp}*0W23>N>q#dkPu)8 z3qsA92UTf)=!!9tmw8isYro`) z$um9}XFlWkFRN~a?y}XY7-0oMXg3`Y z6te{K^<*-f_@v~WmAtEY?I+^0Xu&*;^^m>r$YT_c+-;52v zcJJNDUL(&O!Z^)l!dA)I^80pJ*+F&o&eIp!(BY*R4mq25&=Q0k+U(kEe{4U!;a4{A z`7N&fisL0b1;&Oy!QIQCqmOB1tv$N`9L7fg!y|-IsfaOVEdvfCkaj81cl_0E`T1u7 z%9q+6ig^z8joELmzZT(vL0k9AIuyiaS}W32y*+zv>a1mU>4opM9lMXPCuZJjl^E$= zdta~w&oXBQ4u?8ud#phxopQXLe9CFIZtZ$ox$;H(?l-?hANw$QdY*1z7}(8D(Gu&;dXJNEEPo2_XEy91Hh z!08=)=w?AJH^ob@Y7dqBCR)<@&aIy-3oLOX295h(R7Vhl_e zzlx4++4Qolc5w`j2zuFsQsZxMWB~$lcQ?b5OaI ze@GaYzVz4-#%~snU5Mur)i6RdRL3B>DH2W4+BOaqwMYa#!I~8xfC|bzG05EeWXNlr zXL0JBbjn+xmi12J(215g;QpQL_yexXCm(o!3uFKcSv*mGA`8RvVvSz(NWzhw6#WC!KZu%?H4g$2!eD`SFYj%;~DIuK+CkgEuY<02JiP6&f)ci0-Mqn$VKeMP8nqh9R>@$NlE=`6#Aye)ATwvoc2cIV zuG>tsqLS+3LpFn)jSChn$M~tXyYIP&eJE(3`}7rfB@eP2Zn@b?hoZJ(?M4iP%@kcs z+0q#^pbVhSL*$~Ih)8E=7vKxp0R2@8mzgHDF+6~QI*R2X>!@ejxqBO2`xvz@>fylm zxW1H^bI)Lc9abdIR$Q`&@s9PC)+J`|) z>a~*|Ub}v)oqGW)Srk>v0GzYX@Vr)e09{flAC*jN1b|&*wHD7qBSF|; z<1Q#e2LW8KVFCVa`ajr3}L-S1Xp(@Ij!QhWUZBevCbhI(< zQ&QGaMdMKblQLkKb9y$;q1+$kR>`|7&#)qe0%(eUsm-KT^vZ^Rif2u3bOvl5i^g+YM3a(V#psG;!}6r~uyaI;j)h8Ye$ zljsOJO~gdpGbsW)MhB@1x@351Rsf||B%d8|$^|@o48@{FcKFeU*zVoyZQXNw7(W`j zUh5~ScII-5++bIA_{WeFKlgh zlXb3n+}^_VdPeq{zmm@q0g!r{oDt&CC~29Mh3SkjMRYBLby;K{6e+CgWWu3@*4H-M zXTN_l$>AqMuM1FLXQ_Skn?JFZ+2`1skDkX|+-!%sqN z7&C|28K=GjQ3hyC>?a!L8Ki~rbdY;ig+ql%2T|#@-Zv#Xu(#p@G?L2YJWbHeQQ#m=Z>=`Us{E9OU zW5rLDM`8+TB4b*YlS2u2Um;}C3q;Z7Em0(|!1E_C(ntHYT5~I7QdDHl$rNygj2vp6 z-R-O)6LVM3K6xBiExI*idGJSHka4Y?lyZxdh=%0UHQ&=@%+yjdzZqcSux^nw@@L2dGQ`1N^# zTlHg*zLREu6q!>WhL0a(uos$++FNFAgx9BFq)Cc6M4m_ikSux)C*_(bT9IoaPoolj zlf&fYpu`m9`Bing7Vulfvv@IB(lVYg4rNeCzBNk!sQyHe_bF$j90}TS8LrUrN~rLj zh3eQ$AAHReo{x~%Ps567?uOc>S z#;B-MWR){Fs2zY2DX(ri&X@w&j*WTj=HK6FH~;2FB12nk&YULu5Q)a}w2D?J16`bQ zpW2$aCKVqUOF2M$l!Shr6Q~ThgA5fWY65sK12{@KXreG428`~T{;h|CrzofBhnkae zL`Wn;ieWUYl@ew1&B)l&rAq;vJRC@hyL6ya)T?X~DP!nqPpsT%Q&0Pleg2|PVo0;5 z=zajU74+Y-7HDl0vs>60rLuLIQ&Z!Tw(Q6gi53F*Fh*p|dI^cBMvNRHQ2=9}D2bd2 zat=V;V+@KeIf}74YPt47d-nDxSr?$ZU=XQTUV4;7W^Q}ML#t>PYMjV0VjQVJX(Uu< zDQJg}-2FrP8MQnjXd}FK`-{AXvxpA3hU=V7QBZgIMlH^|p~UhKZBAuEmJh}$#*=ve z6NOK4z%Ykg#1?0Yq|3>cbF`*a58Pxg-TyoO2JMcIHDNT_*1WCQ{AX%skbj_j6C50B zPepK(I90riff0<;k6p2fJhXzn*tyMKy#IFAI3l2kfs88z!xcc!0DRT}^)h4OF}(Cz zlVvPvBDxwl{FsB% z9gCo#mDmwyzTX;WwOIR}ejCOKvlXSOeA_Ntzo*9<>+8vHV@@y@xe)6+?KEqF4er{E zqFF!Ah+!*lXto3nFE8_3v_&ZnZig1DdOk6Xtu*V10KT@b44oY(N~|KRP8@|fo|8j| zdCzEPx@mtSa|bG!hZ-K$Wvp?WFG8tDkRNaLadvtDQ}DS=<26eGR6Fr*sXFq{16 zz-s|U!@qVs`Q($wpLW`5e_gq9<>9aY7>V=d+xcT zjz0S674`M?JuGOAEc#k~?dF?re%HI-{qCCPHhpCTOhje0|8Oq8oYDvh zxPE9h?kqf45Op7rs`CnK1O)+EL82q#lUh^wE zddVUbbGF-gXPpX)ILdI zScISh#V8b(#7o%PIu!*ir~-g<0cRPTq7#&otlcO1OFlOYRYIF-DSYi*oUuaGNWfaf z?n1Qh2<;ZBFGYrU4~9&s1LQ7x!aa|0J@uUz;8Kfv7BBK_7>0D3q9!to_Q7SRI{}3y zTr1%Klg~@CW_=YBszZ3jp@0ae1Au(FG9n~^EdX&Epw;7~EqP9i0_Dl5pZ#QV=N(#L z9B|(yjHMJcJY;;7O754)8W7U~3x*Jp7d-gj%oMppl4w;!%)%oLtaQnzG1?p0h>^m$ zqpc({oZx;Iw$24G)j}uCq1+@2mT(1zE;k|I2@d9Y0niv@x@PyTEmn!85+23U!H^kN zqPxa5;JAS2T$Cf_wxqp4LE0!xjRSuSLr`8-=sW_0;4Iq)tt|k>PD%fgM^&DV7vsat zO`cbg9D&Lx(UI35UiwzX#r{K-N70_>Ao@r1Zeq>|q)U)OG#GjJ)u^&3HQ!`xty}vF zf5jN!!6d`2+?YJ{N423BU>oyi?aLp1r&A$Q8w?^+5Jfgt!VN4B_A|cw0CeTW3F+i< zKDgnfRkUNTl~pw3?0|X)z*Mf7JRn{i6JCI#pJx-8){#T{Rt^pk=sd4Q9ptjm*zyw< zl>tNihx;NqnV*B)w<@s9+2NF{NXV8^mc>7)2#YI($#_;>4jEs1c8%Kt>!1#)zXcdW zKzHbK9;~bA^$~#~n=g8qW=CEb91_|Fhj*)B<;L9~6EuO>J6^$tk zr80mFF~mIn21S+cehm8(ExwFhY+cql)-Bc)FMaPifPqy)^i#CG0N(mM>x-gUN$yuv zDQ86UTtSSyqyz(S0%On#IomnE##`7jhrDy}OpM-t#gA|i6msF0}~UO@oAsDyc(XMRKh zTr>s4Hcw&5jB1@Q?t?@;B4s!MaJpqss`C*AHH1qt>J0iZ$9vRXN~BkExgY0EkvvAV zvD$kORjwoyz%W85DIz7E)VJA)qh|3Dhr388gT~Dr-J1%yzPS2HJL{~A-8h^4=fGBAwK0omnvum!o<_dl3_j&W?ZTx%J*#F+wfB(^se)LK7;3)Tzp z>vtVr`N~(mxp3jab#HmgTkd$%o8ENqKYLvUjXtC2m+_?c%fQq1KK$ViU;7P=ojdNh z<1Kp68xP&%JKph*+dlfykN!-r?b@|_s-8;*$O$K$@WlVLUEg@#f0y5LZ2pQTShgIX z!G_Hutwc-l*eR>QqAJcco30jNK(sbTUjQ(EfQx`&8a}QzZ2@DO#(DXhylJBY zNS(Gd@l41>qS0T4m%S2iToA9kl!Mxlj(i3BR!AyJqOWi-1w8D(_|>oAAIGc~@0)TG zBw^auJxFbiN^8bLFEN@OB#$ZjCNT}8}>NDL48syGMWO0*r8YPpEGAO-lijBY>d_zB|0;ayh6`!C2A;3!<^$DBj#&8B8Ja zH%jR10@0Tt`UJ%*=v3$P1NfGLc=+NzM%P&_Y5pJ^T`G6*DLuE7Z>zryg2D{9j_w3gSQ z&~Sg1fSF(|-e*+WiuBiIA9^=qtPxcxKpyhJd-}RC$e16@4JBU7_;0Q%#gMEeLB7I9 zp)|E4yBsD-x)Ca#z;#)y$r8|BDxurSY2Zh)+J`||!hDb#+8D-I995)$k>dC6 zt{#%Oi$n-?zcPY|dgSOAAApeYAP0r$FEl#W;AbdYQdm-*njc<$l^uNOahxB=0pRZ3 zOD-a5n)W1jgpp%$04Ss=7fH&6vbJN>ZW}`gA%HPA`=CWu0N4g%&E%-`ajkA^@;Bmm z0Kn1@>-W4$UIMuml3pr!@3Fm``!M)@I2Gn%>~hCA zbBg(}-F5FhR#nw(5e$Pe!Z2fsMiO<)g^1K@ZOh8hgRxKll|bJdCDJ46VU|g#xe*TI zpuw1t14#KLA-wpCc4o+pOVZ6Mn&-u_5eLL$HgVU?PmE&CXMy7kmR>c6btXN^9L(F< zZ#~QI{qtiO@S-x7a$i1c#2K>s)y?!b`8M=v21ikdHD#E28{^&t>b*Epl=Cyj`swxo zXt*+7g4!$id#SI|a>E#Qp53-;eHY`0{`=d(JrUi>@?5)~`3&_s4(EK;RypT5+xg+9HSBmI?j+Qo0hVD;J~kKbg6E;`jwIHkBYylXekk}7-V#mAu7oy5Fi-HKGW zHk1k)k_e2+I!EtIux|PoyHS$Ov4OeGD1E^gND{$d4G(HyvNx$vD&{?No?V9aRqluf z6+A2=))|aL=BQV>O1$0A-jqW0BEnpfnwI8kkbR(cU>|z}ku&zjBx`w)sD}&F@_rfb zDhL|Jk&%YZo9-V*2Qp}T*6niiN{wvMiDgE~*s6}q{#%Pp{&3*6zyxyn7oS_SCV|^G ze(dhM?|$=lzkB5u-u>>2Z`}WyA|ic#eYM~I_P4*JzsW$@|6NAM{`cK-%PsGe(Q(m5 z7u~8adFS8z-uM3Q4}bW>h3|j=`)_#g!3WP!)IkP>J|iPwzo9W@%9IX8OceQ0R6zz3 z$7@@G*$F3{@Wh#Cp80?x7k}>>0_kr&*YxSrcV2M81$TbxQ=ht8*AiGSEiH}9a1x+z zYirx1`+pL{3Xgc61srt3Ccxi`V#te{XJwVQ zTzMJtTKeQ^K4k20_;4#r%_j#K)p_(L z)q=?3#Zuy`?o-B#JX%r+VrOxlIc|UrStkV$vH54Eyu!vRRg*lM=+uXwHe0=k#~!sQ z$kWPW4|D(^;z`HL%^qvf?d|68o$yBAKpqGW!M%Zp9(@)7`+|G^Z?#O}A-E_n7D<@) zP;BtI_3OArZhoqs=-U>wm>}FS(WjJS!U|(U=O1g5kjt+LcY2 z{!vGiQH@zg0`Qk3aoUHKnZme>0Ja7xm=^>{4PhKK)>gT^k#QPMp4teZ6B)PSQim~m zf&k^3$~Na=9fhKhp%VLWJY|)o6jekNp{%r;=hzF4q6EW103DFV^HmaQ0ex}@fHWd9 z0{8&{lg3d3!#F|*%D5~t2C#kU9>ynaoyS1Tg#?~N|H3?GjH*^hk>ux04(VWkK114` zdGZ;%;O%d<>CoJ!G&BLiGCY&wAToxbz|d#mKsi)H=s_90t=J8s?F2A5#Q*0vJg)$7 zjdj;#3?8nPP7k3J;AEPz@Y?axuoq0jWP9@W}nE?Z{^s zLf$nrMpT3c3lyvDmA!Nvw6g+rZpvZ@QU7Jo&Bb(S04kZs)_35g<$BT3n42#lB9N&J zwH@{j0n~{Ic{aOfK>Y|J2B=&Ojuc5?M*f&2UN4kPVoXS*BBecypPN1}ttfZ%9nDt~ zhL0v%)lXi^JQr2LIfU1lXVm}X0F5F@peUrGMk-!D%p4fO0NB2D7o7J2fGeOcgJFw7 zF@gtN5uXM`A^b!n0`VOpmO!f(@)!s1&2&f@Twb8jzh7C0(`sn^}Dqx z2CyuVk{shQF$nF9HRtKaAGbfh>wVlr)Xq6}q5bsctr)Y2O7N_QP+R9i7hY^%*!X>3 zH#_ablPsPawvL^h_Rxb5VB{>ZHywE-N?U`d+wHO+Uwx&$?ZOXX&<$eP&$gMZZ7fv+ z=S0Eq+yq#k;;68-5xNBkkI+#n(k zWq@hbNm4{jjsZoSqZpxis87>p%p#|)6Jv=1%i5!W)Obn3Hm}E_!e><+R0lJhxtb-C z++okIc-W3T;c}~On9nOX4N`s9y6ggLTXr6EGiR$Fy9qv(yk z1N?a$P%`QWsc?SU4ueQzvdGv7YYkyOX}tKje;0LAUJrX-DLH9cJc9HCmJLx9+8oD4 zl01@f)Y7DesOs-B9AhX7O2JOj=ot)6Mf&4}7snz#y`}H4`fgwP9>Zzwbe8m+X{h1;F0>^lUf)70K zz?u6!`LF-X>wl)o?5iiAeDb6E8wq)=xMoj1_0)049((N5>(;GXSXEUuD9V<;KJ%H+ zd|%%G^Ugc(F1>I6@x?EG@jEgw^xjx3Hda|#IV8%|m%j9+Z|gJb*RNmj_pTu$;Em_f zIe+})AAdr|jf@aQAoMp~Uo@~4D^?t>-~Zn6&Ue1^78wUUy*>5c_{KNBdel)zJy%;> z+oy<+B1F2UOD?(Ox=oul9VA2PpS}LZ^UF|@p{3}_+u#27+kgJ^pI^TJJ$i=MKZn}> z@WT&ZDWge|BN-o}wdwu;tX=n?@8A79cB)%^RntR!a)D+Y;3f`2)%+{(n3v7&?;U!( zb1V@R(L%4^eF|0ccD4t;^LH67L@-ntSbxm}HdvwM*koM?6tW40Tzj2gs+B8ld9DSR37R1>)uAH_i;H5;_eyT^O*lYye zfunfL>xjsNts766JiSuyDuvGAq-EK_N}(bpp{N{9k|$f8qXZ;}JKSb8oEWfIH*U8S z8{l++gH*qInrfh5b-wm6|JQFxDt(VFUPKZnGP5Ykgvt9zVqBHs z^ew6@kFg<_;-Oas=c?L8L@4nhQ;e?!kUk3SBsr3`YVsl?c#j35C1qQJ;!+P4w)6DM zKv%Z~@wS%IAz3{0c>s2j&D%#LC&=$obSeR;`b*SL1@I{pAQX{QI53-~I(TS8a(7m1 zBL)mIp8zaBvbP@f8z5Z@R<)&o1q>2t=rd3NWF)*xnTn`QU0n^43O04T-~~L60j!KM z0F$JJV|-3r_auPV4^W7zo<~5ue2oFd7GqI4GNO$Ishpgn2wfyo%I8o|qb~v!u=5~+ zTuQ?AI9_ORy}R~x+w8?lH9!E_K7L6vLkF*nEh`9(0 zu@@KZE9cy*aUyV%f}azsq+b~C${i?pE1<+NzEk}uUS+8-)8)pcC^H_s;y$d8ag0b6 zFdHA_ZvbI|VNtclFkChM6rmjCIedQTI9yZAnq5$0B7i1h5Vo%m`qd5rNBZh@!)L;z zXYRc2Z~vDciB=5K_Bs^pN^#8~hKqo$6oK@+?#E3+zGW~}f&i)<&n78rd61=Or*&ka zXkqCDz++B&iD-((sf2joHj>AUj5&>=S}g|vSk?>14Xcd<-X6wTj(MKLa88U+6`fiv zBZ+qV{Vjj8A7Awqd+y=?#Hjg{JKyRTUa^mS@I!X?IVV{a5rsbTbIyM2TZl+@+SG+} zYy@?L<3B>8^{hp2CcEluSKG3a z54CFYmaG$6O+19U(;EBFANMA*akb|_LG~QHc!K$wtd|__KEj>%IfRp z*z9S?+Sylp!XEnGf4Dq@B}blu1ot;>DGF!jAO1FbdGH}?ZG?`=ymbetipy?Y{e)Y8WGE{4O>?iSYo`tG?XZsiG5hxASJ-WjJY?Rg z3i>yJN1uzm){kLC2ZBTy2T8V8-J1}Gw(?<$%sn5;^9$xIu!RdxaAQls#VM7w6a(#J zea@2{-)J{pf2YL2X=6YCUNV7)u3~x?`jg8Uf_lbjnHLC}Fqea@r3J=Md1Whx zF6{{23^T-1ti=H=5Zq)i$wc*onh9OeLw=$Rpi$j7>p2Bv+#H4p$vEt1A1Pt}iY}M7 zpbRkfkRrbqS#QQk+E)}ci%}l*GsoFSoN-ATRY1e5Ci=Irr`;JuUU|)&ZSoQw3<9KLQcqabghK{%`w#{vWj~MvM0&mwt2qXa3#3 zKXTjc|CxxVJj(F^v9O35W(Oc2KN_dh&R20XvH~aznM*K%vu5!&{7ocC&3UpQv`1z zH)+@1^m_}}H#(48U{foj@^TVosR6d)BmiArvx*253+|_UMuRm|c{c#aC<4}C^jj(S z7h1K-`rCKfpP-~v;gugbdZ|r0qF`q}^ODWj-Sf90H%`&C=TAJ`b{>A1RX|r5Ao@^N z(rDYZZnPQGr`u5Pfc4{D9;02$NFc4Psj;5UUckH;b)a1sC8eTAVgQkZkFk(X)Zw!DTgkCYF8QFKdEMgFla^x`%!#CZ3_h@A0V+ny_U{hT^K1C5wvX?_mw8H zFv$Bvu?hoND~RqWG6Ing0LB;rIdx;u2^3Y5vocQgW*^tsv0)t%kUGW#(3uE}t_QIR zg`JF*RFqhNB=aIsw86m%@1{Vw6q~|4lZxLdIwvRr)UqHJ=m<&WL1-4@hbs@n3*{&( zZ#y1VQG|j}<&w~i(xZ$YS~f^Oiz1Q(P=#m*KjVHX1?psl z0G1%hw4;EEpue8Uf`Lagh0B2qiL@~;yo`eoYEY^P6U0cUz#tok-qPFA1JqT-5IP{w z$qW(%;)Bc$yrzm4q**e?tzml-Qbsrp3tSvs@PNF03eU zFPA|Kqg%#y8ZiYK093fGi1v(hT2o~uCl<|(HX#yI0R1W1ID*lg$2gl-18wN(NA1`nAEnR7Yzh+8 zLsYRJ0hn?!yZWc!AwZ`b3VIh0bOiOfo~~Yd*LmmD#yPup#XW9qh*eKR=_zB^-uNAC z9wHu4p=xVF_RNY`SqI*R5goCYe)giB%^X($tlhHC?tTBouFdM2s%W>oU3J4%cGY!1 zaOd^lg|8+b?KYCc^+jz+d-&#W+d>kt)vo8Wj;OsJd-#v;djTry=HWiu>K(8rU;cy} ziv`A_C|A``;%@xy?e-h;!~XQ=KeGN#M3c3aDF;W!eKmI#j1VQPuCsfec-dZj#|P}L z-~G~laLsScSJ6hF_R$Zlsoa-}`We*9EL6l0bWu^Vv`)!su$4R&uPAw}WkK@S@-LJV z$&~~-5icTHiU6qCW|nK_nUh+V6%CWBA=utLtgA9K*Kc^$jX8}gJ?GyXS#lP1ZO1vY z2`b}Sn>OP_+qM3$%+(ru^2S?nJe5L6EVr{h`!&1&j_;cffr4d+9brHJ^^MjzeLm|! z(B69Pxz2b&{z2^&NK@ z#UIH$VLVA0PBm*ntl>WPFHy=gAA&N_a8TrFf5P?{xmQD0(w_9GETeFB>2SW;0Db^}k~aj0*%QM9sq~2SczS2Y7Lj20UHjv#O|> z7q4p(04Hyd0G~Wg;wJkA67(5XRfjF`XcqB$iw~`U1nepYBK&yZ1S+&K?N9R5HFYjU zK{9yWi%WTI*(u)@7ffUr?&6ygf>L6J~+UhfV^UO z^#LoDC`ql{(P<_7hHQXD_aZqIGg@kG@zNuxz`mAe^pc2)Y7@`cHnj=x5VE_Qt9WXU zEkPfDR|i0WO-mKKtBGES10ER|w7nQDAZ_Ovtf7!toWx`)K*>`+1hq_5sStp+6r)D~ zx3z_u769WA9=;4owW7NP0Vqn+R*ywh_^yQSL~VxSBNzgTQph+#Q3*;^9x6=@?GVN5 zouJK?xGL(JACNU;?rds(#4!M6L@=hHvy@6!m!#@?PXqlj2uQ^kB;r(oe5R@kH&Ma zO~|@>OW>K)7JynG>RdU1w`zxED&U=?y5%P?Cd7D?;h=Wbwf!3Fv>)BWU2tuRmt|<1 z9Dh%9UKO;{kq6{SR6xf>VMWHiqBnqcMgF`ps2M{_5*PhMMj(&Ee4F@;a-1|@b?gUz z&e&&6$;j~Hy%u;)Fdj;X+9?@a^42+$wPhIQnQUqIY=9z8lOsP!a}6`qQGe9HGFh}y zy3LY_t?|GO0nPwXTw8N`e-gZ#-xv)ZjIRlrBosY(Mzl8gjzWp#mXuUOnE~|q_1x6u z&`|>2N+v5yjRR_WP5x#eG<_uC#@GP_t4*j4&-kL~-Sj!OX4Pr{CF{|+)-8-EUY9DJ za=KrJTb1^8ZYOMoB;eS0qv}+Y`#@j%(nv3 zjDu&MV!PL_v=4s&$0V(9w@oXbvZo$?kiv^YHh)2!wS>6_&B-6=c75D6vXgbDnnJ20 zjDwuj0qzyqPzXheURnbxZn(#0{^2oo)!&XXermY)S@-+iPhD*BTUr7dN7`-qgt(cxiz&Ed!x%i?Tft%k4YoCKw% z^_-Ju#;8qmUy^SRQ71)4xSyOe<(&9fV{@z%UfRdQ*UOvQZQ)UWyY0yz{>2txy}{=Q zPxJq!hg(zsUwZG8w>{Yc|6jELu#J@$P{UbrY*bka!$~E?ZJL4u?5G|9T~;86w@RHR z1Q1dP*@N@c|tCP-f&&&a#7x0+VF}RetdPLke0dDy2F#jKp0@ygMlIst~=PwC%_j#fDOrcaM}1oO%Z_g;g!?Iq^*XX zAHzzZhG!uE#MN+cz>MeNF{Gx|iBi?{IkRjJ3CJ_2HCV^4L3^g-6+V--<#3Nx%<8mb z4kn*sj_o2+G4+^3-MM{8620q;)2$BK++90gu?DJlw|DG@Vni}|cbD6MJG;AW{z0?( zz0=xAYVPbAaJ>DBhFWW@FC!6~&_4Hh2mqj~i^N8}$TIl$?!j2WODQjWCq?Ia29nSX z!q9L~SHYNyU_^}p*y_pywr?Qs5^=k_2B9nT*^%(_NuB|u$B^blJ0I?J1>SS1S%m?> zB^1r;O^i^`tXAfq_4OfdNrb}-#fIi1DifyX=|g~8h#gy1=;I`zBSz(_uy>JbP(p=b z9~){^-g-QOWASlvTSzp9PBliPK*^_yfJjeY@~I_wn8O&CMIsFu&Xpko6hoy(TK}qq zoP!pT0+6O;V9I03fXu#@8l6X*lAH}df5-!>V|aYo{)vdl+Yb#4;Gpp*FMkT7wW6%fQ8gAHypVi^X6`3$mwf!Q z)(yp@ifed13C0r<5J%4_5E&Y=4vZkFVo9=7z*h##IN(AaSJ9_ZfDuhD(HQ%v5rb9` z_euT<=TQ}9QRb8|u0uvclIQUOv~`HKW#dpom`^^&xp+z;jBXwd;~3z}ICk&jx~kJ5 zV}l3N)4Ov>O4})00oKQf#FbSuZWMXJ@JaxRG>1!k<-D6t*Xd;@anJ5NoLC@C5fNP9 zyr%pSeg{;m%{5P2Uo3J#d&0?xeGdH zwW`9`5a~L8>A_I-64q8zui%uu_|j_DE0HEyEBKCy>ec`iHR{`#kQ~A&NFHaC-TN~Dt`(qi#`K@Glq~-V9aqn zWpgW5M;~V}zN5@B-G_3+RCg&#pM+UAj-G#n9kuWX=%s)IoQFBXkcFe-8opt7g);mgchr*?UnG%}`EzW1_iAR$Xhn2O3s+->9{|!T8{&|I0Du$2W8C5t>aoMzlL~r^qwQd8QGe zBgni{n`qR!vCo)L|41@i`7KE(go-B1X%@y1ktDp{pkY9-x=-pnxC+<@xi|VjhE$ly zaB=ru*4QfZ{O0#8A*{8so;5BQ2PaZMv*x}B-dcEN?LvM2|B1tM=IOV4rnYYTzjLnt zsp9D7&70>w|NQeuN*L(>&UOCTXYRlM{cFa*NY*&@qKSpru}F4_{P^Tyo+M_i0=Q!*Z$e>uPvMZ>@Ab8O}40QmFvzj-6a=VPIN2550}BkW2D2Hl2m=&FABh8oifq6*h}_$Pcz(TrVLzL7 zf>6CS`5@7gJiA54JM5BrV;)tgF!>xZppH5IT-}m2v`%NkCbA-6$<8yE zT#O6`!-Dc-xGR*0+Gg7=f4ZG3Yd;^i=~Jgt#IFYVdK2uT3JOb(Gbd# zG%dUy!w3)4XWhwmB07i_Kp(0?^(cv<>F3KuKzNQJgbaTF$G^~6S_9P1JfEUJj0Z(7 z^5iWj3X~_ZA$eZWanvAcLl>c-|MJXnMJ5#Ykyqc#I9Jq23B)wBGd3lBA^BB#`<08N z_Ee*3jc}634y4K;#As6_S-rYN6AG-%fO_!BnB@Os7OBI2mk3GF< zazCb^29~$RDbrlECN;W)b+48C;dR=yzoQRY8#!{!0oA_=;6TWcUsYgS7aMA9d@6Z( z%-w%1XOO_8QRMDvV& zj=s)nEzx|&IB^q{zEo7Oz!;Zm9mB|t86QrTLa~p&BaeysC`zRQCcMh~8B@&LgPP~C ze~DZ0zvuX$D2~4L(u>QKBP^P}@^Qca{qKK9B^H#MtbF57fBMru_}=%v_t|fL^P68e z;)o+&SiXGuGgn=8)#vmzW5$dfS6p$$H7A~U;^WE{{#T#;pQ+96KNs`oZ%Va0cI=qZ z+1c5oYwv%3|99r*KUAhwzOjUs-gwW-@817hqW{bI(D`IINnv$=zV!ZU{Il@r-9S=>89<#jE*(lnS006q*8>uP10g#f8@(tAc@|G?KiXUiLI=#GQh<%T zz>fRRGVUi#UIcVam@fMG#DeWW7h!4v6?v2j;gl}sJX(HlxvuQMZx%0l5o5-A>hQ|# z_ZI8kRP-%C?T9R>EREMtenH@a)^@�Jz`TEC7v?P}EUYQs%&+ACSbE-3Hx&SFV?0 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

HwvYhVO^$OsG&kRLKy1MmHDjextC1r`E8q)Y{t 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 z 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

pe|HZ&XT|RHdKq5S0*E{(rhNu+qTKD_^uXW$! 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%0A3VV#v8lUlh>p{>>YAaR`g$f8va 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%0DV_0({htjCD}u`RB0 z!;-E60ZE_DKbSZLsdpKdXn~A^BAq;4P{&9!h@sGXO##;U9Ix;C(M^55+O#`4z&1d5 zakIu;1$+oIuiT!2pLLKPkbfP|2dOG2i33ZXd){Izg!-^$zm0TjW)?3O7eR0_1s#0z ztbWW9LWA92gNMx@t_tO<2z?Q9%yAhughK5Gx*fPgKJ>0EDP0E}O-9lH-i?B;4Qd?4 zJ?^JL!Qn~+Pb<5eLiFyW+}g-){;y5+8d=&$FkULJ+(JOfSR>zty1>SvRS* zc;_H?E0B_ciFr>l))O**H-o^9;>PwTpqC`|i}BLA=bwN|`P*pMk4=TZh&0Gkn9T7{ zc980Ba(0CHCWCPfT9uEpWwZMa>FNeI4OD>@Cz*GgaXo!;Cbc`VN+uFaruhE}XMp=6 zvU}{AofirF-3xuz#Z7f3K7@( zyUILAPgAqbQ^(`vT|N5fLcZu4H{kZr5xz3qzs;T0++*ZLRlsRL-gWNog&-p-+03A% zw#rSwbqfJcwYrKrl(osSj=X5t>kq(>^F=a;>qR@LU61CYSrs3<9$2j-5Shlrj0tPaxqfv3_=?jsGGK#q^2Z9_Z%K)$u%?OSjYA27SZ z%-9TcO*||1ENTL|`30H47$VVnV8BvQ2ZsPB**)kqF*3n6sB`0zAZ9**q#}*>SS|!1 z2&!qS{y8|{AdGkefhqc<+_hqn{Sa9FMC9(tr_i)+#du)l`3xD&&F61LctASgP-p}Q z_BO{G)FqU8!3Z8%RVaGUu_eq7n3BFPbkjKQkuJU85V#6i*zx-D#ORGdX6q7wT(2L@ zy(IJ|tlsG6cbtw;gOg%dJc?t=Ai2{32B^Qbi@M%QT&TaGk7Tr^LAlru+Z%eM+`K<` z4$%vqFxBv8$2>#Ml*b;Yd(ESxm30gXU`5XbCV?||%T~lfZml5?I3%ZnqxCAlJqe

yJn_@gm(H)^hI0?Uwm4=u;T}$ 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 diff --git a/docs/_static/esp32-c3-devkitm-1-v1-annotated-photo.png b/docs/_static/esp32-c3-devkitm-1-v1-annotated-photo.png deleted file mode 100644 index 1f8b081d5e005c018e46281c6b726084b5c5fd82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 349164 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


~>z)4tP0og$Jk%iv_Y(C!?%x8IJOL&ME*6v! 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 diff --git a/docs/_static/esp32-c3-devkitm-1-v1-block-diagram.png b/docs/_static/esp32-c3-devkitm-1-v1-block-diagram.png deleted file mode 100644 index 29c14e0a0b022a0734fa9b75c218286618d4348c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76929 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 Im$00F0BWA4>;M1& diff --git a/docs/_static/esp32-c3-devkitm-1-v1-isometric.png b/docs/_static/esp32-c3-devkitm-1-v1-isometric.png deleted file mode 100644 index 69667b511fd5cae29abff1864c4ba5eef298042d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236210 zcmeFZRal!}@GXp&;_mJ)1qu|01a}B-#ia#W+#P}!iWhee6n7}n;$8|AcXx;6P=5b& zzVG(jpC=c|yCeJA^Uj`GGi&Wcs;kOjqLHD&!NFlF$OAOt;1Frx;NVwLQJzPPU%kG1 zenPU5Qjvm#tBps0e2@HmO=BUisR9S*%>)M*7zzh>|2!193kT=M0|&Qn1_$>p4Gxaj zIkQzm^!W`Gb0s+d9PHmCx1;3i^T=ywd3_f+IK1a?<1xV#S4BS083?BUkka;CIDGPG zwwecJM|W9_w73i1Wey4NlppV_S2;E?B!x*Lh49X8o0wAYi2fl7;hBUd=itF(3B*Ao zLHZL2(1v5rov9itD{m`r{XDj|>2kg7Fe-dZ?E(r4SX)4u{M1?H-3nUEY|y%S{7tfQ z6PcbcX!#~xnd$5E(>U_Iuc_qA%YP$YcVCd@|G%rTUkD8UKK1fpQ5#G6#Q%L^na%ed z?*Cl887I{b{6D{$z7xYC`M)PfA90Z-qWPcM(v`P`>CwOZH}&(_MP|bPo9@}b|F_26 z-U5rR5P$h+|B>P3f5sjee!b_~_B01EHT@Xw)5-ncJxry4xh<*4*2Sq16aBk9Y}kFk zeV9krO~DR#<_ZAnVfLRF2t)5W1D|ip-C}Wh`TAzr^x_IE2>bCcBwhl#fOnzui~H&H z#t+t|_ucdCb$9lO!^pq8y}cEjwgo%3ev_WcwdB~;;RNgPS$Q}%^`Beo9d~54uvJhe z-*s?bKL6e1yZz7!^9eBP+1(ZXj{4#_+rqT}T;U?o%F)q(*TwWUI^gtx`kothe0b*) zEseU2BuZ6pQ`NI}=j64x2)%viyz%k3^)%ZZy723Gaj13*XNjk2i6>uEndfErs_^oq zr==NPi@=U<0xk<+Tl5m{XZu^oAX4KPT%c6U)E7t4offlN74x6qkBg0Be{A`;b50z_ zUzSp&di~FXQwczzJ9J{M58f*fzf(%=<(p)|vGF9tWKtYl_&!t=a|A$odd3l~L*lXb z#2y<<*>9&QU~&AaVG)1)#=?_}mroazEC)b4@safHgs}eGJlr2&b_zFXYlq`OcaIFj zcf4)oqPigB+UdYmdN>dvLZ3!a@{C12LoOeu{nyOpWw%_wfnXP8{t`c6=i|yF`;oiP z{hdEYz&8M&t`4YR@#xyP-Sg9h)+?;`g`wT!d6x%fB2E+6@_GAlJ0iM&rnxhu^ZDl$ zO2I96cX`~tXV9((hpu}E*xvaTA9@9v6RKX{$o`%jGK*fwcLeTmemXid&H3)&u&++A zwIc0xRpO6!ObYkYpra}W<(xO22yV>*YRZLwyj+?h8y6$_ZAD1!7e~V=UU&2}EZ%cgd z=kPX(XK}eRX8h-N`Q~Y#+kah6;?CHmj!z~TNQ;1%7bV0jq|yFXL#w}j^Ry#^Q zD5D@s-p28}+u`n+kH?2aceBZSV2KIcE9dmgbp2BwYFGg^Y$C#c%ha^Z+h0mBsgqo# z|1}&4Lr5diY71i2(!RP`hJW*6x%I9#At6DDE^)5*Uue7#c!`4-`Gt!|jaZcL+IJ+L z9>@K5gCeMW-AW9v-%GO8lHf+>Dz0S+fkr}2xXno>=`@gKaCb^?>ZVT6RhgKW7noIZ z{I04g7jNR?;xcg)PJJboySS{kxlCF*x5cQTR~}D;)V_zX%&c^>M4Gf94=e$Cln@eL zdzVfjkF%koTEw4mf9qU+j>*YJ$Z^@=z65s&;Y-LMro6bgK+Nen>2!Js%YlX6P``7v z)Y8{ciNw&Q~n>NL+zYTbW<)#ULdWttH5kvxS( z6VLgrhEU&)2Rxp|!#2tW2j5rZ@5WxSLWBs_Bj|*#02FMc{68C*M0kF0eSf_`PsE2E$ z9mfy}uhMw3XWr?@5#jRk2wWDjA1Mvw%^Pt`97fGx_qLvaD{^PH<6+as^C^d~(}wPc zf7}C1+no0A`~&|P+3VAPM()u{0UgZK%U!o`5C`n(QZ=8jJEdiOI}${YiVegeP!BS2 zB?<1QGA9hq({Q#H1iqpJ5Naa&vykeR}%0{@px#d4Ba%B3h*OcfTP9 zJz^e9y@^)rxu+aPHGyFT=%nP7344(h(22p23N=&FF1y8)kJ#5YSO4S2U2p$$WBx2h zkJZVJSDkyQ61NFARKAb3M@xmXzJe~|PDkug(VS-d32|V=-1rIQY zA^|b9k!rzOGPoRpk+?ysVIpq(efeym#*2*~ylQ6cV=oZ!X{`t|tq&~u%>ap z@B}W}(=@FcjUr^X+S|noFk9(tP^13a_31hCnjZN?3J%!(0}oCS|1AuQZ(2zg0=b)T zfzOGC=Z3pAyW%6^82Gi1JDkNcH1ahD0)0v;-@JvE|Cb0g}IT zVvn&RBu#3_0~9ps$-cT#A`$khv-%{9_#RH6t?aKfTlI#&`W8EIA%^@Vz2z=J%@2yc z@-TMOxg(Jy=Jx@puU|k+#|yBw-fn*DpIm-Oql$w&)tDiJAzI@<%C>xaFIZ!KXI5z-!c%W)^8ZD~WIPmzm;vdj9o9&gI6Y>w>w*Pto z&+WOT<{vWOxj}#Dz=}+vv*V99YVB73?$$JYc=4+aC&B4-1T0*n6~La*eAVXfdP)%n zfk+q$1a<60IJj(@#UMPk;EHaBVz7aRGBQYg(o()jl9nxR`XU0G(s*f(O0UIk`uFUK0zB)r^F3o|MrTU6F+-0>-iqIKVQ0LG6 z!$b4c@2tblC#)1M{czI5fNMA(Y|-A^KDX9c3airH18RgMRh#U=z1PBi>t9v^PA3-j zz8iQCHy)XOd`spse)I4G9=WOhOYtPF9p7Q;Ht`*I5}g}M)bkIwy6)lM7k|Xy^aN`# zZ!uX2!`CwmFtF5g$7V#aph%(8X>0Vbit{Jx@v5m&DCCo*;TGT!=CiQ?lH?ge$-Da1 zON1mb_C`nVWFoSSSM0Gl=IcK_g#a~1#8bz$K>h18cjzL^XPq~&eH)20IVbiK=2x|B zq`F`smH2e&JtwSHvTVl~y}agp1u)@}_;`L1dh^4vSfzejb^9XmXnLrjdQ}E2&3w~kVI`48i5~k^nyY=ohnQ!6Y zvT}lzh7al*w|6`1k^3oDJ}W^o5ZKMheLps}?`hCd9>=0}*<9ZpLPZvrMhsLoq^Hy0 zdS@GKRfuEyU=^CzBi{Hyf1LfKHFb+!hiAfm+P;y5l+tQ%z28X82MntC?L1rsp+(sk zO8%spDWrI_0F0v+ADTVj)9f!7a=-jFCR=bM=(Kzb&>+wceOY{f;>+T_`Y}4hguM?OK_Uc8}*s1B?n_m)-@m;6Y9yubnBZ|>hG9a*ZUz*M+8*i&MQnY7Mlq4v* zwCIwZ*P^g%Fsg|DZ>zZRA?7;v-g)rf z(3QCR+4aykUls{(Q-(UhAxS_%1((1UiHZxLSWoJ-{)U6FiW^xPC_~G_##LnwEU>|K z!Tk!(pcQv6=*D@S7W9rWgAp72S_2~%ml=MND*xFhijX;H!DMd)MW%&3Pk&Xh>sD6l zRO>;LZmJ&|{If?UBFpv|yPo6%9-YKb*KS}32dS!Y1~IDIykUB;(0;aFbvR3}NQTrF z6<}aq1)+A_d71M>gSzn?oc)N6A@@3h6i%*2lh|9Qu>aJcbz*1`8~^5>tM zLwIW@$i%mtt-gc}BdV^re#>*>Ptr95LA`QL7gfcJHI7GLV>zT>04+@VKbOce)H#xo zQ|mah2{>M&_Pp&GKgs46`RFw0`W_|iw>csmukc%=Ab3W_K6MobZNZ^IbkIl)iz0u2 zelQ{kOr*|TTKHC4137evZc>=PMX_`yQJzpA(dFm3K9!puB}khglW$gBn90?n zQENVEzI^KDwCV=&M;Gzty`aEs7wa97-kdhr6A4qLo7kz>o1y$jLDOFjbNR~3i1yaKZp z-oBZ|E-_f~wXSF8DEEe*Atp{Kj!jCCY2={!JyKN)A0nQ6azCRE*VyTjaonLmRJUl~ zCl3r~yb6j?zi$ml&{t%aG`y-<5jQBiwVe_coayi0o7-UPf#1lbwO8Y05bK>5CW8I=SU zyYk>*mSj};h_ZE++BBVdaNr>3fmc+AwB{lhl?a1)DwIJHyCSJj31H1!ybys!-Rkks z_%VW*OV3#vhC*lAI8A#07!vQdGv0YY?7wvx^z-+a`wqD(r;6K1sd=}#Tiu)t5Et~j zYUNjU+p*OObmP$H5uPhkWGEjf^Y_z(BZur*j>zcc3=*OYA_oPzmFtI?y*saBo1Hz` z0%_+3GxN_;ddWsDt_d3@V=iltjNTno8VJ1a*g{#dak`P}d3@_|hQ5E=?Vc1N<~IKP z@oFgfq2tE1&QAUR?@IXPB+-03Tu09!?P;4Ey7v>dy0~3jjiIo`F#AEMhJQ~z$TorP zw@Z9IYuLa-(|hLh`AvhqR7!g!Vv z9V4e(|9vX~?kms2YrVn~Tv{RRDS)J=5kxswtua1J^lFH5u}MPU%^P1?&<1Sm!qWN; zuW-j^0rf*KHLM%*IHaa*B-E0t1=N+70xQPYg>gg{T-qSz;q_+LSe}`ua2by6be^v4 z-54KtUJ)HPUvbIG$&!$g_X31`wh647dUt+#QcnElEf^FEq9@Ul?4wSL=SWdClV;kz~!Lkgwlc=Cv+xk-Ju!|pmh6vlQubkF? z6b)AzyctTFCAY)Ao<4NY5*qirkr<sb@`?ucSkBC2zp{H$Kk<&^Z$ z=}XP$g0F2AS+0cJw+%+3h*CHo0J9W?V7{$1?kRU8*Q;|E2;;t;((NLHsG78$)33l} zBs}MgA-8}!mh7)->o2JGbnstG__6AZ#0n`i8X|t5)pZSxe{8F>iQ}Mk_p6b&KP;tr z+dR)x3g3gvKGpog;oeRmA8Et7pe6D>F9Uun8;C#|0S(|Lk6I?APDzHiUbOsI(>z&} zsRyBSEfbGZ9YreBJh>MhDoYF|1|L(>9GQNwnpr%yXq6 z-UONu01c6Foy+op*3W;i{;$8%9-KUA33ccBQkI?`*7bCz2HSjCfmKs~YxXp!&HF6R zDL%rZkq`I+CI%<3_2Fv($R*i`UF}ZQA0#<|J5e}5o|7IzR^0May-G*2*`Uo=3H&1R zbA-4cZ#p~qba;jNftl=WhAPBP~gPixO}`+FbWW ze%)Q9x}Pk#4Ts2tgy@zvbwef6Ph3&DPP+?Mu1}WFE>1+QFZsSPTxaCtMiY)XbSxv6 z!xzvQgq2RQMDc&cm2u9MwK8VnGFkP86b4w*5+yTZQEaYXRk-?4mLH2kx^|N54GLn^ zl=0R@K~1Um>NrvPQqvFocev__xA>sGn5fO0m#x(Pkb;sKK9mbgh-LeNG{`CG&vPqY{a;Z>Xj9U_Q z7s*PMecX~L4TR2PqECP2j|DJd?H2M#u=>++1l$58&wT+E>b^^!X}=pr49}%WJh=xS zxuom0uZej%*2j#6ns%qI&I~g;s zDBZ1MGsW?cT!kkyLGvhNX%MbOAqIT3S+bcFOIuL-nL=^Nw%2vHRJF12@Z6F=y8{tt zfi1s~$I%<(ie`uLkCg`BqlPy&Mn=Xp4U`$9>9mQ|-5SOVufL&|>SY8r6IDs;b=ip> z%vBabmekso%=gxj}4u^8aA#hz|K}4dUY}5FsMyhT?YqWfZO(#%1iQf zP;9C+c!xF6S?X)W|thV*)(YTBugdpe@4pXw@%xra&?G{H9U8@+m4+Y7Qezx zj+nOlejN1?zcgLGs)b#fcKU4J7p)B`)2#QM=BKgpq6*0|N_Kp`Kd8+Dmy;lv-#-?Q_ZV60n*jc<{cs@RloTO_MzTjFWOMOe??|3 zPPxnIC9X`U;q2zB9b;x4s(0hpmt?Yqqm3YrrYh+ykE4uCygvw6nBn}2jF6e(Bsl0R zfzOsEkQ%QC;H;{lgd8z;$3Rxj-vh>rMhE7X7EMu?S+>N)p`+GO8>_hR1 zDNT%)-el|ingCa{sV2>M(8;nXCmA%p)((uyZ;%p|2N;DU0EfR^vtWx|^FL7efkEiR zyp6WPT{n9YHhX_)LS!rsm)cT=L{fEzjf^kT%zM=dN}_JErNvk{D9PWCe{9pQ@kNe> zzU`HHBKa|L$Zt`A4yMf?n>92MqYa5GZ<;p-IR?0pe*7sqKGy{2Fi@f7`0t z5zd~<^=tK)yu<8%gVWx~Xj_O}9CU9S`a=XZ8d>m=8u9&u-l5VKIAf|qnJw|J0v!@T zq=9MM><!{Dy~t%DnDNx8WBnh`kD6Tv3)MO|H^18xrbjkdf6Pah5Z{Df8{>&<%o7C87z?YFI_0~>m^d;<-5?k--(&p`}fp-^t7(EnhQ%u94| z0>o@{8?}Ew4(U33fUUXYJWV_8kH%t~VU@iDPjBwgsG-VHUHaN;R! zpJ#&x!PW2-3PQ+gF~RcR>nl(~1MyKAzP92^Y868CC9}S}kD@I@xdXm@G;Dgt&t7yx ze@80&*c!>Iw&!w0d@f^W|6UbOOILi4ATUN_*PN+}*8{tPJr%4yYQehLWThDS!cpoX z(?!zlc!-`SS{%ILZNg8HwgM^wpW8X!RZcF!1r1KsH+vzWE8g3BAssbg}au)I84G-f^UrSxmmj_>FI zMcj9Mpij22$u$dQsN2>dAOM55N=gAlecn>bft>uFmbAA;f0_978OBeH2jf_D16XCSD+?($^zeK|Ilr!iZ+)%4^6}APYjgmL9#J`#39F+Jb8u& z;wkkjNb&S4f6`g?wY;ekxgDf_P|&F|>b*m^*&T7)b>Ar+`n7o(8iNtrj7k2Ma8$<- zi&A`K*HWGQ9k5V9T0azW6F z!wIBW<8bJD5(Py5m@0g1wc`?;L0E>Xz=;MRyM?H)@>_9d72Qk>20jd3_(x4&6?O^Ur zqZvG6$kQb@WpMa5RsO>XNF+jqhiwX*8Ol~P|UFL zgWm^N&rL-l+7~m^yfFG*(aPf^oVOinzQ?atZYoZo@f$XAoLH2cQ|s|~j9~||8j9Vg zmz8t~$-k`vH4ap<;UmFHXU)l|czK`UD-{zOy$jk9D}yy-^&lwe*Ugh^)fyA4n)OcF zbY<=1EIiSA{4+j0J%G)1xC+Rkkp_>W{ zcdeI0RJloXR{~_U90zZ27%J6!6#9hwy}l^YC`R$>M9_q$ku3uq3uCU*4pg;9Rn0ma z_X%jlxXq&kr(A3Yl{Sp=tblo!KSY7Ub-weOI$Xv>r@N?relnL=4W~f->6s?HAxUsT zOFGtb$KGqbOwQ{x??Kq-?oG#+7$`3w7&!p?w+LBIHM7}grY*kOCCDMKh;V<4i_M=d7;EQeSgNoe z6d~)53-4p|_iSp_dWEht7W8kIG<$r1KK5}d5T0HN~xSZeG# zSLQky6f+Y1g~^qYY}?Zd_4#yZBnF;utBiWo9{b|IKcp-QyX<4&PtSdoqi;pvFN3biRH|lr6`>JkV|)2o~T;V8>wY;_cyik7k#|g*j?SuuDg;s zjyDLYL_Q`>c0@5B1fAMaiv9^PUit2_GxqTCaL=4`a^v%_s|CIO&(>=HBuv<1ZmS0Y z_cj50AraaBWubur)ZuPVE~ zB2U2^MjClCcba|H%vT8v&dO7l^u>Eo_%e(Qp(39Iqp`DuGS!Mb&{Hsu3-=V?%^P;S zV*M``8gpY2{J@1T~a2oG9U z=N(ELxnafq1Ev!M$~!q`1EW)GEFRpYF+}SEBtXf<)VzH&fmG5_e+lCm+T@}RkPE*s zZ1NX{>Kp4H105)}1k074?rj-xrYhyM9NH@IdySSPrksCF5e`4sc}tmHzUlNOab{Ci zox0}b?Q63TYfDSoR4$YEmLGWO3wrs} zj=LR}Z_084PLMNOm29{x+eQ8DHpVF1sCFH0RK!+J9{&0E5*k)T+;@Tz$ z2KDHA@RRU(T2HXbivoV3qWx{BjHl7UJNo6@1(Ncq<{E9)4dB(}dw!fNfD0>%5*#jo zHcegOd+Mu>PvR=f9|iJk`B`Mb!oYT61cA}o0A&YAc%64_nd*WjElNT8RNi74UPzD& ztCS+e7bIB%86yD06WDF0T0i3g3D@9>vvcdC)0*kC!YqF}Yo~9rK%T>{X%P_3ir4(M z96c%>SEjX??a!!G!VMNgxhv zo*$FEI+c2ZtKA3#5Ea}ZVOb&!UUA`{zWVQRqXyuPbR_WkE<|rPwH~3=Pp_G?#iX4& z(RmB;exXik(lYR>7|yit7oEj5u5)H z?)xU@hE2&IyQGwbS9a#L6rD8}&y}qczv-2& zsjcBm5f?O5g64d99l_dYT+DXQRuHipru1wcF(R^J*rcszQvJO)KV{au@L0BZ|9Nu7 z9W!jVtxP&X;{L0e28c4V7%Q>VE?KdxyNJXrS#rzQ0KLMGyN9mRL_vm5Iw89>?M)Q$ z(7M3ecrT8XpA7lt(2Ee_c~!A{a$@tr7AbQ_(IfnVPmC)iVT$uXu;AbNf&MHR5kO67k^yMD;P85*U1Z;Ph+3L}jqpAinEKe=LGW4D1~QoBRd=(x;v z@Y~oiV4W}Lb^sfC59vR7U|zW?c*c^Mj6VN}t8K=xw53+o7`6JI8Q8-D&ME9!4F(QW1VC{nUSeX{8IWb=x`!k_(fiwJ|)9FqF%YDDIuwo z0U3;2q`0S~m_bI9)S$931eVXRH(PbOC4(!ZlNWOX2g@UZ^2&$dfpkQaIGT33ErstH z7~Y5Ca;|4VMmJOu3w;cf)CUoS zF%L-29=taXEq}XGA*DQx<`(6VP2$6!@zFdG7)@N~_+;>`4)Yp+SRQ7E9*%>zovmG~ z5a_0Oz)?s&=`;&{Wtw5~>c~p*lXKHw!|Xi#A|kYus&X@i%33b3Cr;xUnGu+%kt@z z!2fSsBt`8rP(sz?=W8|73usJKQ3U>ix4>SBqx zOZR$rLHUpC;B0GjdAwCn%@NP}-kJFx)SW-UA5X9HP5YqveUM(0zh|;{)K?~ER$gTu zQN2omzp-}7%)d$qSUBORVUZ^X$5b=&^vRc-F^~`K@M_WNkq{mKcc($u=>IiWOvzvRR)SyB=kF3E?nhFglWqQch+Up{ zBa>UT`5Lm|TE(+g+jk$(6d-Sk?f( z;MdQ*$uE_H7FKaZW4g4dx^@yWN%?+eJyHyC` zjvzsRY;^o8u{(79hC^Z=D}(W!Pd`b?D7H`6o<>H-rnu0IdN+&^OB%{#5?MzmAij+{(Z^rn-uSv&q?R#4eEjx9y6y^|vPu%#g^sCe(eIZg zdIiOlh~jGPw$OAq3{)$e0-*^g2fr)d_YYm&%0|1_F*Y6j(V_6WKEr&LWa&45T&%+8 zCm+4rd60P#WOfO^DA_h|nm_yX%lSWeK#!cBw~+*Yz|r3{Z$E|D z`XA}P^QCD7%zPNNd9OTYB6aDa&~sDrKRNYnmn-?>uHa~6?r35_W-6rEg7GWn3K5D( z?8PY^70d_pCHv>T2Flk+QqDxLcKb$ECllWv28`b` z%j8L~E(GMD8?&t!qeTUgP7gEf>GPw5*}@3YdMd>Hgi@^v zJk`;G?K{wtem5rSw7fTnFI6+aChV0qn9Tp|#-@YzD@w9b#vHewwh$TeZb-LcW|I@A zYHa2E{oFo?gF9R?_Y0dq7P;MikcJSlv;ls_OY_5n`h^R5M15J#ul^hf*4H*K}8(&z=CwTQf0eFgF<)d z2)R;e$=T@xHqW=4KY1IOA_1g)@%Tmg0LI@-jFOclbZ+;cnzUl^hW8R^ z+C@cllJX|sNbK{TH!LUFQLw7h+w}Pko<>VTkHZ%7k8!8O*kU8PUH8O&k#!2%&-$FT z`~r-!P|Z`jr6CM~-fwuwQ;=f9H!J))5Tjq)nB>or@**eCv~6eV&RNUJA65j*d?JFw z=`PIrJgtGq=qbOFD^jD>p6-}E1itw-+Vu{UMCI>_ujG7t0k>EG7)meF=_B_=pB(@D z28o+EkEi|RlI+$BK8d*!qC{>Pj-{6BFgOG$#N?v3ojpstP!`sK29p*%+DPOu9L$z< zO!Reo{1%<&g;bn_UI!~hSA=yi(d(;y&HA)rF6lRI(Q13341+O5MRhq+dW~ewMCQUu zW=fN3x4Z^BG0#fqLb5_eIG{>I#B6J*|M3(XhHmn(KlgdH8~!=wsugV6wxZzWeotfK zQ$1TKG<0W`0fLa}q^F7hP8f9R=Ps`)cMCHxOq$nLs{B#EO#&A+yk8Vf#n?pQ{gnPvY-O9~ax zEG=HLPSsNuU?hG?AW+aTU z&2@i^1y?asI!T?p!f9rE_SF%aIhTqNLV|k#W|_K7gR+AzQvU3LtY(n_lahle8KHUZ zo|uS7)dq9G`p@}hcluY@RGUM|>_Tq!iy!M9X-u2^5vS|4LWfE#=~Cd);pbfUc7_sl z>LTy8hf0{_>8olK*7B4|n^PXw?LfmK&#LOyV0E27Z#06T?!yrdluDDjlu<*$i@vY% ze0+QfXjsDpRv!etwQDSY#N%FFX%9|qhN1S9{90m3_-?WjRrq}XCvP7aK-npObhY(Y zhe#y``vO^PF71)2db*qh>#C^4oHO-Q46CO? zpR|k9UK1szlRG9+rAQXi0{1b>#0bLT`MpD>S!~&>|?OPwTf)LJC7S6t8yz) zh+WgY=VMvN$cV}`2igoVAUXykzIG=W(&sZixxqYb*)K8#*QqXz9fg2`^3aou!8k_9 z+Q5#K>5|kTIeDqwfhSPFfa4Q{<1O@&!6pVc!*~MF@XYjtdN}pSWcO>XF(K9oZLHE0P{*j6^@*TvEa%h%w7f+MlnIEpFt@UrszGfI+1dpJ9 zEc%Yxo0W7`b3WAYf(a&j-YTOtaL<|%B44~BUoz!@rNm0}Cq{_())I$dXNG%Qd}k05 zJtE?*tW@1npUBTsNou9k%3KbmA$43CppAd{#!u{8j}wa#Rk_Hea<9{gI*^_<0dDbsNX$f58?>dCBi6OGbmD)~CUH@w=KphMsfUj@OY&-@GvuXM-P;^;=E%~JLW5? zWW=_duX^+o|L`cqZc9z|q3k2N%i{;V3ukqUK~kvDDU>&j$gR$YboF@nKL}pDk$ZEM%7ri$?D}!u`fYdp6V#nNucgeRwM})J|4Be*W1F zo^NpYeSEQ;`iz>{|Dk5s!3!Et-gR%QLVP}!wJ-5_IPP~k_>-!oWP0z)ZV5~YzyCub z)(!A+!SV+!_#Nt=N57fEmp<23SJVVFZadE5*#qF1eN&Ut=nl~oF#*OIE2ok)9;JK1 zt^v(#AZjvlzS3DO9ew{YNGaJ4uUm!LG+ndb}?gSaRIJ3!9WU#~3fxBLvHRf|fuo&Lvy#2w;E8epNX^+m!gXc1C zldqeE<1KdtLdtht*}XyW-w)NplaOYe6$@-9j*b?a}}Dcsm~0T zQq11C;u59a%NcMm4cJk~$a4 z${3nNq;IxwS}N8?Cs_E=<)jcRrW{fRG|E>A% z%O*%R;?FQ@_l*2nqIQu!?wg_(a6c{jbSaKgbc$)-1i*Mk7cF=5zo%bix7f_?&;Cs1 zHgq2m)_ro5p#Rr4@H+n2JN9~Qk*2Jy%z0lG|17W*f9#2W{Kl?Z%@G4~#g!rBZP2nP zbs;eMBx?YxeaBjM3Wz4*Wn|G;{I1EXEE8okOAybVi1pigkovPsd!Js3+H4my4sUJJ zCP6H@z_LLqa=FrEO=sM>n1B|i=j)gYAsO`gCUDPFBYjmfReJFu0!mtno{i!C4~ zpQU-@_s7R?Ik%slJ664X57}$?GXfYz8baD(#W#PihI~jUsotOPjn}+?LJ1F#@Y?N( z(C@Gp$RCLOYC}p%o;SCrt^>l;$}7Z>UQ2A=zg9#$VKE9K?hT$SL&!UvJXNtp9U~MH zc$XDrUH4pQt@{NLr)CR;M3EQJ^-34+U)f$=)!I$#5XHux_u)S$EcQ>xl6az6{h~NN z+S;rihhJNPrcS9KioHd1!rF|q+F$}9P^M=&fe{KwvZI(amYt`9rnn3ZWvng9b$fr? zo9;lTYOAgDpiMa7W5%#<^(tZO7DWNQ1;J?WWCHGU#yVDPy5dyl-i`zaxn5gL=vX< z50NM(krYS-K!3D)z|J8ZJ6ZwfktZ47GAR{XN@eTekO0$5pEVGpwY6~&_rI!xQ;vNN z3*X8z*9OXZ7l)#f2~_bHJsRi#wMBt26B_*1Xy;8&96cpdj}&C4m96Al5C5&Qye+D! zrj!r#rDSI3P2LAepNGr$mCdk%f)%8?Y1j8v(Nbe}+3F2BmoLNT&abJVxS39;n_6n0 zjut@oWMz}>9ACM&FrEDIdC|s2FEHk~O}EyQl|C%gBp{>z^xW>2`t9`RS8%PySf+Ru z6XBQ)OAq0tH?0aC!|U{U$5h#b>XMkUQ?=O=yI?XR_WEqmuM$@dYpoXDi7>FwF8N-i?YV1`chD1Z6sx=&F*7U8>C~ZKx>Jq1cT=Hz zP9r3>I4n_b&811pwKZ+wLH)w0Ix#ed*x>#K|crBselx_^HbV6ys>3Xxcczq_5z%lPbSV5^9wKR{p`wug==~P;s*=Hu9fxD5?YeyH{92N&94gS8v;cLq6Kv- zG|wmsgWDL4_@C}}r(f$$ZRQh5GF(OUCB-nxQ!+c0dbf8a7+A4-6Vv0_d72(%STYF` zCefu&(9d9bF#s}^wBUfw;%|5+##dkxogo2_OEAHmF_ZP~o~Kf_DxI(SwiB#ABjawK z!-gv{X{RmYe%Y!vaUv(JA)pE!XXp>F6i$8Fg4xZ!$mdfN@t@EBw#=ZfW6lP%p`d}< zbt~VF31*gP@IMo80J>#?si38nnN1VV^6!9T0@h+$6%u6)UG-~4b3(g%bbweW_$^uA zgw^A{kW8=4hsDkiD3mB(;$A3E8Rect6W$_fOJJ9jws5Z0mLToLAx<+H=;i;qtmiUk7AUNI)VJp_Qs>;#@qA@dT&#C~_%c(;7IAowh-#v35QsIxfG zxnH!P5b+8>m>bx0ZLQSr%AT#5IAmeX8FSas0E>d1+ zt}0dG*t8(6=1J+aC^*9Q-(u8d+B}6;-1d9wHxY%>B82_?bjzB|VT{w>F@vF01sb-9 zg|AU)%ZMnj#-P~m+d+m3v_2|9bg-(8=pGKAJYiL;yTL7P&PjS{z3<&0yz8S{tpJ?c-pEQ=y+E7_{jywMc+3 z)-NsG+6pY5q*^C4r3_U)5NzL`6h(KrBY!r#2(pVZ8 zNNh?9=v5_jXz-J=ej;ximLk(m8a>i2HV%Nyw5PU@?cMw>+Ih3`E@yLJWKeoEET_NWIzsw2ly!m%m(|b0~PvU-=t7tk4(T0t#tKh8mp|) zvCDv#GT(zr2or2?j4h%j-+=w|+moo_`?8kP(7Bew2~*qN=+Y;soWI)#h8>?@2Q5<= zb-sye^xeFA{EK%Oedqp%JhGsT$^$SP_S^c!YY)o%a*faKhCv$uHkR@dtEf*0kp;1P z2&g-#)|jNNaZqL8hfIov3p)>w5{ij8rp$Y)x2S|vL)J3GA|01DWCz5_4--$eYEKT$ zrW5Uj&Ee`z-J(XPLdPXGP?9BKA|NQDMO%?o zYImmQJeTEc&g)&6ZG4(=c)q23)>9}4eLP@|0$$#Pk0%RkoB~5VuM_O-?7iiUHmMiR z?wb`Tj(5*s0p{pDsWE z#4Z@6#z3>tRZw!XqwXLX{lz-Bw>j*jPn=_R6tVX*4ye&{Ufz87W;@|@I?WR8pNs7` zH|uHA(upnYEaEYwVz0XcA8v|Re3OTAJW~-SnwW-riHGHG9{U`gVi0 z4YX!$+1YrGj&PY~(kVN`P)&(e2D`F30z~(NUpGx(UsiIS>9C`iw`+%TOk6!-jojNY zW)ssCW7{q~sN`^1cDJO64^CSUk&y44&bM_suan@wp0~K4oSar$o%qDW`UrVkqskY= z`nSAwLyr^b^6xLFb{h0x0DfhwzicKk3prX-1P_u;xZZ)|S+#%{_hyY4U^qt?d?@0* zS@W{RwO>64%6ltJu;JP8PQtAb)WH&8-p6+PDf{~R0A)+oQ<@GkA-^;h`w6}wCkE!j@ha<&`_0=CpF3Y>DUgsGezFS(i4p~4gPov%P{z#`)!1u3^cH@T zt54OOLn5RC+Z0GGe*mfOzn)5Xq-2q!@)%tCt1V-KAgGiqv4(a{b= zS#I0n;LFp`yf;+ih}e+WNS|UE5XdE2U`4}*-zh{3exxs$BB}TMR7Xe{L6QKOsKaW^ z?$S&_iiJU{cv@}Y={7{k?KtVTehaaGA8fu#UugH|tXOb3-GzVFg)w?>tvMKNk&{=D zFB#6D4Wo$2Rk42L(qL4}$EQ=(5uaTCYpSW*kj|*n5p?%Qi;b5fz}gJx>blY2M~(mN zk1fZ2J48hBKCg~GY366=<#p8&|6kY+4(Pw5+=Mr4yjzRp`{UR5BZG_Y@AYsoUt`zG z&Dl70OM>W>6-@eNpdra6LBk}u)6kURAItvo#m!QDj*yhH7In798!FK+OH?mvv=aGJ z?i?<;Foe1|)x)}OP*$G`x4tc^=y_4kD715IiF#N}O^Y;3G z?!T@8EfpX%#Pr*~WkqK!%$y~M(N6H!=cEn8KR*-X!uX6)V=UB6**01|+&P^vHGkXM zmM{q$ofv0j;~8JoPsw)()8aLcRV?Y{5tBc>-$!#qLb;uC$bM3c#g)a6CJ(2a=1qP~ z+}(?$W=jS;mKGie4T2QI^MZ^qJN+XZU!N%vC5IMWPO3Ooz7lUdPy+qVOkFjwg)WaB zg!Sb|zRKjK!f0-}TJ@-Krcw=*F$5!6zUcmXw#>Y7YYh%2utJN)>AwFn;I$dH*?7bz z=KqGSF*H7=r(OSzNQnsCvra=?a;%^t3r#)+sW_8u05T`~qTD9r?e8uXhDa<(%5N|3QU9tJ<*G*D4W^^0xthBKCDD=lv-g5RD4)^0IqU{ol9z zpU~%KTfDf$a!~MX$oCP7pdN=|k3(FaRP2;3mv*BG z&(2N)ztFxvfN^vwVHJK+z% z*{wh2#8&}nMf;vu@-X&gbnB=lAh6L-lRftNN`t|(=5v#o!Kz!Naf8m^lfOmvr#@hK znh*TG1O?l)N|F3M4gmW8%lO%fn;;iEf4s!Mw4?S9|3M-@K3jP1T_>%MT;=&AsUs~Qz{)CJ^p0&f)j?8DR+?ufD)8cIW4fdN=&FN zY4Wg=(A1U(xcGX#-0ep$qoXk2Zyw%KDgF|RwyA;X^Q{ax(x|NzG4Em|3$ngfBR!I* zoig1!plgG9`;Rr`wCk)O^qRh!J3F&!EbX1PI5Fz9;~wxU5>;75;=X`(aE4$lXdlM#-guXHoU$Xp6(rt(|@G>?!HW~UAH;#5?%f{ep>24NP@<6hCJrIf6*^PrN24vcpoXj&Z>NdpP;4s%aj`4C;>J99F z)ob~FM=upaD3(>{K85ajwm9q`2*>kn7hL6Xe|Yke+Ogbl7%w(3Sv&9ptAqg{mqp}|3$L%)7F+B#N7;%C?c zb2tXQ3B9{z-@d}_!(CwS;&0Z-WJZ~@qcQ4W7J%r;Mf&lyM3>BLI0$&Xx3-_^GX;HM zdsv-*g{YRQ-pMj1(~{lUNDEVv3o48TsNbb)bj#`bBT~zll^2HVy$a@?2cbCun*a`r z{&sJ$+^X*els?!KR7Q^=(@E|o<_(qzP<_;7UkG)-apX#`x+VTeJl08#n9O8x6+f`r zw1ch5Xe85CBcaj&_PFMN@_}mj`%GIAA-PpnPCS#KmMP$q**6sXD5q6|O(fv)GH%f3 zD!|GQcGuV)v@`lAQpmRXk3yn!=3RRWCGojF@jVynx)FmzAzT-nIcv=ABw&g!Mk)uh zDC5?us;2*#lhH`V|HJvjF3O~+uK)E#Qxw!_3=b$tJZ_Q7X*UIWaw+{h)1fmf93FSS z`sr4JBIc_|8kh7Li3+LW?F9Hl!;Gz|=(L5${MA7altsiEjVRq|0k7ue$qQjTQWaZX2JR_xDvNLJHTT?6BN#2-f?L=PGpS%-|I_e}^Yj>NUrVpE4T# zy7(T{ZQyloyfi)FebxE*m-7>QadJBb+AO!nO~yw5;70qXO8v840; zP}D2oFsx{c9gBvlxc<-^9BV@UFJe=sTh!0J)? zTP@yC=miC)fWCIN1+y`d)#H`-U_2WpIE0r{+~S}Z5KrMXZ`6kFl*E2JzNIs%?B>}Y ziJunzqK2lLXW}U~w>``1sLrM^F-fVUw)0{XE`v=WO(aPgA3+K;@+8BYDKL1tJEuEY z{M(FTlT${`k~x^rD!r+2tc!BgTLra3xPHmZ))~S^lgaXFTVl1&1_$^u4R9fJne4pm z{k_4Fs4mWJ0{aJE`Z>4<&v$Z!g5TpXO2$q1UxLeQ5S0K*eWi-eb&Z; z@C>RXq1L$o7^`;HGAAP`8H`RP(U@K=6O_KGpe!e+pG|4O8k_q0E<)=%(Mo`kEzZwV z%MG&_if5lJV8D!A>5P;P7M#AVz?P6f6$lx`%gZ&tL57cnf_xd1@gvd=wj%lo#A;XBxWOUc({x7Q!8MkwHs{_%wSr_~lHgWE2D z>dWOOMeNLpvlST7vK%>6G;cWal}u!Q{@&TQxCqMm`;wA+G75k`I+L@*^iHLLL+3Mk|cQ(U08lc&oNQO zllR%R!y&aT$rUu_h6m}s;ETXyZX5XXQVd4;zhVDLX0n`Ho@3OWov6cN&}p!R0eq%m#4tI~6b3NC!jg1BF zJ8$1#{}qMwKb##A_tQ+pLUr}aAs{9bdTHKxeeB9i&m=rcRuMBeheMr1<-BA&J1fZ; zrBgx3iRgj1iULQb%Do%e^>57^$x)Iro8XuJ-RveG*N^b8a=TNbEEkpM(+V(2Qk~oL zz{cWaRhjkZ{#<-33u0SitAUo^R#1wFKhM+x5L`;;C$7=%U|!( zH(#pTbM`V2yh-corqhmcZlyYzuQpw2s`5VSthp}tG8#U@C`moJU2HVv0~8;|CNBtU zim_o+NB01Di!a!iN@FBNPhXr(5104R!1FV^uq+=uf$WB{+SUX@s<=F_N2ON zj`qG!x{?qxkfjTM#b?sfifg_m%by%0HYn?!aYZIGn>gggJ}IJH5EiAeD=T5frt7Z@&h9qr2>c!I?fEbZr2}t-&i_dnwFN1{L7gg zQw=YO*k9t%;(WK=NONrCz2jW5j=u8Ip*IkW=)xM^)6|mzoW~Wu1 z$BwRMmG-c|*w8;ORa=vN(b|{GgPeEr&};#5qc#~GjZ~ItvSqLH_E#=VMuX8;6v6H_ zx2}Ntl5s$0&1te^-iZ{13o@6%ik6%)6`{qalc}7uL(5l@sE9Rj~E7j%Cq7O z@3G>{08%;U{)l;IpFlHdC~XmmiBULL#D6MLViVxZ5I5UuaouBgTJy;C)U7tYnPVOe}5cO}}Sr0D@S7*y`VMt*a*c7tQsTVteC> ztOr(3qi=i1=K7_F$v2Ed2HjuVTsOU;F!t`(9;WS3;`ToyXHFj7gPpd>AB3(^Qzo+Z zj)NolTi!p^*PDA@Xrh_qo@r!mPGs|R*qMAY*#mZP61(P=nTdx3fqx8-;(rW}FrfT= z^}P)3dLN(oevW9LopEt%njBw1`MNe|BdI8yFRWauT8DbKb~Ni|Sk$(7wjezUBUr0=O}%@h=hEFF1E4^-|I0}Kge7+qg)PoU2qurMS#Xs-lA+dM7%9S{+lthLEotsGys{^s`hbS`(+#^u20+Md7*ayJju`EA6 z&c2d%pz*LimRzOxbX*Xt@(63ARkbxmLt<%b3qjxe1_jsRzJ;E`tPc#68~}tXI)Gsk zJoCF8%O)*7+v3}|%p?X)woiP0dK>VeRz3+ z6<2CTj*^Xat!zzTQK_DW6i1&&Z1@xd6gEY*GA&^cWjA(I)TAv}xP^Y3pa{>#9`NSf zwi5N{cGW1%F{$ZSJpiu2r8*xti78>$k@D@sygp~%o3h3}x|Dlnd{jK`L(UJ6t4E?Ooe^RHeTZPN?s-U&|RV*9@VOB+g zj%P^h8#28AHh*WZcVAm@dO7BJ-UG-yL}Bo<4}xo~(|c40PX8Ts`0;S(RH!eQd+np@oP6`iugoR~6X3_CRbN31@a zA*IYkRzc1VlfUy-|7FCDI{mNDU}_}g<@py4DH6KhJl)`UH+;Z8;j)q$o7z4>U2Z_2 zh&OSNV34OUC#uz>yHy^ApTbJ*Z=en~nJR)xhc`sLtj@5IrLk zj_U2+09!?%($g~JC7QWPscOcD&6>~>2^ZjrK+{MZGlVm9Rs%iCU4iwfb! z)W%<*QCIQ@ffw43Y~DXK?f3T&9D`Z;*$0W5*LsFcX@I0MDX_~qWApjypm)h1C={WQ z=SBkUE>D<}@odX4-vYwJWkjPmmOr-l=v%jMW4SpVoHf@O+d=@MOnF7cDZ6IYAOJ<5 zJaM_|Bvm)pWdJNMWBIu_4BiIBshXRo`%a;SSX39my*R(f;UQJ>XbIVbPhs+tZ1tOC z6jqw+ji*HSEe=XWLzm9^YgY=&J%LA%?vl~Gi7>Hx$}b!7Z1Bs0ESN^ll#rgZMmBW8<9#ZI3Xl+@Jp0LcO#e=;_HpX;6H)22JO8d&fdRL2^XeA?K0o;$gH02sDI z+E{@%Tr~_W6-(_~?GFgCXz*+UB-|0AtaRA|-)(nhXKy2j^qTo+?V2qCMYYdA)PnFo z)WV;feE$68gsc4}(5XbRX{bh_sBP97Rpbl~_S111gbBoyvJ%Gha=gZHS04J5_SP&a zBKMB_oXi*K*@kG-s}QX|&@pR?b{Jj2TrOr`Ce+mt@?$i7_`vgKMJg?KE9w-1)Z8wF za@op6uqU!AIu)sS6!B!=Lb#G*&{Pk^+mg_8*W-BC--ln$cldDkB!x$6S`zg~X-BTw z?e1iNxUVAtO|3j^0{3qZ7MkW#%ogL+`SDVpqbq}|}SO_>(*cV@U(7U!vW^&rKU3y{B(dcBJphxcPMaM?RVOSPC;2X&VOhSxj z3-nc7_%JnZxZ6SMl=#J<;k+O&!d;o6_@7GEm zo?0$n6HJ{W!L6Pt=oTV@nC#%N@k#%eH(OdS)%2I<7A_$0V!?c?7bXbz@PdFe1k&XF5|s-cgz8kD*CJyb@r2&bH$?rpYu3sH2DRy{f)Dx-;>C53K##> z($y~8Myq=23zjr3-JkC0h&~_=d~#u9d!*>kYNrfC!s z+b-N;qAdb%4kkXWa(CD5$)#my?jFxEH0Wh#t=MlpKY~N1XpOhxi|$&JroJ@)`u>$r z9i%awgm_?$$)rdmq}Z&*F7#>abd_JL#xQ>p@=k{FwpE~YjTw;TZOGAS^5sgDAVeW9Pef}eDs6zRzzEag&AnQgH!n#rJWUe~{CdFSpSLfT+vWDwf zd$iW-6T-RI^#?8H?CnM`JJY+?X#Mom-5H}dL`@ch-wth?lW&29-rMlR9;X%F*As#R z2VE~%_kwqnS}cZ?LBxuYm^@$69Fc!;K#;k|@6eji-*OVHwjCg^U#2hA0YjnW5cY6P zRx@VKTR%b!eEo&#KkgJ#Qrx6ssTC|Jc$E%h`%Ao@eRq2qrSt4S z@1OoWUPLa610naLyk8w!D|Ne4v|lyBmGLB~$PAr}rV$4UQXmrp6p-?KaH0zCxl}}x zb4xM+HjEhD<9I|!X$F?5$;~UtW3n;|kMKs1mbdSP$j+HiG}+`}{us#_$BS$M08@Vh z6%-(P*j^X{2fgT)z%f6WWVK<};F_1+*6}V9um=}kW{pCK;Gi(t1%*i`LJX3>?ozF%z1ayzuUMhbrpSnLGiR6w3p7B`84p zq)3#n4nnx5we`r;@{CC-R+tlAyv}sH!Ur`iFCXELnZ@~XpQL6fBbbWCSqpn!Mv?xa zTpUc%WEWmi8NDAbIG#Nd!YO8&Zv5!0G+^y-_PyEoOpQs%=fX~vs3W3=U&cTkeT2Hu z4IMxwl(?XtiR<|x1{Z?7wTYm%~bul@dB9?GI{wVtq;q3KQ)XJ^52;7wSqmU@?$}0EdIN?2bZc zU#p5PhYO3k2%C#vUjV8`xQJaufE68@hWs%!6NR`!xQ5Hkui3$!58`S8PwKe1J!wiZ z`h_)B;PxLT+CMyfq?P4>ydQdHXBQ<;`~yJKWYIRz?A@2~g!BIL7X)#C?vviKM3-sf z2M=ND=^9ewJ9D!1)0GI2Mjxa>g)TLH#UNOy-Z{R57kt1m$_HjkAl{(Ud&5Uwas1of zw1n;%tOb>+SYN4|y2kM8En)L{XRzN-lP83jEdK0HrJot1O#RX|<;ND^aB&Z%!V<~I zr%D->OZ&JHMnF}X6*2o*&(8=Z@&?$Q_q|{(RNAx*mLvP-wDfdEQL`y@>cJ9s&kIA? z5V%7ETr)s6r^NpTX3(n2vjQU+u{JqCC>nGiU>}Z-ecK-@?F=UB z!66YswtHMFl%Jksy1HZ75(P3wz*?Kd)9T~|sKe{N4amA~)Fr%5oB~Uq3n=eCu(0^s z07ikFKeR4)N5$r>N-%<2s2F??RnO9;i?aWab^0%!_(xQ{DWOs#=P(}T(U=;02 zL^ecRLfbmyDage5Dgv!(I}ROiQ<#KY%9g5ba-~sc`_rYE(J!a!nUiXr=C>os|B3E6 z{~K^%V#4|*3miSH94?J%)a?QC_|6zql*!|hK2479V}R^#>QcU*(droIYFtgKO<7Kb zMz(oENl}6t@VU5AL|+7wI&b|PT^&+UZCMlRB+SUs9j*UJK}c3S0e(%D-#*a~M@&I2 zgKHR%Ol0P6U0NOevsuHK&|6nml(ZS>oQ&ib8i%h-KJW!0Y;+1Vjg71UjBB!jISugkwnk z69jC}T5B@C`!4>yvHCN9TZ!@FGqe6T$}M|mke{It6fCOxeuJb7~(IsM0*L8yiHYJGjR?4l>&o9?l;;vNteg8Jzh)?+92GvFUySv-UqfV-FTG zvarn9a={Z5uXY4FQ9%z){sz^A%(p+k1xkWcp#BF{7%Zi@o<6D_2_)#4}UEvwmbZ5yu-gOCAX zX^FkxF3y?u_wBBw-Zvkc0 zg!g?)&bUDuiO{!gB2#%^&{0KA=kxP>!84S!k&h3CG-xZHQb#)BRHS6)X|hMGey)kB zzwb#3>?s!NhH8ei8j*Sj5+IR}f@+f{!6BxCL`$niRox5}rq3PPbg!XaKsz(&@oK-k ziur^dBoXSzfgaEYi}#hQJ%>HKiDirS1A(0TmFOU&U!>b)5v>Y-F*4E(&byLtI!f0q zncc*g)8Bi6b{DIJy0(R4Jxp9v*6^+H8_T8TwVfob_00m3w-2!Zocnyt+v6%z9&+*a zJ9LVAOU}qUt=EN4F7{?K6OiRNwR@cr(YEatNqrf+{Ef=ec?mJEwVEwct|9j0&^nru=Pqi`n}g@0nS2TxKm zM8{BvV)2)`ibw#uIzE=GtDB6P7znux22oB9*zgN5`d+;regRa}P6Eb{R706kjS5@4 zssvoI0+o`VJSPMvwI)k?$fLyMRT|s#h&=^=A836+Q96bXca9CA9RwGEwq30Uo{xEh}w@6h@v`jAj! zB6^dKSbUCga;mj#&L~1-J58hLI;R%=JD-m$YV5J@;NpNv0s?${&8>M$3fIr}2b_kG ziK-Xt23`W&*nBs=p!`s4@j1n}!6E}PqPH*4(x}8II}m7)=K}LmlzU|D{WdbfXhFG1 zkYt#uvWX6*sGuJ4uqI{49dhyu(R-^SSy1AnG)@&4DEJc10_Q7VE_z?uC#fd}q3ax{ z=UWd$pB)8kfOuO%lWIQvxp8Kq{=ye8?&SMD9PwcM+tGG{832HFzTiugC=?lfwmAM^ zHFnT-X?_UjbAALGimc__4*S4Jl17+dKW8C&I=_Db>KZp5E5?7OboX zAFvI!zkkA#2xrBw3MW9N`yuJyU_55pYytzBcC$c%&;OSP-Ax3<`P|RoN2$Y}g z4MFwEiX~zNhFiNwGnM?h0qbanAPM2gv;E5IYX8vSV7SC4GdIi7t6}(t=|UaZB3)Ax z+o+x?$MPh6>-gy}XXK3*UtNN?deEGc$;~To)>f8Gfsn|lGP?9=UXNzE?B=WWPhN+# zmWo;1$17TkOB=Ccsuz1gAJn^LNVt*7zA3H~2vOLx`dxy~RQ%T+NUtPVD49LaEX6+* z-)3*-t}wM+pL4Fae@}`)u(hwbzOTw)tgfC~+SqmTy`-?UZE(M{sVTS=&`Xg_xMf#F zCgYH`sf-qRn97628PD9`O}jb#55NsJ||izQo8VUJKG@{n*J zVQ9R*c9Fq8Hnvdoyx`jH1vFOC2mA(dImjc_X^atREiJM*++inx4`O*A=n}6I{C#3? zU~c1tQ3PFdbLz&6OI2o$H)!>xG10Xox3T_D!JI-2QJRIDWsaT`iu?AcBcOZfzCPx) z?|S8`ULjLZi;7uFv9mi$j$xEZOU>Nz!!k(G*fLzC8MXu&G_OOzZYt1PSHu4IS_GPgRrn6gzrbmseos;#S?zixGX z{HG?)jW4m<%*;40G9}yO=aQMXNz~pPr)YbZl1e`rHRArjkuL_B0MRPKyH$PGy85C{HgDQ$o=Y)2bj%z&R{| zM(J{252&8yV-5PQt`8zIf!L0L#fj99zv#j#N`+~IortS23a6zBPEyd2aUew&i4i4@ z;lTuF2Ig&I0&x47voi3VSujX(?8 zU={qT?qncS91EE+d$X2?nU$R#V6IvDIQtf7AqIymJq`x-^xdy{zBJsi@bTo}uE>XZoIQp5~d^ z*dz=DQza(S;ut)T`6XVBcg6XWnnJI_iX36ZfRRww17RhVx|AUkC4Os{9S4Qo)rWzE z)qfm*?TCGQCv_yhU9R&y(?L@YP!`nvB~BVoPPq<4KNfZIzJ9T<^j;^sW9zK;IZ?c^?QMGGi7Nn-`F{BUkR$7NcqG^? z*vDH*eBlTjgILbWR9qTpjlX!_gmYYXdd+HHvO813PS)eLn;LI376^92l!!@mtWa4_ z-MC!e36zpk&>h~MFyK|EH+?iJGkojbs*<7!$zK_0g`~jrSlZiu8fv-qw=7$L)7I9e zf*u|j;g^-Iyff1Y<`_;DbogM6sY``~G^?YxX52MnVPX}x_2aWESJR|5ps+!;92Zbb zrg}t8W0Cf6MmEpaVEiC!^Cg;ESK76?`3jwjn+wm1L)*aMvyThBr9je`=({=2rUkA1 zy;0cvdsj47r^ib)z+E+-p|x&SF(*k+D<*91e}hfsDWNXfFZB^E8E;1N$|nw0Xt+&V zjF2q|m5~-&69TB`S7#}jNR?Ztj@`y#e;@dLA;t<8ZjM&5~f=5Eqd{lcsBH8)--c4fi z*(3Vz!}-)v6PyrCXA8@ws19Qn)m7z1Ck04H3{%%4n?C*OtbdEFFuW#afe@k(H$l^{VESv--&%ZT6e_A>hFDx8O^=&z&^+`sba?9`bf5q>^C$xv4v zajnwz>6kgrUSV3Ur%}q9M7%*+T3wEE3x=9p(RDW&vjgR){0$40oI+HR%20+4c$z1^sn|w zt>*X&w;7;{=FZVsA#(w@VS%D0vm`qtEzqN;X^9T^d1A4N(L{6O3ui0nBuf6QcJM^x z3s(s1fKdacuGsbuaC8g|_h!px^gCautHb1x0`uq2Py=YBf6niWK+~PeEMj2mOum8l+N6&F3wol*dV$Ko?t5f@nfV(xjOdjf`T!JbBnN~zkU;3NzX6L z|DFcnW6DljAFTfRo~4`&%EKilHo5<;5~Z%5@zGml8aNtlW@#%;bC)(Zw+afAqP}#D zpRY5Yxgr*DO2raxb&n$1>vxJ;3WcH$U-t|=D8?ZNMM70a+;dV<5cFgFqmo~$BFaEQ zE&|R0}D?}ksKH)`)s}*zfH7Qx! zY2tsb06p^|&|apOR|;-BU}?%OW2~lr)CL1ND&*jaV87Fk4AB1ASEM-Y;?QD~Y%65Y z(q$%d){|h-ntN_8>j5Os?)&agQFllf3WM<@ohCSg_Bo^o&d8W=|bP!bLjg^6x6+7Z5dD;vG zyC0&uT}-GX^FWQ!C+wK+dWT&V6gi6h1~6X$UhxnO$8 zm{7`Ek4)clp(Kl^S^37ZsVjlPa(`+UqVjtjk*_Hd!|&>yB$^w4GYLY44(tn5ucOZ( z$SAZ9sE4qWYY19<<B zR9aq`aWBOj{;}IzN_)fap{_JT7^vjAqLmuSg5O!zrTCJy1ef19*xb+kjZJN^`~4** z3CsjUtk?gvGN38bZzc&-OvzGQTIK$h>)v4{<&;S$4LWud;xAK`-YVtJn62RSzMQrB zSX^9U0^TUJ`udX$74r1_tiGvpbbbWE#zyXC{y=aDxOKAC8I~+Ku74iYyjKOd=k{0UOH&VZ}`*wX!cjW1?u zigueq2^3y|DF$ts!@H8kA5|IpJ9FOb;;=t! zjXb9K?PUIIQpVOCc3_&po?^|Wf7_Qsk$4n|g{>}Wg#W9O|fxIdwr*;v+GjaS*Q5c7H7K0jLh zKaj_${Otp9&}_UQ=$o>BBsvk;iF-~j}glO#D7QZe$CUT~D89EE2Dx_i@75v77Kv$#? za4iW^RrOvLLGv)*nLD?>wfIlpK&~%?qhLZ+*#fr$hj^uuiwboHj|ZuTVo1njRPP_| zTe#g~6?M?#PR}p4s!UD10ax&v-FP4zin1<-Xs$}dCqe$+!FlRAj)G)!XuPshxeA8a zI{aq4)j|VjV9*^{Iy1um@WJncjJSw8C7qL-eQkYLAQ!x-cKgjQ<0V}kOLy#S<$EB5jjn6CRy2lN|gPl;=rVJgLEUFpdHaBB$RBwm|=3a1agw$;^O@+l7L$o zedC0#p@h1ZkEt)#J0hK6E*hZ^JQN2C6MNKj-S4LpkmkQwQF6H->ja<&M6lVOo~cw= zL?I)qR%rfuI%g6EMa4urZEaH-wtWLAPGSlL%!~C-2{&I968H`1qUcn4O0{c&sSE(l#2x47v5ocu6&?_IZ3h|mVUr+eU4kf?%XL$y*hGkgBC7-wpKvDG$$;r3Tf1{M&QE9E`u%RJZg{ZG&z>ous$G#!|+t(ux1#~?dH9MLcYwxzEe*DlaSO=b3tHhBk>W?n6 zV5x{nK4{oDe{?0(A7tBJX*UmFJSdcSNzFO5;XQ+ObO9!O#KF0+M~y}@jhO57!j_GT zz0c^S{#{D&c`Nqk&xXOVHaFT4^rN2OR7EXWk*GhWJ|gjEQAkMBjo4H$ZD-87atQXr z4g1SydeVd_``AlI&eG1kn~z|~i7Y-h@b_KT8x$Pcn|MSeL5U-N6ky_6X1`|*UR>7T zefVxybepYfp$tN}02ywIg*!P)-bl7eF&0#Nw>5(4^nGiS3P z;HbUyw`5`CWD~JQoY&%ZzfX$s_EeNf76Bb{X&)q5D!KDT`to?um!mlEmj{tj_=FBom{sgBL{esO7?@xQ&EDdVcJajEfVZHsDTEg(#?IRmB z^MVD^3{@{R?)Z9IJW$McO>M;;z7 z-b;p@=e-gVuhXlVj~|h%BLCmu{H{iRTRQL`ju;{eN*Wu>y6Ae?T;IS6+S+(*G{VVw znlmC};fDx+n3BC)7lI7Giy;-x6T$UXfrQw&Ip9NK7cb3KkC@i+Zf6-27rVB6yL6IQ z)O0X(+8d!Te90y;+5SH?on=_mTi3<~1{gvZx`!I18)@krqy{7g1tp|QK)SnY=#V^! zfHa7JbayvW64DKd@cz&7dB4p!=3@4>_gd?|@84?IJ{noEeDfxy#c0iEO--#nbq!CmWSAeh(IU?- zzXuN@gJsBp)U~&YtQRr3gD9jX+fIj{Yn}t{nZCe5@2HyS39=CM9k`zUTzYo4Y=q3j zz%B6D|1;x|kLuhkg@sAR566^z_}1Os4MI{CfkpS3F2=77s6H!aq*c{7jWp|5>O=)3 zX1c_GDAucBMzx2x2QRtLFRsYl1ZWT^Fl4{>G0omv=mM`3$xW`tr+$G~kng*MzIO4< zDE@&Nq=o+!J3-vS#f*y4v^fopBc;IH=oL%t- zqy~i$M1VFiGnpz&kA!kUH+lJ5hxZlI{=J9@jvTNy$?Q1+p<+u^pr#GN-u zvipdD>nU5=D{vNl2NUjvflq6B0xcq@m;Y}Z`;g%{xeJBLrB7`S?2ZdUw@xOyVq)T|>Z?_4+thvYI*QfO`XyK# zO`72+1f`EhdloIZK?r5F6jb$4HTa6K4z1 zVZ8w-MPyxs_iOY&#;aKkRuA8KJ0w1w(m&u^oREI)Tn-i!;Kl(73(wBKG%BgDRelQO zy_tQ2Kw88sFj=ag>kxxKlUwF?IIp-!tX^fg1cbWN-PylfJN`m+I`n4ug_^& z+Gw`e<*iYcuM?fOyaH(kWW7;c!oH-7cUmi^g2yNxB{ zxFQP<)C){ZtR10HH1EUY3}ZbS0OZuB+V2!77!8$x()~dI`@}GooGv0 zOGVc3;)#gV5(aC0d{YjpB$?WY*XHlCVHFJZ|75;c0AwV0+cdA*f$3qP5BCR^lRWQG z(;muOfeMW;xMU&DS(~ko@*z?|;HOCp&*0YMnGi3K7dm3k%9A8%Im~z|Q;C%wEz~XW z*Ba#e>H7DPhm$esfy(<|mN&a79T59{)$A7&Ru*B1sckCVLBl~?q?Hz@qiHvqnzF&!=C zOA5IQZmj>x?FYx{|K^ECx^fW(#+9u29oM!h8h!n5jlpO7YHJjrbT{uzmD&kLtS zZqLxa8saMiaI2S2x(NAoTI-~Q=AiM~hxtjy(DouMOJJA% zI2_QsuXBY|nQt^z>!R${S5v<*@F5YXRAoH1`AGqOsj#F>WNSyiO0rUYuh|Y%UNxAI z9AsYl#?&kGvYzFuB7VPZG1HhF_R)9Wewo@{nZf}F+Ygm~x16-;xw0IJWh?7fBQ!DU z&%3*t67oRuUCdyrs?eR$*roFFO2(J82;$`N5s8qs`K9HzuBOC{AnPQp(wX^}CK#`M z?Q@XD@UoTdjz1Cy2S-|!)2cO~oTAoGMw*Q)Z~XkArLeWVhUONRKd%5KqAkV^*dDcU zjTx~T#te#gAqeWe(&J+?wUO}-Ns55n!sI}8@B}yjClGlr72pCxGS_#Dsez%93M9aXrH+sjy=a0fz2$ZNP ze72@3JBF=dbxZ!O$HkuZlEj;!7kh55&~R~apT7EjT7We8CUIZP>vOcRS4&}REli#D z|F!nRi@*0zC`<8h*5$7sR}TB*+gDeo$$jxzBlS-kX5De*n9z>7&`t4 z8jt+|8JF8oh{VM`mMp$@ZRU?K{u_X0nIokW{6-xxRC8INAf;-anJSlR3Ujgh4rlN}+D`TkPH6K<4v(GQBSbBS7 zGnzVVjt>hpOL$M)P?d4gkOKRO8!L&yKpz9iUb~7dv$M0SX>3wQlsRoKx6NJJNv$6u?hc{dOK#1;W%%EpQMz9(a1aT3@xktU+3@ z4aUhUHoTu(lhvw7<-tBG1d!jF` zp8EX}k&d@@yx=IL>r{4%zD|Pd+W&#UmDI9`GHWiXT^ZPdAfiMIeD%-Y{k$O+#D2Sn zCCg50Bq1S`*>%^fZ(MSbnv-Ln>-m%2+3BrbtJ`gTWToHX50`jp=TpuRFSFk?zI40) zd4ven{~n>9Vw8;tHg%<=qx}bVJHOrji7qdPBWTuP>wE}VgfJ=k8f5XZKAsvQ z*Z`FT)-R~rK3EXEGr2#fU*E0X8q&H8!Wy@#@1MSg6r;nMF+nWsah zWOm@{88w=aAcvB?Bx+F9NRG!Y9UYylR?u^tZ!sfA$E|Eqe8A910^mO*)S1=9uICL2 z=)`(Y`X5E(mBC8Qy)DCGGb*JgpUo|8lNmrttSBB!H;YgK6il`Atdq%>#+Ct{ATTir zz@q3>=*ogW%}|$>?L*KNC*C+Ze#jY77q4hteIqGHfkCXwpr#W?FRg0!8bY+;(sW@J zSlknu9{-4A1~<6N?b}I8WsRt`X7dc-L!f7O8@>folx16hq&Dc_DmF7AlVl$sA%9xA z;S#qfs|E{Tu?s1#pR``TNurFIMvW3lf~jP>2X|jTyFO|e+G)Ed|L}Wp&hv8ULt*_n zgxmYjAwWSk0h|HR0`)dyp zPSCS)w6i-nyBfVJE=p35iBsPV?NL5BJW#grjQ3>-fn6BTS99yHquMd)k0bEH`Kjpd z$JOqNr5^x72lTbyn~d3ep3wSvhQ!W|M}c`rRkj>uwJHnMMjb8DaMUx%E8^fmr5;EP zB8j2k65cNq^c|&uGZx%K21ugqBg!0J3QM2HQGOpAh z1zX%5end^fw@64*;slOD#7U>eM=}sPvNLDtdVXOgA5p4hD4+nApR_q@%=6wV!k9IvB)6s=}z63<}QU zQmh003g~;2_+@n;sukgrWok=jvfcVdlPE|5vYTkECG`yp6tByV%@onD;N?TgOQzxR z9JfRRx=~E%7m;6zLqIP!DyaFat7AcatJv(#o5=UZRgJZZwFTC~Sd>uO{MKgfRiDeJ z&mOD}$46&JFBWPojVsI-?nQoykN>BH(MSCq4biB8iRxyJrfq`-Hl!IAC zyyfO35u|#s!BwTuNqEs98_%`82h(b{OqYZG8@}jq0yGNphR~wYLJbss?tC+Wd;?kb z{L-Ew$m)3+J9OaSpi^pvAZmihu~$iT9t;vQ7XIj?3{42EVM~M;uxu4~VaJo>vNQi! z9Gb^3PRV!5U1P>HzLN1+sR`y*i-C_bLI~$-ezfIKQ&gfvuUOo1RXYZ-l%b(7Y3bN@n)4^@U5_pi}Tl zjr|a*1b#kcC_EdRo1{Gc{Syjw0gn*SK9`*GjRhD}C3d&og3Mz1U6BB@8YvSvYO>Fs zHb{ZfBi?!wy|d?uNW2VVV)t4bihro^1s54amLw$hX>)6s2#a@DM9czXsSJ2%U_d)p z+&f#aPg8*ZnPUAa&|d}RcWBoM508vFUtie|N-E>^3?%o7@d-vxW?sg=_;%H6Td?%b z%i8n)=Kg5)qEx5ExI&lXfAvoEU!_BsSS|#nIvb8fJ@>xhy%e%EeS2#<#6zg9+qgNn zu<;VIR%~8=bfek!K%54p-?>;P`Z}~U?6?i|h}cpmTt-=0;NtK!w=}{p?w|lxNPn{~12Tt@t`-C{eFUR)kmL2_`l8PZWCL)kJ5=H4 zemrOlYQ!PrUm*R@!)B8t8;g|8DwJ)5C#l(Cvw-F$u9`GKODPjIe?toFQPnFMIW%%V zVGLWw$n62HI@)yL_TflPO=V`Q!S}EfbGf1oW@ZM%03YXbbxnk$kTzUUSQx-}0GC-x z9U>oDQQPz_Qdv7SuPPmu)XfsaWFS*080r*Qp2;u9KXB2}WyOsH1%?jLk+CW3MpBWRtmdqm}AEx7A;_3c<+ zg|3tH$!X2O)8@bgfk~&9SpULD;ficsp?LA97cRW~qT;>%ClxFOaTV1UZGd7gOsn6r`XN6{~18==0qxs>a+rifV?qW};Qm+QSPvgt|x4uy- zlMc85oQR1b5FYiZVx?9;e_xj!<{7VAaREuDqvd9K5ne4RH2OwtL9@qFcb%ScO*p{7 z-sqiwg(Bi<%f+%<1Vg{KQP3J4RJIUNT%|ay4Wb}yh6WK&Pm-3B<=2tU7OLm5VIT%5 zJ9*IIc;YKbu!(0`sa;mF*MXB?J*=jkSp#F%+SV{Fs5;yg8}p1SAwHGj_3n-)R73#V zFR$ew!ySfTkNT`^LlhX@!Q9f0jGldx)Q}>#520y|sBbn*dXv+$n49w)bcUYI&8MV8 zj(G`(gM(61UKBy_2_E-0@2lW0{TLD9X_HuDDRLM&p_f zpoj~u4X4V=R=`y@MC$438G772+UG{VKh@)s=xqAjUe4X>OJBPj)Hfu`B^Kkj>HH|9 z|MP0O)gMoJZT2whixvb|IrSe8M%76`_#f?&Z%a}bg(DgH*&CcfYCwc=8`q?@m$XlU z@IS(2*WYxX0+|3q#=w zOSuY3HeF`%ITo%?A;>~my~;$37j@bZ3ObI{>Cg|aP3=P9_3+FWP8I``gUnJ7x8F^z zJ&9;QhI%BkhA!?$tEIEXwi^c-f|YL#XX*c&3_9BWubxQ;?9PT)d5F^TN^agZgGznQ zt}b~=559QLm*!7HWXhJ_TICJi?84Oc#VT7bBXS(p+HWW+K8TKu&-1Nl1iE7i%REz? zA8MX2V3@&SV2hrwN?}u7mps&dhB)Q_8==kP4Wu-wi zDRb7dchQ?wdiC`2lC3Al?c;6); zRiMG1abPmWrnvJUU!E;lKvEK)v8t&iY#fr!JcM7O@u6_yBXe=5Vc*Z6)N0Xq6H!<~ zS#Dur$~Qd#V$S6D!qUkz{5f0Z3~q)1{^RM4XF_Tv&5^Y%BqZ2P&WBjCY~xX|L`lDY zQQePcMf7DcTOb}(Ll}#mvU^|I?6oE@3^>+&+lf??IS^E5EisQx<+Q}Z)8gQnL_zH& zAD^%*QVBlq#M6by6fH2r7!?YE3qW61GrM!yZN9pr>{Oj|k{a~{;(aZmlngI=Xei6{uu1XRBW1+h~41u%jew~Ev1Tyg-3{ib1Oqh6AidZ5q<%YLB`y(H4Ymf49PPdHeqZdpH z3^!IdB;v0Vz{O(z_o^Hj`NkEmQ5|C8N_q84Y>JKj3-hby_P#0gDP*5t`UTH@Z|Pn9 zdGxzV@!0H&rOccO?0B@=>@5zeNiNZ7&83|Bqhx~j*EvY^S6H{_U{o-ynECv~8j<0B zangCQrC?fT?(7UTA%~Ub*Tvb2IF1iW(2DtmlzeFF?mrPtF4VcZXuB87_1TbQ?h1Bo zW?{OqGCPCnlNw+PXrDUmpc|(4ba_W$Uu%@9GX#Ns1Gokt9LTpIevj3|R0A~cLvnyy zQUti@0~|z@2Sp8bb90oyvPmqic;UiHlPRz#ieM|DPxH$gXxyMCx7NpsuA3_P-t7u> zO+*bbdNgljK(1TcfQ6l<0y1cY#{{ks>PTg=CO_0#?Xxi`Hm4m0eN+gf07h`y$f4bF z2%Mu=N%?fPwxMAVJJ&CBfjNA)0kA^U<48eKEP)L9z??ca;~!)NgAZXgs{*VJ+rao$ z2W9XqH5iCYxIA3hXLACsW%E2S8I}3j9QaxgoFTbWKY=0_j*7db2m&#JyW@%EDt$T8*=4m-Qzs_gP+vX? z#*hbB@FTS#t-@5$h-0 z+Z9=wl=gR#n|SDg4b$IJSJX7#0!x1G&9j#FSpWt~yu z>MH&UOl(2Q`%--DcC&<%2C$|N@C}}-eYhi~;59b)a7xfH42X$U=Z|LCSm!5XW2qV? zs$C9RlT>9X&U^x5Ph^^{P7TF$1e!z|^ci?;^v)QtE02+2EY9Wfm-^3o+!Y56nI4jV zz^-c1sB!keFTU(_93R1yx>);?vtmh6-9~|ZirXRlt@1X!v{3W-5cQ&Ozx!p076XU@ zBcCBDgUmi`v8t$Bg1!+}teAQ8WmVb6BgsaH*qZdFeS4N%JQ0A?1x^EZrpwkYQ4R7j zqtL&r8tgx7ld>SJ>ykuwR0X=0|6s=u#A{pY=3`HhKpj@T_N**5&M&Q6czD3JMWD-F zXbmerwia|^)Z=>osk#>Cadv>$M}(=YF^`u{9hSXjiO z7cn3XO-(A@V^4yIsR_9sNdk^j7U715MA6T!-m&Z33~9OIy*D9pD$08pW@h2mz|`>Q zPk(SnAxbX)L{^Iwh~PYzOQM8ZI(IOg-au=6H?`#w(?L6uo`xGCijWhgfatME6gp%6 z91akn1i=hUHcr1#rg?stj?-de)|S=U607(__x7JBlyo0DVK^y8a!Exn)iAA0Al6{) z`(xh+$iQv;bVYHW{oRlazstlz>@xVubNf6hIpvdSsedA zH~)X*++XYdH4(b77k>p>!%EIlLOc7459t|FuaSVnYrFpi`az39wFcD(_5W7@R>29k zBoy#H0ZX4xJw#dN`bF6kkKSwGMYxqhRq8v~w4Qx$IZF(J$}y;sLfOt}ZRwCU<@F#& zZ|sNm_FV?~WSy3~!J&hOXMGyb{3-To#mEzK78b*qHF)@BSb(xx>~$`(wXsy@^-vI! zJ9srx;aE#L58Nv^b|=`bPZxRO_!MUR1`9?cIMgEM~&aCeKf~ua0L;mJP*=> zQf4cbTWkiE8Pl}qs>z|V&7tNlMokgMia?Uk92p#B$j|7|KaNxIht7B zXSGwww4$zjdfQA+4O^oXM&%Ws6D-)}FqOi>%{*wsxw(Oj?zH0X@DmJZmRdq0Ziy^? zmr={D>ek$&U29r77`50QmzRwi0V9`j zFWi(D*gdd*QB9&-Lk&3YIE`!%4v+H{f@Z0cd!^GT^gO;)jhg(myzwC+<9|krXOGqpMJ=lfJyW9%B=-YZSzqvlCIMv6^zqy};D?2r3-OW1Q zV`&<}5gBz`Jfyr*E5n1z( zeqfB=QsV2QPuRvGU%g^f=K!<{Qv;f46vtZ%h%N^e;7A5jP(1;FQrS}1q6lj_i0iqq z$Y)~IgT8G&!FO*M`R>z+UL3i8Q%v zl6TaLxmsmUOrZXZLPvgrQ+_fe>y&uj){A`c+tJ^YglwWTQ+kmTh2gCf_=P?)RTM)Cjv)ebCjq|p(&yNd(Ybq_ zUk9cFdz6D+?PU{iA;*q$AqNxYFv;r+otBFYfQ0I*kS+e6t@UpEhox|Xuy|h_oqzLR zGxK+z|6Z>dibwF$){c&jN{UzB?_GS)og^GfM=Blzy)p#G<6h2HQT2TR7=AIgoXu2D z9NIaZT@Zct{o}IivBQ&=`}>h~<^(t0q>)U))4FE<1PyRHm;5I%hLBQ_mZ+n57C1c@ z3J{w67FJf@08{#mQdOwEosJr3i|;M>rx(Ga9K*EfKL%qZvc;XzU#RjwVL7e?%Mpik z8%8Jaa~Y$6c%S#yyZ8xUc()N*bg>5NRS6<b6@PqlaLb!*>05pR-54()l`PM=75 zXaxdtobyHZfQl3azx4T0Jtyf(l7PWmO9H2jVX7k4M7U{P{sL{$%wk_Ndf;1EJ5u(I zu)L~V@9U%LrmyI59ap@!mj8St#6Q7nyNLF=0vHoupRSRC;8doqqCvom$Of#=VJ59%+jye<$!b5Di2!}F zugVXMR`etSvhORHo=XQ1-$zd`bjHrlQaF9CMErt}Z*ThMm#xoFCTNMfwr9l&>4(pk z+AhT$R=#zt-t*+s1fM2sM8ee8$q?coVmjiwNy=hiHjpdXd3^i%ySj@LB_rr^I}f0$ zKEKj=I5T-h*YaK3?@r;b=fca%3&Kat0VFTcLZptMccc_n^G zkfd_<&HMOCS68sl_v<@oZI4S>e}cE<`Fm7+4PjASzSRg#r&ksqQI~7U}aY7 zV_7UB!W-dnZoE2Dl+>@^nz`a#KRA!I8YG0W*!3${|4D=muY4t|Wwq`-Eeu~cOr?d= z19Gx5ASYKhH$}~om2*Ra`a=`=^^=NlRwatGK#uJ8?fo9BtST|7Aa)>AdHb^EduCDH zBYGEZffnqq7=_HBM26~7<|4VaJ|X8d9}T@y{%3+i)y&~vydR*}ENJasDuSWpIE2vE zLNPvt)>+UV#JH-8Z|vwu_!5b^huNo@Be!=`KMMR`Ti_EsRmDI06PanH-lMaV!LJr` zBCt>L6W_>bJ6&|M@4i^t_DplHY*Vv!WEFN*?HSPNtAhF+?MQdDF1erN%Yft4qLz_h z0SAM)oIIrMJF_D+LMTslb#)whQo)oQyrVy$K>INl4-Wu7%9g(7QjRy?y1&C}yY1oS zb3c~yB+B4k5n$y-S7OyIs~7EVdIS$tt?KCeAdg$5;YF3D@?N%gSi?Lw+A3BD>sak2 zm`IBagXorM>9cNxWCmq$E_~^?2_4#R zEPc!F`G%2=BZWgX^-)|WIe^+itk(rY&NUDg)xRhrA?zt!vKZl(SXAY@6NY3#tZIn2 zmV}XlteO@N8>|mKf&i&A3mbUp{>vx-uexs2{BPd#6EC2J3jjQ<+#fysbi8kUxTnHa-d*FX0Fnk&;Ev7Kog84DmmkqguI16uQaMGKxkpsie+ki!1(*0lmaxww zM6yigb#$Kedz*4#@usd&@VN`xsI*^ZU?P92NQ1}5G|_BBgU8t^o}Hcj+Bv}!busU4 z7$>J~`N4spgrL$;3T<}A`caOA?qtj)1*N@8F%}COT&+GAv4t6nB->$XlP7NEZpDAM z6?p^ht2NG3AI@Kk)DvKI>M(N&*J4l~&WeDDaKQso1M@(ixx~D7AC0~Is!)O4+>WI= zIBW!LuVCP>fs6SN5TCrdTzGx&MxmljeN5msLw`H4*I-smZ*~?(^nF7kWfrBf%DB>$ z9e!0?bI-sOE7gb0-s{E2miPslVsqF8UdP&r%FDjBg_VWPMTt4EXcQCRcn7Qp21vtg zle^)zw{C9rmLE9xkl`+X3+TB&sHAD>#7072%GhiWAmcQ6%}Q2Emul~^1@AB>03y58PcV^g3K&Gto8YC zur3%GS#GZpeY@y=W&G#o{_?j|ti^`v;=(#2R7Mew$Ae!k_6`wl9R(Y=))P6Q;zu-a zFyFWppQxT0L&~(924V(3Hl|<-7vM2qzbcDh?jv~H_N%PzBCunk8e33DurUR3MdPdf zcm90+cS7VFsZkwyx0Cz>rlTD34=r z?l;x%-`ko+FEu(Apo*s0sc7i8cPD^NG|tImKEI|=idkIRb>iMzo`4z62D!d9K?2nB z*-IioWV><9uTegCN2O3p^|i;x!L`>|-xwSlt*3P~Xr)I|I7K{u54wH*jhWwH`u2tC zfMNRvpOV>RxpHuP&m$?1AdDXvaL-SMQ3+`KcwA8JpwuS~TAmb#x=aqL=y4FxM=(iD zWpp22f&$H}3?ukg*RO~3NvZ!F98us4D>pgqf=c4(Or706nEW1Yd*i-`)k$`Gs{<`& z;D3?LjI}{GUY08?euQli5sHb#Ew2JuSnGlS0?*s`UO~tAH`f9}o(b4PF8DDq8x?Pz z-EwY2J&irC#E6_0SOMhX4&f-RpZhygQw{juw+V{y|B}uA^#29?+b zzu$Ih=6}t5@cBEng4K(gq`i#bVOp_{&fsuZ_T5#~5(rR{GULJqO#^=7Q(&aSL#m=!}Q(UY9mtUoDb=;rwS9~t^`J;VtmSOZRxAxmf6+{!-hVcw zvpM`+p^MNbvc*H5oEG)ws=CEjAqhqG94nGL6B`^27YB6>P8Kw5{78OL z-4a91>Ma;q&-s{dLNIom%lWYxdT%Kf6twFV!^an_;Kw6z=LHAmOJf=c4++;|iaY_`uXyYrAoCSLdVv((>TwsJgLLZ4Xz2USf2s z8|86*I5bn)a(1Q$JesW%{8Fb?|EuYv{&(0uL4u5pjifKH?}3M#-tVW${nW9`VM>_p zi+qcAaz6J5sgVvwja<>ujZXQZfc14E;kgE<(fp92Iu^jJ6%!xJ@B128YiAHl zCgF1Ue13D<1$@hWwhGm{qNJZHRpk6S1$8o5R9PR*@lm$cRjW!81g-HnL@u-(`E1;V z)Yy1C=#j$UVS3iZ#g z+6I31a^%D*s;W$q7ADV6|9A$sK`@`l=BK>%vp;x*@WNF2XUD3qH3QpM1V%J8q@NiW1`u5;wXy(!NasLMl5bE) z(=UCXRPgSnqi^Vs9*eSX?HNRI*j!B^a*QENM+Pzx z275GMFe$dBvgglI%LJsLAb&@HKV`j5=tza{*>X)o&FJt2{$^otjOOz^)Ej#VQu$-!*rQc2xZR`#Fz$3|;|YVYwt-tLgo0F_%=$ zy8~7$p`WypPLw-bD=iU1?@CXKF&V9nk875AfQ4V?mM)kG7%k~`e(CCj#GOL3&`)UO>OW4 z<*d|O_4*c*NLV$m@7@M#7{B|y{aC!>nfR+{4Pqel9g>h_ayQNDxfwf@`23jG(@@K` znT=grypz!Akmq_^Z)^(iKP+Im{jb3%^!=KlCM$#QdBFRS#WsvdMi z=e-LgY7LXe;H*IYgdn+ioCZG@a$0qSfgTQlnia5&hFZl(W1>;h%YZ^5fy?BrT-rWI zFOt@SS*O?)wY4^I(Cgxkqr1uP(xlIJZgamsgb&mp@vEa{SSn5~1T|g${Cpui+t>k% zV3?R(3z7j5)k>>mCy4GlcPK{`g28)Q#E{&8ZtQqf-Ey1MxYLOzz?z@e@7_h_BZ0x~ zBg103)>W8#*}vEW<#@UuH`Rr}rE0BbW@{T9J7V#<&0FW_=zS&-0`KT~H&Xp;h#Z+d+#b<4X}ZIZ{^fpuFWvI%>W6#{8!?Lz9B$6r!{r@lvk!-k^1j>Z z#=#2fH9)@1Tjuq%fGsjqhC%mEhbcjhA($m% zp63NQ3nK8O`ppno;Q5Yb?TJ<5pDQVgJwTm%>t-G4LXo?+`o~+;k{uo|47^uP7NDt& z?(xI-6NA?>E8pA=2pM3i{}>v+lIN5!oKR5FqC}mQSK0-*)h*G5g@y6;YK?H<$Hx}v z;`bdN9RY`}*>%YtNJ;XEwwLO#0#ueQlluc!0D7drsU^TrflX5-ymQy2lP%#LHMjb8 z^vWTt;9#S*2Rx9EAqXsZLY+p+x*|+p1tM}ul*gPeuV~vYdw3^S?ejwv_N_{YJ4o1w zMholWx(eK%A(|AxicZi{26cQU4_w zkMV=FkiD5y{=Xd`)OlJ@h$e+1CEHKFy@|4Uy15svc|J;0S^f1J)YfbL4}N41vjUa% z!6LKVRvgG)HjpeJ8YtFeixC}PlaRRaCZa>r7jKk$l`^Qa^2D{2OQLM*{bJ@Zt(L&KeqJ?DSR`k&-Vgez!GlbKC4;R*w4yAPN@$=Qp7G>o>Scod16O z{BEP|&wx0`NKF64pp|?d)7#GQaQER4tVEO6(&ruS{#Q{7 zn$+w@6$=^AWZpbGZf?sBtkFSwtK*ONb7;DSOXbK}C-c>;yB2Y-*Ds(0z)bFvFSjpu zxw~PUoog7+gwkp;rsUN*ZQRK6ylUz1y(0H4iLP}vGpp;sj8A>W(eNlf`ih$pVGg=2~NosrIc|JrM8TbVZVs2HCqKsc(r zz`2;^OMnnghggvc+bdZatr4NmG5(*qDidCCO#gH%nx5WwLy_AZ*(JL-*GbqbDffZ} zzUdXmclA~5A0v>;;Hby}A^;8A-`XT`H$3*hwX))iMT22(2ydL}#Z=zoma_z>IGLZ@Kln9vH z;Yn-9?M=R_--Yr659?^IGUp#-3I1bDVGug{^v}n+K0mE_+HR?vo4rGf9llFMlR{ZY zYeed--arsN*^$`s5o_{{{25r>&Ygln!oz}^ugq;cLI&~~spaK$Y19!Z3A!}E<${GB zK0iM%lZBe8SLZSDj6Q6AdbHd$y0IawXb6DA-r2f0I$zF?P-xOgoc=o5?Jpqh^e^Ov z{Y{}5{iWJ0$uNRi8>)TJSp9yc-H%HDj`TlM9%`-l=PWcqN`M%4%HuyQgzA=Tz><_} z2j+No5R1L!zHP zhOjiZL)RzQ5)TT|?OB|JNP?AJ@&@kj9bl=P1Eam<6)W69Y+|mv;QinBPq1u#?uRN* zE~YdEL>fcJnnej2_#@F}tOuqjKEPCouZ%EhX!cb~%`QLdvJpwo8EUeqfj`gbae}@O z@0e}NbE-C0vC;V}6>l`CaLP8%tXI3lS2wgM6eBHcY*N$OuBfF9WEew~8LAjxlTuc& zzr*Xe{sKj7iH_%d5r4*=0FsNhsQFd{FV-uZ{g{s`Fm_}rE@H!r`yd*}PsIpoaVh8K zb>95>LXx_GL zXfY<3vy%kBAi&ozwd&}-dV=0{e0%f&E-V2yg!yM(7QYy5i6$n_4u?RZ4D`7kd+zO$ z+UtTRHdy6-Diq2^gj4V%+taFN;CW!;I`~N^F)g62&6P>cs$?hxvc5e6m|Fpe1YbQdTw7wR9R`%*9=UvsR&?HcD9@Nt3&8)n&_63r!404VtXeb1z z62exb;w6uYz$hmK5oswUr>B!;QGQo(G*LG%Czb!@1x+{g~qmd>OtC>%6R9? zUj_Rrj2agfJ^KA@v&!aFZOA9DnybT3)C%p`oTllKu5@{(7SS zSDbV<+^_W}Ov}B`diW!Kul(Wmf>r8cRBNWsF-S=!s{cA*+|~nElqkSsj!FiuSY6vS z+KWZ+wH`cO_E=b0_~SoMpf8ui(AvFI^(Y4HN2}%g0%U6W+W}@_p>`=SL;8)A>vKmN z8^{RPXOe4&sa9q_U1c;eH2!h2ZbqA%Q?OKRSI*5ZDH%|k6uUyF0hM?@C(iTC8B1T3 z94Zx~B?e;xWk*Yo0i+%(z)Fk5ORi z%Zm$3nk1W^#64`0e~X{;>5ZFNtWL?8DQdmKeU)hl-(qi|2H&1^6cbi0)lh{g01AQ2 zU&2uopYLm@h=Eg8Vl#*wLtsyjBJ^1%YaSQ@ z*ch~Jv&&TuDw50@Drmc<`>`dCh{Cv=x z&@>5Q0L7;gTjL}9qRdP{G7LpZwoa3qp?!w&Cy5-;BDt)PNo=3JlN!q($#Guw8a5mU z#||g|vTjdz?(h6N+D}yQzo@O$daD*iJkLybLx5+zUmll=WM%u`q03*&em3@PZp4fZ zR>L2>9=(%&P23kQeJ3e>Auru6IOg}Lf)q$46p15#l$0oYUhNSAXw{E;)YCRkpWA#i ze@dK#4%8`4e&-qoP?}pnK{cJ=qiDAX7i*(93$a-rim< zf&7_6r`;2xqQ<*3OR1jXXidQ08zD?>^4c}XJy(Gy3HHX@j!dWy%&tu}8A10XG9ltY92!x?RWjG`Glk}R`x(7C=ZP<-yyzMG00}(~mxB>*6 zQu7}Ak}8waT3al}SlKSe->LfWLWr#xM)2uJWU>Az%>!U z+R=yHtl?r1Eh2@f4&#b>jek?fFYaz8CX_?plDyyB{K|8n~}utfR<9h-pujk8-uMFqEy z6Oi(&)lI^!M`G47s_E1XXdz$QziwOkk)q$$d+!$x3_7;SXFb2PXw0SFpw~@<*mqMg zku)5i{sDk#VaLl&*V9dXQ1AK$yNkaKN0#2-hT|#AV$RV?<-=9l!-2`eMBBMY>h|~C zaRJIwbXhAoJ}|xt4$~T@D5IBxJ(;ZcmusBGqyR+H8eNu=t=;G2v+3Is1LKzkY}e`8 zlm*GhQ+ptEv>l0ZyYj?F3CTYfia`7sAhbE1ZL#Zqy8SWc6Gf5h8;InNcK4E}62zaK z+S>-BmnO!<#cA2j{!4e;PE)a=N`d$OJR|ljQ_Qp)6yS0B1OR?0g@`F=u`MmNnPmIh zC(k%`#&Xu~%rvWN+muUIWb?)miT@BE)6F(}w3D5+Hiamt4Yq9Ek?f?W(-tBtwaaFJ zc>e37b)U*=9F8aX_!n4|k=jII>E?z$_pZZ zTlL!K7GDuY>aC7FXUm^h%tJ(u;ALN{EYNHL)51d^!=${BxaqT1Z{7&XVM2tWOcB`{ zOX7BciY|4q7=igoKQwf87vE@Gh-AS3+~m&-sjF9Q@pTAR02k7l&wOL-^=!?%l9O?< z>ZQl=CV{MZSbAM&6G;gr^pneNY$bDSubf>o97OTKFYuv@{-*2hj#X+1XbX6q{|wr) zC7%ItVld%$nt=(@+}%4ia)KXNe5sW5#M~OLXN#!N1HgH0D{q1PT7Jh9Z||jl4Me7X zZi$_kK`yA(;21?PNO_J7Ts$E@HMGyU=|Tw2mG-^5n8Tuut@umb@D=>@*Ds$gC*yEv z2dsvazTTt%ed>Qg=;vYS?xq!VG0E^E2pq&fDjV>BES>cu-S7YZH`CqSG2L}^H^X7N zyL-Ahx*beUGwsNUneJ}WHN(`j@qNBN@9!Vrm*cvw=Oga-+Z`r=*w(G^)%QpUUIn}L zXvRaVS|=9k?a4b1MN0OX6f3vg0rw@{tSZv+5y^ZVK}Jq?T4W}%@#=VN<$}N~=B3u9 zQ3w7UnRh?G2Nl)_9#|Ln{{{qTkm7ZQ$WTwhGC5JVxZYq^TPF{=T6jSIIPrnX%+oQq zIQJb*D-*&9ID$6qyC-=pSTUVjoLhR3UR5=Li$^?G79g*UZN7-pASe8Oi&*xhD|5C61n0&9K1FhT6J1X#!sPcGgz#XhXy>@gQJlZmD%1>jPSs`)wgEp)p`BQx10bou_F} zqs9}zZ!a>7r zU%HTmASGmk977H0qp(TI$bb05ak%)!uwk7C)gP$R(8Jei(59^CRn4-5oDT;lz>XwB z1xS7nZBs}^6*#kWy>{X_=E}JCFQSb_+sXa?v6m;~pkz?%zJGyInqu@l_#I==#2M2d zlIimYL zi=@=QPR{}A(IAodtDH&4^LtLy;KZ{@wYZ-VTJ+L*d6LSpsNLtfOjk_`Ei zLV|*K``Liqhtf_!5Q4oE@lD=iJ1yl>b+YZeW0555l#s!9#7lbJR;Iy`R{}91cqcXF;qybo37zIJM`l^|; z$KI*Z=B05ybr9;*w8=>|Ks4^{9OW*{Zcw49JUk}s(^R_pFqe|^tm8^fAm`2<7m^^;0&`w zMyBg=tlBCA>a*D{y$tl9nz2IxVLIX1l8mIWwC$l&xZ&3z$Jy98=U&CGI}l1yvm#w8 zC_x$UmRn71*cJIZ#fEalHF<%~fzN@NxjD+YiZnL4DA)Mk33}7}vFhhj&Q~6Q5G3Uf zjq&oe7yBX7tlcakw4NIf3C1>}=8a1Zx`;rx`fpKh8;=?e1j0{=-qK@bE0$+?}^^81D z3DY2h8I+&^f(^ToSo*P@IbFIa*6ThZeQ%eJQ?$O>8_)E4EUN(Id3#ztDgQt0UQY+T z^e^@VEmgS8Lxm_<*;tJXPoZhs0xq-ie*h8nl((mnmNko0fQHIP8aE zJnSuzs5CrjB7kx?l|=rL!RngovxZ+L6DO%D93`&+L~pw1UE}*@vFdJ>GbwjP$RJe^ zQ;`0rZ&*3^o`w4cVdS5w{0Q>;3v&H_EntbaXXN`VsuIu2R>S7;tCyy(>*l>&fu&d9 zg+~6_28Z12TfXg)CgtY0JE=Ue1mAsYZis8$rXrSzG3FwO;3)Q=2pWCeiUvj^$w&C8 z3HqLh+m}-v)0ietf4p08R1^QVYI;;%-xW2a8Tt7KfD|`!+GV*;J3C|VA^>Da9H^)` zBfpu6I7FjOXxP5n=V*J6q+aT1#2LvF&ku~J-F^QookPEw27TPpZF9o%3o7`^ zOvp{V?R6(!vDCSF}Jx;-l^ zu_eh;kiX9l`Pa!O|8Yzy9G28<@$1*AMUjz>xl2;PW>1P{BO+8zAMPEZVmkhG274m< zU!U`orAG5T7ME`i@BMXa$~BnovrGbdypQKb(qE6xpL0#mj*mM=B#iGCKI$5O`iETI z^R}wGjw&Qpxn=2UB0f4~C;4Sh;q~M}YuKORJuXkQj0tylbbtv8Q)~+}CSKsVI1v0L z3JPn9%zb7%WyJ=)Z8sbCSm7dOs?@>5><*5^I9Y}rmaGqH&o@Cd_OE&f{NytRAiiYV=z&JC3IDLi< z;(Q)&HSyC+3#9R3pVn=9Jzul_9PMAGo3X(~D5YaNO@DPAUyN)#&gR0dM9wYUCdZId z(^cSoP}Hc^Sq<4x!&edOa(|>XeOmG%AtB$tkKLP4oBRTWFT)nrEA4t`$p)4#rPId$ z5>9i<-e7_)$E_>}$~99{E`{@yw}O9U8iTlfQ^O{N$1xznMy|Qu(Fdf|_`-ys9mO%U z=R?j{QL2}YWDO^$2}4S`I@g^!ooA7m&-Er1q4lTpJwxMEm@@ zpvaCXsl{bwiE1ZH*ZX(hRanI8zz2Q3$Z8ZoiZ9ai{D!{OcscvMBCj#Wb?mfQ@1}FE z-tr;8TBP-M8OgPhP1Oky5_>e!R@g zGu1PCnaS$;7w~#B{c;*onBB8r14%WJM`rFjYfJ-PWZGsUb7@HfoBr5KaqUEwuwL3y z1*=;E8fhxc2J_KgbobDA)--D58Oqsvwn;Q)r4^mYqoX8wT>IJsyFfUxbts;tP)K9p zhKTnLo6J45PWaffD4v#9=?5^=VSl!kGGXSJ5heNl&s9%klB-+Cd(#EH`~kWl8Et!JtwsHvHaq3|SKf)YM4 zQJCYYh+}#)(a;&>=EQmkjU6y}pZ=WOA6Z#6u;OGhkj{(Ow5x$tD$LFBqXR6Luu!5TKJlS2*|GZTKG~pS!hXq z+vn!y3c3AbM>nF}Sv)GR@b?IZJjg|2X0~DDdW5B#%YA_<;3%`Wp@t3LU!co1O5>&L z;lUmB(HT=0n^x_sr70s)p?Bm4exU0bAR%i4f!|~*%IRelE8hRxdT{>Z_Y^QnfR^2@ zyrZ`5eP6xA8rJxcWf4Euw;@x{SG#7GXX?~@bqJu6rI18KN|xV+Z4{TvvZ(30ayshN z?mcYQrj)# z<>UQZ*EGQ8=HgS-dM7n2k{Aux14c`-#$qE z`}wahq^(L#P??=)r9cvtdQ`#8L4O%6^;g$_m+k24El)H|0h_C_>-q6eeTR~=!!JS3Vv^~Dx>;wChu+I`*~ckO zEIx-}<3`G|%2~jbo}Xq1BXVN6*}J8v98GhJh{UImLTm@eOqS}`W0L4}>WoGQ!>&Om z+~D<}_kkO~uHV6ip8FkCbx@#l@c&^uBcpuQb@R+dgq#KsbZL zQfD>6TKyyu?i_CX335uYxN#2;4A5jZdSb^|PwxDU$>wIl6d@Es)I_zP-q(hDORzA` zpc_Nr77hMgkhM{}T78X@(%!`ZM;=Kkm8QwAO42~FwB7O*M#-7Q(NY3>i%ZB&6l>nH zGE`w9z3MqO1FFb{RVS_sSpz_D!Hq&u%OL(Z95TVbyrGP*pm!c&%vzn|ZB^v?R$7sq z)Yg%jI!^k7LN)ok=RCPsAhIJnBuc(CP1pCXNLUE10!^Ay&LI{*yr)Mzu1u7(=NYbJ zNWL^W^_avY@SnAVis$o0=cbI04<|+~h3M;UbmaOfR!E zU--T#)wr9T^Ncy#;u)sHeEK+Y5g!+;Wqy%g#w`hl@`*~Ur)w>RQPOz4*Dytbct8nt zBA6uFwsSQjdGvT=XgYTATSn0sIF}{0k8i-b#u8CHLkH8Q#9hZ&5|2kAcmK|VuS0K@ zH2vT9QAZ*RKI*}#OH3CUsCPz$A4>K z=!D%A^)(w+d+h$w^!I;c$|SAKjqc1 zoT|Tg3SD&=QS10haU{JaZK%|jR4#Flg=Y#bkBJxLwKl>KVl_diAs!|v7`^)@@h2M6`vGY-WH-H4A-OUZR^CfYj zU{gt$%4LZ13gwkL6ho!52H0{rw}-S8&Ipl;*dYI`JGcIuHkh`~^9`f;&@o-Ko>3lS zl8og?!gWO126H760a`G13-#C)lTNuTi$c!FbAKxxNbZ+X#yK2m$wd4;(IK+PG+B4@ z72?eu!u>(9+&e=x=$`X!#}mTI?>2uV5n5M>l0FqBQ}P6VkHYU(?9CIZ{$Se6jke@*^SldswdZ7Gs$CYm)QNr=_+An;RD32^m^z$yLGu6=fS5>|a(C z9L%KZf*S6GXXob#y6-2j1hA5lKGm7FJ(NAZF9p8ykD59`Z~m)6c^4g&=8G&V#4kF( z-!Z7`zZ2byyTq+Xd=n$pDsSnKg{#ay9} z_&bPtCd`;uKZ+07nd(!-vCA`%Xb|@1wYtun&&@3?3JhxH^OE1H`&EVCm_cmq-BT?U zO!tD$gE-?=Jez&IXIJK=RTM-_|E(?C+dG(@J>D=CaVfDc{EW&pw#v*%VS!Ho@FPqE zIO$rjl>yoe$*PNPY+~i&Qow(*JU_c8U3U06KbJ1flAc4Gp+Z2C8e+5ec!RHk5%@HF zel?JuoW6wHrJ~7Uh0^tw9!i=MeC881MD}8nVvYRNEO2-~|N4ByX4pu`3~%zN!F<~9 zFr`oS9*JDqDm&@)j2berNf_?om*mNa$?NmN#}4!4l9){08`kRyrekM!25|)}i}O7C0Q2x81JHm<4xbmyjV3H6FSC*UREP#fWm+VCI%&Ils1M8Bk{@DUFps;y;9_KwWa-8jnn96xAIeCC6E_oDhRQeM zZ+OEm{L)!RvxiF{9DX#dHCh;17Y^EGk7$DOu4ZSNIwW-*iXpSAt$>)<8Q zC{_+|q)T0zU}uB3=t$9aR6$QP-e1afwRG}AFM@Zjt*tTc$U6^wTIcg=ZtyrTP_>ZK z!_CznLPk_KQAMjQmBg0JNwOs#KCkSDD_mCH8tTS^p+iE0^>w8==zT8P}&-DmhB+6box@W_ZD(zu93yVXN6L>`aOh7Z4gnQW_@Dy1*Yx5Z}UF- zmxNDd;p;J0nwA`8$Q8KIp)$BH>L2laOs}N z3)HTX3ZZHC<#X%)rF{CKhMKmlsB+*a+q`Ey^u1lpYUkq_Xe!_^FeGEnAeB;%l1Ccc zp<^sj>CXb9vrC=l%hfoC+>QKT67B!hvEN=KK2k{njn=T_W=VzZ(b9AO5!FNd_lJAa zU=3ZO94Ky|EgP0s=(aw=PWNCut05}Y=|?6n0c~U-hJG4pwJL1cHB0C4YmR-1K6eUj zVr{Pvb8EAzWjaGjVdE=_ySwk_<80=odi`XbG`i?5Gk=#<3ywa6 z2pv?}k*}Z8C3n(T)YyRp8gE`PO6nL-PZ*o(WJ8S)0;4*4iB281To`@90vlM)*VfL( z-sYs0T~&4Ra?v#?zGQf-mo&nMa4*~#4TmmcfOz;I6=jI=y`oyi*DCM?>k@~ld>u72 zzudN#SKUBMz-?pjIDg>F4^CdUXJS8Q-V0;150P&Ikd>+x=}ITyw!%KtSv6b;9cdaA zm!f*J9$ze^&}z(hLWpzU>z&kN!lzEq9Ar!&NLEf|NK<^5}f$IQDquvd*ChYaXJSj6=bL+ZK~;#Ro4Q;{3|n1_%W4T6+0wNv*`~07K+#a9bzoo5>gSYTzjUeysRkQ%1+J7Z_}3b-E_;FFxe?Df;^rBsZ?d2tHZGnV1%igQV6% zl<-(ePob3WL0Z+a>aFFxMmDN14rV%y8zs`4Tnt8zEX|@>LOBq<5Z!79KGZ# z++&6h@Z$;BxaZbyCiLBwX0}2Q35HMCLqcIh9HBKcYjeuL0h{1VB~@`ix1Gw{>64VW z>%JC8eB#7D@*H>oekzwkv^$C3R`y)`6DKqsYNFq!pKAIiMd5bPj}Vb!J>+uYG3?5u zRA?b=7*WRL9>tWzr2DnTs3)(*aoKZcjzRpXW13e?NUqjM z9yP255vg=&mu~v>R5S+J6#?yuMi&`gjFyN zb#O5WMW^J1&ML~tD}L?0yudt1=Mni89cL81M9Rz%!#Wz@@D}VI*_*lq$3Uq{OkD32 z?M83)P*mfrY#0023=f4Cot|vz=2GSR{mDQ_U?q#U0L%oziCQ_e-26@B)NbA|iWImy z?Y(uL8Z04AL3v~_Zs?Xa!zzKmQ2^&ilaU2eu~L>ENM?_WL-KscAGmzu{DkCWUQxbC`esdnD~3m%S_YjsqoPpHB#Xu{ zra8d)O>WtrNu6X_qduGZzNILZdF+5mmr(z^ix_(%LuResX!Z1W#i}w$-ITzGLgDd| z5oD#baCl3t8m#?02L|i@Zy7a4Ejd|O6uUe1fe;7hw=_kWy#$q&LY)Ugp2>%Kg&N!z)> zF*Dd3$gohfD(Kc|Fzqsh!q>v|&Qmsvy%LCuG6m78;G*S`AroO-)SoDi>GIT5z_|8_ zEiCALr~=MLN{j3lMOZIv>)xlb$Rr+0`j`lkpr#+Ah>|5R=(zRVfVnZjnHX*uA*G{M zq&8Cq5bri#p>mCiOR!I!uECu1G!sfw|d5 z`8w#){%DCAenryvA6Nx};Yd^uEYso->>T+bs*cRkDiAe_DFyQeBF&X%P_hn=fgCZL z8iwDWo)Z`4L0U)MS~^`PKn_|I3EX)d9QUHgBnv3ih?LyM%`OJ=VE&;{Xz*SY!9WYD27QUMO zJ$202UG_2pLp6;4})l*nbw=6e!pAaS$ z3d?{E0jA&;HJlwb^M!z(QwrQU#T0A8vi>10I;!p|4{}%w>JI-D1eWc=(Mi(^u$mmw z-se$)hNBX5^}B7}(Pc%uwGNH(SAWjSDF#oT9-Fw|-&i&aw9K@52<_qRK`Vwkg3rYX z2?_5X+bFH?rt+J8TK8~O3^0&^z=eszBQeg!^0!_TH-$lYWwh&}SfQYr@oP10m>N)d2fm2^}< z+IpO_1iC!e)OLW2i`WFBOeeM=fO$W#ph9S~I55n?3WNT*xibsIvvUTe8erMRK@~gu z6Pw}kGtt*Ea{wuAkBylqJt%Aig0lipH`3)ra;UK>aE|PR@mYk?Z>b>OEo_$bkuoR> zY+}x5&cr8`IU0-A2#Q2C_TbJ2F)dOGrAXveoLV5BX>P%q4d+J=!P(D%3;EVRD>4d4 zOlfZI&v}vPj={wwr}^` z0TWainXz&epHWmGz&p=VR+u&`i`enk$;oaenQK{RXI6QpPIG1`_0%AM=E?zhBq++v zHa17ZouYjgBP58NH=cj`h+E=hks-X97LC*niw=MGM|qKQa>#6T>x|rs#UuaQj!B^Y zuc9bn>~7H8yvU#ueX98W%1HGud+hX~oGD4p#33Q0=mIH)GKQ!A+oe7%WqYdgkHtyd zzrg2t(?iI)c;8m~wHpGxF3(t50q-kD^j|2m5`SPW}IVyglDg&*P+qqMs>DSp-rC2UK17 zCR~?RNd<(tXBvqQm$Ms^00EvJPSB-WZ_*sYl+FJz1_wXJnT{?tEiO*ieZ*>Oo$=!s z;yPk1hc~~JbSLVX1jc4xx?@wa5&)GB3KCemy`i{VfI%km-<;${qvA+2F9$6Ds)imrX;&V7n@g&dv>qKDp;PvfLCREaq-ZDEV(yJ=mwpAdNS~cI4;gy1GCfkYK&kxPn)-tI)7`e&c1$JARI?G zA$>zm8_@uHmnD_LPh7?mAzR&RguSzUn9rC%Biv7e>>yzoN7ZMDde!V?{^qxOGGhITH_C{M{D zeGeC4D|X}Untt1x9(#5aFVCawJaVgx{p)7$+f+{e;*6mcd-T) zRVe%eO95QwuR^uO_hg6!s# zudmnd{E*A6!iW8%Kd%dGT^}sj;Xc7LBhn@4b0D0VY!4X+k-irWn7<-$Ie$BxjM81_ul}%Lu!jZ^>~PRENZI0M!>5R}N=0I>Mo+D%;Hwm^`+n z=*!1Ybv*P?f*QSz@vD!HRT)It+4)7V&Ma`_z~6hOji7N7D$1hFr5R}p)g?eB(g?O( zZSrn)`8fuO&wALm{exvD-*-#xr#@gbs;V zL?52fL@)0F>Lszcc~OF=S$8izCC>{Mc&EF!9MO?tP@0Wp@!`1b@&1Ijj z|0^6^Gk?DW7IFWOM-#^SnHd<=_5?x9ncrR+xAHrgQ#i< zf#LZ()<(Utc(l{i*8FwXu53Up7hyf_Usa08j6aWN{j!T!SX7HYySb=rEe=tHq|`CK z>#&Z9!PYhA{17Sm%?*A%^MdL4vd?A}JJy|2r6EcQOW7XP9g~@Vi1Y$AH^@ysB%)9Y`EN&j2q()5q(kkmfr?`x9-R&`JRdCsYhSlQOM|2F6{R_w8_J_k< z4NY=tmmyk)kvwToG-@#S*tI8LOEVqB%FZK4v9A|$t$3a~r=^0cQ*R=pPZ==qv6pCY6*5WQiLbiO9M` zp^VZT=e|VSEXxYv$1G)RLHPhLl9qxfi<}+6$Qx52dpsj>Xha-ZhRH_EEGdsl7fz$@ zK!s?fzU{4-%kK>7?V%;FYgr<8oP~>=dES4L7&xpI@jHD=_S|@JY!s04O<{p+vgId} zj>O7E3>ys=L+@vqD*DI)zleZbKf@wzMDh!PSPM-ic%_<}!LF8hUl|!d%O6Eb=?@dU*KE(jXM>U@dcOrAu!CNEb6kw zi5Ff`3J52R?B5phx<`h9h7Z{dnf9-IaX8S%7D*M7@^`9D|6xY_W8@w}q>NAITC(Vt z{n~3gi<;--Yu`YRoHeJx5?6j0xYPFlTNV^(%`@F>>oR4w-aMWD{+|vfMC|_x3IA&b zBEl@4=gDF5CnD3=-w~ZELR9t?scFT54OP@4v#uDR)IE|NIkdCIk~yMf6Dp?EMiSxTTI`(*c~KVx|&%N92>pqltOez z`|AO$E_UeqtY`W{Ikr)~42-JGZYX1cusqqF?moX*7-pCPiu#8^Ad0~Ac$Yy~IKa-y zzStle%UQaXLNz%dl@x7Ci$ChPL*M`DapVAv812D=?qSG=1Ks$r@8RvOX(tgU!+`-t zB6SPpkr==2jAEp=s=E5z!e-y@DO*OF$4Cb#LdCq%z(WlH&CJ-5Xg(@3WJU_M*oK%6#r28+GHp!QcbZ6bY`HwAzqTo_YllI?IbXLAkqjSwGFKWy_KCa@*Lx~11xO2l53dV|41is?#8@&h( zRCd}@uAN)sVZEIc9qMNK3jDdM6uir~+V+7=2p6gE8!_$sL)n}JKHr<|;JLMY5X?K1 zsguTbxv#zP-O1LE9H&d~x>&etKbayMmBUf0jY^O_W}3iS?In+*Rd+z3#A|gG4-o%| zJjcojNRUdwJK0k#74!6ZS&^ZNtfg7|d$izTyKc%lvMd)A;NT?BJ!1#aRsNf=G1kU zj)Gj5c9eAC@*x}F%d#WigAw7JJ{EA>UsI7%}U%8ve-o=-!1w=XzGD!hzA-@~grB zI=%O-N^|AWR1YtO&u3dfr<;naU4KdGz>(L;I5=`}ReV$W2{6z>4AgeIp!R3bouOV& zpir)W^WlC~2@^@GnWpA|qbs?2pi8E!_#;!X=V6UA^1|r;Pgb&x~M;jjxRgW_<)wuvV$*FRk~l@mFW( z5%29+&6Br#Q(-3ahiTD3WUVni3^DA>4xCPi9+W|x?i=vY-nTn4nzFPVA?E&Cn_b*tU!MpYv+rjNMl5)b%OhF9*D?#u*xByfDGG$3g4_ zE$n@rVI~tGTBX?xh}D7HlL-sGCQLz2eOIqBK#h>90V--BPPow{(lIfJCQrHGa6(i4 zlA*$!$`ZYR!@-Jp!C|FdicChZBjcKpM*A!rHQETYGoTNatUoHu zcgZ!`q|1lP|K5JO_~X+PQTUW?YVnlhxYB%L;NXsC`!q~UDU=+?r?p2H_!_WvxWfq; zE7b#|2ajoX^~@8cMl{IHYI;SePNCvNJ#{q}B1xWhWg~+*xtJ!yiGmx_MOE2xN`n_8 z2Xg@XKDfVJEjP*A%L{!m8W2?iuX=gpw0PwSum=>Bo1K|i2|9n>R(LTtH*XfA@?(3; zcU0D2g1t!_*;|ph;7^)s>Fv7J+wB^pjvV`LGEvQ_-8anBc8Uii+_!(qcRkOmnmkE! z6~6U&wsko4Pmrqeu6LLs_-Sesxh88J^T)2`_^YM7|sZz ztn+lH+=~1q|JoPKM$>%yu+u7UZ7r?DFv$aFPOJ&G0ROnn@ANxT?}{#|0LVwaNtxxi zmL=%`ZV1y6W@yZ)53|8I555!8=;IZU7{A)I-rkwV3QRg9Yr9N8|Hn)?rc!E8l6C)P zu^+J$inWS-%qMNIwzh6}@(aD~O!2Ey;`I?nlkKv=SVknQLOqH+@~`4?FSY z3_#!$Y)y8JCJN*-4U;A)=#Y`9s?_?ceH^r4>Q-LZkgNgfzNF!BT3m!bKfgHIdx1YK zdP7=Dn2%O#CSA$a%dR2ZC#>;dhl|({6G`75N1obBJRw;eodG;V?Ip0noKRhqk0PN* z(=b&MDQQm-h1w*hOo+a$8Mze4ce9V?_mx9?L^!v&Yzh?{-Y&W252|Gfy_)^Rk$!hi z{GUx5m$mL_g7I&^3_Ie>lMZ~(XWa|XvoSeNnG&!j!5sYB#<)6i*rc$LR$5=DTj_k2 zckNotUQkA=qy9S+_$#5+^z$yPPYZMD+FAwve+XXszdy-*%i@QHoQuaL3V9oQ;%x=) z^7mY>2r_5uH+$A>H6>#O-@p4$1iOPI9$m$@bLq6&1^Ms0uW&%>x4*7_u}cbk4jabE}9ElzHxeBgx&@Yx7vq#D@-BH(iu`&j?0_P?#S zZPovY-UT)7bB2IWh<%Zsn={wVB1=B;_a*OkyWgCT99VLN=fLpexkXxC4|{xG@L{}w zZ%3&b4N6LyqNr1+Kb$#fxYA`#*HSumF@Wt(e);1rBqnG2TDLIZb5?vEJrXZlorio{CkgtfNR7>9Xp>a%Q5lMjT0i1^v97dg z2M3?P^h*s?9yad^x3^w*&S5q(f>aMJrU!?)=eAtu0o^ctv947z(t~XY zcb`l6&jb0L$<1wxf;9hE-H`vUe8}i zBF}#8rA|sb!GjTImE<_+r?`k*si&SL>`b{KKnT60KTBWFXm{ux5-~~7L|-5J$#UKM z8!kZ+GM5&Jm6H=b&JWs${+E5H96>eVxwdcUT z)d~j`=upRZ4OIH&+%1pAGSmcG(+^}g2RX3odkkSwczx%^ng}q`{M(Y%c zZKayvrl+oU4{PdxKc~~cF=0v@*foy3!z}y6q)M$V9Q}P|PcHHX&KALbadxrtVLM=J zuukmhSid6^Be$-s))QfHh|s2DcqBs@05s$0cXx*k1oM0Sc_+#p@Pv%?iG$D&Z7g-OIuPwSNaT>L9PK}JSro#-TWrQAS0Uch4A%QA_OY7e7dh2{IDz~ zaGf|@aCB|z8?ysb@H@(XdN{uO9{-6oV71+xH`*kK!q8;*d4|4i!yRd(JBVDuBc|in z{X;=_?@Q3rN=p!{f~im>FQK^{@>nP9K)#u;*OG~KYRaHV9ua6qNeNajtcOUKKfH#2 zH1^Z|$oceVV^;pUw@lMO`OS&F^Koy0REt3gP`)OvdsqDk^GsA1{kM_3T(kPu!O(F% z20GWhTA28MH=*-?14T9MS{>HF7f;j2ESM+nh6$~)4%$iJn_8tEx1pJoteQV(hi9%K ztVp+}>H#Wf`4k(zj`l8&6+qt=C~jlpf~W=C-;1$m1e_z;VQ5E{3u8v#k4S^h=)O;N zgpEIMkGgX6tW4Lxj!ic@EWYo#s6BUom_xD9#fbJkif~r&$Y`PNlSVuqSTu7%K9725 z$W-|WkZEdw8=z3;6CfMn8@LN4JKzWSi=(!N6tXgZo(TTAFBUmR~QlMA2ujK{y}!yFhglpB@+ea{^I zCbH|R#{b1=0S)$wZMH;qA^$9&h6a#Qnhr3>3=$jfu$dP3KIiL?cp4XLw)n zenvUEFd2!NA2$}tgFPLQjCsxmR&KYL1jB`4u2YcQGY>sA{J2OmqKB1Nay3^fT0-7& zDt7nVsG?IT<$+6=qFPzWet&97a@({_lo@L{#?h?}qA@Lv?6+Kjc@hb3`ZEgamafc1 zCeRfJhP5Ug&{IwoboL%mzR*4dCheb--jmKxhBc<)9JgJ|ymAwGKD8P@)nBs}7qkK=Zc`e1_<{uJ-tiR|7gxI_a4Izn#a@ z`ajXNpr%refY{?NpI}=L|KdyKgW3yR8c}d5$Z~{v^zmc2(?(-|a5cB6_*BwHK>JgY2*`JvTH>Lu(5(N_ zIq*hA{W9V_Fn@%d_EW+&hX^u6rs@hc+u0%#-}m@(HH`CTT)f-GJY2Fg+J9~pcpPpB zC>e%mIe#iZ?$JTcpKj4TfCk}?`k|7g*Ji^YxaG_H?;R0IA*J=%H~xvq30S+{Th>_X ziLxK@__@lbYd!Iomnb=;xg$i%HOAjFqba`?78F?jK)+dg$B|$gVsT!V$R|i}Aq@W~u@Sk*U9Xhr7t?g#E*uy^ zUKy2GR4q}>X}u}7JWBpg$b}ST$Sz4U<}I<+8%F=PCW_iXhZ~qt)jU=G^As&TN-cUB&Q->{-%lwAQjm&ThR>mvsweA^0xF%_ z%frByph@K!=X#@iOSp-$+n%Di%>Gp0iAlkllVez^?YQsB;Nf1dwDkXII?J#q%B|+niZdp>USRA@r6y{XFZh+t_ooOq$q4_4xY1GFi2$4Za6XW z{+?Amgc8Dm<#2JqBzhjxSp5f(Pb!iX3v>6Szn7{$gzH}6^rku|Fd`@7SSN9&gW*c^@n8SF2eAL|MYLDOnl0e+Z$T+r zKr6x#Ctm%B_+2NNbQIuX>bzLTJZ;_4dr+?^RAx$uz0^VmX=+z|r;tx@yuY9~g_@?N zryDsMW$oY41kwhk6?BhOwg#Nz;D6nmGlt$>J?n2>r{+p#_KB%Yu*qqV_*K-&pya{y z0+cnO4qBusfp28+G{96j(k#Mo#$;d1;919m4SbreQ}7}X6CfCs!k|f&ErsFEdo-Sg zy6NfZp8HE^JdNRAgkFDf(eH0$dhh3f$Qemx>?|ZQUaGbE@K~`FGmkUO z%od~&>mUIR<>Y3LNALaD`)*#s$_XAoco(YI3d8oKKu-^>=6mt7%1nFG@8Q)q%juX& z8A6JsS(v-Q5V?3bpi7{BQ?DumJ&*7Gn>JUv-~@YExqHap*y(s4%jM>rj3q>ofpit8 zf0KPMaKptlq)$PBvMFi;P(yMvEhPV166#-_E>j;dBf*;{OySow)=YH(C27-%3f^H= z+d5g^mT5Uh}_)1c5XijuQb@v6GAK1&jjBNBRLAb3{&)&Vc5JDsC_i<- z_sR$j1JmpzeTQ3CR@>L%0h@ZV8&RZ|aW=+gYPKxOfhB*oV zSSrv{KQ&Lzbtd1oyex3v&wK2rnu2`y(=xJ3>M+nTfqApb3R-k@wCXkWf6X`*~fMjS;1quMuxyz?kzxa2aeF!v*vo?+XNZLtr? z-P7&bb$Lf7F^T)R_&{%7M#GJ9?p`aw5$xv0IOmw|*o<4l=+2IrGtd-db$gbtt}P+( zMSp@NA~-D8??CQVzI0QF*rZ&J#{Dt)c2GJ1C4L8kbl!eu{e$&dO+@3m z3pXjhO=r6O4@p^EtFSP!;C>D%*C z{CUmkS)+1e;K~Os6cy+>dpEHXb)~sE`}DeAZ)BO`sHD!{TTe_KHz6$F9p?7?F}q(X zfiYCmIPU&<&6Ar2zb1Wy#Y)O*@L?(;8?^X>RvNf)G|b{m+COjw;lFxjHRhp`$YlJ0 z;Xoov;e&3ulqZZ)n6(;^060i0`BnV@N-QrQnv7f-r+J|mOBuH&?IeVTXUmmxs1FUk z)!_oe)p|uHPualvd)6g%{9^l3X?l5nd=f_IcNy;Y-NG?sLC-5#hu!pY{)5C^23x6xzaoPP$xnUI zj?p{~N@#^o=~7i|WV~FDTJ#s>(5nFNyw1TwLw2la`>TVG_W0^9b)2G~!tF!kppV2^ z8GGcn?a4POCRrd~w#8Y1Ya0t=mSx$NHnY(e$a2xtrd>Ir+J@!Ks!#b}{T zT|NH35PS*$x6x+p1#E1*YoRvY>quAZnc)zlBj*c_h6hYGC(}LKy|Ld$t%XmIOz_L$&Jv#PXJ^Cl)Z9JxtWxK4eY_j6qNR;*KzNq}t<(YcwS-Wy*}$ zFwKOyROm`DzIC}-P^l4`G6G@R*~v6iV?Y$Ustr z4O#0srh3JCzy8ZJq5I9@S$?90qaaukH&!YfREy0VbQ@>$ewx+rQkq7$7e6sRNGukq z;tg`o#C!;e0g#veoH(ozt7;f(V8eu?49=qouHCk5@9}`C$%sBr;%}4_XKevVX~kvqFyP5L>6iM||2Y3Za<6I$@u z=?uJA5)sc!Gn*U62boQNrC=6TeCKY!bmge^Lj=_u%b{?OMQD~axSHUM+<0f_>G2g7 zN+$Xs*zxMsF)+rzK6IrLEqZ@6;dtCPu=qDGQ~z#n!{9RHLtQe@fMQOky8?S^aeZNM zVIgWQx9aXJ?(ONuIJw(uZ;^twW>&7Dw{t+rluSS4e$!dImrVBV@%<$ehNLkxpI%lgN3 zkCj&uSkwwm!M^2X0Tvp^o8vct6q-Tb9N>FpXv(QqLV6Akh)fcL;_4U3JfATDQi#l1 zjb21BZa-0j?NW#vtWzAzeg=b|$_a;$R}+gJBMUPz1imCexgPTa0$iw*2x$FBXq@KHgB6Q2oNYXACbMnH#xuF_g?AKgsAsv?d&w7Js(+x4^f431YP+@cZam4 zB}C_>9xwRrgb6Rm3Tho6RC)R*f;*+tOtc%gB3|^hw;1HKjaa7-$V+$sqm2v^%USr? zEm)959mEDUPQc3x9?7i2nfgis^EXY#&{z-k?-oEAj`xg=Lp8QqjPvT3 zvsW=fo)@j6LdW#S#ykR)-iDXXg>_<~oFJ|$n=D>rMr_%i*aetbDB_=yr{wliQizC& zi%S1yo}TLI`8*^4=aBDIOPz!$kK*6KI9^akG%EKJbDyMu7vX44j)--Az$6KM54!|P zcm$8^?=ro+(4J5=RA%_!Qvw4eGiLXqFJm1hrnW(%cWt5uXY24$@)MVSFMnVAcQ-%& za`unbZUBlE2FF4M!IW|XSD>aZAx^ojF!1&cXukibjz@;HEazN@KUD8J^Vf*?7AQ$E zDL;+w9)oCi^4*!6&Q9!%EiH58Qr~@TnshGAkE{Ls%P72_9ZwZGG$3x~Bis?aN}o9b zNL*i^l7Gz`t^CAh_ZLVLf!j)pJ%)Mr0%$w`tpBCP_LZIEeEDd?V3?cilV`?~miX?c zKJP%L-Y>j@JgZ(WPn|L4+WZ}A8~+vUzJB^&i)ZZHIFXk=d+tV)!?oue5JT~v`@MNd z6}us{Xs^!At@^fQ#lqT}K?SwMx&I%sh^G}f(AZkQBHvrtc%`WCW0tQGOJGP!Rf$p# zJH8Q2ATh*84Nm$f!`nxc_^cJfRM~V!er7t8^66=u@`?KL(q#R9+|Ay>J}W&u&tT*{ zsHdQcn0O7xkyWR@v7iKF@^g77PWQx*p7#R+_7s^#oAiqB)6kdR1*6-hsu6(r7bmpO z+CqD0(=sx}n3#A8(us5X3KtPDR!WS@&=KFop zaOY8#!eRU-z^sd1TWiX(GgHd8@aVkBdWA=yo4lTM#f6> z%R^=}h-=JD^p#2#{@FYkR|>Fbh~Zh3Ik*GTm96qIYeR}4ahB*F-Os_att~Bc(%uo+ z??U@B5jbch=9NPdG!D1Hh&{=5?4|!O&|PSvoegJb$cZ(?se{pHVQggNOwhNM;ZARD znF97Wrcnu7GCz(}*PM`Yp_i64#%VGz7Bz9&hdV(hF8eBl!A2>QEC}lu%!KbkHQQ{t zrD7?}Z0yji)Y+wEhtl7NGV!G_?V{Qjs%ZYUo^hf_!flr{W|PUdxI*K&TzP%a$KgkQ znX`K(ZLsNhcZ8VhwRw~Uy5NfbGO+$h$o!?r%ZNBWxqlV)bxyPUQBW-ILe;{$1<3KQ>kFcqOyQbbK_wA3M|G}_xeNH^@j zWLu}#Dio93-UBrgQkIYgiT0*ue8bE4aa9PYc2^ocXy@2jTW0|#PR{=fZ(rU1=d;Kx z{SDD=`GV}q$KUu{SE$kHZt_T;V?6NOdc8UWOg+KtWy>&3*z@^)#l@RxI&^GC#jH(k zERo*PRW<`n77b}!DNC^?yfd#AMxG0CT+3nw3t#6^4Q-1^WAMW+HTS#rGBOJ4Y zox_?-sM*mm6AD5OOJvkse_)Uo8D8ckqkEvzcYbF3HEK&gDcBDoPrbx(f1BR6^<2@E(6Z?t?pQQEY9CFlYAsP_Kmywbdg04e z)m85ug}V9%E;opv1b{CJIo`O-IB(c zr}>4R2K^ScP6`hONXRWMkfnMnLOGe?4ZnZfWIiVtbxDgnZ_wy*)PoKlz$W40;TCZT zpbhEz6l|HHhiEGc8yaEmz2C+Y=UOTde^!XN zdtE}2NeQVT+;IkB9YKMYtJCO& z92h?UNJ*$G2eEI6D)$cArzg~5_Nv#6G3WYv94Ube?acJt^j{_QLZm#q-#q^g<`|XG z)%RAZ>2CXnws-qI9dtlLo)<3cUSs{_th^{=g>T^E=YK$FOK1zm?Z+zCRvmk6>grt* zGDrwHFsDV`!_D-31M6yfE7l2aTnU&-VHG-t7>!a`KOgv5F;gRgNkwo1|@C9=G zo=w)T8{D|ux44`Vd)zJF#uD;6FpvMyg4Zn-~9u8?91|pd)EUfbK z^1{UOxnEGRBdC;cmMqbJ-_5sJ?|7IxGjW8v`AndmN~oQ9CHa2ivL(aX{|=q>9+`j z#Y3}i+cG~0-CmecK9Uhintk3UCTkiT-1I17luYAWk&@_}s z)*_4yHW(OY(-TZF$M>&adb>oO)GZL%XNVgshY>C(_RfC2`$-tSC)MLo_x5L;{J6r* zs@l)C!tC>EVr$t&n6&$OFk$m~zxKhwL6ORb#3J71mX-7zO6Z}P{$@(1Z4VmYwK zBZ8x(6NAFzVbfQapk&5N@3i%P=dG!S1gK?1C}=Is^xT}R5R;QaDMg=|$FFiFEd14I zde~4qH{TeOzfa@_<;An~FAPhcY0l4l!P83k?oU^eFp;`g zLFieSK85THhv-NYENSF1bix5?W%Gn*@CM4?k1^=r(C9$FIA@W`Ll~glHXU?z_Cv5W zOIw>FO}6-D&I8C^97wIfC;Xd)syGD)S)uo6MzWP=T6X?o9JI*Fb!uTQis}oil9LzV z3Av9n`OY4`Y4jl9M_djBnG8n{`!La`o><^UZ0|gKy6M>M5q-R@t8@NZG7pRpdsEvl zsBYV?ZRg7lc6#IUfu!qF>y5U+`36^r_OgK23!MJrcw>ot^yTH57t-U6ojB9b^eA3+ z%C1^Ye?LufGfR&gzGP8~`_;l8uBYuMwu;%r+uNJLoammZOLGX_%t@)# zzbk-~9K%KvESII$doP^a%PAllIZkM9b=ujI)E^Sk861xbCF4`j(qX#1Q&n>McdW&( zL$-Br?#uE`eEUN;N)-K0fqPbY0_%QonDHlj2lKtV+2dhg{R;zn&j0YI#{awiwg3P6 zw>n`zn-Q9swaB9zY4Or*v!u5p^Ge@3*HZs*_Oq}$@wB47v~jQ>lyxmXA%EFMDcnUG z8Z)^*KfKxZ*|fO$Bj4RpHWvSco>&1*8E=6FhCkW|wQ1_YFL_~+i1W5O6IQXJ{qd<3 zX5V3Cye#G?ho{zir(PSwE=ZV;|0G0n5JJUJke$2|50TAafbp8}wKI6b;)vX$}z-Mu%_QLG`iOZ%=HAx)5O4ADVj0PjhrPPB6Zy03%U~6EF z;J_>hUeA}_P;;*5V@sFB4F{sSOoN)HosN>nGDgKv70962$d~{g70GvBeARbAmyJ!m z3FMAr$0i%XCS`6J2o~wrdJjIS{#8!Bf0}vYu=WC9=TZseB2ro>hwM}I1A*4owo)Z= z&&Z-1%KEyc>K^Cy;(&bkejzIM+NlQv>Av&PHwB#MU+HtkEOOb*;dGnbSnD{)(tbB) z=Wv$oHodw!6j|9ip8oQlr>@Ta-{_lL(YtTJ@11fO_Brzw8do#duk~LVrfE?rY@U_2 zF^s=hg?p|So*)w(I=BNhw{E7aU|pbzKH`Khrn+w)ZO|w{QF6Wn)5JQl;EA~h<5OGh z-~v+ZUrbUN5Sqg-Qb$?CnWXcruLOkq9yiU!nvJf2lzuTw@@wxZI9>Ff!>`+_vSWP6 z*bL-nLG>h`)i)GHaaNlFN15?&x85gyj<0@BIyMiHGo6pXhI(H;_;}~n=zdJ+Y ze>+10g*wQoK~3&>ZCsti881>=>dM)5W?5(Zo=~rg4KOp`LP%s!%<+vs0A|~wA~W~X zbg0L3I%OQg47yIs=-sY!)uelDVw}T#r~gOh5*b*(aqWsVbGIS>Au&mIL4I502d^8) z<3$I-<;Ye09zBt(8OrUpGapf;8_I(G+R#*eQQ7*|AN5OeHU><+0ty)nva_@&14yWyC4dyR^^!IHNBLWWU z5m;FVIhX*I8IPfqOI_oibKws*k6#4?nds&x_>e<`-zwBrKP6J8aDJdJVQ?U>lajr# zX!OV_SYk}Cbl%4SLheD%Ea~_EqUqV68ppRJNU}8hO_b%3H0?3XbbrV2rG)G=0OkMK z-}Pq-io0!oVq(g@XVH6GU?VpR3kD@oPi&)n>z)^~PS|8Y!5I5^=C|RsRDJYj?86D( z#aL1VJpnZI@c6*c^ngo63Xc@>l|^$rN`X0*)%*HrWAFBL?M#`i;Ay$?mEo-IED+Fi zw!`Wf@2=o;%?zK|j8%qW9?y^F2}1i>5Lth+iF;NR3ZeDSlYWeoK9dbJ_Qae8=z}cF`_B(H+ zEEe{8t0P+o5#NfRMg+IHNt>WN3RV$8R+cR+Yz+-vbC_=ME&v*uFp%#)j3$=`Nj^1M zLyty}=SVSUfG?VcrW~NWehT|TF(o6v9mE)53)Q|md36T*V9bMppU7q;tOXe z3gO3y#%Q$NXgNvt7SX2!|JPe3^*_n;{;);4RFIk(!YN-X>l+md1-mnri~BS?VLlGP>AHM-f^@VP{##lf2mAK@R>_lFkL#PI!1+ zFLK=4VkP)57W{4<7&x-P0)#c({rOXQA7q*0;0n9#sSA2#QtM-b_nFSf=EY%!Z>P;x z;thcKt~@$TXdF01AsyY7jvjx#*gZEHEv#zDo_#k4&QfXTgXZV?c>-%8u%|LLj2(uY zJ@KRT7eJ z`QfW88o!rnC79bQEY;bS=e+dwn7?`JVFl!J%BBBw!+-z4-!5G$8*bFM*A=OglVuD& zU8`$w+z|%`TuaH5*dS|zEf|FNZ$f_qY zOBYuyi;8mKX_(`gg@41BF;?W7B=_mKcoMDW%7xc{q${u$`spk$gAIs*^jG2H2`oW2 z>k4Bli#4z|4G0Md^Lys-%f#~DG+Xl9q`FsuF9xD{Z4FbZt7TZ~Ns1M-_PjP8+5K*@ zUOVH(2Zjcs-Saww!DvTt-m`xVhVZ&+3f`K0l|`Ttra1fKefNBZLwUD3A-VC;&)iOukQII0Rbq@CYl8Ow2>v3~}479p$$BB$e2*6`6Bo^PXuubE*eqHfWr zAs->21Z-^?GVJd!)k8@Xb34Kk5&!@&rx5qZwn{QYrH6S8s9r+X-IE*FpVfh{ajtI? z-4)iaecyH4J~6vW=jC=P$t}7-JI~+W$iSvelN?c4k;&`F3Q?6T592v~$->WqVq>b#z-jFg6#hoBC zgMW}A%~K~y&`fc`$q&A}FU!#g$}Js;7fkOH)>*Xvf=ENY)!OOlPsbx4JQj)h)|r?V zQQ8b!FFzU6kepFWx}~MX{Z{D-fwb{-%TDB$bK=vrOP!v?fPfyzImo1~bg{vTKQWP8 zK3aj=W^r=!lVov$n6{UY&xi)@9*-c4GD|WO0qNm^&S$e*mX^o)$>lkCrv9R00oMz3 zKN!+$%zz)vrok4{gCq)bI$rhp;Y6$IeQ}9pe_9V+Z2gsaveGy`R~>a8Z^#hxj(H;4 zV?ldkIQ>1;<0U!26>4KwSXrByFBOyDYT}_!O8KxE+GM)mf+uSeg{gFT<;3A&YY@iW zgQf$iLr#~n@}EKEJ8MZ{)Ds%+(SH!cIE3S>ysO{1`*5S@#;Ul#RBa_X(RwFnk?}K$ z@f?%dsK7 zp+&XF%DfE+)UkOu^O+j*A6STc$^T#>AyFz10csZ*)P2zw5DRsc5vK8(wV8qAV>-eK ztdI4|ruN?>BE$jIayB9Q(yRKZ?d4Yb(P-Y$; zgKXom3|{9tS1w*aLf7y^nrwU?bkUFVpp+w)W`Rl3n&WlW92@JiPi-19eqPbI*2nQY zU1@)&Ygb%Y5^c;Fvm+6K7suLL!1qP)E#xP+ehX3-?=Bh+uVvg)Z&Dbwm6ju@m3DPH z5x>xM%bwVywO-l~XZj0tcElRWN8X8{n{spSbt+*xv^_*7Yt~} z+EZkWEY~2QezCN?v%Y&zqlO@72tPy-eY^GJNcWByMVJMRo|U?a$T42RTt=ldWb7Ta zXgUi?XFE{~pGeTGu%ifa)Gy>%TzrMIvkBD-&-VkvO}? z_MAp6Ec11{(H-_O0pM1;6!_N%rF>8LiPKBY8*}gBVtrqQ(hfi09IuYrz4Y5v+xD^C z=>1K7@psZ`0d)=zA~aw7%+2%<;XBmCp?4e$+NzGTWg1z>- zN!aiqy)eWkv!R`Ap!whb-$!@<2i=K@!n>%611jT<-Czp>6_j$?2Aie+>25qT#azil zFlm%>^71D;%6kP&N`a9DiWgL*oANDj(c6*#3jHpsYgeCBgf#zj18s)Z zOCCM~P8keiaCt=ns<8q{7%e=8MxOVJro$Y~cY6>Hn+QQHSJ#QH1aehD(3^VBcPEGv zIG99at)1&@UWccU{=KQsNde;(45s^xC2Vt5dQ@t?C6{I}WZSkwh7hR`b93u{Po=X9 zksR*_l-9)K#dbuq5B0qWr15cV-%5ciI|CraaqA?{#Bg^SS-|Y=(BuJ=!{=%zC_76sSL3=PlB)3xIwlsE zu)TjwjNZB<^n>tow^f#aUyR#^7hxfowzBnwg;6Pcw_)Y7u6Sp+| z)K^ToevxXbGAWC}F9Aj$O>L{YPszQSeQy34mktUb6q4)@rj6~_V-4dUq{I1nf2 z?%s*&LkW$;rOmUnl86VW>9!KT4H})sKk|#nG80nMj{Tdn`eNnu(Q|+3%vvcLpg>xC zeu((B{QozR`~PjClrmrweLQToEPTK;o6&^wKnNFW9NvG3js`kX89XC42y$)Xn5C$N zbPT*(@_&9R&pusl+z|r!7S)mzfP-eb6LNipm1S&e8lynU_mPjUs~HX6*{$Jg`6z8r zzK)ETc>(*>>}t0Lg>PK0@5ZOr+cr@JZ7U=t(M#c2zoQi(9S8ReF<+e4JyV%w|2KQ^ zyE197Iy@p3vUi6)ZwIz20;Xzexw}yu{?(~xs0e25E8_389AE=8Ho(cObE+p zdm#Z5^ZW)ilWLW&ttQhWNkBd~o+n;;5#I5N1i*mi_ZcpN;pCFJ<{-gL!&8g1o!ctW z=Tj&E`=Mu>%>jMnaoNH;T;{!0-sJH0!bWd}RYlKX+Us5JYs3J>D?_!W7$NF`Ccw{@ zmaY0RLv0?@YZRC*BdJBDO{KQz%$&{}=@B?fBZf32=-7t1RkP_4nQ9jsaJZ($N55=7EJLg(BUhC-wr)%hY#GiSed1ZA>PNY)a10^lD`C0Qz2ZUB~%^$A~u2AXw&oS{o1@n|g^nZo47L@wi9udm8ZT)IRk< zo3k7~3e~4iK>dtkhOe^Md{WT}y8(QsO={nFT3qPBm(W~~A9AS=Q|!UgG-{iF+z-Xu z>>55Kv%r*BlW%{ba>|wPrX~HlX?-4Vtn$5v>=zX+HoFKxy8m4tl_ZYP)XQ@*zjNV=vhMG2i)K{U6gsXpxHtyr$dX!E+n5|&n2^YMkVJejH6!Gl4<-vt$P#i( z0rEuR3qrz&P#_tZCF-Te>urfhB7UN!>J{JTTIxr~#%gUY1qB8Fx}Wx?dK|Fo7yT_x zE>ejBQ5sI8^5Glg%}ydSjbrKbLSO~RTZ8zHW%@ILNhlVUlY$fD*$Xwd%Yjh}qvwx) zFvhFgPf@P#3L}y(5{%mY+t>A2l1WPH3y4q)(|%)P&O!#v@$Xoxhxuq}Ncphe?icgQ zO1M)+7-wB+LaRg;yW*(hZEfbg@WjZFiB0^kJ9Dwq>sf;mQM7TeC_a0XbOW!Z{KP~y z?fQ(A8}^3@eRK>Rn%w{iNm9ab+P0t6;jglT-W$)@QrVXFmLln7Q8_EXZOph>1&ntFdJL z7(-*GR3fBV=M1zE z64Z>ci-Dd6Ad~_*-w`Q^KGQ)w=&(_Mhm4ekr6u(AukGIXK#rlkd79r1nrIJfl8Nwz zi&yaKqP<6`I#uhWiKUkbk`pV?&qQQ&K|6=tk}_vL9dRJ7lld;1W&VRVGA zQROor+5XyNS7rP-SEgT`_9gHc9i3x;WaAMBt+w{}pg->qT7{!0STLcx)ho`QTH?x6 zkYbC+?-Rk^p3NfaeCNtby^V#AyVtf`{>B4W(hREntnkH6?o*x=(GHWc{np>4O5 z@}vjgZonA2=ygYh{H5GNjJf6S@TdlhwdP+vfWIm1abHMSaY#v&rQ6`V^ts&SX6FU_ zNC!EKeEM?RW%8!N&PVoG^PPtWX6 zODezvCWckxTLrWu!gi;giJ7)7>FI}&YF6B@Gzq=a)I|8dgDMwqB@zpMLwf=B0#7pVy)heB0UF8ln+A*ntga-Gt+&DeS?T zhJ<}@MMUL}{JD0jyY5dNi3?wu?%2U3&3KN8c!nwRnLQs?Kib5m0cGQ=1Bcwa&HjC= z>v{f}Uo<=K$RnjsKxRdAaBwh7y=OAhG~PA>F*BDjkm=R;m{bcLPptn3@aWPSG|B*e zaAL7i0#687MKNaUu$5igD7@RoK!3FM-Hqx*_1>S-u!jf0tlQqdByRV$7vX0V@-con zZ?~5vT5VQ`ebD&~Qi+CX-1dbet0oio)<-}!OT*C(PkHP)j#d_D{vT~&{1~~NqdN?|Kp!leKE}@hXIs37Y_rLxZ z|E+WrV>wKhkhmCN7rkZ+!b?k$KO+na=z|1A&e7fz7Qb7zkYm?sMK&V`GdN%0)*7A& zx}L0kDP8Xt3cmEO#tz8Gq~^7mF`fHoqT_TDjTiZ)E+#CWD1M=$|7-67j7nGclf0rH zjg=NAxnTcppNz^3gAE_f`rDj-aB_v?e<)LtpS-YUZ0GGEL6*7*ikfu(#6M}tYu-uQ z|J-<+B>>~&;S4u;w4bM9uNBSeK@Lpd3Yre?^ptiQ3`^YV%nAcRHG+UMKMvA!J~PmC z6!UkGPF_)AMweYxJ_4}XZp#1e9;-=ue#ELWe1_OI-}3>d{Jr}-2x)CZLoY9uL`p>wdBvV%2`ee$z?vGBPKjKHZ_(_?{&T1 zOC5(dPXg31fhrus3o}MU!=cupt$+k3_MqrQEFR|*6GcL-%JQU$(IA?)u>%m9f5Lil zD&0lBD6!6|M+tdzH9Xk`%holPYb2hbAs`>qtOo8nYf@@_W4ToOg})Se!mSC#xoble z8o8#{pzSs+;n9@n6??dr;Wg*$ltX5>sg;>PnGb-uDWS?}$uXmzAu*MmrqIySG2yRm zTQ+N>Ep)Q0M{}kh`bL79eoQ^P5$kkoa0`BsXAG%3E!O8Mb+O@D(D!vle`~TmmH6~# z)di|srqz~W1>nMHy>7V#gnBMaMw(6^tUONdQ$avV&q{EJ`3Q%K|gOX<3*;;Qu$A{!<~6N zwMDU$lUzD|TVKBB zOH5_3DEyEmW5KI!4mYe#)HTE{wd4nTbIF~G-L0yI6Ju})qv<@2!Vp(3;BCTo#~f4N z`f-55e*gxxDtjPSevv{wllPUzTq1C3E*T1CU@W=FLc_&J396=&sLB@j{8tMKt5#ig zg8C3~n9o_UL3qTP)l6+o37{Y1XJ`Moj4R1keJ`UtDy3VmHJ`#IDMy6VljH}AAFn^Y zE5XRyGHM2N-dUtCtI^2H<;Z zqZ__EnciDYxjklRcr-G&sWOvHh=nRt-$)Y!?4?m0@_xi6oT?CxnR1(%BMdiTbKNTK zRYt-D%zN^_;c*esbmQQ_9ZMmS0(pQm-%lb3H^e z7p#$koDjR+>!N1p*%iN9@h$pYaW(=-g^`7Fv$HMn zMYb>QaR4YN_$ER+sG%z7g{$M{sH3apTKkT}?}ixj%qx(3ZNJE>@>g-AgsI_o^Pp%_ ze*4311OVW)gQO%fHoD5wEl`!9qO$#;I8J_DCwSdG_KLO_Nj=Xk{6EQp9BnTInS9op z`$ulDJ&xy31Y`ZI6-9@5URdN?Gr7;`UlwR0HvN&#_Nt{e#-;%Jq|bLk_%)!YU&B%@ z;RpGg62&L2das-aKOd70)`96hOGj(q=6ckNRhx)w7T{sMJsCp$hxg-G|YY4P;`$`b)veX_M*vBW@F=|fCO z9~M@t0Oh;cQG?YKWb22tl>3=QLk2a+PrO7z4*SzpkC<%1AvKp6_52WV1TxCmXGNGYUv*=cirdp;`UPh6c3L8xzyieW(z4ZJ)f z{^_o=J@8|K1Xa=-#tT#}6n1-TIEfFKZ!K`Zi{?XDPXLTHdnaba)_A-73&{y;n~yGD zLRxb=Vid|vg=~F)bFG<{KugekH&1z4cr1;2xt84Y3}I(fGJz_$)9AQH7mDP&5QllE z<3ZqV>=#5D=j2(O82%=w)$%YG7{bp*t1Zlroql7)%`6O%BO;*!I(4c~; z>S<(ALB-~c7+|JfOuuwav67qCRoPvqY)J}|h=k2?-o5b>$bSpon-ndt3cC4YkOxmGDD5>|EC5@723UM)iK@HBOSn5?p%ayi@2 zFY+rMeAep{&7~6hO5wo6F*s6HVcq@43RRU^~~qY@V6gP2|ic`GEbFUpd4{1 z8=+QOt7d9;KuOdI@vkKo4A-porg!4z2L8n=>A72*c{{5<3xLYIKIPNj+v%Hkc4ADy z2|r!X*FOrkgt>J*nhAJbA^5#E<`z{RFI8W&S3Y;EHuKaf=q{#O6@J-ut02f;b` z4P3DHmk6U~G(^Q`KLr^ z(lh0KmQDcU06v5vY?ZA-I(E8VL28@&IAp+PSFZm4yLk^T99hULVnFlY(B?X8D;^U) zn7uc2VQK|ENSqlw5|5SV0#z7v14X{)Lg%Fb7}4M&sS<-=H0@Y}u>?Ldf6dU*p<^)e zpJ*0#E5oR*Kdcp|hkv5UM0mT7Dn*pa9aAt^AKkCELJtp*5V6pb5eYIdS{@$`m~Z2V zBfIj{v3fa{DP|XsZ~VTf9E(?zHfhjFvGr*)&e? z_aK&e59O^-TK^*SfZCAAFCT4J=Hm)kk*PWpy~hAg(( zad6MEq&pxV9UL9vJJnwHiA!N^)EV6m_e4rcDakSa-+L|Q{}(-8mHUJQd^v*LzJJ{g zq-AKd47R5cA_*{5|FO^__B!+~ZkzNDJKlBrwx){pw#@Zd>o(?)+Id8&xG4>4AuE+; z)0p)CipRk%oRWoI$W1tWe`2ehW9jyqc9qOu?{9ia(Pc@BzyZIDOP>V&ocm*3-X$QO zr+rz0L}_TfC+K^-@uEGhFb+GFqS#*T#Y-(>4Z?s+s@%?@M}m2fz!WH5Lz-xznM;!VC*$9 zfF9d@Agw4`|Ko7Fjc96GECBQ@uSqL@`8o6Yy)<*!A0EpnQ z%L_1o;-K0g%7)x(Vc)T#W(&2!<%xJVcgo<L zG8?yqOz(q>RkOWeL~}Yx^glQ#BZJ3o^+3Es_%jk_0G2#1HJhv@s*2-zw}3Jth2Q^U z=`6#dY}>AlbazXKG)NCfNe&^+(B0i#0z-F8ON)TCNOyOG119GuWSsVuO|)OKwFZocsI(qs?=m~9TJt=;Vu!G8bzaDTb z3Yn47mP)oJJzrqslI7GacXPdL*SL&Pdh>!>p@DLVs?M6{qqMpGrf=McPGGAkOJiVgg?dDoRS^D7V)a8wu;o!KUf6xR`9yatSY>k8xt>c_(AR>m z4(8c;|IXaUMtXc|G9CL=+~@drQ{@H~IXQWz`futxYy1Bip47rgxLGwh@vM|4JM*1n zdM4_mUc0nj`^dV4;_`$#(+OcZO4?G1Z}7*0P8NlFd);-#J|+V?ILAv>mJ9zX)r6Cp z=qd4r00fLhMUQYKcY<@!u`L}}R(2Mh0)E-Sf$IroyKlK88oN3?G^wqLC5xMx;q6a{ zE$^TMW7mQ7B^v1Nhbgfk*mK*6o~P2HncF2iYB)&`nwcR;f?i}%H}0I27T1-^<_^68 zjpyJJ!j$D~B1u^lL)XqvdT=30lPiq}ibzX2xhmxfjFx6iyIu=;ZhE?`d2;{hwA#x%^@18p7K!oi*s<&=uvtSbBO&5x%+%^$=o>Y9=+H_q zvpX~R*KKy?!*rzhqI8oe#x^gJP&Eger_UBmNK7Iw_#zXtNtbnL_LIs(6 zzG6tuK@3}s#l@_pCYvV|lGZjxtIfc$p%1+>_|iTcEAAKZua_Or8Jd{2CwRn2Rw0Ce zg#$9oKFK<(bbZOLOv9lN4!HW)WbciGd0mjH-b#HJ`F}@fN81_>=!XiFM))Q&&em=g zi(M%O^jP51X6IQs0H)N$tfe9gAwdynEyii3HW?C_5EhAzN5m+&=0RYtxH!GA0MwAu z*;XaCsDAqP++`E<*O*Mo@$Q%X@<&bYt~4^i$DSoFsHKrcoA-{Ek^g{T(wbKOL) zfr}!c`k?CtRxYp6^K{K#CN{OU#%`TR-DgFXoMr<{2DcOW(6UIgI|h- z5z}^$s_u~|SkRKt;n5h@mfnw*xMT$v5J!ff=JMwX`y*?PpEPfbu3a-=EZF{ZSRNiP zwIy#N1vQ`;aP>oZ{N-U96F!Q$9*CDH=E1}U ziR1pDy?5R3%lS#=y_kPKki(pKdWpXg;7+p8!ct|AOQI+QH)&o?ADx=ik&Ff}&&`6% z#QhHAF99W!#o!zCPjQ;uy4m4N!YJs%(%)DzOnq<_ijdA~KQz*59tp>0!k;nxYOfWd zCgyb4;q2;pgUO<*7v`dK=4K~AyUZ>ECL$k4H6Y^Zi4E{khqo9`(+0WN^$BD~Y! zEz>ks8vJn2X$JwFCO543Q3~CRIva<$LYUfQfw-IjGjf}1&@@MeBHwp+W+1(lyezLw z$NbOHso7OFu)O!r@ayOq$chEJ8P}!2JGZ0147?ht((;(7>L^HzE+@oti4-3z-~o2T zV^)rR!`Vp~-&?H|V7}Pr(Qf<9`tRSPZoLJIVkW2QlD>1j?G>`vc|OkN2~z+8W(HQPeFK5r*NvU93a0Brjpg#q2zpN)lxn+?vc|?|{(vJmQg0|sF zIO7}K9^6|0$vr%)1ZFf?-_dHtXi&9(9PAk+v`c3k^lwiB6BUUMS~0_tlg;K5*nFQv z#mBsZ?vbZD?%7|T%+D;>v-#r^5@uI7$Li=GhxIt(+)+gq^=bGP(JHQP`DCm_(vL&} zOL^oAySukcmZ!g=((+GQ&=6V=G2Qox-FaP0~*ykY)nig4*^tw2m8?BK#Mr1eJ^`+Vx6O3pPwa3jRkP?`q?bVsE$UVn<#rHO2ulQNSWz!K88_V@&7HLvN+0D-{ zRF7jXWOZX`K)!D?U>`%NKzyK{(fs=Qde%X+4q)c7a7AsSa`fF8=(^OB1rS zdsx`!fMtAWlV($O6O*Vo2uCsaLay-Mea1z_5%|WAi52RNjM~395spAj@MPB$Q&Z9l zli#MB46lcSGk=3g*Pa$q;sj4R`zXPEy*xc_fd=)*=?!6?OL2?V zV$*j0b8l+5z}n!>`*gmyoA?vC?FpU2=evA%`#K*7M#W4n>#@a3-;)VZOw8+gw>_TL*0HDaho!@}r2C2h z=HMXVv{-Xk)u^aS>hOJuxmIWCedOKDekuG0vj2+blEIKawLdl2iAcYO_&O`a0IL@mcQqgw1iwt&e|G@(r3lvN0WcU4n8CGXZ%%pjYLS9$MxOX1Et$6WdV ztl}sBj?1(+>ztkQH0#Porcu#eoqH2Ijf|k4d_XOkGx(BaYI0}>sWKWkefHN8S?&Wq z^!}-rzbL+cLYRKN{L?3;FaUfH510cC7UHhKV2kdTQ5d*IKYuo|IIZKXve^=a@S;(jk&8__M6)NN1 z;mL-^C$vFcPox+N=mU~?XCk^8t^!(fP-S{~z<3C) z+A39{L6TM>NqCS%@Y#`~H(JYZLldX3h3sj+2?k2&n>_ zS;a3G*OgOPvsToR3uQjwYdSlmA>FR(mXL(9G)^FUN5mcsjtaSn!A8f9^8 z){Udp%t&rSOV>7sq;Nz=JG?ihth+8h<@+7ArO`=c^MA?7+Iu?eGXVLg%?%~EK301- zxB=n8C*sohOg`*`0%|@n(fh^JkElTL$W?3EXQcqBZRSXpn}fyY=G+Zh0#U-v&{D}K zbMv+ojUNU4H+;fJdkH}yi>^kju=mJNi~-!9E5`R0sJ6A7NanRa3isLOL?f|J+I;5* zC)ytW{bLgTZ`<=cr}e+9M-`3Mph74A+d}=@!67aV4OVq^bP9lKWbuhpS=sG!H^}Sn zF994g6rc6cCi{mT-kS5-w`~_z3HkNqGY;ImLh_bJeAbg^uZqbl}=^w?czotI9?|I4i7omS{jOLT1nZE5U#`q+xM3yy%j`_>=Vs#%ej(;*OW*_9F9m*KuLP-pzA*G<2HacbvQW=0_RpQ#>N(=m(?UUT z1c98l`&^TL%j3@+mLVBz>h;Kr!oP(ZRjx7r3#W>=leK;Z|Mt-L)8y)_4>%VNTG6WwVAGy$I z|95~0H2-&iOjsD_l9PMpG1iGHj-@DHZ7O2J;WDA&b5`x*e&=X^eUj3U(d%2#F?<%xGpF)5!GGs8-IJ{88V zz!H+F8fE6xdZ($U8aDm@pqdk1d*q^eLNZBX5I;|yp=Rtd8x1r!c|Mnyxd5F3- zC(ACZ>+#80BT54q#jkEK2|baBn2nK``rDeCn3lmLBQza{8{b+qN7d)PH0GyCaOC`6CTZC&^0I^w{%R~M?#odc5n9rB$c3_`#rX-z|gp<{xt@ z9X>uIz(j#{?|-zFZ&B?wIiF0~BQBFvmyV8NZ#p|ytu@66&qOW6RgRGQit0;h-DjVy z8(BvN4k3h(9BE-AQ$X;IT1Sn9kXyQ2fvK+VsD_()GaJMtBR;p2;Fln?U17$IRlCIe z_`!)=2E? zo*8`q=&^#7@AKC*p&-Az#4(MK`Rsfnf`eM1MiK&hxHXAmR1g8oLP%%6Q~uG4flmjo zw{l9#1zVjToGcfz)30x@&+pqd`|j__0LmVBMPa3CkzTdi_FtqQ9s9`bkX-Q~_Rr#; zP?CJd)n<2-*EdE14=4cJDVb0qS2!p|`Xd98fFi)(U}s=xSywf`1O+`4EWg-~Dyq>T!`QVa{~jyQTg2~+fYKe;_4t(MzIe5Eim#x$2}PFspD z(f33r9)s|ATIenIxPp1TfLsElHGtFv01)X7Oe*i^jm@5aYZ?4B1jR9n}KkC|eU1Ze+WW_QiCV^#Wm3ys1;A*cpr?*NyeGtPL zKC*o*L9$6qU??q#>NabL8~05kbXfb9(4vrT)sfX8qKTS{5t%}Fe~(AwFpOf744*r; zVJZs7tedqdWs#=Eb;zY1ZGI;SeWNJU+mq>HeiFEx!VEZdT-EAsa;j(?c$)oWp5V{`L~jF&2=uK68vK{@2a%$OH&Kh<5O$OG)bTS=*|oY| zWw06lJvzBpe&My+5(Z&5-Nw`EG zF>yMM1vc&)s9|H90SO2Bs{?&Fn~`xbxxzlERWij=3*R(#V6MJieSpE5K7CLq7N2I< z^4fh%)&gRJ1hS|N(NXNA`DmXPhC%c|{w8+k92N#>K|>fTA;6H9J0g;95zuJX5tQq+ zJ47W0?4o6G8IR9jBMoxJ@%p-E^IBW~I{7&Say5(L3Vb-TfpF60$`tkz58uOGU}(S< z3es??YN4|*DzFrR&?P_)P8jOUEK!=hPXXaolmZBuJ)hMT(lmXje-cjWrJ>)ng{od* z^wcw2(o_Sc6i>V%?r_NvueSK}2iOHAzE|xNh$up+Aoy7McT!d+o%14)yc{x2&sZ43 zmav_xLgzA>L>_X7&t>ToP)kd_Es|9SP#l3tf{RO%BsbctGAnufyJQF^X2N^dL(CJe z*gZB#eei40_jK0MUvZj8c_GXR^!p@Mq<^Vp!5=Hvdwr+22V&)8xS3R_KHB%ZNTC4X zFKgaQq7mJ;1=nP%7xz2Pe7SH$FT^;m688NuC!XR8UGvA_Pts;`!BWa zvN`zfQ|Iji*LyA7_e(Yx+xCz5k6eLdtAOi|ntV-qd66XxG5Z6$X&9gx)!FLnI*)Z| zJMt5I%%i?MISZoH7aarY#NMCPt24=Ege3C%j>P-rIxS}W$4ky;Kw2Vj_puiy%^$m4 z*ro!iBW`Z~J|M!Qr;R!&SIeBOPV!>B(%+_uWLh2n&;-UaN$)AmKreYBVYJRhBnd8w z!u3^UQ=}BeFH~55I~u(Ui=_U_)7AZbfla5&kFq)(2^l3~T3sV5X3cNa@#yJ+pqQ)k zWtQmelA~`^Wu^a*|BV`i|2JyTprM5-rdZgGEN?GaTOTw}PI1MRWzAGu5!i>87A2*D zgo0AE*ak_dNI(8D31jvoTCTOis_D2#U#xr*&=0?5sKKL?jUhF#Q3>6;@!qKOydn?U zGkzkcr)SftvqLg8T&EEBL&dtjy=zdl1qPe=eF%X*XBDNNFtNEX*vI+r0npjNRPdJT z#vLzpNo9E^_0txMQQ(E`WS+QOsp%IHL1hM_K@>Js5V74k_OViJF&Ow+VvvzQrQqL9 z(deA@5;L)rz(r1=uv;@K$bxPAdJMrOX%@OU1WXBafvaA~k(qAS!`#G)*t4svV~ZTC zx=mI{?(V7MN`@9zos<0@@lEzW0c0aL;1@*c{~7Lr9RQt2FGUTxSd%SnEK^mc$*?K> z7{2(PEV4b;6F>FimsGfd%kN25Xe=KkxR%u5 z1cVQ4_;bLeI!#{u6F*B=98hvH`E*S2TH`TaAJ)ianMZo*uk?(VWJn>Fq_-{!U^&8A zBnRT|D77lEMl9ehN|5)EOu>npt$-VoGEoN>0eor{+^sfH2F{2crH_>>49YRrH@E6F z6I%v@8P%&0@X3Shtq zEAMOaS&ljgDmA3i@LpVz0*zh3!K1z3ip7~4G+y1jCOsuVjdJ_9tdjYD!uS#EM;nZ@ z^LbbK<*1>cnC1YXWy3lE2-ceF2}F6&ew}k}uzSG8S@)){>G&C2aVQjY+o9sJwC;^3 zXW0qlOqs1ykW5k>oEI97D^Z}#$sVDyAnJvV5h_HB=;N^_@UnNTuLoS4Q(L+?@E1If zHv3$qTmPA(N-ZO;)cF~}(qU-Xsvx6RjXb9P!>kZudiO*0?`H64$m-WLBwn-PASgFW@NKiP#pxP1emZSCB1>4hn$31VEU6bCY~|M)_(0|xrx!#r z*IO1Oh2OISs8#`lP(Scs{pqlxP=b#vN9_JI&jMX+5A>lv`H8n$)2eV1aD2mvf=#*B z7_`1G*xK55AU!$s_dm^?YvunmbJ3hQwC3iDM)`T!ZEkk|dW&QmexwtU9!#qP`yi=O zbxRKm?v8a}2`aDBQW;zFb>-$(tYqGX4CVkTVdKCv`s@apn{-~ns?^51ir#$6jEm#k zt6p!@1>{#U#l_cYt-3s|QL!2g0eh?BCF+j#77l1qQh_BErJd8=r7Q=7DsDIF`VY%P z!O>mM`-xw2v!rA!v8lyI|IULl2UYe?x_^>)57DJQx-Vqa2 zS5AiyW(A1gd{ySGU0synb_6cfWNdCP>#%Atm^>a?E`j?p{&Zlvcv9-p0Yy^(d+FDuCTPrx(r=6O0 zyG(g)7fag8l}ZJ0jHYcgqhry8Q~30-BIJk*OBo!SlhkV+4%J5oqME%rU@!26BNQJ z7PUK&|e^z!&|4U%oz2NI@u;t44PiuigCjn<8)JbW`Sryh#GX>9NH!acK zT{ATF@fvvVoNahPRZBW}U&FG7YjsM-b-Jt=sbBYkKd$kQQwQF;Ey$nZeXbIMmn zF;g`(fcov^`u5foE{mc4a=S9%_`_zonmwXe+%;WM$6@5YLj5qj`aW-})84tLeL9Uk|z#m5^FNrK6 z$IS+*E@@^meeLY%$tScexs_(FYWhWpEB5{!qR78{a|8e9Picyl8Jv`T!f&e#Ct+3Q zR!$j>x_}ZO1}rCZUfX@Y;;ut*q^FVNde(7w`TNJx! z3;0IzW9cm*?8-j=(Gs1UY&oBO1$_E-ss)3;1d8e3;+cIe&-cq;_rLvWE>rotyDjNN z)fFmb!lPJq`PQ6e+BGgA=F9lL7g6HK72CT{J-UsvKIXN9G#yxB8K}gxY;FQES74&3 zeSk%PqFFl(>Ybv&CEdX@Qa$CE`?l04EAeYu$&v$@iW4bj@bU`E{T`h*3cd2-qTQlR z_C5T3_cbc1m!L2@jUk#IKOKs0NO1pNZ$Mh@O(~(QkNTYKKsLl`xC%{~j}g905>y2r zR=o0^_XDrIw|24&{n#|?@@|~V{C6$C$A8hq(3TOFGAm91XGQ)GIRfN)i5U)(W#Zn5 zjEjfhW!cWHFNAR?%$IC&0AC#aESfX5FjO1wgZHV`^I*J)&*pP`=Ob>sEP>p;E|>FX zAm3u8<&OEd*)Rl;G3ZsLb3BJDDAH}#WF*D(wB^8P8(dt(1H^S=(IdqA+&(n>oTLl- z?5{9AY(0ug5Z;{|2c30Y?%Pj=Ruq}bmobdmK{X#_x!S2F{Y5gqBpuLVygFU&PXzoW z3C=obPd<`8#4;k{0 zO~Yl(=Ch|QwH`Qn0}M7?GZHw;4Nl9-D|326j1)?Fn5N>~PuGMZfH)UvH1v@o8Twoy zZ@t_+P_=S?XRX8b_WXYQTY>i31+Dy7*Wg93c{RCL^Z!}v%9SKhjhXv-0YCQhBtSdc z)DijJr8>JZn9r%L)8K%a`*l4dSIj%ta!k9hi6J3|xk9JihFg(1-eq_B4f#7~_7rSu zbzDvg7o@m^TemyWyLuZBG_^EUR$@SGQUL%u(}2;4hNI@;*$M2=OdsDYt32J|$?@KD zbgB;<-o~th)isA+FP8S^aQ-^V`xA0FWrT0teYNmsJdN|rEPb?N{xRW*TofD8s$Fc9 z_>uU9mqaM|iKC7RlF+~KqdQPJ8Tfz*_jk~yCRy9~37lj25aJkF$B^ieD}&&^YM)G1 zdu^R><8^iq3lw4oJAjNHzycF6pV(^J^;{CO6-m=~&`j{egu@F*<0{}+z=!{e6GU5F zR<&i5eE-&dMwm86(V}9&C(;G*$-5Te3FzeKVj@J`@KC^6errpA*q2kN?G2fz*67_S zEnZi?n4DeLddEw~nh>oyzP1K$n^A8!fDRDPz=pNnzOdd+ckHNhIzBDhX*!+l6v;S} zP_GaE*8ccEkxNr=lw*{X_P79=Wv*_kNr{ylBP2{bCz)Pdyn1 z!;2Y!@;UA>&f9;Ah=_>ZhOgGkgZ!3d`NZLmQhTLAj;p$9Lndpuhr0Xb!wGz(MH>@)Ej%Ffqa zK^vul(n`3czrQk!AJSE7ZC8O*(jBpqgomT%d?0-RSQ*X0*)Or1t!7kX#>Jh-mly2K zmZo};5JfMd(oaL6OOObd;PQ1Z?%&+f%IUC0^qnIE--UN#*H_fmXCr99gjr0=@`+iU zoDaXG+v1%AGaVq+ZOLMt62GI1_sh{X@}cBle0~o6B@&iKXy%Y%S|wwTrZ8JIVfvka z)+;BH%I~v#xpG78`$&BF3WQZT8=}7^5AMlfr&1sDP^ID#V&ns4 z8Obx;_>{bSB1&~_Iir&4z-$=EJCCh0>WJZU{I9J2ZJVR0kqV3_Amigp^W(dvr2v|= zve{wfQoT;6>gAWX{fDD(#jmdazt3T&g(fySVFURKdUa+C`an7Cd)B&8`6wqVyLF7aqegR+SDNR>sj5lKg4!{vOe}~^vLQ3`^T+KAPR%c}YD!j^9Po`QQAwL% zkABM(pC|*U5eD0qv00 z=z-XyjFHca9AMQs+aIM|n&oYTQg@yss|1}r5>}z*2-4R14jcFpKsdxOed(rj!4&I; zjJZwhh8_9F_kXx}jBPKCgI`~}1+7)-FgJ*6C3pQ<<*g`;Bp4_rAYpUmDqk_sqrW;e zs1E(@E{r0GZ>B2bcP)wblq^);{d=#w|DAv1H3X;jb(!0)Nq9Kvt%kyW6M_&W7+L4f zUcnnY9y7x|x@rgpWuMC{uJ@+5xS}kH1}mX$nIpQZbccG6@X*E15a1O?LO`Ggx`-k* z`&oy^tn6HX=+M!4EbC)_13-DT=Z|h=0IO2~i+svp;$y?lVxT6YF8*IlHh?b)Vu3md z*i$$C6xwyvnAHA0uFadqu3lL_J~`D8@W2y*?V+K-4SL^QUnkRky^Ud`K*K&6Qk!63 zV>D!<=H3_YJvS#PU8l+bQQH_S5%M{w5f8Yu6{ymWoce0XJL@%izV&`X7n@on?h1dW zA<39HrcoEe!wnCak`~Pund>sCeiUH@Z;;P*LnDr$%GF{JNd1H*BgVA$7tvu2Zj~ZY z+I^NP)jnTN4ZADSF{@>ER$WYDKucED!5rkP8#Kw?n;k$S{;nlWag{X{oY(9ns**8b zYA8F`IHDw*(mxDN6_P3;C}J+tWR3W(ULn7Y|IXb)Y(O`W@N3%O&a`}76w#zGBEBsx zT}?~6Z(sV@xtP?q_ZG~1eaE5FHfW0x2Cq79B_Ttzo>@ z?IfNvP9or+*f!&-Nvjx(FNBkCMD)n8eR{{IZWFUdhaIU*h?P1cK+I-QJJhra$T|O@ zCLcfu(aS|9BYsqY!{4{py-~2{Nld|007G4T@W6*#6%dkN?*;q1hu`o0_+ipTk9fLj z8(Y}(k;l9RnU7+ls~?iCd@>@>+tYFgXj>N{=w4` zL1sZLRZrGy`{>;=zRxC5@A2RUOhY6pqnM+a2^9#@Wq^WfEQ7;*<`2G}t}LPbWUeS6 zni?kI2r+^7#83Qk`FPf_PDA#@gO^PdpVDMT&10ZFadA<4H^)bhJwgaiW z)%pFMBVF>_L%8r9FA+2aO#3A}kKUf2Ot(G?Y)?nD6JAu=mYMg#*t&305N5aBj zIN$_Lq`m4_lPsc_d`Oe3L?yFTvIBElOh%kYPwoRB;2&x8PZ4AAmIfnZJx(rSy*o+5 zjehbRQj`4=2;89A@%xsT!{e$tGD#Fh~%H-!fAIKY!v&mo5f=DmEHr{MMMj z#`r?rO4GPfQYH#q0kORQVFV-td2R1^Oh_Nj|{4%(7~m zPz|QO+Xx~V%c!yNm@%tw{FK(<4NV)y71|z7?i>GP^tEz2+&kjxK>2(zUvzw8q3_BP zDcmd*H|5Xrg?Wy8>P?k#^XbGSF5n}0z5kz~t=!0{S??sL0piFuS?Sj?vb&2(F3%oD z66ofZB3s!z{D)@aLs|-93Z1q?S4>#s9dDaz&kjo(tmpC6Y;I8>SNNT>8M<2NbTN`hZsCO_aT0Byw8bz%=P3(&nAAflglccMW z`nddjC%;F(F9lf`pLB?!1YgEswOe0xm~rLs>VV7!C@8_zHe%whIA*%!$M@m1p3)hm z5}@<4mh`dGEe9I}cLf?Pn_+yq&u^{E_I19o*V^5%Dh%LfeL{GYRsbN4Qenk^m?g*} zBjm`)jFgHuO#W>PDGWq;+BX+@NLMbD899gIeqopL8*%6A=oRdI7H#)*FsS>oc|WlU zTadDTI4gMlAPp%sp&VW#-;)^*L#0M1fevDT#9cG!hg51kSFJ{6db(b;Ut`WhAIW!8 zNh&5(iffr!riHN=g$^%R&mkpAHVlj5)_ou3_9=nlo&R+V`18NNE@gwx=h*^oxx@z& zDl^<3tDCR>Na4&HvbvdUzA+=(SrxFZ99CV*LE(XV)4mq-Xr{Rb8jxN$CJpCi&Ka`L zYOre5Xn$M!?qko)h}7Dq*qGyaOD)v@o&T*bpgZ+_ju*7Gx=Bh_f1^`@>$AgEZ0iD8 zIA}Nr8}%INs+lulCizPM9ks9U7mzT#iF1x!y$_4p| z)ChnXKif9%^ptAGuBn)yT-k|V_jl6|UMS#@78mwJ{%?qNs6B7TcQy*xaMC0==2;EC zc5pBDjc3M1SkzETsuD-_M*qOgaET)%Y z2&bcKegYkQTY9TW%-a5Pblhl1)L5%Dq2#uE{)W8T>rYoW98M#E8PvgZklxrD#@z@H zi;f9nRK$R4hKxHhKc3Qx0KPw;{U-lCJbx%Fv^qT^a5@2d%6BI3OMZO1tv`U|+aR+&Tt4Wd_GH84Gt? zcb*G*2!F~<0iEHp_FCC~`v?hTPPhnt>LBS)HZ!$LdD##YaXv_W)6baukJv5|R}V{R?BbGoDsF(_#Y&x8WD;@)SD4 zuM^BFqUJ;O8kENx4;AP(g8aqV1ReKZ{7?681ikD1_UwwjNmQyKC=ElSl8mEE-Yw=A z#c;o)cWegvzYr#hoFj$>A^<-^b@^N@4wqj4Tu+ai>+@ZWsjJyaF89M;p~?6ue5Q3! z>Z^koJX$qGA=tUVhF^asnt-XfY1Zp5!t;1DYUkI@&P(lo4(OMf|F8cKlCf>`tdY0> z(9S#RKQa(amK!BypAuKMQ6$}8SS(keNutvdz@nD>HQWLy=VFO(E=Jj$)w5Jqet8j{ z@R`4!hB5r+1qmzQ54k+R(IJ*A8=D-AwI%(W%xc)75b{kKC#`DoDV3aHE_{|p%~_3R z=QQDVk;G*QAAjTU>wWF+9HO${Xel)KqOxo7yH=&|adn4}alcJG33e&t;A8N8ehG$F z@e8$scJG1l+h}~WQU59z>7#nALFBKkkOwflf*c5~V#KZ6hqN8t70+1<8xPYUfg$Go zMv7lzn}O#Mg%PMR3J5!>8uAOn#al#jYH3Q4#7D7@CjoOId@_`^so_>K0)Rvf9qciO;=Uyr9Mu@u!9<*X{0Ob~5(!)q;BtWMsb$v@^ECs2%v^v~jKP z7L!|-UBJmOFOE&>)u>#$#Ee0Ii)edp1neUeDSy3Blb2vol}uqkTi@fXXCKf>OoP^T zDBv2++BLc=Z?z8`RGX{YD9B4w3^Y1McWAG8Y&ZnTYL?}c$huHnx7 zUnB3gH@n8~3ZCd>w7PP?beqBN&Y~BA@oeMkun!Ds`E8>W2rDL*n}WrM67sfZOBF*N zC12Wsi{a~4bwUbuMPMzGoytDeU=vFkpMK5qB#QX;M+&@GSXV$ww7Ij(Yu=LkLb|pZ zt0y;)aNL-E3Q2r|+wLE{?@h=GW8Jwkh1CjRk|1M;t=|?|efn~RxT!7YPhNLk1c%U- zaG|3nWObj>JtJ~kg{H+pvXGnXar;)YiLsi_k?f}9mglk$_lw>^5+ACQTj1I~9*!B? zCFRh3&`@K9d#o~G8*hS6rNrf&jm1GEw)(A%Y|6K%EUeT>Yic*83l!`Phx3_LfhIgv=iy;3~htqIvW-e78XntM; z7~WorIiw$26|D|?#QQAR(+Nd=O)V@0`}scfle*#be!Uu`&I((O8K5hbjD}>VAnTyZ zYxe8f<;l+WsQQL9OB?{#`dW2kJ0=}W;|1+^bZ~iTbn3LsENKArf6Qhip z26rwk`PshS#sa!|-xMrgY`8u3df71kiGn7X2#9YEiUe#ua7hic&3Kn6oXhLECP6_7 z?20qO(89Oz!cu*GI`+0rzjfY52oy3b`c!#;2IjE?T$T}$CQgw*`>5kT!`4U zgJw$0D5w+)=;(&>K2w1)i`)}d1m>SMFp(r9#6JjX6l+!2IX#naGt)U*1AO9?=eA9= zlkW>vx((SAIX{bH8Py4TUott3Bw5Ii(=J?JE}g~3fDFNp)&bXjuW|lo!J$(@d;aa` zKJg*o``IQ3?p#^xK4kYGNje;>`_0tsq?to(otjw){^*fieH83a9tg2 z>c-BShJ}s&df3;$U*CKvXxW);TM7OL|GJm>lI8*9leK>O`xr#bNROGYkuSCl8r&hJ z`aAStXk^Y>k`wHQUvYSPgpTs01ADT}F^$tyjf&ku+H>R5W3}2Z1FvGGX?mplSMdMV zv~&M6j4w}_Jxv$gkgs0ld(+h1av5{7=6zP(e*MJ8e1svwxi^NV03^q%{qt*8RR@$wWSvhp&KLiVYt-#0X6zdK&gzqV^YpPn(x#%I z0=gGEW{J>TTQE=S{LruNgKPiy-s;wfW2csU&$o*gr{3Z{O@I$*d%)ab^=F>8@v2m%8kX_chgz08bd(NBLfQ_w z2NN`f4$M^&3W#qBgf!q+(+w2T>w6-z2QQ{aC)+@jufn+$WU^3$1vz~heB66B( z(gYQ3=b1j7cz8ZweZ3GIQ`AW4Y{NokVf>+hM-q7 zW^zuQ-3VHZ9=71&G zFkb}^Ub;3_h$tj%+%ig1vSGb98#8{`c~Nv04H3_F(aOs-!>+n_RIBn!c6)zkvv-}> z1G<32TK}JAw?+jUem%`&&$6;|@G8e|j=svayUUiTzz`srYfpWg2{^jTwKsk*tL2>l zx+$PQnmlcuhChMu3;~64k(@|guc8kZNTQ;PDyHLfUuMT>n&7M{O2AilC*&Rn%C@+iyek!L^|>b;w6I)ghcbhSw=9s zZNoqd?}6{(f_4iZ?iuz#;z@apOUiU zpuC&_nrrYI-`rln%H>hZ26`*x>>CrYy zGQa(t(|h2JK^DG^*4B1DNUJqo zhINcLdvy@}a5sNMl#y^_))ha z$rNEqI}f~HA}T3_W}1X}is5yf4m?R<66`;&_&=ouKH>e0m;HQKVvDgu$xXXN7tWxL zr@-V>Kv370i0`1iIJ>#2XsiN6kRgS4n+!`2VhI`zMT%cf`J7gp|7T}{KlEL!Cf{kD zV0-u@{)mY1945^Qm~*lrtAN1c0%9^7_YfUBEdYG|fOBr1lnzP$zi2u|4G5RM{Ni^t zTfX;`5q>6EgO)zDBRn73Fvtod=i^gSycW@&C|Kl2(InACdN#ZsKA%-H%@kt)T(F^y z8_1%dV4=AxY*O-x)l8Y!u_DiBXsbv&XJ#FcA!51BZc{quQ*B53zPi6yMV?YGt?iGd16-$}Cd=4!tgrGqP zLZHGNM3`<8Hon3=SQ?u_;Jk`334>=zY9=+~vCHQus3jwP#LNe=%7G~;yH7z@EkH5r z?QrYWV&L5&PjG?E{XdyvNR{W&%OxU`1ZtU(aAQms9!=eY1BV}3T#0zepGsmch=@9G z55Rw=TB$hYGok*v5&wA97)*r|!IsLHyX+Z+?V}D%g@%pM&W?%@T{a*NJ(ZfvqAq4n ztf$c~4~;mrrq?Ab60a6uQi}tADMocybQ>UJP?gHxPVU8iEF%XnZzz=~y?5b5homp;p z3zSYHM*%*or7%R2Oy@+C z>=vrzz-;ATrn7$}DZ!1F^b<_+$e1xum~stlKK$+u4Ubm5cR`{SD4pEYjGpB?Ty(d# z3CVLT3XU*Z_fH3s_-B`m>pL!1{{n$*po+PqOdLGz&7wS;CNYV8dZqvy#WMb)1O3B> zz$s~r&EWZ9&^9A&Nyo?f(C61oS*oa{vA%dVsIR2%$-Ofvd!BoqRj#}4ksmBW@)RB{ z|BP4u^It-)`>y}pgq+rkmIHR`&%cGQrIQF$FZQj{M+|cI-Xf5!)ROR1%JC$Lw<1AT zV&CYu!9g9l0$}+gCwrlv$3>c=)$R!-}J;U+VGR0u2i2^?0Bm5N+Iymxef z2&fnSY#i%cc1`oDldRa?_-&X`-n%zW9o9IUOld^{>lm%ieK)6r9x}kg_f#Y!DC$Su zugT9qIDAy-u=qKH@PKzZp6}uLIIENeGSf<9Vnh3M2Kg{; zKO|sQ!!IhXk>}84=5|hj&4X&${!#oSb&_y!+O>IvKOw7+PdH1EJn(Vx=8uv%^%}$Z@4CulZsQNM=dM{pphwQrj21E zxC_b=9@2NjQ&P{=EqudYNycuEv>%0=t9wK5B4qlxKPua)5f|sJR5(!-`)U;HV3NSO z5`6G@q|^ufUzxnsmDWGUMh5APq@`4X?+fdS`7$w8obhM=%6o?T;LA$H;0BQ0IRdn3ve_z|=9F>uftj0F zhZ{H66kJMZZ=%kGx>K^bAadjVQ*)`&X@wl)=D6aMD|vV1wxjeTy*}j6g2;7){k|8B zMm%xKG-DKPw2Z$H_>5%g#QGT`{rivnyJ{wD_nf${InXeTGKwxsP3*X;pR01h`Mq{{H~aeSGZ^s1hms{FAgPkFS-S z3tN?fBS0$67_BP#6qyyl1^t5vli%xvV+>y{{r%nNC)K;ROb8U2%S*ZOhTId6wx=ZF zTbDWbxKaSYvR8)0fXPd3ic`Ayg>8OYo%zDL3-xoqvciDq&Z#PKxN%H>(>G~P3VX~5 z7kYflk_mr^)28N^QhYE9Ui0Y`QWK^lDp*G6xlyT=Pkqr()MTlKz zf5(euBK{J5mxd;#1C9DDOl?RkRG3lo2OCdp32J)O(JRZ6NLl|P0Z|C$5exs=9?T9% zK|CkA8U5^~4ZY^=J@{1 z-3M06TG25A85Ew>BQ>!FVIBs`lMabBj8D7oIx5wj_Z@mkP;R_gvv_?kKUnWvF+Rn^ zD<}v6QUO~QyGbi$cIK^cZl1|+;3*|QEq*H8Vz4_zRrkjzWJhE-BbU0LfJ`bB$ zhGKW)5B>lah+OXN%gRPkI~~hZMGl?-^j+Mcm?czMmpHl%BvsU34s5}>j$5hf;Q%Lm z2Cf@&C?eC>;81n@@A*3W@pp%n?U%X_+Ik09q*LAS1g?A$@534q;GHh_6^Eqr=A)<= zuA@|hg4ADtn2K?IQie|ke5BPH++DO;m8M3}JfT^#H_TSw*58xO7`d4tj>N(uZT)WG zq~2kUrTh7F#mpeTI6IwwWEz&GY6fN$CT8-4q&jdH`kin zX6+^a7ojhb|DOn~Lbst?^ZqLPqZ$rj%mf5LmS>b!)O|P&SN^#4 z0-8Srm%H60Cd(AXSs>w>R4u2AwHAQ?qPmG}dWcUsDS%~qKrLL0ul_qIOF|J>KB_-Y zQ{c7#Z)x}L9YaMz-B@g59IPdaV5#7L5gJ_tZ1Eoc%E;oedK{V{6qh>+?)=o ziaapfMfp34-GpzA3Nenn_@c6K%qB7~0HWfiWby z5Fss=pDfE_@3=!;JSPd12#%`5>RE7&Qf1kJE;%XLIQPH8%k;%}dw6F8( z@5f=&A|t|xc-zj#wNpxjYPueo*3(@P!LMDt4y=Lu?6hS*?51bkiK~ z0M^;731{RpEotQ5K#FtJZH1Uu0c1Nuvr!xlrA&?N3(5teu>Hd$0H;On0wN+SzfI_Q z5=`HnqEFm7mhkw)*mKHryOH2=kqi8@gNcHQcs=iF-}M%kyn1|@4g+0qqMFnwID?cN zXUNfBYm>{L>TN(~S{MbtxT z$XW=QC5w5xzRm6r426}5%-`v~QfKk==r79j2_0R(=rZbGT25L!a2qoSEZP2Szj9q^ zPZDwwZhSMLJegEvw+~jt zELtJNmlj-`pW65)2nCT*r_p325RgQ{Bjp5T3C2dZx6P(bR)mGN5c^%K4wJUGBw*5H z8#jQnUFIdSWa0g?2iky7FynEEIVq8gOA56DOn|SzeKY z<3!@${U8`&YcedOfGC)AM62sp&J2+6o&pG0);K{^Fm@Ef#2b`OMncL;;$I{6nMkD> zin0qVg9Yq zte_IW&rDd9k1`lDns%D+bu2z(ud{0wjnrWpL_OhJr069iBLbX6eD~(e_VF?!Q8Lvl zYl1H+egxYJm>&in>cdV)qiSF5pG~HhWvQ3pag^(;ioQDs6+Qjk&CSo1Cqq36J$VS& zOTD?st&<)!>V679_kDrVF3Dkko`~*08fA+q;)w1dIf}K(gtY+YCg$>YA($+&OCBwb zGbZy=LZG#OI}LN?e!&c90a!7|zqfjBp+2*N&)2liL<=hykH;R*96v-n9NxW+cW@E* z+}Na6c~$hu01UK*F99j8(Fu|Dfhcds%EeusMcx3wig{B|_+-gMnC~zUr|hiOVWQ%q zlUiD_tO+-!i?hAIe@`$uTf2}`kh>K@`^f7o;o#(y<7Jfk)8lAh739I0j#;d$KJ&K1 zDN{#v6p3M9ZX?B#(QPz~D?i{d^#*{&4sXKCsKuap9wE={h41%YcHdrA+@1S{d|&Fh zqj`6EmEEVYFKmpk4%0R}kJgZ%aDGE41#x$hL_r?BGBvDH8EG8dW;Ukva#tAEIm5B890*DRBASpkc_BQD{Qr1$)o)aAbLD0)e=EXqMBjJU&>8Ufi)Of6t z0Q__uJzDWCWY#dkVJu6pN?)y!RDFj|?gV8{NtQlNp+(t614z?<)?p*uC*P&kB5cvf zeVIi?;Oes&-B_Z7jZ-XXg6(4&_t*7{$UET|gnD!33t#zUM27WbZt0!7MyIWLWS&z) zhgLO>&H{UGDyY{kBrTxJA2BQ80fUVxly$^v#j$>bj>t1+PD;cs{Gds+UvXr@p^Lcc zF-2UGE@C0C!=UKQeYf?_3Y?o>ul_UNmjnf-c%JX;w(@*`UED@gn{-6SB@ls3+CS3% z+oO=axtrSZWP%bnzKnTAYrpcH-@W^Y^twAZ=UtVOM6=)=ag=?1PmvCY;7J4URpXe{ z2!XxCn%VM|w{x{Z&O*3z7ebSombQ2Cd@XKW$R|>tfra+Qw?Y+Dg|;oGSdTPlmZGJQ zrp9-4zlI5NJ<3t^ToQ~@X5@Ske_-C2Ujc3ZqPLy_J(m@sSIDhxFFGM{7l#dF6%;>(f? zaYwt;58;X_*ne3?O29%($gY3CKzRo2!`HQXJQoA&z7~PjPELDG8M8oAIQjpQ!c+e< zX_95-F)JnW&EE(I&VF}v`-sBD#11n^Macil7f|h5wiK|nSuO$gT ziv(=w>HiE>&cX#?YcXWV#Y_?ZP^yg=0q~zF8P5d3&nG}TOhVa_d#_EbHj5jtI~2X6 z05mxQ-{4!OuZzgskM#sYg7t@AufDrRXBN(FIp$h@0V181OJ70bQv&N>y7baHqXs%& zNT7TVqd=nJ2BqRt|^gj3)(Ox!rV7TYL6U&58C(9IpH6*%mwtTVrdMfb<>Bom8q`>;V4=>3< z_;kgngphBh2Om4Cs;U%xcc|aJN0=T4`M2a8itl!wv^^GzMI=`~fJ1fEjIMr7{W86| ze?EC2%Z^JzxACM=qmGbcvG<~%QDzw@tRYet;}gb{W%ns-S5s9Yj~;+h7-5<3muP;U zU&Eb^qT^uHpB;CoMz7?&^d$Ve-97+Klw(vRj3vW-chZ*mP38$K`Ebwvbes?xVbnVG zE8oL@Zqdzkr8@!VX9YBf)&))1!8EGbe?Rgvr0fP8*bge%MHo=#yI^g-SodCTg))-y z+~}}nz{w8|4s-JJOL+5HjSLd1f*||2Q3z@nF*zq&CYZd~$;E2mQh(o(2tRVrIINyh zvy6Y?{XnXcIz}8lu0jc$d=BQY?~5otC_-s?h zi+UdtuTUz4#XHM#qRU^Vevpu`cu~XXvvIhYlWNtyu?bV}q}K z%Fp|8PnQ&AEGwS9vw%`}I<@{lmXXoQz^4M+rMKNX>QFRWVp#N8{(k3O!M@|jaiKgB zu4K_#sE&AmDr&k3xfs?dnf0Aci`p0~4im8TFJFo_4ziPiTuXQ*`fDvZzQ3sgFjb2y z(TA!qYME#lW6VnfJZtwq8kV8^<;DjVbDm*@ z5;!-Hi$AD_CrnR0js?kSQ#C{NL$Rr9BEAf#e?4pv6AVh*Wjm^vvB53ZFffFBFKLNO zh^sj?Wb`8+xzXUlk_a-8%ZFIMRMybvPvWCGeEsV3rLq}7WWp{!FbmKXOui=9ZhOPx=_Y+33w-(s7^@ksYt{|@M44f{eRr^*|J(wjAL zLcf)_Y;=ILL6oM;i!I(Gn|OW`@$Y;Ovy%QUH;^*Fg!_mF--9eH5=P4PMv$!Tnwmhi zGn>qv@2zDZrIod{B|4xm;sJQyO>l`$nir#RoyTrgzF)(;tt7#3Ei=>0k!kU{kGNAk zr;_4}K=BQ5hAC*M%e>{tvg<4u<59{h98(spqk1uO@zc0S(gGa}hSgIJLXj^zam&~$ zU%v~+sQPSwHI&0-{0gg@3y%P?Sw0sj7n`&hX;_OY4udPQIjD`4o~e?DHB%C^Y1*%;A>Xj6VFDeNUK=wJdl1EA|N9BatU_p4%&;JCW>J-i4!3nckqLCR zH#HIgbBxJn6DR*7X@edP=Wo4%r7WqxZC6?>F{~zCUP9Tmmz!eJceWoO-15fZY$jA= z4i+sZ%VAz5JG{wpc0fVh_i}IIgaA?=)6o_0-8d8lI61ybmVDcX<}6p1h!Zik;R=0h z-O)ZUIFf4vQ%S`IXN!nP(I$}u8;Iy*`nbl~B{lKMW14FdW~ryp-PaqkY`X$bwZz3Z zdIcsrjoci?DlS7NNm9nXw{Z|AJz~KI{$PZ0L+)F{YSaIKz~ferD-~Gf2^nB!>UC}T z&CInJ$aCYp=sZ%U6o{H9iI2edc0tjuU{Q#Uw@=YC@Dvi8TEoMz)={ z<-jq6nHebo=x`$L3FD&l4*O5RimKIt)8Jxz{W)Y*;ssZz6Bv64Nc9I^B~LB z8-6eukCG}m1qDk!I6{b8yuFAs`(bDMR{wZ(XH2BlyzSiB&FyHq6YIaT<>vD1!?=s( zvldh2ckm9iT>Zix1gyi&x$_{LUqv-01bXb!C_m_sAC>1Q5L=p_7o471%&Jri#5tsD z;MfTq*MRAL6!>i~=KDyDL+X<<@}^#%v5YRi65+?C@~Rs)s&5lduY6ea6T<1-7JOq0 z$t4zXZOe}y5~e)N|Ne&G7^!j2yYq6(NQXV942KN7q7Im=H zbV0kr$tA9aevxumT+Mn7o0=U8d<e);>ABVEuvo*C9B5zphxiFPl%!=XQ%qn|05!VqV)`WEG6> z;6%!WmH#2lqs*&!`g1NYqKK(fDXGH2-1c-oAt>DRyN#XFg_4}MGa5FUsHw>>WoElR zR>vpm^YV~fo?#Pvszhfz0;cBZ)$~m`{3TQ>J7dcxQK8gsEfK64Ofok&r>6NfZBdqk zL$t3{Zh|st$QsqSI9)Pkk(`J=QWggV^2rT3HbdQ7$(9gJ*jcO*otGRVL*4MFq)O`8 z_LsUk$Dp9dIY%wH&BYb9sAmo@8%w0S4R1NWa~k0k*y+a(ud*^$KBLK5yezAm9Una; z54(qHq=xN~E=t}wjs%@Ceblj%c!;H~VtL4zfZhQY^81e6$5qtlFPqDv$M1Gumt0EP zUHO{;pmVN>$9RKG8cZJ4;#o$y-jq@A&7${4M6z))sEEcKzW{ep|q>mSy0T&|3A_ z!>=1TYS#V{J65PZVvY}?10p@0m0l$u0y;G?kVc_#NjBEjkyPJKK6Mwv;4}2RQh-!9Pw5ElZRi!PSU^so)JBs#?{UJGERbxqRPFt z;NB$C;nsk*g?{Wf=`Pq0Dollk+1qm97H+YI1r>Cz*S^4rBIal3=Ov9A0JCq3BEIlT z`2GC8`Z8a&?RD+R#khd>*>wKv(%SZ{ta4?_Jj%QKrS2gZ%?|+lN4#L*{MB1J*AJ!T-Swf_zjqJk+D)!5>@6mict4QC{=c_oo#%hH?DTJCk@#SrdE*{*u_Oa zXkp<+=^TalkB;w)okconUfzZAN<<5IRMvES_(7kw`tt%A-rj%JNoh|jh|*NjF_Adl~IfsVtStAm+< zPtcu)3Z>u#IkP75p(n^wCGfSU{YX)@^Nd7X1Y@Tv;b@ND%rFW1s6^n89K6c3NthWK zO=;%CO#fR8PN>)NI&>kzEdH|1f%{>LDezcTvFt6Wps5q0K9Tp6Cz- z44cWT9LdG5?k9}l%hia!zZV~>VCmf}eQUyEj!VykoIm}Wlitn+jX}%O$PQPYBhuG@ zi@6077MtFHYK9faYGF&BOHQSS6}q$}0I4`NXMLYWSlCT?-NB0xu-j@rk?<`AcuhDDeO zjVB1#XGv-f@1;c80$_FjtO+V%&-Gxxx!@BQX&>X7=g*hhVEX>8&#ka@a#@s+RXhJ6 z;9<73ki>s?pmbC0sj5o}jWt8bKzsc17f_?L?qVmR-P-K(a(0egEK1-W7=l^ne?PiF_ zknHBrnlu+ZGY+9=wjv2+T*DXCwlo_ZVx&IYgM56BQ-%HQua(1LVAmfFi3W#DaMvTl zh6Uf!S+P!i?5PXjm}HGZWzjzt+}uoQF2q7 z93VDT_Q;KT2z}&n$~ctKzDPd8gk5HQfvT5INyKR z`XJD`L^O~)fjsQcUr~2JBP1{HE64eq9>}a4 z2Ja&PFx&v?T+EHDAY+sOSZ}s%OROLk5b*vh;}u>PdPs$9aX9Qv-K4e{gUY{=`pJ_c z#)OBf?P9V^5nf)|9LL7SCngc4AGd-#io`CWY0wg%yCS*h1Y)W54UYK3O*k2UD5^Hd zp%$XBj4GI8ZwXpfA5y6rB~pVd+z)-VK#u8y0+kT?X(PjzOpSN@_U${W=nu6JBeMx0 zchEP(r~)q@@}=p_NQURtQy0hS*2=zrUEDmNOtil}C2}sR#v)#cGn6+lAX%*~bPImT+7Sq}wU9V$cwLY4(QR&@39JQ9{Sy?@ zKb!p4U68dXTzUvSMxX)PWHEx#=@nXfcw8PKw@8l}Q&n|6qx%;>C2xDX=I7t!6i_G+ z^X+)Wxw1@{7t6Bb_vsR1ykZVAA1?E-&e7*kGSGa<)76mdMZVGYx_eg_6diPBwr*?h zg#0RkbE6=+hw5P? zP9qC#mofg2`jj#SecE?)uCpJQxWHK;W;4CP%X#98$-+OsQ;oh<+Q^<5Mu(T)69K`@eKB5|d0WY}mzX&Km8TmfGERF86V7v8WS(ZG z&ecDCivlGMPj52YV7VGleGoV;tfp(P(NaCZO5m&Y)B!D;Ql~aau~*_RvecMhHo?{G z>Eg&fkoa3he;@h?^aO3HN`7R20p{=EbG09vPi0?2J*a27ZHQAPdgCr$pNoV?u6 zI+Kk77o=I-rW%1u@^3ECN+5A;@%0FxRea@JD6Q4qs7y*xuG(TjiZvP}Z(z+N45nb3 zM|nHo@gy$s?x^=lGFC1IX@X0W7zc?cJ$=vkb91>qH^j&Y%(0VJQ~<_}P&*A?BLk%K231vIc08(_JM(0e+UXF zJ^xCBMRPr~O7ihk0c6<_%^0KgyAt!WQdxEHCwu;vd~hvG7o^$nElhKj4bkVukQIE^ zumCi<91V&{A^%#%d`y~2ujk;K)4k6g6`$?ccLVD_X=<=!GGH=Rzc5ng-^cZ~>;L<_ zAM$>xfMJoD7*BclqoiN>!*OuR!78=y)s=stwuOR_E;-PW6~~QX-s+#GFWevO_j7RE zrx0KVc>NjYlRoW!Rd0Kx45N`4Ug$=`j-qJjewC(PQA9h zJI`!t_Vqeib@-zmp!53yZ&q1j+p*2z#PS{kBWFyTRe4^M#WdG7&#!BXCg}G++KtJM znX5fcrG(`&M2PA@mh zWHqssU_NB+> zw=p@5Y7u$cyfS(@gWxhxY9(OkGkE!OTyuB-s7p0CSZc_Lg_Y&*EIAah{`7O5V4w^& zkClVMm3>;-F0BVSI%oZPDpa+-ozg9BX_7LDAd4;0`LC0WZP3TI75OMMTlTDYK|#SZ zwcVVLRE%Hi`P0li(lx3T6NM;MnCp^*KYJLb;Gc42b}t&r?|D3SU{}}QQY8QRBMh;O zw`0}fla@--$1avtRWlG*a4XOAqV{aqWw`kTRPTz^?y}Y$_wSJ_AxxpvWHi_eM0C}f z=a?KOn1rGurDe#P8ITmMfQ$%!I9@%!)-niI+TH>iUcV9rUX}QbgRw$XBE0;<>L)v| z8w?CGHZiNvMzN`jV{2F%96j$2TiZLZYc*p z;VOFrRYAwgfvjdNZuHZ6Tdc5)&yGbq6+GRe^WW*%wQYXdFKEAw!pB248JTv;@tq&hGAKv|u3CT|l0}Bf7EO+?v?0E6< z{o*g_YK!vWh^UfmSTF!kkPNQjR!lHev3U6v&l3wjK1tEO%W**j6EpHj$gae4=hd5# z$GM2do!xF#a`euBGv90p%)5hfWwV{#+y}G+)}Rjs^ZH9^+X=F&QE6#k4=A&^Eqf7B z314bz?EL)`Swn77N@P>V=2@ooD)E6eT9w;c`L;qzDvFve;kD5IgG|mF0|Nui*llGy z%l|Gbr2l_e)ji2PPAz`@LR`B5wQ0m(j7!`w4VBqL)p_IQ;0tW3cYEa);_SA%Z(XU` z!D1_GD($Y~GZQTj{&NbO>Wtw&ScU1uEiFjHXK4rydd@lAzROGM(DRBS`_{Uc$$Ji# z@(K!yf+0$!YN1bY_OqGk6ZfdPsBEaDRq5kVdSYz0sIa1@BPY9hak1)ZRl@SU*fJc`apQe48IuTsX2=m0Ok8^48rnSWIALsg{o|XvgX>?)9o3SIK}CWX z7&T*l&7VGulj3hT*j-&@XVfEUWnj-zF!c~I*nwq;wQbrvx3ZF=q*X&WpFSRWXo&T8 zZ5=3@x$V2*q(+a~o_|75U9+}L@WgGtVs~F@&I~*Wj$MHuoejAp%8N=7sX3pGQ!ezJaPL%!ociZ4QRVo4Pf7)P@(X0zF#ch1;%{0KIPd)DN&Ry7<5`)58JcPH0{ z{F4Z}=XuJBYeV)3zMVjA{Lfz`nsY!!PT0aM`J_RtL`Pz194=bk&VkXc*qy=(%2;XK zeb=x;S?;)d`x#gYZ<`Ipasy+kobL4}H~awrkC!juSJ4w658EQKg!UwB89k*~1G+QN zRG8k#R@%RJLK6>REV2tYyE0OBoDI5(V-2{EnX-;5Zfi_R4!Je@Qt7f$^?XUA^-(gM zgb!+5-dq_sd5zZOC!BsR`SvX(ML{0(Y;-!SmcX>k2V!pZJ15jT1SoYu-)IRQd`QZD z^AZA@(6KNZGouY=mGM6odfGo+r^76718m{IleT==qM>DoFYV4Ib;mpRimx2tlfkju zLIq6=8W?0iHzh+s6c2JQI=Z#uShUet^dzYa=C2flh#7-s$um@+62nEEWzyA?@L228IL`rIjb`@4x+Qh@7l^NepSXyp(VAlNtg;034txdgfS7*mABgC+h z7?3@oIQVMLef3I!pD%Npaq~;VXVh7yfG`~uV?BBYv#>9b2?W?SB%e+@iTOs3+82?k z3_-j9dLC^$eX<yy`R=J{!D<0OvZh-YQKQixi6xJm-=@)FWK5IFOQbvFq zB!snM)-&_hCEb_7ne&-?R2Ny{(wvrtWzAo47M;0t@XGwSd-wIPv&oy{Gymh2?B(`g zPLIHcAFcE2Q_H`rO4yEZM#z zeP1c-Z5;4RA%ojt|qxrq^6{06=MYf@gW+y;2Iq}k7p!$rj>2L{A+1dpRCGLuOi?=HxS z9+ltZpKV!@cZFxLhQ<;kfV;W(!YC!_me*OT%zpQizaJHEX8P#2$-B-n|gj&n| z+?_1W7+8*^tn;-6MaUP{Q>WE@-5qi>qsY%2=-(Qmk+}V9^~~H|P*w%cTE8FgpwAeq zkh#bPQ01xeeB0_CJZ8ckTc*zjPfs3Cur}McAoh~-TH(s6EWFU0vQXf3pVB#NR-V`+kOsYNr;T~q^J>$*;_{x0)+9IXqA)v&+`y<`m?nv)4A6sj`P z)m#6byA`9$GITS?Hq1Orj|kuG7zjh>(vk1f4ML4A4KcvnR999QMa{Wsq_lP+Kn(8L z=ME2H`3+o1hPN7rUFDV{S~-R%3nZ3XffsIfeUXREnH%;UpO%$qf8K&i>s`5pd6&5A z^KV|E1+iI^Wbffujb4NN?mb)YETy~>$AXPc=kRFUj!J{b%F;B{b?|at7nFKfM|yZ+7*EfPz^FWIkD_Z@YvnnjV0P1_RYF8tMCM|? zz;^Y(O9{VOzc$(?#Q}y&y({VxS-qTmJDXkPL_GFM5>-MGN`qn>s`P4+!OV|Q)u#-< zoP_is#YxKV)AS8UuH23^lC}B8_|zj=YRTo-(@W>@R=$E%zwbI?B3@JqTAI?+jE(;# zzWM1*W?*pD+3+l+gKX2AgI`Px5hckfVQL}WXcw)G@Uk!$;cGW#74+eh@651YI_~<| zB{**MyhGdOdG2ePFF<@AVD50c&sq1|NaValL`LyuAFQFFwOK(({sup4Z<-F83QHhK z^J#&7>)e^hP|rH9GTNj1yER?RNIWJWs-CWP7qr*kgD4q1yaVF1Q!CyWcS-BFN;O1I-|DV}T5SNzf3kdu zIwr-iF4#CPIA6HfrKwM`5kGT(zb!m{VndXBG}Xy2XM#-4F_`eBS6MFF+74pY|6tGZHwz;0DXR^EZcJXbj1D5DBp69Xkz*THB#!r zNNJzW22*TghumW$DKot+#JM_+TU`uj0S)|hrF9(en*g9aX)bEd%z5YbfwO^<6$kE* zVru$%{ZPr-eNb&W11$ZT!$>Srd}x&EM;d+?8e#t5o_u>H)yhb`q!d*uBl+=>J__A7 zF%0Tr)xdrGueP$*&b4(w`I>=GvxuHSx{a4>N>!KCwwD;T-P}j9rT+G-LleJ$=y-+V zIM7IbbTAiaoB%@f%RQHOphqjim$8Yd~tKl?;U)4CHbf& z0zgpO`4)QU7uUR<9(oPfIWw zRLS|3#Xm}UN1wr=zwVBQV;SY9+Q6-*pLpkmnog;Do(|{deNT%*o^RO4Ew}taPDJ+K znhnuD&Q#p~5$RDM4v&%qYCmw3Gogl0Y%(h;#E;hjAAa2Y{c~FU`Ejq3*7Nz_ z4Lo3uB_jhEo}UR1Rk5Q8V=N`cT`*pGKaNuXqWgDk%U@I4g`r_pOX$3-ed(X7mGjgK zJlN8jVm+bN>4M7?VVr1CS$_6rf)4jJ=7!wri~GYEGT?7ktx5CSov^k4(>_9K^F-)? zdyl6UB>%l_CG|$tj$hshI||F3LO?`h^7K1-NG+ZVnjskb?n5i}<|qg#zA7#*hFxco zRwt&kZht-eZ;_~uM!ff?Xk|+K`e^IN`U9SJ*Ewokfqy*NP0!@1jv`+yfhh|~Z9`gR zubc{cF_Szqu{S#h(}AjI|5eqp|3CFfOVQ*SK?p^9PWWiRn6BeL<3=Q@zlbelvHLb#z0ehrZ$FWDj#oK%h zk;~93Gk`2bWD1*zk{Fv!Sy^ReT+N~3bedYRtE#U7tj4URVfW9^wR#(rm}FY}w{LUo zcD3OC``GTQ@T9HbDL^z-EejfAMQ;=49gy-{Q}ETJ0sik5JtqtczP?R@-xy0vJ9e?3 zZ?8P?qv=CNRXCzZ=4=dBO<-(dZ4f-O0ewU5DaChQZ-cK!m(!HLu?5e zV@$)gLbX1rt;Ayv3?QHiZ_4}2XgL8ku-}D971fe&l<{kc$;*1v;{Nmd((_J0$mKZa zTD>!hN65D3fXveiH;smybHZFr^(bKg9&sw-f7&s~^kV!5ytWXW`y^x5bk)XEQ+7v05r+ z?9ZE!Usj0!4&c}SO`bTlwjqBaqS;t82%&9}x&$>`T#yh{ z0e3q_#tr@iFO!nKtC!UjU6@R_eQ+!aMVgwRgVr;vIj{8(QGhaOd~t@DUP`ki!Ld@! zOd=G2s~7R&8pB=rfZxu6;2UX0??AGpnswEi5j|AkN2R$&E#?8m4i{m=uNB_E2AXbh z8@>CDiC9t{{uVH0y4dfkvYjbg}-l)gI=wL@(B4(P>cJ7hjmwhjHd^8x?LW(zV&F1 zsu>m_6X^;=k!=#WSV;Y0n?O~^o2?-sz)ee(=hHTDlM-sa$^a|9!3n5to}Zs5jHK5N zI$>{EA+Dp90qB_;zZ2An(DQh4E2}0p{M8x_*g*tullXK%8M&OOKEB+a%t1QbS?QT# z^qdcOYC^8nTo8Zq)am|1%EJ-;1+U7`4_?OTHE;&Rjm4_Ccq+oi-977UMonE#QPbdM z!Gz|v<9X|-%`Vrs#*qGZh3_{_xC=vQK1YO5EC1#=($}or+H0( zR9X+0Gl|=3Bd7V?tVWj}YhR}Mo(@-@T~d3-`xx~uDC}F$-NahxN${HYy29ga#qjNX z=(D#W$bI|yR_5u|#z})x_s~Ggs*S*J0L}a}w0ZdlMC%9HL zublpYu1wRAqx9H1a%ljkWgZ`CrOyQOMQVpeb8OiMeAlomEf^vbG6?BO zgh?^=Hk#OC%X&?dJY8*v)R{A2dk0@Oex3l7KGK?s;@U6`@xd&vABteR&))ZYPiPSe z|8SP7+uW_h3nrgCdm?s)>Z}z1Cs~r2xl?DJEb3O$B+lxh!qFX^zf92~Qf%p(Qy}PN zlBwJT`TPjeuX2%$(=j!cYlQ2vORJ!3(qp} zA048%EWv2y-4-6DnS`kCUvfxTMzo7j-HgcE)DPMK0Yi2et(fvul)y(ZZ@i_m*czn- zU@x~GJ_Hw5vyDx`IPOS4l1Sq{8@LoLEGlVf!BY{}n9=~Qp|R6bAz(}&-@X<7hhjuQ z{hCEaL?NU_7N3e*CQ2|m2pY|XS6NpxoXrh8%_-nuvR1|^=GNsV0sJKjZ|}xPxg2|! zUryZMXhKYt%?@_c{2w|HK3;xh;^<8C)bf_@u&)|ig_k+GBLd>WT2At)e68+sKnBmzKYvCWx&qV9AxLP5= ziwRS$&D{E|Br0+zg%_8N1Umy;36hJuqMucnD|X(f1o(x}YO(j{xMsp`Z>AkPq!Dtyz?!3 zO&64YO&}y4ym0YvbLt_%9|(&m&HYcYN z+eTyCHX63E+1O}oW5;N0-F41)?qAr?UTe)c@D4KQK2nZh^|fO0RQO3<>=-$9ix&Hm0fgf+;MB;htu_$Cw#-`XSq+f zNv|=nO5|4OXqN7qt+}ThmA^U*QfoDd*;(3U=8S2eT*BL6HZ(x>5f+mt7gFcS|IJ}LqU?i50^%xIS`A)oPi?%RwIK=c z!D4EwrS&VURk?Npv(9#=D0qO|!3}?<8^8K2?$aH06^RoTCK2I^qd^Ih*zrQvp9G5# zJTWdAbm#g%4--uLJ~K*(iaLeVnSo%Eq(4WK89Dxzeo3vxC1UGJ@8EC(p$#)Rc;Di? z(rNV?_`K8jJn$G$6Cx5+B~j^0hDq%WDnFbfqTK%VV6>(QY%Ml5xhScPSea^C*SPQNQ6xpH<2Bpn)$-fxY&id4fw!9nkL&!8 zNF9gGA-$G!BU{^uQx3a=3L8{lY4Kn+wPKm_;OxoX`XtNasMnk8#}%~-i;IV_A)V?H z$K@m7!ZqV_T;BqU4KROSC-!$dO*jnRu)HoDc8@&dKO%QuWq0@OlF>YEO9%`B*punS#mNE@38_D5 zI%RIn!i1qjwWAg|R)lSVKvuuU z*iay|H0}usJBu=rve|*4>0iYUl+JH8+uZifurPuovL&JLnE?nTlIk_4F^jl%Bp91h z9^d<5d8wQ>Omn5klu!{-(E?Sm$Y^0>ok`i{PZa71n+C58#U$8tu-H^I&I^5Dd{R;7 zOM(?qOZpJoO3A|{fS0I)xur)!*SJROMIc9Fb@jn*q>C;dPVuh?w3ZD&io?k}rHss> zL}Y1g;I=9up~2(*@UP@y>{F452&}QK>6IRge%QVeJbxGY@dj^p<=tIBaFz#MOsy}57c3T`iT*MB@7mn6C@ z29VwP?pLW2C_}B%JKo>f8eR))1H;PU>j>apyC5x)!+lt1{(y z|JRARx=(>^TVvrW*WneR<$QCn9cTt$k6t8Qy%l$578}V+VA0S7D1Xr=pVF(-6{j8_ zOO*lYyDi)0)Pp zyLFo~!ZowfL94q1$N}9?FV}@M-@E$=$l2L_QQ*BI#TuECSE5hTTJB0vC71J-06frV zD`u*E&EWwfNOB`W$|7nNguq(+k}UNArk_aM$Y}cEXp&|Tb+G$HF_o7@NoNst?P#v4 zm|4w&Ng;+Mu8u0Tek;Q24A!OXt0HEdkbfTzLV_*W+F3=sZSaoEp(hR6N2VVs z&k?ZDpn?#-wNp*XG4k^Z^T!-tbjxB)8a2too^kJhMcvytR0YXxtI?*y!Vht5J?$kbQ84U49zpNB+Ftm+H79Jke zSddh|&FWOIu4*SJ#Nh0wuzNZW^jyYxfOT5`vee zExt6sq@WY2y6P6$HPU z3vvZsZquD1UiN|j&%UKaZuq2BZyfU-g&`IRGo#LN6hp~rRw7`?Y{EJ-T)~T zgBVB(BvD8*F{5(WdN|q1%Eoq?oZr!N@w!;U#FKs~F(oiqP&BN$tUtxGb+6v1417pm z>HWxKnaH*1k_qv9L`O>?!ctCEXt7rOHn^Mhy2CpEIFKcm?awao17{u*5-=-AGb0xjnF7zvz4}$J`znlPjosn*M!mh(p@$)X`Ru?C?FByfnwj(e22TR7`s8;SU_c?)r0CO9)zQ+LtC$$(zOzIDo zAxUg%syd;lu<5taUNRz6(lbaK!u?VvVe+P2aw96u%!GxiMM@w}Bnzi(ENg5EIX$a7 zp4L>M)#VCxt~WlT9zeBo0t>@1>P@IPv`sCdqVuhxAO29plfI$ zP>4BiSg&Pk@a@Oecw&*o(G@dx;>4s($w4?Il%>jNa<9oLzVr)RJB(9QLh5WioddZ9_&;#wCxbnK>!~vAm$gG^|pK8`z4-zKq6;2G?U| z-YJUg>JopCpyRgVVs#u53_Qp%UHahsYBNj6q|8XGVrLX#VlqmjHgMdU=f#V_*f@;W z)8AkG;Zehqo`iPJ==mWVYR)VSWZF2aSf>ftoHjk=3tj4(#mvAsZueLrl+2?-_e(h9 zZLaxK)ZkgW6Ga?d!~S#C@4Dt7MEIh2-`WvcvAFl>^Sywx^gELJHi&ZU9(Jbp?))~!u|xo8gt z4+GUW?x9hZL#=vOII5+hm%nWTnp&Uh#E-DI+~9(6Chzojn%CSLd|$}3@J=#u2o6Un zy2OSsRex11cbL(PsUgPe_c|Fnui#eSAt_N0w=No4J3|*kl}&5LL;~6WKuMHgDLZHG zWFgKZVeIYJsPYrgkf^MzTu|hd3V-z&8g$rCjO2S2$|WJ0Xka>&^5CG9%eOfkPza(^ zD;8&07Y2b9VXfsEc?%g5ATRJzR#v^gw)KRZ4pY6u4KG1{*A-E0yrdmimoVvt5#?e? ztX`=<)cLTbP>Gb6U(nSYMj11DXi)~7F-;wF`qo)#G#D&;gP@A%GT|L09k(xul<0A4 zx<6Lk)YtybmfVp4r-QIn@IP}=CSuxYy@BNMs<`BR3(sMm1HS)UVIZ)l^j`X zj^cK#d`!&e5XtxK#05*ER;MK_`!-LSiK>NpRSO`8D>Q=9m0y}MMM6utM5rg$PA#VA z{mo=93?Y5^m>_%4dW#KE=_|s&x|BXZWL9pcZE)Ni6Io66{SYmzevZ6IhR)5=xT{H6IE z5%C^940Wu|cBMHvbX)_-rLOKiQN=9kwmFBs?+|s}rq(z&w@?&V<3*!<*Cr*p&d6A{ zyncen!(8|O$OSOKA#HuMBt;|xmNB&{K>@bpA}-!E77F?1&5W@N&{b?>+T|`dt30ce z5@9=uPC?3_P3y^_A%??W2s+YR`0w?*?)vjD7ixT<6y%ex5h1>YKxJY;TNWuPliKi* zi)$g&4T>_w$r>h+!;uy=na$K=0vg=)T)Mw-n<61H(s|W{E1hQFMQ+Ya4-t-7qbi^8|Mbz0wFO%7x`}@8Fl+}R!T~eXp@roZmv)-OS z(A`0>PmXWx$1PHc$<3Z>q3C$DhYAdgPXUrb@A%7oGJ~Ac>!lR1fh(>f0RuQm!f=;9 zgGhKw*E7NF&C zk*^=NJd)B4JTuExap79W$Ze9zAtVe#hBRf^b4wUG#wX>nJ#Qx*`mqD^M-wZ?W)^41 zfEIisD~FPf4q&|_yPOSJF}Go~Wg$KZC%SU?FAosbH%T7T$EX@X4hk- zCAY)>)`mVr{(HQ&(I*s@;`&FlG{yF`QrazLQSSGt{_*44r0-;z_1hu&ru8n@l(tBn zs;LKapS2Kos+or?tlbzZ2P>g!y_c$<-uP?@0@u?jsSN4GV5}oN23GAq*To_hL30F&okR)o8HFc;H zn&mjk5chBD{J5DM-i#d}%9crXS8i;gEiGw?mV}kwC$=(5h!f$?CDB>xOg$9IZP8=!~m#xeMWs8ZTk*Vw*!rvO;8b@XwFY>2upCMja(j7z;r%Ns2P1at!^1uB4(e zUY*Nhd2wcJY#hZ%UBm?YWzia$fKN(92K~pTC(p)4XG|QD^V5kLZg!T(PTS#e_iFqp zC+wGMWy#@$(LFR{A6jf2eAAs-G22#q7C-Lb{88fKegpyENJX6xgt=re?`>Hn8x z-in4}Dp~3Ts2-!t4JHm9P=Ze|om)6k1WQJ;K~yDY79=2dr4K4tjHDxkDB(zGfrblI z7xye~B#D5$;G;hDupBdUj4JQ3wJ6JkeqepkkraRY)wr$ zd}|XbQ@j&=5C4oN%Gp%amXdDf4CxpMJR(^RCspW0R78p>_r^E(Z8X?ReFZdIEqCCS zoci-0G;V;<&V|~4JAPT;J_$#3s7^*#ALc?n`Fp)kq%yjw6kW75r+gN|PQ}ipHmr&k z1CJn*6p5IY^PX6r2x1qz0twvW&Wg-*{U<627#gV66eW8=l0!k&5EVLMMz{st`jn& zNoQ&Odq?2y-Txqs?*|K$25CM+!_5I6muFr2>|fSA1}10}WN8H5DXE}wAPOi**>B?D zkMNc6nmy0&pW5}@Tw^nP;;4C#(q1$ay{o~`vSw7F!16FJ5X1Nt3txvQrPb&TRdM{=-pjn%v#^l* z6V7$X{@Na<}?#I;^X$qR)5u>X0W7` zt%>x0KrN`=aa7n9#Kg-SR~t2g+t`dD{n;t!)}1RZ7?@ccBP+EqpH?R+7WBdrm9?=U zA$VJ^nOkiN>VD65nD)N^MD?xGM6h)Lx=^#gH0g#(vl4nqt=NTMj_#bb`A6+l7y$HW zioQFo0gsF}q)0!7q!aPchOq#c;nsIA`}MZqCFJiWwjME&iA?TW_1QjkJ!gBY>OkCj zqK);(Rx_T27PQ1Ltnv8X5#(CSMR9X!R#%sh-^bUFh^~saM`^`eshe$*_}Q7dkQ%=S zo|vz?y;EddC`BZ;wu#~avB~1>CXt0`;mG(FPqQT{(k{0T4@Ol7M>8Vp-dn!5nk{La z-v0)`=VwT-8>w8?1f)=pu3uWC zvs0((IeaFga}1Q7tC<{fiZm{`cp9VBymi?-w598fu91yn#`hju9(X-6Ygvf=WYSEW zm*!MfmnJ}*C7qHN(PL{__o7k9v$nyFD8$~n8QCuvgcTPj=k)Iir^8!n@H*!XgBD+T zxTb0C5~<5MY&*;|@+l5DEKZnJG|(WC9t>LYuKVGlR&8EbQE?Lk=A4;&`Q!PY_U-Tg zo_r@xEzpERNN46gRB&uI`quxx$m;$UheH)-5)o;j+%akrE4V5i23(U9Ts%O&{S24q zYH4R{Hd?sRZG}!=4d2E?N`YpP?R)5%VZU)fN)ue*rCfF4ER8Y-OyVl&q=e-b8%u{*cb&_>_O@ z)Z3sz{lz{(0dG8%j0WSfK)^hcwAXJ=*$e{g)z#IEoUC3$kBdLRK(5}`%l(VazZzYy zWGUYW1BOb0T$E`87cO3Q0=uv$nhhz8fxuwqjRrPuevvLbRXQXvbwVTLZNi49(Kx-Z zD%@P~eZSZWP!N5gwP z^5(J7bgSDjaCS>Ms2mA}e=c?VIU_IUz}i4S2{b#uEQ>7>Vw7pjL@K~BzLM7f;&uuG zNN5g*<7O$YjwQgP0uXqIHipENQya1XpJ4LdPyPVX1x{Dmz2vwP6gOng)%0_*8jC?{uEQ}%bfFSdcB;7X(0HwB*uDP{Y( zHs!ou`JP!~GHKT6hs6;5D-;t zu)n1(96_PZpk2bfyQQzp%-kUu+a7QoH+R7>9^1X)k+CHuC8@e<(8HMji8xLPd?4ms zF!A$CU4%C9zE`)@dnmy$;IGGnNmt@FyJ!%SwELd?x$ zMU^#@(X5yEl1{Xm}nhBB0IcpEM#s#a= zV*T10ATN zwq-#31PBgs2hHM;SX&QFSUy`60zCbf(~P+Yf3S10ch1_9ZC5)232CqQ9`Xwxj0IrB zb;+X#Nsw9D7TAdM8J-WPemL0J+T;GSbU6K=n(OtyVrECgVJI;wiS#uhmJg5HIlr1 z;cU{J(Ps7-#4fwk2`JFxrK!{fR`*u8FW3CB4jA zkY3DuITQazKK1s<2+Z&5%$w3yELI-?VX+n*?5ypxV;0zNJw)@ku|$kaW2giB3GpA# z!z;B`c==Bi{s&J4{6ZG^>;A*|u1zf}v=~w)${|Xbzgc1G2X5CvFmXBix*wmwDxOg# z35?CA&Q{a41x0yw(K^4cA=P0_nb{DL5ta4UQW`nn`jI%+d)|F(P{f$NP5x+bKgR{~ zs|*rTdV~Uep+z8Q37F&ab8z~1ZyvRU*w;r21{NMRAqx$PCO0;qX=xs`knR1!vD*kf$0AC2`c8`^%y!QH~# z8gg7Qa3s-<+fq=ohOuV$#%TrbM5PA@3A4t=a&3$9n%E_8Eei{3myZ3dm z%3#WS^X9X@z~aPz>W{*nxFw{T;mae%N!Y=0CdDb(M2w4u#Gfg5DUGyKZlHi&nGD#i z(Doto=ND)k{O`rh)Uk1NgS)gVy3kuJAYQMGwTJadT_uFt4)pj^^yzi|q z`apu0<8A^WBaiBGR)&GNazLg84xE5+=$!$|CTGu@ghKFqcp(^;%>Q`w_8$mUshLqX zkO65|I>PS4CJ1~XE9Hej5G752<@~NpzT-trD525LIa`F0vRrG#7yXT1zMe;YmV#@bAL>)EJ&%C&`>Dk4@R2!NI0JS)w*_pD&!=LG0~m+MV(AyK)K5; z#TQH@j-4>pd#7SLhr^u78rL{rH1PHyFe36*K$tqYq_jOS{hK>>X`0&Ghb`D>FmZAM&L$0wod=P)4K5zu=$>*65|Rrrl6??0CrRdcO!30CwGlg$ zC0h!w;Q5oT4k-ehq3b4&fzWWA7yZrN*4p}?13+BL{69xU`~N?K+*+qlgRl5TPUflX z1^wI`8@xBP|z>*v#Xmu?MONvClU12U6MR%2l)I#gzaY8G1Uu3R+) zT%wv$oUXSRYd`)OzBJ>5xST_N>yqX=VdD}MVL-0?KH$qvVsid?$53kfo5fZkgk7IW zn|G?Dq6ed%EaxdZC65|LwB@-Ar|)s>DQHwI_Oq_9Fhz_j?5A#NDRqB&iOh1n89H9G zt@-JFcCC}BBE5;Ls40mea*6WD`d`Fw10F$sg8}W}Lz-R29%4uQd>^G`hO_|E1|r)S zDEl=Rm<#_8iO0>kmnR@iB_bX2IJ;YzB*=_rhHm`B6jGadS96)LjGNibRgxWcxs3Z#w^&$1=*i>N?peIBWC3CCSHr8bGX1mrEY)d~J_(kGr zFW)!I7y~6`yi&g|LE-hD;;56i?_1Zkoc(57=)O$4)6q6l2>SrHp|ej;)-yMvB6T<= z)o5Fkaa#tXQ{{jQ{;O;lb}SeOHc|&oD^d>v7TCEfy{4p{8k?jH7qv@OO};Z#5Al_# zu-ww(uBX+mCdwf0lAQXV;)rSXLJSN`8~fdNj*Y3*E+)U%zVT6v!Jrf@G2z(ZpvA1A z11$TM&Tz~Mjh}J@kK3G2K7uwfEL2Mt=c`RX(YCMGO%EkVmU?1vGy3+y06e=Nox|-G z*G2Qi5GpPkD5A|u`C%ny*yC%JpW+Stz12MsR=AjKUtJBnzi<9O8WY3(e}g{-Iu2>-Nd#y-{588E3mIDU48qt;etY- z_s+InpA=(OhJ`uP!oGT>_sdkBsS#cG{guIC7+&+V;#Lm;qEvH3dh$t>bz}2QXFv-L zYxvcE%(osj8NG$17$1)gQ107=5^tIb2Z6_1;VJlR4)*x)*T3DuUK}6Sftm zx`dP>XR?q4ZVIq7^6Dm^cOtL-t5HllvI$~IE)XRp+N^zbZRO9Q`XX>%kV*IUeC!Pe zFhazsle?buC6tonAeYbRCMLX3xACp)tny5(x~F&mvCgFAry?>Hq*-6B|&R3jBd!(N;82rlLk=lVwq|I~$QwoRD?)r(yc+G_w%;QmhN*VWPGkE|F>X;BzGCkp#W5mG7O^?!x*9{ z;S`8{u9TnzNt;5-9$3L)DSP-_(~=OfI1;}@fp>P`EIj1IC!fnddS$W^gA{*r=l=|i zEvGu>(m&+(I#lBy)MZoTbKU)c1AepMblT;8*zo^Goq8}Zihe|xsX2jpy;sjw%$9=S zxvq*lbrV?xYrv&y=7Mo>9U_E-57}xTwc3moMlR0jd(G(mYjzBZ+gxqwMhg51azaa9m|*mko$(cmR^Yxg=8?tLxa4~^{55tNi=oZUF1 zMKaTemhxp20JPP4fst~!f24+g_ekhXl&ZehJCOb$TddMi@P2`aDnYTK%R5Y%PzQ2< z8{g=iuKTR$@AM0Fslk*mR8Uslw&+@-CjGN~r>0?e^jY)+~@=CYLgn<&PgKM+KRLjrGS){6GutAiD z9*$8Y!^jO+?QW*bRHRr-SC+pWipv-G0b8M`-3{R~#>~E2P|pNGn5$L3{=$GZ{c(py z!1QR9D=x1~u+5ZlNV&T4YM>6f0#&$>X21qgGxPFGND)ePANqHaq9R(Y)|}Jot)9pR zjg0KPoi6WxeR2yxhTH#5BfqGNy+8M1ee@W8Lz3!BcQgxg97s*m-xGM``Vt^Mkd=d5i9`Qvu(=M)<1|QTX6S=0J*7 z(&F4{5yU!F%It&*J&D~%oSx9+zvGhFc>qW7uO2|mqTcER!8%6egM=VcX~a% zZ5RLdt(Dp*?!_9tiFbnTAY|6VDL0c{*0*32zzoB(AuVg1TBulhOjhuXN(>}2u2O>4 zUFvtzO}VDFvBe_VdVHf@3~6+CWz3#JKh?wtc0QOL9Ou!|(WY-|YPzQ``9HkcN6CMK z25dF{sUawRmU#`~GU%xB(UcAJ}%QI;$W^j@s zMga-VIM$$$q8_|h4Q2pK$;Bx@n^#o%nN>I(K<5YfGF(_(^@ZBD`tkX{wHSQCAp#8! zJi=c1zA{0aUS3zgToy;CMD=KX_q+Vujzwp&)e8ps-eE3QYl&z`d;^{ifUBUKH4X&E z#kx=c9GGXA#8Bp>0y@mJw$4QCsruZist9+o6tdX>HssLI$ev}0a>97Yr84rPnyItf zZ&yq?I=#PGUjWqu%1Kg94zpzoaM}S5(3(0oPrBpD097C7?onoPrG7(LCorG(E@E+f zabaTV6HyY4m2{73XNS-GkxXzCeDRJ_0_q_aLnD0fk@_hjtXEn(1Ozf4>dhCN%`L7? z>(wx#pa7|GqHj<}vP9V4G1i7jiqK0h~Q6)qf2-_<1r`%FW5{nrI zl-U4mll8MiI8J89_EA9*kRuBNhNujH#{G*_8@xdJK3{xyIzGqw&QYB`|HC(bIcbGN znKsHTfVOIA98?=qm*q+wTjbMNXKB+rWM~pX0=Q%nco8L}SZULt51k*uXPs}~-*+N^ zJ*`do=8f|m0$EbC)8=!K-y5NjQ`!$e>EyjmlX%)x(H6Qp`}8T`la#2Cs=yA7!HWbh zPEm^3cz~>0nse7cuL_07k=$2BMB?hZyMoyLs~?@&c54pBEiLK0XS5}?vTEcqOa?$7 z4>!7?y*+K{z}<`Co>3#CxTG%8;O(-e-t%U0&o>e&8H_$ZzgTa6hwGdPssRvhm8T^5 zk-v3eC2i4&IkGqeu3^7!zA%1V?~VI_@wSM;>56&rG)d4rYHflE?B+rmcmyAh4%^Rc zh;eas&V$14>#e~H;~LByDhE%84?7-FZH(J{$Nj)RJjRD;Dw?5t;9K`2+4~dEM@-P( z3JO|gOdexEDnv!n7AgjG1hG_rv9U8ep4FI907@Nfu<-#v5XuEULVPRJnp+el^B)i0 zVnE5n^Z(yBwc(=6sQ$(X#6|K&lfjoN7Rs)+$jU)#9v59kRu*uk|H@$4ZR39`!wCx) z*J?1AGe#^XPOdUu7*hiYIOP!Vz2JsV<(eDT#-mGoy?pNd!u#DL^bz@U1K0f_3BvaElwtPz|gi+Vpkb1{aS>&< zlccSj+BxcOpq^m_wlLveo;{E^jqP>38&hldrgwf`_cX>= znM^OMF7GvF5+^BvfRx6qbYm2sn_cc<@V^x?wbp)|)#w_W(a7s{Gbu)+ger5zZ6sq1 z>w%O)!H--d8i1RpPrkk?md#**s8meV^Ai%W10b9&>!Ucpy^hG^c=-KH4W`)G}Hs3Z{nYUy6O7cMR>E zwNP~!aY?akAT7g}#Zz1ZOiY;LjK-1hJhr=DGQZ=Z2W!-ry;R?w>$dwG?*RUT(0}Ro z|H;FDe3bvsOEI7eObE?f`9W2fQ&-1G4sCM<`f3Gn?HSt)A59Evd>smb3^9Dy>RuIJ z7x@`DoyRwhk{Pc~)tcWCPv&v=-pcme#*|)+aTbxN?2V%e*(!~RNQ;>w?$^e!5tj5B zCvT0CS8!%F#xs7F94(E-185wv>)uOzwj1@SC%TyF)%pWR*yucnx^04<_CY^7z;?D9 z?Wx9EH|fBjV)B=7Pt)Okna>CAS=P9~pM_ih{a68j`_&FNNN^0U%fgZ^I5u(;N|TBLCV?>F>{$B{k?}EOfpRpQ-@tAhj>Ox~K|NDGRM# zq#8OBfTY)Z%$rOWduPq%@{gCVvlHZT?iMvj#m%z@{LA=<_F{JM4BogiXiz4BC2vgo z)u!lF8V#qD0i3ZX2nvO~-LMIrm98gfXz1rQ_b2L?`}4!ueHznQs}M!X<6X&U*8&j6 zC2#Ma%`49AX4`_!qTHE8p>@@$u%WQxOesm_GK@FCV230Fj&GN{(G0UQGx9Pf=tceD zn3(t^hO`kg7EN>&U|;}klskt8szQT)x8=Rx-~mk-ho6^0dyAZNxcKx+WJpz*z1)-U~FNU~rLk_=lqRQeL- zz|vB6ECyX!hYQRYCerj(B55+W8Ze28Y&z@1x*vrM7Q@~^W-Z$Lsa5z+^ky z(#`GMl;hbne+r;9RLZlvl0uM?^>G&S5)kqBEgO=EXwriv6T(RGjCwSsRH=8{lD0mA zw~A~=o%!z${U>_U^UaRO!~oGv4^j7|e~xGvIe$Bj$Kmi9kKO5hU90Q*!Qdx#mEx>% zqYycPsxkggFsUU!6O-7-2>VQ(Fk5!!5xO(9R zV%#rmP!RdL~W{)@a)XUQ33KA|wDG(K97=XpXq>BS2Sg~j3ld=FVw>Yt#mOG*IFX8(zDpVZDnS-p!P37^9X3SgZ( z(?Cg5rXT#4>qi>T0$OwO_8p!KcSsYqTXnf7)*AXMu2%_JIFJ!OMhp%` zS~+!Mc4c*dB%XIfuH|28o7-ol91uOQ-0*i(=YE!SymbdVcn->#r1h^``KV%ZLpu?EKsPv*iuHRd=gKuDGOVL#_0I{9!)-%9mqKNZh=$vwk}^$Wdul^S2t?AS zL?-sQlnM!e#RBccmW)JR!|{?P!#1RX-u%wz%v14=h~=;u~b zo1c2h#T0gEhdi@OFntzlscT1ncx4#{BurFDy01^WrP@n_ffDJ(^4kFd>!L+OvNRek zZk1Zn?>$hPEi#yuU6R5*`mCjVbSVou%RZ7&FrMxMFKWkoq+@s#u00Ul#fgiE$Bi7@ii` zwLs+=75U0Pa(RhO5tnc5Y#QZ#(H#%8cMr)$!}GH3t{Nhwrmpq^XO*K$Bgi=AXRM zcJtM>RW8RzNM-GmOC?xBDB;hehSs{*)t4cn(!q`p!1{p%O4{gC&}p@{h{>U}Hn%$1 zLV13kJ)x$o=+6(XrGLvMrQ|~=`rhYN_~YudYZ?X`0?nKuwDlt&oY7xKh@)w*1>#)v zF`!z)2HVWGQ%L$&K2iDbo-55w_T zuiUCl{OZ5=&BJVps_V6F%4K1debe(I)>eOGoNcXHg+4ro(K+_2Qw~VMr69vj4uM~W7naUC$p&VmBojSguG>Ie(q#L-nrKAby;_N& zUA?4?FgY)&Vr9vFk`NJCM*1P_U`+RdGkMfdrm`3X^6Ua-s-L8ktjd9yXo35EgL65Y zZfRR@RR)J~fBqeWWjmNTHurUZG)ysZxkj~DLjHn{5hG3_r8v9{AL27%8TWftf$bQqfx?ezFSypdv8B&JsGQb zd{0)`{dJ=n&BBS7G;ThljS{M6Y$4Ux1BoUk8bTsltUu=Xyenn=%VP-~?__0~Kth4c z!p7GtA@KM)tx9{GWvX)^5nW=$3*HE{DpO!vzf%i~i;Fic?R5X@d4hXw+Cb&p##=>K z1>*Ax>VAAZge^iF!d8A_z3|>Wyu7jV`FCSb$n6WKpxQ$@WuO{k&RoF9!$g=A5P!}K=#?M7HR|rHQo;h7<=|^F}{xuiH(Wc zn}zgP_rPH}Q=t&Aa9ZV(+Hsj&@%2~Jus58q>O5|`Oqs-(O=MxRax5xoY{{0OB}^O~ z{X0|sCQo4PaTnX-4$S{p`-_OY9qppjj}U*D&>|B?|K}-1T*YZ9!&R>i5?mWW%Z3dX zJ8{)roASy{%2(DmGy)FmN8X2lajjL zYeHK-pKt14r-Y@Ao!MO$((7d#!OZmR$n+5;yEE_xxc2^d-kP47>8Am1wb4_4`4ue= z2a|s;%$(bMShha+t8RWRCS`gOVdfDH%TlaeZYv#kEw@@kBfCkJ2WV;5(g{D73qu|DPj{Ii}KzJW$ZG6Y9kQ`al07O}1Q=GqMwu#K8iOnw<nE;ytJh&HtxkJN&D)$nl6uy^IQ!Kr4x(M;Zu6(x*X z`9AUFP;q1U;^=UpWTBmrQEQ*Yr7=O9Yu1l-@2?hF#2s?wwmt!pQpwx^Yv?K^|WHZ~9u<8DS3-ffhn6UR%f?8^Zk|D6XB zIsIv^`-!=bJ0^TkGaBo1^Pwv}-fyochyO=js1k+GKO1Pj=4pHiT-Q?~s z-}*bQ?>Q#CGMEvd>PP=1{Py3kU7FS~g3IySkHq4}9C{YPnAGf1g2nr=!p87K9 zF*YisuG7A_`??Q|!v((}u)`s>q(lY7y1>E0!ZR%3cPh2%1;(^*yTh`+_PiUyW8lc) z`*HQGRY`2>5P(kp2G;Xbegp{QiU`(M3#|jCFGH1Unnt5-rvUBu_jK1k5B~O z>&X|bCVM&ueBKy^m|Hf2muZRPlQZJnF=hJnGWBuQF|t+dHO($#DBtv#OWwd5zCOl6 z_H6V0D7NBy&)wx9^Z}>8^Lvm+*!A8YPF;8B7wF++ArViP;r@A5OJ}<*22bQQd~X<5 zYNFP1t2IJa1XOJLVSUZoJR?^?E)ZkNf@ZNP>wQW1Lig zXb;B)GGpCP9A9ZE9hSRf6AB6Q>QpmF-4@~`vVZ8`uzuxWFFnnip`o8t0+f_h)Hd|G zl`3LR8Jz`L6w_zl5US}4h=2zFE?G}60&S9zX-~d3Y=DcY^8$RFLWwXcQ(V?Q6C=n9>0Sl<(i)&!-?y?EmUeqh;3pJ@16Y7*iD|TcHJ5O&eErOq_Q-xi<7GB3Y)#ASp9TYI*I61KpR3?XgwU{2nOymSQ$29wcG9x=ggf(qe=WudEj0EJJ(Dy9VC-d3D9(h`b=Z zEsXO$`{Q1luI)IwBW&4zjOD~uX4?D?cVM72UpnZ6T?Lfn6mv4Bls(9Q+SV7DLy;{Xw2oD;UU34tgAj8@0h6I$dHc{O$zBhHs1 zqKkqixn)G862T`dr=6#=!6BKxw`b}lK9FXh%(%9eIG^SrmQ+pxkQ=t$edZTMXMX$` z*ncIr%tiZ?*6;6CT4jZOaB%L*io`<`K0pn}zjzq;y6DH|Cwe{R;7b{Po+aDYKuV1~ zvU!jp&eCD9%s?w9Li*)$e6>qL+rt=teIbf#^Z_G|A#Zwit}9wI>rRkO(1iIF(8CC) z&i8fUO>5|Ppps___rdmrTAV4GG9bU9!Onoh%&sf9Ucc=C)`}$+w}J*-sNDlSicJWe zRYbwm!$l35n|MmBOqdGMGiPx+?M+h$Xhxh|I}9rcpmbCL42S`Qg+qmindkr?g;hE_ z1H@QC@)6*1C5D`|e{4P!JKHTR&6o2}&RxYhTzdPv_GwoWWX1+CS~0aLhA5o97YT4TyT_ono?j0rVf zK*amap7Z4_rP050K})7^ru{3LWW+_7p%BA>@vQG+q4IXY<`ET0sj7DVUHqsAur}i| zIrEzzF8CjX0J<;z`orSQO6NP?AGNC^qg%rqCK?pvk!c*9f)rH{LB8G;RE9PRHg;zU z3YxwB)U76QQR3H%AAB;dS!uIDWu`c1P=%DM6t#n`s@}~y7R8K3I(buNi2+~;yYgi)%u%aTGG$ictQn7<9V#o=_5W_7qW||I{iv^ji&f2@Px?*hz@xaOcrVLfWtINJm&aRnbxt4>CZ3x1 z2akN3{}QTi&h^13=X{iDY+OK47O<&>U0w4HYqG`xA&GK#(Ng1zzOY>`g9N?~PTqHU^E8y*vFiKDhtvGDc$834OW46Vug- zl|$7CcMuGKo!l#wl8Y)?Y;@1f#nZzsG&mMG-RN8VP@{;o>|TrW6>QhS9oEU;eyRJE z(gldpxJX?*#x5&+9^AL{z99o5?usbrB{j7XsuGdH5DCeI7fjTVDN10bmyLXbV-&@x zI$T(ntaikank|&(?J?9rMD4FHQg}xy)13S)nXUrf`;2bbn8x`q6bw>ff}-mnI9Tm^ zelEZvaa!h-A!AffP%=G`NNcvrvvgY`wY!80Q{g3E5-`Ex;H)sVvm>{)i-S^a zi0rfQEf1nAMhlY815p}3GRAZ|EMD7S&&+}0Dv`-?eY;@iUCXT^#}Um5enJhn4{6h|)01vxh%-}zX4%-dAs1SmniR9J2y zse9XT%MS_vN9oJU^uT_W=V)@jgw%=Rx-?_S-!~Pp3Fr&)WMdEyS%w|I4*ji2zghiL z^>zcBzr-O!OH!F6j>E<_!>NPfV(dim=vP;-3g-*&O`_}zR06LEy##Td3K&|h%q_) zx&ytY%Sp=I)u$N%ie=$22yyb}=j3Vdsd!8%;&-Pna2p$PWdh)%_Rwn{MMYwz;srQT z;qZ2FxkI#asWWGM$0=fwe@~eVnKiZf40v09e5fVhu9((1&N9e}jkst;I!FF_+SB#@ zYFcCI%oW3%t*5?$QNqP6e2E&#YGOFB=8@y;JXII`lZs`ucv#cfw8xWnYisN32A@f9 z^mUb*-$r+p_m5@()o23<=d$+-q01F-@gT?Z0O#2xFxSZh~#e0 zKg}(#PC7qcX&y;k3AsAf>G!TQmbW1@Er2zslS^p+=(#$|7Dnu_**8}iFi5qSXm+L< z3eRgX{IS;8t*Dxvn-6nFa{U6I%2>96Mh0&|TZRKb$}=JEr03J!F4;A$+%YXPI z?Y>yOEgo@bm`|It)d;MBHxI&RT_IrfigZ7=>ACE>1dU8GQ<_xVx~V$H0XCsRUARG? z$>=WyJ{Y-t$x4>Odjn82Lo*SB6;^8spJQULMAih8X|(C`JGC?gMY$ChQ2Ik~&UU4( zecz5IxjK>(`0)s^UwYZ%bl2(|MAn-sZm!qianiQ?k+HHaDv09Mrz&cs4)y`>=-sNm z!RNf%lbtv90ga&tZaM{>@0nCK^%VG&NHsO)8uMv8C#(W~4S8_x+C4p6H6Go&paA$1 zDXX2k*FU_R?q8eC{%nrkQq?iEF_|tdRbB4%r*8e}BXy5QS0-u0m^Zq4PsK^ZS=vm- zibe#{OZzvRT=(uDx@U(id&o8YAc9dArD^ao6vaM1S_va2ooIsvEQ+91q)<|`4LYlT zxe_!t2@EXA|J!=&8wu*a2a|EK-pHMCR8P{<$ONXeLkKUrx36*<fvJ$>MD?0@5LRM?~6_LXdk$mj)I*&c^U`tqcaq_Sw0fVl8vgX1`O zakHxLMrN_bd??13ogz28-wk4zylh@$`a@ZayX{ZzxBU|<9qk&jX@ehBZacTjL-+H{~Hr}^vfEvAJ)?7OIT>ln#9l0p}Jvg zCGp%Pz^M`zmzs*S9}YS##W#fTI8WnyZ}g)rR+}Z2hXTBhii+x;`3l2meJ!!9QcFH! zGfi-}8cB>1*K6zGzqr;BTckQg(kgn%ZFYxF;mE9r^rdy_A(Ng5$Jy^BtD0LLY36W} z_!tpkx#RT3Tn{m2$({5?SzQ05_l`c25)atiuehKDBCR6n<2#V8cu)e7Vmpc2ct5%l zYwJ$`a4L+3wXcThJQkEj9lA#_6=@+*!~IbZoi*&$ZvvwzAx;}xtyiYiDLQ*I3IwW< zm9o)O`?TLvC%w!t z1H89KFiSpvP+-WgXMBZSEIO;Mgvy4zW-qu7Tq-?v+R8ix5+XfQ-~ZL>TjVM5dSLnH zkn~);_sE+#i?82arz@336EHHQi0$szN0EGF6bEjX!uIJ}T1mzJk}KxRgZM;oWbRB2 z2RP%I?`HLi&^U7nbDZ9J(rIeFmDL5mD+FwMvlTe$!oq|74AH#^6jo9Nj9JNn&~_!) z?%tm_KNaBys0X%*%<0;OHin;2|4>s?p7cz7&8TcYNBmGjnkCcA4M2$5;|GH9Xr&b4 zf9i}=Y9}Gf%E5rKFaUs5{Y@YpU!U5$@ReJc<^Ato$^U<2T7J_J<$tG4)y?Bk$efVs ziooCTZ%6j^o;#2+D;s!cX$#9r4&5$ua2r>lxC-j4X=^7Z6Qwi(NuoX=3(OzZ6Y z$tNczYPxrI8bq6cbyD;^2W$Oe>g0}#m%IH|tUsXk%WYplNy5bi<}@h>qnH4qdlAGU zo4LIdSootS8XmALd>WTv&G` zzME%O?;~2<)$)ls?z-M1h(8He+vV8M(B{(sFg|B33_9UNlp_QX;5lA#pC8o$mw<^= zx<;f|^hfJVBP?%$JF~%c03GIiw9@m*a2W8_OrOnw_;4x)2?u;HNvgI_UdpL4_ySk` zJdf3PtOc|`kJba8>Gs!0g)BFLnFH2>si(Wn*jA&VPR=RT$v4uE9QMME`Eo(IpQWcW zc`XE(n0DZ)=H8F}5_R6*)7B*ny@QzoSSzhh&m#W9pZa@ygGxZ#h&<2VFX)jVUD->j zbwC4`@>;oRag?p!7oB4b;*A+KM#J9mi54JwPT_nW4Xdb!_%v&H z(BMT5Fc6q>zdDG)jWZK~4|8mc?1^yNFgx1W2~623G40hOn3RP=O`UraSc)}RehQ@$ z!b1CiZMIs4L76EBkt*1Z&ICMrR>PWOL>9-4^}^C4Z4WVskqVX4VEAGT?yq;fL=Qh8 zkASp){hbwYPCSvxwRYbt6TJw&2C#BqhCYV)DrH3M&bTCU$mW5!>fW1I)dG;X1S}eh=a<`AdG*TV(Hc}VuREa4{Vy?|aIYnh%^%-COP*6}P zfgN58(QnQ;ep0Zg!%CX90I30;h=}MLkN0~> zqXDkf7dyS0t{>bo1ioIJ4d4rk3nwYhh>P^kI(E%(AC4?7r0Y1Zw7CkqFIG7^IOI3( zO`XrDulJH0T1tl$LLfx-zPILfiOdC)@d62d&u$&OA|jr?0^*<3nu-duwg1^^V*c+< zaypp+WzXYnv-FL%1#ckU$GWtQRDGsY6_@8^n;@pVaUn@j#O*BucP8%(+gIv7?UI=_ z`x}!cHgTp*`L;tBo;BY*Uyf&avF44J%FuJNF1Tg*RNyGg%+G2`W&n~TU=zrI>U9*9 zH(H_I&tR&i;A5J#mT}MdX(W13OhuD^C&aX4mqEt0z{xa zLxlhln+l;s=d*SSbb&4$8vn;~9wQy6pry1A^?_Ql0p~9E3>h%uMb5a;_R@11f|$nOP+k@ujxX*};KC0D?NhCL}GFJ|q#9 zM8l>thE~sz5eMZgnIS?DYV=Q8c>UgsII%bS3M>XcP74Z)_YGk?V}514>Di)72*kPi z%WS8(&4Vy|chnJEbRYA{(86$-K5SPvhvv`lGM0e`-_`#xb{Sb;0Q7HdNyC8(Lw1Rv zI|_M+FN1R#733M()=I2Q7ofduzxUa^qNKc(|~-^+-tw( zR@QVRguP6*)r#lWW@2YP*wk$_rX5{RBS!dE+~vEhQ09Uo<|fJ@?pY4Vk+JBIWJW4^s0ft2NXwX zijhQ(vA%wQLet(CdzKR*%jJfW!9Q2SlU74@z@L&M^XvAdf4_>cZqlcltG`y}-JbtCS}&0g57T$Foxpo@)|BQI8E~#GLhs*j z+ry5zkup)k##9?!9${hKvMo?jOJ_M&Q`c~o@VljWdweV+#+F9IX&^Gc*l4$6@Q!|2 zlLk9CPw1%aBzSg3MVdcmUVW?CIAK}Ivdu3!RGW87f-3`Sy7QJxF8Gr7j^Bz6PoWO7 zhR*9<|NM9(B$uOZ5K#hW$hc51cfUQG4ueXabbbt2yJ0Aua|}Pdd6XGySBGJo`KBeG z;K4A7Pe&)D|3xWEpD#%BosuV#|e|1U+8(J`q-vY7B>Nm(s(_ooOSk zSDq#&t_aLuT1II52w1Gl^;NVMI=|aSadjLG&YYSOo4VE|vQO11A-Js&NsYXV4PLCV z0-z_A%MCjkp>mVAgCxVB3gk7Eo293Bc})aO_ATO#%Z1lIF)0kL1>F4Xyn)h zl(39hB2ZTPE$h?MSgn9G@x@Bd1By^KV}XI%hQQ#wXzR@C_t<7qfXkEwbS{ug|jSrOxW&D~Y;6Wv?XD z8AaX{z|DDyUowK5wcygaw&4lxtzJ82)Skb4`U5YxXnQ#b<;+gsvHtgTrv3jUGt&pax2LRTJ@|`-zB6+8f#4(Bf0*O8G#puThg~P|Dasn zS0nlW4M=|d6}<*m1LY^1CzGD>)UB}44Y`Qq?>I6={!;do0rW|%G zT3d&iLfv0c-QR;|=#C3$oA}N8ZwEmNn7_bJQNV`^L^$gXxtp$gIe8jNopEj26^coJ zf6KoCcRM&b`dnR~X+Nx6Dig_1^WsIAW#g9lyQ8+qrS-M(Jg-ijdV`YYF0>d1F-D*Z zph?aTw2Q*?#ynCj7x$K)7QE6uj{uL!zak;wz~n^ydIELA&)O_TQ;-Kw~2eY4RN;1J$nFZwl$G{X8 zy}PLL(8PrI_14^$)w07o5(43LDle}&I5pZ=N#rPcb$OJi`xi;isSWr6Q88#69f1 zKY!X>lSTwdKknPpEQh3-*o1ua&`v&$xS=$lEJ7MkQX9LveJQW(%D7wQ$&6=yIbG-T zm&#y8WFRc6?TZFQI`oyKvcdM-G^cmC`mDcuzuT{c|KPpiId*)Cw8y9ru${R3>yB*J zec&qRPrPX74~6jf!lL_$m}9mJ@TGgVPJ=#(Qn&j275xSZy%Qze%G)io0NGlY^( zT2(K5w=B=o&cW`#&z<6Eo$h2V#B&4!M11)>>Sl}J3iqn<-`BVEOY^=93rpV@x)PBZ zufnWe@J<4?@?&^?b;izkuvyPL(L>{!vg+bg(s5&O;JO8Hd&^W^|I0@gyiM5R(fuKF zQ4GP3prku0HOgkkz%?Yk+!k^*|6x9|v|G$}_bb zD63?av|>Nj*B!13Bb8|IXZCXTEK(0Yvc`*c=c6Z2&HtyH&`NV3NQh$qdXEN~UeCYdK z2dp>77Kl*V-^^$;@ZkXubcdMb_PcckCy$JZ@MoFU>BkQO)Og6 zIw*(Ls(@zYzeLwN!@Ozm(%aUHn&G0~lU?Pvf3hAUb0Ca#VOR3f{6iJQ>|i20oR@gV z0M^{g?x4XsnNF^Er}!fYmT;9-cfKXxaADL-@GOiB3nzDxo=%Dxobr z-_P`!zMf;C51>v3*auxO#_}lL{v|(U~XYC-5#l_MFup>JedRpePd8GkQ}_2 zC0w>7ggj6*jdq6h*@O|ve6S1LTaD)fM{9Ns9XHdW$P55fL zQ3U}SX(qqTSPk_%@W1Az^VLc(A|_5_t|JM*>;Rc79i0Lh#h~tI^@`)LQ^htGTrG7> zEGFCd0j}~-MH|UKJlRe1cD5@@EyISy!cXk!w=!C<&zpPhEqu6G;D2?|r>cL{Zd!fn z%JL=WyEusWo3{pDI$j>}KJPa(7#mjKH(MOvIt}@-tk!+G9ZcJ=aPg|ljF|MmE` ziB;2mB55v}DIlu9i4U~nTwG2!H(s9ZWsqAlaZIx-)@EwyYI|Suw(40}#OXK&p2sW! zsDdSo&G#A<@BJ{G_1~vZIpdgDY$qr`OJ!{tMQ6`YhxkP&H{(SQzX3iD*7Qk2YDGO<%A;=+D_buEk*d=^ zM^|Y1b1ntw30qECs3$TnD3(?R6KKM0Z>OCnN=yTkLVg~Vke8a0`5%uBj3(-3e<_v_zT=@p;Fcy|@FXV!Ji`pE$6QJs*j>5tfr0ojR;3t*OWn4>;ZF-C(XV z>q-4gWRRVs$glQUqj65na6^&)K_FaGTcXP6r>F@)_%^sc{yC|)&M;&LiK7e3ZdXW6 zeU!C4GVSog1U{6x4Uk7|;pCNz)w_fBThP66404}`<>zdwD)kBsFa-_#ICPfcq(1dT zRA*Yc-1c^}8N&B=)2@;EDR1vR_FF(Y_iTnFDj@Ex~D_y`*$|<0VJ#e7m16S<`;b>DBls&4r~3x(+wZTXTwHDX zPsFc%t~UkI`3koTdoJ@V=_rZ~_`splvK<{#LAS+mrtP-aPdgvicef!joi{Q!=^A^K z)Rd0@?p}X>bGycvIlm|<0#X>__`qQ25?W|kmU%373hTC)Sik*cnBVOkyTct!NkO&Q zkCgTCpFHX~N8jzw7T%kl`Ob13-hV?X3!HIG7;VE~BU_3hM-q7L^%i^)n;z2}p-tC}Qcv_aV#DrY$r~X!A6Qv#Ip5J2Y9r#9Rev#^hN%B&)0}P0Zw75-b54PG9{{k#Kb@2AJz2KhF-w}9-?4`+ zzH`ZkV1tV&dg*~e885=u*z?;BgHyJsK%20dN@Ib^)^r1+x~@E>y8(4@a!RJ}dSI*Y z$n=x^WJHG-r&t1i=C03`zAZhR3`&p)Ibo_?sxC3FnVnsom{>!dQnmySWdM-~a(kv+ zs>>$77NBL`Yc9{W1#UkTio-i`wzGqJl#y|wPGO-^v5NAgsc$!`E97Yo1?7MI-px>; zQSbTF?Q0Arv}qoOc3_$GpGQ$*aSBXGfDtXT&W zuRl&*5}?9f=Yp`>&ts{PmD3T)bE-G9(98DI?w1tZfjOe?nYOzKP~$0@TjTS$NkOx- z&VGIg1d8yZed+=`{c-?*V&o%+r(*;8_F78_Rmd>m`WPvtG zL_{2jg%%5$C8qhk3#fD5LI-FOk;0CM;rmp{N#;+#renIt0gPPgh3MQI0E_YmiZ>xp zkGH({__Pc-Se>Vk;h@bf`t72}!@1C#QLof#=(!)+fpot1*b^|A!$gz!NJj+Q5U9Lf ztombnnaO*Fi}%47bofjTVxE!fXWr;AN|fji<&N#w!gNNf=1n5`sO)ypJTXa0iBUIPc?$s-?bVY9McGJNe zjKm>B^^i8^mAW^qT$}=o?_y^VRaW01&>|pn$OWNnQUBI9OLw4^d0qkF5ntD=bz~eM zCD;%u6tpxj=TV{EJ#hm&O4^-qpUz*0tW=84MsaEPcJd^&eb89uu+`5_;^u{>H82RpN8! zbD1Q6bavV#Tu~@DX;V2cCmVx-EmyZgv^abF)*et_UIP(naTT_L+sZ^-Fh(GZHUvLB-ctKTR9F_~S74M42!0Tk(xEmR(Swk|%I$mw zO?*bJhU(|}nhwDht)BKycDaSDU2DkRpKJG1ai(2PwD_`T1iX{gcJJJT{$8K7wn|oX zzUDUJ1yb}6>$yYEfp`NM(zSS#!<>@DdEM4()KDP`(;L))MAX?IWXe@ldL2+xQ(3#m zTqXHWOiaAVM|D2yA_2e)gXoJ@=4gBh#iP5IJXVW}HEiRf%;lqBXgK-PvvXd2o9X9C zk#wz3j(JWd{Sv_{gvEN^#1zlvK+<{Ib;@pHsLEFa(54;pB_a}j71CAtE9s*ydT&gi zvF#;T2JAFXWZ)D%ZLaI*(mDQ2APqf>qTf{I?;0EDm(es)m4P+l{KW?!7PM{#QR2~q zKE$(bHTpWZ8SEQGnhQeS8A4>%Rr~_P?42rcv`FijI8E~N3+xVNJ%h8ZX7mh)MVC(O zb`o|vk$07WuAk=ibiU{7ZoEvtZJ4;4pz!zChCKj=4I=$27T{kumU&p0DSzj7gIPq( z?_zlXAG~=hp)y>47WxTUPsx|0bC!xP-G{q$YPaxa)8rZqy+((y^mRS zS*W~h7F)rnfT*Z$h2?V+9m%h7F0f1d+cflDcVLaA>2m5~?-5F4G`o46UusZY0#j0t zxe8N~RDOfIWA~n)#XQ)BH;0>yz&b631+L-QU2h5?%s>UE2Qef7+|*86%}5kgA9@x4 zn-R{CK1zW8+*yaF+>{5rR}dg1BQ`Ly5Bd-GY1)$vEV;ao=56!Y>l9Mb(%@Y(B1>X| zQW8=8b4Ce_aRdUZ9Gn1u5rum3t=(`<9`eGZyKkn~ zG5pb<9v)!E|Fi+Xv>W&M-;2EA3D@}Cgpg2FH6bs$yXs-fq@1!kdU=qt$dvdj%_5u; ztu+SNgz%*3@A<x(d+>ag0c#;9mw>*dO~dv<@M>yDurngrCQ|&b|@Jr zLLjN;&!~9ORH)En$Fd3!Nw6%6NC4= zIb)1Q=o`M3*$p+8*fB<>SyxxfXvm9xjhI!-1UK6RtJb5E?qUei4ua^Q0*)|wVsCAS zlM9&AflR#wf`Gv&_!d6CN>x`aD5D$GMdAS9}rS7 z?et?CTk;EUbsW9mH*@{Le|=M}0O|qRFeczCxK$BvHw5X>N@?rr;vW}SnGzQ_eYz4B z5nlk`4FVwtr}JhOF+z@*47>^!^FRzn#s(KvqMkp`b_f9U6=Q}^j_%`0dHf~;ggJeD zW_AtHY+^H>VPZ4+`bQ0{Ol zVIE*UT5eD8Ekpj3yG0ooaCY?^*{WiVN3k>1Ssg4G!1!2)&i>XQ?|2iIsEZ9V2268_ z>U0?FU_`x#t9ZfBW1M6hVHpWkQLgmro0)EwDkA~#W+R|mgI(_fpL-!8-06mMO8P#x zQ1kC=rY{v{m*ig23~{7Fam}4Ex46oPKEqWt+&xH`3*H2~Q5BOSR{`>)FRFY@$7)AR zra#1&1uc%{LS_ebOoN1OHWI=->sl1bH*RU0Yc$4uKKqR&ZDHuYUkJbJCd|_J=WFSw z*~*EjX`iz*LdkDgbsm4Yrfk|?A=1|Zcf@4R3WwWwlBJfzT;${l?3)-caGj^DoxDBr zYs3GZdUHjICfGH;um31h4DX*;}YNp7CyZ128=0cIGod}*!!+twvM{^+)FhuU_$3it50BS zmF63AH|UD8S4x(KfRYV@(`wiXtT=MC_{bE9OS_a}ouBQ97~D_jkbkM3+>AH<=7y`F zRAtqZf%~K7a$C6eY;8{NL!FXsI29u+*A8=&f@_kI5HeS?_X~_c^c{$t@jWQHo@~); z`IW90xk7Nhlz&1~!YHg!M6{J?h_G3-+3y_>;fm2%#PvaW%iTd}MQiy@_M+s2Sx*tU z*>?Hl|4ww9ycI^&BwG;raB}yiUPkG4#|D2#{`G4=Hj^G8BN7%6_V(xONAhW2e(0Wz zEgFg@fsvm1%-YN#!0K2;^YiCt6nhPPAHU3Icaz4OUTP>8SyYw>k2k1T50uu!WAIFe zsp-XzcZ-6e*mw&sbeYVWxDUG;GM5LT-tU%}#4|gmRxA&% z{{nld=nm6H$B+5cs~Jp82IH#FP#??IgK|GN?VHddWF@tFOB<*$msV@<<3r}0uHwON z*N_ABS}D=v&@qAjrFx<_%+U4Eq1%7j9F*~_zcb$#luuuwE5_vBdxE2H$;&EdX zBHMj{p3Y}Bn-@%+(}zb#FuiQnIr}eYQFI`I;pu ziLW?;Gd1tel|IJg0_lOjQZ-Iap0Vxy(ttS0b~0gy=hUtITXPb-?3Hb&Wg-3JzA_s- zBBvlvg)?#yB3E`g>zJt3U1O_PQZGCF0$-*#Wc?C#s9*ZU3v!9TeN^%FK<>)Ls@?r! zVyGr7ECqwcT(Sz%wwa)9+4D~lxEmxJ%kJqGsO&XJ-}Xvn^G*nh%zTP=pf2gn!Qkdq zL4Y>u`Zr+%l=TGn+XO5>2#bl+TcGNLqB;Vy-Vl3se8Sh<*cND?H1t?ok}cT=%KQ({ zLSwE&`K+a<0aa-_h?h+I*KGaMZ$j8q2~>wg7rki~<2XfOBeAy~qr$;JfRf)Y&;?E5 zw}K|zfT>F5)*A1?9Z1@|a(92Zep~JZK3KE;3I{uVRGtk_0I4zc8Cv_eZa5I}{LX)2 zi}|yEuV1}nhG3YHTCB=`0FmT(b9FI~AKp813tBquNUbk^9vqzceR(a`n66$>L`3W( zcGjKYurA$7VeRCn0Dr%NS#wpnL-H#inJZ%UzYzv1h4`=62KP-fCX$98pQ;HD{901n z_y75nwfsGe(L;m#)fX3oy|{L&e_Sr+bu|LpLF_NJe+8I6m+@&khmgnN)3Rn<9Gv`N z6Js>s@@c19thJsVjq(zvSHh?`_vUa0_dg?RBq;jYtf(1t3U{fUtamlzAJ3|V!7KA> zYCO$za|tjI?8BTBWVcfRJ(I_+>ndD;%&0Q&H0(6wRH3Ak10jaohnN@QO$|CEO zRMK6+)PZ7hb6FZdQKU7krO!bYU!csX>~8gim)Ai^HhpVuuwEOlR{dDQnB|Fd zFYRE!{M+ZgdK&3K0stILN`l8I0(dhm)U*MEti8*b(DB>1O=2RARh3zf<5}(V5s{Ms zh3K#74_8-D+qx$qz+>$YbV`KP=nKp;dv$|uHJA!snSV@F%=Bxz7$iO|Yi!KZVw;>Q z5cj@5qC~&rZ`}JW*lCo!Q7_+ArDR!iSzKV}YiW7Z9 z(_J1PPQ%8?qQS;m(r*SM9=&9z)!>Ac6Y8XDa!c=wI2#=OxED(|6n;NQoX}Lngrx}k z0L|)er`TYr*H9p{BWKi~-*Mx}&;W7Ha1I@}{?xIsAT}i4YHDu%zVLJCf)of2@YlHw zQC+l4*9$_&m3@#@`SFA9wLK|xG!)$}_4O4!UDf~c7bPFfdP@I$Jr4cf!jsToN}a#i z#`TE`{#s(a=_o)*^f-bSUTDkcuEF`*#ntsk>)XTKNsFboM{7+^?bba_=~hc`oz*pS zLGdXSG|p4`ELoKRS?h&6&#Go>WwoQa7diVUdZq+iz7}lp2EKOvnC(~P(n1F!1(UhF z)Fuu7!%3)%8*l@T>Ms>I?$e+p=D-}u#{uVVM6pRkbP?X@uCK_urj2M8Jl>Z#$E7q_nY=cAkVfY^a1Jn? z;L<7a!!!{tS5jFCvZbag%1Udw?^N~ezsfR=S_of1xxB|W=5u|>N-)4cX(v7$Cm zhY_h|_!$PyZm55G>&dPoIET+K+`@V!7YOy;n|hDInek#Z*raZ+S$t$~7UY~_ zz;;1vtEccA8-n{HAIzbSBWm;7$pJq6EvLt9saTWel?X`UcDL;L{|rzyeGUZWy3H?uY8m!rPY; z2{BAVo6@*R&94##!D)WGoVj^28M5X>jjip-CSA+*E#ukLVaqGTw>Dm&(&q7caTm`TwvbPcr`( z91_#f5M}ni`|HeSk^6uKz23V@iM#Tc;dWmSr zTq?k*E$?nY-P~*jP2)KDzP6_2tSWVXL&ug#BoQ}r!5&8@mr-V#>lox*2;^!q{i$nN z41Y`w4s!7FR%b77=5JJs18hr@QRg`dTY#WbQe2;7*FJb|&rU&GG|2P?OOqz9v-t)z z$2ws0cwm83xE{BM35&T4ML(9-(i<9lZlK0jC^NZ29CuzNKQ4l&Sz*a$Xff?kKa%zf ze#K|?@zwYF*$-)S09&zN7fzrvvkbLA+-kA1=X`&*`xfZxC z;V73eD4>zWZL?-4Qp6w-kFX<7AKgFg_1uvu();^%yMEaj))0xMdv_dt%4S#?^N9-327V0*dC-FDJJ z?eg|udlL?R+$svgBaU<7huDdk;$$+!gM1zU!I_uC!0PMHi_K4ZTmzSK!MVcZQ=1{` zJyXetH9Lj(Cp&}Rg|i8AEpqq&SoL|>;#G*Qcw|CGIjzIbMFFsg6Mq(CBmOxrja#3oH3t-PE8bEpYBqtpwk`MLo{oNY3e50u?e^Bs1BDYvJQ!i(YH;E!{83RjW*!fqJlU+Vmd8e*7dXqz*iRD}Ds)>Z0Y( zuyc8n;%4f2^TSJ@V}k7^n5Gb_)Q7XDONYo{b9r0Enx#Q#%!QF-*KNu8<^QAVEyJSx z|L9Ley1To(!J)f`9*{=5yBkD?l4j@>VL-Y|1f)BpOF9HWx)JvN?*9IJ?LLBsTsPOJ z&ikC#iP9~mx6sw7*nsvrBoNSgLw?xjZ;o=b=$NhcRx~>~xcy;FpY+(eKm|B#z4-Nk zzZ_lL_x7!69bJ%4w#GOu>SZbQWunZHR$zkGAx5hmF@5M!nCZiIzNN$Wmm~py+iB=a ztoAObC9lh+XiXPKyC26lv~tK4+T6c z#9GO*!(sMoO_~Pf+saWybU)D2ufjg_^?r!=7`2EXb-(Mf1zgBx=H9`i<(La?j7AIc zs6+(XOoDi|omb5Hsu>=A>aCY^0z6*FyDC))v6VJ|+y1ypo)s1D+?8Vhc%4K?O85P3 zq`+?-Sy|Z!y#t|Y&Udp@Pa+Q0F|kXb6GCf#r(*sOk#F1FpE-@t7_kLM%#->I;tZBP zEz1{0NpG{s2zi?$EuaZfm!~m*!kk2drpA!Ec0LCJF_xYJiAPlDVIZnNN=w=XU67;Pf&AzUSnFx5j*>b>0vIz#Mc1#F@OWa-drhJgLa0R45w{Y zVus?Ke)i}ld^k}KW+r#O-LD5MWv1yaWI?X#iMe@rz@L-1DWY+_0OU#d({g>to7`4c zINXV;-Maw5wTOy}{S;Lgox&Z$tL?f%z>)Nqx;Me%(Bo8ho&Dp;Ha>YCQC6VxX(ZV| zHa-?twx~Ip7+v$A9$OXzS&49brlTYu$oeM@ZTzFI`Be|=O7UPWv(-V_V&CS-HpO(wRFCsHcI zWbXEu{V2?87Z){6z%N6NZZq`5IvZv;<#9D<`0?{7AUy2&g+9(+VU3@cgRAE8T!_E2dZAJVK&`$1Zo1@GW5rg%y zU(SN4mzl2$HR6JC^rP}VIW!r_zX8A(U*8NMOzGzKwqQY*L!kmAwGvPYwahl8+0$*U z?V+s57Mu=K#g&cu_4OWuib`ymszAvi05!98&erudSi)+{=W~$fF{qEh3b3cntgHZ8r7z9(=`9O-kZjISW);KS-0ZF1d)3`b zAwb%|r-*LEXW{H6QGVQbFsV{6F$8n0CB5YZTlSJxo2Gs!kKclovH+hCvW-IW4KSNGq#{Ak{=TfiPof5Mb^txS7a>SV?ekU3)is|D0PI zzt|g7DU$%M9bYFFfgTI)TZ3-v3UxZhI)MUQlQcq&>jbvxJ0eeoZaK^Q#s))a$OxHnb}S_tRvJ z2Kyd87!5kp9^M?a>ei96ZbPA5Mxp%3MxH~iV%LE2vyxZr?a;ky zX50B-E|Aj(m8+BqkZ#7Ay)aw#Ss9eqaU(PKI+n~Sm;GR4w}_OBp< zm~Cp|v6(99Ghp%G4EN&~G`4K(E>xlkOY@U>rk=#X_S%|rC=flr6rHQ@$i1XWmhiX*iIpXkgnG8RlFj#iP*FILlC05sY0cE@{5eHq|q!XQk?_vr#_`(jA%^CePXoKyVw!-uA5{+)B2$JW$mMO zNDsrdLz1(wDz1D}vmbzcNHDc0*JMzmcP$L>eK zF#Mv@`&HIU3Fr2gpH$`}3n?}A!SVeiU^4p1T4O2EBXKMKqxyDj==S~6*ha|xSe83G z8lLorGY<`ByzlfWZ^_>%XFCg38Mn=&aBvpX;_(lHB6f#bF`^y@6*F$Qi|fl%z|Et3 zU6*Q_6Z~csskI|NXXjObB5^wh9vOrGkp75tKn|HwBIMJzDABwGdlv_|Q7oQ8+6Avi zL%xTwhS6^Y{LJG#)zqdY<1=^0Q?x31(PX3WI`3QWr_|rz)zCaCXsVKb+ zR`y2UJ@%UKo)ku4a5_CG6Dk446LOGQxHMRw?a7&U8lK;iR(bM9)+`%7aH?lMtau%M zaE~Z640Pf7A6{p+fk4Vks0N*mOoIkMFYeO!qDANRz+d`l7o}kfr|bWp1MYcm$HXzz z@i^kL(drk7P8I&aa-c{YhrqZh_B0AC|+_(WraX#$7t4YkV z=y3$(aEW;3zvJ*%u`;O9gvb_15Y^CIokGi+ZGejtRw(DzJqkSdhOaw(8*Kg|zxV%Z zqfsa_QvG(Lm#f3q++<^o15;;BpR>>XsT*TUyDvgh;Fq*q^|_W!VM!Ea;q*M!NK$ zWjUWzNp5_`DEr=s)Nk|qf1bnK7} ztIRGXSoJA5=Vy`j1G3^$T_{)OVht0foJJuCfY0U}d5ODEom3ev$T_JJI4#sz`MO3O z6b8IL6r5q~t`$J2mhfE<=AdXXnJ^1EJYBxLp_sD{lzhKR&Y#k==|Oy{FBbV8(d+Irh1>cWh& z7AEvRWf==~tYBAFhrQy_iPW_EnO1#KKEW@Cc6>6*YHA)e(q3|J60Wi44j?h0L49gw z?DD}3*uf-3XZAzF=dPj*c&BPsR$h-`$EHZ^4`ryW3__N7H*2}a&5%MW|Gj?*4IO8f zC)7htj$28cJ0eD|NeIe}I91kOolpQ^FI!sApKrs`Y$_M(16GMlyiPQthA_s}H0aeo z%;dxYhJ+4J3RS(D-do77fJpEOPf4pvRU94$n!60V_fVj0sWFI0_8wY97eD4L+)6-v zP(B`i@!LuhF+u&8St>;RUzJ%0FlL_``JZ4JHzbnDrH&QWtMU^%W9e_5@kIqcumnPi zBI^)5buhif@Si5SHm6LQe%^`6`n7UQK%X5zS1{$_nE=3x&F$eTqi^U#=vY>We) zq(5k$&+W30yAgZc7xP;itq!;g9@cd*vCVo_dwTvw0~D#CB|yYJUiC`5?-gwJ@d*YN zhN8j5*|O9>&84~|j@H_PpF`9vaL9k13u#AiBEVYBlMH*UpC{wgW5TqXuJbRC zrl80u(W8E^UWsO}RO}Q;GCv?|hTR%le@CBDO^t-!0Ctp?k-`a)%r*Aaezhu{Z0j*x z3ZOoWRj)#2G({C3s%AYcs=)bKH~-*jU{?I%ub;6tKxWJjAGX*ac*67?DLzfk!Ad3FZ?v9WR^M` z*lnF^x*pgUYL|f?JUhHzdLT0EQQumpjtflx;y#!(~oqI);IP-$Vi~Ksq`| zM}KCkjDBh`&wfl!%?ZYq+T-$;VyqsrfcM_b5wavwZ=Jj~JMetro!tvan=wb497bx7 zHfX!{!9Y2euVH}p;YHv8SFRM2_jh=WjeXx=fS74l5Y2XN_uaeFA>{k3GAWf17lGRD z2WC4SlkLA^r@IwY`Z}ni-~ZGrkx~}!Nxd9&m)0y?48Li;3rxWYHKQCb-8kYE-#DdGdJY_veb&c3H z(==WHxyVY3ShEz>h2BBC_e;|kt!mn;zIM_>k&-i94d5K(5*%0-;WqnS)>xe#m&u*1 z{s;*5mYnmfukyXaQL{_bnA#0!DNzvz(b)$+(0)qMu%cvze9X}vDU1ULin zBjwAC?JBI$2-c?Y@kyNoQ%D92q8_v@Qc=Zl!OQP0e`(Jdi`A8nBrHun?{&4<-xcR3=u0IATrZ3DfH*>1`UY>QiLQRp3mG zFahg7j_nqU6KVV4@Bj9xE7H-Izlj5d>GWZbdu~7tN(ss&6tuTJqp8&;7shn1Yg@8QnM;q=Thaj?* zTvP3GoiEiN{TeIBQfW#ha^9` z$+z#h&#OSMA+#pYG;%A>g^x4z%ZaSH!}Vz;_3f{#3CpKX)!e5Sutzq$?om-gU41keD*&CJ44te;3J zsVz^}Lx9XvqqUbLgB3#>2cG(bI^h_RXkeyRR-v`4XUro_aI}+?nQ-CA+)FdA=g&8Q zw!iRyUSj@L0zQ`na^1hx(o)c^bs16RzyrJ@cVoLzEAq%wvuYX>9?#o0MyuowRc^E` zcnHJ$4bICAv2u?%?)z74Ev_5VH7!w&^8f`n*;xn?1fzti?(s_nK1AnZZq4($v^E52i#99q5yc~g-|{=U*BwG;_a`&E0fro8f>GS zRZ<$NV&+0Q5GY`qwB5M?LOJ~w)V~_7!6%HTRo-u4cNUBjsbuj@+Q&93k6*c**ir|{ z0OoI0C1VN0LRHDmXVK|jp!?Dfb#;*^MIMncHNZu-BSuC@rSP(Vovkcq8%`EVP0UOx zW(Y0NIag;37C-LO^K-%EqZGDJ2Wk7Nn3Wz5l>+ z5Hvig8(V{1(zJwuEYv-d)MG{&)>hho_!#M{BXoLg@}mrq%!UK3l*n9M%F!@>6|)O* z{sJW+*Z?HU)rPOd{5)^PsP`+)p0RnvUl=aP>g3hp)dkEjaaBr*!OWpBPz$Nm*O7Vm z<9?O*LH~%>Ukdyhtq&o-r&4Mg_i=&?^9`j*kR7#|#P=Ion$7rlitm76 z-+B{~6zNJ^Q-j%;`SH1CH$$;g3gH0Yqo4kW>0V_KTn<4+9Zwj{}S1<;nS#Qje zE*tT_GQ8nGl&-Zu;vPmx>om@GDpgwY$LAipqoa#CLBV2)1i=r@nAi!)qx%GAsZDAc zB=(NgeV0UDjhE((F_8;iufdEF6}q3BO_aO&QL_mN5Cnyq%$v-eEul7@60F8_706eG zH1L+LSXy5HL&6Ebg}#3PsPaNMQct)WcMGr*r%RKte;U{{k{asVeL&f#yq_P>B${|N zE(8~mF5;h@_-&_KyC-^|*LiF7=ea&E@Ry%= z_wAtnj-l(l8a8IU48mr4gicVETZq?WAsZjvX{T`a&yo9g z=Y5zpYd>V0CuyFZX*_4IJN&P>++^&Gva|9JG+*v^oZpM|-UTd= zxh}QmSLeRH*q-I#6A2}vvJVW(oL>K_VQ0s3LggYqNH3A(B%m|Sl}0M!k?|&41H!4t z>!G}fQm4#22`?ww+kdjs4DoA9bk^Id@`O(yYF&(E}Nm7sfECE~T zr>QDjy%_mw$ky4EbNO}lC*fYul%7F6QPh~?tf<(OLqVs-YKGxf&+UG`$vnvs6N_+) zo4;Gzk*Xsf;6l~en5V(3R%^kR)Y!*T{d<-Ar0+X`k!oi?1IrNWR34r@Y3{7BHj_^bdoRYq3@AclJjiw`ea8B3LR=gv9-~N&IM29mCM$8Ye zSs7PH6ns_r-I)u~9D23^+euTCP5pwqjd$8auJ8w+IrevxX5ZwCjAT$gt*^U!Z`Sj+ z{y4ruu$wF_YpjH|ir;dr@h z3zD$dq5?Z`)?|wYggs%#LCwT&_K2H0Z1#=wTH7+bu^LYM>zt$DX6o{#ovyCD^tn~f z>y<+V@JqAmphr_hllw{Mq;v!av z@4uXNUaN~;8kE0|i7k&E==1V?%y$-i#qtxJ5^q9$2HTopl#67l-$iBe;0K(Xa6aMJ zAh5JUHYWT7(TLU|n~JJ&hKXdP4`1ex5*me126oL}kfv0h>f=qy#hVhnIO_)m--1^W zucbL68_gLa>Z54$i{966VI+Ho#)JoJo#nSLSr54 zm%_fsD}5&AKgJ#tEvvWFLr@GGU8!!@eOMUEG;~cA_n6@OU1OtZ<)c0HSACUwUbhl{Fej%iAi)}Z zj!|f5?;vF`REdIpKIhjpxmfswP%HT<}p?30R12ch?Z-r#FMhfaE^9s*@c?^H+JN zg^Rmfnxf9mHzxACi6RsJIHqqK$B-AC zF>-%8n=yR)k+f>GI%s=v;6qAA!xHI}=-IAFNhXfeRVz~W^2$`=ZC#EaC4D5%oaFPR)h%8Wo1= zKiXo{HqXOvUl?;2+;%sgL*^=k>aY**&5_uZ`P#g(UQT8U%eXL-q;6ON2$;>(bqBys zDA>D*oPFBwez9qBUF{j;q1^6W3MeH;7r)t$Mr#0yihOfIc)G_w?TrCJPsZGdO%%4g zMzsm+Nze%pP>r^jv9cl!MI)B{LI8(kP084Hxmk^#w)bcn=AZd*S+67!bo6E7J(t}I=Z zO=yj@z7tC1eZZ$nCUGV_BZhpWjd06uRFEa> zO|1{A?BS8gtcS_c%=x9&jrqZ%Q=30takrS{ejkk0QOeG1Q{zqt3#%(~VwZgyW{!yV zA-2N=b5u3UTkz*09|D`G%rU0J)Xvp19{YUqua1`4_4&R?43g|FUnD21mcL7bfBv@R zCQvM#U-=dG8p?PS^wf1?A#te-KBq@G>qL z0Sp`fltbs48ZS0FF5|A=u1T9Sd6a`eru4J3QJES{8_D3ApUXYw2d|=WXiD_B@Ks`< z(*03gUEJ%p>$fwhr#o&h7c@(^Gnes+1=dfa?_8II7{)Sq_Rh*-gcUZ{n>;PLOsCq% zoZ5t5=c6FGe<9xcV#CNHUyLG`L~GRE%Q+-X9j#_c74HZ8qX^1)%;C`sIl*1&AV;8c zLA~9`=1-z&@E?@N-+%w^xIG`a0m(oy{};{fLIMUBGzz+9HIDE_4do2a36@VpE0^{T zZZb~kyzlbhdbQK*w*G%|sf)^5N#McaJjNOafuR$ZA9bV&WS8cWI&!=G|*P5~? ze&NzCeu_!>L;V56D(&LDnZy^T=HCBh`pioyiE6b-Tne77t18sX+G|ng?;o0DSNQn4 zb&eO=aN9bZU@>hBYWgX{w{#=T~345HthvZdPmw7DZQ_Wh_%9+RJy`QHqR<{?JQ zp{Z}OLF;$Zwp&(Rfh3&`CN>s72sFI8iN9iGlvP-0XJJ9S!$~rk&;04&9-j1s&!Nw$ zwDLjfp|N`~mR#yzm!HSeI8u~;E&Z?!sfc9nfENoY1zwWG1FF}hkK$y$jrA^Xb+w4+ zz4&5{I$)I!1~^{>L*=>XT|9T$IR9wAAJ(^ep7o0Wv4%IogYxL%(J@SnXRD_J{x`eqih8C=Kh7H`Xd!5v$MvV*#_ z)i^zm3|j=@N5E_SKKLA|AmsYp%Bqq7spj|Ga3;BNPC~Te676z41(nAPMIh`-JfJv@?8YiD<5+5aVMUMdcC7~+Fo@Gw zSvphhKzj`Pre{KZkC%Eb-f=7k%~H)BsPww8bO8PU{vWQ)yVKRt|=g-!3 zfd__7wWN&rARyxTZn z>u+W&u!;{yDFIBr1r-``3Ba}94px1EQAwyu&H~jr1!7*7W%!8Nof;D8F!#1sMf7=* zy}gvVZ(SA8;xeea4jR1&zzv22;Stf=qe`Ds#g!Yt_RS3^C_`LWBo2_v7T3d^C=r3^OFMR zyN^?0&u9e?lYYa9WTHTK-msG7=-`Cd-IWvo-R`=>N<)RcS*JId+R}P0Z;|z3r9`7b zFS38@OnhXNNN&w*QC*pWeurGF^|Z9OI{)#sJ2T(d@4vrMVX-nHuBKabik%h zoVrh6|J&FTzl1q)8*1rh32oA4pJx>3fmK*pz-&30V07Ba@&t9Yz!8j#&qm4{&B zsE4|12{Q3#E+1E5OaNn-;5S)c?owBfg}i$8;gyQKjP9if{T^!?NmkDH!MT3Mq|SQ} zAfn;^d)k9|l&Q+2e}T~iFI^E7-S_#7R`|}S&hAm;A?UF@gX2T7p9%}cB@({_jSUtv z`gz(Q+t5`nXCq8!Eo4kRD{5zD2~hy%HCMp|2sVR>TpeT`f<5C`;sAb`vU!-cxle&E z=yn~fdHQN9_{GpfSG`4ah7PKJ0U^bu(_?nAa*B#ZLr`H)x46y`iZ=sA_sqmtlCNlg z6IRkiRe|&0wZDQ&2jztC{Tproik+>T+gz#Kf)+cnv$!q~!tV9QO+}~v)po#6#9BR% zm-sA61Oj~WBAqbSy#Aax8#E?jluc=u6P`bnXitLh1HaeJRSGfNmL8g|Xtpq^a&I7L zB;V+meD^O1Zb8~|BCdG1zi*31fj6dy?X{Dz*ckH1HYz%!&SjNYui8jP)k*9+aQNzq z5w=+KC9R~6cSt?R@3UzO{ArIzq+8Z4<=(M~=3?c3!xj&)*<0^0} zx}lA#hQDI#^sKQNaSMEZgg9}cr1PRUM=71-SWzB!(g3bdfz}uiY?$vTvb*Z0fZLso z-6qC-LdDW2yVe#KeCvcZa@yT*)_f9{?&cNWtXV2kstBjs7U}LC^@9L&xdK=zUS{M& zQP1mSEFf5$poiu>VTb{ti|iGRqdSLDw731k^{n3(l3hY>T@S{fx&O`MvHP13awu59 zV$kX;0h^uOUA+LVx{Zz}Mu9;c0oU{YzWz9f)W5x)=Lt*y+aioEu#+b#1ui!@*saI= z8?@;Q;mQv_A2VYq#MT0zUyK3$wWpg{Zov|E-0wGM?sW*qY`_BuqSIGghr5|TNt45= zVb9R>?^^%8WfnAVs&Z%ip=M$ZnCN>eD!_)wv8CpT>#5>vbMj!}y4+RZeuJPI6f|Pn z@l|iM>BbvC`I7!NlQnyJ_4qz8HcgLGEHus7wIiW3$aVLg1jn)$8NwV797x)|$^ONZ z@)>6L>1Gz@%buaP-Otp~iBvtA)2k_RN7kfY-#JMMg2Q`6!wEbrsb;aQftt%$oH!8- z7D`APG@1LyVTl78n+G~B@dY>A1Otx^k2AFqCaMGn;=J)qU|FQA`JoovxtF*d?$ z0jM0;?==c2x7Og7X<(wN`ry5h+RuVe=3cbv(IFk`QM9IHkX6b`o$EhG;FE=tTMUm7 z4E+QXDB+!Ox%69PIWKM_k95$cc#N-&0|N|zUHZ;pj$*DDSpY*Pcr!#w&dp5fK#AuZ zUK^6ITrNULo;M^Gb`$~>hG%p?KZcomUSUE+q2QbfPCjkQt_6j&zMIPGMHicYNAvNf zpg8$D>jD1lI_3I>&ql7ib>3_P=OSwLid|(`M0cpK3u+IK{tTsGuHAoIZSy}wr+H~i znr##AsgYQ$_x%T?%fursQzGvXJQ#LI`w@pU6Fh${xB$!6%2K3KS6eg_QE!(%83G0f zgI+PaO!efm1jD2>PvbOVQONc zp6w?E`^iWT%^5aWJPfmaT{%1;O?e+L`uA58Byc^fzc}VSOg__tI8^z@?X@>~xH!C56Ry z^7He1LP@(RY9RmMqjFu&Z$jblzP?s#&BoRF__su`VQasQ)|KD1Po=M&bI9?eMx6mvyY@AzA;Vi253g?iIkGVNAperXU`~E zIh+E4e+B788c(+VW!S^@+con; z29MoKQStA##4}8=J^dedVGB=aeNR>lPz-X>TpOBRb3^GCxcPno8#6_<8R7u#*VC$v zmWB>6o@lcN#6s9hZ0b$XagmD{suExmNN70pMNmdnLU-i@CM?@Q^L&#vOSTex5C@4N z9y-AHu@~1&o{`M<&S}HrT=9E3h7~U_vyU1tgU>-5HlePu3PDGw)FZ_Gx}^J2G9)pYt7>}B=|2)cmKxoFT0ouq_2vch7BKi zozFVUx_WY{LkL+or#kNtven4TQ^7~Qy+W=_4QZ{NCjbW^2xz+usC@g`pkfI5w9=GH zLKBT{o94Q>1rS2v|2r06xEP_R%~y$E=0D#ESg)c;=79I47)nh1PZn9>M<*xwwb(qy z!n{lC^@09hS80x%E!sLF^H=qMF0O!o3tm_39Hm!QnKV-#SO#zO-M-PQHtgHILd@h= z2Mo~(lnbJm$V}3pa2CX_g{8JcV!B0_wI7qef<$~S1c8b-`rN5{n=xPRc+--VukMc4 zX-+$t%U%COfha+}#zp&-luYvEN4~i~bifkb2Y{Fd&yRl(ZaPl4*MXnCdt}eQUmnDQ zYom0DBQ=h!B}U?=q=xoSi~$d55NRPh?{`Nen&c%N;v|nGJBVh7Olr zsx3=VYK|d8><$!;Cl-+|yyZmu+jYWysKti!&v5c6yZDABoGz8`jgv6J3Mtv!uNvyp z8DmB1mM0HfCgiyQw=lKwK=bluh?;5G4&?irb%y!OJ=wr1#h(9Aa44y87r^wfGWnm1 zZ43anmiRM);M;7HpYNk+r|rvG^+!>6w|yBb6c{I~pyylPOGrOt^>Z_kI7KNmEaS;; zV}dvgOd@EB`$l99N;IOfhRL-?TKYx9Q>kS(Q^xij`rmPzwU3WKaW1Q6h@F1NkUI0< zk0h}-VCCfeT+%z}i#MEwn4qmyo4YF{@>RbgKEd>hNmVg?kWLv%(&dCJO_iwPI;&=q znjQW?raA6@%KjneC61(1M)XvBO^Y&YVfhnt%qS$Sm(UvUS78rtXdgfE&%c@I<=9>TP@~RxE!=k;d7#j|d@;Y74(ktI3=I9+c~9?9^Xq)v{kat^y3`zs`aczgifg8f zTJtJyR|=veQY(BVbcMrNq>aNyvd`<0fCZoyLRR%kyn&e_ zL28H-MY$RZ5E8}y-cVSlXB+C9aW5PDRSz&`YrC!m2`J%E(p3u4JZBf~!!rx^f~LNY zcM+5=HH2n8o_1scyOk5?IPn=tIP2ita=i-@PWQP5Ktr5Cfhv&>a*n@an_SqQoa|y* zSzR?FlFg#I_WJ)VKNrT5DhDcYnv%Ot$q>x+v= z*Ely@Du8=IQ^eDridRBn@>MRx<^r z4|mFh_@_yoQXp1;qU!Ls?*n8Jfe^hs`%wLklK9r7U{o&Sqdxt6f5^?Yz z*m4kGMS>f&4YF{irR+tRltbqMD!pTU&|V{y<6{&UuVt~yZ3_v+QpJ~i(kq8r);jY? zmx!xN=F;WfE;TqXxCLHKh~FMJ0;f{mO^qv%iX175K&j`qfTJqsv}u7VW36JWBGOcZ z>X>>h*cK~Fyx0)(dks=_yQA z5nRvIyi1RMu)%W~ef_2AmVn@_Bkab*mW6whBSMRP8I>#>^K&hqxw0gV%DaZ1?3h0- zE*7(;30K!X=U1~+bq*8gli%;e?*outvnwm38^K2c{^;(w9a+!s3;jAz zPD&suSi-$5m{?w3L^UP_ML&7B8unDBeyyzd8lnCi4->q0Q~cjhVgoE2lY`sv>WRk< z1D<9xrFqiWQa_@YE|WJq7)5xXI#(>10xOvjDJ?B!%~0huZowpZiz}NtvAf*1C5lZ2 zQuZin@UKg^M}#<)oT2IthqSs`989h*HQfjDXLDu;Ck9Ju0{Q6jIZ$vgRJY|nYMxQ{ z5)||57B}+jc$Nq97K?mxD@~qt4DMBS_w3g_5UyWnceLWr^a)qCxXGxh*ax-99TM*C zZ{+#VkM}<0+NSFrqXr|zEr5)Mcw)mnghROHfbkh!3`a-9@dm8a*EOG8a zDW$GrSbMnxw;4G@zPd$x&mh7UA($gifYge20aCGG$Vz+fxyu)RryBId$ z#CEb2c3Y91LlwC=3Pn%I`dpnWz@S7%d0ZCc9&fTK(4Z+r1Pt|shO2^4N9`-Bb~5`fuENkik&KD^8yej05Wvi4W2mrWC3JJMZBIl zWmTIN`WLq38(QnJOG`<32WQ?+16v}s)QJvT8o+IX*LLRyHcPjg&{j-BY9^+?5{;lp z=IU|ToE*WueOkBJ)Y$cY4@Y=f>UV zPT#M3y-X-O)Qo}44s==0ET**y8qAoJd~3O&KW3k^dVui zb+Gj3o`YG2>Lozs(_lQ`_r`TUoPk?|NDV%sF*F^(ruKktF@cSL>$mu8pJ$*c3Qp?9 z+ICX~HoFapCmnz3Gsj?4*1t~<;c$4QXZ!ftleoZQDe3VcbLKg)E0#4jM(mA6-#<=; zW{l}`6J(=W5UsGM!4S&@L)jA+UV|TF6jrs_sc@t5>UmMk=jsAJOQ|{3;Fdqw{U+q*{9{o54{WTpkg-fFVv4}8mN!(%eWg}Z~9tewR32;zL& z|3;%2(J{sJi)JpxV}jYCyvlTVy<2QFYP~mF;4f*+g%kDGpQ9s3{_9N{J-!0Tap*M$ zT-t&M0!jy2%IDeB&=u0s{J~6ONUs;l2No)ksi+)Q#Abo5_vg=4mdr7HVaK_#cfGto zDb&ou%*V7(OZ}*9DrJm-wbmTy6?XDsa%?8Y4o}g>pCnNMi8%^_d;-&iD&O+zmtX#l z!135$69UFkk`d+On`|9-B3ddDS)L#Y<~KP2@Wf!*#F^LD!^w(sXGbSZ^|H#S{o@G$ z+`7Ukuy9x5=~8tDQ&E{VUHL#9fW&#u7XuD0m${!QOf`C_o@Cye4Cy6}t+4CLMX$eW zpy;H|(RwQ-)JmU{GJ@YWfE{wsxa5}=XC_Y~-*?Nb#b04k>EQG@5^nm})rb(*l2lZd zm`ID@3-W9=X-&Vk*=jjzs>pC6GM<6dN!N!!Q9upPf~#gWdb^`_{>pFiYff<)+X--( zIaF(~K@)$-#00#VgKPbaZUIjdcLn?XBeQDinqCJrE>HWlFZ`p6$6}$-$a3HT3|Pf0 z(*LWlYrVhGnK~Qb2~FUUJZDmzqA6>hXQ{NL?(##qUGw81%m2c}Of+9eq`merMg_&bh`YJ z)Pw9enpqJEEb8pb@jtZ*Ar>$es?x=b>>0HR~C`-V1=%%b>>23D>Ka zLpRR1aDtPKPrt(es`QVtm%pcI;z?S}YP@rHw4N$qUUvd7F$644%2?ybq=(Q(6msoTxJD_{5-;#+Cd!R`w!X~!~Lk`#D2tRKZ8PD6XUE%mYQ6tcsjo& z*>&GiITy!FtC(+yM$;KJxiclWLYN9I>`t~{rGB7?n;m3rGTf`e+@=mJCRYf{}?~U zlvS<*uy6Mnm~YLmqIngIj%tKX24(j}cnaugXYJlLlvDam&2T>E!P^j^*ItEr zXX*B6>`pXV7kQ8D?^;J}QIC3)?-ldg_JZhxM-XM#4J*;8^HNjxeC6U6iUV?V)YrxT z+ZS^1dxSt+B8XBuLjOBnjECG)%<(Fj77wiQFAYR3;* z!;1D;Xem4+V!(~@qe({FPic0UYF*34#Qdk@sV7bho!Kj{k;cGZKHk@yMMjl6tePqF zWl6s2X_z}t1 z`pfst^&moa24%Ll*ub`IYA#*)8+2WKK|hrr;vp&Q-xbAyMoNv9+ISVXCX<$gCN9$w5(yq1+i4= zE_rj3WnpGt=mKr}57d}1SuHJkSz<*TT5G>_cn(OaO>68?1DVN z2&PlHa0V~Y7St`RY~neT2AZppPEK5^jJ_2#GO%QGjhm}0v!8gZPQ3lUn0m{wDBCyc zSCJSxMY@LW?rw%25Gg@I8tDd+?rwyk1q7r!C59A`?(Xi8+V^w3|99{GnGYNcbKlo> zu5+#5;%W2dV{2yRsh#vRl5E#0pqOdq^?n_{$EN7tnv7G{$5ss4Xc{n@Y#noM;^#Z{m-r+Gg(l}~ z?rV7@sgb>H7Fjq>Gl_%e=J%%OP?0L>bsvfhmDu(5_paAhTwm=o4ShuJQ(3n|Xy7_r z+=T^w7c-5by>K=I9DQ&K4f4=*y6qV?=6dtuM~v%xg;m` z|9{jF4HvPvOj5>f%2!Gbc0bZ?*3uOY(GpUuOM;Ra&YoCNZjLSY$Ds?tHHvwP#oWMi zt){Hz0?5xX13l^Siw+BYYikgIkGoG5a_Xg&?J%TZ8`lu40}PIOx{MPusS0RuV}3Vf zqEAP+TuyI;z_CD(B%VTEG1x_MeKSiI4ZGEIuU9bZ6*VpD9IbRzukcnGZ+8Uk*H5O= z_@I3gQiN^atSKti7=3blk)b{$qnCdIXR)_!X{Viz!8R46nbV{t1j?TJpR&y#m*f_F z{*`Ef718zeTNqghh{gPIlXL6szoCC9_SzrUMC)VbZ*X<5KP&6Ju-!6PxF73$GM=yX z4&jcuy|x)-N?@S% zJztko;Dapc@3OEsTzTBmI)(T|*ScG%eo0V(T?d=BLJgM*k!BoNe^Ho`FcL5lU-BL= z9|P3~)QZT+m=V(>1C;s$$%G(k)WR;bu(wn+Qn_L(=1%NzdBVcDc(fozgkvb(jVPXe zTRkc|BB@#S+Q>eSE_FtBMzIDfKA*H&wz$md8dXe*H2s;i?P;O@FDSdn&O0>TZe(Hx z-SjMm?IJ7Vi4YB%`C!*=;v>VM=Qj_fa_>{wNH=!AJN%%_F}uGg0x;OI&{CCpeJ~cO zAU>CqeW1umOAMdw4De?--cP(Qq`enbb#_`ahtm04AJGhlhNfqwn`})n9mF7Cdk1+F zIGL)6;VOT~Nq5v!GvXBRE&1j7l^vw!wYJ!lE?AqG|WXa{0$v z80g$~wtzZ6Ioty0w?p9@@$%r#(wT=F8XY4_1@^XWcMk*|h`e4xTUJQ;VYN zQQqy6^<MylBL=^%wUmnY0SCTuhE3|I7F)E z`1^(^Qo=D2FUB(6w)JIB|M`#J99y%0q}UBfgISnfFkdq^XQ%S#xhbPKS5sWq2TsxQ zABR`SDF@(u;j(K8%{2z91#cx`dy!!1$uf|F5D*f+1_}(t6=a)ha(@j_NJ~Z#b zTCJ@eERQyXf@7-qsbkTLG!|q8Ijet<0cCM_n{DUS9`Q=Mcb9Sgc-y?k$9fB`!s$82 ziZyS#*ANwXQT5dG5Z4IwX-R3z5iFf%=%hYTYeMtt6*}sJ%1?Rbmb<^N{v*=2QiD;f zk3Y)*iIVkU<3|Mk$k%V!d(pmgDvb*shHnztnchQblW$l){8}q7s4aMF%j#raI(;~` zi9Bx?%K2q{W&%>7iBbTvbvvkMPKZJ+5H8cfyae{|jEfESyIT?X!J5gOs=>-#>H7J> zYRFJqE`H*z0~u^2;I z0Bk zo?C#>fx4=0;^bP_SYyA)4zE;oao$2qh;Z!wyVw|5MkJ)^pxdo8=RdW9-N7X@V3P(YXvR`1goDP|-n)PWaBSnY5;AK{Y;`(n@` zIjP{`r8z-gv*?YawdurX@}Afr!p#1DMSz_K#P>o?VyI(Duj(4lcKTOG4k>-(?fCom z`l3+d)fdfq^2xe&lPm8$UQWPEt`FIdgT`XNlX4!&mYb0!?gMgYlOU5N?*|HbfPy-) z_G8z&oxi2uCK<*w%BB)vRCc;p*=-|xu9*7_ljFaZeeQ~k?>(ZkI=W6DZ~V8b1v)cG z9hy_dM9~|;g!VIbTj+>Oq$&wV}PS=R}5EAG-R-}~qrVaWgKDbr+O(I=f{ghxU``3R$1 z_kcfNzk=$mc@S@@3R)>5)W^!0r^yaAY1cx?XPwOD(!~lhLp!uM=WBq2#P!F6dg0Mt z*8S7Xbp?v;xdun!!@{LXp0|LTG zL2&o&o9OEFIYBl#C*Tg6({>Iw_{x?u{L$c18klDO|A&iV2Q>X(ZoTG;9+){qX~H_j zkqdZsD~x-jK81kM%xGBC;BY3wcXL%vVzGTQv}0zMJE|knKz|L zWI+?MPTjR#->Ps$JnXi2{cm;$8a-V8ZM^-`dQ3QAA>`y6T!%yT7A=A=_Ti)@2!+x! zUH$ow#Cbc1U&J=cW!q`-s+_U`Y}!_UQ-~`ho={!sXFVF*M`cDG)5s*3!W3}1fS^Zd z?|Q8k(c4Xw*FjIpcjIG^lw@-r=?oobw~tc~UlYlFZU9f$)#}_!Hs$y%+nmpnyt}>L z&`^=gm751prCgRJj3A!xwBK%i*iD(RTy-{Hi+?fTXX(< zR0=?GhG7}?1}*EaU@4Q|eV;Ig1`vNRB0^|MUxz6%dmNi~SXHzA5kys^)+BmIN8rlh z$c}*5?JJx@zl{_XFCCB+=*u6KgvCU%RA){{$V_BfRQPdXzT+4vzDtX8+FQ! z)u6{3l2GyxZYwAc1BNn`luIWlMW7$KExbD#&E;S5t(X^L?HD^ALa!LLe>`jd!T~hZ zyd-H0iz&F=SskpF{O?M($!rq6&%vSM-vz&p#`%;FQopbBs1un44cE75;zH5T0SobL zt`YhmGBLYRldL(74rb*KBV$P=srVtzHg|F$qP@O$8D=#YIwdV*Yw$t3hd87 z^6n(9b0lI@A%o>z(xRqictxKnp27RT&$=q<{YuEPbnY~z7!cHQPDZAL(L_Xwt|4U7 z*~;w#iCbkWiD3o*{dZmmhpVRZ7e#dqH#Mh4Plc`%1VwmXD1%r+OQ!g8{%tYLdoNQ_ zKA)igK*u-Dz9>u*xwXY{`x#7iAkaib^haWb)djfSI?3kjuk(on7sGVju1}f^GAP!B z7E!(rBCDTGH@G|R{ht+D(lE{x{I8hQC|AY~Pge)sL_+sZm8yLmk@7WnH*P!Op*Q?$ zaj=~S4)T1X3UIyTaG?@}b;SamY*c6m9bJ3qb8@)nt-&h%JB2^#N9EAFt<|rY@#$T& zjBM6ZEL3={87@j|OQ@GUEhfNjRS#i|A#Sdh;-RXGhV zAcOs8^$14(49C3INM?wwDkTRs-Ofroi*#l&$7iOCQU1INI33g^o&?HOl3>^!!RL=}5;97=Zo*AJZ(G z8nAFdHPl3P46QQC>$z?A8&hjISy5xN_lFyUT!>z|Zf@D8Tqy|sIUmArl_ z(x*rfon2Zd7Z29&?4OXY4V)K@q`phf$mo8hrVpg!M}dzGg@auDPh-cww|3g{iW=R{ z=Nod5uBi{eVkP3-Rz-C*uf9t-gfGg~167j%S~0V4bx4IqDyx}&(?F=dXaGbPvl8%& zfu&mFw~lu>g}&lv>)5z`6rC^Ct3Ql5Hm$KsMYAq}1CSfc02lQ8#|_t?DJPeYqWu64 zp^e2<)KD`cm&FD2hAc6+gwhBkS_BD@BZ4HH?f!Awe$oA<`|N=4We-K_T;b^(a8si! z`hOpu&-qqvZYDb)bx9SOB1rfOb+!yd4u)sHyxd+xsEwIE_+%3<=qeZBYE{Z9s>cr& zd7by|>eaeqiix%Nnjo2&O*D%h&Q@-Pq#3Vg?5fwCb}1VQyCtIcW1n}Uk6ql4`GyvE z+`F->sclRUXW^y~(CefGTf@F>i#oD*HvzeaES$S}S17eD691Q6M@4J=%tk~8u+28J z#8X}l-R#2Pe0AB9^RN+x-`4AfFRifvQCSSmkuAf*DZOqjM>IX(^c549wy~GDX=PmN zea%VAZwH*{K%K;2eUpN%aUt(@jOF%r?L%q>?3|6Rb)G32Df4%O3;Ov*`I?nZJtx_| zR|TD2(p+1OFO#R7-v0yxcALH&>gZrxPcBYN-%nVxOT1u^L*kRTWZKC`K9r42C-E}{ zOG2>oy7IdaXh+_Dqe|IsXayRz;i|qjE;*YIW4<|cyOYcFa>_m|`-Y*A`oI`WSiE3j z14~6);kA;ruLOW;LPto?`u^YJOL+%ea(kHBD#(u{nsV+-g)A(7Fuf;Cqug##;!4M&XM^Iu_!%i6jsB8%{D6!V1%WDPG z98Jq(&U}9_Tq_Um@~{%16PZfm5k|_!51V^!<@tEs`m7ALxUmqC9IS85eKv;!r}?WM z4dZvS4)fg?>+c0ofk$;3lHEOm0AmVrlgQZl#%&IQfs9hv)S8Aa>h7pfZb3m(yTH-< zP@g7XBv-UVNFE=YW$V(DnF2WIXoWm_Ev-JlU(TLQSpa3?>C|{dFdwb(@<~AAe&yE5 z%{Nx!`Htb-Et;|rSeq5m=8V;T`O{)f%>V|bjL)|xAI%LezA0rcmG|J|foV;wGGLXC zTR^^#{v8fX0c;olXIoQ^Z=rP|?r5cU_l=Bt?+yhzCsi+w&N&$ z@_C=FK^{RjV}5AgJc&qy{W{F&3oyVIXdirzj;fwnFQknnmjygu&2j3_)2kOB{Qse7 z56k`6VSa%8yrY#9(iB=u22q4E<#2M>U0+?yeWx&Kfv#=k$p9sm=>N!-m*YE-`c z3!|p7uy9Xo4zWh&CT6beP<-Y?Xml)@n^;M(tl?ImyK-{pTKy#DiB*L6&tswj{Xgjc)ntGBI;BvFaPdze{rQXK8yXts5TqT8os7(! zeyz+H(niOvJKSH<#?;Yd*ZP>28(VJ75d^~bwl!!bZ%36#Vn|9=LcQ$(2fbh6q;(yK zUV|N#wOk}78=HNwQwkNS#;^CKA($G3v;@j>zGDj1jHzXXT6zc-f2H$q5v7=`lY|ub zztbtbMlHmt((NZhq<{);%mt>RR&nx6@LuYYCP9!y|NZEntG-5FIXmlFa(ucz@?S^V zV5Ek7)YYFo-*yHW+^&R2$N=_%->L%3BS6ofipdw)rR8X??t&p$>{4aFm4JAXum3pq--Eat$|~xtp2QfQQW7B4yUovWpUKp z|2sZvF~L@Uyi6inx)p`Ro=u2D1`6p$Z4l9H%|^3@ls!Bc1Xg_U(~5s&?*ad_&trN2z4M8d3A?6Q^xh7ZOu6>( zy5kfVu33}DlL*wDPyEJ0Mn+D61gb6t>R8#-$Ipjw_s3-yaca?wTW3{UsZVCwR@~g& ziu(1ev{N1(9f>j*MSq>bhW{7)&HcYyP6!nU@q`+z62&Pmyg4qF=}NDq{P~}F+F;`m zzC_YIWB96C$P|I^B(>GoG^^JRkwF^OSc zto`Et!4VA|qDh5Xk+#ggK}?rl71{liK5smh{7@V`?@VkkhaDbgPPzQHMd$0fK~e7` z2Lz)vvV?f#`#*8SE%{4)_@&~!wdVxX>j3}S6&3Nc{#(EDh=d_abMs)^NiCo}G&y5l zh{ObmG>m9-Tz}pA4=Lr>^kpB1O%L&BJ(%CW)~(4%Dn%?i`q(PX=qOe;n1a6p*1Pvk z{BWfxT#|id_a$$MV)dAbnfX5)zFU^fy!?<-4SAF(6n_?z1e>pb$P`O1@w+BZ+}&=m zZ{@qgc7w>tHb6r~o>5BPHOu$LyWr!30#qj|#RRotYwg1=sNTxuipRy;A?3!y>H~X! z9J$HS#Cw?EIn}jya6}?zAQYk0FtM467^gxt_bY-j88IBr4qRkD>tC=%xQ)=Jw4tY< zSz&|O?2oh486nd9F~Tu6iUe|q5Zt@S@3$)hPaaEy^IBluEEzOOv|t@j1t;=Gc;RQv zggMV>19MNJ;AFwW`0j7`O8DR32491i$XLQY)L3u2@tVr$GFN}OX8yHU2g853&8rnZ z{kmu{@ALF!qQl&CTE2!&sP00s2ekO^%xC=FZS2 zEG4)uk%IiQ%GO=Z;v?9N(k>9LFOe^T_Ro+Y>gCu8w>E7j0n+e{9mDQe?Ag5k*Tlb* zU{CH+?U@OMa5)dt4Pyv0I=<6MH&ZG*=}rTHxp6(>4!PHRr0TN4wj}@soFTyo%ZZL; zScZZ8{EuSG(%Hj8Eg}9dOGCpC>SsljUqfbQ_=OEbK%ybZc+|WZD#)wYAX2BqM(Uk_ z2Y08-ibndBMVji{KEk1GWc(!bEJ1FF)34YIu{v!lx{nH$2A}(WZs&ARqx2na2R$#ms~4|`}5T54;$^qdYk6-%BoR646gAoce;g1zSP6xoOJEN^9>u@n2 z)Uvl~Il?h&NPrJhjzHMvb55G^azBIkIqFX3N4li*YJSw*Ab20wgkHI&*K^2!=>T$% zRTq{5vsppE1HcDOX>mAnY|gC*E&W#V_tVyr7wq4S76G#y&{1sAXw=W~-1^cLAfr$! zU@Dw?<#PDP<19k`nY`H8EA-={&fmqw-=Wus0OJ`57&uo{Fpd?_jSn<4wLA!;7BKT| zmeiXQFSLB;n?2s{&8W>HZyz}k^J%(-p?IEmfrMkj3(mrN2q*A7tuLBcpWeJ_J3e-> z-2HWU-_P+ify3{CsZPUOG^b1bQa>b}irQbff@_r1n00)5dbA);Oies#qwk$@x6t6y zBUyDRI~FcNvsELWA_2vh^D!yHx!xv`bS z56cMYpm;2fc=H7o*A+pA zSLsBWmETnF9oVggrJ5+1pj^K`G9UnOHYW~Qv8x)HovJogTW{*8-d@+%_@FNPEn}1$ zM&&?o`?#(FCHSqS0v4zDIoj;O<%o)k275B2+Pf+fa+4&o_k6K~pD*Va3s=J9yEpEQ zOfS*coc^p?gCf%P7)_$yyY3BaAv~%O7V(j{llS6bwLLOld*c=(g5m_7c}cj~nUa)4 zU%e~fo11eyxFT-x{x|2+qnah=l3?1b!hV*Zn_q&(Ee{%$bl@mf%QCa@eqAj3bssFz z^K%;rYvy!}+)ZEB?Lg}aFBLQ9UKPz0YQ5HH%4huToX%)|du{8v=5~uy_@>+?szE@t zTH6wMXJL_xt5q8U8xcq*>?1QitKDkD@hyO8IA1JvwF$MDYXkBNDF0WC*3)5jd#`w! z<+#Dmv>~lLJMqGkZG7dlvqhmo(bWI_=%KR6|Z*Pp`D+l1jQn9BEEVd5i+ z0d#f?brJIILn%OL7PMozTN0WoZ4w$Cu2laS85@3I#IqNQvF*J?u?#I3=SRbOt7qp=_I;uND{Slamg$Vf?1U`C(j2- zAt{ZrJScIS%D2;ptJ~X2o~pnCl(>nK_xPKwidYq@Cx(g$Q?(5--Yu+L?yRsa@*pNJbOR z41D|AgmmO^{rr-ln~Fovt3TM)w?9agK8qm^T8z*zrI7wTx>A{%pD5#iwM%NVtqq3T zm;{vQgaZfH)%M5P(;fwibN)9A(<~mzJ5hS}B>5aH`=byY_CxCL!&<)-cuCxVVKiKoJVJp#yV!pp zXFj^WI;g*jF)IpZg04!~7Dw8&ybl|SIL~`6A7axi>(ILM%jb*brdz9?P+M$9hBbX< z3^2{x#8Qg%82kUzVl}SL+8$0@XZZs>OLxT_z6plRL5XN%>IETGPJ=#-gc&5xxcYm5 zp#9o|?iIe%S;~{$N=wM%Nn6?n0PTF#3^c8V?83Z40eLuS(4u4tBKmLcyVqWx!d+SC z6R*1Oy35^Hyg(hO*~d2=$C|%%#$l$Hp{goshGu;~Q_A()Gqu3rsRPXNU??k7ij5+Q z$f*~YTv^BIW`gc#g3KT*gIX3`$#c8!1F(2F`8*qIPv(2gNFN>lZ6=a2RuVl}n@q?% z`6=ush@lE@k{|zY(gA==#7#bUQULvd#5ty)V`E4gxWxEEuxQ7`9$25m#6+)`E6u7w z3=#R}mkGQd1AgcF$q9eYZ>^28sfPqc6HpPDfN3yDl_+|IqB#{y<6-Jz<$q_Fhq^vd zTEgWsve`8-S<>gIir_*D1O_`lEC;sry{^Zphqe(caIMm@E)-ET2?`3s2+(Y&P2Fny zuxS%wIGv&i*ojlKsK+DQeQuo}jvH&;|Bx7YUB9=P2H9e~QBDJ*KF<2JZkOH%eKdLa zx}=kQ0R>4az#?2?ij0B5gN*i@v7d_1Z% z(K-$^KP11nHrrd9&OH;rZrY9;NfzOnvIMfG+SJP{doV0q?jN4ely?mbaM6&0aXcaP z+GLyYQP-Gox{P-bRIy|QmI`{U?rg1%r)%ANdL+|ck1A*^bSCD+Mh$@()wPeK4o@hl z9LM>s4n)~l0Jw^C-;h)qFsl%#F>*^WmtNHahG15`ncqGuPdYl79Q}Zdo_G}f+Ge^* zr(zmrTx)vV_p9M?!d|4YY+0nC*6%^*OOq3}z)`!9zF6D(DRllQN^;VD8n~9>|L=@h z4KyvfN}pIklzvo~$(05rjqUdHe_8N#+HLsL=&)EP+-^OrUv2XQ3I5Iy%}bv;!oiwb zmtWQ@^7;w&tZr<4oT_MkI7>n#^a{F0Fd8A(3QYIH`&7z9NmD~~{N?-G0VpSCi?NI8 z9H|-|^hv|jyZ_qTE|yrb#C$THD+cEFC1g-1(+IJ;^3Xq07z zWih0M%Q+QE%~HDNKwu1g#w;$t$eO3{tXm7b%ra;u{7+IpDOoZ1BpdW5s0J$U0 z!S{jq2LqhgaH4;!_dO>r41w(}-dS@0+;$W&n%0{3p~2aW@{8)Div7H`OW5Xr(R5EXvIYNeSCTA?b1JME z648p^y27BK~m*I62NGP@W)3&62a4TFvZVZW_OJkDBu1&L+if_wwS=t^6+0X2Gm2oKow+MgVZ|n=HpO+V{=U? z>=QQF=mA9A*n_`;!>~7*fV~b3%dvwdmJLq4VFinOTvDH0omCQJ&E*3Xg-7S7EYPTEQHPWjJCjo;L5%aQ+W~mOOX>dxq#HCtb{VihAb&n`Ln9TR7TKJ;+w3rL_gmHU)}Uiov2&nWx(^G}l+gxc^3p zMcpnD%22^Ky@9aUh*j+|#vVF*oJT^EdUaD>=<#YD?{H#ZK&jzqZs_TDNtHj%5~wG- z>j;a$H1@yv-s=`t6pMp*h=E5bN?3ZLG+kMR+6uIV)ly|CKer|aryz&L#hv{_G44;b zC-u6yPh)($qub(3?BLbEsK?!u46uV%69@0xju}>lfEI@6nAk*B<#G*1YC@TL3TnQc zonio|Erwz&){SrMi(vUKVoPm&dA|EmIsz(2(?AXEip_^Z$z888YE17TfT0-p6_mN6 zeUFc1`zoP6Cv72>&zJ8MQNC_8f55XvgbOC`ZX#MyOVUYQyX>-?0{ENnUo2h%{OWdV zAAyda;om)$cMlxCuZ> Gkl%w@}oA@Omdq5C`o&*Vb)g5~)Px2uLp~*mOv{LPN zR{MvRhYjTAOHEn63Mgja0@3sOQ?52|B!E=5);l2HEgwu6=*lm%#Y#@jhFJPd@}ajO zmP67e0F4(Ekitd0zeyVNcQ9`;7?s$TWU+K`bjJ%03qxDCI^X$j~$@MpvNuc_4i$|jaF~%sXb%-XJ#wrpOk`N22)`<9RVm(#Xiy0*OcOkP+ zSlQf6l;e}3 zj;g{^O*9#Ye&ZC(11MYT6Ma!jez)Wpm3n`EEw_5@s<$OE!0wpS7=~OeCflCZQSJef z3Yx^-#q8a-@guQLCGk#IUQdZ!i;Fp%?T5-OOl&du?#sCn7MYMdQNNhymXTI?T=jFcf89hax+(bsF(x?ZFEgoDf+VQx}ku+LZRo$If zcxTHm%^bizxWg0?5;T*Tkf61tzvy||y3$APvC^|E{zAKYf73Ydz*VYE(m1D`qS1}1 z4+yV(hRW4t`|YTL6@hLM{OV+}HhI!D%Os7bb&O^EQqsEvd} zWX8j#3o$rjK*xwOLCVcer!hbkdh9rwaVafIA%Xq_V^Mek&XjFd!dB|Cu)>04i70PD2M{e+f1*H80jO0JRK!&+fT$TEPs^#`Qx-p-UuAQCSRKNk^gxk zTU*<2uSKDFZnHe-b^4%ttoWh#8+*luhBS<_+mV6I-oUy*fcm6LFg<|unjhml7;dA) zyoo#TDkxweUzG$`u#GB38^`hz2Y#my82ZK_uKb@o|9JmHM()xn{V+T-b#OOR!1*DU zE{%FJ5uAcXbaYz8i_cx_7~(wzK-X|XFq1!)TM}Y1k*W1k(dpaTY?Bm^#yXEJd(>>V zuw@DR#omV?^g&{dXIBvy6sXc$_=k<3uZuk|z8iyQVMTOla8t(wDsF0~x0g`>`Dx~t z-uEi+WW-`rnN0|Kh_mqIOQ!{x3H(%Y>ABeN_36+-dPd@Q7CnZbHoqq#;Td!S#ps6U*wCr zy1G;i$YV*pPC<;Z36Kr1*JwGl3>=Q<6LcL9?WfKMb0*H#VP|i;Xhbu%h*<|8z_hG8 z;>j9}m;oxGL8-nJ42VV0goYU`i(PcUoqKv8am(GQvC;J$guzNq!;3qupW9DzD4-Mu`ogXn3;m+ashKr})roB3ie=X=pRhn(uTY?~b`=sOdbTFBBs@)#>e)XiLp25asTvY z{u6EgwD(%O$RpE}(N=c{qz($USxF_I!cwuasByt@16ZrX=m_k1W+#v=nMqh$|a2lHd^O!CqnfLWC@( zFAMd_caY8I^r3FrG$3Cwu_r{~_ZZ`Q+Wg^eC9Ol1ip15U$m=QrWv<>#AjT$xuWWX$ ze7nKGp{TYXP2%NJT?5^gkx4^3pnl2o$*t}1_%xSaXi&qFC5R=>@!$y1%$3Q0yKr<2 zL~%&Op*>Pg^!eX_JG%nFVBbUA)vcm5Bic6&9Vxx}8#*Slq zUeo@oDZXTeze0ZuyTM2Wu{1q<-gTx5{J zu&iV;NlX+=bvEa!3jp!$YvTT(6MI&BSK?IK#i``R~YG+mW0t0_N)mEO#8Jptudz~pUSfq0f~WFQV*A#J*k5j zB;G)~4x}u^H$w*HWT_fofA_7_5|^ ztjAt~!3-t*%tZK`g({wmI-6N4k}yRLtYan!x=Y*LL|NO_1lPefbF*tEq#jtmT|TmK z@Njuy79mQ(`-K$9h|78Iyn4b`Z`DGP|BXWev_U|u7`?Sh14c@s`*4batn(Z*^VQ^> zIHAVrSSF^b1&b}&5ihwHPN-hWsaXG9I`yoFw`lnvW>iA+|3rc_|54J}lVPVS^HAbc zqX%D=r0xKziEB=wy`VmQyjHdNjk~`9i$=uy(5kPOdPbT##q>JU#AxMKG$yp~lE9>W z2vcBr;Or+`A$0QFDwVWgH!$eDJ~Pd2vD zP+^TzFriAm5Sg`?zZV>#2qK$M=O)Dps@3d{awN=>@g}L@HL(Ni7vck?6kcx%ibsKT zGI40?^#xFBQ|0|fI5g}7IC-Z#>o#YRx*LyOxh7OAzx%t8_xT$k3AHa(wKZx24mTNlbDswu zZjcUwIt$PVmeAW`X1RZ0->+Ph&Oy+nhm4#W|K~@u_dW^0DZK!?u;R^jM{(avPe^6j z)JMx~WYIJblFF;7t5>@%@&g~6*UtVfY7dbu4RoQurw5L_enitM`)w->(_&O8n1?rC z7!;yGvWvmU33oidpri2JyCz!#;Ij;I=c68NK}|X)n?I>fIyNl=wNqgo6bn4$WD=gi zZ~Cz=e%!Vt{m%PrDCR*#NDW#5zM|5}+BJ5*Sq}}Jk3Eahq{;y`Xc&3m zKJt8@xDIbCkgS1Ic{q_y(KunWXrI(j+ChP`KQ^b(uyV6p7ZJauPoqT+6m{z330b!e zi2|#%%kqOX0uYf3(kef(vXbkDa^bS`gWloy;|i@_Bw)9t{eG6JD+b8X9O2!9?5qR~ zsT`|kmwxRs#@diHV;@OD!wyaMr%dpXhLuT?j6UjGFciJiaMqs?%75tb-R9sW=KsvU z(^D^ufEaAdGWJwRb;T9v{W*0G6nRZ_h*+<0kE_8T#UeYj*}8iF+IFUbI&D}p4h;m1 zIOG^uuH4Qih||vD(HH{9%fAyl-XdnON(l$-3Xz(DgYd^E7l$v3Wa_p635eisuK$@s zEnB#^zSJq7lir=;6;?!XQc!a(a-Mc~X*hYeP+f7-Pu)Xcuv`}`XJ{b)KBrf%dc+Fb z#Z|x!aSkDM=*Xb@zPY%1hXu4vIw(;V$HB}m;eW2KuDSW$Q+mSGFXjQTqOUQ1jI0`- zNXladXy@II#zM7oA2;BQCMGfrJ=X%**Jx$5n!3PgM0tN7cL5h@i>UOwXEO3V5mL(* zQ>7=TZJg)`;|229()u)$RNSepr_E{Dk5>=(y9}LU4o?gI-5}3P1B%b4-hh0_v55*` zZjCm5K$3k*o(muq*4JS(c*m&8H#oY<6QCj!r-C|8W147b;YEE$c7iT_yDdgSLLxDr z03h@MWh4NQNks1oQs~AbUE^sqGM$^@0|VBhFj6o-Vbx$0QNRTqL}|mSdPj+tN>%~S zg>$ZOhEQtBDmUv>{|+0*6}F?-6?Y0`pu?~7B33}Gd*n!voqOr)Ci|B*FOKXW8S|%a zsoE^YkFEY|-5FYsz3T0hmZWWWLzjg-)ctzce~FP|3?bhFY!- z+U4XY7SAFWe6HN zT)Myn`6pH5-e6C^x_?CO4s>4KYt#9W{-9Bwtsi?DXr=SeD(msJVp|IF&J z|L=Rg?&y~i(tK+wLx~ZipRK|^Hg$yoztd$n6OADlq{0E0Y9F*cUbq}BHKVJ4qmoyS z8~r7&gT=PFPbn&=9rouiZ13c#sJ4~zn5j608;09*qe zec6PnAdc_=6=cw%BEqWLhDx^@Ct)GbQlW+=kChdbWRF0?fPW*$|L$y@bfwF#XsFvT z!gg~r*#;NrCFPMWBo=Z{jVk!h)#oN?GFb0^wk6Qf-`Mdi7R+VE6cIxWq}<_xTlve% z&ifZ~qU2S+`<(Z&Y8{so!_h`0eel$qRI<+J@129O$0B+q+V|HlSCko9u-uCJY{p1V zT+fbf5@jM0Q?n8s=A-%AwA+^{_4ACe$JL`J%VfiSFBrP9!(86a7GVZnQ*f~qoEC#q zhzEm*DG`rJ^KYb1RrwZJufIRB;!_mb4?9hT8a%p0Q+ft7yl$#pGE%Etmy){MuRZtG z-}Q6a&FA|m;}mKR^liV6kbDAA86RyWu0?PCp6GI3%Eq7=Vhrk8vhSjN_hcy7W{#D< z7K)t9n^^-`jSL@2qQ(nMGGuv6a* zRc#p%pZ>)I5Kr9;*JZ#`1*OT^EgUF#t{JI*IWuuzX-pardE6pG|FH7At6S=qap#c3 z%fe}m?;nWx+4=Lk(D_T6 zD9I}*QYN3OOE9W*7F8z1ks?C2A6GZPDYn6sMHr2^g=+-@}-?15qApnK z)}feG?s%U3AWj~wPSD%tI39vX>1GuoM#EH-c3GPMZN84pf>X2o{ClsjU`DE}o(z0G3(qDYHz8uWQKD7eAeJI-43X7Y zXx(2)rU0B=x~T~gWkL>drR>;AC~9lKTVEt!OKY{Lxu%5^M5 zlNk4(7=r>Yt;Dou$iMoe>xpe#J2!APrI~aqA$*K`WvQd@LVDSEh0^ zvc%aI%IA#SDGbWw)Yc|NmG|tXD%32?)yNX{fz`98yuNn*A$b`Q@p z&JQNk+p8NG7Ypg;QG*t%Un(X&<1U$?A;D7AS|;}rOym?r88227Tc?G99BMsLIOrcS zG;wvpTH4lQ?uHrY(6Ch3o8Y0uS1~ek#+*2s-YhA=OM+SrHK$((;KB24ULsEE0@r&~ z=KD3DlQ-il{qJpqs|yN>vQ2G)H6?Y*sO@Jl^U`(YoEHQhvsvQI^v^$2Utw8Z>=K`{ z!by|I+;*W`3_2_Gj}Z#rE@@t9R~Ciz^7_FSD7JKp!CfLjc!>--UrC2kSuN%xQ;sBD z(K0?~N%#j$>94$WSSpt94g?fnd?f7_k}|N(FeNjYz;HP9o%Qg~`eVTFXtu|kr1d`d zjB)$E0sCvZ2>+Me%8onHVl`Mlx^gPtf8Gc9=tu1H3DU58iI*{d8632Z2Qx~O+h>7{ ztSo8j@cdW1@4q~zCIV_;gI&jW2hm&RhZWzD*wpxxvb6E#mB_ll`G33$v6Mv)>(VgK z3r(zSQ5iQ=lD59h-=1|hpbC&_j0VjMj7gn3_N;r8{9E5YL)Q8EmC@tH#!?-8n-pg0 z?Olr$?`-d)P%c99tzAc943O(L3}-2`!Z&q^-vFD;TjEjDaSA#_2zoTveSFDV?-N&c z`@%x&z#*E!6iJv$LYuhIHVS))BeG&<3D zr|ScxSjxGczNoYT(Gf~r#SaQ18IHQA<964-|Z$+}}0&lMa8t#tX(}jNuB@7pouz8|imAU&hrnxMfL) zzoh;)oF7>-QGK$X(T#Bdnfx_*O)NiMHU5u9dSJcrpK7^MQs*fzN<6)4Cht85>I7@+ z?2kdSj8Yr6OJ79LMyhj-=V0dQ;6cnpuX#O7^qcKnJAxFOm|oq$+;8=PPY<`X$G=)Z z-H!o^NL=V?tVLgb+;yiJo0%VQ|KJLdGp(Rf)%x|Z6+YbRarqdy1n*R?q8>zir>mHtZA|8XvD;dae15RrRd<@5(Hnn^~Qn5$Z4J#Tn^MF-oL$DgO^qZ^0Jj{)G!GIUv%VLw9$>P(#Cj zbayubf^>Hy(j~GfY3c3`L8Kd`yWu?hegFHMZvfZz%x|rA=R3cB;f^@DJU?LbySvSM zk{SrFcDWkD;&WK;n^hI*PBOPHn^2)@pc-XCSH@*Bu<|~+cXoMxu>7MRbJX%m-ttG^ z=QTnMVqmw?H*Btx=W;hhsa2^ny!)O+(El%jZ9CE`CLXRN!?Z#^L?&EH2Dmz1%b=JU z&}1I3Mre?2F@j`bD{HNgBxe4HE{954E!7K$Aan*?vo?27&eC2Oe8I&fm==!-)I}UR zY3~)5YC~I-*~^%a2DvnK6YH) zPoBpEKc<@(KJ-&TMK#o+Sj3&Ff_{te%*@Lx0=+tn66mH$qvqr2`o|`abJ_P+FW2wxt!8#!YZONx z;Rf?ByAS1?#??j*J9+5}JEKo4OYba|8^y-0@@{mg&va6wlOT%{1Z>Ezqt3zKJAXNw zDSv(XT>9U;9i%<*g?FGd;X#%fdv(2*r^z`&$o|misw{|h^wq<{Vf!UB(~bn1NeoRE z`X&25l%5Uu%hyVmmt`V8=jAWX-L1WiALr19izK84S&D?8AIEs`}& zPB%eO^m6a|a#s9VBUJre=N)@M$ZW)o%X%02*bz@bB9ta65$Iz3(h=mpdRyh?c5?KA zj*i|%H~LrbJghH5?Cx!-i?lmQprv94;Ihv-TDqiryrrOt-g=rm;r4$j4ak1{c(i$U z@b2kv^)uTZdv>vA{BSa{oC>++^rp<1etqP5l4+H3a}c_Ds+YH|En`N_!1S-h5#+T? zG{s%^!uF!9YZAU%i*vKx>-R4EzfEJC+L~{{r#`pBI&BV&gYh{MnV}5PHum=P^2F<8 zhB-MNO`eIG#A_8Qv{P^?#OW+XP|Hv0vdQZeGG%b;n)$Fwn7ln`hp`D)QX)OGErw;v z=Y2UcD_p&{1sydiT{WTY3~93gfmWB+HWp$?5yPyFLCH zBX=5*n&5v`B&`mpUje&X)%oAU>Wh=xjtmlhC%2skpT?E;m2&(r>dj+eZ|6yv51mHyw}Z|7b38wV-!L?F9S2l z+7OxjZ<9E%znf>5pfWIeSN+)TBs1)H1t91Eqf+AC?4* zjwAZ>jy8O9t$1o$!GI|+)U0MGx`bKY{(Y4}XE*|+ z>|z5ZQOv_yLIv3iNyf@8R^O324M;A{{lrk+j*m??KttsJu@M#(d_hrRP;-VY+>s6|>=Ym6?K8m4JIW4#K@Be0)k~CoYmNBjNswU}4M5o@$UyVLG+>A*{TvSA z7G~ANK&3s9P`MhC>~cQlTA}FP+k}Y#E2O#lczYJ}I@p^?SeyrypqcJD>vAob9N=JTsRAEHk$Pts2QHcm#(S6s$F)UY+)MarzDSr2DOpH)2>bl zahyL)-u6SH&d;&fj0GkE&-2im4V+Dmd>~KqhYsERTk@Fs?(Frcad|>oqhXQ26EfWy ziTr8UI)}w-uMCt)KVzcNi*lok94E1I(JHtBpDd#O+A9%}au9=Jdr9oY z^&i`uMMbb`iV&$ zR;F+$@mX~|E}oj*F?6>^=Pe6YZNMQS z;KS^a23&6aGFVQg>2NZwg)KZ8QlIJA$OrqMF6S)TPVpOI{Y5`~3eZ=Xxw!X)Fq?G^ zP=X+VSD+G5C<3^gzQVXBwlvo}xz+2au&6G>_oOA}(MzN&dWZQ-Zl;-4BkK0sqdEPP z4qxOjSmweF#Q+bJ_r+H|EQN}CZ)78;;*sM8=aYaG>s%iaeLlxc`^k>6`GL8?U{RgH5nN2Vqz0i z)hp+Bvsu6XAjCnYoaO%TR~Hp&q*5ljpNhJP-e%4oifr>XNV>((CIu4s!#izV#wf{P ziZVzIB*LuCwncp!z+Z#KqSF>y{MF3LPULA$0|=?g_AH-QvtukM+1wr1XVK-#dw)3Z zy0a`ZVEs?3-lzas?dg!~NEn|1%z7iapH#>@uxybiSONzjnjw;*36~MqyoW;?8i8ik z1MX=?U`3b^M%ymcjrP+SaeG7!{D@v61v5XNfY5MiZKld?Uf5Z)1NOp-Uf&Q!7OFZZ zippM-QkYp#3_-Xqk29y&$?qN#cJayN?y$QDG*(v22Ov+{VTTTgsF823OxYPFnB@&1 zm;CaM+fy@NNWEZgF&KtQi4X<}vSdzoeHbGekR4Rl!@`GTUlybI-~?CJncA}F-Sx@Y z+S^Ma`$*|pwdG|xDt){~d)Z8uVHP7o*qD1AZ35Ak5Nn&B3zqbjOKN6osUKK}B`(~Z zI;jEB3LKzgmQSHme$gsUomD^{Y)iRSR93S)eXN7&pC&Mo8NJEI?7@!-D|mVF$pD;G zH)`#x3}0#RdQdP?57AU0%_Y+9Mp6-oKn+h4n-@ER`p`eT<$?hxgiV81YD`1zWUHn# zxQ8U(_CNSuJ+u$s*k7vtC`lAJ9iBnD6o&X8(Fa5iFB1J3ajb7@Fsm@X|Hty``ufN7 zgfDa^G=_kEE1Rl}=WdyxqmP;WJn-5a6XV1`K2 z1jxcx+n0a(q(C$+_UBoF)UUe`@dq?(l{^^`2LxO~cZpvH_t!IoA4SEYLboP33}6&I z-g5{Fj)!1~1YXCx6HIXW*@wFC0n7P3Lu+0@7z0OrW8avjwd(|>XW#Z14}AjJUOcbY z+013@{g}1*An+`5G(t!j{U5CT)3b2i8?E^U@{XoY!PsEcO6C>x%CpN@o1`fkvpQMo zEcioyvY#8nanS)*i?dh<^dT}hI;K-;@8-Y z6E>kgiUzITxgm1sNrW-;s1fw#JU?BJiF2M;mTO+nXEJr8)uGzf!lsy*4bpw;vEb_0 zUtwP)_D+bSAfSYK#Ly{d&H^TLrnvAs`f1|O*t4j9g_u+<1)=OQ`&>>WQxQ6OS22t` zMOsQlHHDo@lhs7|NKL4*Gru-~%K!S7#$%8}jl4#a68vJR*!7dxWGtv|Gt|~{s_37nZ#w0;43m#5N%G^J7 z(m`e>`FR~xZ-FMna2V&x=g&U<|C|AvVT-4|p!*f3hQ|Bic+RS~M(b^~y;Pp$#lIA` zN+5{X_Lm#xTP+QK3xk~ryjgr2)g@?aZ4-Za%e(b&j)l8`y;7&spA2x_Z{D4o$Eqk5 z7Gjp-m8niCB>IFjQ4!482KB!6$x4xP?oz~`N!5=szmgX?8;Jw`=d$hbvWdS#-Ry(FGkxkxGecj#ew9Uynu&&# zDK!_3UG?$Urmtrgl$XXtd=%}9?*4G(zk??vw6uS4KxTKJ_eb~(8F^7rd6uPphDJ4DAzk+mHUofn zmc09?48ojjN>oVw1UDM+GLlgD>ZF_vg|vd;r4(y$@R%S4m@q6{+6}=$EvdY+;%$>2!=jG-tf3}?Vu8Zyxk()k^F{RZWZ`FBd*#|qog=E_0VVTO~ zsK(T!{@2FR!sbhrPdkIC_EA1>rK6=*wXR|TCXfg1lg$maUi5s$2S69=$QasGbP0vz zzAwXeZlBMeK8VjObneHzrkR`tV4F%7^YBvupL1v7e>W!yeMw76@L2^WmFmY=Z4jkW zvq49_)A64&VJ)^!uh|iqFxGMc*VCKp3cb1hwi6XPW)#zc5dK>-GdH_bJm!o&BlI$c zv=J8KqrIyG>ajUH@53n}=jID{Gm$bLS*XYN;aW6X)V zvZ5uh%Gvo<8JH?3pO>USfeR$R7=kLV?L|-VI&o^USbM*(HoLN<2n7X6Q@X;@B&Sb& zbTTIWrk-QDQQIGjX4r#skyb6LSfW={nJvueb_#X+$)3(5e$gwgpvVwaNY!({j84v2 zpSCYRaLGuC8QHeOJY^yZK?#NRxnj|FH@D5qx1eo^LhS2<`iQu;Bp3nrEQhRORR3lU z9UBs~WJ)~}4L9kE0dbyiljB=1(HSPfTQX6yJKGq~4<{Y3{(O#W14l==NvKIZ=DQQe zu{E)AvB`g8)glW~4pLzvkv5UTb2zB|*vXyiCDYP`t zI~1%2MHG-}Fj6J)bhquVjays%C3tFCqPbP+?+)CE6x{zU6HX$pIkTvgp;23Rnq``e zrZgvZjL4?;_9P99OW)PF1wTkdaJH|k7_@lD^OVA37KZPBwwr3qIqBiKo%>s!5 zpT-q{QOZ$fIoZ+9qXcI(-YhAC3iuX8igjGDu>$enilrIe_2ifI_zWNVVw@eFd~Q1= zOQ_lE@D=!ZN_dAfK6f2-e*1}7O(1I4w~ zsxTg1zxZ{u;uX|+ciBm!=9w)&4cpsOwjDY0$myn4{63~-Glx@*Yr#ir7xiNm6Or)+*A;p1ZqSV zCPK1T$FVKY^I}?Skq%o9o{y%HAA)5qEfh6(+M`s8I-=!>sd^bxNH&L5`#;wpiXf^vl6-zADX0(;@{O%YT;TzQnmbRep1FQ3^DyJ~u{ z@(-MJ@bopSX0^EQ7&gveU;{Bf?>$D`cNX8`Iq_-n^a9bPDsJ}~`cS91XhvB^A|lmr zMgkW{SXkAe&6R2QiugDRl0{-t$;D7)+hnz9Gt%5oMcqdhVG5PesnHBoEpHsVtN#=WXV!%8|7z zTMi%f^o21L7-s=+x&%1qj{ZC6@WG)&!5jk2h8NQ5V>dzx^?dyTUvhZ`3OIUZR#!*M ztI3MX+e6|{`04=wHTvq7&1C1F9Y75hLs<4>6%3bXR1ivq87%-^Y$;3dZCvY*zFuO) z)dP}1dvz1g;n)mYM*81rGp0qyDyg_^^dOFuzyVvV<)=^KqP{n3mBht!?(p$af=O#9 zicwz8->1%%V_K-ZpuV`#YPLNRCMmYNlZRVT^yJnyeqSUQ{kJ1tP;O6t5C8Va$$M-z zHs2oc@ju82_zF>!aF*k@p3LjFLLy@5I27)TsEI;(c{nr%9{Xg4&*6=YRIDXj)YRsw zF~?}==ny(!1{Y~nyB>^q-W;tYpwTjc{R(?AT= z1)NN<{m~mm(3|hI#vJ&|pFX?TE0?~Jqm~~#&$yDXy)!5VUK2BFov!e%@;>mp**4ZI!Bp_Ps_m*m{ zi8_V?b1Jp~fm#{gU)%A{M!WGw3Oh%8VYW~Qt!+Nri`zgT-{aqlYfZ?bo$tA(Lj4d2 zJX<`nz0WZl_eS!KQ9c=9g1vaUWUqDY)hhf=oehqTsc&kW`J=Tv7NsFT3Ks-}D?l)n zthId>ae$dGwV&n}mFLa7F@Its$Zw!h#&LSTX3@wM*a>?B9*2_QJdi91U zh5&<0gsXe#;vtxum13DZWOt z=YBv&x|^nWHO)r5>(TzVT{CTCnxw*@E*d@p{nEGdnX!k1W(qZh$ieO>uU}UDgj25f zlO!G8x8{#KT=II<+>E+<=A(_*A}_y-(AHWc?MQ#g=Gip@X8lJm*UK51bQVMDg*Gwt zqs0)|+kP0}HoE7_^?pD>@33z$p?OSU}h0$XMYAFm=Tla7Tz zUC81kIIP03GrFoutnCLVX~$aINTd4eKeyfdTGdMzA*`$=@4&~edE#sT(sTIJ|2vTM z!)_fL%4#ThbStG$7-wV=OW+5rv0?OQD&Repe^A5l|Ml*DQ_f0c>P*qrt1(&i`$r=s zThJY=c)&ZTJL!v%m$SZdvBI+Nskw*8$0GQ+dE!0MRo^Ou=7DjN1)rmHx&5Of;O~`@ z4ujjG-V%9zS}0SQoPy$1&`){_M4-cWQ6t)<$xVLdTL`Cd-;2B@Pbg0EPEGGKjdV|E zCa9j8ULDvS&suE1eIx$pE)FjrRubcT*VXhnlGlDgg8^TX;Q=45_Tw|%%X-3V>ZLZj zTBH;yK2WE!uuPsw#rE-Re=EV|{x2^&+3#L5uL|o=g#!TqAOK0nWm4ne3c2(Vb+!C9 zVqe`ZyY@u8?7Ozo_VjT0Wszv6eqvDkflTCbj5{`d)e3OYP&YYGedkwG;0#z50aiwM z_;;CKvrRobNbOmZ=2?uyhH`F2M(D-w^S%&v$SX3^#J>Z*g^Tz>{MOsRDdY-Zl*>4O zvX~$4j#n7B2KR?t0^`Ec%`KaGuiC6G6!>Rwq@xe?rBe0uK)r8H!K1{@SE|Bob5NAy z6;Y*SVyokCo+8gT);eu2l&7C=eSf!odOu%W-;fRzElTY{6g(JQ#d^1rsH9O7nIzuD z$pw0WIGga!b6LtvFD=o)U4o?e&LRwwV7zZhlHjwMjcml~Hz9Rw&MKGS;5YRX#!IUj z+@7ImAYi)lUbFQ3VA@9W6V3Z(!@L>Q^a?#9U%tik=_RuiCC?|#Pp>Ua&g_iZp6*kj z(@GMWRBr8Fm#4P2xS*#_xWh8#p~_^%)T8y)b9TR=P0z#89}Zu1N%5QlZTK{KfyXcM zzsHX_^tP%_O!%IfuRI+gm!&*~my6DdL`NUa)D>DB2q86%wYaKtr-n*8 zb&9!O5K8T_t7YbNqsVXici36E9wwR2AC$q~_Spmra6Zw|h8s(lOm-GKlxb z<_FL>mKOR+MWV^Or6WHlt>Ur5zFx2nmV6{e0#F5TfIfNr@)) z@#IhU)4k&TRq1PBg^)}Qz#QP7!AxT1Mmd}Vdy@I*?at7*ME>~rZw~s$(&zdm%fw{V znD*j3#VuRdSw$c6JG-51eo)Y>HTxyRW&ZQ?HIw7#b})Dt)>bzJ9*V%+;$SOkFHfj9 zq6Q%{Ygd9Z+vB;3$v|eTNpBIDASf5d;psZ>z>=tE?mJ2_Don75(Y8j!1*)Sc)fotR z;*$%T_@FyEu8(>UfdC_lH2K$Cg(O}(?=p4u#JudV=ATm!em_61<`-dB43;7tUb0UC z9&ZZ^A;{lAhN*SdyI8ZbG}-ov{YsKAc97FHM1WIFG%I`0iU8S89?o2})hrk~eK|RG z+aF@CFlvP>?)wyiLqu28q3$>qDmhxJRblWLV@jAX|6(GBH;ke{y-qu)DO}_8m%C`@6Nl+ZlSD6EL!?Ae{D`v*`DX!ah zg5*ATl6*i%5YC{A`{ug(ypv9EVZY*=?#0UmZ_i0Aqt!a(O59b{?DP6GeeeAsLy_yo z(tVr5&9j=KWl~~E#IJ@J;zRc_+CStWgh+(5;CRS z@nq(VY8X>k+w%dvpwBjg*YVGY_;|MD5f%v4DIwPFa2F*1mym?KK!`hL61EBJ>%|aP zYX1B-;4C7q`?q`{12`7KLPe22loQh9(*{Hx&kLp|Lq%4ekK3LdonNz}f6F?iYv(=_ ziyr4>cg7pvjlFpj_(on@Qqu#E(TvSNECD-OS^tz0L{p$C;9OS9cx{(cHNoch_pHYh z7J*A%iK~ZXf+nd6k#;XsI3JHy5$i)aJU7~?kn;{3W$AebLhu%BdOK`P4~mKB>Cv-z z89_Y7V(TT2L4^x_bNIY$&jR**pUQ2K`L#vV?+SYTgf_lN`3Yhrb>)o0lJ%6*DSd#=((vYk&E}01eF3@qg#WJh;N0 zY!;`fQx%nD13ZqMJc29VtFGFgojq;_MB%?Rl2EJ}>gLCo60T0Dn&4APr)r>!k7h9v z$(yCW<>E~;(-^&REZ42KA?k-PGsRv+NM{vV1fJ!B$CwqJSIGNy2J0pR;#Sx@hqg7t z!iT?GA|0~y*s~x3i6=pq_lt1@=7!<7`1XiFT75wP7O@NLZUk$O@Zv)wyoWmNcA|%T zP8P2n8c=MyK{|m?n+U4n510V$yo0To=~`7ovBkH>O@>(A}1q% zJhtflrhIkd;eKoA<-V|+mbyeXsG4Kt;r2BL;|Rbg-~YWvWtuzsc}t$oqCYfrtY6=V z3tYskd(}o}-WEKQqwC%at!optX^N5WI3I70cP4~S3)(B=%m-Cm&(0`4Fq1RUm|5ma zJZ`UMX69uKoVGMx4`vDNLQO-_sZ*mtA#Z4T=Y@dMqc=Jcp7`S07|ab8_v=)DmPYF{ zmV8e7_kOq8aBA{y+7UcDeR&6Dl3k5zR183Ld3_MmM|47w6fsbctSesA`n*tc*>o6vvW*C+pE zp{_$>ry+B66yW9`0)XBtgr-3!Za%&qU{30^IJ_5{8;cuMQi{L)JKD;aI^qXN`K-rV z5SL%iREjSUf+Vn$X$F3g9OxLYCFf;|2Mm{bVyXbz6wtqGo%4UVw|Z)M`b#e-L=NL}A@7x?VFazHh?{0Usl-R6+czi` zE~0NpWE5Pyl?7<2d}D8+jG$r~c@41_!@TtaFR@;2fJ@1HO3JgkRh+yGy6sG0UZ~=7 zvnMPg!_k-p7@HjAlO=g-cQnJ!?(>vE?}MF;X8$dw0;DY+$Dc0G#A%B}jgBh{04R67gAdSsLkoGIllX5a zBy6ItlE?IVAW5qyVw+$vcBf+*bLYALstnd}XIsyTKFRNmWE6s7E+SRolE<{BO zPRS~%q}v+^ z0vLC7cm9)_j&;%uHGCMI>;US*8I3L(rDjLYxxdrV5WfHn+D705VsQ7i=2&C-dXqcn z3o@gs#Ek6pVfD7JS>2P$7{Cg*HY_xb?W?U-N(y+UpV&vaOozbG`<;S`Omu{BeX&EuO5r?%4H2J z9=Eq^gd`Lg+@Iml2_b10{#O#ai&ueLOC76gGNCEe*BhCzB=vxf~Wqw@+~dCcas4R8Qv-2Y#GJL zv$(9WdG6KMAnW}TprgCvSzrN-hB#0nAQFQ=v6mD<(I+IAT&xru@3uMRG+%Y}ZFyzX zre-YWfacV|3xgFs*Y`#SxB^{)MAqSBeg6HEzxho~d25dtos-ktrD`LTsdl3xw74g_k8dlA!1Ft_1Y=%UUS27;L|?cx&e z@6!}<{L+1a8X#yUMz$FD{d(XKzmXV)*u_djuK=;JU-EXa&B#Xj5qFd`wS0}E&yRM z#43LIk|PQIUdmYA@xV2z%~IOl{?0|m+1ByU#O2)2=w;v%&A3xRQGJ@*87n9r*jR19 zX6BRty2qClcC%!ns`skNUkH_C(|=tmA=AAc8T|7E8hq@$4;6jYj+(;?iapmdN32+B z2}>*2x-@^iD!m`j?il-Lr~LOPKtS5+pVj%0!tOqqqtB2Yy-ZB@O$XDU#V^Qgc_iNV zWOqBtJa&bAKwrL?C*&Q0%PV}Vnoz!xvQB$`OaqXL&>~{BTFXl+>J?w!6yY=Z&toQq zSDnW&6;lJ#<8AwJx}%q?%PCeZjpfVJ{lAaqd5wB11}0KAt`DCR6RRj=TlWw zWd7ITFX*?fOnj~TBRDEbmuVKS?Tmpo3Zkqz7b?kft2VLxu{Vk4y=HzOrZX7?S`3o# zPSqqd7w~)%@N&=_3`V?UY^uNb!#v5&>7N2cWx7TBLU_D*qZ5I-?f{2i z!NyLHsi2{Xrfc?NI~U6wJDG(t8m`UL+jQF70+YkEJ@ud&eJQ?{a>4WBk$! zPK}2Y1iElewx3}uW}wZ?81*~?!oY^gkYDy07Y)^7qwdwGrguGf9u+@5cHo+v4YxKA z;E#NE6b*=4hMGssd6clKVZ?m2y{6gYs!>k{bc+c0rOQTO_#EvD)S%S-5}N+a_ToR# zMb}e9+@8qBM(o4+%5Fs3m+R^m@?XRDZO1tY=QRldp`wpB8qUSi(D*!&;q-Bm`}GL% zp_T^wGEJss(iRy^gbKYn>@r@_W6tt)Ps~Q)zNeiw10oqsGF9gQfVu|i-fC=$x&UD12hl8%038wzCcqq*kl)fT!>vJ z?lw=Pl0c230#5}$a zhQ0rE9hS^v=Q(nG?6Bg`-tR_~E&2UTiUpcsd)Lr7mKLjFd@QMJc8$d%SGKa7HVECk z?$gZKV+O17t<;X&k||?Wa5wN(QT|`VEkr{BU6`HNJ0L@mq{a*1Vb_y%p$D?0T?iS? zawI!`EJ%`4($5}C)TSH^nsM*aZD&1~*}|X0%?A@|t=HbN84{WMF;VlP9%|IinfdvDv#b%oFtRD0bDNb9nQ~)I;qsq{cD5sM5iIia&*CUW0RxvlB9F+tRaSB!DM(p8CDrQvgo}F(Q5E4^yqqu4!9Aa@fr=b>!MBogvu3I`$(Rb;^By;fx2uC#e z#H3=QR`MtWUc#M{uEn|uA4WwZ#-3-3`$i?5qwqN|^{mg7kp6x}T55DI`D{e+jsU~W z(k2pCBaO@K6t@By|6;&Ni~KU8=kJfct{0-PkEXr6veJe zR@cNWX*;{pARklmgsx^{qc6Lz@2>$HgZlv`1RO$mDgqgIVYXSNzKjCBqJ*BqB1BYF0D(_$eHwPvYg!5g~v! zOiv|QWMulfnvo<_Slt@K{&{y6khDcY6yGUGs70QGh~p~K`T9ngwH+Ti($nYbAd%lp zegF)Y$$uwjI%O>Sm3#tvwtSPof|?|uN`}zxt4hK0^B`nMw?wnOy!=q25@skO$k(AH zKruF^S>s*dBCrS2e52yBy)O@-C<>IQNs=It(5Dt6o%%p{ITg&mTxBU1nWbL|iRaBp zbMT1A9?XzvY6eF4EtW@yy3>r8k-$?uVkq6i!I zjK#KNHY>UTEc8vYBp$^f?4SiqXpj~*Eh)?ffyf9EWPL7{fvCWWWn@D3<-vdy0!{Vs zW|XkWZsNGTR;+Zj4R1g%!4r7LM^RgUPRKswB9O8f3TK;SlRD#G>I=u4L49tNRE(5I zE0Cd{nG5F(24|r0!KyG;%!Y#{=N*2lXhvees4Y6M1U>gL9e2=y@KHjdmRMEmedA?S zQUZ1Lw^;(jzhq^i&L-2Vf1hcDLC%SN{5k-x>b2{?xyUM0tcNTYir!iXj@)cS6xX#m zc#>kATN6M@)%vyi((%l#G0QwaUy78%^J{fm3^`0nFiP|5#5`Z_=NrU%=if?Y`B<=` zl5eG@F>a(kPS>ZO{1lMCJ0pGjoDKv@BeBc34IjcBPcGFIsL~`%fb2mQ3WFXEXWvjc za-ZOdDsmvbcmxNq)JS27K?uW^TRd?NxfJ>%1(F#uYE3ra{P!aQ0$1-9?AZB?Cm8)RRPqA~d#Co{r8Y3yK&P0V&HlQ?!eIj#W{{-cMv+ zsGj<>I&oca2xP~CM2-!Q+iD*_JUs5!SUn3lt^HIe1AJYkVjMzhMX1AmD+AeJ` z_Ype=2>=wL37dUV2#o!5+`RZjV~`>@@v}WUVC56|(T)KEKRs61rPcjn{{Kho$A6EO z7PYignMnd$y}uY}3m!5w5b&&6KVSC@e|eLT5a&eL?rGnlp|Th8WWqU@!bFzC3Y1q} zK3z`MxGy|2&|)eS^nO8%NmpZw$QJR5W@+%=bD3Cg?-LF>vzxeoGb2?0rV@cEbWDJ_ zte{eKQ&{YVY;0nT3SPN^t5>N((#u*{y`XD;JWIF3PcVbc(Be~LFitLw;$5@x9Z*N6 zKdIeugJk@8q`l7u+Jq_P(+1%RSl7(2|M(6r)`?xbd@#aiHSXbd4)`h+q2hjjCFqb| z`|(;2jtF!AjWwCjlm%U{aM1jE8_=br9w`M^c|SV&Osmbdyq^1bV(MX$y>ZA7ts{ni zm%+g?)!WsDt@lSrr{0Ef&HF|dM*BmBOHi!4b?uS7YL#^7&o4!rG%r0A_6s{bgqb}z z$pcS+w-OrG9j)ZzphVQ9)~?IbGEi4YziB0+^AEm$tM@$aM5)24Cq@+p+4mjErmNl7U4&Mh%xM8=icrAvB`0p`;^c%9e? z8#Ln^MZgH0`tNH3f(NAyL4xoBkDpsGgTWxHhld9YgElvx$CA+uUmX3}G=(q${INqP z)8Wl9=m#JzuST=5yp(&*3>r3{{PM!qBD6lvkC8GA2lGw^0Ti-K_%(ill)M^~1OoOR z%@?7=4EF8J($!%=(peOos3C{$KH13X(Ud{d!8;L^LJue=zT{RJ2`w!xc3M-wP-o_5 zjE*d(*RhM)YHk~z`)VY=w`~kX88DfWdCM8SKNL|=xasUj5T1A5*pNHjJFA&(t2yNr zd)3a{S}%YX0S-mnn6Txhjqcyu&P=-8Dan@at*i!hxY(_3>(;vZk3}9D>3@1WBLM`2 zN$IhAa)#^f{SfMJP3jtJw{T|pp#ON+C!MoMePwdiDsJ&F7C2OAM@tYE~NzOdQxXZ?$*uG(8gY~ zD3LMv!`aS9+$UZ4s&Xu5wZGF6UH7S1mWGC5n-)Mzav$6jN4@Qv_x1?bbS@YxL;k<_ z==J@7a}J*}^h}*pdAY{_c!O+dLA=&|>CcU!mvbtK7W=nW)_hGHOAohbNX<~@>>lA4 zafvca%22tOM70QykDgqD{#m2i&IKMk1c`h@5`k}I{H;0mq)?K1WzC>3T&2aRrogbaekF;{V3#xG5nJaJ@me zeh?6H5rC_o`t9t`#>&<9gJI7#Sn#&d?6d=3#QXL0^5?Z2AaN#G0?JeeF!cdn$%H>* z@4qRdfibiplOZUn#JiktUtTo|eQMQ%;*5?ulUfY6d%2%Z_%6QgO0If;rdah>Ar~F6 zukPpzyWC48M>Xw>H@v;*DoQxZd)a1gYdrPT>+z$TGun8=ii@6?HAoA}Y-MU25hY!H zY!2jy5`k+1k%`vZ<)BgXroRL-4Ygc^67t4J{E z>bE9#()=nJ>=3@Ov|vl9EP5U)BpX4QIec_Cba&P$eEPE2F8UnsPpTa%QWnqsTIm1S zZD&dds5{bXoyV`^xS)OhdbhIWrz&)HS2fyY=d8&)VH zKAY}D*5eJAzCGA7*Hn!m6lWd2hhsocl}3Y)?Q}b5((lXs&D(!$cTBm+UCu%{xW%cfBWrnMntcuJFA*!a%Rlf zp)++|__Tfs%_nl-Rlk(F!O8Qf-rG9Aem(SDfyqT~`Y#n@F7AHV)ijPPj!(;-cY^a( zYXEK3z4!a_k9}${Qx8h^83+xw-HaUeRoECCgtslHKqcPfwz^}BNO_K0JQawDn~CGS z$4STUMa@Dto=6^xr=&9B@^@QMp&$Q`@FOQEK2KWq`FeO|D zL+wdTl0!YdA;Haj%30bnzw*4UJ$#Ydw{h+jj+nuk(5rg?-t}x9>!j`0384ARw*ZOw zJVTl<2u?X4PdA+~i}`BTK=jF$-+67-~;11V__o`ZTf4X4F ze|0(9m#;D+g5a+rE~Ey~l+~HUF0V4j)@*K+-b2e+N<( zyT*N|#csU@lnGh`2_s`6t>pO)%h7fCrpy)%_TRf)Z;n`vyd5LsJ0$1VYLbR)7*%ov zh7aED`D~UA>UOvZKHiX0IVzbu=H$kI^xvfSCnjqEa+jXuos30QniDZ_K@s@aG1Lw5 zP~^~{0o{mXxKQ{EIKDNPb(fyPc8Iq;<~HryRUsO>>XTph2U%Ca9H6~_?8qjpXvDTg zele4Zx`l>BV7UDqV{}^UK+!=hi8M2iK*lQ9W-AfW?-okHMV+;AdAPDouP~VC>VnwS zdG_dF4LKwA0rACsx^ zyRB?{&lBE|J|+TO(Zoho1 zx3sj|C>=dUIFSu>Yz)0`tT2vi`T(FGahP9Wz9dZONw5@2Y`orC5i8H&PRGzOn8Qkfiyi*!-!9xM}%RwR@rz)Pwz_b?&@p zw98$LsioOCpj`xBFPc*ki2#UNH6>;Qr6tj#7l_FJ)oJ^#Wbpm6i~7`h^{J#!Qo6Y^ zhXa*kf?JexJc(K^Gbe{K9`2;W3)!CEAzzb;%kL7ux}!Ghpp0m4xslohE_;L@X~^&H zZudTI(vWx+rHymWZg!5D*J-uoeGoW3IwqrvYw7#>ofJl`%?8BCcjx_sudjgT1y2f2 z3K|=ciQgSUft}0Y123Dw&+++VjA?%7z?%uSlh#wCD#Ol^4bcce{|6COu@}M^g2}D* zT>izMA4OlU=mU}!sMlW~eyy4A-UxbtT?AlxKsJcHuRe(+?)eao>bk|y_BL*&BRH)G z4#HG{11;F4TFSS4u}<5}D%C}2#AEa!B+W22lr1unksx19N6&oy2nV3MCMU(C7yIU_ zKfGOt2-pnYh?Hxwn=h`rO=OEIQ_I^%NzE*x?y(tIjfY>Opt8^V?|qE1+&-Kw*wq$k)jTCItG5Z@5<6bR+G+$$lVC}-j9?Bv zuRxnhSFJ=#le$=NEU2V(Za&%_-C87S*v2A#QSW_ye z@6h&tkT(8SJNtq){cD-abuA~6Nf|%3huZGLv3%QtH+`3|$M^q3)LBMF8TD&lkQllf zq`P})7`kCVI;25B7`mhpN$E~u2w?~*k?!tNq`OlQq~7~E&pGS;%vyYzeeeB`>-t?; z>s=r9%C%;f*5#dB`FwG=4^Pcy4SglmtTw~h(j z@PS_?%!5x@Y=o+|WB7fW&(-8#NqIwMQ78u{EV)EkyY4|4t{ZkQ<4` z*M^NrZ8+#W#kL)A7Hr&yY@pwE->*;oOE?CH9C83+G;8=b_ZtBx=>7=nD|j0M&^Mgg zSnr4c@RyDE=Z`NEDxH*S&5ICjG>_^cvod^m$5&iR_zKmQU5NlThI%0z6A1L)i=g!r z#gl&E`y};5p7}2RGUTypouvwg{^dn)=+Y0RQNi;7vi0l7^`Y%gQj|#|NliRg@U+TQXie%_hUWs_F`+5Z4-0a%G4#HGp3Bdn0d)(h}0|HVO ziL;Q<3VZ8M^4|QfKPmYBJbiu zTqdtBhswWzHVkjTgXKr>C`71{v-uU}@G5LXd^n!|Bgv$x3**=-O+tM3Pl_)MMEWc& zS@{LFfBtz_|7=X>OHA@yOH*Rpq_Vtqj?@9vh#7~6u(wT^-l=bN0ZwoPOulL?0&S zNayBA2-V|hx!!631k7VfrQte5FSw|UWaa#|s3j7h^n;~BvlOoaFK{z>EG9Ot{xmi> zZNC1PhMa^VCyS5PsDL_Zp0AOpt;02-02_}X8oHe|>>NG-C@wK8Ul5GlsTdL0B6yZ< z#9@kWb)YF_?6eQfco%DbI|{K3mHe#!()U7QSPO!~)yZmg^K%rOrY;*C4o^<4h7to+ z=h6U3yY<(2*1~|CvnX|^!WP03WQ+BCw5Yo7?(pC*e39WtyH{Yt zUdB9mj_B^9I={miNKszDMD)FZfyQ=XJ> zY_hTM>4B1*pKv6pv zn~W=->yO0hh;K>|a>Wg)7*zl?{DK`Nu5Ax?w)LL#kyv> z3^0#nhir&1Cme!7&lHsb#L=Q|a--4^q>brwyl$NKa~RPG*Dq=><~OIW9M^H3$BzMo z#-raSOpV)MoG@yJ^vP?s?9B_RTKr5CqYir32f7?azP2A>o&QrGD4=nBW1{KdB{i%WAsO4ZMFRKr^!$C z{}K^FS29oZmXF6>rHWL&2f6FKg;bjedB=gtdtcb&A{d^53<$_}rjvn+F&=-2GA*xR zh^ka4bXaq1$KXZSh{4O@5F?vJmNBGMe%Gn0E zSK7sT;m(Gw_iJs_3Z<&Cu}lz-S*4fUBmzkl5QX(_$;8g~Tm;^Vx~T&vx-Tsp(V@Ut zwKHsD>cm9rvg6n77oeBoFU}>`#5qcA=2^@5 zV{B%&2C7%<(t8$s>6%`6LuRN zG;}neC^DVgoZYK|xN4IwQUtfIz5?dJ#_TRJW^75cHUZm6&Mv3XcMqCV^GC-@UGdu1 ziK(!wqVGvLeDUCb12#ZAz_3(X;NazxV!}AK3*&3KeBs1|)S7J?5aC{g(StQR@A&sMXww}F2(-+`c<)DuaYnC_v3m{8UR5J?{Vjn=jU&Z zS8fCFWo$S@@bOY`zL7j*WzlB?>E{7n&+S3sw8=V9=Og3#~5}f!E&~{DUMDgjx=HVgb0X)9}Xqq2CFpm|mUz^e1yQKMmS=JTIq5S>m;XFnFqe z8+DFXN1Zql<~+z>ikOZa7|Rq8k?vU*uDZQY?uw9Co&u86o{lvV69^(>t1WiNTRC0U z{qdYdS9*%KmE8xo^5mT^*7(WX_DBCz8SVRDjg*rY=4~GIY>$smUhMpOrMyAW>YsZ! z%7nG|7xr+W%Y$eBX8-Z8ZtXlQoBpGEsmO>Y8%u~Q;6Ii!e>_=zeC;EB1-zg{%DjYw z6b%a$-`mF8Ph;-8HG$U=ll1#Pv~RF$G|?LDWVm-)18B2u5}!=IlthSQPN>Xze1)>y zLKDB(VFBRp@)&`DoN8pe?d@&Ab|PxjX8#fa4+Vt7r^&j6oFDs0OFa+xE(V~-;}44J z!45s2dqOI``Ly%^n(c@T=KnuJ&R-Xrj()drZX%n-UMF%P2>QcsZhR&Sq_*3>lVPTs zM7Dsj)G!+LnQ-I**QZlLR2xK#i)!DzhPsZA9PX)oRa3YfY4l%+* zfw|vKmF1&A@$aDXzd^je&O1LnU(m`-y!2fkxtDq1;fUGzF)~*nCez>9aSsG@wzYa* z+n2H0gME&O1qFqDPQO#pUl+gqTjj>*p5$O6s7Ro9)S(uWUh3cwN) z_a)T21Ned?>>}d+lVm(Z^hrv?!IZNl+D$K)V*6@g>|~`r^>vjY?7eO5e&;1a&03K@ z4+KByyV=)oeikw>J67j8gn1RhNc*A4)xl~p)+V{h8W{s{3`{fUtPXdzsllAgL^-dAduLAJ5 zspUnZr$LyoZaAmB83pa$r7~@aNo7%<96HjZnoCNN_s1ThOiZulKMlT9V*uNODE`yx z*3n%Rmr?!4=(F`Gt-(WQx4w#`KfbF&JM*p_3mkeSEp?TwV@Je&D`P3}jB%lg*GC%K z@u`cHY7>Pb&zh3c>$R>)w_4e*+)xQG1_s*ZH;cuRo`!?u0Z9l*jN9jmIY^ zx!*kw%jy>+p=|W&eYx1IMQatsTZBt)D{r12P}59JFV;d|B800lxq)@*9JP#h6!gTX z^$1uHVnNhOhh2Y62EP3h33#}-I13;3#7k|bdipfxsp;^+LE?tmoT!ucVj&*}I2GS= znXqMfI)Rv5#Y83}@T7+)%_aOdI`5s15BK#7|Gj?|vV-)>&yf|TzlUY{J}l0#R#)eP zwOPNA0B)y$(y7Fm?fs1e|6qf|xrG{yosaYdo#n&q(l;^5NRk4+#JiEge-4oYTEW|f z(j$OT4VD!WbQU>e<>?z8$;_E~H5|C6JitE4QvT!529Is=@ZmLCtGHMG(%+N)KdXU1 zueaXKE`!x}g$J9mRU;=3oSp3!Vi#_)%N#fw8wVY+RNPeG*IIYY}$ zRsO&0S;f3AK#r;NRBJOti zwM#nq>h?yh!$QYoDtm$k_}S_6cdp=^Uf$kw%O<_|@n9aJOtotBw#1oa=k|v!=QPae zpHhX^#UC3InN+i=bKki9CRNrxFA)*!y&LP(Skhx6tj-sVq>8jY6B-G{>EVbcLQ#uA zq1fTUU}ajP0J`#i8$6luey^yhrv-<*17+#{Ub``V3)tQ`>eH=W;g%FYD*N)Ms@30_ zc$522!01zl+gF<#@}!it4axANeuMh@7*B!^UoZcX zI5hqC@p_*piAm5_q!?cbNCv`X6li|emYVD=Pi!(8$<0jYP&Y`Z685*iqc!T6AZi5)FfL|DBn?Ktnv?f(XY3i27R4Dnb+_i=A9{2OKAa+=K~>gZ&{D`No<# z-pt}^LKqoSm|B>L<{+~F~G%gdO!T8&_kQvXRY%Qgh0vn=Q3T>WW?kaBy*=Q-D)2KCX zZC>!F9f~5?5qgV*;*VN`pO|SGP_R&CIAijzZ#fNO#t^GsZBZYd3rHm%XF1KfyfQ9l z2v}I%_{D?=a@|fgSL!?R!~(Je4TmahTOXHytq{M<@BjJY+^c}9o{$p-s-$wBtk!3? zlqSoV#8#a3s&KEBS9-uWXyi zD%G(6h|JM!Dwn7L$+AsjqqqCRym1|0Kw#Fr&*@fz=z9O;WO!zz8hu)kuG>bw-Bb7- zFuEc7kW=6IbYwe!42!WtM0!i|CnsxYO#~JcA`0P^R zcHVNyIZG@EF(+aUELYU8`RQsrQI%A-nIPBVC;NG?~G=9w>f)vU7<6ZmA$bQH3lSFCkR&=*4@LGTK6Zp zgB}7q3%hPdtAd`Uq~$BqcAEN;^QPR_N=h9jVt2Vr_`1tZb7Q{mG& z30LZ2jG{yK;NSn8rz_q_wNgj{Lh0TIR4gZFULqy>MTbUjAAz92_;Fi5=gU`=gPTod zYZVMp8_NsM^KSvuP(uB?Q>CZ#=LZT4KPyp-o#p@%r>tKp*yB`hW_kzWH4_-~S-FTo zjf0e*G7I{JzXhM7nZJLzLDILxJG*53xx73TQuz^+DGc9sZ8Ieei>$WJ?+$8EYd$qS zaNJ0&R-vMY(A@4|N@P@Xb@fY~UR(G?Qb4D#|Ms=L1BWAmpG6*1(b+j$>1~C68QsOa zMrUApkm*3 zh3n5Q&G|a|1blz*;}c-MXZEAwHK?hVQe`fZEm37It@izCRdtumOIMnF*(dk4#l?}0 z?iaNkPaM)*)59nhYFwDd!_K;bpL{>Ki4Fd7*=?TuY?`OAMCpxT6W=OPL(>`xtwO{?&cTA|dE58ky*VA)?CR zncJ$V*GTN;-E`UPD+!!3bwD`n{xGaN_)beFA0fyuHhJQepaze<%*a+FNwxR#YO1rl zR>Gx~8vh)Hb=OPQ*;^om4x8Li{E&qFN!iam+vaX`A?VhIb`WbMJ#HV?yVcS6llV{y zGfeduxRs;oldYD;V_iC&8EI%-fo*f0-D7|~YZ(EAFO_LtuWux^{O7k_+Zz5d6{u*$T9ZRrE+F$ zDPmK5uD-f##JZmLem2xZjEv*s8uflXFQAyV_&O(t_M2O~wv*7>MRpR?W7ks}H=b8! zm#YKNF@pb{^bG&sRr42xK5|Ab$mD1^bF_m~jk}|Zf;jdWq9)wGqEOVRM#_~H^2Xz> zhlOi%vw(Vo4g;TvJZ8`Dd6YO(UV4yC=kKU4`-vQ3U@l1)6q}YaSs-nIumCl&zccUB zly|HaWUF*v3?FueMNPTxK}IFf>9{sj^Oe<9`4chB65O7r(fzIt%Q1S9uhI4d!Qax9 z3;g08)-HLZZ|XnsNl1+S6eM$ECy6nMYyaDE?l9F;0w4|^F;zwSK0RIFK`V_rk8No8 zJMUk;8JV?{yl(l$Zr5z}9WoDk5)2tpw+u{Po$BaMj<|Q4XG!Ya)7011=!2)lp_AwGhxELFe^YT* z$7%pb=pcK}*Wv*I*u zp%NZHOF(#4)LKuTieG`BW@r8I>~t>E$JGIh(eJx@->*v;PQEsOZJwWMU6tO@4Z=vm zS9;UU%k4cW=IiZkShKu|>x|g%dw2im zp1OcSaNLWrF*y3S9OCR~HSkMKgv#*ca% zFK;hCNulw~u75z(w52vrEkJW;S5?sO~ zKunXWkwibZ>`t!;EPU7BW5>q}z|N3YSEU?L;nvBE&A7nr8!4BFV_3a=8?&7!BNMH@ z`6Ia`XwOY%Fr~)lEmmA!eikD?J+IqZuf+NjJ`KV(=qY)KokWNybw|Jd#?|z83*Zor z&--7YVnFd(g|Dm<@6Q8YF1dcsSz8NkK3(bSb9Uexo=bPW7qd@fjHIWAms~ec=VNFr3 zZynAz91LpAub+3W2lQ^k<)*HAu8{h#CC>vB@GFV0kdq#+pH1;mAY{xtQZ(hvum0B!^MY{- zR;~>bX5!Iaq})s!_*x?9?Q_`lIGh;?S7qq5w!1m6tBvY&0NgDjkZJVW8rtVM)$uVA z84#8Z?*a?$005DXi;of;U{la$=_zskd|0^AJ<{NE_s_Ha;=vOzUf1q7x1H@#@t$tL zGXajfB1d!@#+`~DhjN9^8`%6YR{Np<78 z_gv?n)Z(c#QpblN5u~e$aZrO*iY2cW?YaW~tQXN2s zaK<&!KCqEe66+hWVLdoL-yA%4v%X(67b2yy6ceylI!|yi$V~(*kG`62qC82NeqT zIIx_pyqB!zok^zTl&>DEcB>X2On5S7KJk+OmOL-K`0u%xd;a}07myWVlLBErcUMQd zB};Bb5{nJiyP8WZ9sg(W*;jxttsMH$ z((wnU{cgf-=SxEF?eGxoekHHehedX^FMBEc)JD;>IcFKjZvGeEjrwZyR5&R@_V0p| z_eIa`-gPSRtSbe=aoCyV(pW9olJOV`(VM_>VAXmZh1fmuWjG^aWSD(GKy2W77ujoo zuiFS)STL-&|D%R`wmbnrsJX%l%q4s;bK1@ol*D|_f5ptR3p5y6>4<+e_|&@hAwi#t zUyq20YkXYC(#+*-<|_q+Tzq+%pNG+@lzbB$d_cahmA@_Q)}9%aO+o4`%)yNyujETW znRDFG_tZ1;>{JF)uED-XLUE~c)va%7j%&Iy5({{2@n1|NdAz%#)|Px?UPSzobx_9A zQsx@uzh2zEASgi?gF!zg4xU#p5uq zZE@q(d7DcmKJzh+L6Mz|M1PFpELn^#Yqr3i9*7xB#z2h>nY=}%JGtvYv1bL+vs}d) zi{#|g{W*JR2mtXB4yh+`MrHAKS^Jv0*+ZX^$b*`{tylOgUKsS-IZyICl^q$ucYjl5 zjHr5KbTafND|`Et#e(1(qqdYska{2SpTOl3)3qSwcakl!+^)B&%H3SFJIwFN#y*@b;u zyObrT?$>r+e%$w8>kEAK4%sbCp_x#q!AwdOkS2i}m_EyBo_V>tX zXa-dAq4>KD2Gu45*_ZNp*;#UGaeegpEYq=k<1-(L3~tg64^KA=(AQ(2^!ck&X`IaX zm=0WRHz#lt1duzD2+I&GpG+>J0LB16e^M0O4Yq*f6Oxdb>72PPb__dv9c2Dc6g-R? ziUm93CH#a9zXjo#utmOhtds-AdmEubsXp@!HPhT1H@p?b>pTp$uDbJmzQp@atuPkh z7A&Y+Ka4dcGgMp>ZDf?Cq|Q@AAY$a8k}3{!O)f4*GN?5goDemS)(am8rEu8{B@*>V z9@MFj@6k1o@4F+X84Sx>Yc|j-vWF1?6^HmQ@roh-WCNqrul9d12U#b-y10n3exfZY zZ^^`a{u6ySYS@Jf*~;5Es;b#4%XQnkE_@`sZrGm*E7N~l4u{9J4xqZE5H201V>3*^UL*D& zEG17KH9nwTw;$8nhOJ->Hq0`Ojy1Z{76+OPArZv~8Yd*O%Ky$7) zZq@%jEz|g$Y+0gBnmyg5ePx}pVE_GjO6EP1UjguKlcfLjQmNXr3nn?T#}bJpj^J-@ z^-;kX%s^Q0Cq_tKpNt8m5Ib-~Wa03LzwPJchv)2DgwZTa_=L=iDM}i?VpFl{eb_Z- z%J7c3n?$XDZQqA?uM|vD#m2^?R5Q3OwWKW>w6I%)5__Hiw+Lb24Rw(Y$98ph7K%#U zsBXp10mV_#iUpJ9D1AC4McxQ!f*&TpNuRnQ0O1NtVT0;RjsaMXknQebq79V&Pp>}n z%k)JZs+LWf%eG>>e5fPcW*Ve`=CIPL$tn9{0ioKr&ID z*x2Gy(Ls)MnpE8YLfi}p;liy!3XEev0)G?7Rc@Y)Q)he4Z)X8=U{WI16`x~n$v-=( z)Y3s8+0Z#gzwO>=K1>67^y-1Qo?9zm4l;VXk7<}zsQxrXGa3cCI~P4KBfrb4o06TH z=kIvfWgyJ@u68-It0n~{x>V}(l)uHF)rd6Wm#Rigy}!gdS$+~|S@T9uB`b3ppVR|+ z(xF(9y93N~+*eY=`L*wHd^`6nFn0wYYVJvteLpW@S_P7-zO4%EANe3qZNV?s!ex_| z-S!k}9~+xie1b*}Vrk#Gp5L~+iT;&54;lEMvfogIJ=y%DEFBYz_xxVD?kIu9N&viC zwipx+SZgdt1T8}{%DWzjCyh`r;lk$T<_{<6!3D)(($)1$#^EEB{i;9<_8q1=KDujI zxzv+p>C@$3KvnaERPvMKgw)AJn3y|@p#iKg!0 z8<<lfeP$QAtQsM#V8*m z_#uG1hdctC_{JK;CZ#{g9&FPMRw%1es;@J02ntHPyGzS&!<|(TBz1mmB0d&$9OXb! z2-dbol`C!iyLRt)Q5^mA`!-+UQ$Hifp>8<^HF2PN^!Ex1Ls}6%!H1Zi#(Q6`Bdu`Z z45VaaPEJmn%Lz*jrRAAk!MLWMMpQNV$7i7I*1Ge@6rW^nz$_z14VP~La=iTePNgCg zlYKDkH!}K7zWpkR;mq1ot^Cr zbo4q=j@`Wyg{S=)d&JrFU;8T^f;tA&=;`CFX3*NFx(3xkVH~G?1}#EcoxPJCArl3< zT>0b4(E0GNPWpn7OU311zYdO1JqGZtTHDKv}sIE5o)avWo0sMZW11isf+YlnF-*Pnh9fR_%IIAXM!zm z5*z(&w@7E9z*MHAQNuu{d9o2z#sA>t(=6Eb4Ft*)w5^Pg#UJ8tyP@4a`{lOX9o7)^ zdrBr=-9Fcf9{3|t@{GkugSBl|*qVh22T3m-`sC~)bWlu3E-L$wgJ}N?h(zQU2MQbW z2sW5r2e;G!bg!MeRO~-kS`Tf=Vgm0@Lv`6nF_2@%sA=-0f=&4}cF~A_AnO#r|gnu<$V=3Gv zjZ~`Y^OQC<sKu;&2>Qwm_8@Va>82p-J|tZA{KzAX;JIyj)6mGVh)d+0P>ZuMYh<8X#yG$ z5NKQ>>NsyBeRHV|NVMr^g$6NITw~|(!BNCQT^~@*uH`#GFE;T_@D)*0l;YEnSjLht zx2miE{kUT1BX~xHeE*x`P8YqKX#?l3j>GpfVMa z!&K;3ubalyDYD@x#T!~lNE4cg=)P8Dk_yfuMV|0Pv3IdMs1(_(A#DZ>YE*EJ{+h_8 z8gs>*7pg`~XwNQy*}8RvQ*GQ4?p)heP%HI^@YB;{$u}=j1adc!rwjyqeE@$0|3L6H z|LjV(wWe z8KEi%0S*pRsq*TXPx>`FE9kdAo>SLP1OF|2nLTUF%(EWZGZ&TaeXZB~ zDhLJkC~xCy6ot{f=;LmF3DGIht~>0p!Hk(%Li(ug<+PeffUH7p^YEM9o|Sic)wsB- zC9dF%dFL}=<0*w2p%0Sdhnw+h7wgEf5A4(4BM)g8ZuVdHjcZI;VNWc2P*ZApj?5fas$n3|edTO4`4WH!|2_8zOY?HNb%`axa6;Ekr>Fg{oZ zjhTB8E;O6v!8}D`h$u<6CB7msPZy~cWXdke5dwUizrB5|QX=0n?sjhyRnYYoyOXD3 z_h2-V{urlgf}mw^MeU_EyF6`=58yLT8_)~L?{Ps;CUC5+8qD}W$N~S*ZhQB;h7CJ^ z+x61PtHgPd@=eH-`Cmp38RZF1;4_i%yj)#L8n1sjlr0|ep=Xm`A3xMvqfllHXUS5V z4m*2zx|KAspsm}?W!hwRae1=1m4maaO@|XB$}5-1_?$HG(L(#luRqD3w3^{MQ0tQGB1DZUc)q$VStL?R zK=vp>*%lAEo)IW{t{Hi@i&puH92n%K<4It%qiGN%duC~_C*&5dYozvJuNF2&)8e_! z?K``$q+LRw$3=$WK_Ew5-1mY84V2HQMROO_9pM)6!WyT(IFC0OmCsNcUsr)xiP%Fd zMX2N*G%;UNlQ>=1Y8u8)d&jT_R;8R!}uB+ed%@$-*{Q%8zlljYK z|1MFbpZIm}8?mhdXMpSSYfZt|kX1#In)Szc=tv!Dd7oo_mD|O(yt;BQ56F}CVzckM z{Tb&80QtrJfk@g@IV#30=-0d|7c%#!$%3* zd&s^fE}@>?{aNoUVKX+wmZ3KBx&Z>^+979aY4~fJ+cQ45_EXVto$#~S^n_!zg1Lk7?+&W%HJS(zGCH%MIOvU@3PwmZQ@tja6S*jN!^bYT3F9e-s zc)x3PRpuu5&Kfq+)2IB;OMlvcvsz_FU}L-$!;5@#dINHE`fCIT4~ap>fD}iBo~`jL zi+cq9sj?iZj9*kk-&I40fYQ?FND{z%-JRwSBed_6c%^UHt{24BBI+hmQP4rGFb3I6 zJXSW+=ojq63fD);{E2*)Ox{W2BR?-u3qsyu6+YgwP8;XbK3CG(JoF-m+>;f4CSPzo z=d$6>%3-G61!ha-83x7z^L?kjE2^gI5~eL@)~g@Vi9Hlk-lki34sTrWbv()gG~kqi zHIX!flNE1JiF`o7ze?dF71o@Iwa?k;IemK*R$eX*s#3#F)nR+&0fPe`Bs$338lG>c z!jzKi*ax5r#BaYeDT=qX9h@C*b@x1i>G=(;Ua;y5rp4^Jae0TPg!7Tn^8$rFYhBqL z*xp%qa$-qLtYNsoX2|a;YF|tOmgi9^+msC3nipGhf9?Qm%Y@t13wMf(wQVVP*A2h9 z4tL`U@39|S8KmBuS9jb1DT1bP_+oqeq{A9&D~@#4Ft~^R_mGj4=h;<>iy^hjpJR`m zK*Nwe@!y7l4+*ofrdh<;bxUbOAPz>MOP(FnX%kqy^6#>_d2#3rpMe zGxMO!8QzOsUYU{kaUn?b0Ud*;U>@lN4`I$yO(XL0$v{fmUVDtY@ik>C(r!^#Emo?n zt!l!hUbL8uKcN%!Rq#;Xiu)W(@Oeu}Zlm;scJM~|e{f+Fr!DKTSiT{UjAv%l@YGZ*x~6(&aVTSUv-VncBUjrA(z)@d6a`EZ=*|0AjA!~ zYTY8A2vCer7RAB=z7=3KO;bHMJqEB)2~l^(M=+XP%DhGp-Itx)Y`maQdF4;nt=hqf zcAS~l+cN(wES5WSKL!1sTM77uFsl#d238AtD#yd|Z`L~*0hw2Ud~~A6y9erMJlfB0 z6`$(u#*pL~-_dD8)cLhZP3`wdv-1kzS-b#R5+bFlLdDMFO-Iu!RQT?tivQ*Jv<%QD zoo8vbyfuupbP?o`i=>6>n6FGGKlw^}d^TAwQV7IsT)hDH{D*z`fE-mPn^I=Po@A8P zpt6ZSSqvW(n{%OQA%!#RN=FYc=J z2fW(+tfdVY!qEQjfRzZsrGl`?5NMzM-dHug3}YB?c~(ms3qe+(0n#WdYtCvAPAO|a z!CPjzvQ;D3dMGAIaN#WzoH&Ky(3qI(@kxz(j{!A&3J8c}0FyKG6YQj0i?oc)sgzfC>v3Y6aaS<+dEk0m>*HkGx5wsR zMoj_Cfj1}C9#_a}&iX|JRt1SS!B4kc&-}&MJ(Tad?zLV8K8(2pZYuhmuW4q*{pbjx zHO>Ll3u_e(HunZ)<@UPEo7Cfz6AiY9ph0*ZxIMF=z(5~Gu0nM->pi;G^umlbeq^lks<1cPy=6Tjf?t3}4@^CpW7U|erBO1+!q83RUt7sBu2V~6myf&<1 zcA9rL&_fuA!H$?#^H1Zsso+VO;}e=T0$AX*MWY#PZzx-&a}Ar15ej7`F$XpXl7LNI zY(VUhlNL!7{b?gSH1NEw(8B>sJNQmD@s;!_UdN-=7pDllAzb%`^rfpN)`Bl5RSZE<>AG6b zjU4w!s)x;8G2g;3o`nVCw@-zZ^15HJz>H@ab;%|`Wj zNW}s+=*Eut=x@Q=N+_k2c7qs&15BSh=zcdASPCstB#5Xki_tG<~2}!5{uQ~yo z*or6G3%MAXc%sV8gu|z^F%{TdSa|-;pC>yCx^I=r%gr9L%?Q%BclpW3IQHS&%`)Jw zYGFuY(&Wx2sh2-_^~(J62~zycSmh84O={|1X7s8%+&(0~ZU5MTFYH6m6DqT}i<&JD+xc8y`Jik2X zV#dmqZX_Zy3S{^hr_e>dMPp;tNtQQGNF~ivpw}fco#j8<@)lI5$0ugcRCh*7WhO2` z9*`|5-RpjO-`Lm$<;kpHZ#H`2q{ajo2&dY@%b<3U8vs2V=2iBPo3V!pgy@?%G9n?vJmJb~o?VHAOK^-0jUK zzm_p(BlV?^{GTP`GniIZa_YJ>1U&Q5eJf-3i6fFv4nL2Q@|F1F>YRr|EAcM+zhC{D zORlz!ZT;!anb0r973CR|XVRUwKZvmLK25JJ0=gcs^TEM^m91l_L*aX*;~c7n9M)Ha z4k!@OrE`=0x*D+xS71gQz8Pk47SiY3y18fCdiBK_47&yApXLKejB|5yeaYJn_z)-? z@d4F=4Xk*unfuppl)ulpw5;0{9bU(!cVlzoRW`5mMBG&8M;|l?!s-$C$s`sEx8Uns z3M#7Y?D9f-Y#}T1lpn<9LaNqa*b%n6l9Chqo@xyH4i=k(akU7r2QF_Y$pvd2o*oo8 zG^M7pPQD;y&+X|Ii%FUgfUu%K!{r!|JYiC`i}X95jrt~R`w(1eaTQ-T(OtEuaq&qF z4FU!FNy@i>DD$~b$H&K0TCts(Rr?rpK@5|*}=of!+8`MFg$oWu4 zY~faqFnRREueR=4+<`aH1hUFWZT^*|9vsotP)x{It{%FN+l?P^x*AC^T9?0;V?fvg%0$~n@lgKaCk=Pur~oH^Fw$6{xekt6R>eqbZx1B1JjpZ@ik z!FEZ~)F-SQi-q1l%6l~%`W^n_Eoy?q;lsN}?Yp9zoUZ%oo3pskoGA|7wkIXr9K3$M zCAI%jZQPJ(-3o+JJAkg~%Rd!vuiRY&SflvP&R17=l8-N?g3gksQpc1*n|`n{(!9w_ zz_$!QT|$x}Jc^)*5yE&?fc^^;_HmKv{*U$p^OVLV7{=MELv#e7WjRMS)11d@u zOyXiel-AIh83K{6_H-~mAfcVEVE*mx{YJ6(_it=y^u)1N4MkmDQThu;{AMv{WPq5B z;*ri^4wp=~j;WQtBdPi2C9Ec~6%di%<}H8j?w^u4?d(1EXd;TQ7|LN$t>3 z9cO`GD@=Vu0bhtM1V^?dSL0dvqly+YgFBk#t>7CN{rXk_?;PwW&Nd<%vxcVoCi2~FdOD7l%8 z5}Hzq6F=sP*1VY*Jl18{8BXp4@&z)i>lJ{(FD%dfU|NnvD^XBPR8`r5%!#qMyrqy= z`U$M{!4Va+ZxUfjE)x>YrccLP00u{p;HJXK*|Q7t0kH7P_I-01g)i6=EoVhKJcMW| z&`y;cmic4$eV#mrpQCUTC^R0D66Ig>!;fYv_}EwQk}W405F)h&^|yh+2P?`2+d~9R@lO>Uz)<)k?q^i$}6`y+O%$zM<)9{DoH3E0YEz zgl+=WZyfF(`xHS3R!6N}wrU+Cc0Mo)nduK26(>2&YM5<}SRBJk)hxVvk-la7xu6=h z*4;&t_G=oMZf`0#x=cKkuUYeDHM$61($9-BuZ+KLtw&k;AzAVr_^&Xsy$& z>gp-QqKc}cWL2F-V-d7<+#|&{;WT4mPrm}*p6eLxCmKM-Th@eV5_80Na zJcwn)j;|8w?DP6XsVYP{Zfj3-%((56^k2Y`N^1O5STI0rR+)<*SY`k=@+jrn1q_Dc zx?D}BTvBuqu1l?0nDnUc~#)s zg;lb78@3&3^{Tiyi#O?KT7Z<*(Sv^mkm8}2V@6D1=u-6>xO2OG`}+1kq!^H~^D0wv`RhAk5lUq}6#1W24 z^1;i?SMM$7^;TT&j9jPKy_H~|Cpg*T96@FD)fU4U7(D_S^!$8tFYiA^5%@?NnikzZ z;?>lnpsljc-7gx*?8&Jq_j;q8Uit6nhV!|+`v6JFL_S4faJG<3A!LB7K-~xFrr)3< zgS}6P%O^Fj3uuGUcPF))&zBYXV`Wvmin@DN%+g0w_mS(~>l_0eLA;k+&={8nL`)t5Io7OWf{Q#%B~;m3^~s~X?cF`V3YMfz_QRicQJ$oIE?m^r$gK2H?) z%-}iEjGLc{mIB@6tN)&QOpK4v)K2a=hfI2TW|+_y!JR9+JdEu8PcRB2_FVZ1WRp>Z z!uMfDOTS2}ci&=yiv1N;od-5H2#@|K;?hdS6QvM`bYV z>|lw7%i18ehm&onfB3$D6EiY00#7VKZWe&+>3rzV1Zcb{YMk9+#1qV2xKPfIpFhg7 z=hc<6^x5)jF-^=N)9aY<2k((9YZvYTJ_!YLu+Qn5Iu9mBAIOfzc+beFT0l@@s{4XZ zPOAw1pD>u$&Wl$FH>siN4SXm@%6B<(ath<#BkwVzW|yp{s?3?Wh2E5Uf((SQDi9WU zEx2G$t4iq!$W}@#J?C(iA~cgo^Fmv*Rn_36k(e{$8@Dl@)M79Iw&r*LYduycCv|92 z=y`=lzDQ@1o|%nH4NCzHq7vIGiQqo%hmlz6rA2uZ`Q4t@?v8TSlb z4Pu>j<^LAlYIS!CYbWx6lYO+CQExODN)~Cd<(|c6=XW%)9~mYC(7nFl6)rs~ksJ{j z%Z*-W-k6jvn2eH;Z~Fcgr=3x*d5MK(A?ZxHxD$h1Z2{9&&qHfXD3vJ@W)5w_14)G{ zx^<|Ec)8c^1Vqy=v+Ap`-tUBFxv~BW*x(S_rco7_4&j`Skc>zTN&Nl}R8nG6wVtay z5&|@PfIVjRs*(zZUKAH{SY%R_Rc3O&{@8wA#=nyfSs9$M&w9s=&HRU4LWw<%i+>B` z@Czt%v1@8Nk(W56f6pt(ce0pqOouc3coC)yOfJp!?JeRZeiN1!iEB(}CWr}(KB1rf z;Dt6o=?F46mQ=FOm^X&9+f;C8z-^~VHx5^_!{>>kdlRekUEf@=n42%^^YD+23m&eG z&d&xPfI?lP)A6xo|Kx1K;?tKh33mzh#B2p;)r(J94%D$sxT&hUt!oCvv$Rh6_(Bbo` z^kjg<*0@T8hdZwk;9BGQ^>Te5`@L=iO&qV#nZ}6T{K`>S2llc;KPEG^cduoFD8gYB zP6l!D9#*4XdgJID@MPVjxG+bo!hGtZ#2n^7*KJFmp<_yJ9YVZ z{>iX_1?D_{;rwMm0Erndj0>TN-h`@DMd+nUSVSn zT&?kK0VZBq1w}L)Eq~rT4cuKXc(#>q?m+u6TrZtPb6QrBESVXktCz&aZPmk3Y5r~S zO2(HgB2f?r5&ABx;Tg(OQU^H!FV}l#h6*)Zxyt&o z;4#E#OAAnR5US#;s>wo}Bh)NBz+~`!uAEo;#T@>04MS0t*`P`22%kqbI1)$hw7KB> z!1(-QMFlyYTB9n!yGs&a;Ltkq1MUEa^=#j2ZP24M8DtT3RmGcs%()Zw$RZ(7b^>$+XrI)k*qV1m%WN}4MlM&xOIrJZ)n)m-KJH>~R-xfCX z{BQ?r7kD}no9ABDBoul5MME`xpPs3}EStl)?0J2XDYv2>!@5111*sI}2c$1*K$wKZ zB%>+F)KpFF@%n67HS+)hbW`3j|MoM7SCrNi5X8Ot-PU?k62KHJ>1i!Dmb=apbl;s7 zE~&>hVL=W`NBCemiy#u2abkRo>|=H!#U67(dL-GBlU5aP7Q3!}+c(8)w#M|+mT!x@ z3TsMp(i61hu0ErM{SGAsU0x^AyR|3XH#8ghVi}x}JJrzev}{Nm;bgHREh7aBKt`lP zl~W113_mf*1f{k{Tx`a@akNU#^tKNDW_JGzKn)rbmYx{5vgGVA&l6ko6R|0?_cy<;vxnn4nF zLKJquHrRs-WHb!iI~gYjC?@|z)Dnh%V&6z2uz!xf&?=v_(NHtEHj}fIjr1tDLXAOEFjv*|6=>d?-hZ+?O&MC$teo{&CW0#g0)EhfrS!hyqxGTE6 zGF;b}EB6SMA$LpDs=gvLKJ8N)vRP^e$yWLSs<2fqd#0OexoFvC*!iek@gqgY;^QMl)cY)XMLjsEQ24u#=34lSbNz(_9IZC!$3(x zWx953hI%Apl!6dPlP(1vMRDY3=2YI$@a4?~;Mzw0QVsU<8b3TU=QVINYTsFBoncBKU$@yeqo4rm@bQ$M=C{-N-} ze&01Ngslw;) z;@AHoY!6odwd;UZoDqAqa-`ZvAa;^X5f?+TGZ}Yanz~o$%t(N`V`A=Wo$FckqEZp4 zQ6KY{*cK{RW#=BJNa|!N!Sk1{%L4}ofG03KQ%v<|2(+_b( zhXa+jwa_n#esqETWb5Tozai7ssAW(BTmv7V2RiNrV1k($;5@mF4pr(YM0&Aoig1i- zzlvd#q26B1OOjn{4_8cBJk#xOrs9sOjOELYE@sP5=i3FrB>VpR0khuMs-72#Nui3K z10sSQ?UX5WfIW|-HmnL##jgK}@(ogi2b&Vk!D(-t87n0(HS(LhRG6j`@k~lb%^v6Z zP6;dy2YAnXGttf4W9pi-cD+n9(3D|zK$RCpL+h6?I`FvsEUC7<+ zTYK|gMOKxz*Y{b7XDeAmV8j>!*$2Dzwy>g5%>7sM^niX^MO6wxG(xts<}W*=w|&vq zQ?$`ViM{%LBdFdFzz3fEYu24&^c_1iz}{9L8et#6n}p^boeMr9L`T7VNLiMWTz;xI z%K{WfhI?}z&4Qmc#MDtbmiMaa41lTl5Q<@FHWhHOP7>#xe&SdqCL>s4w>?a==z_6) zH66RV6bu9|kN}eRBiXaHW=a1mnoHt1QA2WyLkvZI=0R(%H)Let19x~7DwKkFl@CzJ zNUn(~fx_$4C0(qv!bGX6a$eI`Ojmwq+z)(MaJ!bW`)XUo;P`AdZ;s8_H>q< z&$8*w-k!E<Ey_Na(sbSk{ZJFq4$muBr=3O)!&tR%cQAIOq9XGR9up**L`; z_IJ=Ev(6CVgqq-AJF=JYoFh)c7lFK(STrT|4(mVmxDGpgJ0jRMhIFkF3Tu^K9=Y1h z%|urQw<`xszzNA>&o>KTN8e`rD>P0l2BAT;qzO)W^jr?T^6Y8fFiS#G;HajC zh8K?gjXNCL@xI&Y+c7cRxmro6ji%fjNuh9Zn8h-2%?5PedyKHM!tIkX?fz?`&-R`}3}X<8&S zAw4h@E~QhK+-D59xNj0&D~)DVXmlP7KPhn~26jsSQO2u_f@>VK{Ku@tfHTjlZfwEM zhKS4MS0tgtbB%8Dt)359yX}Nyk7D`8z8agAO@8}4Qf_1a**d=@UAIOek?Y&1=L7>} zaJAiqM(R?m$ieiw=UZ~`IqU&AfQovv4mG(rH!v~5Y_FXMvBTC2do zdG$3)ZgBZ}(cVGd##>i8f;o3!)m`<&3z*ElA3BHDOeC6EEQWk`D$A)csPm)!F}1%x zp8We%iD~=5$-ZM6RGGXbPblrW5Cgb-qP-=6ioRI3152Y!V9aZGiaR%564PP& zXVN#Cb+N3GGJ2&#u}Nt@stj7a98!C6e}9>>r&|s#++JT!481O09(wJ#_2epEv)*MNn9F0-eAwSZ_DL14I*{n+t+NBeG!Hd9&!4bv2{P zrx!hV%ZN{o#Jf@o6p>up!yi(o*u>T{=jLz@FQSW<jdLxS--!97=*5$BynjE8 zm))e76^{4z_in6UN_JfN2>u!$(u}9xbMMWt*r`&q6+1V#z%jGGCn&n+OadhY=U8kg8IRbtGdb9};oeNkP#B*=qw z%D6P&@XJ4wU%M;e`BC6^JjewS{fn)rw5sVpP(#D5(~+zr-}V+iuZ^*DgshA(EK*5Q zNmv(1?-rG9io3=m_VB-=Ff?x^Rslrwic#a`Qv_NNPx^-`TD zvDA-QZ2H9M&y$!gNmHp_w698g^8X6F(Xdn{$eyW+TOSTxkLFsrf3`Rj*x2)XofCu^ zLm4(Dor{$sHC<_;(r7YZ()Y~g0faq8w0;bQPI`}ze3q3yEztyQH&?wZjQlQRn)#f% z$?54-uALXEuI(Gd4+8$Epz`t*sIYrWDov(`#ukVy&)13pVpQ%#nL;tk)%O6jy*`VCDu)JC`D{JA6gWpH}9)r{mE{M*S0v^@`uhWB#bji5czHFg& zO*8FBmly+&*9%m3$V|9w3(NSYg=28ovkl8%^!8qfmC(}7dVlrb3+UTnHY}`hOI_zo z(5=@0vGaiK)5gW=CUs1&Y{a`YuY%X98J0`%bQ9&03uM8yio{|=%z(+D+tt=Bs@g^H zarCo>IxCypFW)~=E?xHRuMe8Ku8_!|Q!_~UgBino!n!3124t16UVD3cgSlWGq~t@w z94He#yj(SmvC8C;u&T+=tv4mtLHW)<@*wok?TXl z;P+#q&}r|6X40Hgm-%LopWlsNB)>zv|6KOv%VID3dQGt2{>=F1yUs1$2dUl(7OZd| zDn!4OB5uDUBa+bD$M*}s8#kMjJ=m0K*`B5cc}h)IUbNe$w^2mctEw3U73vA>Q$g*P zPY8GY@_q5o@2vs1;p?beZD+z7504X*C|wR%xd19+aloXI&y~h7*Jsfx-~P7E-nx)q7A*Q z?K#KIt<7>n>Isu)nt5zh!m=X$U4On>uA8Fw*NcOX@I9qfdDS{+bAuo2K^opQmu5u# z#H7>Ec24dug!!$6$^Z&NaXm+bu8~d5PBo9pUIlQ5zSgYMmB#K|TmTNx#D1+zAwWGm zBUn$&s>4#}&aE#LS2aO|@Zscgj1z&BG)#HV7SA|tE`u*wn_T8`wV!!_#4gIx^7pLM z6Yi(9(s1&tgL_#hCCh~fsym*s1J+kaGe=I>DH?i42oV;+g~(tiftTzlQf-^*r_Bc7 z+QGP2)KwgtkCOY8MgS))As{VM#fDgCs;NTm>G724sdHyjuA(5UweiL`$7i>RNDW*d zQ0Pjdq0yHmj}4^6K+LF~9Jw)74s(A~z70z@(X2A)D>AMe?9XDY3v2E;Vhmh+V!84p z_=wcxowRi-1QX;5dCWDU0!UhUsi`&-)jiXw-kBxzRFm!d?O#`#iAO54JdbW@DOsiJ zV?K-77@fJ+2Q;Fge`$Y|gLgA^*?k#SU9LZ1J$3fSdf<@|AyButdkNP(AE}sveE^=@ zt1n7d0|l=$ZHCYiQKJzmjw-FQpHApql_f;jFhm?qebu)UQ4<#F-c3McTgMxyKuK|Z zR6_NGcYzOT9m+4h8Fs0b8(F{DrZF^sjRROm78(iEx70>cLBJtk5I5jPtVfqZ^V8Au zclfpZ)eb0)l>)OI+tDZaZP2mcHWS?n9#atgQ4G5v+1!ah+=W796r!HxBZ zA1Oa7A*`=_VERVm=hYmZe1CI+-)BKCV@mS`+q{BQ=vL_A1RR=0Z0m`J3I>8nvw zOZ3DrS1T01h&8Uxwa9w&=%PvffobQBVV}_9uT6mD&$2yweGizSwj1UP4Xd2^AGz&5 zA!lvqU8{8M7b67*RMqf_RP%8 zLIX=?*RhmVq7r54_y*<@g-BA7#PO_@v71}z85Pkhvt|!+K*>N|4#3x*VHMTwVV9O? zSb?Wc-s=8{cBip*n)okFoO=+CLXQbOs#h>I+oBF$wJ*c(NjEpm%`g@%^OcXR8TXN$At+Hf#IPZg*cB> z*Ary+tle!>0gLA%_RO)hkcJ2KE#MTX`v&hY@1sHzjhsD16r5o+ih3GJWbbk}ulEB4 zXI#H2^P@5|bL|Ve@Gu9)o0rv{L^=uS|h#gVhNZrb`-Oh5^BWN|%h^Q?%gP3tCilZM$|lY{ir&g4N?r!%b_3 zo;+IA2yU#XxZO|F`?oM+@`$~=qO8VHt#6)ttCjK71Y*7r=3$r+179urbN)a?i&CjsY*%80Js+`bx$VNbif$i?e-#*OIx9 zljB0TC=ZGF={Mp@WQR{XqRvk&FKYtVf0t(E(rs<#NO-JF;Hzc`K$s$OWjyHO6=x}| z*+*6JV4IxhI=447v=(*Q&(t0|Pg^P?JHo3>eTzwdsIv}pMW}cxhBVS~cN?kMOQB7f z+G2CumX%Xubrp$uSv8-15KAk)^dAf=s;JnnhnN4{2)cd*kV8!Wo^Jh?@mF(ym5pm( zHKe}Vt?X$f+Qx?C0zl4t>Oq}{bljnyCc_FW2`G zQ_1(~tJzY+_+?%~kaioB7=wcbdM~yihQmeJ%;M8Vx%D8tX{n!tgftAWXXi)qm*9De zg|Ym_%W{EfFqFBZSK1va9*ai`!WI|>OR(xDn7VdE1ndWg$lo4Nzq+b_%lw6>)of6l z{-IF2ZR+ynFZsLp)ArTQ08$>S+kC9=y|Vbi<{K<$%K>=KHQ$t-x0tO3-X#hOPt2g# zdKt*KbcztH1fE=w9K((VEXrD2Skl?;IZ2)8wMm!|3xTP-woNjhmRPQ_j(`&am~8WLnGd#BVjq>eEk+D3IzWMp2;Cs_Y3D4z@n&(@m;R`RfTq-}hlG|_nH>N3| z>-uZ+{rr9@vV)p%Y@AQTBPdMmX75P$@;KHuOK~JI(1g>X zC?%OURmjNcM6!B1rK4EGpsN@;`CFVx4p^6RQ>(3E{nbu`!kelb%0}i{mey`j*f!J7-y5f>G zXPrlV0C8WIM;~Dw?L`L>C)U~|t8RCqJzET*@4)JiOk&ApizQFipU(R#$j4}Yos#DH zJPQ1`$=MhD-{VCJQP#rk5x_o69C+?*15u79@|3XrnMw5Ss$kQz^%3BHl5%;v*D(i5 zBG)5?P@rh+>?_!&6YX%z#Xp|yB7@5^_D}-vgaFlhdb$Cynf+eS5cK>r#myrHTV4S$ z`vku6;anAF;IxdI{x$EnR)_u|`EdMMN2E$|t)xxjcnJnEHZeClT)NUlqL7tOJvNm% z*V;8G;phh zcGH8SOop>dxXt^k4mIJ%_206*ulB!{;pRosQA3$1IXXl|Jrtw4cpDllL49jX>PQPP zv_ArB9c-_*b(QdI-W3o%OGWe<1J1I6M^;b*ktF6utF!7nK1Rl(O!T^dYsAmpAGWn! zIc~2nRT2uMhQ_WWIh+%xD-w}YboV*X`5OnJ=DRYrIjv6dQ`@nkoC*En;dpvtHD(Yn z)T**ix|X9)N-f)t4VV{-(4EA+j(RI3_h@KK{*uehf8{}Sn-dlgyv<4Ec{NuMoT_D5 zv(71Z5Y&16)$Oo{BnZ*E&5h8&7-}6Myet1Tuh)05L)i>L3ZWw+ab6VA@x|tvEiIDH zn7!%;i5Pk+2*o92Oa;%=^M&Ez{|e%JuV8_9$FJqmztg*;8($jk4VeAc+>y!n$K|ip zQk^eC2zmwY35S4Lc+)g40TF5nqiK^XUpl;13{_@8?QT>#-W}4A-Lg4*vo;!6#Zas( zARaXyf$VY%5$8=8^7ttxC|jSV#7QC|8jzn+aEXhSJrUE9yPyDE_aNFm(y(;eYke@KA6y*U0C|4-lG?(9q}XH{pCU#Gx!AeW;WVs0>YDc!2_6JpE-rWu zF*Y>4Tu%gX)@rx-^P3ZSrFEHzH0&5_L?}$E7j}upy>nhe7Z<@tH9r6w#+7?f zjkGE2D zw@X;Ci3OM#1HAgk@Tj*(c)^DmQ}0m_bx?SskUmXCB7vrpqZ=;}>h0Wef(ih6BZP^I zm_?_>>Fheq_WrCW0G=Scl$w@%)L((l|5hRx^Y3}`p-B0$HKd>KHk?-pUS3jB5#U^u zxW7>MdMjH@v`9Q8MV$?Wv=u0>s>plRnuZQuC6#b(&xaO)ror2o)^ci!Jg2*JvG*xK zFg8AbZh`Aq0LzW#xx(!VsL=#k zod0?G%h1V;r5ZqC!y|sc2BRY)CO&wN_dxl(XW;P@or53C^1Z=;joDcD1X<8N$!+$I zTT24mkW;X$Hk`R8$pjds0g}}a)O1L5=LYZ~?KzdSy<*f|_VR zukt$<1m6SbFY+%pDgSKok0pwS3rWYw$SA1tSmuzcM%pMj zE=KWay2wMOqYc5=G4yV2SzH-?QsK#OZa%YXYUNp9?XnHR-2v@yd7Y%AW6%e;bb>WL z$EK+w zeXDyASvi)pNx=CrtL4Uspe)Q(#dG=k%;Wgj@n*&MhTN^?)`y7X_~@MV?WBq0z~Fs^ zE&^U#BEAMxSXLlEUZvt*1!nG4e_h>)zwFZT!#|_ui`T)WseogI;Jdqzy;frdbgF(C zZ=A&Fn#bb`Zq_26a1w?RIF^V~%*!}9?pPgO5y|*6FppRrZMs3c-UMGe-_mJ@3w^?< zmFyZ`fBQNguyF}RP<#=x9b9!Erzyb^s4p4Bh-80lJ|>`<;+2lKbal_r+{@g{fK9t> ze7yJ_C=LDj+qcNZTA?llS}fW781`k@Se7~c+{xQ69*mWCE7Yo9GT9) z+8^3+HG&tMk>R_y_BLpXge#r*p7La^e@Xa^{3{YARxA)@Q6G4V!h?0>zmwgmgOxXy z4sK_6Ov{cx=Pb~>6RjTUr`B5CPq8SNfg>#irBU-steqKi zB{Q9ojo4#i;wO7QI4t>ehojVKC-q#5YCcAJwkjjdo-JmJANzP0#$zPa`Jd42zZ#nN zyS}c0B463Cy%1JhXy%6=zm-oW}xcb^0s` zJMA~2c(t|-jg3#ZnkOfxwTpDuCPH5$ir8v$Ok1dCBT}fKh@}Ym*<>h0=P(B!`0of3& z@7v18h7EmCk-pO$Btlc*j1Z_jzEb}nEpr|+GftyQEe~ys>=p|pE*udSPFBD~;EXWU{{q7c#VRu*K%R zpLQw%zhK$$q&JG82-9mF{*YFYS&&_XtjFVK)*$yTgC%dyjHZ41PJpwyN!4u&+>loS zIn^Jta)7$Fc&Y9F^H>t#L==`)q>2oDtJ7XOPY>AM-R^}&h~sO+ll!Og?iW}}H~qvy z>ixc_{&zpANN0iq9sQBO{V3Fj<48W&h0tCA#c z>jE5N$sC8N5E9On!D-3&E{#K*3{lHW;gKuURoh*?XzI5;K#c+Gq)@nLk7BUjX>!Sx ztb02M*teUoSsEplQZa^!)8s&)X+d9S)5g8!8Nqjtxs+tck(2qVXTrp_d zIzYezHrtcW+s|I_BWo(uA881Me2Or_|IR+MoxVWA~#$vj23Ba(}S=xa?K81Vb= zD^KGeSrkAw$`n%pWy;F;tnD%k(v(cwLW>&S>2ZUVxfQL3^`UAyguteuwcs%`t{j1x zr8TUlluTz>^F9_CIHWeDYIytCIR)+f*9;H+k&OW~EM2FqUap9(&hVI9N1rGrg^u>k z7@UEO6?>2lk=T%CIy@5nHuwiQo48sw5}~M2$i6deIer;@s76cA*e{Jm(@ly->t)Ns zOzS}K6$I9fyM(G_ltOW$1BB~49N=l(qf`%L{=U$9XYG=p%);&f8IJP%Fa=Q#(S4J2 zWAGqoMZ&dZ6L2AA4!gI`ES_ar#(uN`M;F{D61Z+;1`Ykb!#koGOL7d3+ z6%lt_8wU6mzL#G^|9b&k25kjqOvDror^EiQQURQ|kA6!Q!d%`=W{*udxW%*_4L(g} zQA)=&QMB7;q-7Ts&Js6*)WO4aLlk%vJ5x(_1#BiM;#d=aK+~b!U0_z9XCEY?0!}9M zQnp5n6ZJ|}QWBjt9(CvJSq*#;Cb%FlQ3K&QX17K}44OG>><7~^FxdpO#=;0 z_DasOKL(ga0S@ElG;VA!xZGGNRoAx|tpc+$Glq$HJOY5jcp z%*y>jFg`)x@=4Xn!bZ^29r!Twe~ODicf+8q9sxE1sS2V^Is3gajdFln%f%@Zf10WG zxQ<~wn1Cgo64RL|bMyRVtJ(L6t){~(LP2rC$M}jyWy}#9KY52*PCv=9r3ZG7RaebR z`MHxgGK33D+H+Izt`Ip+GRNEegux$asf&aQ9{}xo^th?TX4Y2z`fN-}Sy*oik&92fZmVo^Koi}sylP$A>(Sw%{OeiK9vrzG22Av}%;}&s zkSUC5q+oDMq_x9Uabgn!$@^zV;KN=l}08RR|fJ3ezo@PHju>_qs8S?@z7 z-$C<>)!u$yT-E|SE%o3pOxUaQZ3ZSEQ*r2ctnEtK*>4(4PZ5jgv{t0l+iO4JN!Nu! z!ofL6Bj-A(`;QgUo6+EF#sr2({rwT5nh6CsM2{g+lVO+pAG4TRoLK>L&__yr8VV}R z;;1lTHm}%t^3lQRjxJ=!5%*mw1SXN2e5s^_cf2AK7G?Qo;8ct=E{^vF~a7)_hMEH7(mXv8!K!@wbv z5Z>v^_ds+NE)TB85=J#3^&u`kvG08Z);>$jO^`ckD);2B7+#iLB-p z#2($%zw&O|_?`7{5pVUkN+W$H$hLSEO#vE=TdE!!YtSS|{`H?RrQq9b^tDBu?vF%i zFzgZ1pvqb_HibL-p7XQ+<{0*GikfxZ*Tp#A3i;h&D;5!YM{qLvMY0Bvcnmqa6}ng< z23n%IGRpP+%V+)zT;D;1XY9a(iM$zeUdJGb(d^ZJlgN)BTXx=SRT|YJdXO63wvyN= zf@eGG^i6xVdmBibis1K&yn9J{b{Ur=Cje|>vGs4^XfllDc@5H{$IZUYkIFgQ?&oVBDJ1?A(PUP8Qz{- zzh>Mw(s;QW8&<(I_+h}or)(zWKjv3X8$c!nq+pb3$Ttx1(z%ZP-=irIDr{G-_mk)V zeg8!)faJ_KyIua~%s)S@X>Rmw;NzQuiH3ryQjjfUYnqXik%3DG6FHVT&Ou3HIepKG zmHX@Z>@Uvk3pRh8^O+DFUVwD@45+!4F^*#Ir|PK_sl&8EdmWc15*E#or}>J#W`N1m zCX0D_ITG-lGNlkWD^IJCxVj7!2&TJhv;eo5E26s@x^Jry_Xg2{d~TL5+%7LKFM!I9 zIxPH>*pktaQF?}tPFcFrOVXN~QXE;+Ht^64p9 z-KjCtgcbR~UcI|*b634^C7pf{7^sj;E`8AfE7M@3Oya<7-Apa}rpy3RYkf)k3|%uL&d=n+0TS~zah@r&s-Xs z(%fmV=``R@5Unaxqqr>--s@WzZ|@7YC~L_hLBA{DzgW7J|Lb3czRcgsCET*JXZm(C z=@sm^H&z~K=qAW9%0)%seeyC{?AhtBM}rpw2+^Up!VM*P4?9*L45L=>vkvjlJ>=1dZ zW#)}b`mSB|y7(@7nQJ)jU|fwv-FfwJ=C)s^V1uK_;bmLV-|11%sL$bfB%S$?ThIl?j z$9Sb8{b5Q&i}6z+a`csFvOkNvhyn(xH5P(}pj2njgCQnCq#^pYz)m`(IX*=rFB3J6 zcnTf=esnRg|3?Stw$FI})rYe;i6*>_=`>#!UgaQZO*GuOr|qbt2H8V#`Nbp5@{5+( z1HYr?M`V^yG4lQY_>s|DJRT5pIkD^qOav1t`K$PkHK+}x>9*RCCb z&Wo{!=Y7i;gkgo<+2S^!q(TJS8*HeAy^;tofFt-V}-)SwldHGcfuWi#YTd@tM>f$Mb?%XUIx%`l*cPl~UZyprpl74x>u z4nO8@hHU;<9gYrQPt^PTALdi?UMEI`l_-dUMYs^qdTt^U;5-wF=&h`*JREip=)|1) z>Yp6fXY=VU{f(L9=&mtBbh~mV`1A5I`r>HovB-KhZ%t`)O#w4?A}>WW{e3!=wK-jl zQQfW-($>GV0CYEgl7O#i+UTO=6x{FJcU4cg&|1;%olt*~E~Dd+ufo zyWOGWA?(^@xn4%jq<683KsWM^i*0Np=~n0gcef;#_R0r7{^lkIg0RBSzn#UI`R_Y{ zC^`UnZckNur8Mkt6Xm5Hh-djW_>hovE%-(w0(|Nzk8xLqNd7%~z*8u@pZweT70_7S z{f_=<`~P|2@87$7rCsCSVEOOc1Ze*jvHyF)|CaCnuF@Un;NPv0bxW`rJ470{~o`zh96_{-2HDMLPexX8uOr&i+C6Pn>|Dpdewl#~yxxk;?<_pzx zE?+6?7sSu|?J32h9L4>9`2EPtqPs)D7EAGe-;|!G?n3_e(jCqm9M%7R%^iZ#mHPnf ze_y4P{Qvul9N&il|Mw(!5@;#tY#A*@-A8Jt=EUl0O4xxY%Q-=l*An5*`=X--%Ak62?Du0Ah-|Ur#|tnMzeI zyhCjEh8Y6>}o({*?QUSIWjWX1$G?b&Z zbhI9$9i(shMQx-AL`cfb56Yc*j7nwcRcw#_MEQXDFQSUo18Wmk9;U*H%k*rq8z!6p z`~R&M>?uNo&gfI=89n@E2>&&Z@L#8p@W@NE$5r}(8XFs1Np4+8FzWv3wwZeY|4UFotbJN?ahg_6-_+z<AMZ5y;hwJJJ7s8cV^x zHS8=o0Z7E+(s3xJa`r`HqMz<~cvXEw!wP;4L^a8DShRuVplt6g0rY*+%?&s`tr>gvWzdX4f53oB3To!Gk4-h1bkbHV9gSL$X{?>SS~ zm^v&VD5y9unnVmF>BAObN3~O!E3bxip0=o7QRNB*q7z-Uu<8Fp6{bR{G>o$BwAqtO z-PMQ1jc+Qx%+|;E;g!%hkf%H-5CDI(rx3;he7*l!_y3M!>~yY_Y|4CQQsvy!#obtY zy@8KsY^SMMGbF-H^K-J@wX!!a=5x+xo8mfhZWA-S(5PnH9|!QBb(0oO1lbMW0W!IQ zTF^wq#3KU(1Fgi!9)jy;-~d@`Vy4D_c1^IbTHA$?pH6eX7##mo;N-W_B9v;enA7FsYno9BS-m4)g3T zEiKgoGAUDIvMG;GdzXEVh^K4}4aXMuPHvtjME0P_SjAFQpfk$X@2)PwyA+;pjKThR z=d8hfc2MCs@D-sPc4g;h&z|+)rl$Teh~k(_=Gr*e%1FosZULHn>_x49>tx&GWh29w zs&-+o2S-(pmp?trCM6|}0Z1fCIOZgWn1C+)8e_gy?e!Mv$Mdq^_fE)92h_7w|NqORfKJ*xqD@{Gw|arWD&Z{KD^$8}|P?ytA}XA6#0 z@1d=L7zjWTwEOei_+44eqW7o!f%ih0alc=XQWDLFNFDplIu{?hn{+Igy^a#p356on z?7h`a?>;)%sF=^WP0kfk6XqkIp9vj}N$3g=W4|aMvwK`|p&MPVJANdeKm6RL`XrI+ zL>G26URf!)o+b7u*}No-U!2s$3~+R!A&ls7*!eVdqiR_kNXCF4!l2A3zB6l%y{$Wx?1AoyTu8f4?CO? zcmYWQL@AyB?f8s9e7itwI%+gOl-Tx>LmGSZsl^n~Xd*x1-mJ=uNJw@h`+o+CJJ`_W}_|{UsDC!udQSX zn*UBV&IQv70djp{L*{c`gUI+4va|-01bFio}$#dENWzs?M64eH-@kjJxB` z)l&-7TR8_S{V9?p#nj6x7lB{Gz!N+ToByD#;R56lFNu_IgRy4{@FuQXAdbxdQ|wc@ zKO})>zN|H?J``A#{gkux78Vvdh~pj(bVLe!qVWT$}Yj%2_i?Xh9s{qmo`t zy=Ah%ND=5*b$@RU+M~Hu`=qO==qJUvq=@~R1ca(5^0oX!YWQeRb)l4uOtU+p&_|Zh zsidT&kju_0{_N^n8#_w zWmpClm{8!`PN2%9^;1&>0-*(ZzxR1?aoi7F?nR-s(cpK+F zJ>PI*pwH9T)lLs#hw9mXcl`V(LRN3bLeFA!zk=swA1ff)?@g}z;1(Eo0LBi_nUj|*{e>@+-ULD9*-?FEQaZe{D%EYf z<+9fT4+Qx5TGXGgfIb~$SqHH2`{Ly^?d5kpko8>BWvuV`st z+Hng2fBpLPI|9M`yVRV(m?m?|IwL^N>PuN`@*9{ZSt8`=!2n$DKa0bpe!X)9~Rv4ulCZ_q^q<^wp7?mb(3@ zXpB@o&6>E^q2*7!bN$%7vo@R%*~eGWEJ+`|V84UVQS0_PZ)j++B1dL?U~osAXxIgz zZ0tvi?veq`rD2T!G(4Nm;y27xS&uk;?zZ?bBn#6*zC`ao;w9Jyq;mFUe*K~Q4HYz` zWa&>Sc=ce?O!1tjRZ8Fo7JR-$Tc)y5bj{!SFal@| zqBid)-j@9oR!NGuo<~%VV zvH5btu-mG`ZM@V3$mDTT^a=!Ap9NfB7(_ri-Zm=NDxkCXgB80W`#d;Lbw=Iqz7^KO zgGY*4X#jdMx_;PLjdHj8;*m{1UHkn2cxEH|u2%U&8hng9L9~OLiw6SiOBqTY-nnso zF~Kh)q7t3WqG5+`{h=8I0Z~052q+@+JOQTM5#FX+Ub^3}sx+P&Wds=i#dMyot}QgG znr;36baAOBdM?}~mx8AY8tNWfh2%;lJ)7IQ$!{=7#SFMQWV=9KvIoSByQfuzeYgUu zR@mdg@5=X@Dq=n=d$>mxD(=0I0>D1hJ}GzR5*tqZh;avi+nzSHETywa1?*uXzi+J; zB7%~YZ{u|j1s*cSLP`5@*ViEW{nNIBzqjeL&g!_d-zcV5ChLx)xatZ9xrz=uZ1!>o zwiJjw+}+(B79Jew*xTDXi&8+prKY7xP(_F2eh@vhw5e|9pFMoO@eXW6WbBw8Zpb*J zvXloiMVhs0y=h`C+nomAtW4oOjV4_8mk;ahO7F?lej_NSl)X8o@sfTL|IeYZx1f35 zucWFsRr%Qp?>|3Qhh>716Ih-;vLFT2QK}ji9Kj~2&IFMw2Ues@)io)BXOM@`(WvYY za}yJ^hLDhuF$)$oSik6@6Tt+eR-6FI0b)M-#eDat zu80MIy`*S{U`dlbG$uRK#l@xC+jd0VBY)LLHqtR??Ey*=iW~s)1{kF1ArIO1twLFl zGFs&e&_{>>Z$N`$G$kg*JbEZ14rsxT-sxKyq5&$$s^|zV)kf~Hb}n2e2sLj}0hEJ- zgCfEL0`-FP+-*(2fB(J%*6c*2N5qF5o6gXD39s1(>vCq(98&h8MIdW&hG7WoB7oPH zmDSp24X&w=CM%4~Am8urVp{*U{IKSlAFlFDZzCXZ!jxEQQ)?Br8_wRh@!4X6pAb&~ zs+e-x&r@sL8}0SAElVNNK2bISR~|b-wj>CfYdUx$z4mXO9{ngtUwT)0GhxSmfbaG5 zUiU2(9QeB*w*yGIaBnoYZQw)fwlQbioHBrer8aW?Fo1xc>$N>?gy&jjuDgfFqK@;T z<`Ew75g^bRZ^$*$CUABJ!JYVaknxe4op0^r0a?Naesd5ki0am-*iSqE2$h@ZiSLTI z_;YYpnI=l{VC*6#ZS@f@0AA7E+VfCsa{^)$O53f3+dm;RO+k>1L=oFDvDyJQIHCgc zTL(+-;|Kz(wovG_waap_^EDk-+RNI?f)q4&$-~b@@);Q!olV}0%4o@FC8GspQA8xoc?!z+-7F#8(a&wy;g`g^TH@8-DNVYZDWyd|Iti`u!Hm zjmny^f|-z*=Eca1V}-!&7NTf}3j8lBv!^&bPnCgvH76&hJ~YD88)ny7Hp#Lx@E2WV z4jy}^H+usHL`%!TzfmJ#JIn#K-Uw{JAzi{sG$Lw5$7>MTn4MBbYu;R}&}9y;hSq{@ z0Ss(}$pqaSMGqS{@E{b3<80uXVl6!$JQ2t3!9iE)Z{9@W*}XxBO2Zi_?w3)IY++MI z13B7!$GVj?_#7MLp^63foFmDoN4&t0Csz$3hQqi{Z*KTckGbJ+HN%F5xnq#MfvZq_atLBoBAkZtV=&0H3fL zYkxi1yUniWsi$+7@~@ibNTOD=@mv0cWbrGi;GLVb_5VY=jZTVfyhmD?2@YJ@&9pVG zU=n{vX~9m|p9H>iWyJc48-c$%KW3oV#$MgDd)>su)+1@&?UiM)pVJeJlzwTf5ppkX zWfQOLFiWvIhzIzEMjJ~~t+HrDZ<8{e4kZ;r_BoesIASUIDD`ndt4kZ1iE~wOVEzFe zJt+n<3;yF|B@@;_GGGv=3dwHBlJ=SvE_sNHl_vWp8saSc(w}8qvKipT_lY&!iXNt# zadIC1_AQ4fw~!e6^7$Vdu;s=V72)AoCn%Zd%%?MTbKBH_QOOgco!_Hp9~-u6f4A5p zUh=Mq^s)nF1WKwl9KT5b(F?R%^?mNh(5w>zQrs3kxmG)|*V)CO_d5IL(|97d?y})D7NU-*aXS*u3Ch}93`t;k2 zS6NFMVfeRBt6%ov?nPPWsWe5X+XO5aMM`S{HZ(g!w6xmy4#|n5vxanRF;0Ldk@R7! z?@J2;wz2zIthM#Cz5r1DH#cfdwD6VWJne~h0Diz0Rld|Jk}jo45B2p>2`pFH7N3ZCj{H!!GI^0htYDQ>~$vW3**6r-PMNc|R~+5-q0;jo=(roTkaoDNk=x z8f6;Jk-~VCOqc_axU3akPqfOj!5|u>lue5FOxCzk+|uOMFW5HKQX*ny`O{PW11LaS z@U%ZpO)#qA?$ai~8B>=6WS!8J=C-AQ4>vQjvqN~~@kYqqLHs0HaN&j^#R>F?%V8L~ z`llO#o!HkEU%6a1&tCU<4&(M`Y_iIuC>h_*9^b{4P-_T#?0qx4%Hnhy-Vc08Tz+g? zDZ<}Ux04%@S#^f@mcetFsU4)@&PaIwA=q!V6Pn;Z-$-=~tVpjg)yhvrDHn})M@5k$ zA0OY8mosXAr~eq!leg*y)e$;+p?i1@UK0E^IH&<>nJ+yPE1BqU{8OE7;Y$1E0G9q0 zdG8^(*UEKn^m${^{$f2?zg5&&C$loJQ$K6kAR6B_Dyw=ZHFb1!)D#stoOXm9zW<|2 z#V;TbCM6}ML~NIL_b@2VKJS)B4w9LzWu()M4@Ht101lw=u ziCKvO9f^I4v#Ur~geAp?2S@bq^>jm)FVp=4unD$TpHS5TB@PwOpn4!Q8d^ z$EQ6d@6B3#?AO42M#E+>p*%s|E2<|VAYeI@t=xbve$MMZ#v+{Q@gU1XE8#-~e-&fm zIN6_I#k69k{JaabB6uXqghitn0t)T?X57yS5}cvI<&uB5LPhorKk(#LU+sGb=Rqv+aP4+r6ugox?|F=Qf$h%)kmWFW59VhrY}$scrMY@? zv14dmauG7YrBk3d1Cq#>iMcsBCht~+xv`NtzZu41}}_Bdk+jm@o5H`l$lCN(}R#U3p}@|;FHdPS4!!S?qJ z=i86kS!d3PE6Yz9ZAVZlFMSqQvgNiOMuX{WmRuDDc{MgRHqwAj;V{5B%QzRP!Sri% z9hK72=fMCMTRcs>RTclo!)O0sQT<*GoJFj?VSZIu|Gkg{Zk#oOTd6%i4Z1gjFEBqZ zCE_M0q6h$RiM=mNTb3lTgIOMw1eLPLP^X;VeY|vt^TflX%2QCdg$3z7Ti9p!k*ZzE zm>c?_p^zMwLKTGg$~+d8!pc|U;9}0h?r7|xKjrGzVat!N2E)NLSkB>*(jNu#_dE0m z2fWs0t3CRQ=_t@WokLgW$L%tcE1FWy$_rbvP^HYRT7TmndO4X{$-?5sWQ=YNI@A_% zECCd#`S*|u@Bn6&jRkb!)&zs#Il_P2TgBqsC7y#Reqdvx3}K340rvO75W0iW=Nv1v z?^LhOP8bG{Xqd?Jh#-MDdz421+aucMIj`G_b>sFY`0xM3|6QEVHZiK|Pj4y_zD;&*I_}x-^efi~OsG4m8pf&2s~r7Xm?P zv}?9#GZ$obmEQb@1lT`rzVL0H+rg6ed?!uufki^%4Vc0;u!5n_XOz|e(Yc+#b+$X- zn!rPHyowE1+|yWO+o$`b3+&>#T&s!h6JuGc9czC5j~4)&RpblXjs{-$>=H_ad&Kev z7a%dWYIeAaeQKHIYf5!fd?m*qgS8Jthq8mUI11u3PQGsNE%9x&b^D+1AjjAuQN2Ci zdie4D{M^USB+y(DB(W$#`AFv0=#yU2q8Y-mwvfX$@2M*5+})7!262*@TP?oMs=mGl z?+$F{XJ_4oEt@>^t=kv(7Tsu@!f=M4$ma)v5)I6;l~?(f4Ib3DJMyZls-ofr|9)0# zYVG*?;fz$_j=%gKXHk67CJUf5KEHJwI{s#$L?Y!jkX1UfaUALu#k0bupz7d~DgSG1 zrrza-w}eBpFv2UjT7ME~Kx>E|VkMS})YsR0Yfs94lAYaRl_=}zy36^O!@%)*t$WyQ zB=_ban7>mWfj1s?_ia|thupBxeI64O3g(}p>$k!A#LNOy3_R>nK0RQ<8tE2iZ;MM1 z<|$$T9%7l{T^K+3%a0^XfI1s4d({hnFHR7AgQ}uQdBG21At7BYi^ip!kT-YJG+~*1 zCD*x0k?jh-qHE@i%Cjp6Ixl|ywxoFdJ27Ex;7{;BeMe_+n`Znk)~tfKnRzAvazjB< z+lzDy^a}ZLF7n%bOCaamQzf0CTYXzfkDN88;N1P^=LK`-IFl(MV88G~6?a$2mDr=% zz$Vt-DU0Vy)E!T>>Z1U7@AB!iWCpAqfcloer-ksd->V8hILlf( zCM(2EG6FgZnjAdmnszRVii&9ZQ&?_R?%%WqEk*=c#$HF!c-@q`U6Uj6%Ent~HvN_5 zBQHdZ2^Y zuKQJ~b)3DGEU0xglxBl`6$?I+f3{UgM5J1Ha^?B^ckk?}D#vZTMg|8lwVO|zM+%fY zL3%*HSKj(NR>?$hIkQm^5~V*QdD|6HJUj5NkvU0qw1bU$hy`+b_BEBmFT*e`!|=9n zCWaYoiGnf*jX?mY#wW#$qy+-g&i$UYYkRJ)tzFZgtIcVKb7iX4qmRt~Mg%)>rJfQ` z*yjHNeXa#GTS|(-Z9yy@#Z|m0JFf{dn(ea7H~hWxXB~DMZIvr+&F6%mw@0V(O)Q9@nv7Jtv9c5R(%)mO&NpM zJu-5o^`(lDoWJ|NpSH*Ad@1y0`Q^yIS7-Ybq!%eg75Q2UKALHHHPsZ+zBeYd2u$os z;FdV<@?>P4HR3G3PWV88vBpwk#1<~hA=IDL@!A3fDJBE)G}mUqepo{3;&pI2yK?Vgx;K_+f?Lo6i9=*&bRxTz9#9BFYU<#0 zZ>m1>RZ}9+KObm`n*OS|dkc_$T+f{lFD z7l4`4=k;N$cxZMsM|yVFyklzH%>+!pZ~wY9h;`FFAsDG!Qlgz{LPJe0{Os!Tz6%Ms zp9{V#Uv$lyJZENQt5hmlT26nt>i@a8l7sm(!wcu~9Gsnb^M|*T=_h5hOg> zqXr2q9ONZPyqpcR_=1uTuDo994t1VnEJQ9b+>WnVFd^UO8(GOU-0B>~G?+WMxrK-qSFNF7^Zw$IApd zl|gp2Ut;)}^%}@(<(LB#?M%xWBPn{qD}i&inmIcvth5yqY0A+6FvJVXX>Dbisi+|o z&ddd&im-#04LA&Ut*Om?FatiaFEf4*H^_N0A5q-|k$m0+8H z7PNZM0mH;fDlIX5{!&KR@c7qK_x|mTam6HF5I13Okl$Hs>Q(Ly9<$GhitW2NBKY0& zHK<0ev-ZQ1nsdRNNk2C518*Ut+tF=#8u zehWb+*`E_}Vf=j;;On8VZ5w!6)bYNE`~I@#Tp*F~1EuV}tX3i>8hNfytns}EIMCa( zy6|}4PPd#XjWF@l$=Mbb(Zkn$i8S6XeMvMv2S>^h+R|nbXlDvX%x(G$V~NUXTIZR9 zt`rX-$WjW_tbdV$=>bQ6*o*U<2q<5g;Pl%%c* z+{*$3LLCkZOfD$wzdt)%kFN^f8GE{NRjhkBs8w!etEwQXd#H+IBpF!~cQlEO{M-GuT7OSs;RyH7v zYe3oSL`N_&+=7E-$vS%pI&p?Tx!(d4<%)=^Zd8^wd(}2rURk+4IWcj>TUp%YNgJo| ztoMvL`stuci&d3NyH<}mdm9v4POV#NPupA?swhT)D8T~k*5V$LbCT`?qH27`@6u<} zcYFLfY-bo3dFJn0U`A_xF!?@m;ZDggd`Up1L++G&*gy(`CGPFt8M8#CX7#g%=Q)P_ zv*f&^M`@rtiI^Zemb|ThCopJrDp%O;a{^SKm4d`80kBH{(K*1J3<2L~8aA#7E~oCfT-Sq+xIMkFjCI7#r~MUw08`vCB7&xQ zIb%H-@F8fmo?v?`1+EccX($>R)GZZo^A%z3i>cWn-=Y4@HBOCVSlE9IiXE4u{a*kxxjgXMIIqxM`xs*@#upE8f&oVmE1u?L-?T#3HBcyWA zuIdBV*qQHFr?u}#gY81LUE%$2ge>*$z5U{HN8&yX)6tAeVFu@N*E{(`Gp~C~2YMfN zbFc(<(hYMP&}qOtIfnh)C@TO$_DC`Sv|Z&kqDLr4d%?^y`8lb{?=Mr6U3$g~AC)c> z1c?^Q*Pqx(arVXG;I8&V=8My{JleQHT9`;;q}HvgSYU#iu(tvT9ZPfwfXV=;o#=C2 z_E2~>OD5xWDs)sjx8+ecL8iszFSC;LP(H|`(2Q(#Baho22#HThrKn3mxHquPGIsR0 zO=jqwjIE>Xr9jera>`~JDibWzA(^G;>eEvj9;zpU7l#SMgM+){7UqJ0+2 zY_7?xoiW-!bmyvs2Yq?#AD$riiXB&2-$6CT`dx) z=VOwXefT&=;%2)k-AuhB;KoDnn+gqV4=GQ4H;jzij|}by!7&WdrBxzFL4(S(xP@_j z{K~!*(sFdzcxzF+fp(h;%{1T0$=E)2o!HLw8*4PW(i(+pTIq zO|fI?rg-qL`inz+Y_ok3%GQg@V{hWI;=EH{%v^~)>WG3DEgLvf3R`eL9 zMzlGQymzz&I665A6^cFj5+_<_cFpFpCVcFW0mFl*Wu0*X%-|u30a<NLb?1U9i`9cx5aEXz|(B(1vd8Z6dwqnyhh_Qfa@~8DDm= z$;g~^kN)5QWu&!VY_IABB+bU1RsH<_Qui*rC9i8OO3K0r;8?HbcC)aN2%yRaY`J2x zy-8Y~@!<+-Qg7`#Q)8(dwiml^!fJ7j{v|^lO9woj(pA)TUtg~D#x-iwC^nSt9(?)v zw1;3~bi)(x4VL)E&|V%#%FI-I1q68Ff$^Z{PAX7C1(tuCQ)sUZp7=1IlOX_MZ9Y-f zmjcyiXjs=t4$x4lbNa3ykInU+~F&e)otya~y9z>(hVa{Fj(MLL|CU-O*k-%LV z(fUVQlbB3G3wwDp53k1h&wwbP8r3|PzkYJTq3ehhT{x+KD_fpdLgEks>dRnD!BeD+ znomg}BcwJfh)s@qOBfx>*6)EBG1cOdu>HZ@fX2rTCXBY`d)GDe^{cGP@TdM52&W^y z0azPCfKR#`b9ZmrF&ON>`Rq`4+%v2%Mgv1RFzvi{+ep}Z0*h{h`a_637?% z*s;HGPjoT8UB1zQ4vhjNAeTf;w!~$i@S4BTBA^OZcx7o_%bhB>$B&!l@ldFB4}_PW z-52CV{&0}eJ(&QB@z~2n@iZFf+G&>Wz~8O+ zv)upe{hI^tE(sjD&r{8PkNnNo*0-%-Y$K%bv(JR8rz~&p=7Ghb6%1Kvrs%tvuyAFU zHJ0Y4CS@tNvG*+aK~qPr@ywwcZTc#@iwyy~xV;I9;|e~CtO zV`F7FwmB~?Pt4aR1zz3f=R4{in6+Q%iK~RKvgujF*uA7nx}UAKvqU_y3~Isx&R%Vu zui_|D_dSca9HMh+j;N2?`R2qLeydjI3t#FmG>pBd^RY~%v2n%-I5dE~u0J~fL4knw zK}{^c3Z~@N)i;(+AVU@LHr?Vw`uR)43W8`!^ScBS--Ds5?|C<#e>APW4yfy=|H1(C ze{JagEs0J-y407^K&$cB>Z&yvvf?xZ0=?olj~K~U2vWg$%A#Q**^HG1F13*P6;F?; zbU(SyChyqi)h9~YFcX1QLL?RuxBqPwf>LPx?+00fl`jH$n4spX){VchDx+wG6R8aT z#t$Cy0d)jVie*hB{iVXMHk4XqoLA=_B2CXfQ=zmPi$&#qC$w*h_rnTotjf!03YRl=to zB5iGe(?W}nMX>23_E)Z=`cKv#Ii-`rsUjLlvy+&!}V~dV2*MsuyO+H;H(0`tKtB+Gn`#ri+fRY=)M>-(2Q!#2G5agpTSwW@toD^6>Xvz{gaoM zSN*tclY4ODzBQplH`$Vczo38kd-VBIljbKF0Xiv|5FK)A`Fukhqy%A4+b*OP6cpGf zzr^5^|6s1lPf)Ha&)C+1-7NI{8c4gcz}zLkx%h)bm9ZHt^5mr}*=#obbs!)^aVaE3 zYTJ{uFJ>e=@pI)RpCeJW8exy`-TSf_u58O!nfOlSQGjkuOS`de?FEm1foEm`zl|kn zuWWHcgMZ3p`{U-h)xdUgRZHe2rDJK`LvzG240QMG?64!3eJ)4$PAn(!-6<`2mH0pl z)sIb2Q@8i1bL6^lP-XU^ zc(@@5v~R(SIc!wJu@kPJF5!ndD57F1KiTwd%+(yW*M>wlY_no}*U^P|l6|7Zaql65 zruHre&q*Q*&0vyHq*6Ik>hzo@@SYfKr>#FWb`eCY+-DlwqZk!SPyxoqhQ=hGm8Ac6 zLv#Xq4lk@GN#V*9(yG1ZEo4AnI<8m9sx)X6SDJ-ae6%|DKCDG$_M$ke!<*Pap6 z=y|!ie#Q35>1(`z1p9(|B&7=~tCp>2Wh+%nTU%w^0?Y^QxQp6a*8MwYdi z9Zmn{Oc# zSaQJwWz3h6^iYOR%mZCnZQuQR<>|v@uKcW--4I99{jh3Bqiu$o8Me{51VN*V?9!RZ z$Sz``WG7^3(A~M+R|X?^QPsBw%0M!6j5&|Dn*hEboYxDck?W6*yZKAL$7XT%^LQA= zZ+=Ef)c^8YjjQOYU`Wr&Pn{O~t1PjI?O`ua(oC%%s)kgs#r#A zFBMP_azS2I?I`80Sj%Td(wkKYx~xUWhdl!O8hZGYJ+u+;JFxV*u1>tYzg!{Y$J(iP z1KOOANi&Bw&OS3vGjj210~%x$M~Vh;_I+Xpcie}51-cs$N`u}P8c4YPs6Q93%BzM^ ziDjirr^q6(#`w!Jy098B41CiEhXn#m`TMDg zxBbakVSMm2FI#ZGv(^s&Ir<60{8R0}RS2lXc)p{)6!$aDcSY2X%K48m?lp76}i1f7K>v&L~BF#QrjJXtTlWwO$dH-F7J=WZnK*;+9kWCx{n4^y! zy{$oWSS>i4a+7#+Z9N3aJGQuXC#CCXFu?zuzGZ-#m&jscDMb7U1ubym0F8xYtvxN2 z_)ZF=+;0xR1owyj&i3>zA+zpcb$dqVYp1#Hm~P5U3#&-m8g8B0zuq=S+Apm&BEnHG z`&U|}G9JB9vsmPfGt@#DXz6-ifOO19y_2ke+gO@D&!=ZH1lzCnaJ#)zo@oqCh(nio zzSN_rZ+4&Ce}tC%6)y_0WXC`o%w)-j8)1D9C0f;Y#<{)AH6J~oyODID zitN)k#Agg@IW&5O%AFdwOY#*%>K0cH=6h8mXFvniW6OEed1pB41@roA<1$8E?>n<-VtGyuro>x6@MDr-5&93`g{^MOw%^uWC zHuLzoTq83x+1ClmcFs{eZEj}ZY*+m|{6w&XWzRf*;3)WqPS$717^OI0b%S#>DkNyz zb!iE*;<%MGLhJhA@L=KA*49h5eg=E%k!BURd)au1ibQ|sG#w~yhda&GIbmj57{Cd{ zKcF5vyn~8>uo|4leu1^uP6nX>rXVfvC1f5`?miNNc4j0fw-Gy6aj}EO?z8Z&=NqSH9fWobLpx+R zZxzn|PT%H{+gV>c0_`;z@}=i`3$&_|kNjjAnGC<}%r<(cR-BJ~{Tf_ff90?78cQJ1 z92Fivw-YI02FRF8RwjycSEX+Sj<$j5&DX-C{h_fhXyYF?aBfQUx#W2>F!9&f@S(hX zQ^^cpB`d+1zog1Q>-g&uJ~01x3?RYtFx4424f;E6Ij}Lea*zjEQU~n!svCz1sY~@g zfagQ5rs}wk390>jw^{+5OGR5OenE|Vl0UV_YLR?Hc%vL~u1JQNRa|LAkFPLRaQ)-w zlm3CpK68rg;3H~t|Fb>Q3*<4+zN-4UzRX*)i!0h+DwmjDIA*b4_C#mLvrbl8%R^}I z-$80vv(#72!lzO(TvZ7;BmTw!Y2R6^I`tHS=Q~zAChNdp7eA~@M}w-7^D7Lq8^sVg zM{p+$Atcux^x)UzM0dKSQIJ`Cb?;%v@!mbZLYM_8QOdJxg>|MnvcIUP(oRu>iA_R4 zHx~qFjXspqIkL8`?Yv%+Z22V^UMZj;GW(TN{W2MU{~bE?9SG%NKg>KLNIgxADMt$_ zXG|+Z53>QZD`MRpq0srM8AN`jASpIpLw4&7GTl{9P|_&;=PW!Cl2qsV7;E1sb5KgA zD>YC=tNaCqR&C0$R z7)++5_NL)AaDUyA-9X^y|HIx}M@8L!Z=-_Tlb1)$=F+$QEr#g7$0GtbC#Jn@33Y>rQ}V%!bk~I1AL{ zt!TZnTEfqbv(aaw)wC{K(Vuo**C1%cm>*yL#*(g)S(f5V)zLviLlZ-|J3JdL*>PAn zus{FyElE|v$BPzd3P>&d!fkk;{*5c-?J~igMnE15hZ&$UN2A~N%hSq&?p$)o-!%T` zn{%5h_pQbTVNn!dY8k)bIu6;Nq{&!4PimiuqgOEmHOU^KUpIH$*>4THi(*sm;sl^$ z1&?&rPZJ@U$M!}Of;7THjzIFo&DZCv)JO`pV?S;D{d=5T;~5@am9rsrEXg0$R)dV1 z)xsWdqpdk>UcGv(dhayvZo`MMmYlOU%AGELR76_`X-Gf&@ZgDa6QyZ{bA1z+!TToT z0GasGO`p09B}c237$h6NqmS<+ezUj{mQMo9n_FJuv+HvmJ7TzmPXeF*RM+9WY@#+Z z4U}ns6!!J?p!-&w5uW?9*2jZR0lLEcuGW0~_2`V&ejp3Y{FICQi0wx2aMWMnmEEt* zS=r5VLTz5xL4~_V=jxSG%qE}d!m6LcF}wVV$MN&VgtAEUeZG<~{(}YNo~fhRN8SXz zD-S&RilOj~dtjKC)9IO&xXz+WRZQq6Q&(wPTAI>=_k)&KV3u6ZFOAyl+_75TpQQh# zgX3@ZvgyrGV%F@fkj0{bOI;0ne8Rj^okw7dK6(Por=31}|9N;z?+A;k?WHSm7pm-c zR>lM~-{ER!okS-LDja4~YLj-+w%%MAAkJ=DEoZVEC3+Z+KjF;Il)!b%|B75WN9@0I zg^H?wX0bUam5?&>ETss)_NR8d^8cF0r1E)ayU8cNjR2m;>HbaV6Y ztXQAarwq-lyOom5R>`_lA~u~PkH3r;2<^EsT_}f&@7=QI*a=-LL-1kgH5i?zPnR6- zUZc{pD)>4u&M|+7Onmchl2G|%Dr3H*V zsPy9C0L#xTsSK#kUnvV zDZ}&PEWhThq?*>&LuGO+uB&x8LYRNc3#%eUUqLIFd`q_^t3&s|JK)$rA{nFTp@z-b zS{!uUbaepzc&BjuRi3BiD%cJN@+!EyOUR2ONod2m@hYczY%VB(YdPnYoliX1y^8s% zNylp;uU00X1yqdDS{JuoX&zn5arZf#DdNVwf2M6iifoM`D_!UdWb%j2U(!sULD1+C zAldhjQupIf%477)7XfUB>^UbYCAy%7_^Fwzl}P=)yh}4CsW!W`bU^Rv(`vnx3#qy( zrz%oeLt{!Ft654}V;=5539(GOOR0;#^RzbSapyb7$d>6}$6E!yM>$5fcRi6PPm#{+ z^V5j|U*JK7bCx)y?QdE~%S>WTkWv2izwHcuCg%2>nNG}XarnLYZofZn@|yfD@wIP+N=;2o zj2}u2B!Yak757z89k{M$%a4>?S{hfWs7?yf>Q*P$1S7+!sHki;=lDyM)xM;?W9g(I z_ScF0v*l68`37M^4GU4_zcng1|;x_^WA}|?K`nxx|Hudk^ z%I6Oi`q%_=?eBCm=W#xHM!nlLH4JvGGN*GiWwIT>+`4AmlT?!N63xpqZ*T`Ei1H*4fI#bEs@MW~@pBWg| z9~d4lC1f;b)Jma$AcU_vdofmtDWeyvwEVESVKBV7y0Z{_yE$RWniNEh3&Y70B?mIM zsjG7`QOcS8WtlA?MjBz8=K_JKmkd^EV7NVmZ*SqqcYcRnG6T`#^Q{K6*DO|Rt5Jj08=v}f zwRbA(n27Oz8DVh$6QKyjn<|t!?!C$9GHqp5Q6V~FjY2FI!}B9X)pzmCPNNa&`givE zsyA=m7=rA;T|bXjzs6&01OB$IW99p0-1m(=#}$W;h`?*VN#A0&1p^jR9<3~23u>?* ze{ISTo;fuc#CWX0biqwg;)Gy5oI+x=#~x`YrYNh+I-g3?e?ufnHl^olCM6fO84TO? z3uia?Pih%0GHt!vXiP@HV&Gz83`qVU4RfB{*(uCB%81Bldse2w^XaJDoz7+Z$(0f6 z87?P2!(^&88qZmx>WmY#-||Fh$J;`u?A$L~eGh5SYICmZekLa(z71ikTO+f#?@Cx4 zwD*=h!+=w=eMq~he1>oCBwD5_F(g(AzUgQmt<>T%TQup7!EAn zZ>CJHWD1Xz*%r{X9jEvF;6h5h**=8t94V*Jdv~4hL(uqr;L=`+aC##nC|b!H$TyJk z_~<2({Usk#+=26B>_PX&J_jzXzd+3Nw;&gKk81uKQ5tpiJ6OJcCcN~W#) zmmJmc1D`IMjR#UWK`~cex+1NGRcYN#e5d)&;amxPmWq`-qJ(?EnyW;Aa3w_uE6=y7 zET)at-5Pj&AQG>Y|Fl8{+rr}RDPr0L_P^FisCjDLjhqf;qk4E%^fU}C3v!RHREiBH zmD#hx)HV>usCDbph9Tt!&b8_`OPvW$E~aW);?DL&zb6@yPRy}ZaUV4*bVc}UckAX8 zSNmcU8w*9NT3iRArlOhQ)1M9t+&bKc{O~#(_I(ONgYiRN+2;S~fg~d7Z`gb1!Sh&x z+V_2l9aNNtC*%g?b)PCoTR6OA0+8HM(oB)NfPyiD{VqHg> zo6HTP`Avk=x1sCgt1@?FiF%~TR=9)nQtlJ+gZBN+Oy-3c@eJ?booBkp>#( zR$KYUYHQnJ5|f?-!>`E1d_I-g<6`~_FU6WC#+iohQCXGTF{j6atXmxu-f<5fOs~Oyy1z z$}Hc~^76atDIU^{A4?Rlw;pISaWPp0rAa{*dvcyG##P3@^AvJZhoom z7xnaqJ~K3$uld^70S33Zl%OA#fl@F_24q)0v`nun?nm&={sOO@n}=akpIa1#ql69}!1~avV8$G-z!GP^mVqCgtf?hzUtBs-+l@w{7)sPlr%IyHSc|*Wu6KwO9 zNnv_cwzqhAjum;6kt381$%%loI^pQqnTz3vH8NcOk)E_4W$Nf&@HM|+knnIa+>$cT z-jTXA@uo94wNz1}TBSMGu{J}S>4G_S%}3H<@)QD5&O}*VgX(^>Q|ns9-&2BpGRAIE zVp6MT@3b>!_A{ZyvU)qS*ky&(kTkx^zQrS8_MV3Ge1f>|H)ZFC(;>2+9*e2PjM+HH zA0In9Ty$|#?aw}bdc3TOw8VU!;85t?%lMK@1BR2xanfK(yt;M^ZJQ3_rR;j6+wy90 zd~E%?@i{#?@gAs0iI`GlY};h*_kFL&PoE~3hEz1_dPbx@LOp7p-^tZcL-S=cQx}U- zldk-A6Zg+Lh&zvVA2^$0CSfl@d z@$$cEXKFfg%WByPsS|kzjrl~P#4yNF5<1xS=g%K93h^~WKvcIqzz0s{OvhIkAueiC zGp_riog;)@@~moam(f;RzF+YVk5FUC9pB zi(&U!qWkb=W&}VC{7bI2?LqMb&Mubn>wfSJ*UOv{ON=I+!=)v&u9Y^1l%bbb6BB1h zW4V+bE6((^ms1A} z=TlXy1K~?t2)_tf1b$fmy{5W89sJ+FCG7n7*a(F5==J{&90Fk0?~%8x8EF5pyK54n%5;Hxz$Xv$ch9R~xMh!xmDO~pt~OCrRJ3n=+(&C4Z;5zL zpJsx$Zx_I8!~!~xV32#X>m>>O5r>~(v>!hG=$NZfqz$9HG4Dq942=sINB17MFT_iGsF!xkva*zw4?>_`jH@L#NK;zd~GZ zWY=mWWc!?Mf9F(G`QA>`lq1Q(T-3MJmPH*RgplMiP=FD)$v z>o{1U$r&ZZ|CDZQY$)mK4nK~kDcs(60To|UT92!i)<>k0Qs@J9LhSHx4rGC@*93x^ zjAr2j92U{=?%#30>0Ca08is_SxD@}dpN0Q3n)sjp|7(5iLpT53Kmy&ROP2&(mY!VB z-3Dp2alb}if^w#VgM;xl?Ngp(6Z|CT(moWTfOqLgm^2R`{!pMmDTMI-XlU*R-U5tNqY&CZ&A|L5c-jL+Zt?{WX%S=WBW z9lCV=DEvhbhyR-;h_0`trKL#>%mnyJZQLq|#ZS#|zqz4N?uVqLV*;z?M^@HYg>amg zX$Xx(bna@gT8;pxRr0m4&p&9{7VPv4I+{QJUbFBTxXxNRtno`gD>Kd!H6SFX?CgvY zY>w^g(;)J{*FQLzTTvlmwhUFt4+af=kNo+p)=o{^-Cba<*^8ezG#gY1CxR3EKYwCI z1^~@xf2c)L%LIL7h%A=#xP_~#tQ3XmOuRMvt5(W91qdmKy{o)B9Ucvn^?v12nPHr zB@W{*gtso)L4DUT4y)zd8;8{P0jcdbzEdD+W1Pi>teulD9!C{yI;7VDUCCK62q}Lwwz;o-89T@J5U?7w^^vR`~pw3)UMa?+qX!ciJ z$<+@%b#K1OIZCkNv-CVC0X?URmN)<4ZGz|V7$NJl7C46A%m3in{of81(UFnZRd@PG z(L*&4kENE!{n7b3Y)Ep8zO13L@C|ho3U$JcpC?qe{~@-|6wn)V@T+ONoCme^>4L#r zpzuOAZ{rW@NV|x`e-i)t-vB>LKlto*{$`VhH>0E3+ekA)!D4p+&%gBg_3Mz7kS5&` z=^p*!O`(Oq28O>kFfSu)^;4za9vDz&*E{sWrq7F_mx}CMZ?_p|U(mL<-FcRC_tEs1#3z;D# z_W0=FLuBL^PW6ne&!456NpGS~`<+F#geCS23~Wb17PNhMWaM&CHl5gOoE8nrhk1S? z594Vp$OJR}**{QBXcppLkahyoEK8}$=&l3_v42KIMMYsn#h%#w{5%EJOc@xcs@j{B z?~75TvpJg|hgfzdJw-Xlm2nDY%W_-u^b4?93{JkNayJZ%(;Z`$=r|9ev3ECb-V`wX zaYax_$PyHPXK-m*&#$pIx zezRlGNnEC2JKOfbDL$>64pqxFPhe#&-yuhQhgpCJKlu1P0>De3#oJsX=@33)&MQ8o z&cxe!`px5`qvDW#T<+}d_Von{BCxoBRRO8Ay~xivYMZa4mh-1E$(5;M8>`kkKG|nQ z*D_ysA~1I8HEA7?>yX^D94)uEw6Pgz4yB_!d-{6|H2>@$8p;CUWDYzVND=kU#2Dto zEziTPQ4SPL&kEkOk(GMbr>G9Hf#IaOSeW+`|7MvgfAiCu z^CF2CeeNbI1No-}t(PPCV0;q1MW`tGhc{LseDPx%5Cv zFXQTf)t;0MpS#XcHw7!(X{V!uu!XO`C}#}~V{KjO+eFVZSKBTBDwa=`3&rlPPdkIw zHh3*H7p5wx&NQ{OEa4yG_)vjz04$bA${<{ZPUT9_58=e;?hD^u5?a1^ z5whTAg$6B%2J|Cb^aNj%51E;OmSRxEBe9^Mj807CM*j7v5w-j6M@viVvFr->a+8B& zZtE^FFL#CP&iG-zjzIAV<4&`}`L{Vv>m`;Ohm6mM4XgS3nnH2;AhA7J;yhG%_z(+y zLZYFlJ1mSGq(o}a6|TnTgaZ3m<^odp=Dd7!Y+cy^c{;#7I|7;?24i?<50>HKeneVY zR|`+YpG!we(CQl63E@loXCcRut5ar^_^Zq|8R`;*fZPzA*liZ>fKg9E;s(^(ktI7$HJ+nEeJ@k-n!0?^+G$)@Pft@{9~~Ka$$Qmv;+=UJ8qM8= z+c+{F8c(|@biEDA@^cm>ZIb}~ z2|W9LIz27T$un$Xb#T1K6N73YpZW90y#5u@r08|%HQBxP`w{4&hHE^_78Vy9^ehwI z7e#-%FZ6LjEtL}FJ5>`INr^or3O2NKbh1O~gmY4vOZ=6XF3fElHaE*HPt+NL`i*>N zdSg#RP3;SqV#(wY8Xlrk1kffC3FGOV#7KIK?)nQQC?!^d`B@XW`30#~bud$)UBYVd zMEzi}oZ;v>0(50MOU_y4xp}caXBPTcaKxVKdzh+yvW`7|U ze(l{}9@%Q9vzPMFK}%O#|Nw0T3T9-&)1+o5woNxWaMB3UfX!v{QAo3 z)x}j%eaU_asM|=)K!Q88;k*MEXf{^qJX_Slz)xl9Wj~mCl$drROlk}0Fjzeg?+SkI z=cRp0bgkXS6j%UZ+dMgUTco;35}TEK0Gr@7cJT=N5r6d;R)!dPW9Fnw6lt4Bn){ zYIHu_wRf&5uc)qmy1cwx`6p7*32e1Fi0i%%z+-vn?CeYntYY1ft4#`&kVYpbGm@)S zLgsbbS;}M6e0KsYzeK*kyoZlA6c0R9Q3-d;tEkX{uK|dKXEg{$ggFd$1d)SX1SSt4 zW&t||4iv7UKbljW1qm8)(ja0T9i7R3mgft35o$U*G{>Kyf+j^ZRc_0@mIY$0hYJTa z3!(!_8k(99`guoU$-+mZYTG;FG{oj`C({_u&X?1lTozyQ@m=e0gyu9TV)Q|#|D;Chd*8`SEE}d<4(V$~57Q0!q>aD_fG$(&RCs&s%4Hg@OWEs`f z;`;VYl$9sP2c6+Qo6OLDO24$GMn954sQHjLR~itA!0sYI{riivUB2SGzx_RSCxe*3 zheWZfEQI?WrozMekepo5&QtXWG-%)^?OC}zO=Q%K&;s@K%e$jZxm1U6O;x?ncG zp6=H+M3d18nZxzvWM`|&%eOcLoJuTTZ{woia^37HeZZJFo?lnB@3*(UYIZ04ifrPu zri1YvN$A1_xj97`(#iJ?GY*_wT#C@gW|Hzckl$KROkEy2JgkdflIO49daSA%0pcfS zq^Q?!;niDDdRD1L*{4AOA^;7seY#g~btEMwqWSY{SG4clyI1DNOij9g88moDt*8y4 zOj}u5xe;YkrY9eEEutG2HL(iq6G_5z9gRz+^bf$>-P6zube7Bnmk45_m7T*Rr!e(P z4;H(>wxQ@YC!1P=`U3f|){G;j$9ogww*K|SwW#UB+s)-qc?L&&PX>y+C3E9#Yel9K zYCLxqwgwGB%9IN(HxpK$gS1`=fNAH-z1jG!;^dlr zw!kum*U(1lWUqS!7U&R#_nfTD&dMB>?x^Q#&7}9%nS~aq<08o5XU+F!T6M(o?KiSZ zra*1n>u{Ag0i@L7Bn2xH7LPVrPLyLb9~Pq+)@1T=C62Y_j|1_6)J4@?G+NWa;VWEe ziTj2bJpB84YikEbu)MHPMZLK_V%v_}u)rHvO^QV2MA3BEcEAcy$7JE>j10CM>uAw~ zcco?unYCJOWcLSY8Gag+jP?F_mo&VnI9U6|n>%sj8QBcRb-AqU!yRe{#)_p_KC?NR zmDh)C0JM5f-r(MV>r#Qa62vm*HXV8qIybKlT9=JwKvltfe$@(=kV5=3489KBQy)%p zM+E%5+*o&%iX;@#`z#{2cFC%Zn@FncCS}9``^5v*QFl1QI|3MTZ5@gTEt}p_Cb~*p z+4>BD9#JSh47|^5sP>A*dxp!9PoJI5&};pH1f=OpGmYy{c6?7Vp{Mr{sGv&*e`RfN zZwGTt`tCL`Zi}qbgn~;w+8?YN_@He-qq@5rm3){64(ZC-)B6+rbK-X}g$AfQDD^BM z!CwWxqR!MglU7=pn?H7ODFtAvVQ4sktAJ@gTyCEl#vqXcZA2|W)OoQ5#L!=0C4eDT zBoC4u(Cr`iyLF1CjXJlf_)Bu$YIpi-c1ZXPVU-4tt*Euu$<`Ze}mUp+)x{VD0vMYBG|NfSpNO+JlK%B<#s76wFfp5 z>y4LXX$!9mD^G*B@7J#V`(X{0yw~x3b1pSJgBn#U@`v2mDnn*J_53?O@3R^&< zyuMBq+e`M;NPGjxpVa*6bvT7MW{c>w<;b{wk)6D@*4EwND>;e9ZtGKP(*_0FDiT{7 z1>K9I-&cK)alRhx6bvEdk^3-E4<9`Od>sLh5*QsO zETnqM~0_zFm0GRwHC+C|X(RS+8kPuP;AU3VJn0>6X zRRKS{fq%VGV|P+M+oRYEJfstt?dI9e_$o?z6*vd<{l5QmyRq>;;H&JfU)2C~zZoKd zW_D0atv=lx`p$zcA0YXTo6WOlDa|3*%|p_E&KI4Rl3B*g_oT=sx)w-yzZ;n0qwlx? zKnt0&%v5!pJYH(8S8k^C@ZrOP2OYUNIVG@x1w%LxEMxX9^l+UK?K6>lawqGICn>Ot zPP569KH&wd?2 zoF}|@<|}YXQ7iyJ77iv(YGJtsiqGZ;q_H;5yhiChd@-V^yi}KQ`U}qP?iEsEX0~61 zFa3`H#?*0$i0BXz5yjnp_6jt`C4fXB!VKsJ5k&IW;$lI^*+=+rYqBMrUMvIf440IY zuk`iTgNw`dO|75mO~Jq3wVStihlaTNLrjbnR3MI7n&N@PX%RIO)wLw8XV>o9Nw!r`G8 zy@ZFxfUc&twyRhjfT;fd{x~ULAC2n@g9XpERr`?N5UlLP#={04mXG4a*iB4K?vJk0 zc7y>S;;q?K3-8veazW?U?k^aO0HVx=Jfp>!W4AFf)$~Vyd z@x;n`?e{$xTm?1rDTvy$p*hXqtL04PMEo$o1NRgk@BdV9pP8i9{>*$K9(9nUmGsua z5%-#Z@j}zzFNpA#RFJG7!P-Tp`R>K|o;#B*YyWQ$x=0=X8W6-2r zN+3ZD<gr z$7y0K<;-42Ge17eRxaij59p$GiseN0#f+f<#f%9gcFSW`+8`h;2Qd;&)V*%-{$=AH zR=Ym(@<9e}lSI(kE(5%9C*Qou>ruM~vdMP0ofy`(;iEfjLKRH|N3zL<-zQ*Ks-SnV z&rMC|-*V;mz*NUK(SS|O)^7R(DFU+s|L=Hg4TCslN0-QTf7Hgc{I;0gc>Z zGMc>G$nMlcsr`DDQOxBLEXfaPUt^tsd74T}JyC~u4d(2Jkx5>Eks~^fG)b&Ax0Z^# zatDRg zvM{auk<+^m=okpAD2&ik-|x#VRXqlEg(0_bDK$^_}_q-k;^fJw9Yco}h>4bDvvrqU@(ny~HG*9B-G^(c3RU zgg*!(;Sx2GRuk_<;WnvA@n)ijm#(sJ zkCIa(+8w~)#mkRCR)o{k)wMKmpP}4lic}%|56LY{}du&)4dE(Y|mHh~a0K<0hdV+?#uUsn4wZ$Y)7DkfAm zxz*QOJ>`c=`lj!c`xI33vO;PC9l80pop-T`%8-;1ig-N!M94#e(!K@~79M}w*c*~# z{OvdAes)o&)Xc9t&SqyO;n|Jm#jQAqW#d3+6gO7J3r*fxkw0|AzV&{#aQJ8eM5Fiao!qHiv_j&mW_WN3Ebi57lZ^G zAOJaW22$d!4*u>rS;qbM;E66>zU-ZyoqZzoxw)Hggd*&x;dqU?f_3y#Td$tj6z(m~ z5&8UxykL;a3N2(io(Icee#~_Ofa$v|$BU4Z?CI%2x4P=-={4rO&(CGq@6~x-RrYF@ z@FylT>8)qWL);H)E9>(24ujU2#(TP7yy=VPE;qD~tYC}l5(U%fe=NjZ+B#%>H^oD$ ztfX{Qab;h!5;{1DHoPtbQwiPel`0Qbs+6HMlcUvTu7djpSvvaq^y34-L*PV0Ae@kQ#C4I`wy6R&VqXoVpo3_8 zD2aDo8sf7aEmy_k2)Aw@B=GE>hv3t!2|dsC5t-{EI2Q_IWF{s~2ETR~EX z_v#MDR&Rts7W~HHk?Sn3_)1QNGcM6p?)5F0-fA)DuY>dRJh}$>MAgC~8+gCx5TrKc zdzT>hhy4u2AyIFHPt^OpELX=qMLI$%BwxQ095k8*$Tvkb2$BM7e3AiQpS*orU?@i7f{C?Es;qAU2BJyBltklg)vL+!woQT#KW&v{eI zu|Lcmus`1J_#(brq=UJ-5IJ zYm*JYy#c(?_V(^>%6D{dz|&ojvH;{)JyBbk|4qc_(5;TB3#uj>9*o%A?C&LKE|@sy z)GTH!vvF52=isj0O-ivn+VS%It6_PEqny~vTe0BE7d7#C1( zuU?%3mN*+=4%`sX9Saz=`P&4%HT3pTmfGr5_gKizB&MzQg}!QaC%v#@Wbo;3>ApNn zXLD@0!hU+%1O0HAb=z)~=C(>m+S(dNkM|J~s%p@#@woUGPGRj#h=H4P<@j)tt!?!} zVa28dM=iAe{{565VaI9MskI;d1nv;H%omVpJOS=tw;|3{CV-%jEvYHpALe0 zV>=hAXw5)Lq^pjVVQ{|@glz%!q!x~lFSEOMrYoPb=}uYc{pmj{P3Uj7zn790DTmCwb4HoW z2)K*^NZuL`fZDVN;D|}cPki1bHa6?;Uk7|v2^a@xBU-tTldA#A3fUm??DX^puuBd^ zgOLrBJueB*I6)3U-=PhHwDI5HC$~H>#!YVx!r9r`xda72NNrb^b7Vf4c8C|eiP86| zlf@{#5p}zv-Z}pIIQf?Md|BPmGDVPQ$n$n!ou3N}2vm>u^$8r^>NrP=@!yJE!3=;% z^4|aiP%=TH@LL|n0GS)Yr=qx@mS)AG6dlcL@tH1D>>7E{2z3-wTgqdOJ99<=t51VC zL|30@unm^kiPED-hjQ?g7mY^5CWv0i9Vqf+>L70vWv>MZIWVdC+{VC&Z5mtG0pIMu*{fGI6cRMWKobzr0h#F^^Y z5Fq>0fmwtWWVKB`byD0H&X%JwvK4phACl-=5f11kV}vS?T5cppYFy90k1arBeCfZt z;Yql#x;S|ItYekSa`bzX>>C0$9MHj2!%Qr!tPfJ6@md=V5{U7laDb>FOz0vFPF&nU;7LX^$$9d}NQLybNp7$sl;f8j^ z(1_P!yxP4l5&;7Hxl0QR4S0SOympVEgg6rh}!Wt>QV&-H)#N>xgd!&RRM82cz`Gt z$f4mNGv7{q**+hm1wl1X_fdn3A23?5eDTS_fqWJi{k6M*Qoy4LSoU#%IVRs;e$Rp_ zD_aDV1&I_bAO~PPA$uSIfm!g*JvFy#Kx>e52jc=1e-iwKcyzTbiXAe@_@xeAju^TD z@TdaG4O0uUD!iPVTO5$uaWCU_wa15`sL<`aw#{IKxl9S@0ADFBYOCm?_d;e%29=ZYSE`T~Cr?6!XK zq7UXaeeJ4C73@vOf`pX-j7KeW%9S1`(Xn#={f*#1oCvgVh5wwLoLY6cU}^xZXb$*3 zG7WkVXO)y_M1uJ4JB~rz?eS%{M-V{$^xK~(vo*Zi>V9%CF~Q9QCk93@7s68@FdGOI zJUy#iR>#NCHTi~RaER9pAzg(zxeE)H|FeiDGt*Z|0d4(93y|h0u8+4P{v^`icp!(! z)0rR=h4^y{6@q*(ppB(Q#-lM~zDzJ`OgI0j1{B7H*hKUzpJLtU;__$;uf}jy2#C0U z8Jxd1!*BMRKR};4s9}{qqhrx2{~+e=+hnqI?$5j%xNdD@W2hAoWp4yw0I&o?tZZzS zumm6xjrY8|Fwy1#ZAk>uM>_4z!~_wB!n4F*vY6{ibo&f`cBJ)?M8NY}grQf1JV6K_ z?DU7v3^+ml4t6RJV(<2^{|wdL0v1@7PzDKIa59p~Di9W{K?Aa|Ya*8}#@;8ZB`^c~ z1_m;~ddt0*jdX&{GSR7*HucJumO1$qv$T+avjlD!&(btZDrmz>#^(;fR+j*^>(lbp zX3vrjh-n6oA zvD@6MrwsU2`*~GS==xpRe50<%!*?PDSB#30%UOFTOJlBH8k)mr)+Q>{`8lJKq!n0C zpG_gU_nwXE>J`fKEkQpPR2? zSHH7d?MqtmNsRRqi|nagFDXXXiXGtSKOyhTi0_Dpiw{5Pcvie;nc)46B=8|3Gvivz zaR}*ndQ0S|Pn>1C=*u*ybFY~0|9T-bu&2}biRtVX;vwP%v_LSQU)T%h_HZoh{N8I# zs`|U*C|+p(!sXbDLI%yIe+?&m)+fK$GEiK9?Le1`S9VTV_1r8 z(2ZNS9*uTW%bJ^W$jHh{Wb}eM;<7gLX(FQQ92{o>QQrgZml{DM^dh!BC+OQZ>Bh!J zCSG0&(L`lZKXZ(32)&pVRx4ZMhM*uN@Tgg6^s*WPrU(h(w6kPnO|WGe%k=v;li;^+ zWlT(106{bz$p(_z)7VN&BaBff*mKhVy+4JXReS9RrpkBQAGqvJb!P!@SetwA7nZGvS@lRu^QQC+h#5em$ErQ=V z2tsPqh6rv{doX_2Y18RJ$t2;g!jCNJQ=^TXu}8jMLbJ7B`6(&+>z=ifSsps#wyGN_ zZb8C10+DpaE)%x0iwP6SBxKPai2L-ZfQe@>@p|sP9n-I@0E0 zA1b7)9U|oAue>L_hw(v14ehpdhjTZ(cn|BWWm;_s|K~}W{tA&`Av8GidC7*cnyNN1 zFt+pW`qozQf^+3t?HkOtz8N`|{S~#ddnV>G5^P}{&n=LcvxBr3{@BVC8@w5o6AYUP zde&WJ?jyjPw-KgL_N#0Ba8%Wj)7RIxV4sAP^z|b)Ao?%th@81ROifCByZHh&^^nC# zY5&cnFi*87=5^=#^dC2@$AximiPG{KQEWQN8ynw%)%^O$kB93X;F!&=tselZ6n^R) z_$dw^o@QWlE;2BT&)~ATs8I?^N<>Bl`Z5F;Cg8Geqh4?ZQsg}=ir_x`SGeAo^6^BT zjI!!&@|pW<%RvVXFXpSxSvEhp>(_mq%;#<;;Wr+{>i(2R6jcyGoUac}1;}18d7b*~$!nIzd~?XQvVxDFpWhLO zUgUe(OhvRond;2+m~HRwyzvfE+MDN)oa5PI7%oxzV};R$5?^L^_A?NUM*7{?*12`{ z30fTAG9+ni4k%LNz^@{3L=9#|Z*wT+F%ZPeE%w{FwIWn{rl zFnoA|bxiyI{nMvToq7-MJ3kEi1(SYBO`XKy2GNou;Hsfu@CKX>(2~vhFHsv&b;(5M z%^08eV&7elLE?}zcj)#5bb5Fn1!boy{u(P*{{1f0e~+TBaqFk~`VBvYpk-r(C&B1c z;i_r#kaofb!;F0VU*k32oW5p7G23}rs(TksBfj;7pM#u>l}qnO_e0MXSy&P~=U%Nb zAaob(ZQ2mkgI zoENna+x=|tz~?6Fd^5du(ON(~`0)kq?z$B;6Cl{4&I!eLF7|V+z?Ls$TDg?3n2d%B zpTR~D(q#w6A=ml%E`oyo0i5S9u4mo}c7Hc1J8-(f$Qb_pyG(+lH|@`#KXFc!XV*iA zTFp#u4Yhoc*)qUToO{vKApE>Y)jwx_m@2iRY1q?oD5Qu3;VQOthp?RB+eL&P!6S(( zsk7hw5e5q@7&hLwyN?A&84iQbDKz&KuJ`18zm9U~E7M9DfAX?AkU2|O>tPovy=aLkcw|AEoN?`r~%O z&%(kfTN1J-X9)WCbXpI z>mH3t>Qrf`mkIcac(YbHEus&vAWY26lnK_ztIzsu!X6!7WJOPIW#u>|ijk9(e>`0X zvZztw(WAq|_p!0TzkeIGn%tRl61_r6S<&|~vVA5vB*aOijv1B{go_gsHK#9Bqz*SR!qSdnR>*~ghw55O!$DfZls_iv!ao{#y z2L!m2YNTakd^axo44;N1rYz+5W0l+JyF>sl_F%EEK&RgJ@Z7tmSCHtdO1Ml%_bw}o zgAb#v;xJ4>FM0(Q0NA(It}Z$FVp;|g@)+%npP9}osJJHgry17yz$Qfk;N%I0v;#Jw zt}8qSFUeDOwfgA zHj_u@l~AX(7Eg4%KMB>avx=j;WzeQG?Bsux9g6}d6!v*B#vELV;B1#Rq2LxrwJ1%udZkg*h&mIQBYZMiL?%bt#xWIp=z9h9-$HW0#`%tBS^ln{y(T7{c} zvgS%JwJ4-_nqV)fmiX=g?epi()gSFlOr#r{``7#V9&aQc4qFwNh7oK*H3Q{@?@7(( zbIPlMXBgc4Fg5IPkJz9ITY{&fb(aVPuJ(WbAP+%5F%?^L{p|O5VD`D7SNX%!Q8P$C zcc0!xLf=@a_<+-%K8!cfS@rF<-t`31XsxL>sjiKM=T5s%cqI3yd~r>0Z+7uzmkRFg zASCA&i(rF8_7Z_8d>1>@m^IgWp+guu+C;#e>XuoJT^ML{O)B8+)8*%iJTej7E2f0mQVWaH9 zdebtaDEpAJ-e3RCr4}n-6wZA!E ze)zW?zbc@ZDz?+?nxq%CT z#U=ABl)CnNxpl@!d`dnEd?nQm<65asp}5^FfM9SKGWD-%z6xawKBvE#1x+6zM#mGa zI5D#);)3%MrRLuUVZi*n`y1c)*t>ak9O&1|J?(icF5tm=RcV(t@60cr%Ow`OgCX88 z%)aZ};6G~G%+0A{^lMY%md3J2@5%2TMG0c)crYwQ;2Xb7Pj^-F=ggBAzb}L=x{|FZ z9f)~4bsQuywD$Mb8OM;*3B4fqdp0i4V^}fumTL$|j4}LoMMP*Io_(J5YIFRnE_xSq zX%*8Xp}-s8fO@&ntEUNs$K6u@=t4&x<^uFqzQAb|>Ez@jbo09eog%IanfH9oC;dtB zZCXX@C{D_cz0%>vI(^sBMjpHG+UpArVLwU!_4aamfUwyXP-;KrwPKb1lVe1BDQBKGM1C zJLaxQzOl2YvrUlxJ+SI|qH%$bWSp5v_w^4C1A>Fk-oJlenkOc;ur=gA$H)O_LBYAKZ&!CA*4gYF6mbfo_v;_2jFam2~| zLcp=xkz>?zR-`RSYtAu^6jj0f(3C6nISQmC$d=9WiF>JY)oeY-Zy8myd0(q#H23tZ zQ(uU^!4NP0+w2j89e-&|o=j-%X-2anM#S&RmlQXKrS82bo7z2pTW9OgypzX1S?=O% zDjq$qa|Y1@I3v_#OSPJ|-_W;|7h2dO^Yb1o=DmgHhr&y5l6i3}YPyLQ;%_BP7ge9% znm#%_^VRASRdBcp4~JdLd)zNavFFI~9iQZFVIk9R+&tbQmrswL{wDa!i##AG2nEHH zQ>6w4Eimxq@CGUfoe>fYJed$iDF)a$LE6fS3;281qx%mYAhCJ?uIuf$9_aO?W@HdU z@02O%!fEVxgjoaI_#9Gf48ort!32$D377;jR_xJ5$gG9J=x6m?o+c)~At`Aga zIqEWE{Q^{sqhoJHC~Sm&1dRP&>x=}vI`OgQDO$_;u`wxK#BlAd+ew5v$F1x?+@jt0 zj;oIH$N>Ad4pYLhvXQ+F#UjFPlKyPhj z`AiZS?5tE3Dy$0NLQnQ6B2|*EtP)>7b*j<7(t5;*hvzCG3jzOgnX6Zca~sB95oqfZ z=_mx3kF7OP73wTqJ`{RKgi(z7vQo2S^rNlFaBWGyPq3i+)pbqHsjb*}TB1p_jaVM3 zb2z?=5Y%6eor>NnOBr1efrZH)x_Q(WUZ<w`*L*=T!H8Zi1-x1 z4?sxTX#2Rqz6T^g6?5FYDFZs87MJnU3d7AKy~DJyG68|C+DkV_&CQvENCa;IHAs)d z1+5!JVt$Q^ZV4g zdC7Ea4H)%|$FaPk zuoRa;!m3tn9=}e{YuJU&4Zt}&56~qP*xWUFVFKEu;xaO!q;a?)%maDF^h!tYUqE>O zvH88Cf&gs5TekKs-@iWq?7xR|7k~e*+{gZopc#@;fRcbx^4^c>sOCIK;YY90_oCt! zFY?n6UEFDl`Ceq-s5g|)g%tVRXg!B-Eu%IOMBI#-K|H@YW*iwsNR5z36hXij>v0Qt zt4Hw90`wN~sq3Ay>Km5&@H)uh5DB72mOgmQwL3p^OFQ&Yykj#nELAQWcJ?ckcCQ-H zP-m>wD#WgNc#@SstJ~nPgWz33Yn+UoCfp)XmOP@rmCD2=)yta6ZV9 zYFDZqVgz)Ud22g3KlS5NcCaULe7fekfPGfuK^?+YKF zui+YEGcYiet1&%iJeD7cxro&2V*mK*KnLFSRV8CQjwPI(54J<$TrHBaj|sKz`EXiL zI`d^t6$IS+KPFW3(6e=D!>nz?gGN$Q%XgPE4=;W)=$zZEsa(6hZg@^BK{Odp6Z)}h ziP>#&so#B!{Q?2{#uc|RzBZOZquRCfl+WhF5c#z7_pbX#dI}d=7`&~k>lMEHM4vMG zm>$z!XAdUYcJn_UB2~kN>1fYxT+af3MzfA!A3;_l+_N(chsmTDEeC?**fQKZGuuO(q;Hb0}d^G zV(8n3juuq+4(0sDC{^hTTr^lXl3O?DNYJ{So!l#zQrCfU7uMeitcg`NY88kCfPKAM z19G*Bh^$fSt;@4ig9vqXw#R&{N3$!#0)|xL63BkP1_+R-zxpA*zuU86*^B2+r82bi zp~oxW!GH|(Sp76nvMMUUj)jQYXY>*kD!7poqLh=%wP06Y1#n@%VQ3*p+{EcVx0zSp zlTdp4`|r_8L?k2{bVTrdz~AU|r?MOML|YTJ)y!D(I`5JKTju*%Y060kGCUyP63ZW_ z5fGq=iPi0nTW@W0JwrIzMzY;4j1vFhFWox1D5i$?w#Mi!Iybz9UK(Y&Tc!Z4L~x0dLU(j^^$}s zTQnKk?Xou;$dX$UTRvksU28)X6%s<=uLjZ`1CU0aTB8Ku%np%jtD&AmwXWgKuX3X| z8f?7Qc{epNC;l6MbH3J%9)spb@YXoT{mS$d18G@LqHcnx@|p^xxsGSdRMQ{Kx_2>~ zpy1Z$wS~M5cMIq_-{p%fmQgWnY@j!tX-M}mbx%^kEK<^X;CBmo_#QWCR9SymeSGr@ z`;3d{h4`FWzP9}qIO2yTB%D!8M%!5LKSV*RdRh1E6^+$HOcYKs`CydRITgO#yu6Uk z0YE`kb~-y(ru$68$@vge2jBw7q!qn?kv(e4FONq1xi>mC*6+UVj*ky1k^@;B@N_v;4qb->a_(o@v`GHFggLPD?b!)}P(^-vEi zi)=vVlk>=XTM!)=7XTV1&U`2d8YMwv`kks$dlcga0C{|`GD~m5MTP_V!uMsmFVfuj zJ_rMDTGB7UYk(nVAyL)xpk4tOJ11F$YsBH$5pW(jw8AJT(0Z*f4#IamjV1lcjMd)Gls zM@u~U0+IODSCeE^RGP?PC2LbC)dN)G9bIb~RV2@@&g1Wv_YNhpy~jEqZZNyCF!IiF z*8I%soPdes-Ed9lW(R8QSKhtXO1umc0*1S;ZZTlYlMkiInfq-r&3&b7L>MnGkg$y2RSvYh6^ z8zKl~L{Z%o>|Fr0dj4~XEp<>Y+->(214FM>+i}L*qDfMIM_`ysi8;hqtWq?`&ejzj z9Ss9II%p5b-(F@51EFNuEFaKj?zTllhBhI!f`nD@@wj=l_3*i~KnA+s$adW)6TjuT zDHh3L9nD8DVAxzIXc~3K2amQqnRv80-%iTt=n$!z2IO;Adu?AV9vnyl;A78?@jHjU z?-lgs*AE*(9oGC?$eZQ%YyaAN%rUzZOG>or0fp{(KeE@ZxUhNd^+&wKJWC%Mh#O_6 zoZQm9dfB&rmwLxJ^mPuYR6BhDp_q!xJnq>iqnF9mmRtdkh zi>>S0W0=U$uHRhJnC@$RP3OUrW0C4{*`^Z z7Dd2okud$b))sn0yGNH$F12_i^ipPZ}&w;8=e9!d$UbJ~d(wx*~{ zCBr5O!=y^w{br-0jJ!_4r`lPMaMc&r@>3b=dQ@UW-STr}?DV}oCBwmAiyf{*dL zm%3H|>e*&fW&2AkJ-k@g+T0#dFLBCC$?AMb%=0kOz|t&>bk};3oi~%**H*&sj zqE~7D+H{`}#*Bc|mjMtCvA_Y53Io{PBi?tO_gehZ%)9xDTQ24MSeZI}S}xo64ou!T z48Kbu0KFp&uN`WzdOz{-578sQ$RpS&c&V*<42_@6J?CAtd2IU`!OWd#+xwSm;i*IRP3eI!bfj{5oHVulTm^k|gTCgCX1x1i<>LP%?v)Fawqp9Rq;XT0VrbRCy>vylcT#kHg` z`vlq*C4pL}w=C|#H>g$kdqP2q z(0XvESGUEv-e~Dg{m^`+v~%kG7@`Q02Q%xzP{qs-y}JAlxI?};-5)4Hm@?213=~5E zfIo&kZ~pvo+@JCyWYJczAFItJrK{dsVMYLY#-A5yK}JLW!v)|ekZNW(9ii@J1yqIP zbGSr!wU%Ybs}dCu3|Z4sEU}x$4=_P{R@JkSI2PO$G$gcyO8eIECoBqD%`1_Hlz8ZV zYH9N^xh-ghpVX?}%vV)cWo^&dXw&JekB;hjXRML%IrIAXY!J$4^i`k1jvlAHLKWfNl^hyQ zCN?~FiJYs=7eXuPyVdadaz;W?JRj~KpQ>Ngu&BOYz&-3CmGMJ7m8I?e$54}gC0_TS zZGX&Z0oNOX#cP(sSEYh2uf5BCDFWC(A#(uZ2T(I{{`sdlfM+PLzT=J@ zQYj}8dz1Me{GFdG==e42I`2W0=L!nwhi$QIm_@3T}5i8fba zT&sre!8}R|{0dhkm=kS)CPHyMg=^V;syAu5ald_e)j*>8`sMZ5cqer@*l}XQh}-V| z^mo?G8;I_N5XK&p$Mt<)6gtE59evjA`z|J(=cIkKiEV=Cs#NaMcD`u4S_h;qHGZi33ppC!X6HhEQf=&);HI}ZHt-ywb{l9ht%WdALKme= zKoQFo(>qOeDa}3JVX-B2vxa7P^_OUr7(*p%@n{dyQ7}PSc|k>OsFg;EyJu>n+@DIS z2mH7Pg91G)AuTfVwH3>R#RF~;^vF2kGCib6aMQaV`#1^u!mt}{zPzlgtQ*HJ+r8?k z?=>IDLE)XK>&=ISWr4R2>=V8e6iCm5K?haqc9DQAip>w|OH^-M9xnhkoz-!pLD&Fz z1#AvtpGQDyQDNLqeA~|o&-#%)qycsSHsI-i>thxtLn|gGhEGWuk(>KW%VChq^7i`g z06X()B;~7TQT2q?X%$x5?jj^mwM@v5I@8)a$sn}z(?cz`LoY8uR1iA?{w*(mXf7eR z_POOhVZl|FO(_3HE8EIU40Dji&yimk%cHP<`DqRtm9s=6Fd79*Ybd4|*X{?YQFitx z*E4kqfh(p~K3Bj|b4oCz`Z=r7+d@`N4>JHD76Wq{A*V*QGSMEwB< z*kyYYZjfwmay_4&?5NLXa?PRsq0_DnWh+A}$KEq5|HaXD+s@}QfOV2P&Zq0LDW+|7 z(LF1i;qA6K#bD(dfZ)sE>eh!hl1#2V8;g}A8T>}Rc#85Rn=~w!nK`f0w=L&zc0&^Z zB9qKopAJ=b3wMZ&=PUces?dZC@v5IQ3cWgd@+<$A2qqXfNhQT>d>-XWRNeJb;sOWO zI;;A~*0#xQSyacu6poX z<&D18+G^Swkl3tQnbrO*(;Ys5-+3P$$))iU zMOP&3{bPeVEXO2SnXIdA`UBMNq`74&5CNa-)+v228(D&{^cEH>Htk%rE59XzvGU;T zk0!26&Y?cZ-@0xripCdfGOlE2(&UP*O=-*s${*Zb)hoU<)2kiYNK-|+7|>57gC+Td zuyaGLCAi(G-~(v>P<6g*Fli&y{F<$m$U1XSHu8kl2>Z2!T+GA-n}%cgQAXM0XpA$1 z4c|Weo}`n<1CS&eVmyr!x_Pg}0cbE?cjOG)hm|zf1ZpW!%Mh|+cyA5LySg1vdKzXQ zZ=$1aE=#F?+qhj#nnQeT#TiO{G@UM<$%lS5Jhww609tzhJR;&Di-^5JKtPCH4j%m2 z0XVa+z>6(6ebT(MFP^d9&?*WrW)hdX!DQ}MAe3pQOppSKSRyPO9HQFuy*YaIPQU>R z1UmRnnZh6t;_%G33QY1GNt8_)0!64Na3F5NDpCQt>*;Cj-H|PGtI+Q;6c1lHd}?$* zSx5q(6j>BT-N^fOy)FWNdwb=>cK&}aRrq?-38`V(OX?ge-3^Xm+nck!L-?inR|Q#r z0e&*S*GQ>4c(QJMCmv^6-hb__FHWa$uYOuBMP5b;Crs>{&QxI>9-`FkFSzIf^a*4; zVuA+94=XD4$Z+axzW;)%7K*U)~8urn=*cARO|;P)v1C zFVGDw`8Jy#whBYMiwuVZoAW%9Wc)|{V}b1)~Si(53wh#K%ixw%BQ|BbBlGVQ`5iS&XV)H{_yCZ}mL-bfyScrKMf)+f!B{K-+&tPtQ@Jf(2lZbcJBhp9LeRGZW*T zv|_Uh3qwszOv0i@wJT1dqw&AJe*si&ND!zk0TFQZPbCmDl2mDwvKZ4?N;9l~O5ipGIdDz8zJ+wBQA59JkBD=XUiY+9vAq8Y$(QEj@o)E zxE<6e9q3eQ2hE9#Ckkt6UWwS~UTGx(mM1?{xj>mJ@Esd(h_4F}efDu>t4JSSn0mcf zY8t+(q9@4#4q6|p8#12*33Izxe!N7$2^VOmZf1B4t=R$5Cmr32n!~fc8q9qwO3G| zY}Qwp)NVXMDiqwkxq&f_YWiR6>seaq*}-|pMJqr2AqK; z6ogmp9ZQXBepKl*cDcg)H&@uVx3ippM~3||?Br=?=L_m9x#vO}nSBR0SK&*ZhyM8X zb}ve?TR->H9S=mYY&3qqY}1yHTJ3|1=VCsg>85urX@CAX9#0jSfv}vkW-5>iK+g*k z8_@4tP7ODtTYEG~Eh{>*z1XxbNqD_n&PM*&38a#MLDyBuow{cS2@aFL=C6Fv>J$l{ zsCE|B?QCbAIz(Ewm1B1kbSRKI$sghe?n^9$66pS-zNt0h;7&!l(`zlyIB{T6^|$S^ z9b1BL$%(WI4#y>Ws4K0vkAO~~31&Tx#+?fC-_(&})i28Ve!X(%ZM-2NJVmR&thuPBCSFJPN$x@ zUFV)`vB%kIxx`2{0|f zn0nrKO{k=^cFmB~;c&CPf4Ll|*BL}*v!+ABj|Ky-Hne>ke=MM9NS_cV_4Z0-AXkbj_-)+-^?0al8bn!F`GO z@AnMQf<1>;H6KDWBxIPdlLl)P5eUXkjJEs&B7mG7hHC%X>)nGiG(R{RkbLj|bN?Hk z6z`@a)IcQg&u=t>;=P&wjK%%;QE{OmMW7`$|DEn8Ox@}Ud#B6vZVz3Z3#kcFpLv)Opk{7dfN zEHopI^l?8)>1zL;Rw>enGrpU4WGb(g8&OO3VjmLfQ10~AdUUuDRr`lSo9}-7$_`ty zoHH{_0?OX}2!mtrcd2D}8qBx@CjG*a=W)d393hqK@5~jlB`8t2^|Sl){l>+J!c3B=LYczQkgaVx@pg0oQn<@xg=$I*haG82`eE53M8 zJuqq2l_yF`yy*t;K44b!MRfxn7=YXrbAk5K+kwq3nE2sE270*sI)~GPB z-gax?_N}F&o>j4yX)}r9<6@x^TP61=@=_UuSAdiNZa;Jvs&gHFOn%zjrdM|ZEC;O} zg$@tznz^L$FU(<*C!MX{jHF6^C_8D!tU@jDvTm>v)3cv!-QOigvoc*qbb64ej1*+)Lxpb zG$HkrHXz!8K3kV#(cKfx<2K`FcTAs%1;m6clG5&C43vwhcfyrYzdo{8k5$XFx)F^n zcPl`{h_S70IpGyQGPH~|K7N_C(X-Gg1EB}z@2iU}ih#;z=xX*$=B(;CyEBXg-pMx% zp$NNoaCv)s-+2I~GR3=2{guo_g~Z+qVo+;)P<+zo*57%0S8Hjc8wKVl@{7wN+;20h z)$ghOkt!+9+2b*9-+dL~uzT{*AC+DG4Z0;Wb9r21hvO=;jaK~wP-0dz<3DJxs$G0x ztw~Nk3i4I!GI~=^^p;}<*v#gGVkak4jp{yc?PToVvMj!L69r0nU&V;YFs-ZG-@ZkB zCyGF(S{hJat~9n3(9p01Cnl;sE$HhT_B;+x^SQO{VCVLD>pQi_Wsdc@fgubhvZy0< zDSSO`ya|V9y`9HfjW(lY4SM%N;A3x$Ubx|}=_lABMTWz0Vc#j9B7WgsDN;jm1g)L& zqQ|XTLvDX(;%VT*jk>7Ic2Jb#xrWx_#pk9>7Of)8?&+-}_GgY1RfXu!k!j5%HUL5N z348?|_k&en+t?Vl5Y!5IM5Lqwh0UzNmJi%z2@6kYpPTdh(!DELPto{*OxHQUH2jPf!^F_`|#+s`6?UtrOY#P zsqgq799fJxfe2Cpq4>bRr)Znp?;nNQm78-cY2LyU zORqyI=UvH{5TSd1GUQs<(FT!nd-K-Y4R{=tFhTG zix5*#VE>!Ye);mm8wl4y*Dmo4aI{AN#NKUOp{B=4rVJ<@4g6**PXUFes*1C>1@JpK zxf_^TS^;I40Dq(<7N|I}LDy9Y;Q2rp(QU!Q#RXb4h=2lSMUF=YXq3$u%c79$`iwCW zHDSvN#U?PnlN}EhD>+Nk2Sb7M?qVn)m=;UN4?DBRbNqz`Rw8Ew?L*`lh7?RNjGF2w zBNlRLCsB|qaQquXe=yRMhM`f{uPJjmK94=yGxUSQ^T*XrQfcu%UOfvNs&Gv&*uY(myb zKdW+s9)ha{BP24!_f}J55!F^1Rm2+p5=|S!n>WQy8YAUY=4|wGBJ8O=2F*H;g{hc! zq90YHL5@cGMN9MUj0>H8PQjEptsusBp>JN=@t?{&9pq(P$g1)i7O7!!nuA$f8x|o| zSlR=}WV>sx9Gz|_B&qce_89v?IGwaod*YN)3?^-)TiIaBe9(f8SS~ z!Sb+nv)Gs6Hkdx@^oDL%&cq^-K4JsI<@AdSK->rX)V)6$uYf%vH|X!!H8wS+0e}@W z^?nVd_dg)iCPB)}&%d7txB^ViRzPDa))0uHj2Re8qq^0BV&xtj0oX7E0S(`$urNcw z_rRaK@A+kVUlthc9vvMe@z^}Jz)Irc;aO`wUtEJguw!-G-M1Z5e*ZoIRO5%h7C@of z?WY%5@BM(7i7Ph5(KcLWa6F~Mo)L(Q<}RS4q3nMnWzP#ekGG$0&rXQfpPiq$kgi9n?Un=~X>Ao1gPSp2GS$rmYH zv&8gb6(G;Z$b7}Y2>U^dt#&q{(>ee-vUNOod`WrbjE zROq0_%63Q=ftTg;1hl0hSQL#s_{v77f)aET7xe*^<9Zz-Dc)5#u?%q7<)W@Abuw#8 z#w{Gzzu!)+RTpRqpa@Htt$aQ_3vaemdehKfLH)rsc(V@$WnUVwgTmqOzAq_0hN*tF zbR@qv)Ryy-#2{FQy)>G@+ z$HKTb-e&ID@2pwK;Fp+}3yt~(g?^yCZ*y4;S^j%WSr*nO8TM>5kTl{Pq3+vn-+95E zXAY&OqaVT%j?08PZ?E?Qj#o>?K+0ao*hT!5rLeyHW*|8w>a_8}$h7^?JN*S{dk`hl zeyAvY_L{KOGkC8a(%J8mRHGwwzVq%Vj~kKw;YC+OV4(mH0o%7y3G3@`{A9gtId%)J zXl$I8P3xXRd};kjK3>0x9&)7zXzWMn>nG}K%v^?2L41(H?hj7z*o~tq>wW3^aypCWnSmBvk&RshPg4Y4RSl z*1*}-0Jyiz>#;2ZqaMAS*E5-#fH4fLIm3b1Z139D-yj_Fx>3^rYV=Q$kskqS=C5U) z`2-U%Kr}SSfd35Cno(*2yt%G{Q{n@E3RNvT6ySHT0Z89Td=7Mg#Z7RvSZRU>Nb-V0 zk$~s~=*p~Gd2eah*zf^EsTgqRpj>%Uuo+sZ7+vm5>89$>R0x}wq;{+pAN#efd=z74nX_7YQ{^vODU{mo^qlTxo zMhU9G@v)rI)b4}133A4mDO+S=V$bko440L*m@?_#p1iMgD$yGIemGb+km^x--N3U z1mwJG_BRadwKCqp36z(FWn9za(#*r|DR3^YT31iU^^?)g>FrC=H3~3GBR+gDKht{^ zpuEs-5oZt{)sWFk4~lzn(R7vB=k6B3CmNZz#3KeHyW$*%W&mxVa}BsmVB_kS0Uad( z?#ZpJK#K+#L=SrZ-5}Xlo67~_G~gDtclbIK_{C5Ff2Mh0-bbDZy3@cfN#^M2Uf>LT zJkn~bs_OPSM8CBLFw`6${)~uyc{Th|Ps|55_{66Abg(I_?n{RQIhkg;+f|zbzmV=K zcLwf#-ZJ#=KY=Da*6q!nUcon*?BN>IU;sw!UIGsJGhKN~Br-kh**WXaRf(2!mZlfi z4tAe4nM^h6-(q|7zRmwC_DgBK(yaqEk^7cd7S=z6HQnRO72V&Ex!*}(NU`l-DIuDQi_Xn`l5< zGxz?G!Fmb*;KP!Y=!4DMYf3*-ZFbr-;@&f#?<65@QQRLjL2u^P&uDW!N%NU-nRcE9 zEjVh-T)*6OBUsrv@6FRJrbNSD*L?fh?wDbMbk-s+y>N~mV-@?5iVU54pa|_3l2y?& z=;~NUNr~DzRgNx>f8rhBacs$uF*WP3x(NY44cRyP_f*g?U%Xa@fHJIharQAAz)009 zKjHwPu#Rr+V1}T_Gf{$it;iS?o49T4VCI@*m31uxzY$=B4JvRRQKST>^qbmp7St zK&O@v`=BaM+m?H|pA|tAX3z><xWXg4D+ay-pN z{r$J> zi5ggDF)KWzhBmHzkJpJZ5-e?)uiM4@og=q%Nev(OCDuA9q<$zpPDAYd{6?NaY;y1T z8&}ZVhuoAdb7y*!#M5;|?K1;X;$q#tzHNMJtCngP5^O)cSxub>t%G;E#kywmr73`t zp}EH+y#kRPp%;RQxP8NB>1`WIU#=|DMDQrj215kwo2(>*4L#Borp!Qx;uc8oa@Xm1 zNwv%jE7T76YM1^1-<{0ryngd5AL!z!o2rwDVZm;_hae*%fiCi?kWj{+VU}+4|8N0j ztBb}r6X*Ev(%iG96)0dlx>{RjW!AlOx`*E}mry*s{KUtn#6h%I{11GT8I6J}w)1`< zO|#_NP|q@#YyzZU#>r%CJYuyN4l61}guY2d2AFRtRb}wrYY$KzF2tDCnO6fGBC|BD z36L19ehXhf8;Sx5sU*7Btd224E$5uPSs!B0{P4wCkY`~(hsd2o9nbyyv0JUeE9iMQ zHz=z-2F$L|6mj@AgC7|VLWqqVSv}>?d!3V66tB+-6Fp(3cgVGyg77u|B&+?*sapgj z_UF8m2z~hBk!g{sZ*%cXJbHh#M7`U2U)Q9eyIWB*`bE65Ku17|;hlI6y5G?J))7U0 z)(`)uIu?q-xrT9>xFnNGw+f7tWBH?xESx^Vf_@57138Q_84 z4FsvjK!+nuy#}b4v6Igtfw@3A5Lxagm136XPw=~zn=quBTjYJd6ct_2lyqd*!+vaY z4Fc5|*T1M*4_}ATONo|?Cs--3NIH2Ido+jNyi@*{+XZ>d78QnLOJ6dk>O^%-X3#4O zc=2J^-+3czIpBnD4h4D-XFL{)Jx=X)z!|h=*WAM50adkO^;SL>{3ucPPxD36AK#f9t{zTu^!oT~ zo&aFNBhYiy5i=d65|vkPvy~(u*pMmmh*^wM8CTUeGgLo(`?dm`w|}ePzuo!TJN6iY zPuy=Xz)YgsgbU|vXpFL^%s&`HhxOCQ`&iu%vh|}wBoo;w{&5L9z#Q5yh znwg)!?M{P%5~UJkZ|@8@L$7Lxy?mo01zFwRzs`TMcZLZcVDv>|sNI79sry;mubgp;L!E+>27CbfpgcPyp5g*jQ`b;=~l#MIDLi zsS3egCyNL?Yn!=?%n$V>nok~3S1sAiDqk}8l0NdU{)!r*>m8EC=kUW(>(7?yH>s!~ zZ&eRFmCw{$e48ANf0BlHfET(BnjSaQ1M&dxqnYm!V})UbuLVF|{-s47r&$>{Vs`cO zZA$nJoA-534Mqg~TGjHNE!6&_nu*ynw$4U; z@k-5kOOb_EweX}fw&BST0_mgAVTMRBV$F0S7!eFHeL1bepyCq(HfXoi?s1ZtF`!h| zdojEPic(jtg7*!@b+!tRCY7NT;Ox8!uA9rE8@;TY+{0n`_Se*DU|PG+jsE3r0h`GX z1zp-r+D8EDu#w`Enhp~Yxdv4yEL2S(T(-|inY+dzj`AK|BW?!nq0^N&4Ct0$@5D$`$GFkoX= zu&RuvrjA$^N>vs-R3rBr_#^xmfD6={3xfZFD;jPWe24Ue&Qd7&ffC=ZQlU1k3=`G=)N{6p<19Exys zIKtjdpbnyNFh5OR!?^t2@S<0+l(MxCbk{OB?jgn>K#WeA`&|AZ3Niumm81{1CFeo4 zeu!FymeOvZ1uH%R!9yZ^Z{yS&Fo%#Gd9;!mmPD8UWS!KoSQIIw z5ErWgt<|`C3T@sw6&;lLraqS#vy(-=(Fv$YgG%RHzROaN30}feG)gYTgQ-98el;tc zuEO|Q%=FyQfTAYe>ztBW8eeRBBk+up1C^kxCA4oaRT*drN2quq>3si}+{B{iixwml zF)v=|eRDw4&Q)ntxLCkVW=8bckLq$tG~v8b^Pvn67-~)Y6kc&=HomAvHp7}f!?7CL zKRN9pP`nZpse*K&TC#D4P+T(piyx}a#GjUspq1xKZseCdQ%gyJpXdBI^nD49JohZW z=wnv%-o?32PWIakC1jJ0lvET@4p3)4f8FGR2bE(zhD0`7TfV)F&v}y>_Cy;O())YF zV`|y`=u5-i)^sXO%rlit_e6U}g{O;fdh4B|syEn=Eng}4vS3*#`dGT`N~fEwW_#OU zyuSA0kw0m?wBrO6c1Hd_>;}gMCiM>bEV9G=VqqFzPmNFTe z9;^fpn2-?z$6G*`54<;b@7dtuFo>imz*wJQ#SDk>_+ zz1a^xChBpuYON`^9fvIRChS6yy%F@kYO>Z5NjjnXiqS~H;86>kbk9dre{=?X?lpS7 z&$mfPkBH>S{?XMZf9?;KY)p!?ey3-^v$^@7UV7o|su%kS>|nv|Yxwdb;J0dQ&HMB{ zyiiPDb&m@`M;R8Bf_?s-8yhfY(;_-esK{&i;^uNE<(T(Tz|kW?GNBx)skv=GRUO~= zJE$oEA{B4z>lV{zvu(V06rNrgV+kL8Ro&xCS--ffl^Eg~B(8d{BF!!}nx3vEkgJmP;Y*@l*cT(&H(ZnlKfsTp+Fkd| zLHXVMYeX1PH;JJ^yBxCF6G&}5Fd{tpSGnTXGg6hu+Sf8q_VI#K5u!o*q(eNK)p9t{g93uo{H>6%)9;73 zmpiPQR(LeX)^#hWN4@l!O2C!n`uZA>ou_7o47pP)fVZz^N-+@9r#Com8+d3hG`dIu ziFt+3op=6bSY%{Zm09EggWin*z=1*l(6elPuKJ>|ylpq|HGtfjS*zluN#1 zD&ddlT~Uvod_TsluSc{+-rX)wu@x zaQ0sm`K<=w>|IHk$cIA3^@CPvgInMF-@f(ReZ=t%FtdKIuHgcPz{uS(-U*AfcRG<| zSr|5In#Y;?LnbZL+S^Z=OCjA34m@10Fz45rc|T$|ZhD?@?U`vm@pXB7spK7UoVFg$ z{!^#vSe)v`bF0gx@A4iw6?Rc;#S$*~%0$IWiId3YC;|caNRXDgg$Fn6Al32v>ptn> z=9@My@myh!cS^NqlG+c{qctu_((*zIOR|@x-dPRFwSCs?R#xaNaGy(mJ`+6Sqop7f z=IpvVPxSSzK)n;ihHARg%rDEo%1z~lmt6;RCN>^mIEE_H^v=%;#utZRmc=M=$Ng=U zKWTmh{0-iL*&H1;z)Y6k`}4kSUu_pkGn`4MLs1o=;?#=Kix_H;ZrKgA+xz4TA_lB-%_2O5-lx; zvC*?EC5RYHPF;OuZ(4K%hzTe9+;E`vb-uCXV5*=dm7%S|g+}GS-BeK8@U2o;XPZkq zvgzen;7dAGF)MjH{h`4?>m{K$W?ftdg~$b=4Vk=+gTq77C}ZRL8?}|dLT7@L+1Ka8 zT~EjHFsjFH1or7Fv8l@TCE@#@j*Up>z<|F8`W3uB!$A7T1}tM$_6ZD6$G07mfSF$Z zo{o;r;n7jOkySx0unYr(!P#P129`0&-_QzNA|`h4WB1I@-#=TWNFVh2R8)cn2IRnW4blOH-(M$xR$Hh#?$4_OF}E1qXFznr z1gL#nN{V?Rcaa7#ts|hIu+&@x^tSNVIojmFehXN)c3W#JD-!_nvt>VV7z(iA3#fdu zjf9F_&bXS9ni>Y|I@gANXllbos>hvr|E9nYkxQ*Imqj}Eu}-;O8ya-Dl@r!H zK=yYDx$gOcsmmZ78NbBW8}^MgZ-W=ENO8ySMh;%8KMYCX+8tc44d?=v!(9 zWw1N9twQLAU}=(Ve8TTVe#Wy&I)q5gJV>25{&Qr+WAoR>OTuuBY&c~7Y_zT)giT-Kq+yrBDiK>fluyWUY2yV9?L5oRAQuS7+j4{W2=_^JzOJB zVAzd@@cxdog#zv)VuZ8WCl3s@C*~Q}R#iW-{T_aM-_9nHSLAH& zBE;@4EDw$-s}9fE+f8G$-xqZq4N&jOV&zyB#Mr*v$*Ji=6%m6dQ1O)&E3ZCny>p4$ zmVTOv^;cms=Y+UNb31!4?AZkkx;in&_+4F~GyfbIxaJ91Cs$-#TzW~Hj}QhF6%=&V zE!R4t;7g*VocZ|Kr~aOa4=cK!e;B+lT_H5asWlF-sOdz&2VXRtOS%xh0?{=RwvA}| z=fpPwJK$l_`>%#VLhyBT_NVpVzBT0yjT6sfz}U|1pnz%~3dqbU0uu(o@C`VNB}dZ* znGX42jRiP1J;8%vbz+oxcXE$Ej7mOFRTJr>BoRFn$N!FgAz|J6W$9KDv<>d3Y*E9y z5#~{{#4Sz^9w;N|#m`uJuK;uR;#%HteEg^ZU3*56JJgWdk_ou1?=$2Yq_K8d*5RA_ zl2;udRe4+Gga$q~`%j_MCw<7aOVTutN0B;^@$sm|%*8~+%apzif15mt$CQLA(;Zv8 z;!UBmks5!OYZj|G5_WSdlH%S3iBFdrA;IWJnjh6r0^*jvcQpa%O0w1%gT`MCtI#CYl5Vqc4(L83)TzcfsCloeu&9>$6L#Ch$L{);g-tcsSR_Q7jf%M z%|4nTxbR>p-e36pWnLVJAA{1G{m%m+%H+NI`IGYg^!(@H`~Mwt;{H>V{P*bYm;dz& z{~p$MdM@SpDp3gQQ z{c~(D9^U{Fwhi$^(>TkNPhObL>HPmEV=qJK76=ZRUX6`2a_<7=!VyEB(=0Fi^fJ$X z_M{I@f{eO^i0F@#Y{J0Hy2`bfhXisDzKR9eK@HF+D9e0wQKuMvlR8>9fcb&GWM(SE z_tQ<0RJVF3Dq?MtOrD8=*bg9!boLQYP41zs0hLG$rJOB z@cXmu9P+@EvQ5DFjPT%xhyoTy9ZH(c;4$(`>d|)~@iR#-qVo_YmT{tf?BBYEcxW@Y zul)f1nb8G8K)1U>er0J&^OJlvn*}CeG`gKr^g3lx0%dXXSc6zxR=WzOyxV(~4Fit40jArp3y(yK+pcZqs#7725;L8iZ)TlDV}5FFZL^{x1F)}4`1 zK)s(KHSSb>-u!1}u;qh!S(#{EODF&I_bTe`vveCAO-+}M4-5w3<+mAVwW4r=G9o`J z?pWB-n-M%so#!cw^WqpZrBFG_DcaQ?vaPYKP{phglq)Ou=xd}9E$X=dTJ_k``J`#A z{y~Lp@%()9*bs8{d!9L*|3vP6j6WQDV~37*r^dExncGMvOWq-*=nj%RwhX+GV>jru)||PCb&?wh2?EmA9YLc zXL!jC)vjMr;z?y=j?Ueo_w4ztbUr=0^ht+c!Bj&NQkg)0cl}Ks@85U0dEPMy@8Wm# z0-`ZaQV62jqMS&w1u5xK)v+Ha+@|?^$tsM^2&X5qd?F_b(&Uc(e!4jqlgi*wwAoLg z^>?Y|%Uql(vhyFi>5o4(qc1leS$bdNKkAc%ehj`A!SLOlRr0)+6us&RCUlF5ojp{q&nVks|qD%dII*9j2z7WGN4V zv$iN>h!_bN%${F20BJGeMRW3|IcNOac5TAQ&=A#J@rh%WqPPb^r+ppeI&KEzEu>BG zFC^O$o@PCyjjrKasbRtSln;c+KKFBrLE47>YzIG)R=e2q4=<;Xw&XH&8PC2ufe{!H zj4Uj-0|s`K+h(GO@_2sF5t`@&*a$}RAMX<0#|ajD0i*z~em@kf_mW*%;u2dwe|i;g z8;Lw=a11Rt_w(Lh)s)V!6hd&`i%+BhjiEMjsB*^7xQIua4bJw=cCL|i`1Uarc}=}Y z-3}-B2#;ooYGri%f3%%tP#xjcr5kq(4#6R~1a}A$JU9e*2~Kc_;O?%$-Q5Yng1fsr z1o!FO`%TS{srflooKr;|v`=@x@7{Z@_2g@D2`#qSP{&!=5bypGhW@>dntf3gxFm$Z z+Jeha_&ueR)u8l`m}<}G(m^e>@RFHEdDnCGz&}NG+m^A{EQjCqC(V>idejbN&=#!k zqB|j8Yno=4$A3@^8PfCd&|hFWMT6m>>lxMGTW-&5y37B)o0h$!Rw*C^d6egu@7~v0g~3csj6Q& zocMN6X`L4eCkE|b?nK4rhbB>oscmf$I`Qgz=1AnK5d}9b#L$rXLXzVGY!i|ztYu(? z_r4XuC)&P1RkyT-UEW~(D2y`TeH+7cyy62`b|#6gK5Z2&oxZVg=t4j7j1_)NL(t5` zU!r4+GF6|vr6^$0vhaTI#rL$iw}}x+@SZ!q3Uqzco_H6E0KM+ehK}c?lWb$SpE{*e z7~e_Lk8r1I1zLYIslUm7hc|jlMHe9Kr(`R=^7wiYcRY`HPDd04gp{2>d-X~fxz1q4 z;_*X+l}z!D1=jIjh5YeP?u$YTS#3e6xJzcyctm_e6uCuw?O#F}Xg+3$#xkW(4J+52 zufV2QzM#P0MfHvd+Ri<_S`9zMa%R2E8FwBdM2_MF=C9<17$|3tyo!l&E@ z$u0ifYauy4Zlf0o@dGU8ErwuXB*k_`LL`88Wy@uE^43Dyef!`#d{Vjs7^JgRT6Ze$ zR{`_E&=G+DWs+qIpJ|j7ejG43MHvT5)+>zUHySOYINW3O%oOxrgGCRG)$~{8PQ76z zL0|?u2$rV;#guAjausUZpgOCEV_w@IG^mn-nbcsyBoFAo0D}*~PD~^=z1qf!hUKlg zy8ydB%bJ>^Sp+l!CD_Blh+9nI9YB&11U)LULT6&(t|*#+t8*N zh_r$P%}rn{a1vxW+i&=;cKAVb1LWV^FU=yZRirE3sJWxdDevh z0$5tni|IJlGybRvcQNA~YF?a8RkRie!EyHqyfDe(JZT{LUdtY-eS(51mqHAl0 z#ZU6_^^wzi?G-bU-k=jhKgl8mCax8x~h3?T<3AqyA= zPV3}AccSerhSzJAvcH!lLSXQ4OiKegj(f-rM`fmt7SIfET*dUbU+~5sfFIvQOgJB8d;W z?D9_p6FKeL{7>s(QjT{8oFFLhZd3*0ZK3yKjw z9C?&i&1(e0!)nH_n4wGu(PXjnn@PW^`wpi>Q(8JnRN>&aUOWs`Ub^%kf$wx*Hg_|d zrfRl8v^t52u;>$6)8B;N_^kMM#8_z89+(y_FJd@Cs_40%eA~6C+jbIDbzkeB1g(Z1 zC)~B){|1dN7w>2znwP z9D)uUF))9~{d@KH2H%Yd7>+SVV~bo<=f24CtLKfjJqX8xBb*zA1M0H{dYorlcp;Kr zJj?lhA;G3kVX@khappmG!% zSOF2e;0M>mQCZd2qFHu>HOOLP_&57#lK=b}Ru^RHwmE@UfH>I8gaFpo)`TlGNITqb zeqA4;==uN4#{}Wsc{j)NP`(7+!$4u{RT}=km8khIl_ky(*XoKVyCHJN1W)rHkj-$u zT8V@LJu>1pX|~HPAj@`!IMdxV3&#O z58xMjA;%#Xqn4^nLtlR``nVkMXWrg4jL*2+|2)LW0`euhj8lqj%Q~|fkE(5RV`=#) zzM})3-ge>hy3PZ&SKK|l*V4B7pA{uGDAAv>+mGi#h%K#q zStr1)k9}n!5bScnIly+>;y#ncDdY;7&5x<$hnO+zMU`#Yx^RD9P52@fCz{?9yKQe7 zU8H?0ilKvV-?w5nV6F%ifF29jls8Btb>FhHV59;wqjIlyM&r{eFReI+uInqNL`M3C z5J7iCmkQBfwR!VkF5A5SNHHpXj~afqpG3t?FqGQJBsgLXjt%ugp?G* zSe5`%T}$Cvnl_U}m2QVsoshQM<6+TchldN=9RUbD`US#oe}nlUW$JP`BJ3|e{?oQe z#>#^Dm1cETXX^qNuwP}D{_R0N{V=$}hn$=NUVgN5)j84o;zG*v_N59MzzN^>)o4Hy z)RV&*vTxfl*3pU|Vu|(j%i`5NTT3-A=Rb8!chW|KKfkH|q+s*4BKh$yBU`G$EP7EXKVH_ijT94>j;yL|=a1(Las|%IDjv zxk>FMEwL|RlAbnvXs&SFKPwY6k861TqM)wl*dYi`wo?ILZ#KTg)dJ%C9rldb_d`No z!>WR9b1Ua17Au4nPencD8#~Fd4${d%)RAk(EHzWqOJsFibb<>SF!j#j6=wToaRAbf(!xfyRcA zh}M&R%rfR38Oxx@whmyJX^krqv|}I?qAxef&e={5F4VvYA)!-S3&`mooG4>9T94h_>T|L>mNd z0Bd+HpRS{u|2Rja&xtA32#%jMBlvmQ$)5){lDzl3a65AN>hx?4wuvv)12=B7_HAv0dYrO=0P&Z~y~DJ)bWJz|l1rS|@!_k245f zPlrwG-l8BV!~Oce?;o}=;=S9eyAIO;$j|Kq#S7m+aWQ1KQ}tN8@xRSV87|n|jMre8 z$t#gRXrd(l(IOPOwG4*hQ_FY#9w-kjx>F;4;W^9}xZ7@XQzO_=P8l;BTy!8$mJjmxL4l zxv#SFC=YXu^2yz=H>YP)a;wCctcsWi50}6B?)N0+T9UpSVF+?x(1^6>vhd!T0=}AO zktM5pTigB|8bxYZUw=?N5&LPB;;+yZ|M{KXcHV>iQJHkiM^?1ssLF%ls+OI~*GDvS z_xy;HG}n;qw{62x5F{Riz60jiextsRKx6azw1z@fY^3L)pl zzb!hpy7uOr+vlkFp&;54jl}2KKJO_dJ3AUoc!dJ~soOwoXV{wOmE0wWoQDLAS@GAr zpR6a#)R`gedIUlS{xu$uF#nyw2q7WimzNX8s6Xx0!0v`tXc(dn;q@R#VmUbhz8wz%s1Z81V{3AYUoir$zUp(yTO1__{wY- zRm?KtryCL+Ln={I(x9pJrZoEx8Mh*$Yb70;CnGS_7SM{06BMFV0C>~>t+oM;DLkLyqW z8rd#Ek^(FY7GUP^eTwz1#AgkjQZ*Xn#47K3hiTK}&k0|%6!Y;3NkSl?k}xo#n(v6_Sx zGv#N2t{XDZApQNZOr|Pumjd3_EVjW`a+DgOtF7Fd+kt73sHD)#Emy^xgRP}YkuG9O zUtWU{Z?wS1bp!5uFYJesD+GWJgwhDP*IK8`FG$`8L}CH@AF*=D-_XqK)Ro-k5ZhA8 zP%v1rJ^2>UVhH{y5xx+x``z~8l_9=;Uu-NL^mdk7^;)G;PRV>_Dt^W~;4Jtca2cBY zUB9%pTctpBZar{rYa3{li|ly}zU%$E`TC?fs$g2HH3zLB^bRrdJ*)U=^t6h}H^;OJ zB)=Gh2t8g&Xy;1&kk!W#gHpQcY^P6?%tg2 zW>rqEId{n{M<;STj8YreKQuLJRljhL+-5Y$2}H^yOX%9(X-=hIc;N40L;0x6eR_B< zt+T@}=25IggOy3F_##=ZN3QZck})&6EP+6jf_e$Y%z3xcVW~2$PuKvsW#4m}xuoEs z7dC8w^@XYS`f!db!Y_TZ1BD?X3s;RCnewf{VgJkW8}r?TLv_!qd(oj3p3#X2&Pmag zIm?2U>W>PoCN+}F!>hNYf}=EIPy`X2ttYoP2g+~$#j{pA*KHqJmgnREGRaJR)Y)H$ z4Pjtm4Ts{WP_VgO!WXUjk7mn0f^_obRtPBAe{Xb!8dU7R!NDmwn*--7ac|?8J4CEs zY1pICbcSYs!iRJqK-6#{7@6?aHp)}z3<)L=ARak#0T8KlD)$mPXmY~L%bZ3guyjbA zT&+IeRby6b7h}$AD>Q7oZJ^IDLapkNTbjF>@PiR>DME4N2K?ZLE?J0%b!Whg`Q0E;QC%v zdYp#~f*_NvLn#vo!_fD1*!+j&u_FwIjey>`_j-`W?bO8&bOH;X z)0j*hhf^@Y)gKJ*=2<U#YJYAeqj2>}M3RxFoQr({Oee<(N>x4*{8r-a+!*2KBw ztC680Q#=32zpY1`J~)r8;YB5pap4_QQI^ZDQcZ)E23P*x4nC;eA;6DG(`&d%97PtE+3D%#y*;S&Vx(hi)yI4iuI}9bI|-= z3u(|%-d9HE3-&1n7bfmCDXc&37Ip9J_KN*#PD>+{NH*EpZ*x|5Fs&VgMkm_h{z+b@ z5S^Slje=|c>^~31&BbOJFRcMj6>=H( zTNe(FwZ=YmPqenA9hvQ8=ccPKmRD+z+q)P-6f1mVjc2Pbbur4DYt!X&#;_MgP}ZDK z&3SWwvF$Jbj5#3{`?1Cr8Lh>P4kFc~`**P)=U!C~2|4iVKkZ@@3#`EO=vTjenKiel z+%;jv|M4S3kMI6*E*mE{=0>MjQBH|K1e` z!u8eKLJCP-eUxict;bR38QriPnVnjj@9`NgmgKYQ&>d+~$$=Ricatrm(LL0jSnVPb zh*dem8$_&lB5G{S4C*ixq-Sba*`DL4f+{%Aq3tixF`WqCoPhyea=LZsWa~u1+htkR zR5@Pi*bxIwabXFP-;v05T1BXKL=mBcM6hq%wh7rzy41f?yT1tH{dIL|TmR+rs*Wip z_4cAI2S9i4j^Co2aqePjycgp1{-}HKreIcM;%$+>t^n(F*@r?O6nY`Je{7CkeY#7r z@VH{|JuyZ?_`9V=I3-4unfj-^xSvL1a`x_#N&wZ-6dMUMzaLpg?&c-T=LOz@_s+ob!&LGy)yy91VB(_D)Zz4cpHM+G=vo+E z-g`%I(#Jhax?6A|9>crRXjOfnU_b{01ZQmj)SYzwc258{OU<;JuCpKRIbP~upD5LH z-*vY|deVl1>Ii;0u_f3gL8uMq8R+;A5Uyk5%aeeo1!GZSP~IQ{67^1(=3a;^+ZaJ0UpOvv|8}$xYBz7* zZ%p^QGwbXqHUXjy_Q?O79RJyCNwF#(EN;5YeRZ$9>kr?9Opr>K|8r@40)k8Y}5+sqD-(2{$~n@CPnA8656 zM$`N?2BG85LI!TtqvkxA3Zfx(d*~cHK>rf|yr}sPOV|c9A1~O4U}@{&r*#1-e^Vz6 z)`FXD3_e!m_+&I}!u|K8)=6W|?SdfQ>tf#{Z0cItDs{cSJHE)Vjf? z$10^EJF4nW(1!_cU|r=~P@lP%d|&`1*@jGjaIpVeE|*lZgCgA!^u?IJ!0#L|=hb%t zz}D@o3wPalVXt+~QIod#3=>I+XYm9bL4rrF_Ilbn;Z-EbY`l9+WEutd8Y{MCG+xPX zsyQMY*=iB5UlQB1_^?5AJNU>q5}iz2Dv1yHQZ_xlUL8i;=NeZv>_wMgX<$>^m0sse z>j$>g_rJ@a<@<3Ycuxa0!DWSox?}s@oR7icT|n_eymP&I+q47NIO>z>ohKa`=501i zl67@?V<;E6iPiFoLvX{v5Lir@-$o_pr3m1L&*9~rmWQ7V4VlVhuS%!b5hs6a{OKT@ z#$E#FI|e9xqlHq~s2O^GhfZvMLpg1`cT09a0+IS60}OClFc=bl|JqW?FT z4V6G$fdv_na=@dpu`wwd8z@A9M@8)iBjS7$>DB*{=|CtftbPS{TvF29!BzXkFQjHr zkUvplBoTeh$HX*NY2F4-gKfKBV1df371n=3gV|pY=yS$D@<-GNT+EmxPm0P$lwTUiZcK1qGE;AGLnn*vjQxKc zRdB4pHV-^7r$MvXp^M=Lx4(GPOYO-HxnE5^8%g@0-IL@$xqsTVqJ6f0T71jluCi?w|Rcei+|m8Kh7 zG5)?#v1*o|W8TXGxm7+C0~|$xB?HF7BJTIuhxKj8r|iCq{rCwt!+Zc(mwck88}MRP zP{Fl++n)4KXeoG*&vJQB=toP>+%!Cvf1PCXJoU*Ce4w7Huh;ueDV3U?hSWjdL*Bp% zmr6nN-_1%rKGv*}FN_md;ZH1*pvi|}%cx~rJ3|{!|1=!QdJi}Ipkn65`>?rY|MC8M zo}tZ|6+*Uy9I~z|8WS^nUA~a6uD2#&@h+w8>e+h_srBbEgW^k}4z>^9EA2C;Q1)y6 zkk@*4mmjBDA-kK8I%md9+}Y_%+G){~@cNtKT48Ksf)0S5gW9*+q1U*4eiy+^6y+p0 z!1vLk+oMtBupr2@y>{CfRNfsp`wY^If4dGhZzoa21R%=&qM9tYKm&yV3Gfl(zMzJh zH<8Hq7b|lBEW6K#_(ti_-XecOn?dlz!z0(9kA;_QZg)eQQCW^9u%F~V12fdE`UC`@ zPT2VGv`6!Q->v(Qfcy+FpI@?W9K?`^f)WFR(KL=xK{YVdGBz%b+@fgxaVwk|Bqu`x za_Oz3{~2Y2%9pS4_~Gp?C8ADLV!wI|)YGZS1mDGCkX>BeG-{E&+li)!)e5&dU(1Hg z8?w*A0Bq9T6YXw+W^k+OQuf-MWAg)A>NrrC4CA$`VT@M!F;Dc(Ma+EMOfl<)!cp8O zULzZhZ07=z_(x3Tl@(M5CB8ydL+;}K4D_wP%Y}Z<7absw7prH^9foFH!$`&_G5e9y z>HSL)`u;I;fMYsRqAl*vQ5`uPBZPL*pzxeAHUlD;dOH3_cvGGDe$nC5DOfLPeZesa z=)B-S@?y);$fX)=jbg%QpxiGu0%bpjWld8-5bS&81_h9snZ+(sCyxY(W)~Q3XFwUx z@f6xDU%C^JLPdI(B%{wd(LisI?4M3Fo^7=0Wh5W4OgvP%*trNTzj63gDtmAQsfV-< zQRTo~@RdWv2%eoO=W~!fEGu8%zJ!W6zqU6;hKU`eB0k%9yR8zqU?-(tobG9_I628# z{q3~O>x;2@U2v|CKpc(?K~@X5d<-V#EMIdZGEHsV5B|Xt4gGv%!w(iIT?IZ-_L=2A zkkHV3D9>UMAz4vEbxDeax7-mpL^FuY!BAYu*>re$hJ_G-NXMyBwbAyua6!p?Y8f=r z3RhfUqbQz4U!>>>W7pEFwq8cTr(MXI%bVwgwzh#9eSaM@zLnn>{@iuhJ}UX74|E?a z%$m46P7I{P*k!LiOoh1^sGK-Pgk{<^y^4Xg1e*wD#nJJH&g=fKC>sx&!)OR(Nii=8 zNrVc@3`77YrXnptDEz&NmPFdeSMxeEzvos8Vw^+r5&I#$Hp=p44EgP#ENoVdE2iaX zhi7}r?JWdYTr8||CAvhM_#sNYcGr&}!P_9c00RTV53H58!QkBAU|Q8b0|E%n3pP^m zA>oq=RDEi5KV5407vNbao4QrX_r-_1Y0bS144Q`r$ruwY4rUQ}A0b&aMxk6l^GmN$ zw18Si)pV=ozm?p`3EX^hEJ~29+NRxH$B_Ul^ZMIrjv8HJA3Y^)gKugkH=C*4BLLqS zqeEi`2Vww!hI#VPJ#Q%DTdc)PWP2|Y7uoHcaVIa2;M+C= zD+fbHDqy%@ML7#z^xsG`Z_A^=pUlpUSjv1Od+F*`GkIv~yx9309w6-&iD68}aFY>v zCfxDHGf~&X?_7w9d?U0Z>c)k1y-k9)=T(=$A1z1tJK1V=gttlc`K}V5|8RN;4ZOFu ztO`MtFDE>IU0X;PQ19)`X&jAvK~oG-&u=d80Jf?@9(bTG;X^w7+*g0^8t>4Q#XGs8f$@oneC>nW*z`>vEh9BI&y25qG6U_JR0hRYCLPEj&T-s^;EjFJA3EEuF z`$6PTF&K4JJ@;p6{p8EPMf@bL8(hR0Oby&VN!2bR{JOONK9>u9kcp<7mW(noEEq@5 z`OZ#NCVSe7MtCx`X_G_%M*5sP`P8wm&F(Clx@1bq`)y9?`=c^m!vIb09pNu}#`r7wPNm-S@ zas4@6t=PgTBT{2E5QSPIp|I*C}uFPL4+N ziz#cTA2GIe?|+*%Fr3<-4C)|t6qF8CmGMjszxId{GUYuzwKIJlSVPvR(D*t#5{J=c z;u$56CIC}W5P%{t4 z!x~NIiaT+&cvVnKz5CbV1=ArT{;k+}k^M(<^2(>Qplt;_LvGMLSG&_J=bowF;Pk&~ z-Q{Vznv+64dmULjJjxO?;2i54S*hT$6YN99H%PtPRQYU~A7Pt<&W)Ie*GTE6#sj>U z#>h18{sIxexyNnsMoH5_Zau6j&PO`?XFyLLEeGKQD$?g2*4jsOR_sATU$F0>b4iRx z|Al*XnBJ9TN7`rkyUFVZbPoRR^1p|m`X||a`5^4B+wgl9$LHN;m^HHA4O}Pxi|AAf zt?U{%EU-xUcJW+^zWGy^YchCtxGFS39fE&y2ddFw+6SMhz4usdeRSRrxZvB{w3X}EgSIC%;8@=9XaMLz zE+FKXRov8t9uT=i3w)c(p9Mb5>SUv<22sB@$cqKG3Sm-q{YJ9&Wb>UG(^k-6)KZm_ z3N7yBET$(Tg8)H$7Q4hB)r3Gj&coGy+sfJQE({4tw#=>R_`q;P3l|BxX#C%mwE^%9 zztVG`kk{hlS>~@3!2MJO*2uU2IQ6US|I)3INd({ji+@8!4O+DN3_3HShy}vH=wFrj zm1;J}0|k}&JsJjv-ylZk{SplpVg#|kQln>Q<|$k1e^D%LUSN(fh@e&Y`ZeUo4@mBZ zwhYJ(oc{{1M|41qH1WsdLn>y!jYrf7H}uRO+TNpl%z}noaS!9)KPtgK!*A+h9LU7F z9PA!A?yfg#!zRLLfj7E=pvgAKzq8xM{j-C_>yju|y34w!X*RxE-@0J1@ z9GLbX4n)LkBpCmBLb_$F`>#Jz_XP}(cS~&Z%4Lq_bXW0hRa=Rwm(F+;X32YiqW8Hq zJK(o~5v;MnqbjwyZ1ZujX9%=2QE2ykms4JZwvYNKQy2gb1Ox;;>uPKBH==x5T^ZkY z2e{A`ul^?dccB2Qy}gfh+1?(ozJ0iwir3+x==W0O4+7_%f2*hI7K4?wq5K&@`J;$yuta5%O?Q#&58+B^5pIGVI-eK*VCq=e(3|@*8hLO4+scZ^jvY*{4 zHQCZ7>m>vrHEYZmi#Q<3;(Q+*yR*XB*79yW6IPENy8cPNwIH;0!dtJ8&2`cE#J7`?4Pu%0>W9%4~B;@-vnwdd;bl*#DT5ecyav;aq!+6R1c z_m-LgM{3~L%D{imsr*?T6$o@7Br-CxvbgwOyJ}wV=ln6DP~^P8=mYW|aF5V!Nd7&` zDEZ$?QVs!Le~hMkKCgsy>h!r-?*f~g^p+@)hOSu)7?xA2{yZM!J?ZQ-mkiuuZSK;G z@>7cW+I`#SED`^y5?=iqH;$bQs%_Aipuu?ZknwTrZ`{baQUi|=&WsH`!=O3@&#Fzq zhoTWT(R@diPhoMNpt-v4l8Jv9qsQz&c5^x4MA~|qm;pLwRm#C38{Bc>sL(@hiQ}BY zKf-o!G{&Nug4nekdjk<@$z_?zq?yq7hB_NyXxF(0Rq~Pjz8tc?h44wf3;f`}n=}9O zmw!5^4!3+5BAE!#j;c=p2mulh{PJS7ay-Ov!u;V-q~#r(fMi+Q0VHVy2!3|r#6$Li zn9*~sf-tRH1Op8aQD8-XE?U_%FJwFH0<{o3b`@yg5sKgdRRI4PoM}!zBzzSV%eNl0 z=LWVkzyo)R0w=7wDo*rYn@8JM`zf=3-%+C`Cic$P6h`Pj-}dimu6mBn_1{bXj`{yQ z%~||^wUzvj*X#fMMqHx*+v}2NevHb}uQ@l8NtMQ|A2M%<1mdC2y!|K7z#*?kCa>@w30ZszbIQ4()Q3NJ?L5`hEd%(; zX#EMK(Ofm0(4k%0o2b16H{M1{zvKLY1fXnPh*ocg94B31~-9 zAZ6279(#kmVPynzi(^5Se*XUms+zw3?hw&`htUe&0G0$GGD)q-CeVH!O;v%IIl^`X zcV*9ABfmXefD6Eb^@UOxP5y#zNtKc`R-}d2QrA1d!v`l4)drz05zvftrWX$n0fo`% zm#>PGdF10ENbq%bLJ)Hfp`irQ1+p2V+YYi_v$KdXV&b|7$BYs}rlxgDDQEH1t{|HA zi|w4fJh3kPCfWuX0Ck*&-z`i2I1|6`UXtMAW^4>v&P#V!AKFng>-?PzE zWQB#$XBgKf+2lzE+Yx>iiDE zMsijCtqaC_d{Rl!rMiA6LU7oTELGUPP7*&dk~$*$A+y%U(xf6|bxd%2Oz_DqoVCy} zlf3y)8%Muof{ZY{-{I?PsCM{(PggkoX=BdQ3&bLwuPM@G-sl3{ATi)$x1>vjVZJtP zD?~@JsALKs9o{q1L(Y`Spl@%gPir)MKT^Ra@OhAi#Cw{RSJr}EytHk)OQg8^$ z=Zjye%#5Dnjc2NwZ|}P0my;|ZRp9Y=sA-3Jw2`f2z0BSf1Vds_K%LCtTSU^xSBXej zP^JB)DM3)7cs$aFzP=1vQkQC#7NBFT&+y2{(|`->{ygAMySjV8%dz6=>8(Xvilm7Z z`$rHu0Qp*UK|$!=@sgCw2fGx>QXy5Rw?!f>wx+22F-`v6&b&Y$8*6zm-tGNQJi}ho z4e}dra+Z{Ap^Lc?lSb9}&Z2>o3tpzg_qwMHUk;TzluTwJI+_^ezA56tkhc>)r!55REAmN!!>|GZRzy=`9Yp?&i1$;h6*(gtDyn-i|%_@5f%Z20nnO> zL{Ka#EhdJq&Eh|i61|YrVwNU439plb;2{AC?C-Lxtp0UW1&%&k!kzdVHbm@I!=bD| zT~C=$6O(qMRcda|+_^H#*+Gt*jvD&K+@D>fEaOh&&Sglyjd$Ykq>w#S-776+iKV_r zjDXJKq(h4~si7%_jb6+1WW$Zg@V8SDd}I2P29hgJhR9c;Z|wd8!(Xn>_D?(};riXT z^{A=&yl7@|X2~z-8Q#0zFyLk|IV_Bgs)t@yUFUhl&y z0fZdj)tN^pSE_a5<}9dXYSaHz`?GOe;@i_rQ^uO3c5eLk<9;1ZE#f}s)ozQoH5Jb? zl>iq7i=O^Gr>!l&(M(PZ3}0oyT?_jS7mP~X1!`_bT7pxBY|mNRS4| z@$>pq4JR%~(C0iy&M$kELPHPOgm-BKx|=gHk1@k_CotVrGCGpH-0Thl)@Ts z_mI3VW&T=iyekbmemp1zAzV}~jC{8459Ac*N4Su1FHS03u%$$fmuq&~xk-$RlA^ZVEjH5atJ}e!Tb*ABF+}xb=@|m~_N`7OdT6Pm1mH|LB+;~ zA%L)fRMtuj!7c;*G@)!`U9#?AyA=I`D0{$97@xaG%4wIdBdAkRCH(n8}OB6`m=;#%@-r&U#SSUT23p@3W7DM4xsearMs#4*yjsDmuo}X}^vC{j z2|yx<{X0I32aVku-mgKt_SEaR|tzppD8A2Vm(CbeCa)AJ%n5=`RVASOm6P|o}r?bK3m z{>-1+^;}5Fzd5~%MB<}j62}>{&&lq+!<2)d;~o3o+iL(gK!I()nnbf=!J91eFq7>v zO<1*@Bt)iREECrKgn&xKH@w&~b>}m6Plh+s)Yfv|8oA6v#V9fLft&%|WhBMi#^K0{ z&UUHwEl?uM?dc9&^Q{suJR$vrCve~)#7LV5-8>hyUXdT-i3HFrjm6**?ViEJnzgK? zNc{q(N%JRn{*_GIm?pM0v1fMQ0sLCrjSa4bt7g)BF%Nc{yVIl4FL_Y0HOuyrLGFL$ z6Sl6ozLnpq#+fz4>Qo~5NrW6W#FUw&)b1gc(#|_P-yJ4>fnK?Ikqo^zDCXGON#2j` z=nAnMc7i89k$E{kg}loNg6!!IHY)bvgC}WBFjLtcSz_NIVl)wr#OTx!U@`XQ`iso9 z`=Hi5H0fYUeWK+J3v_SzbV(ntX}p;?fBvAnV#%jlU4@7NG3G!Vb+8-0xc$rga9*nY zrTNgHTZhWFKASPnLybnPOKEFL3QlsyD>a^v>WfcU3g#~UA|sjDIq-O2f7g3I zsDVeqgS4LQMPwNzgc7v7smr9iQDTtI!>?EEVFs3I_S(2tK-P*g)w{6mlSXB+WFe%S z7RZp(^Ha-_4^7ynuZba15O@me^Jv}1fL5AY)IqgWMbC|3a&=mXWY%a|o4H&7*5WmE{Aq!2{fItxk%u$EDtJ z+)x@>K&cHvA`w+miwNY_IL@FQoN+DKbbQ_nJ@XcwSha;Wz0(Ykcq5Kv3w(kAEL!?6 zTf3nS_PF2ymbw8EE7?ciH38P~_e1nE6a>0-KEYQ^lY1OAZ6(VTuI3wB#?}{#(b8w8 zx_7ceFSxoZKJ>}+(p(Q9k_4F z*{^|Uenu@+fUW?Xh4*~na~sgg5*H9)k8G?O5S_lSD{g9ngZ-VBn=?CeRQ+~=@1Udm zsb)vJMxbqC&F4$%{2x|)gN2Q?iDr$gPmk9jx%Up=_Bhwp&O%PVxqX(A9SZ2tcSl*} zut=^nnYyPpztV$q9bShUHR)W-GG3jRtFV}mFHn)}AOFKh39v$TAnQx#QR9F&c2p7m zRYYi9o>qcIIbey}?PoY1%IEyTeNqkqIPAo!$ma44$bX-96<`0jNVlOy?z9ZO3j&b3SGe%-U4_)rn^;bd>fIiUW1QcUNz+2xT+A0j~|;}RMcX?Uu) zb0jcAAgm~3-B_k~xk!3KyR6|D;;!Q);={?@Kr`Y5Z&UHwsh`v1d}@)qR-Ao>LKa7s zv-rn~I(eh-oeme?r1=~9(WxKW2eIB&0Sy?QW!ja^P{=KH4tV&34CSA`*rSwM78V@|Z}yOt?%vG*cC5JIvj&cU6e6qWmZ7>XX_q}3Vyazt@>?Jsq|b<`Le zsVihs^n)C^H{PPJGK@zJg%?rO&P(JJLHJ-{l4Zu2R#}ypo3*_^3+{(YLylS7uo;5V zScUh&0bATEhXpMM@iI{qKe~`#yHI>$n+X z4PU{8A{dVtU1Bs#bvl znJe~WONm0V5AF5hMq<#a8~yeu9YfIIp5Ks+JqM91(sr@+Gnv^)$0cP80dE-<`Xmc5 z7beQ@J9-1>ME)e5ZiB|Lul<+w^fc<|c~zul>kkpi@8~O&q8j>bxc4J#5gF3MFMh%b zL+@>2k0Ur}su({fRvM(tebXWN6}ifw7#1fTHCsVgOL_X8PB{krr|bW^N~BxdsjUt>mw$U zf?gkeCg_5*Az|6w1xz8DF|BKwlvI)Ov4B2R-=5Euc+)7&F7@@Y6#(aGau|s_g&jA_ z!gs{MI?bwY3Ek><7=2V@W|>t(MRiL#sp?Cz<>Fe@C=L zfom9F%}mt8R5!`-5mC7c71BS0V-oJB#DD&1k!7Sq^&=l6wX9s*bGzOn*K3CRsr-F- zKa|nxh?;mEd4xrd0osoxB4!9HEL8$_?yZzsd-p9ezeJZF5iA7VQMg@jXaGDGK&01f$xkdz;+nZt?VM=SwJxc0=`qr|iC*X@h7IQ(sbM7o(P7;Js@ z3#VQ(l&|jBG}p70`vL#}u4!5%0)HSn+G*XD-~r{zXu&3z{>?jCH~z;JDs1)JF3%vg zJI-s)l8TA#yI@oYVcU|ZMx#lDwY%IQ!*3JqHtZ*tjVRy#mESEACt3@O?h_erS{4X2 zP;v$o9!tp>4Ca<7DVJM{S7v3F&3tQa)zmN#DFGCb(m|UYo|hilpI)+e9GbWMve;Xr z`?L-VlcT;TWg1_Ib=TDyNfuP|BT*Zx8G@^4Muv{H4O@8;8gb^D#yf&x0@Gq_UFtp7 z4YMj;MwbD$-mX~w8ItjJzxmge;0iFY!&o{Zv>D;<&LdDnAj9LP-Tpv#Evpk%jMedu zFhX2ZsEEdP+U4sPL~X(sW?psA6gK*Im**AgEI_-U4Lu5C%MyS8mQH+&B)wBA2>~z6 zyx6+6VC9_pMvDL&dh%0Ii-*KXLaPNB2x=+uj#oj>mc?hR`}{-OQA5TE-J6wh37F z7^dTs8WV!OAZJ+1na7O%k$PhnOTQ1}LD#Rc?1BwbZ8r!9@7yG|`3Ky((!=de=d5Eh zZlbit-QisCaAxt3hT*@m1yAgL`>eY9!AlnX;%{Wq{QO|Is2ut5;t=~Kgw2~dEu3+E4?{n0Lv6kwTznq5MeH*z7)uBLN-c3mM)<~tQ_U;6P( zI(#fIYuj?nTZU?(X<^2koIdxOgo9)Bvcc)CM{FY=iO=}Y) zX0));PoJ9fk2z?1TF9eoEYmTh4vcrfQZ%A8B!Hw-F?V{T(fBVHfR8eeLCb_mZ=CQdoWY_c7lbjj{gF=-{<>4C^@opI zpwZmXmb^x>(FiAZjQooYQNDs>E2pO`Ry8EwzTr*F^La2d?s2|!C=-j25}=jqiSbm# zIqJn)D)0H-eW~<&)NOyc@$2sSK>#1-c%-7P&^mQ(szmvrqsTHgZg)znM*I5Gof?hw zmqD8TbJgXbc(Cc^Bx#wj5`v1x=wy7=+;&+1Xyk4cGd^q^pV&LGnx5MVWzqPzOGiP% zRIj1u_kSty>h_6OFs-|s5qA(N-$Dv`*<3X|;^4d>>b1TzT+*VKBD?=F#XFl+ES~GH zbJstI-PgvQ&D1hu^C(q+oms^9O#CW$I9$up0*vW5%8pk?)jOeNj`{!oP1x*LmxW!2 z9C?gLX7_iOlbr@igD)6mk$T?U+IinvWB4{~e|lX`OmfebM$ui?QB|9@Rfu zc58t$orae+3d{RF&zCtGF+ZfuJZ3i@G^89b$Spx$v1EQKP{^5i&jL0O8NJ9@G!UJB z{97O}h;Y)0dut(4hCxGLR?W9adUt!)6(-e6ZNhEB|8%{lBz&%6*^T;5AANdM<{jA) zRg_)2(%v$|2#)mCMVw&EQwu9zFHT)FB(3GObjxM+)@}Ab&Cu+Mjodl8vFe+n5^JKS zA;PjY%#xVbLMah~+P;EzVcAr|=OCuIyh!VgB@OSZHCYx5&$ zNoO+uN+24-eA?)j*?5+cW$nI~uhg70W-3pdu2S#&1k1VekKjVGsCx@qp%YGcqPppb zJH;lMYHEQTp(v`kKtmU}b%b?3Q`aU=8Oaq0byjy&j_SN^8WE@z3zsJ*3>PN@VZgsU zp+(v=x=N3i()zb#r zEpL0dz%5z*<6`fUyS1cL$V4aAdFdBM3@j52iEz2$ja{RmfAeK>&?J0u1D3UznO#iL z+6XfHY=k#Q44*;j}N4f#YS*<9LAc%?UG~aD2VOmtER=GEK(H?V=vU zzZi(An7q!JbRIfb;b`3VnvmQW@yk>TiG!GSC{|Sr@t=zsgF~nKm**5VAj;Zu{coRZ znBJL8y&p`)`F^+EgGoGe-@TuKTzdqy-c73;&P|j#{fr=rl=BkA77=!0Vj8OFNa=~% zF;yTB4)+=E>${p%B;j_*2?g z{0NDzA&9gYfy!@joT8XDwY|CL)#rXrU#6k}1^O$gs_>%*(Q?NBeR5*nJka&O@q?}%tsDI=zdkz?Y0W56bi(t!0xh4Ply|J4 zJap!9Y30C=3hKky5?P+6*$^B@1B-EjEQBN+WFZGhcD;>7?XAIpe-=JRj#O`#^zYBWqdJznbJKcFKpDd{ehHa_En`Rl#{B<0tG`b&acJsED}@@ zxs*kNS@uqxNSePDZLdS}VR34PIV-zW*4_Xqg$R_In~R1qQvN=3M_1 zQ29aZE366!FM5$iQoe$IMINGQIqgq*;5wD&A7Crm{cV4C#A49cTTpANnIh{1uiq{h z^vvp88?#OAI=)eZcw^_3Kb1y~&U_)(Ez`Hkq6s;iFfjf>z&lMBG`cUA(hXTM8+e&s zsfVR|3EI}LO$qTD*v*ck2ucC^q7%@9?9M1)bqM};FC2gECH{d7Yt3R-VbRkEc(13d zvN%11MDSS614eC(pR*->J`PZObM3z;8GR&jOvQYL?Em;M1B#*iEKYq#azxi30(H8g z=zeDjlw)pA$#fp| z0yW_e>aXNZdJwlokvX1X#dFMY^Ebwa!4d+QssVJf)b>gqht?S?3qAZdpX;Nlo!j^hly%*k!`5*M6!qgtr(AD+wGQy($EK3u@g=1YEC z`yw2Yfo-qso@3Wx{>@#|Nc0RE89vKD3!?ka!Pyh-_>9!h`Z5$W&<1x_GjneK9$hqS z07*0gvj{hlXSIO-hiVa_9X0sf@$mnBEqh!_)LV8>mu`SXg?6GugwfCZ(Gs8fYGK?G z13cCDR#)X}s2p+Qa`$i*F`s_#RNYrLtJa}op;WMpeFEl7%6YMx za4P!>bE!J1k*uGD`fsm%CR?IidDf=Vo}xYAWmqA71uP!cbYQNc09fg?_~cJ}2uHe- zd(V2(zKt@afBIGi-8v->gse`q@^}$QulYo|WR-0(K9CC6?V3BV#2^K26(%?cQx$ef zsj2d{2}ems3*zX1eINR+@kyUAD8rO(jsSnnc043mIyzliL;I;Yq>*aiL+~u7=!L8$O@AxD z$NKuh&hcj~V^q3CEe}$$G{v2*Rfz6Nx=T8sV`I5&pq#C76%8emX@SWcQPYP8)!43Y zw=mgJb0O6-Ea8AxD{JAAmLFj^5cp8* z)bbRS+Fb(Le56HLW)&>;vV=QD$*=a-a*wDZk-y@N=HuE>0T2ae>k?{SB>JfYhM)Ug zK6eLK5$}Io3Z%uoE(^{9Q8Wn7KitTO>k~>zfS=yK?wLxRyu4j@XnrO3Uycf8<=D0b z<-|AVg4JRj0+F1W0@3)GBke(q&`b7##^bDBMH48e_W0Epk%j~|w~YN)08M}Fsep@Tr7XM+)X!@+p_Gz@{{xXzCO>s957Mgh8!HKKHGjSW8soTX<=%R zZ#MVw0F%Jd;&0e(s8FOd)mXl^qy}}@1DTT$-5yTO+&Z8lcS%4 zCn$XFFTaXm6^YMT7)6#T}ijxTJb~q$BA)%NGDyMmLs?6 zE%VR2J52vF!ww%qa_x9vLle#bnid7MqdcK^ViChH$IZz+&4v1u^$Mki+An3{nSC++ z8i|vra;L}e(#&F%n{F`fYaTOMw)%)eqn3d_)Q}~TQt4>G>O6`>WKJnfkHD@2RiVP@d_e#@#uchk&-=UrVkUW9NheDkqy2Q zWR-+X=3SkK!Q||I&oojKM+~yVlYjh}-t!3xBL&$0oY<3NxESnU3nP)Q}jf+$jlrP8R^9Y7VVlS(gMme^^m2kWW z|NO=9B1c?U<<{_v0TO&s40pCXm~pVoI;HHYRo- z<_xihWaa>oc~Wcn#qD9YQyR>GSpO^qBo>Q)dMPnEm8TgX$%!yGIAf9LhR3qt`^tiAjl`Ad0tbqno&7T}?Q^f@iFX zBli8*eP*y+dCz_CGw8+R)^Qm2N5*&&+;UG2sG^Q4+3%q)U*}x!@o-TdwJ9B^{|=Ub zU0ZTaowzCjiamqe9FM8=TFKeg(Pj%gmwf3vU;eL1aELKA+~p7qxa!G>u7HEk(emuL=Crj_2jz%0-naBsl&)Z zXITAFTe-$a|M3$F_oY$!ATuvj`MU_c2F9{ky%2ZSFFLW*jbxY5)z53Czj}ixrG@)?HE%N;= z{Tcq3<03XGF0>^OGjtOUFy6ubxY~^&@eupPz{53e*aY7t_$rl+b7?A+;JC8xtrBTU z@t?8@F_i%)`-ydn$z!g{fWx7J8kRro_r(Hj?hJ;KnvXKWJ1cNUARioUKghS$=*U*W zZprIM{b{9{=!zKnl;zfw2!v%4ls%Mx`CM?P&;VxO21o#C-j}V+Xh5!V` zm(e+CkiWM#*>XM-H1B~B*jcpj6jNBZWwrty$?wQqg4L;#Q{vr)eYjYpbp zIpln|wb7kX+1ydk*YLel7l?AacCPiL%DShFYjlU)I}uw zYg_gws!onyKP8gUN{x5^+T$B|_es=n5MvtuH~O#dJ^t$mJH`b-thOWZn7FG$;?iT; z)tC2MW`JF%q5TCpMr+T=Y_sSs-pqI35!S-gER%MmjcR49?g$YclnnLfC~p!7`Fz$D!<0A|mdd>tuj3?trO8JNy| z!_n0USHwY4K{2IT4fle#Q@mU9COg4m!_?DG4|`r9ic@z){>L4Rf|<%o6kq;8O8O^o z8Jl$PL_mG&XmRh+LUbZ=pjdvxZc7iGte{e`zQj4~V3z#~1q^(QHp%n*N!92_0oH3F zYz^>nU75Y7aalpY%jr&d17&~5_U<|b_Y$23yWc^|2IFa^%R;3GCG6_J!dCfn=J!vE z!iP`M1M|@2n4%Jgkx3kEn0LoYf#RmJpI6(lr~{?HGM{B8+TL84_KkFY8*}+y{-Fo# zHA43lK-f-%lE@1v$+zMWe5|Gq{U{XrC16G%0Pe8M8Z2x^(;=jP0_ZpbSOPkxeW!jM zJ|+Zwa?68SDE@j8Q}noc|LC!ib}oScKtB7>pqMF=$a%J6&}}K-8Mi#|7SgMsYe9XLg zcfJ2km`*_@vog;=ir?0mv-ZmSQ2nZ`)s(JZ9zklF`Y-WH&~z-l$%GZkJB2dIzGz6{ za}NdvCnBaBMr1Z$J2t{;$1j2r{1ihtQx`SvCO!pHhM_+Vi zBNJPd&GNFLi=Sysbhp69Cpw(_rnGmcmn5vtZ2@*R#86Ge2<|w&uMGKDy9%y@j zDU7|&2$X0wl{IfPxbrI;k=AIbk@fvfJb$5gvavPDJo zUJ3x-(j%hRr{Rrz0gr1@x(ZU)Lk4FW_vdUck{j;r#^e)E=8{pesg!#`3>!$cvhsK6 z9YRGBmx_{(0Fq5pndQm7D=AVxclY0k_VhB*J$?j>w!3FhpQyy<0r(;TlD}Z}i9Q^3?~K*b?>Vgqt2qC5 zU)5bH4is|tU1L@kJVJ6>WlLN}+2SAVYEZm6ow=@2;clmWum#C@Ah8j#kub=fdkp)e z5WG3rv$rq*j#tL;hZVT^zyqS>$f&7dofKF^k#QOhsN+X%StZUU@s4i6bRnS%y=Q-l zT}9|X+*7^kke{W(C1WlSpT@BZ4S)e!@XK1;F%MAW9niZ}N}x_&A|2W$zNmhNkk{$G zb0MYpJ?6zf0@q+y^USXMNaF5g)qMf8#{MKYa76zz7UC~l%8NChGil1Xu*9w-e;SX! zu+IIE5go4J<%!4${=vVE=*jMfMH@cvKlH5f79KFf2;^C$gzld6yu`|L|L%+W*Vc$Y zt`5M40O`<=sh#B_E=!9H8$?|ZGHEU;UNw!*_@b=|1+i^yxV1{AkgrZ+=L#jQ*4&h^O4!!`HXulk8i4<&A3&l5|d)pWS+?#FBE_YiI)uG5H0wLjHe4hMc;k(t3R|>eiT(Vcs%A>abKg>cKd46 zQ0j8~!j$zg`->~I)A4|eJ3$;e;ZHWa0%su5JyxpFpIRH$UtJs0X~(j$GFpN~<|(bb?D`Fzy7jvL7V%xX@1>03O3`+WqX`@Mu$v7Ecc7K!x$y>ov=Hi}7J<)|~~Th##1cab1S zzui)vXlqY*9ltf;>>ydm)lk~|5FunCe1kvo^pt}Z>m+qG%h4;FDs(Uv-IO+3jW_F`p zc4mw=w9a83{1ZWzocjC|WUyPy>PERB*g58xPyef|W{5xga8UTv-RSnYtipbA7QW?S zmx%>35B_TX1DnT94N0vhc|I`j3F~gfNHsX-dpU@#KM)Zqr3`8oz(NY;U&B)Up+j(Y z;M^KlMtOu1jUr8HO*;S4XKHc<XIDZ`9^0*&bzuGMrm(7JuU|l1xO>TfyVPd*^?0S?6$M7aAFk7Z_rBVh2*wc zJyWS#Np}uNwD{)f8jw7NW>Omrf=!YJE?X4qpr|G&mxI2&if|%pw-;6Wu59pwYs0jiZ%q`-muSh zx`V~#>VLR#6`h6DqqT;z{j+LkH>Po(o`r=rsPm;yN?sm$XFPjtj1v<+Ls>^BibgK! zed(Mz7brN>AgZc(jE2GHV~u#yc!Es7T`rY8#5$?pTOV|1>?mOe4LI@IF5ksj?a~tX za{{G0IC_DDNXD$d;k;%-%0e`O?~?sL0e-TJ!$yD}a zW7QHvO2et~8)0T&wq+;&7HpIuikh9So+-io)YJ=j`tAHHIoo9s6s^xoP(!F3d z5?70C`R%-|)@Z8nsU!P=Tz-Wom!*b4s2qa96=?XGKlj&i0Dcb#Q4%&qTmwf1pyLdP zr}eZ8y$4n#{6$%n*QO!K?*rLxSYeH+I>=I-3|ZV={~=jhXOFt)i%0L`t$fHLjr-o? z`(G{qA%0Y(iJfnsR4<8<@icDHjI880*tAxI-@j`=j;wsE>?6jRD%2LphS@|)ehJpp&w*3Q&Qt9ENTboyx=kK;ty0wz>IiD zn#mYqMXI}#e>1s5h};;(uim2AgHLJq>ph#P`>N*msUBm)h>K!m4hE$@JD3#M8@nf7 zE@mYelw0B%YhspkCh=F`>E({?^Amy9hp#?tmW_sv^_1?}(eL|ad_Z#i-n+linap~A zGRln%tyv#>Ct4hyJTL-2niS_ngMn7MA7D7CQMXRgGC+}9ah3nArtmno?!X`&m$ z-+`**2J0idW`ZEV*->(iv)Xkzg63 zMf|Xwa$N`TS#&TZiC+AG5YKHSl1{LQIj6HrP(*u%DDp$_m0ZNUek*afuK8=Sxh}AQ zVXCeF-6%u!J?g|06l2J-Typ(%$> zf0mdFg*Oqx$0&S)z5!DAgxi>HsG&hSs(RNaF8&zBR`6IO0U8}3|B2!+vGvO_<=d$f z>cP^F^9ZU(CHujO@UZZ)W5Z~Bi!ic8Np}gdu;h^}vbqUkv<@3S|3=`4>k_;s{4*l{ zPS9M2+w^7}&FQLC&u}O9s%o|S#acD}?*w|3U9W8G^*f${VTWAtZ;~B%^UbWxHQZ-l zQ78}z^DQt)CXZqAU={6qSW*u;{7#>wfH1`>5c5qn;4|uuGv%TMw6FU0RA9UIeqHqJ zV1j;zSnLY?**pI(V1E3F#T*-U7vjgqjtbB9VKaBt0>)=)kw#uwyVw}dC&F{$t^(079VW&YO8cR@boS82`Gwas6&T$<%+)5q33^%12R zg|LQ=Ij;6JlZk=}%o3(pEk0>d&IZtjen*X+JabZrd%Pv{HD5zlcq3&>&TJ3XyqOiOX0;@mi4Fo4dqv zuU>S0c>PoqqqNpQUrx3BX{W$$X{Upu8mc$~!B50rgN>%+8LoqIBx54u{2MUU1ZGzD zl@!piu7!h;@Bn%oWQSmipcts919yhWDNv((`cYbhn6OkWXMtdy@6S)omDZ}Svo<6O zDVT|CDbWu$_Gsutb?(e}FT9f~ADtR-Om8PSFq1WP|^ko_iXl&q}4Ia;r zi-Gy!Kkow{+Ka2I;;NQu&P@J&JJWv-05b}#Mrv`B|M&QRpMLwLP6dtr|9kj<$0QT~ zr`Gx3GyLBn_Jb6T|M$@>UR;DIL{ZWQdmix6Wx-#Hu@NR<{`W1(LjUgs+BXf2jS&9x zY#_Mwzb^;M!DB$a@$UZn#D71jlP2^(wfX;9ivRmuFcfioOLYI=8v>EwDKF@Lo=8$V zVu8@c+mSUu9Mu0DA{IgM(-xqFfaY<7M?;H&Pn5+WPaa;;dY`OmsyJ!RrS*4eDqfQ# z=|7)xjDT?sdj{d};35Shd4=pBlhQbPfgR<+VT?&XnQahhKKPzGD30slOKLWc8fg); zZP~pGG)D(OaAAx{{p5?a%WZ}3`5vFm8R{Lrf0c`wJDGz_EL&OLE(N$^$q4@mFqE{i{KFm~<{>)96|Wslb*IvHiC!fosUKB+is4HL zX)eoc(nmeI^8ak;L))WAqV;EWCd(!BRAuEf%KDQ5_GqFK0IsfJnFOZ)DbR~}_DZ+{ z2)9P}0q%hW38Ln44pANQ^!}r4o3--`-ldg&F+!KFDHv6+_?^5##mWLBr}1F3GV&tQ z*@uAN@phn8kEe{#8a%X3@P98j7Xf7&;yM<=GWsS>OVHb57r9pfbua!O3 zYyY?YllqaI1U!U)9_)IOP4)XpTjmuJ_*fsf9Ir>kL&v~yKoI%GKC^Z4@8LiK0a*ZB zb0(eZLWh4GJQ@0y!v|6d&=WiwP%cv5Vhx{`0rh(5Ew=Z zeMSm+$c0$s?>9t#DdvKPhL#^68(Upo-L*x^Kp=lv}Bj+&8a~v%ep4)&g&4saZ%cetk6U_#tBZPa^(HnimRq$#IF= zY*5+twUJ-;Tn?x1P_XqUwpf8@0dvD-B7q_QL+Pot2dpnUD+q<>iH(a(icoQb2%ccRV|Ea(;qy zsk=K!g(2}*X+whn7Ze&A+H^f9VbnWjX6`xqL|J!FPoBN*k$3d;l>&aXnmUJvhf9of zbaeTX5v?5#)c(kOs{XIb4k_M(I%t#HN@YDuV4MzBD52>T{dL(K5*R(o z`$%Sut0>Y!zpwtG9tN!lzkx&_D4O^vGm4&EM_b5wZHU^pnKY@098wYr6)QeRm2j^+`=PEde;q2;HlxC5M?}Ht=RHuTH6x@b zS(4glA#w$jdzVI3{MOs|%lu9T@-R|X4(YW?Te43!K+OPG~8oRx@ZL|fZFyQW@iTdITAF7yZfxXDit58+vFFNU! z04*L~B)(k`lVEi1C@Sk&t-@Zl@CHoh!o9MVPo zD(OdcUEJxdZ`)q>PEZ%VEk7(as~=;DYF$rtV}(z5gr!7g@*?TTBoV?3SQpRt+4MpD zPu$Uf?GA_{0|Uk!EzdVgSN&vu6JOPIOw_O^%3%a9EPEG>;RaI31Vq#(vn*Sv6&hJ=*T)Wzy zr&XVfv-m@$V?o}u;q|srL*=7)Ggt)#2cO)MkbO zPo+*c^S$LgjR-Wzno z&PsPGS^r^#I%UR7D1GLUsJRmjI7@oin!NdY-flprG3-B<7%eirL-SO)hWqwnY?v`V z;UjhuD&L5Ae!vY}*Llw$g;K0}q;3GY{CKMv&!#(I%Z_t|)I#JA0$4HhKg~8$=lw3W zssG#j!G3+-I^=`bJen`C^YS{0H~%QTQYe7a(9Or(M;$xRy*_8nrHQ)S9k`@exilv7 zfKlVI&V*$7-0~(I8AdI9X7|FTNquC@ajISzN*DjoEl@*7+01M*>BBqY^)T1emjdnB zeiQrXf{(2KxWp>tF)}wE8a~Vopvt?O%wj&Wg7YdhA;jS+zM&Tisor#hLbmhM#dVk5 zAaiNH$%WC;$;m@S1^aNRo)r@lGvlPi<8nv+k3K|!eB~=lEk6hmiCS7RU?aj98XBS# zX}!SIdflG9cRj*?)5wa9M1~JMOS;~&KqMtf8wz}Kp5ZMGtVo9V6xA@I`l3?dCX6K> zw$xM0Bq{!6ll+*<#h;qlfISvfz~63WkMECPa_p0FiG{Ps1bNmvb5jlY{@xF!#z-@W zj;=*I2)MwoPCnqt+k`&(d#lFogzp})=1b$oz;W3}#>Oyhg|tzxsmpVu zg+KEbM41Z9VR-~vahl#~aKm}?KBHvfDQa8*d6xk0>FrXV?n54(+5r*(=wj*#lD%RW zxt$D7q)w~5+_?DCnvsdOq!~Cq(Ut1N-bbIm%bvwwy&${0A6q%Y347n~4vd!gh!e(V zL(bnIN;IEc_$<(LByozGB7CSf4{7i1#=J^#CyOmHbazTPHVeRmg^cK5Qrs-W1KKkn zIKuhFeegZ|AcGdula*&UJAVaS+_4PgAS-3qHa<8uD364rzG4zgMNK&LIf zqy1j}9pqLnv#jHik!!G$6A^6LbEJ&4P4vn$kfW9_uICA5SS<2ul|5Gd+2%t?D3_Pd zg}e9F+G(To)}q-Lx5l`vK{Qf1L&sF?*5-bV8$4V_hnILhs&dUk_fic$82g%$ZY)(l zbqsb|Qn+<-3AAtMpClpB-)vGPf}Ix5UIcJHoJHX@9r?p2?6f2QG6>4p_=&9p6SY=q zPoVUe5jb|->3~0h?o%Hq&=%1hiY8#K>>3rWC;cXf1wOS@wNjxcQmRo6>)^1%DzLG! zq2BDu9D+uM+N!%YUJSvF8R>w0n0S)Z7IM`R%v$FXxGIVij6e}J9wy9N!a%oCQ}mg; zsdo5-&@UM8qOKbT0Z=t$0OB)GkWdEu&M;qvc4T*eFRN6D7s~7+^HgUC+wAWqbBk37uy(rnrwcCmoBi#~8Ux z$pam8gRc;PaOL0jNj|R53q3o%2iP{cQT`LCo;#Ngs^cNM4mL#C5n-93$i7 z<9#2XT&tryLFL*wVP^K+ZY}H4#`^bwfb-KR_A%G*u-;93%kQtZNjzl1iB-jI8d2 z{;{zdlc9@DU2yD%)v8x_{W^*mR@p-Yn4rK^7Y;BGeQffSbVYa&Uw$}bANGT<{SvNU}|5e;3}O*#(0{y4Tv=6bgggb)VXU{(QmQzOgO9GiDVLq>&UOkpBfb4GLn(wRo#XvdpHH1V3qmK1-i zF^4zl_yl7OA|RmllhX%F=7I;>Z_AnHFmEnPJi|Z+R@nQ_J{?LfiK+MkseI75YiBf_ zgmip(xVu0h{S4Hgh64Cq4!*s~6Rfrj@v>>a>1H(c@^W%wW&6GGnU1EJEb#h1xsRmt zjz_T9RW70)pat<&G?V#T0pY&|D7d(;bcF9QC~Lide07sFvYbgaU(Er za9~74MDUSev9Ympii+R^$+@m3nDC9vXG;knp+;TM!^6YvA8%|5p{9I&eZirc!Q#21 zpoHti#RWLeRz1(Zt~&79#oml0?{m96HSGZbP^9vEFtT!ECZh|e3B3;q;N{zG{%zq$ z=KrqbSSZ6OKd4R%5HzcOMlc%LSBYl7y|1xen|rCuimOAjn!B#}Y{^tUJ@(*p`=yiJ zj1}xlO@I+IbSZ2d`fQB#&0f`eUNrsKr{4F^(%{U`>IRMY$SOiI-zxnY)Uf`UpPcWe z{;iw$sV=WA6MG@5N*eaYw$E3NWX`9*kdV#2C=5fbcpN)Dxp*~qpTBdS`V8EhE}lVy z;f;BTCyND)y?TmwH$rr=#PBN>T9sxeJGe_o%*Bg%B;NbIhij`SNbw{wq9kYuERE1} zGLIOBLKoiXwjovSoOyMyol;#W>eCOi}y%X-x8qJIrl>UNw7?k%w9m=w-U^ z;Xe0!=Sg!`QvROu?Nkpxs;-#Zi%~9YiEOD6x#-f24u=Nf!g7~{Y${LB2zaCFHUv3- zi*OP$!acD3(%v;=eNP5mPDg~7@nd$A|j%jDn{^4j2AXo+`wtXoQsl=kKpmm_`cjp)1`$0hhaARp23Ofg*_YpMW_xjbWY;5Q;LO1wC zZ2ABsq&40s4j!HnC=@+kV}ZrWP(@a8JYPvgtC%ss4@$bx>t`k;1TkyXo!KnaHFBe4 z?rB|bnR6YTZeVxQ zX$Da>AuVX|40N^yyP9FjaZ~AxMflH|vKd!KnnKYa05)3jHPgJw`UP`X0Fu|>d~o-! zoXDz#I3{e)kU-8Syi#X0(D;#?Y^0xIdd$MW#kS=0k`Y~b^6QiNC-R=ol@~o?X!&cb z2@^wB=$;gjMHy@*_%M(7!LpafWMk_9-9*cUB-OjtIc(7NJxC)5kMzIvS8i&h8%*sk z3E?gpz={iu6kQ1@*Tat~tO1(1fng!PtEsgdF;nm6dIxZx83t?Aq>W z6FwgKtstYJ^Doytuj zO#t(MMG7|b)O87Snnw3tUaxx}*vng=2PYasU!$$B6`I?JyNzB0R+XqIu;|gr(W*6` z4Y057PNv{$A5P2BmvHsx2uUjZYkY|T>jU2+WT|;?69hY=`KYh*9xwnUZQpizL~4h^ z({1{p6{pJhy7ETBk12*J6IH<-tLu%fPa6%#0)9q&gf{Kt6)|TIi2h+FVqquElP5@4 z7Gt``8SZ^MZi-B`%-^ZhpWC48JhNbW1Z{8m4+6KAm4KeOb)JL`lBv*qGM~u9uWFXg zwnhdMcnjX{S2vEAq2Od$2Z;aO7-}{*4dDZUxPgoh0`K0zbEJ+qhE_59zTBHxFV&$K z^`-oUp{Ax@&+7m=6*d7#*$6Ai~59Y;@Y?IQ&Ysu&@9se^*^8-82yr z6GwvieX>F(f8y?Lx?UJHCc>Mnyxf^Y#oSi9UE4-7tDdy8GuPWjG1SLq*aL69+Opu8 z7%UgAa^iD5@-*_s(>Z;Dy*8yMkB&i-5M$o$Uw}nyE2D{5qie0AQk!Y(YUxav&PnmH&&NL6c?_IzAn2QxQvKt@tbrMW@!>u{V$ z5^LL1XYJz9n$ram<6Jn!H+Po*y~hbOJG95Qh7uX~CUT(wQHDfHaD=Yc%@G99^73%l z!UQvW@ozZw`dbF4uFv&XWC9LoVc{JC!4l1~4QsYvhNJP|C1vZo0yZtV8k*=}*O77@ zH(dl^QHk$T)tN{UfdGmHfTh7^!AtCW@(1R9x?l8Qz|gxDlf0%h!q*S#blyjk2w3Zm zgIc|By1t;0b<mWG#VjS*zr<*3?447;YL?5F@VdW zJ;3k6QTUCWFe>SJHp}yXK7GAES0eO}`6Q(+R~p?BXd|ocTPR7fu|P));r4!EwkfC> z`VTjFMC1sZlMC_9x-+MFt5g}FsLWy@F z$lrH?oG-;Mr+4RDYyTf-Zyi`S_TF>fbImo^%&0rbQ9{?)TGQd$G`eRvk>nl7OUjy? z8cytoeN7^6+EW?Is~Rq+ehUo9z_mQD*-twoJORv@9iA}UzX|vn zM?#(0dfq@SOVW8zuOL@)_{K`;eoY+vr$-KujX+rr&3teAWH_#utKes6a$}X_I%AO2 zf13s;`sad6C(ZcLnq*?rGzU4t)e`-?KXudJx!qH;*A!<{64C6Xf0qD2O4O_uu2EFm zt>F@DLJ@s;uW8k3^~;aEM{b;v!To#M6U{dl-8Ok2zXy{CJ3*Z6$YsU9WB;$+Cd}sR zHo9nn1B#Ci8;>gBkTC7RP9iE>#^4y(JPTkQM9kMCzK;PxXoL-hy`o^1+sPouh(=Ad z7IVwpp@8fw+-$YNi@N?GE^vAhWWXk^&tk|B_uET?`mM&z{J7Cw5*%?$lYI~>@~e)5 zZ&vQ@xv|>s(M+ygW8EHxN9X2N=j8f|1Rc@qW+Tz7GZZHQjn}h;D@fe0Jpf6&X3~;N ztw_TV1*E{*`oJaR4h|60)GYHD{UN5&?7;=5bK~S_c()R&WXS|vBsDaWOyk2oYWc*L zwHvezrSMn@zLTl)Kw()z7SB~Xtmk-GsFpoEuxVjjnx7X)bkaMxLp0t8Sxh>1f=y2K zO9q(e;MXvZ315>Cy6 zA6|NcBn(h?B0+phA7D3BtTPDj({&!39zFcl{N8Q!mTW6q>%_zb6X{CN+9 zZ9DdZ*BcKIr9xXVyc#qH+L9nccV0au4}W4wCUz1ovu7LKWE-cMqF>itpwTNlu%dt0 z25k}LuMz;Yn=t1k0m^$!%9=~1sG{vhD^5-$AyI9;cfb2fmpM`1Z6m_(8spt!=o1k z1x1zZBJuP1A~4#rzzfu@vwsPuPG5eNUEo>Ugo(2x8rF9jSr~{v2TTY*ex(Y)R%Tpm zOk9o}=Idc?y;nBvJiR=a=XL5{YO41(#k(+_u#)7km=ISu2vlbxsm0w-|G>;ul6j=@Q~XCN-C8~=0m!8Qy& z1wJ@y%aZGZCVR}u$1cQ(au>iu^Pr)ZPbq(>E7j%A1FpLKK7nza)@MYzN}pP5dC50S z+fR%hGEr6gPUq>`%b-cXW~<@#H&an`{u(~w*dwNPccT@uIq0wL zqWb$J4QJdKf23mR$A#2i+bW2>uH8)VIRf5A(R3RdMJdkd1RVaU*$xBXxsluSH)ukAyGFNS&@-1*VvFOc^(OY-7GV&bJPOP4EB5v+Sc^@ zoZO>!8Jvw?CubP~kOwYotwA#Pncz(Dzf9Os`L{#TeeA{KIoL{Bf zU$nmdU8zDT^wU zuQN;~bN6vyo6sN_LSakADOUQrJVGO_o@h%5GdgdG5`8(gSTzyOJ-SL*Zq8lZ z{F}+GGE@Dt68Xe3c+=;gt;o?j4RnF?rN!me6fF;EzD;Y|MMXn(m!;I*rPT8Mi#^RW zkNbWJBcg--xpFScI$Os_qS$56N)5!x-Fo}UemWvGVT-4kA5x@uDp0#9*tG^Y=}eP@twwlIm6F!7k7 zsG<_(H_@F43;dV(b{zNUvGjwbih3`-v1bod65K6OSp}%qIwhAZj}2+RC8@aeJOL!-8R;in+K?ase?yGk|la2H@OIj!w3mN|BK^W?Ke6p~S-pHf-Gy@9fazU8I;pLPF7 zLi1YjLAPLJK>-s&Y+q+0vvxN=s?!Gr&X{aA z&&XWU0%9|%7txv-+B!NB;GX$yB$=b<8|}dN(o$Ah#qXWMH|u!m>FIhqb&ThT>}n4a z$xq9_@Dx4{R6#XwmS)NtC5qo|rslGD`@ph24wnGHNINM$j4>0WO|nqsGoUtQ`Gd=3 zP<8NYm9lM#20AfYuAhhZ5#?a>lT7EWYsEg+m93$QQwMSDcyu8L)CRUujX?twjrQD2jV=?gNEus16T2Z8t6-w%>%8{K%89SNAGqK9us=asTG$em zn#|H^kjLmO@oyy~3(j5ZSRatA64?PG>2CuLUNtwe~i70?6^fO9t5htmXZ7)zUeKjV59-G(3g zhYZ7fCHk#VAiBQ?IZQ8*hT`^KtaE@13)@Wn0|t9#TgA0Y;yOB{{jf}Ye0KeTlaa8vOjFpsl`e{!8&xv9@u$Kf-=?qTZ@p_Je?()m~?|ebIeATE=NF zpW3+pc90z3V{;CcdO`LikBc=7jDt6qNJ4$(SUpfCd?S=Pv^YXxArSA3L4ht(7^lu3OWb$kYj`&q@Abso6Yj*z z=CmbS0vCd5eF_Uu2w3m4Xwr!OjMWs3R}<@3CS!Z#h{8$pBSd0Dx5SbMn_ic!1C7IQ z;jT^#y{-#e3FD$E1Eea5;Ev079?Gm#jR4f5`i)y`et#+O4JdAR&_A>`WE^Lt~=!8){fR1;z|MyTel zJ744O`qdW97$ynN{HUye_!%c2kr8|k_pTDzggJk?Vj&Fpqz(+O;EO$6&*{BAkjuN_y|<VdDmCyZ&OnRbO>!z}?=~CnE?_#lru}%cznny59BN@;EtC+Z7(H|=e%p4olaLVlOi(ojNNsr5# z-B5qDV%-=1tPmpPu8@JTuIlqsLo>1fk~)$6Ga>%vj%2Tl41u12E5Yuogo7mEt#Nwl z8FqVu#TdB86t?5+0pTS6=FA?kP`a!alwiIF*@1XVX8_`f-Npk*Yg6FC!$i?8?mGv0 zVEV%&ARI8#(?c}92f8DjoJ5W7jGTmB+MK6Yh4BpizRMk)hQHu-WWm+Otl9i{o*L8O zx;aQBc>OmZ;Q*w^Q?6_y*C?|)?NgPR&raF=? zgafi;;2gmem-hDd?a9KX;99l9u8o027yyistBHK2rGq!No_Y9_)vo)((w2%UaC)I( z9z$*f+Hg+rYEV$X&9UANWQsAZ+CtC&3!^v~dk*WNbWKSVyD3|4aK2_qLikJBZ{;1) zd^R#SeL(~&Zkpvw2r<%Tf2RETXs?5-sb$koTb&7SDe=~MC{;xUBqrEUJ@Cz~T5ih~ z!h|VkZW+{sXS5RRVeAZ3C&`ETW~@eF`7zouiZ4WWW97^qw@`;|!n3AHT!`5Ot;xXm z_at9S8L=}`dK1N3r0zcv*Y_SB@-2aXxnMZ+?7BG7=TE7BWIXpQ9)CJi*VIDi5u zGkL5UoL1N#7^zqyJ6qGTdnk0r88*y)_a|;GgBxy?UsQEme_xdMIG|-Z@N%T zHr0m*l#ufUz>B&;EgfNCYEee+_7^7aBSVd02cn*8apbKD8>Gx?n&tlC$QS8Zvox5> z7dw<8vivOv{1_|_vtg5G0(PlHw~?vvQGqsg$jTFBDGYVDvWzmF=z!4WcLqha zZnLZ78RQ6d7E#k`!<;_i=kAE37#X7Q?yNh&@dO!hofYa&+yU~kz){MPtQp86FB$XK}8J+f6qBT3_6cHO4iRi$XZm6=s^G^9|3Suk_ zfJ$5dssV7dcqg#aewBR%V^lsv0Y%?%9hh=a&|xAd{H463nyheX>f&;#HC+E!E+f77 z11ghv=+<{OL)d>z-|Xesn6gg8XB2mLcVu*Q$qZp{rk(;hzm0v=7;tL@p=JooCjLiL z=Xl<&I*$tmzyO>*BkdY0jWuhcSMWLqXpm^i&>({T}iG*O}Nxv=w z{tm~MLE1jfAl|bAkPg1q!|szwxn&C+9Ayf_;2HfVo*cFy_WZt!FgYBaHz-vKwhW&f zvnt9FMR_TK-cM~be#Upua9&Q=lGqHo8RIvUZpf4ouo_kXSLS=}1*hXUiEtDAP zP*}=9PT>f4g(Nl@CBc(G8qxPJT;WB3{`^_yak0z5dI_fS&Oq)>qlTJ_>KGj4TQ)OO zU}vBtFW>Q;nyIX?R>2awm{3V#GZc@XUQacCxV>;zd&vT{+u=zyuMt1<>Nz<^Ho-`+kQx*z z77ueJEA$QwIGu$)UmwunM9E7@KSS<+*XzH31abaL^8BBt#@62h|JR>@-xBlx@sDJQ zJ^uH-9BaSIWxJjB(GeLJWrip-f+YIZbg91Gw&8zYN15gyMQbsk=d(A?TMmEaAU2`% zD%e#bI+uO*uZQ0msV#2WP&0w^=e6#WobRbmeIrZ@c|G=_qu*d!s)+)mUt@eEpa&(- zMj|Y17B;u^)X1Xu-&U*2ND4ICFeBAuv@8xinJ=W78Vx#P-5?#x(;MYq_(#}5AT*gqcIhDfqEAs zK`X}=Cr$%(fMKWSVt5cXnO6i|4wz6FSZ|>cnoo}z$f4$*0#}o>18VdUw_Oyz_n$0O z&AgA{_FfXKcmr5$9}dPX9Wir`xkOj2@@xpB1g+nMF8dw?w8b`1J<$o@(H|5vvW_OP zb+2Txi5JI;ViRwXZGonaxr9m$?&s&hjRMr4B_%r>X=rHdEUUFL_*?K@R~8hyXQ+Uu zjnusbF3RT{yC6glfdBvc;O@Qj%^-_q8wrrmz2R0QH8eCx%8iwKx;af%dU{;G86Tdp z=n%fec_LuHClM_+8{;c|s2|3aS1i(;U)A$a+}ZFQLeIGDlHnWJyZxT-&mJY5R^i~A zs4!Kp2qO;1Nk32(tNu&$G!pyXS@;`;FyUJm9C6v$sW%1i9UhBDAl`e)uY(Xau-PS2zh$YK>tXbNI=O=%+Ai<4xUOF_{+Sv^9{Wk%U=@a8oo`0$Qa9MSY?st z-%?+|`0sT7xILdvfZk_h(Vk#(d6k}aBPjzUefPU@BsDL#gS?CKAd+%ibk@3WH7&ya z6jLU8(jQU|-3QWr8JX;delJ|@p3PxoI_<$W-J9cvW2(;zkrU^2L2Zd3qs#%Oo9@ON zBf8f+1BMrZa^lGO+U<}03huAME)L@`JdZSm^`t*rC5GD`IL-zdCYHPFYqwY^rO=Y$ zW1^s(Oj}k@PgpvO3hB?qQz8SOVeRACr=p#FW)=T49bM>uri0MkrkBS22!la-e|(vc zC3S|}*mLdyhx#S{J;NkhGQ-vyDjJHYto@Bw$HBf}TwI>boNP93mBs8}g|1eC*zJK1 zPh?9lua{(m4LFN(JY9ZMX#gG?L^3;I;Fj5hBQX$~iP<BwM!a-x!2H6T+XTAdt84qrEr##Kl>wG^Cxok$=i00Q?ry`bJx2a z73%2}+I`oLkCa|3|I+?%Xf}imNE2|CmX$^R%ufaiu%AUlq{3bhO-;@C+Z|Ai>*YN# z;A6o_3_e+>+$ijQ+Xez9ASN-fXE>G5*xku;v4Kmg*4D-~6#)UE&gFm@R3a6*h5$3a zA$whXwG=CK&--2e4-20H>OkzV^`_Iy3Oe49wd6|=T(TFziF86b8-riemwpIbAcdMyV-z9}=& zenH~?H&Z=Q3K2a>_j(5k-{n$*T3ML?hN-LlSjG4Oiu)QLKA#_46Ev;A#O!`aS$X`* zN8SsEPs)tF<;g|1ldEvNVRQN&8-%sIY%^OQ&Rj1mmLv?xBX=buE7nS|whwZ=4wslL zO}ElYS|&myg?z%KgKaQjW%y>hy*{8eOyEw@A7}%%hZ<>=i8|l#Nv`JHID^uYp!z5N z;rpfwE@7S)8{s7%+OH2=14|3$mRf#4^YZfEf(tQ$TA<*tSV`wQJZaTkcjYtmLJl6xd?67 z6>)@sgYUW}%?TDr9+%3i>zg8D%vCFWTgdsQHlhR-%zqHD3VO9?lQd>L%u7vCiSM+C z;fOCpIl*{D5;u(DLN54w+M^jD7#`bl@uTq!?FcGl5fv+Jh)w(~`D*RaZx-jbj6S!L z9FoL^ywCqg5%;iAW22qQ>j0~gqu}uGvmv)vN6}y^T78zs7`;%f*uS>6_6`x9l7$8H zsP#!$UO~Ymjo+DJUMP)y({1$m&?-;TU#ol1z)rA|#}2+(w5$V7;_{s;XJ45UrpgCuvqM}39zYp0a9~U>7R5=;e z1{a`34vg4n>mdr#&|ie z%UQFTMpsr;G_*ejs*LDl{P=jZ3ikYYe{vK_n(hu8!NQGC#ogCnwb4s1uK2sVyGl$l zeuLhamoWny0MzARZUs!>n}E=M4df3Wfnb;!wL-M#Kx4gRj8k|Bd}J{O;kevb;2>ny zYfTO-ZY3)pl)MPF3wettt@SB}zuIn=a?O#4mYW9H*3oTLRwQ_As4BCLrFfSfvPGd_ z=qJn!0~me9&xA>fNifEQRz(uqI6WSYm#)Z3yX#Ol--U@aKLOO>hy@^mS7@^02wbAqU`G5Ij2mq9#{&kMHXkRIJ3t(4+!2hy>wWuK z)wo<6+Z&8;?!no5qO;{7!?_014JM|qtEi}{%Z<8Fxk2$L<`33?-Z>DPj`L8d7PRC; zR2_4{3*vVf@2{Bc|4>DV6Z;P%71eA>roC&eKZSSCxD&O5t=XM~gp| zMTotHUD8q`NM<+ZHcAMN<6kSZOx9WoHq`Wmh;OEIavR~uL|^jR?u3KD-$T)25niMS znU?z8@&zy9?m55nTLzrbV(;|%+eRLi+!NNYdI{`67gG_Dr~5PR9$KYzYrOk17toPJ zfD^UA&Yey(t{xr@G`v(_Wy`=K?$9oy#2&AMIWF*ULSjO~w2J5TO30rgO%A|(^YowI z)=~Y(KN?3cLv~%|Mp$eFABVvFtsep)MU$;sWhh168iN2O%h>i*J13e-W3`C5>;X{~aT0oUso4iS|33I;ErjIS zi~+yRU~JqUL52B1@lF4max#hJSuau|x|936X(3 zMi-uvAWR#n0g^Qnw8Rpg ziBaOfQdcMR{R-&YPOue<eJzFkv87sA^koK$hi?7@BC&hAik+jU1 zbgcu?xl9%AC34lX8m)9N#0`>)&%q8y#@T=7JNP_Id_%R zE9ze#Eb{(_Y~1o=bShh9F?`X>`)t=nOQ#QSXXnJs+N_sh#YtS~X+zL)ucem&J76pf z&({4LxZc>>n%}qk^V4y$c}gc^xVKw)FBKtu{7swe5+I(+ZwHpSh2>vuNl7vp$(>O zV8G?H+r&|y#Yr7Z(|ue$={H1K966{i6&*&4y{89i&;80t^_)RvGOOPm-0Fj7v zDL=-d)xSg6a;TQ-CW+<9e>u9_WxFGf4SAmrs6c#-PTt~iuT*}m9s z%H_@93b?cX>?`6lh{%S8>Xp{M_85kARG1D>ewF<(z4tXKDHKd5>eSh1s!i9solprs zUK`g&XuiUICc2B9_fEg*g7}t!B&ElP`_;3dm}UN32+?#&*X6h5j2+1uNxt&m11d9B2duZl)~l6aT>h?O|zTV*})s^$9bK}4M8 zqIMtcq7_LA{T2=n@iD3{sb__THKR^h7Vb~wq7}Dy&c=T6fkYWN=XzK>oy%^uYSv@QbXlLaq8YAy(@ z(pl*u)bIRCEi(gVVU74oCM{2P3riEy?$oQ{{_X5A*=->IF@{`pZGRgCf>aj-(Z*o% za7I+r_-n=!*u$eqB7pL1=*f8<(u_(pW(Xy6JS~~+QopqFX>~BfQVP~=wb%d|u19E+ zhxJN(6;1F>9unF)*K#w_>NHH2hj&;;bVSI-z05$Up*aydI`D&o-VnFy_*>A-db+wr zrTzIBEKouytWF^NxTTClZhjCI)nvEDMC*$$EFM2^aeTN(3U=D@Q2_tPTsLVeSrzhtf>%aH_=H*}7aI)=9bNYX|BR%}&RLch&Rwa0iw<#Uv+d=4*H;nsX92o%S=hFx zwW*3g_LD*^1JiC*qrZoqr8(-jjfH!wH`@oex4v9t;f*@zdGu4ZsTqi-drGjIYM|j0 zQCqHX=wrP6oj5OWlKALTGF92VyuaIPXL75$9OK3*hHVcbJZUl^WE7N@;f1gz{N#xA z>Q#R<*g8sR7_rPLFzg3LOs7Gt6oxH&)o8Rd*}+D8?FoluNl3>hC+^zW%HA-*bMW`> z9VX~h!ph1{t3vej^vd4xsnUXo0eZ$mxj$EpM#5v;X&f!Id0KaMv>eT|KU1Y+^d`C%Ey5MLo2|Sut-+)+4sTy$Qm~Gse->h{l*U2L`V&~a ze6$)8MU&~7=)#nv$$RhB3?}-uvbqk6yiyz8A~PD@hG=!wBn%_A!WH((fFz;xEtYG) zW=32?hgk?RiA9?@wf3 z#e{JFj-$TGr{Lug%VHIM_eWD_Xdxkwcpa=M|FXm>BHbv5}8G>o0d=WrrMC z+)Rcrz-TE;8-PNg zvtY1p17mQuIW$x6L`SQT1O-LSKUH$yAtNJ0DUm@fL>H*`vfrO!-(RT5tF>LMaDQ5C za_5L5<1nLF1O@Y+%^=#(%FFYj83x02pl~CDPAR<;6k9W<R4--Zg2J)e6$*2;gleq)E4ERWhxQ9QPTD!fb!nv#^1uT$dz@W zw*|hVvgGp+-|oZVXBIXcA-wy?EsD)%mF4LYG|=VD!Wu+08!ygn81_@YWn!qhB{6Xd zZz|i(9lpQrLUzUaIxz}v;u_|8dkCpq#25{(M~A^UT&Z9xjQi#VB@7IVM#Ja)A*;+j zbEsaiW!_7^S6>+^<2`5hwZR(K>%a4F285s~^v9E=Jn4 z@7^LAv?G$3TnvvW_Q6e21&QeV*M@%?*owaO24WG8r0E%y4lUH{0Bl=X6f@kzY#C1I z1&Wk`>}Mvjx`^Tmh&Ya8_rnS6cM8|Lu@Uml&SXljkkOGwxI5Y_hj@YBU$oaAL>~&i zikg|vxlZAYX}BNmdMS}5Iw{*BP+q7JVgg_#C^VYfBLG=3zt>&S#ME>H2t~oddMf+% z%cS64Zs8uoRmnZ<28;%}!RsxZwVab@z`D*N{x1a;IlNHs6bY!Y2ao8bRsKq(EW0C; z93oo#*j!J*n?yjWNh+({2Y2bkb){L%u{GqC`h;MxEhAEH-X4ksR6&t(6!J7h17JoI zGf*uSD!rGU} z{^bOVc`zn`EWCY;(-LnYt z*#a9}cAr&0$com$%uJ20JtriP^U;0=lmC}x0+%F|9SeigZMW|E4ui)K|Nm4@Cmh>X zvz+|1nKtx)hh9$pyZz7CG0+XH_Tgwv59^HMOaAu+=ezV9l$3uD!JYYy!YjnHHp)=h z{bWX!|9Ru6E$;@}=Z|<^9dWtEH3ku4>zVoW|8w~Nq>wr#LTSc=$^9|PKT1oD{sWh? zSyKO{4#Ah7U>oHRW_^hYr>O`ghyCxHRsT;4{`oK^Zt~B}5TGqJO8(VJQJl_yA2|W< z{rw+0dD#h<2WlS@5*ikwrL!D5%w;9M^}b*u{`}W}^v7BZLlg1&?SC(+`|^*3e?D6% zC|_}KJ*Q5h8xo=m!Oee>zkucuxd&4|_pNuGTs`K&wjHvEVt@|C27FO8LSXvqpz~~AmF?QdLhOv-oiLxlG0(4%C88* zOW(fwHUb)kkA1cXNHifE<)a&Afy=gKsdOj_8JDm4(HuFV91CVp)V*O>9T+r-5bESp za=N;>9f`s)QV>vFFQph*??$HOxq)rEg!zbwiGz-frbWv`5RUKPAK6i?PCCjKtbqB; zKI*`;dkr4RmEnD}1slK#f)qq{6mU_o;s9l{v67AnQrK|0wz;lv0X+3?=Yf&n0#!Ve7#-R*`#F zvDCgL1M7P-pVOvwM)Fqb)`VTSodWzXXp9N>8df}l_T0OTs)EBtHUyYc@rcA%=Lj#6 z(U)(n_b?Q&{x$?T1QVs`V|4Wu99~bT45;pZB1e_2#ToTaeh_;E)2F9HoO>iL1d^2K#p+y2Kr-eqHEBEJH?PYW$%}blpr7p zKtKsh#n{l$!R)VJzgTxqfuXS4Mi`%T5A%04S+=JBNqag9hyg!uhw-egJhk8o~Fwt#?~TYz89(A8HSGM#gZx4$K%{a4NrZ)c1;Tltp< zl7}zd*-?BL(2U~RvSPm2)`U<0oO%T->Sp5r>*9ax%Pw|3uQ}TlPAI>FI1)08!EW#x zLhpkj+eEf!>- z?<%jG^^U+6PEYl?8cVWmUj2Y5&uXV#8a$(Ee?d0DL z5C}B~UpU4y=zW$HNzjQMd!mEruB z6&f~lr?UK+9UC#BCFx=Hl>Kazh}>f1oE}Bo)TL~6^bRR(UNA!}`A=r>*jh384z7$jds-pH8 z+`~kKMNU?wpq{-75U+Ot<71xT=vvANxDyy0@Z8}u`Iivvt#)338MWlT zday1Jth0SqLV#j$P-XZOaejV2);J2Tsz}?#hFLW>jwP=%MH91mv&-kkVPK0KnCCjq zE)u&Y!+C-iFM>dtG2Y4m3?fibQSEO|O`n^Afn}mKHehAL+Wo`B7Py|{_KIDoDUAeu zkJyPn%X@7Eg@bMO?(76Wld33NZxxy`vAw*?g2=kbzThXafvH%~JIZ)M7AIOtKbm zYpA1#ZoLoxKuPd4*o?aDRr{sCjzRDbs|hUs9Y$aVExuNefFrtvEUT=f*OC{;=npNntn2?jbhSZ zTh->Tdmw*=0p8jEn8jtwDsUzkce{dW_x@t2rrGP?(n)e{_wg;YwZ}*owTvE)c`azj zzGuiF>;GCL{ldamH1SqoM)@>tg@6;0cv);Cy6008MxXUWPbTHvE7UWVIU6E`TnUfRv$oX}ye4JI5FIKSB-nT={( zIs>QE)$$N3&sK#v#-pM}Cg{TXV~@ThhWVgNsmiXn693TXVA!J+=Xi;Kp1c!NIBAcC zE+)CGT|a*9`Qzlc;GN3AS7dp@u9f3LLtc1*LB9j{6R~ok+}?ZpA6N}8mMSZ;&im(5 zQA$ zeG}PDW|L0KlYMq>{Pc_B2L+3d^_5X@o%CwZlD>-Pksjt15xIki(AW*LmxmF#UGr)E zB6t0-JZ0_h2d@pM+lSky{iqRm*p-Jyp3xCjh99bIMwV|{qz-T}S{Z7jG8*u@V6f}? zvD<}&>1ru+lZ8+KCR(zReezy}AMy`muXFVbyl?%!?78^+y|YvjMEpz5v$vfx#Z`bT>hhaw|L(fD zV$Xa`W;yPT>gH_uXe@J*VzwCVV2R|>Mu6&OFwF7dBduev`L4%^1Uhgh?2beb`{x7u zywer|c0^0G(1162+TQ2S22&S>GrU_q4KBx6A@fQPWl=6o!W10@P3_I(sj9`737Ii{ zMP$Fyy$mfFiQZOPsc7n=p&qyAWk$8qeaZf1`jZzJt5KzotgDuZ-xc;gMEx!fHeP6R zd+Z}j@Hsj8R-Z`H_}YIIKMY^v*=bXLoV3PwPB#Y?4qz#~xN%QZ@p(?NT=s8J^%hQ; zM&Pqw-os|l25qn`R0O4tWj6ENOd4eX@c#Y#A17yLo)yDb6TMUtmF%{n*2TM!B@Rs8 z`J5@m0C=%H!Z-D>4C=1*6I$;vWUR5@#xPEf*13z8d|ZCtj+On}U(+@1mCQ~_0mF=X zh^I`tT?}1Ns6UJXOEm*wTW%NHU@Ge0*6f->Ku|9$;AVr_FLo-oblC(XGAeV{bpe6HU6Q&=W5G^hn8b(H| zh9x8uM8p#s@goagILB0&pej|7HjIcJXWd&d_UTf_Hmco0O8lt*7#)*;TYrH`P(b$W z@2Uud8S&}eQnA%#Ld{e_E(+z_->D5&sgubRJd})&-xvA4)exhK^>wF13KAC9;jKLn z+;2VR4orFnm}`YNSO_wr4h}f4KMcmC1Qes0joaC=6dhbGwt?WdB<9yF5LaC!pGTA} zPRmCgOo!|bfuVYaQ{wT80FbR5237&8yni2KBjM=yM$diY#S%!k;Ns!o5EFj^g(?P{ zgUOsGvXj#7^4|hg3)M2Mrc2l$q`7Xd(`>UqB6?~CtfPYF=F)+Qa5nc-lk?rl0kx}d zH1gOaB;nxUc5}{maAidWSWSFx27{VZ1rL8CpZ%ZA$X(b6O8?P79GrEz7vK-mC%i#g zY9?AdrcYaN^RnM4`_^M#$HnxKSer-$kW6k7-#4FEmzXKEYFICf6YtFK@|&v$9YPE#3<=#fxUtvPPO+dOj6((L`t%w0=%Rosf-}&uGZ)#a(e-!xkAl)ywp91O( z-wpSnbkx5&3j%yP+#ZHU!K2<9)wS80+r7S?8E+Cxc+U7uNpJ*VHdpi; ztXyJ(Jq9U4=@iG?jj5L3YuTwDVP_nV{t7z?kt3p~QC_%`Q*8xf)m%+l!=krASYI>T z@d;~cJ^{#kS0c)uOGbrjV>RYANuSwBIMT@J)=nALyPu*>QL*TCsaMGPgC^4d0KhkV zFFUpe?c(1!0iEmB?YNpqFzsIxfrd{1) z9nDf0FY8%c5g+Q`2xsf_n`x8ZoHiDHW<+6ehY#T^8W5t##}mH(7U@BDTKUF)=j!0I z$AE|Zhc89)o<3a(H_`Kv%H?cpjmavqiCW+En0OnIq`R92#L^li64U)vmP@-zu8i{P z(wi9*D1ROmhc-FCvXtwFm>H&zwvFGb?yk==YTO@MB0{%5ElHHHOdYX!`@k&Sn3KVY zMzJjKJhmP@kc9Q^V2Z@%6U|1c@eqHCKspvTu9d+4PK5*f2P2iiw%Ho2$6z&yn50zv zy2LvLg=cN{^<4Egaz_UThfuJCP%s9G+wMeu5|5o;d`U3>=WQsVo*PVQ)2Upx=>Vcc ziB7#g*y&+DVHvEO?d;S}DfM%t~n|b$V z!zTP)yiu-71DJp>ynK^%bURM5%-XQggf^cJLs0%lWKfP zm@%6W`3dgvtq9b249j5cCi}WouaHqtuRs{nm+lAvNM)~a?(n$R&OYSY%x8Js%|5;x z>w*P7cPmKeH|A;v*H%tU(h$dyju=n!9YXaorFEtx^x+XK)QYH=rQ6Q^QS)s% z_g2WEK0TM_oWkBHgu*5@koOwrS{j20F3$M7MuzP16hZI5vmg2E+EX9w3y_X(2%TD} zaGD9eMLul#!eVVRH28_Gnm2bfE^~4z|4WqD!)sgbPdFb-Y}ts=9F7NGyl9zgDV}ey zt@bWDnaFXbCj)lgxby3H-7^T)i0}DN!G+8xJcGn54|{^C1y7O}NQUohw8BeNKF##& z&Ydx?Mn9U)_fWqg9iKijs7`UV#E%bWL=bxSf#I@`5`ofE;mWHl_3=hkC%h?J(XA#XL zN=_##goI}=jI4^IasQl1-DkN6`-_+p-qTxws`2fq;*@c;g19(*ofaL(fajtq7np=G zx!l=2rVT_6V=$TmRZOKeX|=UHhfQbik`!pwsZK5ZpZp88rVQBVK~*^T!(Xi+Z8O#! z=PaMnfRcmkKYCn5Eo2h2KGoJcgn$2@QE?l4rHRnP**Q!hbMRRAs93gI7aZ^IuWKyRgxrr?S2T3;)8m=~xA4(HH6IJI@bW$P{VAkum@Q0}qy`tc zuzOTo)i(@bfmO$mc9Yl1)1oxvP)lsCZ3?fD#dl8vPc6*XALeeIj;NO7%(M?d_geC$ zUq7LTzg3Yz^DPq8?$JGskr;-`EU=BA$Th$)+#8_!F@UsA{^tLq>Mx_>h_qJNLeK4Cv86s=BL7_Fj9gxt@hl zTbq#ZUZ%5#I6OO`T-QVNR<_klRzo<4B12wA=#?p5C|8UKB0Ug;vpgZzYtwDE!I+T6 zMuS7#p6gZL=0zZT?fJcP3f6H0cinmJ3)}XC=83}N>+3GZ^4{O$iL7HGs&>+^CP@BY z=B^4pPkN@cxoyQCOY3WYj9WJQb3}}0VzmpJ4ePYkL1jRFnn-r&lc`fWBqIwwJU1B| zSJWIbLxvFAxTrrg)hQa&)&wW2-w~ z3BekHx=IjKO$IVH^C1&AeJ4t)uPxKZDcp1#t1X1OmD!y@m4J41pa|g1yk8-x7k~ll z;%qJw#{U!ssEbK-vR$2jj21+F@_ktUb)}n-1+*z!Kj5fQp=k7U`+D*=H|n|z#jkI5 zKyjo$wY%Lu=_q>-8OLZ^>dwoQ?l9cj94p?`xBfL; z^rk4}~ z;Bxxzm(9kzWwv@DzxYR-gX%I0%2%WTm>;#;7A; zZ;`SyPWk?~&2wxf_InYDf5$|2LLc1^Zti9mv)Xf%2R?W)yC@*?zfa}v=_zV`%Qhhg z6&2LtBF%$?$LWgf>FExg;@Hqo_hf;1jz0DC^VP&cjS&>BV#7Gpa%Vt*z^mtb+TTn& zpb5x*#K?$SAC9w=@6_jThgNDFDR}bPvjum~$}gy+e#s9Xquy|L0de@tOTp9ZXHoOl zh{#%qFK5Gga{7lr>khS_?FAd#_tjtcxc=3>FRy;jUc`!vCyrU*aJ&i`-mAVDh2F^3 z^lMc9Wz}hYZoj{v_0OxM?1ZADcEd53V(Qfwam*psA0rWJ-fF`Zbh|DG57LBS!~vCA z`#cD#>Ysdac8xT$fx$-daemJ1BZiv&NrAHs+Sy!!YQZTxChC}>-XUq}fU3_Lq&e31 zN3yc^r$mqKPpv1soW42b<*aAPtF>awuH#eB%O2afesHSCd98^!crjp@tNQ1_1PC0* zDizz>F-fnjq-cJC5i4-}IVPE$o(vzeh%8GRBE+~_RbeBNSj13q1HGV_RXBl86$m5R z#Plnj?;FWpH%-HLki7MMJ#>tY`i(41oB-y4cQd0xoy^ir?S5&K;sgJ`@$89ttd6Pj)`@ ziMhHH)HxP@qQ=?_Fe^4QEy~aLbrj@mw~`NJh8OGmpA=DU2!Pc+Aqu4-F)>I$S8p#A zm;sehP^h|r0JXRC%Mq5XUNqslSwZJ*nI|diRnzYZgca^5$8?3Uad9ve38nO_i{yZv z(aE9@hPuqe4%n^1pg;*4N+d`YE&r7HckShjyuC~(`HCf2c?2$0sDy0X-Z56&|JwLw z!H9uvdJ>nHp6)@-&3)%g(|Qm2F2})~I2&37K#s6G^ai>nMs+_Ann4DR0osr}3D&+B zjJn@&0pf9}WOc*5JK>p1yLx|%AKGb)!6%yYhJEWUN``al&98rI5mh$ytwTdQX_0^S zPos`J+MJYz4YKkGX*#KU{w+`m0?d(wcrR>Ig|cvA=XdY}znLhyc+*%l0$sK;;?D(e zJP+HxO)&Ana}MxUZ9ZZX;>_s|YQ}dSZ15`ApjX zq;{MJqRW32vGdKjx?PD-5Qk`dpkkx#3VOAcWg8VrsVW=1Q!M;J;9-W4A76`y$I5aY zK8Gg#UehPqUMMsHFse*9@DHMv^)~Nl)sC|<24|`}s0!}+u4rT+U~ch!#*e5fH+8V~ zL@Z=zP?!xLbp=5Mta3>&E0n%PT_heh-B6e!3vgUlJ~)iNcpS(V(K@-VW4 zv3hZ%3$w_8vl{?exK1+>`DC}FetJTp2~EED=)sCzTu_V8(ZqTO=}OOU#5EUi=ANu} z4&OO{nv%PfZvMf4<8i-*tQD}NuB}w2N&8E8n+*#Z?(3eX z&41ESgxZ+Ezb1jLbElNnV1zdVnlAWwBNuJ^{~2X}HG8MH^A)NwT!1BzMPRa|!OdbK zw-2P*fwoJBGN+?A-5W9Y+%0VUS#_m%13zQNuf8FHC|z}2q|J@YuXl#bN7d6ovn^9Y zbHsAOY1+k*jyj9Z64c_#K&uQypn>(D{&MzA$DYq`$01QV1&nUJt@V5FGv=I>>knD@ z5w|}*`un;YLkRKz1PpS#P&#!VYN_v)ky@*lCuG^0R|OdOBM^Ym{cApYGa9O3RO;tQ zNYw{ry3JD()($sWr2)gat(X)RjR!Xi@?7{R_4fvN+6g=#!Dq`k<8fFmG4|TUVX?lm z&`?U_*jj&&ZgAnU~+?df^ z!PXvUv!k=6dPei{Y|x8<2GVDY|Nf4GN1&Ij)(4TbV9p{avp|jEZnn%x{!5?Of)fw2 z2TIk;&D&|GxRTa@*ENhNI^pnb$fiKWz>Ri7q}=!<$WSI63x0(Pl>Yc$IOvid?+jAu zvFhcvaEjz+x9iXLb^)2q74`bFv-qhb!OvF0<76kh*MjR^LRz zWcEN2p5-=l%DG&SA#?2&v7TWfx@i)hR$rXTuO%tge%eH6rp;avKMT}V$E>K!xJ-1k zl#*Yz8dZ((huGi++=QaS=0@OLZgXwED3ihPe&(s$U1!}k70=65(0si|iK06Rkr3Z) z@AprlDe@I_I0(BfI_+9C=xCh1==%-v!EhXj_)k5as}(&@y%kB${W{^YP_k}N_e8tO zj{(adTRIVnvIwte>)utpm>P1M0n+BS?GuU=+5H7(NB})OBRrdU!0N%<{Y0daGML1E z`DtEue7I`9`t;D~c$?@0PUim^+trBxWDs)xk63%Q_$#8Prw0I-nVB<$1BAc^qy}_W z8UOVD6}Ndkctpfn9Rp=0vzanwd`{~xy>=kIrs=HX$?^W&2pt0(vCqeCYP`g>cbp5n zU)(NTIcJ(s^*V?RUY0a;c{r2JM$(eNrdak(OJGlMX^@S?$np-JJAYcU?PB199C=@* zRpG(lbs;FOgb*gA5kdw~@*S|n$8a;-Eh-)s&@s<@o7)zdHB*>9P4>MS;9Y8XJ?6LE zoI;?YELohpK_(8%4T=xYvG0AN2is zb5i)-U@;CrzEIDZdvwvS_WV4b6-C(Qp<%c*)-$YvG7uIgg$#*|FAMN{B4> zIJF2}z*VL9&%XhBJX}-l{Z9_7>yS?hum6NsyvKSH~4IrJfbUoc3@ zeOIHqpOQzWtS8|=88qfZbT)<3e1EnRjEle{eKjKUXuVUGaSjX7uJF}v?DaFS+c~`x z(r%T)Nb85D7)z{r2!_YA(acm5-}C*lXu#=C1zqsHFkI;Kf7QhY%EBptt4J+62xL4U zlL--nm0wg24h}NOp!sE8^+`J(c8MYeTHjuu zlm(Jn^s5Kv4FW(?9tK7bXpl}@rUM}mU{!&Py!=0G3P>$yC#V8D#DO?!SFp}hyL~6x z{#`MhC`+aElbQhkjf3;Fh9JtX4v~1XqgF?GhkFD!@mPTVpQW;?b^aN)fdh|4|97Ee z%x{=U`L1~?G9)sAPe}#pc@u#I3zyPzz6~_dnImra{%y6glQ9@ccoihD(bMvu0c5zE z&i(cG#nHljqh?UFHzjXK9dCbJ$F#Jj{EUk~#Z|rbPEIwF`F`l09MsF_*d?47s{( zWkM*Pp!aBA5Pz}#Sn(&!TbuO!GP<0Wb&VAJXp>5+SaliUGx!^EWZQzYVQf?R)(K*c zJZmu#F@*xfT$}++Sr?!NbC9`ak51sQFe!8)0*V?+YxH{F490h74eujX{vhQRU?_}~ zW($YRT$S357zsXh3$p$;T3mqg$(NJ+`M!~em(;m<>+U(T@(oJocs+tzcJlFF^k@eu zVS}|yceVU75dapW=AEo2xTy1ZMIU27y!)W-2_50&c?J==F9@Gpk@mS4zVrt1+Ghl> z8T3kq6^o1hVX>qnuxM*rK|i1lQ~xQaiItd?i3Gr-+)5^PD*j9Qy@KwOVC}}AsMy*} z_^(r0iZ4?OC>Wt7AE8D5SuRA&a4Ek+8PW$XeQPaGQTsegkv{T%ZEekihK`QEBj(R2 z4^kiySZx7e9xEvR!cQlboSk>XhJ~7q+O?-s$ipkHV<3-HE(0y{F%pPW!rNv?Iwf_- z*n-ui(3I~J-CU6Hc($^mU)-1@8vBRXVTLMU6yl9H$wsG&x7*mt3WgL@XbBO zyWo%-jINWog}N-+?4j6#>agxAlc{68G$BgaYXpwjhioP>URp|j)5Rl2ZW#tiQOl~Y z5)vB!NxtufWTsf2G2rC*(Dhy9cWKK9cNZ`kI}96Q+RU=EyLidfSZOrD zEL{GkToynopoe7iL3VIhb#sMN@!4-YK~euwlH?907QzuOP(yNLtp@B;)m0IW3cjAj zaL}T9cAxpFtL^HlWD?OLJBL6E!}GkC&3Hc2)3xu3j`z4q!&?8Nlo{#<^bi$zaU*fC zt?|lxHoKlf0UGWR7xsq61JG>-96Lk?Q9;>CXJHlU-|wgT@uoNykJA?@&kITRn=GP$^_!1QuhA-y;RrM zUdpD;f^H3G0A<+^ipJ0~2;e@J!R4Hg&_Lun!Y)!E7nO^}Vz>10n;EC;(OX!((cKDX zG`b&}^Y=|?mDFZYNHQS4Cs=(K@a?d1?Ayb7;!f;G$&inY5V2fWLTTG%a~8c%3Y;&Z zy~-SpW@!nJXXn+2-f~Aje1+TDHHF=TvuaBJjaKP@7u<$^jD( zzOBDPh3Vzp?obH_QY-lfBV*|Q%6FVSqnUs{bzvA#2-HDuBoJmB$Rtx+)h~gBfnECa z5gWIp;ZeS3U4PL6rDt~#5o1#SUGCqFVjZ2Sh(1*bXcUw-RNl+hb9G@2GM^LSvkaK7y~tx8s{nSR(1`&n?b#i9Kn(>s7dw02{qT9v1&y!9q$ z^Z{6dI3FJZJ!$4rIvnWmBA*@X+Jll{tT3tc4}wfUe!J4_i$2PL6>#@n2#RI}-7bj& zp6O4@Z0K*+EE?)8e2aB>sZ`S;S-^s4t`l86_h02GRzZIUR=!H)gyMQlPx#TPWYm zgF*-LhO3X2)JnqLie}(*2pNbJw~8u?Zm&QI{3kR0AKL)@O=M;YK+WmS z|DO>B-JVOugj?j_*Zlwe6;%CC%KPtL|9#~q{(o7!|GV{OI29!M|J~|8?^hiEpIY^Q zKQ@#ozU?Q`f8r!?BglVcNNL}e?iAUx#sHD}Dw+QsLqR6i|Fd{Pi&{d0?3<%+q%nOe zbT|K5#{Jv>gUA08F#q?P|9{6<22txB7}wk~$D`OI*T$zg^i!N7aP%E&4=*Y_9#p#~)^}85kvZ(J8Udr_Jm;@(1z* z*GA-_BK9}SGelTWQjjV@w%NG`(&&2IplZsG+Ot63r{FmD10k6|maIzvyvX$9$q39Q zU*s!D0}5zgf3h%lRCg!-nHw(Nqc@5#6KhE8Ip<+=gfqYD3uF7G%e#3hx#-hhrZIDR zC?t2kFUgvkH&6fuJ%la5+A(u@3Y1_>QJcRuGbex+1@e{qNExUNX+T`A@)TkNf|77# z)aU3i<0TIzJO7;CH@EGw^`mx5_y^kW6|jYT$830z8wT*)Fzs>%3l7MELWf><#9bLm;2Yz5h`SI^9k0yu_VTjf$^`T6Qjjajfq=QnjDw4VOc=QW z#1^JVrx>kY>vR30CSj{`@T4xf%P%21jIW8Mc+5wpM*66em2sL$r+8G9KmP0FO z*{kG&msD1>-fgHopMYUl`@dtx35&tJQ+Ma|7BFjtC{O?sl%rfP=TS-Wz=j9%xdCQx zhQp<66#N zq_)fw?ruAhF2(d_WhL?;J%10G3kC{}`qoy(?+rFNZTSPNRkhBi%wXo3fuutp#!;E5 zfJKR1P$w=Wy)7xVw0wdVG48kV&kfMEGvJIpvzs1$;UPMTYWl*kisk1ER&VFcSrA283I+}-a9Kd@_m8F@{nZlR zi>Ui`ziXE&z1<)t{+s@*7wb0}R0s!eh_i~kQFCb+W6c!p(mrF_Q3{dONt8C(XIb;n zD9|CBgQG>9Ae2~x97~F_Sd%3a-4~pW7twRz@plVp?NVvzgIvZ1{8tUQIwDDmAkDAp z(P3nL0-sAs+Mze4s3FP4azMvygh|xCP0hZt@_OXGPlyVKo!O|#p*8B+W^x3;XtFRL}7bHX3#FY8Ubk(^1MM>1tSZs=M3@p_S;f@O3(@PieMg{MfzIf-EoMJ(zz4>byOL26A2Fs zD||8kp=4T3;C*DFu07KWdG2%yNnf zwLdm`!$ss~29Zd5qUtzMnO^2{gp8j0)?o-cu7A_tzgl@;%@KrN8p@4|0XQi@i`WZM z_t&Say z*n^kzfV={l+}mrWlLZU&;`i_=YnuMUHj)q7m$>5ok#inZ$ zO0v&R7!Ovkr6{S`nBIcZxPrNM;>-}Je1&Z2chU@~odH1;4$&T3(%TD$EA_>lm4fTY zOJhzxsyU>;N@S$)uf6FGc^luGGCWz8FZA%#?=rZL@(zbJm;5bp;O;uR{hLHCNGe>I zXd}OjZ#hRb1#e5yp94P5i@I(0_k4u#1PxnK1go=&-3cm)6P|W2FR8K1HmYzKB*0|r zOnEA>26s*e;O#( z{LO|BToH&2ynw3S2%36J6w|NQa{X8Wd*(l#`WAKLUe~+^NiHD)C_wIOS>Nyj9gsC> zfi~Z7#4~@SCC?^_UiB32kR&I_RQ2~CB>916JmC2+N-QHO0%q&i887Aq$=f|Ru@`n7 zCj9k>+~m3qIO4=qG8BQ-EY;Zd(eeT@mL zbmgo^OR`gbF!>2bW@gQ1#G!|ld_oq-vNl_5^U!1Z*yqj4`AC9QsS!q?Dy8Z9Ghp{w zeeEH_?VGIxC?Lcg>r}N3*#>nhMP82*|EBqNDU4TDn4e#htF0#<%Wu(MbB$nlN;fCj z28Z!%X^9BgA@nO~Nm_oltq3$s49uMRViKl^I-%i>+0+m&PH)zA*g0#9)tl9e5-4tt;=-r5v62i(dZFc(YzRsR@{aG8L;!1=w zy+=)j76$Fyy)`vH^uwhrzMK?FBYKHuGNMxcm{mKueVf|`o{B3TtQm5!iEbBUu}@1Z zuJ=4HNF0f2d4czBF3(Rlaf9sN78+!!d$XVdzTfk6`w460F$WY)$>E4#QCbv8Z`i?m z*q~MRkih;TrGK>H`Pzn+#o`~kkUj1Gr1ZUsG6}Q*PO}R9^_TE=56Sw2c14ykqH`fH><7^p*(GX5i(NdqKpI!)P4R;!yW|4bEHHXTlxI?oC-WaQgs>e3LP(- z)hH1foAIN;rltfcj)Hf@@ziHsr%et8j7$%eRws)v2_9baMt*!ITz@XNF!DSwo~i;A zzr)O*jHBouG$z$K??pjZ?L3Fz4CFF+2yK>J_uS8MOmR3O*PrjhYlhJw@A`h*8QAh1 zwtx0Cqsg1#(H-J|Y-03dZP`J-hHr}NSy}GYJAi_vs%FI!Hh5UsY(@@LCg_^3aSsd} z$8ms`XrGhbQhnG!Tq&*W6;y?`L#o}eJG6lu~A0GSu+FKigkxBUkMLMZ`gfY z?wO$f`KZB9%=eUqnLLUt?VX6x@ok$E!Qz!ruAYE_OUAFTwz*w!pM{R--I2xV{_Oi#8{#K-xB4m?%81xq{{&&1#_`1Tn9h0s zaF^uXiSr#3}2e!aKFOc>8(Ox2V;#{)PDEhw-PTqgAw} zSug9W#`~wN30t!d`a&7!uXq(RGnR=Dv3(c!G_=s`5P?6H8W2Ga9{yx2)=~rFkMm~z zRx7%_Jsp0Oc%sGhXJ3Xqp(#stqp|Q4h4o)k%9U0NUG@tdd#wK%(KhV)e~D^CY`jX@ zf-u2&_1T`|(Rwz^WU( zywz`PQSA>l7Xvot4S6_HnC2hcee9*6p|gT4AlimmJH-NHikyR1+cxHhidMYem~+q1 z{ziS-O7)l-Y^e}Gb{JCfVb~z75Cw-M8RsM3+E?}r zSv`6goVRN(e;vWQ$&j{rPU-_;`QE{fTBw^3Q(kZl=k{l@pH3D zaMxijRUxY1(IUzKk`=B?08lvl?fD(*-1y9)>_@;u1wNP`^868kelUw8-dp--lv(cL z{#J)aGGMGl4=2zbqL=V<^?v(a_x0e?Vh$(&;~gXG(MTl`slTw`vZcgi##?w7n*^uIye`m3_V+4mmtY}_)u=u<@<&=v+5=^-q6Y*z*aqNTlDLk5-8`Wmui)?v`9v4L?AWo?W79i;ATO*@J<;v|17j z1PZ}U>buF-Xw7#>wejI)g01!{Uu&>Kwb4jM<>Y&I+WC*?PM+>bT5S3>ckE%0z24NL zg{_6%3`DDLoXq?6nKc#71jKa~PBnq9KEY1ot>Y)zyd-nY@v?b}t0gm2{nl6xVf*|* z)TxZ-Egq;q=J$Q4O$Dou3$vN7yFC7$?yv+`m3s&5VVKi%c0a7nd!x@EjSW@%Be=#7j4_!IkMg(14-}2S=}Ybv~Ok=E9Nz`ja$Ys6#X8<%*cG3w!c%M_!x>>l7do4 z84m5&DK%I&4vuR{48K$r)Xa)+Thc)V=(tElla{Uxt*Q*En2l&>;zr%C_s?0Cwm)Zd z`0fr76A|UNXu`^~V$MXCLpXQodX!4`>U4L|>Me$Vr03D1Nl$gVa`XoLksCrt_$ml- zWr2lm+hIxnmMz|_`i>Whp$eDJ*rs`*-}9f}h5flH7c45c-A8Vw#iw?m`9+b5vPf4T z_XOpb_|c%`I(V*>4139Oa2A4FH`c`=gQ?DsxC}Md>sLaD~ZE zp;w?X`%n^z6|+@fgzOR9IEqkKFRHh6y{Tp7!|uy#oZYdTZB7EL$8e?0a}mHTbZS4u zsRVy=zJ4u$>u1sDBvT#_$tGnGW+Hl|OKlgKC;0U*mS9HofVR{TVg5Yr+e+U~ye3l? zt9=^WysD{O$ei}3(4en|1BXB3{2sfQdFiG^H{(4mcE<7E77>P%@a~xOiYYy?uKH2NtiOhO@Pc#^&zTj?@lo709+ zM1mw~{@vl5ZP%dR8J)wAaTgJZO`tzbJ2glp2-}3PW(K=ESg=1R4~vzEY!ULYJsl)qki#5;9IWOjGo>kYhM^^iO%vOfcUQH` z*POI$TXMjXRda5)sKs{zKMqVmIjVXu&Lvpgywgq9zg~K6jrj$){3+5G)1}4V^iF?> z{Tq1xC{2@zDXMVRmCU;2*bS3)!_jxY7Qef(e}M*FKlL`^1VZO46IE*XUh|_9hkA^>g}&vHS4g{Slk*X4W}8 zLvurmyCvB$tnlHV9Y6kyvFo3vY>N}E?=)@l-R~syKNi~MP_UGKbUXaTety#Hu@p=O zu-;Y%xWow6kCU#zBH)jX-to55Rw;%_VO>AK%3z9CGCaKdI%bZK7^6Zr-`(idNlJo& z`!_-Qlt}IgEibrW(mOzwHf28-L3|QK$)Q6u-p2J$bdprOK>P^GjHD5O6anSpZU|75 zwYD7(M&lDtuD3jP#~v9O8F-%8U}{5ByN6M-6Tj$hzIKxF#OJva8y2fT zuy|;?#@Ne+JW7ZsR|vKg6=@q?PwHP!$3w|eZ$qJ*AZMZIt@fVMRHvaq)ZA7y*Hv;5 z-AHmb%Zgd%ISlm$umU3KEqG1=3LBB4%RgMrRT@e$0876oO5;h?S*EhIZpb~#%EV$O9WK5^TJ`OaBDzLE#bJldzt=h$Q{guKB;_@*5w zN`^Oe^O*sP(=JnHl8hu9v3#Z$*-y364!4XSjLP?x1wtC>Q-A`WSRzuXPQpJ29er<&Pxbz|br$=p_oH43Yz@jSVmazCfR@LtysyuxU7Ach zm;UOx#I?^%;X6ke@|D?L0uZ7Gm$ewm?|*I%WURXJ%EvMxsQo_98U#(|OS4DCs9h_k zj3;X;N8=q)Z`s~3QZW$FJ&EVvJv;XHlyLR-6B2we188mglL~plbX5#hmMv_bz(M8w z_pQAQ=vfCBVj9T8k%@(*A>uuyf3L7uC_kTh3W;Q9UC08nh=D)`kbljZr#@Q2sJiO{ zR71Y&cqEgP_-I~rryHFTu3whII6frK@~0tWQ+~Hm;a@3w|7`*dUflP~;MDz9HiS)x z=B6~=0B)C<6=m~>B9$WHXg}l)$uHk}vSlQGH4`R9P{inz?<74?j5kaiJ{IVmi(8EL z4-DjXkJ}jZnz99F7JT{6_RbZv#7)-}k2wEwdVLeD<1v}N@Jf^kPb1B_aNMKW-%w2! zy&UJ7m~@z*V+TGhFMWkD^q!&obk?+>vG^oSx|w5EMe@N}bM)-Npmk#)4diaL^%gPw z5`Go*(DptHoAf!;L;p$6g*~D@Uwc|e{w_K=x<6QJO<-Vtz6@LvY60!H zyWCGBqbpZWCdpQrvb1r~p28C;dqeGa@Anj%UDodEzM$1S59)HwNNB{yW<^_s2Z+9M zW<70T*>~f}dKjxd;x!0G1qq%zzH!^Sq!JjuNG*vCQpLgbepGDNDQ^f+`M%Y zY&0Xzy5Y62n(43$9bB7OHV{Zl>ewQza{eN^8PU~bgR$nv{QW3O%BY#JbgrKjc;{z~ zv9hTUeSCv#&0X|T#2leGD1twXTCj1C^p58hlF`q2YO95K`FSb0QfA#{EH(@maGKpX8OF5cg295Ta!)@sk#j~vHSPA2A~z4^4$9M<@E2_uJocr!6$SJ>QTK>G9&w1YKP8n-2 zrWK9-4!q9NrXWF|WVi4tLPI)GeD~>%Ve%Nrk=ubZF)TX{|3O?5(+F37hE54r{1+FfJ8-G+GBN}nR`Xgs~1{57kISiKM?^6FYr<^Ypad` zkYc+%e5mq;2;~9%Y77U|p1j-OnlLO-d~H>A6js6#=&L^U%zOVA3y8(l?4%9GIPHurolw+`B z=73$PQr_)K^OyZ}D1T+Z=&a-F5g(tExy7FA-0XGJ`FU7d%s1Mg>xYt+(vw31?j zO^})>kEBbF;t3$yBvoK3D}K0aDBZ5{H*X*NB-*S6q{){J>W9p%hdWIj&?wl{rity$ zLm*IfP?WRz4&e&2yRU&iPgOJBdnR2c`o+K(-X!%VSB_o9>2jX)rr{0+RZ=TrTp<9l zc=aGE@=*5|Hk%X6R+7o7atxr{E?9}hv7`In;mqRHHG9G7GmW~_V zGeO55+%ZLo`>PFvw)TS8FtC5~d@tP^t(swiS3(feZ-zf2o08NE1~Z|9SR`T18OhpTkn!*Ed-#!ZC# zH>$Q&hfyy87_FM8ux}_NxH%F}8xRbCl3C3_%0uU@^7J8>F>0T=%ccJKIdA#fJo6pP z-q_Oy^^Xp5ObS*I#E~S=9<5Nfjv}904T)I4+O%W+?C3F0CxOz{vS3z-&-(O%W_w9- zOP7wVamFuxzn`^4GctwT<_?$q$D|+Wf^#K-qMvjB)l>BcPgg-=ERUjT0ip@N;JQl_ z(uhBq3^k^2!h|=Ur@!i2&oo_JUWae8&GV2{3th!8yC12fZ@v1nEEbA9O2vj$vjg5P zIDF0c2FWpZO~m{bUk|ZY=6{JK)1*ZbD$Ll?fslrXEo2}HLyWZl;k?%;m3?o#fGZs}Zk~x7Ycb;5%iMJauQb1&aD44D< z!9BoEZN<$owrnByMlc@lM^!cA@5-aOPpD=l#eEhXCw-y zf9t8`KF}ORyZ0!$!|U1v8WZ4rUY})*VO*PADMNc3yim9ixu$tiN@`!S(@B#b6n>V7 zad=7Yfr~2YXv9&4!{>cEHS-%1(jf}dowat8?d5ZqlwJCa&oJzGzO2Z488lFHSJW6~ zb0|Ec?;tyF`?`4GBD9-Sx;wjm7u61IAbM)y+{6#M|W{qD;kh}iT9~w zSDJzgrzn9IR^($A0y%n}YAA%nq$zdcp~_%_)3X{O8p*(IKk9y&Ueep9}|g!+XIj-(EOzY3+bIxTnPz($QXwF_^fljW2Qac znc99jJm)UmnqgP;dA(81lKPQ`MS2KJFshx+C>%}7DJ50>O-#(tBb#0@kdgzY!AlMRD{$%VREY9x_i;(0GN^-~2ci*Cbp=7e z*}f^-wy9dQhr$vrPdMa=kfVFbYAKE2=G@GG`NvMKN1V<6D(v8e>X=736!hQ-+I=R9 zpQW`_jb>~WUi0s~Musf9KeGh3T>4Lj;cd#i`$gnUS+}LZs z)g=mT9wIBpgpKihu0^9FE)-1(e#%$M3xi+xq|2dP;YNLHeZ)?RVc@NNGP$0OO20Vx zX(9MZ%7Bo2Q^%OlbVE2K%$E?O&;bk1iNnjGU0SUvkq!$=_u(isUDofWa85+b<~(%M zUU|2@DLwU+%X-oAT~eoc#XoQ5-23WgE0!Z3dNA3b7{j&8br{_O3Be{4PF}kVrCgX< zI(7~=3w|8;>3F1cz{1tV^2}KY|HDRO9sp3b+=%@-cY1FR(DNMV{-~W^kd-I>!E^KB z*8dW9);|KOXv=Zn&EL4*U<4MC)kptVoyV)!8H#=94;!x2jj`q9NB4=UsHT(t5qe4{ zd{`6CakK40)d;O@o|O3CP49I59vlgUn(#DU>cSFoKJgp;1sPuqDSughXF4 z(rG)782{e#R=|IgYLm>1fZB~3rf(hS(*DA7c5Z8LDXg%QWys+VAe;DwjjM~w5Whgp zdUN6s2c!vlec&y;u4f@LbD@dFp|RKWZ?~5V6*DoA$$92VIeD{i8elB6p;X7-_p+fx z_1hoXoZx_P8gEFC{`6yW*tVvtqEY0)M$fVw>Wk6?y^;=jd;2CsI&IDAL<;TT=X4j& zSI>|15Y-Wt~eQ z?Ve4<(84O%DRT9HZ7Ers%*>9{l&8O4gBQT%vem2Yzmr_~^WxO_f_vJA(CWOhY}*os+Q05SCY{fR z>;$2gt>O;Z74AaDX*Gsk=IpPk>lXf41v9@=`a@hYkO7*{g@z%v5B@H$9><#w{q(pV z80u@S;l8t|gMEnDt5K8@R%!k|MN99Cfi6e@F_l7JdnaakoV%;GK8c`0Ub`od$e#G+ zt0i>5LeQW2)5v1RH7IeYDW=oJnN0=nUws(?`Z-iGDpYmTFSl4sMGT!kX;!{UyPiSF z5VDaT_%s$UZ4r0)ITEVd`~ZO7x7T-jbgkU3oN#`bE?)vfBwSMl_&Vlzf9RVg2*F2| zcQ(Xz39@tah=({`euC}Lej!RA{S(3G7Aa}%%^dK$O1t9zB0)G=DwkE)*V#N=T)&fyXCC+NQcA>>B zp}j57F#tLB0W&sn0P6Yi_A$<@GFFa?$B_B^OVqJTEs<4N*+_!>hDrmoac`Y?J?=OR z;p2dB2z6<-^m1>+VRX3jRMXHkx+wBW4ieYCO9fgRX)UBqoY!tL0WiQcckERe@m(`r z6sljwlBN3hk^1pro3&S!<+naMMs&f!4w+9a0)!Ux&5XYnZU<=z9x17OsVeex@*Lx4 zJEt~rF5(>H&C7;w){v?wRGi&BPh+qZhO9EP`(|nP&H|-o`Dhwr%`Lo0;*jOdWUft- zqjHaLe?9hQHvVKR?GW_6%h<8jT0oYxi-to>qOUKbAuHWl`buNoyi}aif1p+Dcxq8w zw{+D)C?Y=h#{hWl-Sqq*fG-028uMQduThlNo~7Hc)cH0AXf1XAkp?y1VWV(k!xK*u zYTquZFFof^4go8KB9ZT~15LUctO5R&dbbTa0PTYg1D>u;h!wWKp?PB;xIp)~e|L>a zwsX7WaA08E+pPHYL)BDa#Q%q?cMhziiM~ZUoYzyH3@vs=e1Tt>GrzwEhVlC{iNr^0(@(Pzb4on>lsjuq>1&^%7!a?6Z#d5sb5 z;sGR#d1sIn+u8I(9_ zmR-4?GK%uG5gv$ULUldo{pTv3o2|X??8QR?FC+MoqdZsNhd_<7#Ga!>qG(ziBlzLS z?{BeL=JFmck5Ir2DTx2k z9!2o;(0R(*hxV*GE~uH+fN3MlV4eF(=OQNC@u~O_>=1E-tp#l3;gtE5Hy!3Ntbhme z;Aiw+#3g-%;l1eJM7AQVzFyqoK%s43V!}nVEXA|o-NbqBWIo?6C|N5u$PECWe7_deLH<-RZ> z{Ii>k*btJRnPwfa3(>#ipyODW?tVLE-mI`EV*o*qaQ$)Vy2s17U)Cn{i?1}ed4AOT zY$(%9X z#`jqrMKNF#D68ytuAF~84ShGyXpa;jgrb`>=Ou7MCI})6)&>Kf*VwWcH<5v``^zXH zPVUk!3iZqg%n|IH-*-$I3%PyNvxlT}OsGH}F@@1PFPZwOzzK~&ZRWf~{8UDb_9@!# zZVg=ZW9wLxPdEe|rYgAmp9;L%c@WLB-(h-NJ|A5qzz6ABo^T5Ao#&sM05QC9Uv_`@ zw$p(qJG&(dXYarP>M>xyc_r3SGg;!P8Wu7DK4uP1b|CtzaPSmzmj?w40HRa=NJ~w9 zG>6bF0JuVAHh>*L!ZkUl9gBn4%5If#pmzcpO_A2muy!f`W({wUQ-=kox9Xz0?F3y{ z^oybPlAD1U#&LtgZ;9Nnn^S{|vRRCXyVa*}&lHt1&%h7a*L0dWbFzhz3q&HK8AK|X zjUEQr>KCy|?-N~8DF&Mm9py&_^YY#=p@%mI1RrLvvgarZTE2B) z6Cr&2L_S&YF#?D^SEyH!ILNs(hWkY9U~peHCGx|C3^wkmWj;ImSit;D$;MdKNk2#V zIPe_1PWB>(;;floV1x)39y?1$>Bpboy7NU9Pg{RKT!uXv(oq{9-Xoogl&KDEcAQ8IMD{^+22s}MCYs&)v0v*;5_fx*!UiruD3DR(H9LG z7Pgfcw+9MMA{W|`seLpiGhkf`h?q~W=BBD@@td1r$ElgudQ+{fJ(1AtKcwFX6I&Sn zH_#A@QmR_lkgl&4jTdGF?Hjm_65f5*`)Ggca2!S$A7j3B-T>A(w1-f0OXx1DCg z4Y3Eu6?y)Iunu@7HryY}Fm|Es6rL&aPgNzQK`xe}J^s>B zt?;ppd%5#)4A5-B5$xg(2^er-k$SHu+c;`YaHA#JN1pp8>wlqE>0`!&?@X9Bq7@Zi zLZ;?=pwC2XtHpUaXlr(e{uo`;glyQ-#J+}AB{P$n{LQ9WDCElLyK!z^q9Ahxt2#g> z2DL4P*#0BB*wCq6l)%6@>eBa-{=3{dw)2;i;;UNjP3dD}UF{JB*r7YbJ&W6KCqlP06jRU55Wb~k4uQs8FoUb8YPsXVscJX9K~yIJ z9Dg9oiL2Fs?N8e0swO44-m@oX#?15@->7`J`sJwva(DIyDNQX>ZpB}k0n(q3j^|e} zT21`1n+r=2z}+cEm~y&SYi1_Bz_V>T0K{PYJorO!Zh2gN@kCrD@XDBJivHpD_UmK& z`Vb75j@1(1BM`W~uVZ(jXg2p90TgWMCHxuDS5?hBPqc|7;aUup=CYgj9AM{bZx&8n z*6xvrf?-10oS@nf_ATc@(m;&tAv}=x&OCCCt9hfg?5!b@5emujPIu!G#*`T zmQg%iETDmsq53ZWzErbzW?a^E>eudOHA#4?y5Pb&r;nENEf)13PSx9rwkUXRJ~>=- z&i_deJVp2l8td7jXH9d?zu}6Kv;rOATr}CCR;y@LlI#kUw;hd1(o7eYAj_f+TtdU+ z;7_$GXD^-;Xkp+~VXUIb>D5KGTM5?s&w<{AIim2wWd)(eu8+VmrrC3i2{V(+cRYxt zQpCtQn2?*oxXFt`<4$q)#?50c>IxgkYuc{KvOQUtbq6FhCkD;Obyx!SYTl_O|%qjUanO=i*_l*3;ZzZl1|ORZ)Q8ZS5u7BobD=;8MEo8Xy z(n=K3aD++L>rY6$ld^X(;2@n&F}(o`$XgI2b-jAM_mC@jTg#n(+X$AghTTi75am9s z`C^l!vUuSCC+4R#>0KM$AJ@uB)}4y+j~zQIJExadvpF>myfcaTZa1p7wQ3vZ4iduH z3i32K1J^-u?$Ygyfpf%+#YWnr*ZRbMd6CAmpdjNomO8b>05IM z|Kxl(&N=;Af%$jTwC15ORQdPJ0FAQ6N|vo$g6`)e%z9HyVn$BlQv3i>ZeaIlPQ68M zVD|OQpNiwHclDW|&pS7%@ZpuuCESu%BLyB9J;B5@|IgQd_=m}Bho|v7u~c?)R;b7? z43gioNWXgwz8X)-N|Q@Z4OAqf5q9!`jT4=V3s^l0{xN~&yRgiu(%jCkU&|qDHMS?3 zAneTg`kh6U2sfGPDRx5jiOdN^Li)Bv`k(ha?IC>L(^azOSqkB7cVSo_H!M9cl{c$ggDRl5ZKQPkJ+KAYN?kGkM}xl~t!s(>pX^#fiS122VR?+6UGJ zk$|`WWX>?lWx#B#`*pU+v}1bz>MgINKEmI)95?StZ9`5FJr^&Rv9HQrq@9&FtYoyo zX|t*u`hHNFsO8u+Uqb*s(w|8LBW-2t^mj0L{}v=DESb$m9ZA0oy)55h*48%p=%m*H z>6lbMm)k>-T+3OPxQhhw;S0>w*4Eoevi%!>Z$who^0w=F2atLQ9B|wx+boG(qHP+@ znJ-#?0Ss^t(km2l+TcLlH;-;>-e&I$fHM{=s&B;v&OieZ&wQh;RH{Qj0YgIY5i*td zLB8C7JQ-kGYZH`zhH`^6?eGGKKX}K#kugC4Dl)=2dU+B)>@3MK$8;63QK4v?PN~j30T0_cYOI#)+Ww^^F^*y)y zy}TZ4ct?$Fy>!Lhq&~pRg$QqEVW;55Kx%5c6V3Nl7%*!zq~IX$UxC-y1GakTK8x~? zfhujHCW&C!!b-e5miQ^T9kS57-?UXZ4NmYN?_hh!#nE~Lx=0{|bd?$jNXIqYVK#>6 z3vGq-)8A0p^YM13aXc^#;K>~1;aAN3_+vy{BYix070D+Dr^?Lc&yTuzi8;o5r;&Kk zSNGIb_r`^QImKfpv>-;!h8mXy2J^iY*VK~kBq|^FLRWGX=eA9ZWbl2-Ot ztjiFuqOJ=Ps4|g`w?usSCtLz7VuAd?IIa_3rB^p-P_rYEf!rf%r2{+K%KLGv2%@XI zJoOm4AIO>azpi3CqsUcJ0?>YwkRQt>75g4Pd{i`9#_9GSRH5g!KAC*R0(vkSn*%&Q z!o(E5yartFm;b0Oz8JTq=Ol44CT!ofxOYXqIEqEuBa5$FeBGf-g>%G&nd8&fjydWFA(mO0IFx(3Slje81=YK1z*0 zJ!5olds*Pmr&!It=bP!|KHL=Ed^uUQXT)3}$$ZYO8B+jeK>~6|7pHn2;?$s_ z-O+$PelwK&7Zioi$*SC53@?fLPL*8$3pJZ+Uetl7L3(&+5y)}o%8?c$s&7c%@d09j zsh8T`I2yS;Q?S&3xYOk+;FeS+4vf*O?{x(>T=%CD*(jnK|Fs*8pfRuIes{`Z;0=N^ zW-)r>ZH{8zw}EYITQ^pq^O~VDs+^CV9$h)5Sz`*1yyt#uqC8i&T1B;ydT09W?1KX2 zsXZC|2@?FTO}UiYa|gWlm>EB?PH;9xIONJmi1f4FS1qUR%f_GeA+||-%MDkhAw!vOd~I?$IIe$VI?eU)-&fi4yveXW#XTM|0p6(jVdPC^}YcMgxnk zg6&qQ;f|eitEz@Hg2v85B@}54<%kNdLSpQUu}v$_D#gkzY%1Ao=mM`K5Zm zPok>dMLou~LO~Xv6$Y?4%pI`@nYMMJ+R`uuG4WRY{r!K~dwWdFPQQNfI$98`WRx>h zn8GKp_icXQvhK*PcO8QEYt~(X|21f9#^mgkEvsU32bSt{CLSjy4eDP77-oM1`8NLcZ;e*X|Gg13fNJhcE262wn5d* zmFI%#AcOc00^^!j34eLmh=)iPA76zYY7pc#{=uK6!ok&sH!T0g8*P}VY3{FSE+PJ# z5bDb~7s#j~6uU&y@l0NCJ8^X|rhXCFz$K`O`dxeBe-$~?t6?aj8bheb8)O118NboSttLvar@?4dRyQ9NtwTNKA8n3>Jf?trX3vOTMMSqb^>cwN6lc9 zb`x$Rn%R>`cuC*Y8mSX~6&#Vx=wHc_HAGDLA2J1rt6Bo-vz?c(5!;R^*uVRt3(s7F z5(>QHF%IC}qwdQFPITc9lXU8Cu9NK&fZO=I7&!2){==pl~BrL4q zyqBj|t0(&wKQsL2*Sp^g2g__h_Zm;5oSN!WjaK`$=vf6}h`gXt2)?ZA5^c1`$p zVi2U^YC$RaG(3N`Vhw0SHtVlH6ZzqFm27APVY|xjp{0Jsu~ym|X$?9qU6dXk-VUm} z=3G4PA$yg4i*K7tJc5Sqh9E9kl-j-#Z__{=-u{a7H(+;d=+eQ|2dUWRebJTianxs@ za21*Dx&dpo3cK3-Syzw$RY3cb;Ib=XaMyTdFQQBqJ0(utwvSSi5(;&y1FXpRa*EB& zeRH(%DGg?DL<|KueFN;?ZZm#T(c6Er4+^sBHf$mR^Ja165g8^L^Ue z%33|+MIVx4L#@yT?Qe*W2u;s}UD6FciW8=lvUNJ*^9+_v+5B(PQ|*{D?pVN@Eo_Xb zPO(j2wjCkuPE+o<@$At`;@9xc$ zrTvG6))XEK!Vl`E0j5 z_9$`pZHot0Pg9yyzBf&-?pZOV-X7?XY&`q_QJj5#*!0Z@bf~I zp@AW5vx!%rJV=Bi=D5p>WqdKM#~5xJ=L$>q!rd*K2P905w4Lh%PnV!?5L?!PbNS{< zXAUtc@Il}WzY`;|DS4oYLH>y+d_BK|zOnoh4-{0L(2NA(kybQ(X{*(W$?ru$+Ym>U z?N72#>c=L^AMHPqioKzAuP@XRMLAT7t*3u(9N*}QB|rl^=yRM{y*-m=^eVLW@P5A! z1Aa=DdU-h<9tz%eV_q6Azt$-Ka+S#DC{oC~U6ID|`TS9{EC*4t9qGi|vU62FT}hR8 zy;tdZw5yL~Uy2=1ZX17nNdY@EPuHL}oz>&a)KCSTv%@DG^z*Wl?ewrYMU>d0rWNrP z4d&}W;WT|$I84RNFuN&vI0~T_r&~FhhcSD3d1a;uDC>ko*k%4zBQ1X!FMqiuOWkvP zpriDAMx*ob4>Ca3VXXv0My~UQYz5z#151d5*IYh62~5H2Oz)`rr<4*eE+NQEzoW6D zlaCZEVj3M2&)|`UcmaRTBVn8t{Tw%`Rr-czDC=;Eo5%<;VFp0TD#(LM@)yJcF$9=T zo${Dg51WPBIE`7g4azm|O1<_JE2uN?Rt;8P2xZENsTUs#8Yp#ngwRxwpinDZEbYH_ zYp9F3-M1z8RP#5bsR>Z{>y@eJMW%JQ>dJl03PfL+vuIs8Tcu-!xiEF$e}IiEfsX>YD;0_&La`zm-(fQaRiOAw@uBz#i*3AkZ7m zhMfRSUeSf2XgtmeL|;Z&26!1RmtH44G$(h3H6lrjhfHc5*b&;dnI*xB6Sjm%SI?+7 z0C3WpITp;Jz1*!6h8JBT|N95PKhyzsAV4yN_Fkw&M*m{F2wvMytF<8xUq}GI6?=x9 z_EW$`)?OC#F#WDmsPkdSU}_ZErnN3_5hRXk8Hp)O#Acx|fVj>A0gYe~Twtn15639G zKnwrjFyPQ`CAKLmDu0CVz4KF4@MF)Qvtu0DQyG!~2$Mo2#`N10Vl}8jt|#&{hTA=! zc*|ZE;YhreAJ(h*s?eIUkmA7~9>9)zgv$XQ?*n_K4kc<$E7{FKa5xrQAf?|Dl_IeV zFDV){rQ`2dn7J0NvYdgkw~eYYtu#lDw>br?q3q}ij~f)z=Z#Vsin#*`#b4P<84GjnCan^2)p*^*M_4$2 z{V=DXfEwz=lpZ`8ASJW{c;P<+^MbDC<^0lI-N=O zuOlb7Ga?6ikK$oJ;TK8Y;V0olI+&(vNubAD6Q8!5z#&C}=Z;OM5zq$UM>Z6J9sQZm z)86LC6#|6H;#gdMe6_{#jUf%-mkdl&v#NEKG}mkBA}g2uOVwEgT8{Ac1Edx-ArJJu zRf$tdH8Czq79h$f3LEY?KRZshg8-#i3dl~5|A@^d!LOPJXyE-sxbOsHAaHso4%rvH z&N@rY+1_RJNLAk@;;=@dulGcP{PxVCs#m{7XVWH7`O120gx}Zx?!;)ML@?{W^)9)U zsZPZ@*ntA3^D&kC;B0JW%N+J9Q0-|`xUD~UQ(2xQ^K21Cg~vq(hbFxCc$uaJnBs## zQ)dLTABc9fzN%h1Y+;3Ek{@rbgYQ_1s4!JCng&_O4dk^&jxzh^)}p9sjsuT37U7 zVA{V;ei?(-98l)~TE|4uaeGb7KDt=;mdt@NaT1nxH)`?EYKkzJB}Km)Se`<-VAF0d zdJ24y)4-rPEJ^(w$`Gg{1ML}8CqVv9={h_F0y%|?s(_7xmQCZQI9FGe_e zI+V=bUzxn1$*kdRwxecBU{^MlYP5+ecSFVZ3{G@v9bCABT3MQ^Ee66pz#YU0JHgWR>o}| z2evUVq2HWjFYAvL&o+f~T~69>ABs^JNmjgZBL|Bex=R)cV{JGbnrV9&xaG{%o-iyE z)Dy^p8PqO54H-Qo(#weZ)OQpa8}j1-y6{)-L}*VgEb@1_4VYmI08xt@3egd~SE~Vh zTt7-8kb5~yC|2Nh36XecJM5qW7sH;=q;sW=_(}rz$!K*vw#wSt5EN_%^%c}c+J=8U z=$2-YQq)_J3-sxx1P99t&lcZ8)s(}uV%;Or`f(PeF#LisMlW43o-IO_pF;2Q%Te+b zA-S~z$VKY#!XY(FLX+C!O4Qjm)>z5R&k;$XMjCz)I%#LgOBqrA^^&b+@g47nm91{} zIi*!f(nOgQY7}=c#9JFJQo@<{8c@7IA9kEaB*j865pKp`ZD?%Or8uV`6$GXs(vYm- zlDq*dmfMuyQB(-T*hK%Qb@Bdd-2kvRyxwS_AM6aQ)-V0Bxz=m)U;QtKE_y5(CQ3G4 zb)|H~axvX*3`4G(V@hp^V1#Ty z^{`YNAi(ZKz7~+M?=^VC8Y}e|(TaZbZ(XT$&d`}n`cfsBIz@>^L>4H#{}K|580~(DMijfOlwHow*&?KSM z|EY@6{{L6A#TN{0?3PikdV0{G|9!KNeLl!={Lg8hco4ZXNc+h+a>!9w!e1(3FoFEr zJ>361L%_fP>spB)KM(+W?QxR-^D;lf?W;gQtN*F*f4`{xEXn`=mdT(nuQe^`|Nf_= zgA)I{%JhHT-#UXzQwv!&oG9OYVRxfQQJW6Frj-JZ+CZ+oAmkI)&gZ+^A1qsLmeCop zUi@MkHj@|z><&A?3BZsS z1Oiyhx4)ON-2P_Ck$5aUsFs!*I}OKUkUPb7tIR9vPtYb7n-*E)CHX;NVFXdf^*Hiy z9_xh&bm|vB)WjJ5wn!=4TredKcd^Mox;T#k%$DFGz#=QWgakg-#v=^E!jnuz<5d1BH#^`3=EZlX1zF|AAu}s zR2wI<;CD=&#Vl!=5FT!E9Q~{q{X;t*Y@kVEzYa=a`KW%YygVAlu`O&w~txX&97o^7fNClCVm>^SF3 zI5I)TKkgu++|4iRcZU$0K+Bc@(;Y?d-(Wb-gkm}UK0+b#p$0=(nyxK7)^&TBTt;Fh%F+oJ z5VxubR@2Y{1A{lQ)UwRYYKbnM->VIR+N630D^`0H6v^}@CH7bJF&OU;Xc2+ z!pW9_;SLj3MjX^q@0AJ{nqH?>)?c5)=@58YM|HbPWH3BHyn$ctsY}G`WS*s2{1%0qIMre^S%gn7*!5VYIL^TtyR zjg&cPq4w){zQ)x7=;N7HUS4YQML6bI!R-Kcco7;fr$>6+>#`Ecnwhaz*gGO1|4^}B zCYk|qs7wC3k=_kEQC$%Sf~fxllEQ*u3^#4tji=|btgoMbgIrnzn)rcl%!Q_p*b54g zP!k8bMbRo&;MF!^Fl9Q;!I0mYi9Uwq&m)7U<%54SRuKgX$Wa%`e4Ac89Y4qv78ZNk zPow!w|M}vRKj+x}=7{zy1&dF+1&8=LD?$ovBxsrM%bQI#Q}JZW-3t=Th5ddfdT4Ew zHC0?WEpFPpb&esBZ*`ZIqj1={N<2`>TF9pxTCfk7*0?1}72*sllxl5+vcwwaMaIUg zmX!-57*c7)J z>7FyL*CMM|rgBE%Z0zNQxql;ARI3_hEqlDhYOYL(;P6?eCi5@McOr<}_3xEfp!KVO z4$I*awvva*BZFOzleO3b7U|0uK$0vOs+SwkC73dWIGWnHvwsOGodyaNHSNa_XwtsX zMhCp{uX{B@WBP0*2VFKhn`R4(MZ!Y{M8;l2I5KQP?S$ zo#$G-ek=b7lZ%ThFRd@d z%f@Q{)UQaz5NUH^@em~OKL@4NcOPVgS^J?=%Y&qy@+i;ZrHZnq;5W{ z=6b}_Sv!6xH#hbU&Fxe3K#X_nhfp>JJV(FgHbx_wn8wyC)&!8nDT{4pm_xp6y7N|J z%E%2fB8#Q-?h8BW%Ey1Z${C7Ax5PqLUM1F{LR>4Cay(^PGob~F6R}}~Rvv7bl7~!P zsX%NFX+TP-pXgWR`_|7l^J*+W?oCL#9@kU&@0Xp9uYcy;+flv3_15I z!D#pT(D^q0nykSk^O$yT7|A=>eu$Cka`m!$m2s(02BHpqo_EG@@Qv@C9&hx<>nl9!M+;nUnx$8Umj5^~TV0OHX=yfY?`+ne-iPw*(;wF2l+mjP=4RhiQfLsMtQ?D;@w%?NV3OS2@W zxh?yAkE*`$sN5hG?0h&d5Xi)wO8_weg9~TwR6^dE*E|-P#>TE`~ThVn3 z#Hz9Y%4l43pnGSv|LFmzVEDie^-T7}o2v5RS5D4d8C_^T76PlbS|KKGDi&w;1SAzpqTrX6yTUJF$K`J-q? zquChzmo7q*&2LUYCsWp+q5WvTISE^weY5_Hp@I6E+%ito-Ob)gVh7TxlHfkyIrn-KugBCt75~3Bg0?Z02qSMK zrSTYp_qJHB;$uA1ps^R2&_e;ECh$PJD9&z+T9G>=d@Fwj=#nbJ+s zLFtf#ZY8M(^40vFD&EZz#fh%@ZmsO6+o1U7)!z&4?90vKntEgLxmI&hJqU%7j#(Mo zkcR6$dEoLJEBY(~(8H^fDJnLe{@mHNG8|%k?TdVw9|suky@(%O%?)@Sr9VnKSjpMb zNmGH=-iKd`MTS`)&q{k`tWDm6y&3k`F7tm&knfcm7mgQiOgH ziyA)X&-vXqo0zBg#64lX=($wFc<53_)JMMjF5B6@=k4y^i&k^jxvD+v=n)*5h>}l* z{(-o|0w}~C=&J9HaNfQsi^VlusLLex1$?W*EvawRXd}y2c0A)bS`;N?e*9e|ahw-A zrD}9BQj)D#7$ils!OxPyc#0h{1DJDvulTW&ZnG#HTf~#fX(CkHZ?axOg2|c{|{#=SYK^n{*&siGk@j$@V}_YohArRs+j!9np*4& zmU3RB`F4c~LWMNx;mTJ#2pASTpoit8DfDc7VUCUlI*+G_wi!g`I4D$sU&dyS2Op z9__n%GmfHg;ly_p-Bt zH=X;^bLu%KUijUNi0L^P`2gFkpPCmsP-So~)~?6fVcTu1ZL;U_jh<>BfSo0gqI^qC zXY<$2@d$(Y>T-(K4A*uF#gr`d*1TMr92OlTmvBXlSb<8OM<97n7&fcpFc6EHdOcYwzTtBm^1|NUR9gc5LF&aRe z`u#2E5II^&N5=4PuLd7?2VEIPxAkA~kU#dzm$tnd){k=T>Mz1W1IgxHVSjZM%G8oX#r znBISf4Xj#vW;}p}VsdBC}*nXV)P-nYz_=GEuf0149pbk3h8ym~m(`R&9cB0*fKZI)ww z9K3>qheQQ$=!#x>)W6Xs5AYn_Q98F6Y(GDcdP#t;%$6@`vtni+RaMKhEvlWxQ4jjJ zh1M#9eC#K9H8?=A&v%rbX0BxlD8wVG(yzFpRPI5}a@xNyt+d5MKKuJHR3JwfZnv0%&FWDK)Q zI8esvlp|P-H0}^qk_0%s4%!_jhahI6QP8Jf{L-jEvI%^!Z5GabzM=l?+^jn)k8|08 z?y``=C+wk(#Q3(&VbQ1-Lo@J~1@xn5KaO&6gj3|2fFHpE%P2+is4FGdRKMKmjXXR) zIm&UM+U2E(ckR4V>QEG&O2O9kC(VP^pj|o>+I82UuDvrMSVrRwjg~a84`o8d4|N|7 z?Bj0-%o>dkwV|jtH3lfNF=5}yW``l|o&N_5@Y!6Ak&3>1+a5y8`q1f#QH*E3Vv7~W z!x$qmaSCPGFj*b0PWqVPeCFOjykia{Hv9~0@8+|x&u%nyuf3{bJltyjs&rW~2O^LN zr$z8ArFs{bj<4!Rsn(IwN6e@nczIJ2XPcAokuikb^KPaH zM;jZ}p(b<6566=gx0a}XZR-vX`H_v_GQliXq$kV*qNu&T$8MP1hapau8UT+?grQ$C zEME`2GEp~b;4y>ADA%EgZ46Ho^OnY(Rj}yjD`0ZIm>oMK_^WIVWxGrzG$cnsMpSpdhm&kPc zRWk1s{z0xZf3nrQkEK(u!CjF<)I)KE_l(cv8%?8O6|X9$WBPi}0oZ!Sqc=zop6~`| zKnJ+YKCWv_je{T;>(Hz<@J9%1Ke34yXk0y80VOvBap^fhM^eijG)z4>5{bAJ2gyDI zVR-k@N10Iy6-hH8W#Y)00$uf2z1wE9GImUch1c{B0n7^lDvqXee(KeAnFR1hSOX3V z*uFGYza!29uNYH#T3kj1M4bO^aDd((A_nQtPb ze?tOhG`i7#zr6d@P%IaTW;&B3p?XVIO9zU5h0bgPPYDUsQGesEgswZxBzFuNiVdW+ z#oy0BNT5YG;8gFkqW=5xm&wp}0=;P(=MmmAqi`^CDaIkv;#z_>R^&&^diJ`jHNO@7 zr~CpX?Vi@?Vi{oKM?bP5ZAQyn+tInYu+xFlC{Wn3Fos zy7{)gp6T^a#m}>77I?>O@7&K5fTzAQ2{AdwvvGNXjU37T&uW@8mKTRBgF2DD=~sMx zG!`o6S59Q^^LH6%c1X5<9-W)iF{wLpI!1tt_QY6#9M}9 z>k+6gYZ^4cTd;)@m|7KMd@DOe^GMW9>N95UK~0<{Yt z88`oII;}xHr!b=;soXhSHA%wGk`L3Ie+GkBo(EY*<^9w9pb{YT8FY(M>`amWlkpV{ zs{>a2p0N!Ke0SC`7c>{SHXG_MdSuzqifFmZ?+->hGMfCD>iqArn)6O&w(e@h_p2$W z4sahNH@<9Q3`?~r8mWv(jxkO&Mc>veJU{`aR~gv_6?pt|&A=s#6gNJMMMBYSjArBz zFQLPd?#mjLIH&O11l1t=Bj&)Y{Lhx0SE1|zWuJZh!jk-z? zGLJG;1m2+L6szY(?5WdWc>`3tE_La8w1x}zT{Iqi@*@)W)C@lKg zuLM&JZ9JIdid?Z}1uta3Mm<$Jca@+4rvZT_b+I@VLMWFB6m#B+I>>(^ohe9QfNXLF z7vHb)+m5-x7z}Qqel*Ho{80mFlwtV9h7QIX!z|F;+@o5hkqVNh|vbq zDxEFVrAO7K>o)OV8frY7-fYvy#Estf2_#saca4~qLWDA7mVV9snOuYbjgEA{YZFs_ ztedCO{z0hqu)OqKBW%{PZunRTLkd&UCZ`UB9ccyO6O(*IsHBsHqEWZjrqBD$S`2^D ze;Wks2hJib>;;ztU03B#+s;f*Gg8)F4-Hpi@o<2BN8Fb~=b?ktsKPM&5pYux9X2!h zOrg*Bo5O~G@#El>YYeLV=r01247`;gXp)WKK)6cu0;-G@?k@BGNsKRahxo|U0~m@; zbSZbe)ZMQEG$tXV9&E8gPSt8dr$R2;FMyHfhWr@Jh}V=A&z~x8ArBpos5h>8>h5V) z>TL(!(+C0ki>OO>3e07Oy55#Su8}K9a7HF{kog2OBYC?b-c* zN5K7fK3~P%P?Wri1fX_<2?Da5?y$r1sw|glpkeuJ*yUZevPg$keu*GM5Evu>s~g ze?qpC>n*)QR}MUE{C&Y(x2T@WjUTi7B`!zcfKNqAvq3#v+UuClAwL0jaqnN>eTDCp zWH?HU6bR!ny|L@%b!Ki1OJ~)Xo1ZlsYl#wvty$lfdpcvs%e%4*&|r6G(=|yCN2dCr z`JOFF)Y}%{kJ7(}y#6kk@3rkNobQcWCw<&zq}ZO7FualCW4r4CT|7K@d3E!k-P$KQ z;wID&xiR~Rd4k2>``DE6JblsOuG?TtrkLnYCBc}l$1(tLW#M3(O%y{c;!BoS3v(cV9gmL!jTlN0-| z^+J5uY2MP6Uf>|83+{TjG}8A>D?`6CISdgQqwUhUwPr{^dsK)ZB^5LhEtau@|#3{d0{a z48vW0+==Ww+=>12nKmkE)$+=Jfeg(E^ZNpnBhOebj9!T8{&=DDJ<5?jh2{VaVJfEg zM3?>PmnZxGL)A9`M;3KkcWm3vB$?Q@HL)hPZCev-V%xTD+niVv`|o-0eP7kzm8!0E z-9ER@?Q{0od#$zi_TAQ{dlla4EWkpz+|z39JX_>%(TUvVf?0yfj3kJx!XGSLs1bF-xcQ9#H_q+>Zo)ZdT zN3MyLDM)x^*n&PF~9$dQMMw^zdh|ZlBGu7`S0~t)zBDzIylY1loJ4SoOraB_r4Q zjeTTXc@p#h{octoY(^(~JZCodydRl&PjVMqNKW0_OKaz*i4kpIYs5X*@=_jb+ppJ- zkp3QSdLq$9r|8{*Zz91r!Q?n* zp3o(*6-%L)UNO5%Lo#c|u5@aMXDeV*FlNy+P{bq+%-1i_K4MM)Y^gZrd$0snt6j=_ z%@b!|jr2%+$CVu%d(m*tuZHDc?TtUrH)B>jbeL%dI;N!yV|^}%EU7|24;g0F-y!qb zu$klGrNDH_5;;!$b@5_RkH9vSRxnNpPqwO4j7J{z#mu6BG4s~3u zoO!|#dS8c+zJLJ2WYX=A{Sa^QcCZ?j{_yk%m5$XMpC(jhpj6venc&Y|_Okpm_23c! z=(`6b0b&`AbCOVJB zj^(aDk>*^Z>)@|1v%;Pprw1frq>_K|Vj1!hkQUZ9N$@PQIJ&0Ap05*6!zzNd780yj zqHQUi#UtB5Z!$vnv#A{#doYj(L!*!mt|6i@(tfLLG_Qr9;q%~D)7m5;c6B$y3`~m# z_&RT3fb70EYY)QAhVG1crrp#wu0hBvGe_@>KUB?PL(2B;^zKO+VfLNg`yE` zb#G_ia`=kdCxI&m%sTygHUCisC{xk7O`ME2jjq+Np5TrUr4Wk*p(a}sSW&6{DGV^dldT4NO1|dLX z5C%?d*s`9v?hh8@Xg6Pm=JNBvnJ%Jt!ql~c3a!Pw1h(zPu{3}KSZ$eG&Q=ZLM!Ud< z8*SxLTq;|OrIe4(c6|jfb89p%i=KD05y(P579~JIXVp`TzTETxfD88TpYOX5EY0gV zs}&5UT@Ard+Aal7!05SuxJ9ex#bF$o6AgWJ4Szq0w4wa)_`(i(9EkJTl7o&o_(N|v zWtFFUT5tOT(8Q6PukaRIpnTsiXIMCCu)xWY;S%a?IP6=-yvFi^(xQXA;mYc)xkgNP z5PB6wEAMBl+J@Hl2ubp1P08N&$)<^zzecKc;HSv|q@D2f^tdV)hj21pufNggTIt`R660WE9hrVqyoCOsqv7W?90 zw78m+qG>{TZUkO*Xu@)`8L5();2JH0FY=uQpJ}Wdj+oXL z)RA)@d}#+$gquC;krl8p?+?W^9jHwZ6~L*fPH)ssi|ReqOaOBxvq` z5a6Xd*PU?7AolDoE%c!X4yPX9oSV38QeO} zL8WHAB{}tYnZoSGome^~1XGiW*=z(7uPR5B(&>qV1D@{FwkEX?OD-J&eoh6o;DFq5t(12GnXWKw2S1p1^jA2*H93W%|?NAfV<|Az17_c}@hD8n%@BSI z05H$MU2oWgUmJ-e4knxd{hlZqk@EnS^G)Ugz92+i64Fsg`h-5_4fvaKYXWev{TZw^ z{vN`wQL}Ge6}}Q43yRJ#PTpM(XXu4u_kR->Eca6QXA)Ey3;L9PS&G0ss(tlseD{Tb zO5K5Wl>_zP1>f2t2Aw|`Dj}%3Xhq=elqfuT(`+tFh&B~qFYSFc2bN(@(ShxmGj6j* z?J3rRi>WFHu;^FT2@+J;H?Mtq`hJ^o(B4ti$X|6`0hWt*f42oyfoa=lAd-9JTE4E~jJ+8EFy2m?f}ya}0>E<>iYVJd{QW5sah@c8Jtq!CO6 zfE5EHqS=1x+w$(?mLR!=EfYt$<5D(~a;)IKCRQM49ckGAE?;|GqBWkdVw-H7i0 zyDTve{u;u`C|mLq7I2Tz(|o#~ofELd9~4{#lYPmPm=rLe*gjD=-1w5EUb>U)^xPX+ zWKP9!%kA5qc7M{)d3+ulkzwV5uU&_(tfw87LYuq*kr5p+S#?66U2ym~SvU%PEpQh) zObOhlH?r_$s^A@QfLt4-@P^=j;MH4Rk2s{_UY$}lqi60y@2}{H3v{|!d0|ja%&Q5v zt+BF!9%4ZFr7srgLXB(E1*n40jRpIn_0`P~>AWd-7U9ECjtBt@e)%YWoYg!ErU0Q_ zveo*Q+uCDBXSZ_1Mt_Bv9w1{3W3GhfF;AT+^eh_L+EY>sR_JZz90FjTNH4k`UId;X zSj(1YzNJyav^tp_H%=ymN|E1SE9`Sy0z6!gnG|+DBuqjg?k(<8G6C4NxEE9!iZLmH zZl?zaDDl-oA`Tl^DQjegztYc@k%bDWmO*wFxj;lv7w;s6gLO|0;!sJXzYiP+)RA%p z1TurUV!3*gaIwkrGHrNOexR{HzI|Ai?eU3jyrmyq19H_T8O^;#r9pbL$6fNNWc^A_ zw6vG*NajRe^)HLr1-|wdsq@XJn0-j1*mriMlJ~&xF|!)tER&c)EYp@Ne260|1XpdK z!EPj>+BN3J>(~JB0IkSQSqf4*mbWgH@DnzG8;2bv#*){5u$6=K`j}nOiT&N$eKp*k z&`Pxq3d-K|TXl7{xRex3e}8{mR@S9;gWV4Q>ZPl(nHd@FB#D`Vre;KaJ+r8&Xs(s| zO8WWLRtE@x&+9Q*>(c!x<@fJ`{CrSFMa9v{N$}lS((R5FlIYaLM6i&4rWZOoIx$t% zH#qq)=s8VM3!ZL&+N+uHe&Letcd@B2h>5~KW`0(Xr#-yQe&$7&KLFPDQ+rT?7pZm_ ziPK+RI}6#X*O*gTxZ7YbxDMog6FjZ8wn%4F0bh?W!RL-S=qBFy*2kNLztl3_bu?Nw z>^2Hqys{9H0YIW+sRqnAZUpr2l6%tleTci~ge?8+-gQNW+HK~6c$rm(eLvHmUIKyJ@kr=PW_KzJML{^bgrM%~GIIXa)47}JLYh?;OeEn#*~ z)$v_@li-slrZwQ5jP_6%iE(YN`+06qxrTf1a+D4)YNE|R_-lhDa`nr*l0_1a88&b$ z^lulBf`d6jGDo>E zqS?JMW#nWBvN07H1vWe-b|(z!mgzk~D+izrkUxfMKnPWfA{5i0R0{L^V~<+rKX2o- zdT8Wm#FCWX{7yiA$P3~h$Lr37@xIPbI+Nz*6FTZ|L&M=D^XmG+^xK+L3fiZ7rnlIy zMdxjfuV}qXuS3kgtq;~Dm<&OqI$oHdBzR7uE3yZbCIp;lYh|S5Rzufnc;Jf*phD|q+LYAK1u*5B~s>5sc=i-13^ZxYxb-t$ELrN={zm=DO&~M`{NFYHL z6^!Apt>f{zwFtMud6aa#svyd}z2wy+917g~YtO(T_6VuYPhe zT2uujmk%|jYTx1qYug%{a{E@ycdyOsyUrIphLK`sh9P=D?`V>RB*HaJh)PIdE$v{L z&VVUn3cg2~4(4w&`>?(<0fYI4?b-1Utgi>L`er=L7)>dTuY`$cU*^Lg3T?VOtDqE> zjGGe)h^+eABGq5N-Q`0N(w$tmwIW@?1P@>eoMH+Xm?F>252wd+U68JA?#%8uMnC`} zO*kkPxW}&U>5wiVmknqI9ac|uc(p^PjAh-HGLaYK}k zYPbIIw1VAsreSTwkRU)_p(~8RkwPe%&?I2lTq`a!!~hZ^S!tv(+{D-Q>vGJ%g-yUI zSgSrB_XHCsSR55bcK-iq~g|pq*+y~LyAs0Q5|zY06+pQ;IEFK+w!G3gR~8jXyLTIEu1TuetYoeDD z)kXBIeBpr3(wOlzqAd1a+fs`1)ajIp;7bm=E}bYLkc}8W-LG$hOs6GEWvF0sp+OK{ zIodrMd2!y<1H{5!GED6mWgd>=@9eSHnvR-K`DYu9wEAge(NWj zH+OECd)vpszI1`x_vLdgy%snijgxvQK3JN-$m{`Yd)5%Aby0z>iWT)EBZLTc$701D ztgfLJ+u^1w|)#0#iOC2ER&5F-K++B0v zt0X>}H#@FB*MWK5L~R-SXp`}SWh3vq=gu*cOrq75*&NpX$ypzMmIqmW`?fgH#NNmQ z)pdWV3K74e{`!rZ>N$Bu@Pfu$u=wcK2m@+c9Tdd>kmk(@M@n`; z{v)4v$zU_dVSx`LQ)Mnji>|nRt911)cV{MZ^-0X^r^rL7KMu1sN1pe}4wumd1318e zk0@|T`*d0GjN(r^Hx1(4RuB?i)G12LAxa(92I{*k&vCl*ea{evhXKo4-SvRc^kv}n z1ecF@;N2%d1M%;ePnGFcM>~)3ZS^99UV^QYU$^Je>2Do$$OE8(;8ALP2$&iEPrlSg zj77oKIjNvhcP)vD)nc(K2(DO=v>nLk-(2=fOS*Bi-qTjP#k^r;=sshTPvKB%q?~M@ zfPre$RQe_`b{gdQu7(EC&U9fRO?K$!ff1}K!^e|O*}Llu(YEQFpGW+U7J$}9ooH!T zNduxm8S=a427z?h@NuA6C%0{CAU&ti#5KRa)jBjXH7CewL=;Bc)LjVPJ^(RYR-R)Qq`3Q&` z2O^`-tc0e%S>ekd*dV#kHgPmj<0_d**hCL5m9lzN>(kMAAv=)- zP3^9#l|nK;btDmqKvFk%<)u%*md)^ZO!b-cnhU>r>yOnI8`b!OgxDInPQmMoOR+no za}o!E%V$TeZOdM;6=MWMXUXz$F^{TM$jijMq3S@_@s4^ogEpWCD~XGKS<&>Pam>@x3_v@_>LKh3CdM$uN@~0F^1>v%!ZO8PQM%=cbNZvE!|c<>Q&eMmSh~2y_3O@ z`SDauXUJI3s@6`o#WQ+k2ysMRi7ct5-?GmC9FN2;`lcve}XTwzA|r=ESHRv zhLhNV{Y}zJ-9e+4TaxP%;#ZE zDZ?jf{Aq&_D%YVc8bgQNIR@&rE;cfNoq-ozCP+h)omWmS=yQ9kZOcp^GTEl=_T?jl z0;oSSKuwBw45lcbwUI_Ok&{Pl(tPXHWmjpVx?L&JJL71XQ0*pHE)g z5?3*Nq}T*vO#Iyeq?-|wwaez|6A&}lbi{M8PiSgfP^NBZ4$cxZY=wU;;W07xDXt4s z#v3UOyJ&bg*Qsy7Wh|`yTvfgO8CG+RCZsh!c?l`Y|KiobUerzWLQ=8x<85=Yq&7y!ZLA73;}T zh5Be4=6=$gaY8{UFRD%=&o?K=npU`xA+GE&pa}~@B;ZEB=@Jrs0x_SnI+YXUOIuq3 zQmC&t9s0wAlU^W=*|?WMC{KgufM;j_i%N}XuC}|Z4K$YO0W6Q1y!tY1zm%H6oTKj` zfOMffegfj|Gsh2=dw$GoA8der%TELIA$B{sj*4abo#(n~INc-CJPM4QLK6ZwkwgxQ=z12f9<3P0NRpnE;g;x z-~Re8pYqrST~V3u0!3?CJ2MyssOG1yiPnD&j8H+;qhQCtE4L(8Q zoep|SMwtHIZclpzaLY%Wx5yUCeQ^&K;Z+!vHxSc*L;bLu$iGrf6#J{;7>%B|LnsOy zmHR2}ylS=n23exeLNtv6pip0j`&u8f)-TabceHt~y|Zyr;#lhKMVE12h5aQgkU*nj zMf0)~5flxrBIh4NAjEko4n*KkH94c2=p)QC%0Pi`{;WcKRK=q}K-8UYLG81{^ug7g zw;K>|!~Z%Ug~T74zD&Wbo%OKF|0i^)J`Ms0h%$?s=w7={-nQ6ssPlj_8HIxSD11{&><+`_mF-$BGa@Y|(qZ zsL~cw6}s=L^NrRQ9^DoK++^InH%zEdE)~#5iJ&I3F&}!A?(BbA>nZ-bVOQ1-0#Fu4 z8^cVBWl_-WaF)uRQHhv>jXgA_nHEeIs}FnCXbrEaYvuDj`?Lw8WC{*~&Dy+7-OURz5UL~VB!R(Y8^$(Ja)XW?7*^LBZp?BwqS)UM0P zO9+>sYgm~M%?+h)S!J_SI19fnt*XA@`O>`hu2BNj5Ky6=-(E9!us*}q=$Jpc#@;NJ zZe!hn*OQh_QJH|68t;7L=Fn^DYC^J44WJD7yHk6aLHgF}r^b0y$g|xPp$Nvz#YZFc;#trNwY zqrYTjCq^#<-3B?up>D<%@3w~JV0+kOy_tbs0`gOOvN+vz@Wm;$g7~PxBZ_enD-~{o zFV6YXwF^)*yZSeC)xo3%T7%z-MepOyUCEq4Mk^hhg0hRBcz4HV=KBJW-3Q>aaZ+|M z%^tVKc*u|76TeJMD0Ek0>V$GLGjza5_vw6NAnT(Hw=7$Ya<%rjsy&%79{Es(QrBs7 z&5OkKPcq1ftG*#vJnZSmjICrC85(3`ne_d9T(b=rqRS|6U{a}q+K?kIGs@af%_!iy zE5Pv?s*#5Z_xeEeiCZHA3OiS)gqA%G4DkH9`q*p*;&qgmE|Za3Z;f#P!qezGN=79? z>G|H3em*3Zx_|SWa!6%=Df)TsPI8)%bApnxVQ*_qk;ub=FXLIVl?>sy(?D|x3O8nO zV1ANaUybMq^l#Svb}-AEqjFfd_yq$P}k#+2X?u;n};ba&I}g+(6Uclz_BIsy-}8}44Z`i9(~FC;qd3`Af8 zRR|-J^1h0U{Iq*_n|Z1>f8}tb_#pYbNY6bXZ+#FIMqa?hfh*#yn6A-Wj`kSkmb_@Ot`MvZyGpzdN)Ag7&6B|L*|il*a)IO5 z!KTS>1}PZVQ~PsdoImaakJq>{9mU0S`PY#=_bs+{Fzyy>4!&2R)|T;WxSM>S6NJ}4 zUWy=9*feG-#3KmD3<5|W&%diK2#g*M#WMHFNOl0LGqt$wOgweS{T(UR4Iq)iny-%B zvCqF{ly&8ksNmKsVG~M>*~n;^uFoHIJ@E;`N*uE7FRs6SZrPs!0pLmZ3;=~rjNC&g zH@MZ|!+2;MMt)0>No*LTe4SX1`{Dtc!k=n{I#FP38JW}Yrs7H(n6{TsyZ{Nx2%at@ ziQO?p82~`+0qW+oujC_UXPelkKtxZ_-Ww?lUF}zw3kwS0(BzdCdJCxi3jKRP+6D&b z>(UwF`=H!Up3ak}p_(uk9|@0{$;26jw4WO@{(a;MJxQ%;0;dyxA6LN* zbq;Rwg3!VVYtZS|?n9E?6<6lZb&IS!*WXswDv|{sAg$m!7qfAD7W|;Vwy~TR?{o7R z@>bXKigbAHDr{FKB7Y&-^YJzgdb^`h8GpAMha^e2KuSg`v3T+K>S^}m5Ql2%_#o&b zmIbhgJ#o|5J@Wkc$-qN8DCDj``sVEMR3{;t(zvKIhT%Bc*)kMBtSsCQ$p zuSNEz*tkO}f!wgMi(MqVTU| zFomqYmxD7fj!QiQOD2bv)t-UMizF1!UL#*0gp1=ggaHveUA9`&v5~9An^WmRSs#qZ zcba^FGGJ-{(9NGIIupZ9T{kH{a&)qiXZ&S^ux;9bk9QA%xginMZ zyl1MQ#HO6%k94*}Y~J`BCYEfJVnnlIv%P5xhi-9W$Y-Z_gj0>TX9 zT`0)NfQAW>giQ2b)L2pEfbeL{m8|xobr~2y^9ARq7t*UM?sO)1HhqtA=8O@M?*keU z_k1_;A7zll!((8o(q(2cDICyNIztD941tfyn0ev@h?Aw~8ob(PjM6M(a&OMoA$wk{ z5J$r1tpr$VeSQ#jYj>wqsb$2n%)o-`{x=|`QGuzuVsy=D9aBZ)6Z*;6~L_aoXj?u zaqJTlf@K1Ai_~ryX|5Qg3)O!uQkDtcu!q-erY~Ewk$y#XeQ(@~n|;!pYYUW%O(*;1 z{ka{u6?tQ#>(6j&03UmXZy>Z!&6}uLpUbwmZ&?QY9 zjCaUSv0$PZDl2!EF7^ZpJu{C>0Q;lH62dAT%6WHb6Z*V8E{Fo$?<|&F^b|P%5}*8{ zp3aQ^=^S%(p28ndP#PntdRC&b945PB!jIDvs%R@c4=R%Vz;Bs&z*&By&2iWp z`vL^P{Wk!ez!-r%%!v7D`sZcW_Ob}fYNr4U*&BFG!{yl3JLh}d@%{O0C{WKNYL>?_ ze!Caj^>UTwwf^yG#Y%OvH~u)*#Ng=UZ1b8?$JaVSF1aP1tGj86tA5CtXYdzHw@&}B) zXYSz>WC*st8>8OengzYSN1SxIHSd`E#H4ipm~yecz!YK?;Ciq6%B|Y6!>X^FXKOJ} zGfTy*>^|lM9ni1|$QzGZe-~dQM5Ikq^T`DvLeQMTK|_u6Fd!Xzi1DWp2g&G*8CD`2 zZ(el#{Hw&8<-D}W*(P#)_v%|SCv}JKlZHZspgYxNT10Z5PaZirD@aPls+z9YTo?M} z;|zbLG>o`P9CAZl$tWCS1_G|+n>X|#C zc0;Bw-!J;Rp4)lSSKYNg*CjIf_6+Af%LkxNb|Z^)FA>;O&DR7TZT(DY*G1Dr1Cs;w zcPNr22@Q)IigPpBWuv>hI$n8~>w9uX{pN#(Ny7SPn9>@T{uY-Igx*}G5sFCs^W&VM zBXnPhmSNohi*)wq%5W?L`qn!AqlPYB8kd2)4P9f#;z8R0pF|XsZxwY`di=kWpwe(X za1HiHzIeVMVf@3uGx}(uO-+1mkMom$h&)iL5P3k%X>x!8_C0w;qlk z+%@vA*F#?POMKR|DMO}F+XCz5FFa;0ia>gC*OLhxUDv(%n zU;SGQY%1A}Chq!9(V@WLqVo0R`*S|48DRZr-7rt!Lc^WINOm6kKG9&tT z{iY7AobLcpt!{TRvI!-du^ed^=B%8)PC-Z!We9IB&(1bD#j*A#cw202S%{eDZHoic z#*7`Wpa2p<;U%|>?{#nHWO{zSSh$IJ(WQ*HRxRz@fe%p5&sQ@vuGd%q!BPV_J~)7D zKWP~-(mWo&uYc#LEih!8IlCo}mdp;MYMG=4Ag{*khw@tUy`VK`zsF~6URnLxB2MV6 z2QS8-P}qO+pJxn;E{Myw%ker4^ln>8`XKgXEO7r;6-8+$kbm+I$ z9pY)ys54wyN((yU!+eN7LLBx_W?5#ow9HCAgw1GW=$kRardgjpRwUfyK~w z1OV|5i#S>MLmStzOO>+S?`XKaY(k?iGJxwP31`%64!sKcrEzN-3+Ril6-U@UWwd9^P&b=7u`=fzZZlT-(RRY>&J1-=jq`PsZ@Uv@f}3&r0e~ z&>Vd4bSt?}8v|0>ReKzceP&j~9>4Pneaut$vuM}S!{$GJUQqK@YdXJb>gD$nNa!B| z--?SC_7W)hPZcLO%~1x~&HddT<`FPf6<2##e%P<(qTtpcXsO!uUB9_#bQeWVsUZcW zC>W?q>N&roF)%-4f>QiTJUg%oY*=uC@XT?-ktwKBKIYWV_0Sg5WKexOS8VFBVG9JN zPQ=lytG_i?myY2ak*{Jy2`~)z%>+%bn(Y=zxVz#o;=TQz6(;Rmb(FQwfP+eKfb<`( zCsJsC;70tBEwo+;Hz*G#@r`lmGT>_Ut&*o5`$F+)*k}8aO~4kSZyVj6uXn^LziwZB z@X=ee@rU1EvpU{XeKDgoX<$(0e8sYKefQmpViotN&eKiM_VARDIc6se#1(iP&SXTD zFt}>rL=J^|(`R@5_)-2NbJ6(q?h#E>X_e@o9rfJB&|mA^q2jZH!y;&CVc~`7&V1LP zS3H-NRICQN#}i33YGUFo?EvD_OtJTG$8G^2Gu!I+D+e__2)kF)Cygw~;2@Mv=XYiq z8G}_*rbw&Z5FH;E)Lept0zJ3aUV#h0d1UftX*onC+TQ9o9I-oLVn&ydOTv(LG~A!$ z=o7G@9xAxOanK|Jye8Iu^Pk4=qQMAT?xr z*S51CXl^O8c{fST44A93uAP;i&0P!yN0j)ThWs;F0R834qWJ^r(+Lpm`RPx298p2T zM$~u%W@u2672_Z;K4b@@RfsB*7z*(}1VU-7OK#EKc$lVcq%zIVMt% zW(Ghfv_8S$^|Vad%ZUD47PrfpW9t%;r4UKWL8#1M^Rv|5B1-m))4(t9h1iGT2Flzs zhLKDzr<0}?T@gjao1Tp}aZyq5cDHN7bnjqJ8(Dm%z#g6M9F@r3`qm#Rp$9`VkdBIJ zGZs^q0`E5>3UjfCqu;j>dif~!Yydf+&j|irC@V~polK=5uApc{^4G&_7-8h`DgH?B zK)A+mNhdcYWI*3aFnLdOhS;WJ^oG+L9OIKdEg>vu7&QRdv;nrBs|Iry zl7SViu~L7osl}Y`zXbj_MdlgK{w@HHn!dzGhJc~0+d%JuAV|Lprd6MR#`#?VPSTMW zY6rBn@?jxRq*^{eB^eM19=HWwvBwFzH1|HS_k7UZK0~WJUvDKu4e4J?X!x>@T!PyF z?XIKs%wW59S0s5^y9YAY$@lU+GeE(*K_j&5V?XG)(bV%F6Quk+(z!A$Rd~w z=TO3Ld@F^Yo?h;be^oB)$WZHoc!TLr;^409MQC*ps6S*(>Ap10%q3KSc*d^BfqwP$ zM4_q7!Yt%u_GuT;Ga1B9byVbOzKd)HP!-N)5!XnpISth*mvf?6lZc>@?|uom_+ z(xWEZiFO%Twdaz&-8w7LPejoVb0XmjV|slc%vQ^^Ny*7|efmI_0_GNrlzu#TVi>^`nK!DtCAOA0NAvGjYr9#;Vt?eaUBE{Aj*mnqor`=&j03T{6{9}vY`R{PVhHO zWOjQFx#FLNj$9wuOd>PzVRguUxeU{KNj$5IEWG?Gnio`4*?YG$O?fgjy_Sb$6ajZa z_v{o|lih`s^e{h)X@9Uob+p5VRxW+u=~REtA+j#i5Vt0nifQ%{q^N`rl$RPwSkM z{)tgb9Ciw7OxGzAut2i=yeY?jeZ-1r3-=1>eLe9Jy;(WhQ&ac4N5LQwqbJ*!KkLTr ze|EF1x?y|=%*_1;gPB(ciQ zu)i)=7k{nd<~;p=CWK0BxNGQVGfgcYgf>{MoF1G%`pws`dOvEZk~CioaP{ESO4!S2 zYMW?)GYT>vsAMZq15dDD5FHNPkUN(v=#m8+79%!b3{#euP4|w0Pu#NY`MrN&z+2Vi^S)C${6Z2G7t zxrffY7r&@NBHg2uy)=uIpxjA$)3g5!D2H~pe2{%7dYhX`tJTk%R4DNT7exw~A(1S` z3;&N6AOyUh2Ij5{xCuEAYsMNHS;PFr$Wz?l<~$a`+_!_DfB(62-?6ZQldSLIxFYK} zI%!NNCgEL`?%m>I`IwmJcL3coR_Y9lV>we%1Q~vRq1L#l>DzMa$rBB}!DiV)Lag%1 z0<{)(|51)i_>=W(yS;a6##b0I4moQ&E4F9(hj?osL=;&*y1$4)(dEFTAeSH%$qj6q z=JRK=`qiCsz>mpK2C8_IRB8}<5HhsjL1n(xFHLMYVsx|vB%ZyDZWa%T+7f;lnVCeu zZ!qjJ!ErsN?}bkKAi1yr32^-)@aI>QY@8(b>(V!l5$HH=nBgMX6GZX+2CYA90rA)r z@avM36V096-XgW%An|_%wiW7N?+|NU%Z6roY==UNiR! z!olW9mk$0^09p{nsRIQH{Q9sB9xMAxlff<+BXq@P2@|Filv#}dDU0h`vrK5v@XNT` z(uD7&OJ;YHzLI z+i|{PMiAeFrWUsnXgbIZHlPf^8ZZsBhrq+!PXkQ_9-It{t|u`5dj;I-s;>y$2#Zmf zrcVXZvsdvOBkPJakt$$3qE@rkNHeFRmSz={1WsNb+PD=ostz!Z0xN98@c75Li zIs$ZOGFCz%-P+IZxr#hulRdE)izQA9y2_`CXrAfL!Cx&tDW&^!QYXaBQ#4BoXj)1C zp?v?62GWW1PXVT&C!qS@{ngW6jJ;lAxdcC3{)I8YoaYt|VBq%4U}*?pXyhQhlz?BU zT%{pE6)NzXK#%mR!EIYn3Ec|MZ~JPjqk#*`^>?PzbbfwdDw$#HAMnx~T{0S7uroGd z$U%S2em1yLDpD#g8TpL6=|5>}QaU?C4J6T!%Yu&T3?66Za^C@= zJtsb5*uY*UDYnrL=yP+yTi+>ua7c*302518h;=5^%6C)g@-H5&*; zxOl!jsMV?>*uwblpm#|AaK!&Jp?||b={Ky|@AiTKdTR{^c4aZ_O%v17PPSL)v_Mc?z~TVj z;s2IGvpq;Ka7DQC-t<~&Wu%J><)VY`Q$z?%q{G1&lTsdup#JEr(|_DfX>`!%LNFBM z0E|WDS{=}5-$Dbx6yS3u>y0-2(<<}ZY-Hau`zvXpNMRz7ks0b1I2%o}gsm7Lmn0loDg-nq?dx?V3wP(g^Vh}DG(Py-*Jdzb(nc{!vnlvTjH zd~btKjj+VN5%f-+YtVhDtx#FgaZ_jwqPFHzj`8?7TvNH{ zUL#1?R>Kx!9zC#>@335WDB!DVC_e+7=z+naE65t91cb!)Hme{;gAA%9VlNam>u9HGzA!;+N#O znbPYr&o@CT=t{N|G1v{a$(;pNHowB10grvBAQ<6qI7T%skJ^3ak${A3jc5n3U!{7X zAP(`S!REk}NNNS8yrI5HbL;J#-k9T;1)v=U1==Q%U?)pxq$b1tT~PQ7U2*EVCTO_2 z{wrh!&5HiHOvwv=)QM)os4x-OS1n6*U?Jgt5PZQKh`S6NBbkkTZ?v2!&GIuH2Q>7{ z@+A)YP-qfx-k0`EFo_;)Ex>8`G`V?TE+55g9PWt-DHv!z>4IO&DwA&ppxg~Hn ztk{GQw@neQLA6Av)$TMnzQ?vt{M|R&hR^W13+I|%+(L|j2GjY+$BkpH1qFNm`{XBm zFQT77HaF)!o+Sip8HcOA?_SyjJTZy1rLdSnkIaHw`cC`wmU$FSmzAmr4; z;XL$fKSVrJ*xP06uH9L;Kbi$5sFzzr7`Xb(%K)U%pei&N;6naWra@DtV7u^iMM_)< zjucXX1AG4DY_zuRkH7Mvr4kg>k9Wc~%T)SpTi$}pNJ&eVERj*HfsKh>JFIgmY{CXW zehryT0ne~Z>-T(0sc_Qp{DHL z`z~j*GuD>uc>7+l5NyRR_d_5fhAot(eXQbrLDuFLyzP;)s{B&Wxw$DfIa;dS$V$8j zzfmw>9H(s3(bihyGR#M_OdVi)oPu~F0{Ht(l=V=Oo3Ox?ix0#wnTAaz9VpX>bDNWf z31ZA+1eS(uDS>+FFwr)R?A9i|EUJeTg843JO4hDmh&ZNxT!5jUX+THrI)P?T;{^zt ze`kf66^jiOP6U?zv84_wdPSyX3kx8gi&7yuofU--6ed8DDi7My24u7Wmea{VW{%Ek z=v_gR(#aYB_)jH)8J$8(KH?$|VENP-HfX!dXbRZ{*kb_-&%6qL4g!M9@(q4lQ?;NE z=+g_DF74FHu;<)~S|#S9zWdpIr=wupu==?Ae>A;wbYx%izTL5HV`AGjC$^o5ZB1-X z>`d%TY}>YN8*hJ}-}_zb^ncxFtzKvEeeSCJswz08&>wOb1hwA)MSTru*?{REx&%>v zvnI%e@}bI#`D<1^b&;DR`@I7&RjYweL~%?ov46>9zSt3lss|0Mhd)?5u(Xdw?IPL$&1NH`7p#&8TOF2r-E1 zM~}!vrx)WdRpHJdGfi94tuHUYyRD>*j$6V!G;9bc4h{|=09XPvKd&GdlSHWi$uCi} zEDEH1%>Vsn{!crSiU0)=fS7{=Q@vu|Lj$;jY&Z(r+Hj+p2L=a)6Ul&ee^h^Dn1&Sf z^{+6c!=Yu0P!kdoN=r)}n!&ilQ`6G0f#L>uS+e1(s;ahx#ICGpG7T9vuW$OYV8gS3 z95t=miTe2P@w#1L1NUQnef`>nz7y9LnFJp5wZS?y`_?xv19G>W!eHh%-pGeXP(vm_ zL~PcfOGh`q1|Kj4wgO`KBVd+rk;pWm%0H|^oFKYM zCOQ3HNz)s(=!h@(%}ObXD#oAEs6sU?vdvg(VpjuP8d@3(LfXVUiH?f(_g0&TSF+Nw?_VX|92<+A;7B^IY#8&e! z@PrqrnfNdg5*Y;M9lszg?c^UYHfZ^;X-=!~nA4(pg@1bR`nl z6>>p@lZB-W`v5#Yk$tNf>@D{@SW!Bw<_hZ#dxyH(V- zbc}#jRQo-HjSIe}hTUM(H=&u1KCsF3F(HUhU#--{i!r+RBfP-V^hYZ+?bPzd`gZbTo}uYT${B?eu< zcZq1?2Hb2?Pufg^&J=<^tJgAa+14h0Bwt_@tbtaT7_C}2(eV{9Q2`93WA>ZneSBOt z2>VQ~;e;f!b@5~{e>}A&1>D7~Ai+r&QZW0i?83dO6w6RjcD8S4RE>o6f5&O+KgwZg6*AAculNSqN;rIxwLIblP5`3wlB7m0Xy5(VHnDZW< zFr#8+5>iq=kGC;x6@m%#<9qc&C1Iku1{X!OMF~w?`P}J7EU{=|<9}NoyIqXDZH!gF zE6nf_OXi)f(d>&*jQlL>F*4b_kf(B4SWfaji<-MkTVIO+0kjr!#lL;qIm#}fa$v@YVAF=SPbGfq4|0&%*mD?BC09<( z_iM4dwPy#30mI}WZo^>xsfLOdrn#SgQc&r(?)~#CWYv8^cM=VkF@kkwi2VRP&Czv@ zkH@(PJH)sP?d=hkASM&ukgIm^S4yGZnXQ@V#`hu_rOAjBomPxmwxH`RoOzF|B{6mD zmv(V+cXxLZ;tttAp@3IVFY$fX%&CiEbgMtG=j{C2BDwa73lDaTL~?5Ccx+TmOo(<> z=;{SJv#6+OzA6m~bQi6gb`_>u`zCz@@QcBrp=}WHk&&?O>teycqY`*Xrpeva_ybEu za0rf~=DC4Fa_3a1SxH&$-~H-d7D_8JM1;PMz=7&o(FTI&R-6L1i4JfQ(Gg(fsLq}N zIP@FadhRTn5{*bfLG`(^jWYg4SPWR)47L31i@Kl07$kDjU7MlSNMy|-I8dG>t7zfA zwco{Ta&z~0`(p_T5W%fzI?;FCI&S%zkeXJ)bvwn)D_wKf4Gj$lgV$m5-o#!lA&Czk z_nH_|>->`c3dVx^XQDTis@e7pqrNxHHB6MGT-}3aq8@*|a+pD+q6xSqkL13A4Umlx z`f-i54Vgrl@8|#1AQAy7iz0}5M=T%4;6rIZ-ImrhHJ6nPH_jk?md+$0d$_{!Strc& z`J_@Y_8Yyn^5iy8r(YH+=B3ja}t^#K4+|>uqLMxs)s&fH2(zLo}?7>h8xg8x>M!q zd(6i~<#(;HV>?FpAX5JtT_*~h763Qqiy*nlqjBM}EAwb%kU^Pm&XCb)DzWE5$<do%Nt`mQ99rkYIPLkc- zrI%VpZh!1_+Ht%$E)Oz0oyNuEwQ|_|S_c=6#0!MDS7D8ss?Ie4d+rSoc5#w)?6UQePInR^yln%8dRT?^g!~VzXJp@RCecew|Ag3asO=`aF zq%||WpSg&)+9sF{0zHIy9VS~MZ#j3|d@xV6vK{6#*sX$KB1X0|*-qqpT+(dNa=y?q z(g>#eUy3Fh(>PX=C#wEiA&6Nn>wcv`+8r_dM_*jKw~Atjo9Nr$ZK*O@IOV9k7<^da z1;y2bZw^l(vho6ySu={hM8^CqK}OS|#BDr5DuB}FwM5?zXE@ajxJ;S6u+285qRI{Z z1O_j#_V4pc6!<(X|K!B|zZ&$?2gC<3?01#Kw~YG5kthYN2*e4i4lB-1@#a9@ z$o{3dYV|ZpfeQk~-xn#F*}rHwN6wEZ4C9ouz586Ce!x!m0FfZelB~IIORC~obpl(i zlg8S;oi#}03IC(vWa-YwcZLQZnHjC&wsF)H>_opMVYQclocP;rH^@QlI_x8oY6}^K zl>OGj?Cv^z_O01CQgL{9S1DJhcH3)K>vq}kw-$dYfH`%i%M*AP$p%oO;HCCZIw-inX7?y~50>iVhPF=r{MxIGq=0;z50)TbAIL~LTg5!4!c+dooCS9tLqaCtV^U)1nxHex!-&p*GG zI#Hy=lr1@RmyaEz6}pnI-hDwU>QXqpvIJENAQj?XGbAYVk!xe6V6!sa_$4TGg%m#6 zg9uo_r>{5Jjfn|yZ&BD;2iFEI7)$aCkL`XYU?W&h{RUE3E(&wIqt@-p&EWJ~F9Ic# zWX(_v@`V+Y6yQ}!gf)X3QSCF!nUPxAi|71u7chWxfEUlqEzU7HG1=B~zh*wl?0dQD zh3B(a;V0dSRnMBY8*7L}Fo#5p9V_auo|sc)^r>kQ6D!aueXcaWHrKG>z0QCrVAdsq z=ntjU?Qr3{)>dv&X+;Bxog#SX#%9dh^j&rsS#0EA{Z#kp;R=x-dvi6z%2FMWh!w$x zq|hKg40+**e4>+j2mxsMuJ3`Aq;w0JZY9FMaGpS-eD~;eErEdE&poG~`1Gcm=5c-aT!a zdQIrIz^iZmjA%&MH#=Mx@KK@gYoK(KC1~>hz?^#PeyzWoi0STA`M3!i)Qp<8&=cZb z|ANus$-SEX@}390N38%i(VjgtblXMz*tk+TYUMB15j0m%5fm#O^3?d^p_$V zb&O0@4a|!U;BW#z1vbzS z*>9gYiZHDaH=Dvj{*$0+xtAA(3xS%QL@&HR;yIwq)7C}{mZX@}oVaR*D7rwVm%C^f#hNv%=qmRwuEMNtz(QC&yioVA1SD_1ArUv3MzJ>Y*U68CD z<&YAyU%55vH?)i%R`7uQC9v}V#Pi1K46bHz0u6*xI`aJxi@oDS#J2WP-hXh{Y%@urD4o{3G8Mz+Qb zaR8v_kxLwOr16-LytCR>-_)uIY&qLKSl>XPW%DuzSbZBhGBPqm%kleme|X;oLue=l z52_~}j4TZp6Dm@n*Vn4XkU$6W!l!Toi+5o|`s}L_{afxrTO2;=p+WHxU%lnaR7J{E z3+n4pw;ryyiGKb11@sCYmJR$}Nr@Du())G@i?Fxa|K3K%IP^F4KOApIOjucO^mY8n zLh5m5Y6xX^>#3NcwL}&I9Jd#(f`(&TWbEi2dBq_{X9r74`cmA#F{Q!Pa=fdUY7hlW zEab~-63NMQ!Ybh&_woD&jU>`igK}u`!E=$}R~GRuupSV4?rNy*YAM@hZLoaqga-)l zzQC(Q;KIl9W`+)OiY4l%-jlObJh2365hhwb#dDhNg$)|@F>2-Rh#lHtR>}7bB-2vU zS26;KbqRtjhWupRD+&6>&S5{F*yS){UQN15VhUcj0Azbk6pB_Rgy-t*!HetJBz%i9 zAVDk-QjvDG_Zi&WDBCvF!gkUGG8L68ZVfVSKG(^}!Kb*Phu%MzdaUd{D2Qk+Z<^Z8 zl|efO<0_3=n+U1`^Vf!yjThKF4bdOgdd7tZRtE5;M5@oG$tN*EyCCIQCUd{jA4Bb=P;RzvKQnKCVTOm1kcM2sfJ=Ubj;!wQN$SJ!Y>$ zpx_|ns>yfZ(n<*A64wL>`fpWQPMu7*E-*=n4 zE`~`J$%=ZUhCbjNMe3E(yEXOBbUE*41QLNTL60$6l0u4B=6(Z$({hl6@*|5sE;(N} ztRUexYrS>=@LQan{BMn~n;KNM2OiI!^h4Sg9~<4xyZ~re^0uE`lIrSe@o@bSKdvs* z2z`C}w3XtSkDlVT^KYN|`jRss!Ad8uyVg$rI&B6Ho9#)OrdDIS9LCV`abu{f(90lR zmK1h>g=g%khy6h#+i?O#5Vn9t0?n%|z!j`o9|F!vANl%=Wb2Vrsnv`DZk*2jwapJu zR8@{W!~H&&Y?SymD&|FO1O1=U%4#ZFz+Vaj2RFdE2E}{C*e}H*gg7cukLNuZ1w)D6Y1Ix&<9t$w8U6NO5@ zpINkQrv8rwz`o3h8L4h2?ijBO0HX_Q1P$T6c8GIf+XajFTY_|IwWf9bH6wu-(&_^R zJTwc79oX4Wg0%j3xSp3I6+GNT>0?n58|~1t+!peD^B&k|kMbFB)faR=|7aW59eDhX zYwx^Sur~dq-|&rF=id-N&BsdPsYF7B?4+o`OK?lF;k6%UudH^eIoH-2J2`xOhuJ;l zgxQq!(_`YgvT>)RM?}kcIVa7nRpENTABQFifC{Dml?j6B@e2f{=r*x z<_+ectrjcO0kCFC-IIEC!>8Ux{4KVz(cN3rF{T{J*m+GEpz|iksKfU{|L#n;;s@p& zVYZ#CIk9w1S7I^jk5t}$&HBz4%AS5*NGi3lQ=Es&&PCg3B%)?U-LK-WcQ&PfS{yrM z#(x9~cqpfm!*|+Zx9kG!UABKWxkC)CK$7x+_h2Y`k)eBorpJdh3iUd^J+S?`Y~fBca-{0aJ{kVnnzSx}f=mx2KcF=75s zq24(}{warbdYL2;Ntg!q0~K1!UT; zb%|haY_Q#%XaM-n_J+QC={=uQs)q~op4*xkPyHCL2--$E`2}8;>DDecz8C940Dz)A z^ZvbQSARbp*lvq+rO7hO=}dMOVh@#6On*o2!| zu+PoivhV2S-)~M|?-K&^(|2FeS zH{NyUp7=3=;r*D2zrjr(Qk}8${XQuaC||n`{Vn~P7onQ}9vvE=9;SW}DBUvxmGvr= zI6OdHFG)oc%gzXe1URsx8(d07GPywW-82JsY%S@#JcI|d8Dx>QchOH10fk?VX$`IL zQyc1P=f=|*ijDUnG+2PqKkuC^PRQm_)$dYV)t&wZ|;@S)bkclN6xE1uX zduZ`B;5@l0kcnAeva!(TmQU-q>)+n?`R&RmFk8NzE|dmOf$)S?-S&f;v1X{;Ae%50 z?9DBt1aLRsW-FH%=-=tT-jZay>PcmpJp~E|x%GL%n^0nnUAg1;1oZjmg`xl65cP*T zj~Pyl>P87bDWOnotBVVxF^@dsCqf(!Z%Z7t)yWgSEUA4WnB4McrIQNHO&XpQ3=0u# zO?TQhClmXx(;a2s#7V0s6L{jJpAWHAP~!oJsrt=a8tItmHvV*`^0}h>$i}k^~m{O^zwevlO*4jd*~{z zdCfk9lsv$OjdI2n{j+VR)7CNV<|t=%VqL}3dY9%Sp?R*e3bT=m_EDQ@XalbN+&OiB z7eVFrCbaD3!te$HbJ-Ec2rN&9!{_=bxiX2|Vq3jM+f6rjA)g*alfNH{YezT!ZkUtM zKWW+VQe->YDcEXV0$h=r0DG>m;WpA%Oic{~2&~K(_!kvT`I%c-xkXPy`%IK}>V}F1 zMDtv)=F99YTQUK*r@=gX+#F}melwgol*CbG=PnHpz~bCxa0>>wNJOBG{lIenVgXNA zdpEnjHuQ1dvt8j&M3nr6nsLy0HtBi#ofuN~cJ-nIl;i-5xd-5~PK*&QF5V=TwY%DD z`pq~u<59x?Sg`qA|Ko7o=L|fEnIs)#l8|ea03OQuU@u^C>&6VYfw%;- zW_%C{5HPyeQ?YIOZ}pncya{mJSP^XZdukpS{Za8vIeT~#@^E$l%ZBHls zd9D9R9&4$oDvwR^OvqoyQ|sz#LGpRwA?N2w4AOH;1b4GM50#0j4l7km0c|5Mt}5UQPq;2Mi9ArX;Ia{G<=?xDc*?_e`{pZmqGfC}c z%WvAlRd*ZHtX_20i9Zu^^?t22b%S}KV++TVqU?x-H-&loM`GMbTy_NmWJM-MNX8(~oU+m!D z2s$`_0DRmfLUdg{z_lCfCT;ks8_b+NtKvVGQAKataXuc z*+vf0SD!INzxlt>0jwfr7$E9}DU>WjPWs~q9)`N#+bLy}y}@xb%oO)$1Z;(9c=07) zAE`^oO8uZ5z>p>Vin5>rms<=lgD~a!v>#m;hgas$aS##XZxjvj2I33lSskwt@j+Sg zBsn$`|5v~N^BND;y~*bNxU#60D-iDQ*7fR8_#D{?pImvRnIS#284Ixl;o$l7N6jZk zqJ}d%WyP07vlkeCHVgbFDb)BtqVv4@Ze$J;0N}?}hh6crE36%|bFBlByJ6PQQaAlc zqzav>)LJy0Waz-CQhRKt+G};?bJ*5Q__6F#vK;g(NvxNX*Ny+v{$x);K`jLZLI(j5 zFqR}C=HiMw_S`Li;4k2sCyruWUVpHcDbU(GBZc)t0Yximd$n(1Bw_@*SA1MDDUTQ% zad~H0YdtNF6ayO}ARsr0l8g#v{oSbhz5K2#u<^;`b0eykeNg30dDdhNrkr*gB*}<% z;xJRoc9e&UZi>W?DbC;D1Fwi%JMDNFjTAyzqUI(&saz!RFx>_hgK}Hcru$W~)C2^u zcA}(c1w5M29Z7iTW~&6!fekMxN&KfdR^%iuv~E$RyiRaTZS~_KZH_-$hLeABy`9I| z`fB5pBlGXQBZ^He#Zd9OK@TriNzCP;*iFYC^!`vvPlYf^uQB>f92tHwhjExb4B!gM zimS;IQNrPm=dc1z42w0!*)MM4*Fi5|DsuZ%nPNGV5$|xuW-^!7%T}6Ov!rWP+P7T6 z;a2To0Kg7ziZIv!`5%tvB9kU0mVM>8?bT-S(i})l$AQeFBQ#Dt@ZdFL-`aSDJb}^P zgYQZu*a|+odHv^7Kf)RZ@*CbxO?8kjdLZ>_c}$khGH;j+pvvgp+w6#{*qHV z*Q_e~n(8WGOu4aU^tqeV87AuL(VwLTNf;$?=EWK1ELu-Ku@e&`T~^8ML~uf%kqVmT z)ws(vRmU7Gz_beV3<4Qd75Pk@3@}nA0AJDHIs<&swM_h&j-U)}6ZuGdlrCJ(M^;Ts zbHbUD&OBr=k?X4l5K{Dp&ytNc-CM;$mY(V+#}lkWE*Wi!M2s>Zv0F5ZQoisM=>v$7 z^49tMVC(I9184x%KVvLKuq({~x;V)D8FRnO%R{YUZzqMmU95ftobBi$Lu7f1W?W2K*1+K#2>x6aZ}RQy=XI6ZK!3QycK57j zzP3JCCbWLoaBO2pj+z5r-29!|cf}xd|G6zEbD_OU(ZxY`5#JHvfJ6 zYe2{QsOg+np^8|ShXc{7D1fO->KHykLR+_=>#n&I(iE%Nk3>*FgnZpDrnIl;gMmZB z4N3ei4RZ5pre60se0Sy!KiYHQl@&$-NjNp4ZsfJ_HI%(T!p_x>l^q*eN}rH6Fp$`F zPAUzyDm?0&GqhorM$`J@<>^j-LV0mws=k<8HX%=BBLKqBdP$AQ6zG%y*^mOBYwO@5 z-7N?Fh#85vKn^eTfOlv)5!+ivD*gw2);|!^c9))ZNAAo>Ua>!*|F_C`|IKJfB(deg`2K54 zclGOT!h~v?FLZNU09ZDD&5CSt?G=yE_VK3vsA6c5=Smll{8#fY+2C99F=j(Hr?n0# zblfy!1Y@Ymq&BUk&X#126jCH-!QO1Op~=ArNtvH%joK~_Kq z-e3Oj3R!uv&9m`@Le&O)(lH@2N=lQ7G-kWo{yzqN&PLrG9a$W97e1Iu^dx+I_|Kci z(W_ZmSsSI$q|&HkV`F)XRzROsSPaPb0uy`x`4ZqDK!pi1_(MaJX1aqQ$DbA*HoO2D zxD81ImCJ$$jX_M{-P#Eb4-bJpu40)g6K)KPW52=rS7Mui^CUZ)@0$xYJS3fV!%6fD zK6f@$$V$_6wYq?gp2+*N@Y%!T8e%Cd(~yl=GFVB8VdmZ^;ge5ToJ_{mQ{oLp$&rH) zh^h9n4s+4CoFzs+%QRBY>FnFg6JJOPdeaH6a+MA>4Ukbu|;KKq^Day`-NA_KT zt2#_6Hi+7d;gZ!8H@tT5``1n%$Ky%1cYF(_2e0jPO-=r}&)v-OO~f@ZY9Zs#EF+zX8Wx=Y2ssa~ z`_=F9oc%-T%k{+Hgr`kjp+I!psdo4F^YY1$Zp9Jqhm!2u06^(MN(i{_p(6xSVcoZe zXjoF;s)`ZMg9zt;#^=q5s*1Ow<+W4s->~r#T)g9RvK#{&)Ig)*dL99DPKb=tdYEO{i*v8;q`1=?cEv(x{AH1Z2u<4L3I<7y%!mjVG0(`{fJG$DTPjBUr z+;&pJ4q6Q+0NXk5V#mjvt7+spjbi5pcABi*m!2`uh~^zlQp2n^ydiytQcr@U4vmDW z-{-7Mgavv1`WMZLBW+TL@h>dn8sJKVFJvX^}yZjtNQ1*uD*&T&k5am(%v0J+{axgh{hXcSjr z)=H00rG+7CUK(q50v6%hpQV@Smh0rF_3WhT+sexKTxA{=%05cO1sJQTx-& zmT3srHnX1_LshkzVIY(J zX#O^x=Se;=;|l<(%=R)!h%~s~q`%*>gbljBps~Jwd4{<1PHr9z2)9E3mD)aUQykqI z3wUNKFCjdXjg3IJj2~qs~WE5y6|UKgI?kTWkEo*S@6{HqiX1wQ3~C)2DP~ zZlI)d_C@h8|MDO9W8}$5jc!EBr@muf;mpJXVat)X7qFwb6}=1zD@H!@#FuyHb4*2# z+L#5FF)}!u&iJC%XTL zOd?|Arl>4>BaVFHL7RvumjbFOkz5yMaktJ*TWYaDRG_rHp$uRGa+9jvggyARI`B+* zO?jmE{N}*kEPWMVmF!`7pg?#!B2y&P1TK?(#WWG(KZTXhnv4>mczG zC}46w*`xS2jEvSYbkGJ@*Ma9!YQ^e4@)>&i^EDe?k(#7Mu7EvD>6L6x4hjbL7>i3y zJ5_DxTOR>ifkXq1WLLR^g(z4KgD)!er`t^NR7xWeE8fR!l zB_`YOKP*09z|&4wnIs_F_GyN$%BEA}r|b+w6O#LhPF$TR~yDyrW=vFFe;fY0!dZ4YU&m*OcjNQkj@}(m^Fjt zXtIjd6*jj_f)!_gJy!&{8{a~ST_lxi1^xu|6BKS$^%Olp^$1nY6@0mKFTCR2rhv{? z*PbYF0B@APnI8o5tT7oA!M)4sqo{2*Se&0r^rpR28gGHv#vY0 z-BE&`@ldHgf&@{2d)Vw!zZ(6UaQp#Y7rm=7UEjQD#zrVGTLidpv$IU+ZQ7e&h*TJ-`qY@gMG?!9JQJLKIiO!r|vFJ`)i$yCb zFDRgB6mUPUek360EHR-ss;(O{{Oi+QVp25?01LnoDl}22SXJ_Kl1_Rzr`v=!DVr}; z$4Er9U7!L=E@2~Tjh1t0SpJ3tQN?pgJ_Zv+smE@ZBc^^k>X6Y|7!1lSb5}Ln^!3DE z-Maab1?TETWic~w7eZ&uQM=&ArxpeNhygcQHrBJ0RXXeW>#J*LpWNS4MEo#=Vc&K& zDsN0SOP4FPH(D(s1~9PXq1z4?N&c)#dTqvM9jU7eo{asfTCsthybd4Fxt7C}*DdSd z0T+}04VnNWSn=bZPxB%)6;|;YD;(3`D!+rIs}$51h5!GsM@%9F)nNZj5qbnFFPQJv zIcY{BM$B>pJ(=K@5!<>}-$4_I$33uGMfsVNl~S?nr-a_ad>!ArIg`XzT`e6YrK}a? z?xuq)=6aC0Fq;_BtRJW>#`dxV|A^)?dQzSA*dXdEl{=SJ7p4AGl*kj2qf~1j2GVlomtwVK*DcH9~ zuaeU)9rG+R8#j!m(dO<$9ZofhYF1U*ib4SGh*%m~>b`USUv1*>Lp>|fH<)Tb@Bz!U zTSvXA%0a$jI`@#g;2{c!cKzzSQBN^PZ}G$4ZN3ai?G7!#`aDWx_W|@am3P1!rSg}w zBj1WMAEsN_48^ViHkcd1uN+BL9f!rk)VUrIFl5Z5hiKS?OBBL_!R+QOxv1^$n+A7? zvZ|^pKBNH&fTp*ytIvz?>Q{an9vUSa2XQCsU8@a&6EpXM-;SfH1@;fv_*Cn` zXn(vnxrHGIe?rc%ftUgzLCuEqEudMPbSYl3S~~FSig}5A^LQq-qbAK=gO+;z%Ro5s~3Q(2FjK|F{OE0qY9C2iYOCS$tIl^cjVBG4y5fr2{C8!z(9jZkjn}{4`@Im9n2*ML}RrSgxRe z{n`o1tj?m6p=Dd)^`^IeGV>ET923LDWCq$DUlsh_y-worN>-TA@tt#7ZED?eLInVQ zN$)J>m{L3Uw&p^wk))AD%qny7qmE{5>$K!p*)DJe;8+S6lFJsaZBYD)*qXRb2D}*o zfit)}bke>>W)Gi-R4K&EU54>$fpGee3T@x7z%{gbu~J|--7b#YSUUJn-8_1BEztH$ zr$S+kYfB_l;YpBG28^kb=t_bdmZR8sF zMr5z92Y~~M4ZpV>s<-{|?z;3JyQvWQ!`kONwBAHC$G5Y^21Mj}DLOx}q z0b$%)2zpps+CHCzqIE2&HJTMr{Q)#V-)Bw)P>|1^m#tJm8F0|TroZ_ErtomV1Wz*n z0GcRK^M-tQrMzbhgdCir_X^<4(8lyro9^BHCJI0K!kVc;T9B9U&Gb8`X!n!^`_sWb zx}}>EawC}mP4L1Mv9j$KFYjB-wb%NyhP_daQI!3DGs$P1dKK zTw#<(bn$wjL+W!>+y<@vb|y5~x$5^+=w3T%)Rvd9@!99@U~gr#eZ4_g0QOX` ztu#lwbGJ`|ix!n=IwHIRQ~Gx-l}+GVig;U>;P+j&FgAq8)rdZP0xuq;ah~N;Jqr&^ z7%$x4jU(Y&2sWK)1Wa0XJe8T89qe*h>@g7)krv8=>U-S*Besxh-@!Yu7Ur$b8d=bC zd?bN?Xz@CR3NFzF@$G{E2Mqh2jpAb-AFDK2FwBd`k%TP$ z+9fS7i08XQlfkW9I4#SM1%vs5A|xwCPIrVOWwj##f*c$s9AsfQ3TcN7eLZmKUR9C znFvlEXBIeQ8LQzARR+p9(3_?`AlbenAz0@+-}knc88r?A$XRoNS=VR-0n~nsjAN%W zZPN1r3xR5HD!WVPlml_CAreK~MQ>hg=nz@;S9su}rCC56yq4D;U9bJY0Bri|7Mw^P zh|3S2E1q5bj7ERLD!%Xf8Fzb8rabyVBmSd4xlC6A|IS>6FL7ux6VR9m$Y-Ezl0V>y8YY(1Hca{7Q~fe>4*H{-bOy(#-_vQ(x>JR^8`)^cH^z z_{~Q-k{w{4WPo``N+;=ubLGKT;htz+dF3!{ zxN>@lAvlMn!m3H^>?RPIJk4^Wxc<&4fB{;AblGXGPtlm(SW ziJ?o7>B2XI|G*Z%YUMW&qcsa)Jzfs9<*Yp(t|2Xt<8d`==5-KW)}g97qAFmEnDIW0 zT~B+)@SC)g8h35rbHJ@pg1H-*d6(fVn807zQ3LI=2u3%ScZn&p=pCb5qGV52HpyPj zLM`l7VQrriB_g!_gUP_WlWs=2+W!1N9y8|YpIEr4>EX>-&x=iCWgCvDB5e7=?)7nx zaP0d`TE&N$#|wDqV8fyD?TRxl>R{zNkf8iaWDBm;DWTSz_ zO4ycmJ3t0Uw-{#FoGh#wDvTyDV+#!lz@SX+!8~~1R!t10&j&`gB;igb2*S~E-34uH3g>l%E#h-%64#j9C~JuyMc zi<7tPD8Tvy?1BNzLcX1jz9awHB6w>NchujjJG)%~90^9J_*uGqdN z!3KwV5>}GqRsOgO$pigg5r5WCxZW=V$T}4mVwn(7?U-v*O=NKQ)|p@&@#8SFJ}N%~ zV@Mp)8~A_*38Y&grv(r>5m7GFK$?ckiGtEEKA=>=20}xYNf9vAE`DgmNqK>#%8So` zjegIXPe~rVjncVJd`qFt))ESly^(<>YjneZ^bPvccxW&1ZN>^#I0U2)&CFFszE$&P zGHbtEz<_V6?Gc6Mo>#0`{BQ0FfS8&2mWU+a;cO93T3Q;IDsAxl zd}F;2I&`6OgW8?^MlhY;XbMS=Oqrbj2m7emTJ0Uxl^b10N~#UH6Z%$w3~&eWzyx-P zgt;4(LklQ|y0V8r40;nbgZu;)6!9!70)MW_3>cR1|NX^`a4yReLikxQ{I&oE&_TQJ zWtS*r>AUt2Erk9JNpkaW1qiql7c|-`j#~ZkLy&w~Q-};=uFnSxdD+x2fYWVrAC0s^ z-jHizua;-PcqvVFjS|4-`8cC_+_RrcXmLG#DoYb`zbcsTPiDtMi6gt*WY_!Z5R2lR zf^R;px1DX=j~8uWR+aV@+FlIW{Y6GP>k%Umfy`1_5xphcj<50F;vW53ZM6~JdLg7%=&Bu5G!}YYy|&ji6S==tKu@dMcNYR! z!FB)*cor*PWin5)P09D8u$EWTWb>hQYE7dA&mc z^oy4C*Kt;0^CV5S3pew3W~3V79*dF|?`%xrd_V+g8m$lQ|15+%xouCWx3tj~r%@RS z8to47&*u2ZM%c!NMLQHikQwGA3_&V%(ue#nm4}uwwXvVaqq8>QX`=PKKm{nM4fbDW zi=QQjF~`^2T*q}GwAd%*u~$)1iS@AfT&TJsHTO4rBlJ{81uJYSW}~y*11_XPWD$hA z4?{L^z;1FHbN$7Um*ezU(QL{j+L%X#%gPK*C(%?4}D@O$qtWE--jDVm0pt zjt?KZh)ZkrY0uqX4mzU`{>trqkF_uN`UZS?&as_txhQI{f!05xn+8!u1}GyhFy;k@ z!&Wnb7C>Mi-$EG(3k|@~M1mCsUXX}BCGx|Xxx}#*+8(`rqGV8H|4Kp}yZ7sSD|p^= zp5~{PwsXpH&M|3_aaJVEzROZ9v17cyrk88_XXA1{6r4PTud1-IE z&p9)xLTO7Pz5v{}hJfY?B2ZB7HJ1%l{ejm?QLe0d>5t5=3+wBuR2Jh%=skQto&gi7h2-|PN{n`MK= z3;s&k*VMTH51f$PR(;|Eg%IRrkO|No6E(MNyuohu}9!`;PD=iS$?cuWZw~2c}8r#Yf)w$b;4jm6)4SN?v zZ|qOf9I=W#sGVy}*z_p8h9N%FgUvp*L27)3%~(-syo3aU6{VU5v(=4u`*Il^3!%Xu zC?#{x=x|P&?fHBLHru^_1#c&cv6=tQlDWVT$SHMI?Hry#Wiu0-*5*!j9j z)Fr2tJo%Nom|qHF>eBX5wyM^lpU_C#-$2*5$~!S6*pQ79CxSFA|4ub4rr~(|fskDL z6vw8t+hPw1FuovX!FhP4KDoM&ELJAqm{eRNIzexjsTiV!niq{14i9|7UNGsa`H94G z%`}&pU#Rh!T}YAV29dfI=v_ykO;HKws!vEQv*k4++IBQmecefu`z)ujbhZm-YYoGS zWb)ZReQ`Wjn`BF%3o$877^2(cEY(uuGn;_rUeEc_C6fqPIG7*++#N}>U2?#4>b;Q6 zVy%w-3ER=JzSKR3nSh2Fp?>%&cTc@ujdYaq_ z7*%0$DDrQDpwfpH_L+bV6sR=h=kmQj&8ZW=g{n@&rza2EB!Q5bh-kx zRlHgH;ASEf1br@TUdgQ)_ZZ`&>((xcxW_wn8$x|SEmiz}9iaz%${znrH|sp#U~Eu? z?od*ZZ-X*JnW+-5Y*DT)ytZHH84M654qi0v&yrZ^VPZrR_AcMb^gb^6GH}&T310&B zn6p|&0T_U4LiX@jh)R+SIC`HGu$Ybz0c5hsIZMwG_})*r?;L0aSN_yE_hw8^ihp!b zsU8paDFO4$rzN??zVA;)y@3#WMOYMy6)E&Kfq3HcCFtP7b93{|??JD7z)Jt3Py{^V z+r2^K{Rhlhb$qoajz+qH(?D8{aET8-*t_ccB1zF-*Oz#*);xw-hHq#(iX zkEHJKTAD>FJ}CQW0bvx9!;*ef&=ubT5CNTSnS-NL><@atUmq@ox=?$m|65(CnW+I=zxtFshv&RAA?X!?`>Uv9uUDE z`NeAoWWP|u?Y`-*+&T@1!yZh~dk>KnpG2-*7o9Djloa7|@8D8)OqvZslyq)|?Laj- z^ai?&J8NjV<4~kYF7Sz6kw$}He6?dyQ>f0eGE0%L@F5kSV0R~e$${EW!wmbJ`~H8d zeT7$5>lf{&8xA2LN+U{_bT=Xm0@97r(hU+yBO)NuozmUiDJ9(@E#172d++a!_Xj-3 zfCG-hK6`())|zXsxl|YK*0d>ee_v@8TEGnTQyD!(baZs~dZ+Zz1P}t))C-tG6AHb( zhE}|hfA%ZFZ|RTi<@E;zz*5hJlDO9!vmC4=D~Uh8zb_I;#@)bEI(MiTFDx)=DIv_T z<`;JsWVXS&33qP`5=I;;%O=@;iKv_;3R7(gWlh9LY&vh>#`2zH!*9ue8UWk8>DbuX zNz#veecJv7-nBwtaO*t&2cH5H3xcA64*KadHQQfn77KCUGw!T)hu6R8FU7?GP6<>( z8-q?Hm#rd&T)YdJ3WkLgbKPaGyqj9+Is??g_ z;4uw7(tVyQ+Z_4fFyp&pw1|~u0rT1ai*7G zUwc<>c>e5pyqs$REr~M=WgG2Jwu8KS!3(%UOjy@%U8A8y-d~PC4-nBt`NfnvH8zb* zsoI2K^4dqO3@H8d=LdY-&nP_+Q(tp(?&*D%hEG|;C3FmXltoKQR`E#y%f8`N0JqZb zH1G5LZHgcYV!TF{b=q1XuM3~YkNW+WB_vJ+e1Az{>m%AV!_rSoW}dyUM3zxb-bY5f zT5BEC#gR{DDEnrkv^i1aSs`ieD?@{q;QRTM@ymF{%Yi$Crmd-B@;c`|+5R{dB3|A% z2?h1^Fx-a5LDC|ih?X8HbcH%qG?Cnion#F*rB)@ONXa#H{tuy**zJq7(4lr!MAc;JA9K6jBo3OO$kIo)m?B8 zleQj6B;*ohf}VLPP%J@tSpxe{}DCdiLoaVf#W5?qGo1JkHLr>@}PKWq{qj z5o!#py#mAAGTJ@KqtR~JIeEi1ixa03SxOpO(%K&{@o>bEYajOy3#-4zP5mrFkGg5t zmNF|9yb>DqZTW5r+nE&|lQuY$%@>B(Ryxc*B%uUf^Gq)Lw#a^LqYR#0G9H1_4F{J- z5PIpm=WaHj0M82l4Lzve_rsXu-!-)BVbC3%gAb!EgT^j}HOIuB<@}}kS3vS%$HSJ@ zg)QEEh|;;EGjk|g@)r<56jOw7Az3}FgqUtbF?zY0cLYH`#c+3(=Mq#SYkyK4soL5R zLntXEU>3t3d-Km?f^5FPW)V!LJyus%w#Ua=6+U(n*B2D(@G9c~Wnyx5ajkH|95_4d zXp)Nc$7yhfJ4xiuL@+T=S&0M#Y^?w|9z+T~y9EHZp?kv6?WG7ZYp67l#EFe}nW+N4 zOG`Av5n~>cpo4Ca1Y+YMxG_5`LtBui{pM%hQQ^>f($8+G;z{iC0@?6~$Kb=L1K#0= zwnKf1;T`$vI?y*(76pB)kM8P%0lrW+*+;i<$u8MWuqcU*!%8iv0%RZ;_LvtmG>8(2 zR4pcWvA!~+EhxCH^GPVY>|Oh0VnG-X{ma={wukrgqM(R?7q%|VaCB5u5g?y@bZpPm z8j*faNI`XReVyU3ImBbXwokSTXuF5g<|$|pv5@D5U@7WViq9S0P>L{4qn`elydk&* zxXwHRkFC(d<%kQEd3kwD_HW{3Xk5(vVOv87NCB+F*ndVdq~%{uuWz^bH6=ByhY>kjrj+OyM#KhbyLe z_WmVFp=N3N%xwQZj{!z_zwO_lU{l|tmH#0je0M?3X+1*#r7FGf<%f&#nBwkIFYFNKR3@=WMGX$#hz1NHe)NrWohE-?hY!<5ul~z zWw;~-jYcf9f1i;}edhxd@Xydq)cCc04t&GMc$~e*^}j2slRYfFhubS)m}F-cm-`Dq5!GPOCMpnW?zSbM`}26~ zcd2pS{kcRyV&c=Ai`7Uc8}y+1dVZR(b;4Y|ot;_P2`$9sViLc;eED*}b$X>t8%@_? zziFz}jNK%9HknFdWYDdHSoSrY4Q~`S}!uSFd=t1~BI2gAhFhoDS_cs8|+}`g9)4 zWzTSit~jgUsf_(f8;iRY=o#$qKJ9pdii(<>9s34{oSdA^=gw0lPmOc_8$JG`M}bZ| zlM{{{zXgZd2O)hH(i3E~ZzPW$uj#px@0t!d2F@v_D?H_XFr< zpNcc6cY%iQUv+Zsb(vQ!Yuk@nO4A7 z{;-SFqWQ>Tj0XXMZ$7h1o*lN7QMpUxXU8=Cq?-lVc3bZyHXpS#NH5V+h~5`$kY0GIa;98 z;L7mgMGrMKwXv*|UOnyHB0Ca`&|j8I56jmA%nqFCy3v>wmS06PQ1sgJg|$KipSKs( z#&jm}Iv@kxSySh)e;i|av)hR4i6(GmsRn-qRY%KcKg`li? ztKpy=XC4>;{=JClE4aM8oFLu%K!XYoEkn+@%C;bMd0rX(umH~?Y+qLJT1aJY}!%~a4qA{nDg*9XnjiDM;(;-JTKPqqLAl*qu`QBzXFfxyOJuee%= znxFqV2JD)7@MO)rdn_vb0>>jrB-8gH^Xp!Xj;_af_~VT9Pg3qjWrIj`bj8z@MADWp zpRd>2uZI8?T|_82I2fL_Stx>(-;7T6i^~4ddOsBhM>MoF`BNJnvbVRl>LaYNTlTB* zy5@pw*_*9~gFx+5Y}sV-Du?+{%h(t`1didAHR+!3t23Ohx(7@9%Ce&KG?` zCyqPt6)C_t`d*S1s^pb8?`ie_^-JhojTDYZO{IWZK>zA@pvE({UJi`%XsPjE#vczQ zS;NEKffz(~r`vD7%VqnCCqt9?%KVfPy~<1v=B1R12Wop*UG*?!FNg!ZN>EUc&2~ZH z2dg3c-2CgOGP2N@#Kf@9P@+(NI&TPC?Fw%P2bVQE_q!1Yw4UW^4J$S7HoCd^3k{H# zO~QR~-kUK50>Y+MZ-1&A1L5F{C4U^dyBoLfahSV3nzcSy~9I0!16_ zW}O#GQriVUns0S8#iwh!+&pR001U^2`v^v|9o$!BrR5YAH}{k<4b9r0@$vD4MCUXu z3PvS=bF#WEC5uw!+v25>X_!v!`evb73_VRpqWj$gK#-H-J(E_Ksd6XNPs|Z5gP0v5 z@Fs6b`eSy~v}?ogo12=S!T8$h$ABTQNO#d_JzMp=%rtbpv4(LlfxG)Vo3Rx<#k03% zCTQTMKLUHz{lr7s&W;r{F%AKgo?rNi0?H)|Bd;Y+l3`+d6&Mfuzi=pDTU_g5WvRz} zf&;xATUnZKjPP%I1_wK($-M$V{X_^biJ?MXS3%&3Lm4!7Q^F~tdrR!s``D$^VokwP z{{Hekp4q_nkB=DCHB~Mk-_M^>ny&ZxPxfYspwy|I=jz*3mA`+t63J{E(Kj1B4npk0 zc4iDRDjpb+%NaLjB~DezOH?5O{>xN#yR}3h9cj^Ku#iU2Y{q^eF98`D8Q6MH5Ft1? zIG|1AFMmi4QlUU~TLc^=qlIrdzyX7bLC7fL?p`-Pm8;(@v@x8b|A(tcs}h~1@#HJe z-_6!6Hw%}S?En*KHB%8x!exaD?L)|KuEZW(i29sEJKl#mj|mO(gquTwz&aBt)@x+! z26b6iXL}40Z6` zk`k`RgWP|?bZV)*dqsoi34VJwo{Q_qr+bX9pGxQu{dlC-EnjupVwMNtZb8eWU`-*f z_@!!&!lQ+S1(=u!eT*1$95pvL(WAEk0YRyw?+TCGIlA^g2+l4z%fhDQ%_OE`^L~5N zv^}1f;AzwoZdkfK4d-4EF)_(p|GnNHH=3hJ4o)QPGu=8zH0^4ePN4Mk_is13_T=9e z!yUo+59-4Pi%njpj~G6Po{;i82c>vl12O{bxY6Xe3qC|5wN?6AKFtOT!_&LK2_pG|}V7!9dKY-GJ4V*Yl%Rrf#%ck4_Rk zA_d;N#g04N<_N(12Z=EtAOiMkrPb_phDsjKMJsXnms*n1>{17_I5?5+?DrGw)J1&Y z+$3&!%EMfTJO!RI>f1N96*u6De+Nfovd4a{%1#ro9HzIl!JxYqgN7Khi$G9vZ0skX zdTA(#ZvyTvC?o{l_X=Cz_aDQEm<;#NiR+;Wj||+1id_P+CBRU9alTeqSf~;S-0y)O zoEVGV*G$lH`fpJA*Lk?yPWqk&a&XVIZN4Q8C1fhweZp!0aoH~HN=amK=U?GMiV!n& z1oy6=Uz9$^eKhHfSppJ2H!6(e+s^nE*o=Gtm}q~q-Ec0BGeuxET^0xdq4&GUAi{4B zA&492_GrEWP$li>*tod3=TJvS2ZeyZT-iOacfY|xtlf-rA{PdSBbU{0U!a>p>gzW6 z1?*X40J30Lk;o`2c9Z+u7^2Mpoa1C?3P<1T^i2{;&x7w@n&1B4xi{F~j{%lptaYH6 zA&19mL2(lmOYw>q9!WUzYIh`y6JZY^2(sGD@${3BihsuL1ZT?fH?9$K9g1V^rf_LrAG z{{Hg)`(Re89r@+bd>aAw>w zvPeJGEzwjiE-zab7n|px&w|W4HNL>u8%-9zg?z!Ogh|R*A?8GY<&8=S!^bx+XJKQ* zWgWJ8;kNws2PNDHvdbBoHEFnfg$a4OfD47wYKf=ukfS&Q!59 zP$Y-6(|b20HG-6dEJd+4)*f-@uRd?D( z%FXNjhR$mL{{35!sPX{|nB|3T`k3u-u<0nDKSu!}5;Oq!1!(xMf{hP6*0MRDjEsy@ zU?0)-&HKL5Jpg$Ef`jL{(&oN3_4TWz-DKrf7?g*=Uqf)lBrtfGFob~&tjE9%cJ)Pv z@mq@B0P!;}Y8K&(B?Nj+rPHg^9T^!J5l|XfdZKyO)8F6DP~5O$XB-Hlpc+Wz#Ro27 z^{yiDmBDC&2~xw>&m`oHh6T-eZiZQoKB3`pE=^Y5HVOm1V_9YGcKwbQnz2)`@?LXb zF(Yg^s`%Xe{XF;)oZap7^Q6fBt@b$0ZpUU>%wNBM4?17)82&p6|D}Ijv(n` zTwFS}_DImzM0?x^!!_ad6ncOmG;0H3B+zp>1F#~wNU2YErn-UIf49;RjEaW#;X+Hh z%BodS_*QNC7*ss6y&IwE=;~TIozm|HJsntG_I3I{ME3>&mxj!}k&HdQkSnX%{`&$& z>w@ZOlFC$Cd71)7Hfxur)2vs+M^!&UUW>;Od~DxU#^&bcyklj6I2@3_*#lg)En%rZSp%I@hC-?Q4}?1{P-V8qkM`TiihlO zE7lk4Z!=w=B}a8a0T|f)Tk33 z@{NofKF!R`9K_bp>whtB?|Jq538ln(EIcm!g_RdWRATRr4{O)HP0HObEfYG1W{Rti zKH{a91_AimYW!etG^^X$-T`NU&2C9#4(-M7!?Uxhc(n8hi~fXB<$=4~>%Z%9`h1fH z-%(g^j`~@)er1K0XhoZRgo*9gtv~Fe`sd?GluQpl6{v`zBH`W=wP-+ge||kX*%}ph zJXj#b5j=r8ZH)kT4(^K#O;2B68(8-rc7L;#f+e4sl{GzH`F@NRJOcC(!^t)*ggjyZ zp_W1Xt8_Jb>j-_|)Btzyg|nWN6fy|JzkniN;5#jY-5+bLk~hA#zb{mG2f2+$1g_QT>Q|- zl3$JQyG}w@R@Uvx=B5kP^XEB&(C$nn#)Fd$e5Wul3K?(9%>cpzI=_gRnb8g<@qcdr zjAIP)K1z93aYI)d3AQj25_AZJpJKsN2|`|c0N-Ppb?JMHEVeseU;W!_&VZGInp)h% z#DoI4vk%9rvvZYG)EE@2epmdDN%p{c<7~n3u=w}oB`RPoPa@P;!>ZH*B&b9U43@@0 zT*Vi4X94=E_&~%eze=T+dB5LWG&|~Nrq8+Kef2C^sh(UBOK&bu=pi=d?3)#j+$86J z-8j4WDKvBUpb_leNt=2_tE=beS)P*K52?X7Zz{_9B&DV6vvP74$KSma<+O8?<|qFO zcLEdBaS_u7`w?u6|A9YYL3#)!P{bhZ&nk+bf`S5I+wP}9sKYtoG?=fh4rPk$NX2iB z(#C5^nNz)F#j#;WIC5f^(QsWFn1F5^Xw?!Mbc!p6guq1Li^1EEHjgn?yiXLx+Rj_v z$?|V~@llMayHi3qu|`dCSBMPz=R#JY#kK^52mv@zaNOe5FiT~+jD%%pD`^AO_jv%U zI&qZvpCg0+-$=PsmNGpX+JK1BQ;&Kl3s_-PF|zVPLPGVR+mCb(SY9zcUGwe9kc_g# zk^u_vW;J@x+xYMyIv5@vI|zz>zQo0C>IdG!N2q%~ZV`j@F(|_n-r@W+A8ZZC{{W5j zlBgeWTcRb_uu^eAQ>WJ4j!ld_we97N4MMsonTFsVajGaDJc3>T1qZ9-Ir>;wY)^sg z0y4^WzUqS)YkZ@p38vqP*LU5}(2xlexg7v3#8?y^QG9_g_l(ip$(_?b0KDnV)qy0C zmbiQ~#DdBrD*j*O&>;vWhD6bnJqxZDRvPkJK|u&*sq%*n%EOInzWFlli109P4p=l^eSlGYl-`p3c=54;7YacOlGp;iYQctzn-s>^(t zDs%u)00CvH8a;^fw2_!h3!RTnP67b*4B{_2T2*=Of1j7_^M8(B*u-~He`LdsAY3)a zW`!Jo^@2dztTqsacY=Kg6z-KR1VMb?ZX78n1p@a^2?+_NKH#jtCKn0=$Nw8}#KgD@ z;ig$m6%h-#vQ}D6|K^>;UMy-D(#W z=m{eS4s!_T8h+<!ATAF{>|dZK(kKsahB&N84^$+$e=3a3~V& z1OPyTt&ud>!&a0(0D&U>j6+_P*W7TXt(vFi9A`Q}b|!ESXvPW;hw_5gxo(0;fEs=0 zYnDa{1Z2z?&Jp0S0f}sQc=(YbU4C?sGAlFf4`^=o2~0lrRvlf4d3JQR7l@#NmWb$KV1f1}K>v6yM^`vq3VM=7{ z5XH?s)tGwnn0;DH((Z7jhQr)3V!StB5kN_fe53*b0$|Y?PakY-d;;Q$I(wu=IKKorIVeJdi9J z%~hsGL`H^(=H}Jx zoMUT0ayK_O9*;9daP6g?olpP+w9U@eyOVbah6U+Bh48Ek7UwdMYVejJWe1YEe))Mt z5N#WiE$!vI>sNE(cQo8}F+S?NG;JbyX`jcxy)Meuf$jIbwUrn_kU?5*U^O!KMbw_^ zM6VZ8Z1Bd|Z(=4!Trxy`i3~&cYmj}SLxe^QmkD2kW`KhFWTj2%%5j8BFTSz{UzAVn zy9EE2Tt$jSdP_@P+Aq&UdSPAdVnK_-w}+MGAQcUcSX8`~q8rACc(#JZol_dfALaPMRil{v@(ATbnCiEKj$Qn)oN*& ztkqCb_M*_L4o3EQ-~8=n^S*I?ExzEkN&4D1{ljXPX2m<)M`2`uq|=$JoWV%0m%wTH z34}UYLlZ!&SkR-Y#;$cvT1El@@|_&R0>*UFAOa`Sa}_1Xgx{X4<#j17i73glk zc>0AQt`8d%xoeb3CF1WLO;APhDH6Rp=}NA{(Vvs7$L$1D>G&m^9ZL?*VhPI zJaUBbdXib^VTv~7XjZvv$Az6Zi#p(Gnc@74RFtCgiW7*n6yv4VQ=h6yA0j|v6}JEt15=Y zdC(Wb@E{Tf_CDlr*fx_9DP(c{^a?nzOszOA0#8f;PV{cN>>0p(AqW*4TWYFEx76nz z==W1c3K*$&gCN2N%^TWqf~gnlF=`wU^@#7Z{nS2i{XMgYRF47Of+`uk!F3>FtbWEaH_-yv=~#u8UT zx{P4EeJ$v2j)>`w_X#|u1ud(bgcqC~U4{&zZx$rQ>;AK8jHE(*b)d1#{ZcPt(v;}K zrnk>IidZ^aA!$j3`(uALCk^u1Vf^AnziTVBCcloq_tfh2il_tdhdqTfnAfR7HiS&9 z>wEWt3^HX;Dc+)Oay*B@0}|796Z>(rdF)U^U0U{RJF)TlhZmiQ4+eIh=^j>#fB1a= z>yk7a{0JL=z4W){`~B?(8+p4ZQ~}N{yx7Ll&&bYA%0^&%1m>}}W|s+L8_u{JPdeUz zttTm{%`!a(j4xj}gr$Q6+v#fWTla*aaxUu`O>b_{Ij_=EBiPA$v8i#(4e|SwFqncY z(`I0vKmZq##1hZ~av`#X{-rYm!1nC#@5kGbxP|&WD$8Do~YvNCM92Bz$5M@2qeBWq^P4PEo35ADJ zq;vPz!W)D0L=(if2cB*lU(Ex)c*6PmlfRK~NkDCG5^(5U`eB0(;MdRQ|74;DY=m0u zA=01cNW;lkaU~`8{G2C5EFoc%p-XsA-emblN|IgF}tyE-s1a zkjT`w_D5}s6vj@$rKYf5c#3Ch`<(!NjZ_%B^9Se1&26>(6Fw93b4{R=t}*q?@X?pL z?}tMd)Z=OI>*hCMa5zr&AA4Y&jrI8jBip+9C4uW6_qXSvf^ne9U@Vh1t@Hle`{~V% z4YM)Pgm2#hZf%Pct$wrOi7f$7 zbvEU3L0-jUDz8mfJ^pchiiV&{1C;sYb=8_#t-EB@Xi;M&}(izU;`L?5gZ3lV$Uw-B=AEy|uhic*lYcuy8t&qRUUYbV@pmFf^uZg1bocZ&`VYGd5W ziv?(KEuDq!Mq`yM{fvw3xhTk-PhZO;@U<(FVK%-B4QrsG$tyM({^_)OeJ@w<(h9I>Vo>ucIP-E z(Rcp1u*a$!i)ra0LS&Z7qOIu*UW2&PSog%bW#)*ZY_C&dOcsl5JmNk%t!=DVw7e zP$7avZ;ZXb70ddo2;z^v!T3zG?;X%r3GrN9B<_wd8jy*|T{kAv5N-f~6CX-MeR(>? zbd4smlb9Iqke)%*pmiG4c>@X=+_Z*Q?W28+!mCsJw6kQgf>OZv%C-UDsb4~{?HU>zqRZO1)Kp+H& z(uRbD(5oj0f!tvDX0k^FG7ec-O$|>}VxrEoJ?E-q>u9#Ss1PJ!bXSipw#`fNlkIzV z^uW5A$-+C^sJ+Ml*tXvyTmxpR!QYK2iI=LVQJSNn0*7XYzpok_(zBf|k&?v78Jz{% z>K{X?EK;krlgD=K)E3-$d!_4-E-7#8QGO$uaLZF6!lz^m5m`12<#%9%9Hzt`M9p;y zQ1=aXMsw+2mvvkxsjY-)@E2x&PVXk-C)|DtdF1#x94srK%V9B)1OS2+=yRUQiQXgg3(7U>h*`^Df)S$X=?zqhx& zC~Hs1f~T;bYi$c(&CB*FG-%DxAwoWb?nv?|Se-%ZmVpHc9`8*V*2e2>>HeIIvKQ}A zMQ7~c4;!=;BDJ-%v_$n|1=ok)Ikc6EL&tFT4ENviHH2Tn5IkJy%Ll?|^IiZJ?^G__ z>7Rw7igZLs3?eF?Yq@GZ(}I6q`4P6p;>6j2u$1+~1_K04YRM$JV1iqd3mF&Xd z*%gvz2U^x7=IQ#~+Sn7LKTXl=DhsFKJVF20PLN*oTlBdn1wRLBS??p9oSt?9)b{;S z%STAbs_OHpTts>Z83S>zo}+|^>9)bHO^N%dMJec=Nf}_hXbD`n11H9ZYlY@vJ5890 z!|0y^qgI@sqg;}2eYJ@g&(bpK^iapamx9QTXY8u(owm7ayZ*IhUznv5W~z`yw-qr1FM1m(@0 zHD&hyoZIyc)xK*-y9U-c?x1;Kz`jH-1l&Ya0o#)STkCRaSj z*G!)3?^R~hcwMc7`5sRnFc6d44$?ny#-l+=Yy6n-l*hTQiPvS8yaA0&&J(OuJ54iE)(z23$4Nop?~n>S z(K0Rs=1|EeVf{<DcI3_3v6^0w)j2EXSZDEm*5c#z_ z*aZ;;sF2nBb^=QEDnYgw0i?nxfS%20{u_pu?|%h=P&dN;bo*^zB>-!alaoz{zU5<) z{Yegj$bYtCGYPY?mIHc}CRJV&P0 zS-(Cfrem?~bX-h|AB%!wchhV$<#6gJH7arAW@lF#Gb*w$`sDn)+?bq&j=YNbFRukh z_;Q~oTd-jui6Z+{!!RS_eJeLNmu1h;Fz@FD`h4_;<=>J09#rY(NFYJ06nesEY^cQF zRg6Vjb^F_15g&H3Jf~CGT&DJ-;yvnVSQ`h^$~&cTAOnQ)imkDqEnX~ z!Z0|jl%gI$SR4^Pdf#7(MN3L+W6ki(-WGz=J+%!d{Bwf$GvA^+7A(F__xI`L6#j=P`V^z?Jx3!5&=wA7&~js(a{ z2MjcRE#~})61?@n(4J=Z4=B6U>Bw`?K!O_17yr`4B?z0pupj^4eBuEIX<7GLR=~B? zVbyo+tzp*mn&y&|1lf>ktH=l*kI6ARbk->QZ)KPYhm4=>()%zv<9@NEu|a?ei~l^N zDPFn$i_!Htp`jweRP=Z=#NbZP_MY9XJ@AEc>b*&SGe4jW+*)TkF3 zO2nddc71h~4i@mU$x+~lMh-ggP*6ai z45XA-n1cf!#J{aX`ks`4?xtp?9u%nCC{cTyRmThE-lJN8G0cxr5Lbvw4Mt!aX63W=m z^Iz`}Pu3xjIJ-geC;}mH9Gjs;E{TMq;R$aea`gE=`xo48_B<1KwtvKo%{?9rxVrWZ zl|6$KZC5x<0VTWKB=T9wDamOfVn*yky0RT-&5_2fzsNiC$~73fP1!Xt$>+)^5j`Q_ z{4FPd;SaU^n^ccsAV;mtNqlWU;c0BV43tKPlLeP&QbqGjeyr#5!vIG|^0F@yfi|_rv4Pdk(n6^6LE% zyQp5uD8hyNqcV=a#{syGAFfk+RA+>SP05nC*lM>_*t1>>d9<0;PaKX;5RRXtiE1J{yds7ep&;X!&9@n0%( zsXeZN2Fs_0_o^>7tA{pTTY<@y@i`DQ6l6evz6sxlUA>O;+b{gN#BV{MVm^cj)ksOU zHd<=Deml_>&T953qQx;hs3fodd$LWm`JCPJ&ZsQUC=pCFN(80tzEl@~KvL24J|Nhe zt3&WQLK6ueup{QSd77t25BMGcd1)ISuF`+7xUtSj0&aMKAJ>k613Z0!bg$m8&m6bM z=`wS2GC--?yUD`%!OH^mpJjgt7OHK@k+Gk?i@(GrB>V&tbz^y|IbQ&&2OK-8ucB#V zkHk<5b!t_J!>ekK9v4{K%+-8kX}S=5Aj&}wwC&*Czd#{-xqDyx>2ug+j-~h*;{&DaDRSZ?SstXMnW5Z$!h%_IfO^{qQ-WMN0 zxE;NTdM+Us>1{fWxOIF~;(Vj@Yjd57n*kw@=ne_`5{gmRd`QbDbSw5oAV5XZaUbqr z#4c9_7_G7*eNh`{T7eq`1`W#TbKX;%*tnd|+SkEbBQrPg5>%8gtzejv5p|!m&CKwe z?(cosoX=POrD5lP>qfvyUEUaUJpS7)IYb`l#ov|q^aZySYfc?JMQFq)>8YX~e#ahx z>-K!2f-NiD;2i6GWMhSh!K%ETs*Zv)(7F{}RAESHe{;|E?xxRTJXbld8$eD0AbT>i zdkwJ906@TV+BQ+Bq>Aew&3gS;j#v!!f!5Z>XQx);v)mSFv@sAro*%>O;SZ?sbxu3# zh1mYBzQe-zI)KKV*%ldE`r{BVlF|Srduw4{p!b1%Yuk8A2vEVnY>gj5FhENOjfwGg zcp`%NAtG#Glif&pc$?93Jp8~!vkaB-FOT4KVHs9zGQ5w;4NsD+;`^3hm! zcJGI`swzK{RTMX?iB8U^P+AsKajm_Y&MeFiqd9#ex3KW4!Q-A~T%g2`^^=pqhR%kl zj&dU7AIBW`!}&m?)7+1lZ>GJAKEiq$+;QVISXO$f`}4eKhk|r#6)vPDVl*RrQ@cBV zJ_*^2^KchWiNkQxV)qo=jBZ z_S+aR@J%_M$mEPIuk}V>0J398*6U~I;`wUy51a%ez@~dhu1QMGFylt2q(lPl*eYP3 z5dfUHU}UvafwDvMO^J8Y`uZau4p3~B7Zemk;p5}5X)PmzDiuj44seiul)bQI~<%aZomvd3G^C`Fe`991x{6XioOtNoOMsHq*?WK>5G z%&f8>)xezhbPs_wGm-t-ubopn7lt|Km>xsc_{9_fT`w!XbL*M6U2C6|2eV_`cds1| zs42VeoVd{mD)M|mlKfhEbQL*zby%21Ls-tDKIjM15C1=L<&lf=@hZfLZWNw8e2C{c z@gC$(`_V-~hgC^`J#U1Kx<7OLS((IwWq&oVrb*)Svz0!}h;vTCFS4&T>V8G_QQ!Xs zkoG+i-hgdNMOF|la7`Uf!chytxYwkxz;GQy@3tM)Z2Z+JF{W=`&1(` zU%OztqmZp-oFu~276p9efS6p;4T(fJd#$&wC|DH0H3qbh3 zEV3SQoSAe3)E+F*3+`aAcki|+;^ih`kRvT8)GgJZ)vw-LVC`rMfTERE(kFxO+2c#R zuAQwGn{-`0fKVw7BEX&jMPEiip{hW9(ty8;|96OM`i__d_`G~+{x8w^A(5(T$l_E+8$Vf-U z#v=c$x|ueZD%NMI#+rBrYL+n>-^%h*Q4f}5e3M;YL=RjMu963q}vIqub4wu_UXPfqGO<-?zZ%4Ugek2D8cpk{myA#=5$7u>Exu}UE z|3)S4?Pc%9$_b{`YaOf>f%;sk_a$Y=s@7HFf*G<*JAbw<@xS$O%^6TjsA6+(X= zG`{-W%q1+y`S|_s>s}p_qtQMKH>M|8?k2kRR@1b>h)vjt`cD--on26|nAyc;m3NP= z!zuIQ$MYUCM*kIk=%`R+q%T@v($V$YpXYO=YaKH9k63jw1K-?`EQp6bcFQrFcP=Yh{9JS~Wn(x3$3k{_G!lkN09@G}c-d zP5Q-6dX4AF9tX9L<=vakJ)1M66Q-uK(^vRN^CycWd&U$KhVXGeDx`RsO>}YH0xgBH zpZzW}tEEZn!LuSUG^PCbgevK$+C7(Ci5HhY+}4AYI~hw^d`2}CL+bajUTCLGN7onL z6nWbp^W!g8M;x+{@uRLh6lupFHk{(?a(_hQhP8{OdsxR&fM~JezM_sX>tNwbd?U&A z5!aDo7rBA1zudZR`fVMC-*zhV6nBx20l&8BTP>^Ej*6yC%B^-p_#iL25A=-+82;)Q zdBuO~RYfFTA`iufestKdhjM#*+v=ok%#rB22d?AH^&GePB=P8w?=8s`ul5~|5j0)1 z*Hzso_{-f$#|Z=HR;3nwui_b^iM%_yhxJWdgrzyY@+hrb>Qylp#`zN2Lsa*)!20j%*F7UFIsIHXI1C24{|9rz<2;>`Vv?*+cLUo5^BybT}ClkR7$-L-u7jVWitMSv@z0zN7tL#dDsa|>cMbw<<{NA(NN8( zQ4F5%ZK5!lO3oXmYMmxFZ!#(A`He}o^L6Wvnd1XP-EE&k^9>iCH)X}j=%9+B;Ur_? zDC1Vh!04lsXR9J!*!4AI841>6Ok>|3|A@Z{>CaeklPLAg5t8wqf<}W0DO%t8o=;RS zpW+3kxYcgypy#6(HlsXBmY1rOBn@lXVutA{?7WRl4jGnmHqGHK_8%SEjY{3pJV~?< zo#5>EPrAQh7Vv7bsIC0075dP9@ zB(W|4d3>oIDAjqEi@2|k0+a1F1L$ieDFFg!oj(e$>#(3YU4`2H4T7$E?8MzOl|N+W z#f^eXPk+Y}v>*KVwsFSzWl!2Dm3u^x9W0AK!{SMonTEV!Z0B8V4j}|QNy{p%7aCBc zHlr{?%US!b0u)>o1}WOTF&=M zPrj94z0^TN;F!``Nz|UuFI#(#)|Pr04EaKNPHbn&Q5?!S#ggh1Z%y8$z(H0uhioY` z>!O4!#`Jyj+>S4W$eJUq2XB6CPGwV1HWS(GUxo2LdIaed@_bC1wzL|064tsrg#dX< zc&pF0dGQ=Wxu~nflOP(>w>gRJ{qaHfaRnC{P(GxxjV8> zWzCR)iO0NH6tN)fphTaPDw}JgRCr8zu{kxlPyDsCM25f))tS#7b9rI-q~+C~dUq}p zUB__bkYQ^n+7|B~mjsUdT1ZI*>${gdyjM8b-lycp{>)!5Q?D}5hc_8KX-uq>s_+F-GWQHTpqh#gIg zA2Cf@>?I;$cQ3<>&XoGEGirTwQNES$U~w?9IZ-&+!(!vHWCA5dryWsIsBUL(p)&{k zEes6hlV7jrM$h`leIzbcIwu);r9p;B9fAJTts~sY>BSFWa@@u5eXgugsJQ*HoP5kv zf0SPOG`+d|kR$?S>D(o^7g*(R?FV;bwcEo;wyub^-uxu6tahK<1Bc(1)s?9le;jwbAYtNm&;2%5lr^7bx=dG!; zJE{U~tYP8Ffu(T>aA&MtiTSI`FD_bnrJqX*EY#Q}&F`^bUdF<;;F#azyfr7ZgK|e> zSAY80tiG1AHa+c}u1CR*>OHbTB4z2tIheGl0DFo;H zmxX2JkB_bK>7U|0_Fspyp*Yifs&-cJQi8mT`v|(pPPiydt~hpwf+1*#-|vQq=2!}& z8wXk6asDn{d-R!QYpA{3VCz+IumRz~6&j0UbU5%p>E^Sp^-ReW*A?Ok zwcF7o`z6SX?lR9;I_kvW>BV{;k%tN0Rl8#d|Dk}s@>E2&8=J2atn83iA6C7*_J?~e ztal=pUwti#N*OV-=M?~^{evu8349B0ztdHlmMJ)7ULxpdZ_Gis2g*t~1Qi#gS6=&!3NXNDU zE}CsWf5_6Bb2R3!;G>K!e7bvd7XbUE?s@u}+?$!9XZ=>gc4sIu=Tlt;%jO(_$r2`5 zrtaH_6EF>YJFCi}JG(z7gK7!7oaeQRv^(m_ZWx?e9;UBIzKyT1oQJL3WK~!w{B_XY z?89E}O=`bf_WOxFOI!;#%W~`6?Si?E)Q9CacU?`oSV?hkeXJZeEkZy;AzmKQ(Wh@wxm05@%Jm+>k~=WNR#aRo9RhMj5Yi(%bSBf*FBF5ZN34&M0qvHmXpKq?>U0S3oh=$_YHQ1m``zo*TkN(|ms@%tt{?e^_~3bjo`3%)5&l?0 z-mCh?-Lip|D!2;np+%?3_0owe%cgMbmM{{{rp9AcXn)Jv;j}3)JZs7%@)g7suAH>K zg(z=^N)pDkQtJ_G^DaQaV^rQ`!^2mDt^A6na2m-^R5IJ8Ff>~VFfvJKcb zYNV3p6NM7D5)3$42P8HI3T1K<)iuYfHgCHr32t*Fk66ZFD+6f6ve}+rS8u!Dk`_v} zLCcSk<2}s%S18qN`eO}!K2R_&hW+I05zq4Lg4rVHAOCydJu%A$mIHt_XK|o)@X5c6 zG*sN6V>Nrts7Y{C6>h?#QFX79E+OE0ncjp8!QY^Ufh7%evu5A5;ZF*b4SkSMH{cpm z(|m`I6}bdB_|SuWy`Hs&>2E&WudIA)`rGM7L4=kj^>-^coz27bYj_n*E=$vA_sjhEUk%`NIM9Fs7q)9`Fc`OGaCDlmnRXh zuh1dp!v@TIUzLvDBE96UFpNM&J`&F_XUzZ8&-hwgJ_-d|*e$7)mAT+9qfRE%U#zT| zf9xqFV7hK0o6)i~mrfZR%a{#$8a^T^>$oN!sB+tU^C=8Q%*dmk8D8KlEWyA$f7I8z z^RUUN&E-LX0uE3wwDD!`Pm+)8!VKYlo_v1I$RdxW|KO_ch<5{f2M8K3oQ6je*9(1tC2;P zEG47P@2wk-#WUYgPgo4vju;`gG&B3cW(Txu>2l6iOXcK#*eQR2O5C~El4B(#MER=I zdEEt72xHu4#@&&tuA0x8$)wGF{Aa4*{aGOwNjmsAprEAmG}X1g>h4B?9>R3ixui{^ z1nQlgGxZ^(k)He7+w0h*m2v95f~X8D{^>uXrNb!&f$~H~Z=6BF=;#Z^2u-C`qET(uIyygq@kWXlB&mhqf!Msqb zv{RvUfjqh>KiWHS<;!r7>V90`aW#-v}-BLVaXRvffREsY`M}>azOOcotcq zDEeZ(?6p?8@RF+w*mu5R2vm65cbf0^UoXDy_NM>PL+HqjgjnxPYA$0lPyLv-0}pH3 zw;qz@>nrG2Q+Jh~$Rnw%ne*9b>X?3yk9@)&G2`z3ek3E10)mC(yv{)o>?z~pQ!1VN z4{Bq&jqnt0(&f8M8^Je-c z`#?&q1-7w+AJJ{0i7-CKohM{2N2sBzjZy?+t7o=G!o$Av%#Z^lN3vPveRVG-WWIA3 zyOUt*lCGf2%}7$42^HTv1Eg^t>nh)N8U~0(VG$5K6vIK(KwxOo8Fs0ZJl~FM-z$9_zGm)RjE#cx#8tpr>u-n$DQLvog*B2#JN4eS7Sdp0RcfMXrEMo<_472yjs3^Vr3wi{mG>y z|AXK2IH_RJNizmw{DH;Y?4Lhz0Q0jBF0o2uX zPOB{Lds+Y+t2M&Z%}}E694}Oz0lIF|nmDN!gglOvfNk#w_1)hw6he#P0=7N?Ze;Pf zu*D}QKPZ1XqQt}!weu%*90&a6Y_g=F^>jN-HSoug|-v;#57$G7fumX14 zk*xF1{Y)i_nSu({1Yu%z+j*&9mFU+bqe-p)E>_Eb`0%0b@!>W(Gc!|l|E=p5^!A`J z#_x8&cK`i_90)poBA$W4hiLHxm(SzLi8H|bpMeTbHz2ZEErv+NBqeKw6`%ccfUSts z;M4yZFjca^0*O(hq^+O1H4t$oAx%lsgUb6-C{C(s9BpBsN~HwcQ-N5B`!1o+ClK@fUP6eV#7tROu9 zh7dd{n6}QnG0#8$^TM%-;_Sjt2XTcc@|gk*%mFF2W;Pbt={fkMeM02&{J9v5+tN*9 zYs$cw1B|PP9xbOF-D{Mij zRY5!!*w%%2c8WD_{sz7x0F4{$A>y(n^uE~Z+q2tUXygXO?=Q%hTnGSSCYqSIxbOkP zYX$+am*qfMby@@59*jUu)_phtfO{?Ah+DjY11=(;A|hOhN=vu4ERpM!LjR`)aNV6m z2OchO_Ln}7TXVMDoyhJjwJxppZ~?(Gkl=idk3R-$9Kcz|S2yb>S-ZbO3=kdJp;(Ym z$m_MVOq*?&7>Z%BBEi4*^2gZH2omjCf!2!WeW`amXu5|R9KWN!# zt^&2xyjQeP3Eq6cE$r|Wa4NBh%GT3r^u4CpZ-n4et))o(d#zfxhh{=UjT%CqDD}mQZ6+J1;wo1&JVLR~PifQ~@OVZe-^2@k*w3)m zfNs?jUJSbB-l>XVc+Z~)Z48-~kLO5YeiEb3KiIa^;S5=K$r|P}ocBtG}RZ@!WI4xFVKx``%Rsg;d^C`bZfW<;$O3Kb+6%D2;LxLw5 z$e^Y@`E9e_^O)KIVEIiCH@g6lup4pFmn8(bwC*s3rWFnB&{QImT9=`K%QIfd7Sf9^ z^jfC{^lA(8JTYN+@ZuQ)FfIr8)A&{}a(ct#Xj1EFsUf6G_nZ+He3gg4V9y|q%shE8 zQV`0dk*x?>{0&jmk9v?fbi|VTR{A|R^VaLrrAyWD7nf|v=7FaV!b%0PBZMuCVq{f! zg;Rn|h*~%%ALThew@oZD)fw*Z`(pzZZHwmX(}*5S{H65;=wsVlJtVkx;3zU)vJzwG zYTQZ`PE6S#1g6c*-W698Ns067mlg?tJm z?J^syU(f0&J0{44a4-2*ikpkis46ReKtRP`29u0Ef!jM+T%EHBW>GaQ^t&~kJZ@yA z+%G5NvhSn@F@hBi7xw-nfq@<5c9fHW+s4;D%`$XtrI^Ni9C9Qk9eJXeN%cE1y}N@s zV5oLU_){d@ef!7~q>0~&>{f3jG{7PKH|GWMFmnjlD`U2?5wF>-YIuLRKO^a@Rcc2aiJg|6e}4b2pyJbC?5U`@{}FPg z73m~Lm=>zromV+TX0yiy18u@V@CPPV9;9I(+ovy(kbo&yh3D~#2CDyfBN%BYmSZ#hGaFuAX654Pe4nu^s>3&g!@~uv_u6n7LPN^&|U>beyVnb4b%X$de zfLqq>o_0JiZ_gQF_V8`XcetLCTMSpGz?h5O>9ueq z=@l92Aal1^$|_rIm2`{;A-C$a#<3!ZPaVyN9w^K?Y_o3%FMjJ%#RS% zzB|)hJiw$1=E${sK#~L#Z7kO|sYyD~(c4+0BhlqmIAbZ~uhahF`#iZnMQyFDPJRjc z&HBGX;)cJqDc_3g*qh;{BSR1xpcb_`UfX}Qm)`SWZ2ZoxbX;@_1djTijYxuC_0jKZ zuy97BlW=*i&kq6FqCG_p)3Bq}vx7-@>@YDbl(}y7MZg$#ZI6*B6aKLUIPuk1PK*%; zakI0(WH4;>ZC<*CY$ku($ICZA3GP@<&qr1-j<>JwLYi%*Vm@o^2|QTe^3|Y(j7_aAb5VLn0f4Oh)nhU6$jiu+bxCFHkmBJbg1-r zgPYun7}Z};QC2?M%F!bv{>|sGfWk7y^C|lqtakiMm?Vb@lM-WJF&u)>f=qvFp6&{h z-pr|^fKnEEw$K$er2DUrlBo0j@#rFk0gh%5gxbF9{Y3BO`1%H;K>ZNVBV}h<8zG#qT zH6aK$b)6_f4qb+#A}f+$d`&9$#UZ+Syw7xd;a3}OY|oG5QSw~9&~m69-VMiM$D+sw zTvj7;GH{4XmGOs(UbmWPUJw_Y%bY%N)A5H%>mStm>=E1X{@yu>Q%(p>Px2Sb%_D>s zUMNNeC^oU(A-Qnx?LS&BVD3b42fx^ zWQ5Z&wiprJdSr13;LRIBr8eMNkC5TTx+(n!(D{vjsk!b5v^5P6$1L^zW@F}Pzz>UI z?i6(H6&1neHm5%1UB{Qg%Sb)0yI?Q*6D zdyV~AoGmF%&uwR%K4nS|!a}6XaQIJ`OWn)Vi^sCR72)G0aPs&G##`w9%s^h?e1lUf zM`pLky}jnuvf0)r(c^UyH}`ezL|%gPH=l3)`}o2bQrV{|=dFFmqbdkiIC}4lRc!07Y*96@_6xw+PPddEd6u6Gdc$NE0Ll*Ti zaPZ`9+UX6Q8!Z$8vV&S0*_ej7>*%7$CPUWnJz)62-$C#4xri?{v0W0f8FG?`L|qd* z4vqOrdyA~&T;4|?a`3Z1OqPy0_qGdjw@gi$u0j}V$-m*i3?_fzQD=k-N33EBObq!s zk6gF}4zL^dMb}5Z;$O0WQw&sL{!rW`zjA;H^buCsf_ZpbwOvf(GEtq zSIpDy%9@MITO-G={iniL>_@_GiDC1yJAv)ozSeT)=aNT8j{HXByGpU6Sjb=mP7C;J zOQfj34O(nqxqL7?G?}_BW6v4%Zf?N9OBz*ndPSy<#ogRyeayYd+%>MYsRyUIfIx|mjK(&rOc*5z87b01DLJrBSB>@J9XZrh!Y`R z5V>|-FQf8i^ZVFPAFQwhqd*TPZuqNPYQE9qQ#1&UQ%9_pRBXWW{Z+?~X{wT@Z^S}& zvxCEV`p!FikgR}1PtYJ9tvrdv4iT>|nvr=t8K`$L zXX9!;P3BH0?CW$MvVJ?ozbX97btrf&q8DJyz_d(qF|n;w?_TP~yHZ?M5=b!{iKgZ- z4e^r}y}?;>TE)6?*e#((X*O7PU}@Uf$gSdi9=h?(C(>s-`~BMqqnqB>!>+wS;MxpQ zt+T&x4`Erb3)uU*`hnbml@QHtg>XNt@g3Yy{S+J~0Plf9@uTLgl47pP-z38(L(E#y zEaKXz#x0Ft6>6@PxMT|*+TVSIB=APTT}7^t)ExqzO+HBG%-%&g<0dhiXK#mW&we?I zzoVn6S}tXw5#uOB^f!eiEU`#hDdo3$+wBaUnD--qL0l6aJS3A1vR9rId z`FxGuj@gX`8U+pVP1xz7F(3FluT#!{LMeM;1KVuP_0={vje1rzbp*lZZQ8T;b+iX$2frGG> z7al16W=(NFx-j$fQk)(%heeTY_|{a8blj%gwjL^lYZk|&9ZaFKzohfNy51bi^t?u` z9bLr{k&^vJ^iLhsYSgva#lU*OR%hJ-t>J>^zM1vIz(!s!ENiTkIpD*7yoKF zCFIv;CQ>aSG~r?gLA%v|V|`ZW0h>+LKnL%YCK&T}L^SFJu6l#;Bw?h@KkuS-zsE z=k=SlWx7nU<8R{2_=V*nZVe;CSFd6@oiVM$5n!9rv6 z0y<;s-3cnVY+c#6*E$w6zDh}9oQkZUEl^{q-GPEz&)cYt_wJ7(7G=!VAJJ@}e_iX0I zL&UK4IMt{kE8E~t@@UZ2@|I|Cp_LRf{qyUUo3D*dhKC_X@p{+MXWW?ckwIRmlz7)! z9=%ea-DeYg+YQSy_%eBR9p<&7|1&Tsj;`FtmIh+z_Czx=at3-loetp*a+qrQ4*o=| zvgG!|ZJ0&93lR_9I09P+IF{V}6l@_(MRdJxLU#0n;r+_5`~CMJn-g5$p(oha)FLCE ziCYO$A%b<)Hlor&4DzosW&}P@Su#SPNmF>`Z+%h@vbVP85XPR9XXtKO?u4O&?z4S| z1+U4~REizH|C!h+L(a&jG#Vtw<^J5)eurG4J;tyw2E4jMFv9uDt6RUBkEe8pQ)BcU zck1#R=6hxHW$Ffmuu@VO)<|!WkP@4Fe#T$GLC|#2xdgbA-1a6ikv!}dT~=eUb2@Rh znGmDSBa{6?6^xg%RrRRxR)Y{?lFI~Yv*0Ow>wolZ?xiaRtRaZ6A05Yib1^0Cjv{UI zc8fp&c{^y8=8f>aW8<1D8NL4O31w5rw`nkDWRxZ>gA*<-e;Yt*D~HgkSSO5$E9K)CeKl#q}}O}&2*kusLaq-c#2I zu<`k*H-#V^sEXteIAR1fL&uC$``8Q9Q8J4R59>-UNbFI16}5EVfuH|y5RuDv)_QMH z?B-8Kk}rJvB3lX`)Z7~so3Jk*n?f(Yjvld1jjNd~SsZ#EGUcA9)Im)+31;)3t6HUSG=OcuYSXy3yl zd2@AT3WL%LG1d3M|IJ>X7dfU!UpQ?JAp^x~_ji>o7w0-I_UF|BcQ85Wjbn@fS1=E? z3+4tGUj<02-@1QQHP%KHM#IA^m}#16dRj z9Hsl~edo&J^Jl7A+h`E^=XN8_K9@tI{p^;A-CpjLHJY{vqd%K7dnh0mhf9b1Z>HUj zmfv-Da=c00VFJc4%V~{zslZ1TOI=-^{6Kxq{dh$jl#Mq}DCdDkMibwCPH77_cw`LF zKKiWBgLbOeM}}1Ut?zZw2)#pG@(uLN%oH7IK0$7Xl!)cQF8*Bw)F!XVp=RXiCTXX7 zNQ2z%d_4~&krn3(XGjpo3y~AD#D1X+U0e0#JLiCb)+x*Wf* z_AOjqGR?h6j~1DU>;|{{oc+*M`0yu(y2=14$=$G`kl%8?uD0Yz;5r0p9?QoeemK+Y zsKeDCbS<*kP)SMmoS818!?g?x_~RdBC~-x|=V6N2R2dY(R?1MGxb0@(YtUEh9IrK~ z@e#UxT>y>!__+d^X8wv;odV-xetXd=W}NL@ zlS#|V1DB&fy*Cc$E=adNH5#$4P57@~y*dxtxYT=aniPfXY1q{qeH=V-(6nqMf?}g< zlfE=~aFS7ip8KKEg}bK&V4jBsN>N(j3a_W-C?#)~*LnJ3wVgFW#v1rds|8BGU7vsc zwVqCe&DBKbVl$dGsy=6zs_jNhEK2rWL^YN{Bo0FLydKxHP}4xusG6VBmj8~H3Wy$o zP-=CQc!v@%#b60V87f(6efE{(dCwFFye~r~dqu!ZW7|&;Z9jq73{{79(E~r+aE#~( z1D71^!wVF1NS69!o285>N}(YnueCDrGR3=?u5sbT;}Np!-o#Rxx2&#iP*Ia@u=(`}Vg?;jK2toL=`g^q&@ z^&MGo<6maG?@mf=m)S<-q1qx&Msii7+9uh}8QSrubwT`F>}b}<>s>aR3{2YN&dyvd zIf%!He_5f{I4ljVuC8jkAf36mxXhUvUnb_MF;v)0y%7ZPp7}8BOrr<$rTHK(7zMzi zxh(xr1{h4JsHy_Xy*3S@+Fw1D0gZtRjE~rzgd{_}LcSqfsCA~9;sIz2;ownV!?^04R>3O7#A`z5&+deAP4RcJ{#FiEI( z)gOkdQ-h1MI}=)S{_eGteXxqA6;J`Q(7*VgF*T_N_A0T4srEm}a9-~QuXCpv0UfGH zZm~oXv?UhVZ(!eztI}Ye)A(VI|8bmE!*f;vn&5()E-x`MW9oiXoLgr%W4(C)kq9Fu z_eYUsm4d2j2-v6guC-_L8{5X`F7V4>TMN9)%ByQ5h43DAsgU0PWh`#(^0w=UVwTi+ z-LY*rrDcbCFpBr6b8k@`AYJgIB7=ARaMPxi%%rX0?>%vNCWYXHwIBMklb(TBG|6Rp zA0Yt<4Ly?D2t1b*3Raa%WuQ1k`(H!QzEGz*g#-v%cs(#~R^GD|;{Fu$!{TuuKP3~G zoqw~Io20cZNijhnieyx@t4sj|SCtNGlc$@;%DP@sWD+>Bu)7V&(@xJ!top8o8Z1;etwTUNGE| zmH?`_B@g+P8HG^83F8aD)<|{pxlDvY^~v}5IWE(xw_~2d`32qRgra5JwQ!KScIZx^ z-da8>0ynX;;|`C1lLbTLWjt>o_`W>FG~HMDbwVE4Y)p`cYYRLT<)dUjoqvOqlNM>xHt zU2LHIZxTST4^&A9gL29QjwONfC)aU|6Uasxi)tz;MG%H8kLJp1wfOR8vYH?^sw@F2 zG#XTXfsv6@>13q`OD#8m>Q;eG-&Zy>6jgd$jJa0{G6051uMHVj4GGC$JX^pyIn{N@ z8dmYDwy-dr7=Hy+=%h$c;OasFrie?<3R!w+EmNY!?CTEmRI{7!k6aTJL)WsA6{e6W z7#`HN?N`jd8)j+SKTvI8Z`!{Tbu6)b3t6@t;nFJ-MCyiSljVc6{mRdg);kBIC%oqG z+*lb+4jYlMs6MtuP>GqF*YZ4aw;ZPYcSB9&uUHcHmg8Jnlh0aKK3ef5q`bF8KUg|) zta2pDSYnS}n%iaK0&}|>LyLP#E^LjN+#l)Dg*tnamXK(D>lqpqp_P*TiZ1- zgB5bcw!2Ot5OJ-1iIBOV_pfd2=e#~tLAs$s%9HWs;bdYmlDfD;OCCJy;W3r_bE1@3 z94O9nla$s6&oz~`g9MNiPr%<_mbTN4$MyRG>A1+m4|+555j}qxhGD3J>jM8(7g&9U z(Ayt0ck300yrDxnhrxmv1$GzyeA+SojlfSHTHOr&1n?OiWQQ*gD3B_^a5MGaTvVsf zQdbuSWi>mtTWd4nOgKm7^|j~K*mg$}jlrD3L4OrtK?YmLCgaA4-pO-YBUD!(EcDHd zHYLMu%l!WRyBrv|l2cH`0Pz5D-w>n5hKGgWAVybXz_Yft24>k{U+~o&X~>j~2&Db( z*^gOQf8}xdcKsE&S#H$S%&j@sd!>RzjoFt8GJ|tGn;4gsW*o$&vs{v3%Ylo60GiZP zN&Utg#KypCf5JLjqxc#yR9PM@Su?Y-|8MA!Oh?Q=5(Qksp?Rb*RhVKi>Z7;BIm8B95bMqS^F zNy8`K(|*^zuKd!yrQe#j-m^@1v&OY%kD}?P0~-Mg6>M&{(oRt}Yk{Lr?Pker?w12b ziGlbJ5L}gz)`^;(U;K?dKZa`kd3*2Vx$P{iZIqn2)E=xtvNUXz)pNwebMJ?v z_^S8oNjBBh>3u2jxzQ+Q-*THY*-36ZqnhG~!QZ0>b-Lb(Z4M>0tdW9`kAvJfV+4jQ z(ju$vIM<)BkBB&Wn`{dTphF5WISi>p!&YJ1hpGYB(iQe zrYg~MIE-z(YRtXB3G+(TDRr;Q+>aTtbiHoau?PU6FkilW$pX@sgoFg(^baIDmhA1A zS^KTr;|6kXJ+~rdY1#HDcB^E2ZYEYd5SO{;5F;xnwFp?45&x*&FxD1)*|~fj5rlcj zL56wmLjcQdEeWLlt0G;jdIdZmWhX2aF#N~oKG)A%XWbsdP*h?F#%b8Cz~25n$Z*g? zcpFeVGyFVq9_s8y#esKrXN*9W z&}83?zJ8wiE3g^%nXWKxxpp!Up~9i?8HpcGXfK$^IA1;{#tsW66!^w`(Bu_3VPoI3 z)U#*MQ;_YabuSkl5S2w-afzmX8kajOBLfA(-aRx&P}+tx}8frs8Iq9R*NFj@GY3u!jc3x=+tYN_E{H-V zksJYM>w9IjfG1D79c^=>~CKslUR5xOE(E4gRLljMJg8Hwr$3AYVpR z&pwnHIIxwzi+bMm*6Tj?0ci*qZdQX`K_K2~IbXxPC}Qdv@x@7%tDgEq~oJ%oz4yVp-sp#Hc`PG`7J z1=YGXMV#P8s+?&zZ1#b|dLAAym&dsLSc3g%>3D_&eW*NG^%2xE^2gFx@}b%F>DNb& z3|~*E*WMdvE-t-cbsW+wMv5hg;yJk|;AybtjUfO0=_?h@->FxDyA#A~bQH!GwH$J| zpOHLRrmoAoczYVWDv69_y41nM_L}G#oU*hU4U6SA~ho-)yV}nd5xrWcBw!=U? z=J`KZRrB?lssw+87dbFVe}8xw@Hx)8#%Td3PU=%Pfj${)dv zslm154lF$E?w>9Zb#gC_gKpe|=JWq5O6+v)F(PuNS>Vp+KwRp*IY%tZwjZy32(;_}hvNne8arV{0L)XvADP6fE8qaPsDWFFe z$zeT0($3iF!#xDz|Cv&5|Af+L^KECvw|y;dQ~R9F;vmJ~j#KxG!;ql|uFn^L1;w88{+IF#QKkCIeh9Zh%KX|>l7vvv#{AtUt2LW09$nmC%HD(%S0rNsg@S z6pff^ZC7z{gS*}yG2({@6;T}6rlj$4 zMLZ&w*ZnoO0TrDuh=EwRp-A@mJQkilU04~KD>}!sKN*Pd{kXr7MB42tc!2Tp14C7Vy;0a@i{|>}a2udGe*T}Qkv%s5Nc_D>jc)M1XRBSlMjsA)@AjsvG z-A%2*dar*0`bg@9rIX_^TABdhm+gfx-}PjKCKZ!MnntDMuwh01KEnm>gyJ(MLjp+? zC1ZynzJWQxSciU{XG2HrliE$D?jtt$Af8D3vgZl(U*) z4e!hQ;r4jX%`uAWM6%Gjob8`EA1~R3%5PKY{q3z*6a9S8yUCh5-zmERVNy+-XRYX0p`-mUWsx}1bW&A<8bjaN5I7h3wyP3E(Z0tR!)z%B~Y#O`Ge z*zjYC%r;dA$4e8)xi&)1EXVDFy_ z87SAM*eh#y@kld*Yv3C~x7)QfXL+dfrerQWvubccjrjDbZNA=x2-0-DkqQJVK;66c z2MDa9bRC-U+}zx*jyf>s=98>}d1%;kI=1XT=cJFF-|OnWQt&vo%`H4BR|h)ZvjVsA z(9GB7z15t+wYv=nTwowi9e+=dS6F=cj()k$Muj1jlZq^o_wu5oAZ{h68ty8rO35d6 z({8b;zK?nf(nk0kRtgTwqT*%=G6^FEYsAYYnC{XtQHbH)_Q|3{;u@o5y5IKs@guN0RK zQ~DEMC4?gI{R-A(4rVY0Ea^s%Xs(!*H^Y})@jnbUR2Oj_%>1y~3qGPR5~mj=^;OaB ztAsq6KK~x5mf)9H)rHGx->|_mIXdN#VE|Na;z z&k-r)leowyT1^G-ZyLJ;uWnzcu!{ZazC@myuv*?L*WN5}Y`VH4MTF3rC1{=f{cVm} z&x#1v#&4>gEWV~HTdv+}69uvHhG4~_?7F|z=xCO77+tGc*RlfPCWRRyf{!KQm&oUt!=6qk*$~zX*w_iE|x=wTsupi5zKsA z6vu$0lBp)t#c=J;^K)v_u?ldk=jGW%?4EuPd92iGCTuH)yw2aIg}Lh3f6mpB9TRaG z<6pnp@!7!4a4Jj0@uz3)*sV318%7YW=KD27a79RpD3tQ69(y~XPpYg+Xmt!5ZYp(X z_t*6sjkGrLG{^BZh*+K30@FPIuP0oiNjW%~8qOc-&vQsHH7oTEhKShGyTOAXv4gq2 zdsF`hdG4ReU%ZK536(i-2Yu@=c*bwM_d*KKelXEliXNxEr~NfC1aJAP84+*~`xTLH zfT2i_3^{@-I6#NmZ4rH{h{^O&i8#QP-1wrWMfBC11&0A%B|V+66_s1|ccl9{DqiL_ zi5fW_T?4-PvurRvn`5<^dCN$k3zhR9U@?673D`7pfOo(bxUe1eEFeZ;Zyr@>C_OEaS3CGJwAi~9Ct4CojrEWVKJy3p{4%E!%`*A*p%MdJ) zwEvi54&8vEQ^>q)N`)AVBPKWckyuXh5)+{u9CZdpuq6U4uI!8IdZ5!*skmAPI&HGW zZm;To=5ulXLS|^O(NP$Xu_SZs8%D_l!sYY*g>L&F<3IZJ@@_^}@Iu^S32iI2(T(so z?`&l+JL2vsaLHk@1aH>M>EPQ_dc?DL><2XI0^2$;>43t-Za%C&pTSIV^cPi3N( zqD1ka^$r^=qS=s3*smC>3>=sF_|?#?tv7_emo#toNk#&sYy@g0AYPCfk`I~q?!PYb z+^>B5Dh&l|k5)OonKszUiGVyUIx)G(Ia!LnvnaFHsZFh5UX`6~7Ny%0fkzhhs*JdB z7_*;%|J#XsCODn7|HF#^$5T2q~Gib0UV2TF-*FAf~GB5*OtKwx-h%C(Fd6*4};#huNh)u-xb(!sz5Y?5w-I z|5WF&JxY)O`LcKbc&pgSsSOvE|Ck^>QMk*0RH(tRHbnon_P|uQhGO{={a=V@|M~yE zTQ4($hBchk6ZbE9aS`@EibyZlas&3?d#~yIhYb94pMP%j-2O+f^s0xea6iqo;01q} z{f`Y=V-SC8EdKLLOtJm@HrF0!8c(kZif$iQ57}qng8fw0aFyRViYo8IGEA2GGwD>> zPwX7p=!fH1qkJA1ln#WdD_2aM*j2lgcI6((7SrRGTH=YDEMVc8VS-c(vyF@;3U+C_ z4pU4yLc`%68cg=fMVBFqpK?e38@_^&*$)eNQuzKC5C{Z1Nd*H7zPx$G&dxqV#lZ;v z%urQ*B3Und1+s?0cZ!Q255PT^Z)pT(V8A`eGFi>DzGr_%l(C-D|NE5SwY|OV2OjMs zBeN^~+N}GliphYGW~okfUh^sCHPAG~lZjLU8tO9{Y)gK_&9H&Jz5P#7VG?vgmSriE z0s75(rA@s?cCEjTbqu&D382AU`Yg1Ab3e^I{k!^SL64z{YHob+tA@cNLm-xPCUVi= z`)Sh|x1rH;w9??->DU@U!jxG+>r*x~IN0nmn8Hb$&c|C50UQl!-v*nzonN`nTG1iE z!rVYz13~`FD**xhY$f`cY^j|aAs>AKL9spHJar2~6W13(O_jB}x_Zu9S6R{k`a6ns zSh`_`xAuD_EcgtTfKCzu5e6tlbljPRv?w2+I$dyl?BQ)uNeQWzwzl>>=;;>&RK{z( z7Nk37+Ep89j#v7WVh~kG(1iZrhP$;@ws%i2DjKV<;n&RVzpbm4MY8P3`=Q%ym7ne| zWl8=%?Af?7eG+lZx5R) zGXfs2zuOlRaahKJR)?Cha@+t*%DB3}N0bxad2boV@z$_>tHH#xvg`IO^^L%Ip~+F^ zo1F)O3nvQZ!{+py`3K&Wapn!`Ee+K9e>+_unokn-NcvZVyt<{Oi$vlVY^1mV3 zqM-*BzSk!Sb3XU`W}Sb~8xH0JxVj|C~km2wB?mQjyU zWS^4hrlhFLI3UFI0&eG);(ry!dl{@)t8CiGY19UVLOYct(rfXrjwc*Q@@|Mm8s-E9JxI|_sUIjKrfY4=}=+oyoy^;dDw78+A{ zD=)v`x?oqk;JTimxf4QQP|*5!WNj#B>HffD2ORx;_*pOnqKG+VK-f)ohWE}ZCg86M zlA;n{08zm9AAR>3vsMM|0@S|W$c&yNb9uV%`i3mOhMCpQnM3MCPibV#2dm-ti?pJ$;-IhxcYHC!Q?O|9BO1 z@JN5Q)#Y#gb3sm|!^*tpG&{tA=y}|`ZF%vEn_DyBy5I2ZYBgrJASYVI+k0gN3mlNd zY7LJCH_b{Hkb1H6qw&DHO1Fr{`|_X^1SeUZto3;V_Hpq3a>)S%Qtv7f5Si2^fyG59 zB!J^-O}eqVr_0#1x;fj9vUh!L*rL~ZyKtzcq_lhhI^;~+KflYzW0LWyiHnQxW7vb3 zC7n9Q>?eys;NaadQcn}jBLX~$R|MtqtN>1Zn z!KNR}6ToZ+g0e1T?9m#(>`t>TxqD_rC^B(ceHbtN$pKt22f#Aom)m>L06h^HGS^Ks-S2oES(1SPNs=b!M&lAjx;H)!X z8<|=Zc;Pn4qy&Lv_5ZU{>zGFNeRlowA`0X{A|N0{+1~-Vpw-pU--B?*AC9!Nv<-Vd z`{zF(k#9xwpGZw5iuERF8Wf6R@P5~46}&s@Am+AD!{AwlfYn!+F3m9zK$ra=PeGvS zh`{AMjWl311&Z_|T$Q_d?j83u)1BEbu0&fjyi=BlRNYd>6omx9mY}zqD4+Bs@ZbYV9Ii0M(|r=1J?_zlXo&$ zuF z4B@YI?iuV6Kq}bdHKsRLd+_Ed`HFsK{N_58fjNQ$sRhfMnpOu(`{!z70Lc+#n%SeO zYirGd$g7zWkp5-7?{W~e^GhTs?;d~QMRqH2bp9glixeQY)i`Uu-$u)u_I>tKha`S% zk$s@HRz@C{hGvF!oo7)-;EsbONU37EB)f}iW>`8hSJi&2b)sRl} z6}M#|>(M2R5vB8K<1!3Zk4q5AT$+%gG3zu`dR<$7-5?et0^KPnzL>IdP%@iinDu6w zQ?p=(XI;li8h7%~T{3w&6(y^M?E~S0bnnSfU+8&8^6-8@MfJNu@oxn2ECvTEa!cjy z!Y7Xu-(p$R5vK@{gzw{{ zW?15-e-XD^=Mh?&f1Lylo8?;9;%v#T?hYmh#gKKO6L=)HzAUs!0zEKWIcSA`u-qHN<-^6xUt> zNe%LQYrUf$cTnosL(>#O0g!z`Hw^_6j)1>BYaU)_Tw-;SxUu*K6yHohIuOsw!3h($(;Xeymm|#} zVY!5Fa^ug1tgYg`>z=x3$qIi>^ZReU%#YE^c6SACT+vJ_-SfrgWM|Li7ZmqUA7LvU zAGjYqKRsC+B^nlhuHl^jbvTn>SzV?y6LAGcqxyR`I9^H|;(UvaB^& z$AG+hBLlvy@>{g@Owug^U_Jp`jUq0Okvi;sR0E>Oaqb2Re8?CP8nj2n;;aIU)py?X zPSBfI@z=FaSU@pdEyO7CiHW(q8QwOjSGOT1>xVUpofxW-fIXNtsrKPJRlw*-eGSHs z=>80p|M+=%RjTn}VG)1;E>NMAt{ViBu4;xsz?SYalbizT8&}O=%YPLp|CJUan!fth znti#zHhLV7>H&d+RVERu-9)1k?eTqyG2-(&|1YX4O!gp!Oy#)V}O22j%TX#Uu zj^NFAmRy4BG@X@*U?6K}QqZ+Z){h5N4TOvHp0&)f;X%iy{HE$X=-QA1QiaYnzY?5! znB_%8wBc5kv7ztt=iLK#G)0yg(1iQpB-h~!iK(fAsIMIzmJ4a4f9*S;V3YbSk0RV3 zd#Agw>!?$8jSgR*s||Gc@cr@d$Txsv zGIo?dyZ}bgVWoD)d6|ww&cxW#BOV$T^gkO%VBO(O4iLY8{qkit#Y=e9VQS`5z^-8{ z-cAr@9hjI)99Uw0N`!_W1+vTUZbC?d?(3@tp#_Y``$J67eBM-6#fR&Evl#aBbk>xslbQW;yARMFA-TCu+B9)VFK8_fU zx#bclReB|7o*@k*G8jZo#qZ{H*YNA-ym|M|WW6mTs&+oVKxWPNPDD2}36a3eXsm+E z5Z|$d79+&0Y$=81+ewrt`qAHjKPJ4d$Hy#evF9B$W?&t^Ed#ROAl+)6Y;5K8dH3h3 zpvz7Bdqhop`vr6vt1Zhl$lG%NeAc+4#=i@8je(I754e3w00%xkGNpk6*Pt;+A_DI2 zT3=3^7gbQ8bEa0F_u7weKd<4`+R!zSa)rO04U6I&1-3YC*M#>&*9Zz6p~Ng?LJ;|G z-G=V$iB4%DlhWqToHq$?^73?*m7hZAb_5~KsL3&QDc zE$8P!n67T7?d#VbSe6B&E=`t+R=#;4jWf{}<5_%{X(^{XEQ&Y4${)>CB)pLJMA5j^ zz9VH5I3PjfTpMp@A6WlE*G}fwySx5HCS^Ceu8|4>(l1|?yd1qJ+i3GSEWz^ukH6c_ z6zBfEukG!TMA8gkP6^PBF!bFC3O52D#O@37KghPkwfm_Q?~6B&YX)mqv~G@KQa?5Z zQ8RWLKC}Njfm>GAyp;{}%}8Ey@_v8rg%}tWqi`#_BIwOED>#gfXi_J_t^I(hC7yB zO|77?un#uXPtUl6`c_sMozeuhbg=$r5OTvSpXRzB<5N!Eec9k}~BAWa6Ka}6;gplXFx zg3_|xuAM8p&$!qkPpP=(!3K{*?%|J-w2-8dw|8pt$&W z4n^lDE5pY5_iLfLmM7EkK;DSU3*T)tLA#>Q5)|crW~0lGsosC>bfT z1*|VH?i6SZcZvqX*`ZZgWOHAOIMKkA5Fa0@-ZGND1jI~$UQgaiYwrOq!tU=gSLTL9 z?r5~{cVe`B=QHaTy1F7=Jzh-{gNK0DSzFEA_YVPr0;X>qcAe!sXTRTaO>Rpxr;Fz& z)^*En0J*PVchpr+_^N{!M1@bmMneyIRKMQ($VvXeFn$5gK{x7E$)oLypY}kHZx*h# zU#tD~lV&{SB&}Ed?j#^)a+B7{%d{XPvh^4cDv5g61M_Q&BZ<(#R@O;G8s}irF?0F(-;r`IJ%c=8X<81_il2o?4IAmd8o! z(1AnTJX7%OlYrMG>!H?$Kg5eEQqIW~PH{e_ZoQ+a!(41_K!s-g6Z+$rae*)5qTYS= z%ph_NXc_*BQXp@!3ncd$HtcPTE<=c-?a6%abx?q~j(Q^dg4VTNL3Xd-gZ2cnIsW^p zr;%z+iv_v+HFbUk?l1NB_8t}(mjv2^a$PK#xqUrz^HIK3BT%TT>&<%Wu_kCPG{^Ke zA~lbp0#xJ#9gJ-wq_uiVUUT{gop5*{;1q&Th1YvnSxrO$?ufg;P+5z08T1@Xk6tDO zl7{XrUA-53cx@zWS=uANu=D%KpZh}A@w|A#gj8^!Q4P{^)%twScF76Mp06Q#@L_6S zfl84hnr5VwU)|b&RKLG6&ycPJN%@lgiNG*qD}g^6TP%p&scFCCk;nt+a8*Siq(o2UU2hwF!#Qa)oo!`ke6=| zlb7FHC@d@tA#D z3_R7)VanU!f36H^0$obAnDqDam+ePGKDN<;(A=k_?yHt|N1hW&l&4#eS4E{L_IDUT zW!VDuqXPQP48pMh`;5@0b>Oz$;5*r;66u8{7=)K-b z`E-g`ysa{wW}dvr3@~K6?#>bT@8GJx|8gmfSc_cD-@mZ2)YRWlBp`#DRUjn-Un7vSggf@d#?RX>!V^`xP~v{ zB49%Agaj{jC9Y|sS`{FKi{_D~+*U=jTNF7N9>~^$BKMWt{Cok~VYinH?|wdGE#B)2 zB4chYmcgDbqEsm&_~lW5dH8@%G%2gR{DH}08BjkBR{_$8wuRA-THD$E%7K9H36`C5 zUoy`qFpKJi4Y1M~do8Rk{w9`|09)icK#4^Cm6bmy z?bx;?{RZekiY>EkB?~2&QD*xdtJ-bKzx*@c#F~&-x9N`_bo7Kc7z4;@^B30ph{2T` zuXN%u%OL<1?ABY;Fb*L1-Ib_xg)%y~kKCXPK9%Z4aA5t<&k7o)8SW1;PZ5D=MS@>j zQ*Vnvt3c$6D~CWsTf9X)PI08(XO+SPYpUB@z+0(C{=J_Yz&}48ZX|9N1&!5t5zmLP zJy1o7*^bbs`~PV>4iavrjDB!pW!Gd<>1eor=QHJVUpoD>Sov+>7k3LS>oz{^v_g39 zz1FHgcDp=-1zIo9^!)kr^79Im*$Jn4*v!2iy)ZxTxd%Y_cq{{DvVyO^-o6O`zTo=s z)3s@FaWNa)2O4u}5Io*@97Dc>Vf42!hUoRlZ_lGJ3=1}#x!Kv4V{raZ23#a7%%6O^ zWDI2-Wsgp=$)Bb?qFjoOKgZSoc?f~tuNM@{_Rqy1^7kbE{X|uo5^()_2$;nGH&9gn_pGR%Sa!urXr~gz z3ztVW_cB_NPN2>{RQ$2vDz%$U@Oibwc=Ljgkkcj{&{pH>@3Ez(W2{vLoSfJOMl?_) zRTi6wIUas6?86|hl|5+X=k%+}?=V)h1^U7+J4Fm@>Sf>r2xGn|PT!2`nwqjzLYFo~ zaO3hUeqOd3&oIuhxGv;g?%SqQSM0wHNwd)rf2A!rM9{L@3LJRYTn@B!P;c_We|Ar! zbp)o^lBTF~Q?0f%@*~}voC|79ZmuOMQZc;se|XmE`1xh5pEv_g3|>lLyt z>aO@(dy^g+6eo*qhDYaK_iBCE!7c(DYM*<~8x@d}gno@{?d|PdTAS-_3R95wS{^F| z90nQ%#-vbap~GhV43;A;pvd~0abU1-t%gTcC|4$JYav$Js% z2x+`Y&<8WWS2%ry=8L|9P~=tBl+26_D@Kz1y#k;bHYq`nSNS+o^c> zZtMBM!SO8B$(MQ4A&B+3wN?0HR&H)9rOw*$+) z8B#@+Dqv-UxcJ}Xz<27??vchWCyH0eqyO{e8=J5RR5j4=)EACZj1lZ{KirFOPKG>= zFNvfsGql%IGh0Ide&6!Q)EAG=ahIZwr5|$T16H$Xeu^zA>< z%(gtLwO3?<(1o$?^`bKx%4(O!b5!SYOyrT4>9_Ak;#!fGr;i@Ig&HyKX>3WdRuhP> z+i*oYd7cq9K-F6IxM4j*JJ%OxS4?CD%gu4)YHDg53GT*^^wkmRf)1N&Yik$7;x=|( zr)Y~AsP7cuR)KlEb!&>%DPlXmio6qDJy11AXx-d1#o9F4U$oT-ymhNZD}&&%DkmZf zARrir!g3hm{D(bli%xz^ktpyo&t&@d4qq`zkL|YvqfaZ*Nv)@VFWqn3-1F+&+U8)AbS}n`?|$*#jdd zP#BvilG`Bv>7xefwMcI6sRUN%cYoP^%R7s`RzC1-a^{7o{S#P#ztd6}=|XY~-1M$@ zZ+HHYE4ex|RE;I;>goMSb(QkB-j!=f!UK=6e^J<(|Ie;M#Q?x*ZqK^Jjxn;!*I>td{z(H)_qrLnVlOiG_+5kpCO3ig; z2KfMFQR14vnVH#T1%>_goJj#;;cK5Z_u7$>iQ*MGIXTxRL=X)Z=8U>l6C_sa52JRH zac7W`MmYCG#%*7bt1WUpaJZYBqmf*WwAW~6#yrC;=VDt_S+Z2~s#s9gYQCe)tM@%U zH!y>iUY6)HLH`bPFmrk`l|#X@TQrI9!I_~^2{)f`;P7Ug!`6gCE3IOb^qd}D z1VU{8&hl7|N@9Gxgc{YM$L}Z4B`nZydavM6v1Sc7xkW@o3bL}exR-x3qnC8x-gsH2 zd?s?SQIYZxrVrkXVdpAqy{cNP7)dH#i+8t@V!JkMCfm7Mf6BJ?TdJgp?XR!#u>bAO zTs#%){uFmSJS?n}?(k#nR_ohEdqG&|{sC)N{&GM2ER3@afJ-NAj%v)Ubu5QRCwsze zjRaf(VreQ(wyCyuhXJ)esO0~jQL%ToKY&ZE^fbCc*#G5YwWt+h7gkSduu8!t7F80} zefybLjm*qOSmFF=KR^mrY7&27@f?7p5uFA1O?+tLxa=Je4^saUJn3X>kz3_^URoii#?98(;PBNbL2 zXpNd(21-0sXHeOiJ`m^N8(+s#>SUHEyh_475 z%QNg=Cn>>U%Rd);Uo!0r3kfZTPj%{%>hgQaZp7*65$hgur}Wbs7fsO$`Z$r+blR`_ zm1?@W-NPfbD;wsTmQB#E={2(9bdx!^V-2q0(fc3xQF^uA$Q>~8j;(T7u-?D70N_iG z$XYkRS^OD<{5eZ*@)}c1k|4ZTVN`Ve<4EnM+B4ki*PK|!s)0tqxrb?KX@2IW2j)-O ze#?vy&D?2hO2xh8l9ifgzZW5WE9PKGSXfw;{?v4<7)r%Eqgu^THMjvW_hoi_`KRla zF}4_sgLCP{nY21-;b;9|=VS@z?C#t#0GqGdS)-2J!;ufzep~6R8JZ5^JbJK&iIK71 zDyZ44E*kgt>~H`j?4(@xa&hs^0+%lNXO))zrgyUZz(3)t%m9)SFp``n4ihR|10>N) zNUT_-Xh1sVH9}Lv)zW+?zHju6Dk{rsRHpRJn^^)@D^ylawkjf_($g4q+$<^o!)iSZ zl7DBHC0)Fw&;fnlNr%TF16uxWoap@at-h?PYQtMXSoxfYX3s?|9Rv^R-_1z9?=pl# z)8I2%cic_TOlmuFGKq*bX|G3Fw5JJU(?joDl2TzX^LJYHb2Nta3=Gy}31cy$iRn7~ zC_cuW8ZO$V!?1HB9zA-bEE-}YSpIsBH!MLL)49aJ`Ho0xD5{*xAUs91t=8|W{wb`i zK62n;hL9X6jsJZqo{_mi&5+P%QIqdcb}9|i$&B&*>#v`6VR6P`BD!ZqK1zEPR92Ng zwO?pJ?p>?Br9b#>U9Lo4mf2UJ=jiTX^pbK0VXso+F-)44YbS7;TZYOzD&nf@>Xgvk zui~<$&mM2+PRLdxC;sm1E9)`h<~?g!Sy`E2J$OgOyhkb=7Qh3m)uLireo70Sm=m0< zfmY@>p~bpcy8DWpOHHL`8CQ1UeB|?OfB(hx&YHJHm65(#vrQe}7Cr}BPnK9RCqk+E zukM|$NKxySJ&nT%dH%dhEW|qOL}z=upQzd4!lLZve{Yvc7Yro-s+@~Sd*WVV_}IzD zHZ#8vQG1(;!B0{Wjl*nREVkq>iP-Ubw~9n_zO2@>%6FmvWZk~Jm4&zxMBc5SQ0dlE zY!l!JS&@4ed{L69AOU`U9|f@Uu`}l`2?(TsC zcG_oRD(u=m)QFQ?lIS~YQW5NI4Tvu3&EQH;cm0#!Qj_a$^kiST+j;3tL4j)XUGGxP=l#2*s_n-oE_q67z{FfnpFAetMSQuA&y8 znjU^r;kk7B8M+W&HOKOmy2=e>th4TPI(hxvU3+`-J(%KOD}xZb#)o|TIV|*~Uq`H+ zdG)VH2fxr_$$cN#iWmaO1&E^Z0j-2J`)_m0ElK*w4yUd$;KIxW=c>C;#mB`ha?piD zW8G_TH>ZRZO4-%#e3qZ!LIMBl0J)MYgMk8hpRKsz{?@G*xA3Vt=mT(^spk!6zPuqf zULEQ8@5wfHuhx$w_&7OMz@hrz*K<{~1E0*ylj7q&NYHs-@>6E`1Y6Lpo+|?*O?<`L zs^Gn&?Q_WBo{D^h+~bI(cv?E%#qQfh9dYidxb{h{j;{9hx(l`8w*@I*Rm1^mi&#Jk za}u&Pja0veOYg?QO2)#zS%Y%v5{C{Wg{(XxTH(&lzuSzaJJ33y2rMZI#mnJ@VoGUQ= zrkxaYj9fTk{IpHfc-phKJ?Iz4&4iWIuIrZZ>Yg}0=*PJFwzwH9j4BLN33fO!R+Hr&vIF*q10H|(tz_CP~NzPhT*%VURD zXFAa3USXA0(Ulvyq9K#5ocelt*wS5d2m_?hOUYPp&F*QHo+79}azx9n)njs9vhP>x z-$NHKZlpZBq<{6+_P;YtRn(g-tLSTn-k%sd1iw$5ArOM-G52^0WA$LTk_SeZkV0ZD z{!?iMF%<QHjnPY8VgRdkbP3uONWB zYjes3-Ky?u5HmAgmLN-@y98e4lUeG$y-~R?zt{2)VG~Rkn49|*vutJ$akJ5hlnq>S zity3atHC&HqZB+lPikJ)tipvh616J^0x!-P+J3v+&9gv*Oh-7lk0r4X##Wb(Zr>)1 zU4f5n&%&>MZb|Czl;(C2K{4g8ET1}WOaA^LEyNVPr+DG}$IZQ)$oNm`)*^E&N!!a0 zI@3?f1_G?wFC93izSF!~FEKE(sCc2YiAc&-C;!&91^(vmT!0;GR3>UieQn1NsTpIC zDc*K0{BDbeI2P!7b{+v z&9U0T%zEPRV1?VVi639N`b_z`0pCxn^+(KRNB_J;YzIze{Ao#AfOZErX-mM4<0?0( zQH0MHo)uiyH%-wCj1G+%uGhL&$@&HcchWIsp$V_BGa)xFKE2UVb+9eYy$lx)$5jP| zm4XPvb3g#(s9sq!slF;n|Igh~y>w{1^l&|pwIowyj<0LA%8_G2w>Z0QFY+lO9teYT z?w)K*zkDW|!05NA`If}roM+_kMWV!7Dt>Jbve^E4{Qk$cs!y{d@~uiIm79^c^V}*? za@CReOp{LLGbau|4vJ6^_5S@MoY6stQ|q#@u5{roQ3y!Rhask9%31l1V=P6E%}zlNYvlaL7E;>p>rCN3}-~w$Lh^ zU@EN0iF6wf1+i}&&JZjL{2auQ;00}Mza@daibZHb{v18+SEu}> z&qV%C8RUPztE{M46GAEIO>YyCd0yYvDzVq%)}m)uqlIh-1TqLhi4`gp+neXHbnzA1 z?&%iFjV%kW7wRv~QFpBxRXo_ag4olEc{X_y;S^KBclzjkvimPr)N#)xGZ{LQ*~76~ z@<3D*)Rxw5H*&s%1c0lRcjf>25Gq9*gktH<;er3*V-+1$?N9v=ISY9p|C`QbcX&j1 z-wRl0D1x1z`OIFds&@I`KNKt+&T--2$3WNW9H1Ov{(b$QJ0w?+MD6tP7&X-}h_E}TBf_A8B*m^P}SCxSvF z1JDtsfT6m9A;?>SOxuqEcm=2pX~L1QyR$=wI%|04y9$<6{dF;jbnZD}RARN=%gT+A zmLwXa;gQGhM`bT2D4`eaB8C;n?=a5#7fzcjkjP9BR!Lq71lb>pEKEz11T6Ow2~p?g zqBG)zF+NlP61FR9NBs2B`tv6a zVsFCCb7Kn&|2T~E3ykw)g3tcFj--2Rt!jEkMg!__qO{jiRXoZfIqt4c$wO;Lwn=Y# zb*)Z}pIfLfgmV*1EDt2)PH@eQ+-Y46xLYKz*b|C&n(!sk1ddg?5`pd{@TCy5 za3k|1npy`&?%RILTaN}RkZA(4Zwsc1rN^0L&mBED(FWms`P1zviIz2q7JthAvBC`g z6CYjhsFbCKP{Tb9M+(4mrp?x4obz#Bg_U=`Gd4XIYyMrj4X?hOtW>fUiCs&s+<;8- zfbSE`vhSl`m)(B>`Ia_C4XB=n*yT+*Vk2GQ3O8X)C{$~!Q3UlDdPyBy48y3fG6*v1 zaAOkP-h{DsEDKVxuyPzZ&NXL4urSkK0P|T~I&f{)XQEGO&;-4TIICW(r04mla-qb} zx`!PsWMupJ@VVn(thScKwYx)!JWg;Qg5tbe9s=#f)jhI9u&a!J;~YXkhdje%x7eAHTV8EuJ$I2W_FeI>-4P z9vuJABq)2}j(pKUJw`gkt-TbTQM3J~eYR$JEds$icN?YMm8sCw9l4Q`lH#t6;UMTai z`~}k9_fUeZX{>uhYsi?v)?O{_=V?iL!KHAfJq4M61u=ji5bz z;Nc#^&NoByJFuXTkK@yl#HsG9(c=SbKmdBFttdGN1T^;mRPsFi_;U-V2#>;wbrJ8& z61htFF^D~`9XIrvNfyDq6tjFCM#@Dgs7YIAS|YFpCy$gz7cKSQI64P^tTso>3{BH1 z?J4vR@%ysZ19#9U8OM*ELGnF*kXyNN7U8;3Jq(1v`|?J$JQBXCvGtbU1= z8@i~VSn*N_qL{GGi;8JWGd@;2daklU)xgbPu|1`P*Ci`-)*M0nLe=W`bi0WL7JcbF zVu~(F1Rk6dbk91s4#Ba0R6_nSC>uI{_;EDi*eA2P0$c$i{d|x!kcqP`-LSu>&JzSdPTCIIyJ|ga+)re>l z--8-_SdMlk*=hGsOHycOO#|bwX1uHMg?~KHca9~kU;r|_X78r8lo>9FwJb9D*-+wG z#9m?E!wiD_S)p|IVBF17R$KkT%A1I#vqukpXe5dN{ZROJaP~wu2b;DT+9fs)a2K5Q z%=kX4xNN=W9Hx?@7N~j>6^|~g^!l6$*(mSSVtTAQnOA!O{kiL}f*?^4*BrztPhmAl zIED5zW129_%*q+7#VdAwHrtKXO{6JXFxC$3GG#!LKZ9lU{-NUS*F=)FPeygW=3-U( zKn}1dGy!-b`_kN>Kumz!JSBbqE?AsE?17e~lHAJw{0>hEK7wXpf~Suz5=null(7Yz?s}(QZh35AD+;(|BNC9R%~h>(D22-{ zFhsZA7DFL>Di>-!1p=U`Co+&M-(`NkXzw8|NZpr`kIBst@7wmTIj#(`z7xzd4y z9+1%Q6`l}`#o>K22B(E1yeat4w5M$SXA3dE77_xC%+bUb28(HRikiHN3F>BCbGtfx z?nPXv)mv$pb+-HMXkD%EvgL$W61gX^^E-3~%jvedn^#Fafa#RaQDqPsWX4ow)mcoM zqG_<5QP=!m7A=^ddm}}Sr3uA)(=!hOh-XdFiRwG*a4O+cb~3rB60i1Ev?Y!H#9^jS zYzn$De=L7tZ-Mm^np4AXl0JPSnL-@74KTn(g1#$w79(#Sm+H_=|H2 zQLc-%KY`#g6)8zqTu_k8KX*xDd05Z3s6nO2BZJ`N+@2N+#49^7Z56>@oW$TaFw(_1 zXDSMWy2pC!U0_tItExP6aH|3M=*R*%KFh_~bgkx34VDcQ$Hl>F<^egt-;ux;SQV(Fiqa6TG#(b7H7fG#VY0r>dQPD=ReQitWr^o>?*#q}9pj_h?}U2-DMu#b3Q~ zFw1EOZijY&_ttP+$CM>Xw9?ZPD@^9#ltjsB_w0kIf$q$`IYmVZ^m{vz@oV<>_A}_p z%Jhs?$4_RYdb31>rq)%tuMhq)l#4%PdT4N{7UtJqI&PtSg_utWJGY8|e7$cuAgw!x zK)DF~DV~YMUW+y0=f4?~vJv|AlAZc|(LRqX_5-s%K6r=-yt@j6AYOT&bQA4lFWbU- z$>Fwmj*pPV=*8}FCT%sniW5fqQ3h-5dr$*?s>(Kxl!bicsf#<<^%|QITVWQ%enKBW zZ_B61Ib>cnMwol!r6|wMn9RiM*a^?hvjTtKu0G|Wl}E8GlgJp!3Gb=qEyXNi?S3Ne z_}O9UGJ_rkL;&tfBq{v$>ShGzC>wgo3JhBK*}1uL-IyMAFM%GW4~g!{I3_|zYGU`= zB_ToJQYtaa$|x1pd>vd<*8yeUxf8~BREDB$Cg+XK%}KRuP-;%RoR`1)a0>5LRqD?F zXsGUaL-mlYWSLE$(wW$MS+u%Y)Q3Df(@gVOLT$uTIBY}Th?4J@*@_G?Se72=Q@2d{ zx?GOI<2ebPVkfSQnkaUVd^j?aYbZ%g6?U8ToAn}uGY8V6X}nI)e|M+3MRf{NkMqtH zEGT=Q+9=G+^Pzbc^V@V*J88}3ShFwD-uZS)z7_NS*y81UUwePA2Wf!?LY@&W z3e0let~siyInADo%8$b;E(&AGL5hRVo;?d+^*lv$I>yb34L_ozwp+v1S1Q)RYzt6} z^26GVz3KoiKi^ToaOueXbhYe2#UvB|;=;nk!m6BQ%34j*xy?lH^XBohcgR;Jo320j z2^NgGG_?#{=Ut08$tvzPTZ?d;xjTn`fS zmuVNN=15K@*1-XFf6r7k`!@RpDaK_kk;W8LjZzd?;NLZc$cLQn6({WLM5QM}~Q*qIPY zMRc&>v2ncB$Oh z?VzUzkzdlM&CJb-%oDpwFB*%lTx{NKe7>8fD)Uijax}}~hhAP^IW#_{rZpVTGLa2d z;u5_UmgPdDkb3#A4~8E@PFcgSo|QVcRf1V2L(bQRQwK)B|7QKBP|*nsq2{AM(qxN= zs3%C~M+FThc(w5N{#_WbIvPi0E>STkcSk;HlQ??jYts;9p}X8`f5P>IYgCufl2yUK zS9;S`Z1|$b7b5jx!hp4FX8?U}iA=`j6@QMOUzbFlddIgM{ek!pzvHaAv(R5KC;>&P3yZ$$UK4Lh_1gx^6W=QZotvWgz=C!r(cCyK2C z)Gxg4ntyEll^UK&IOsmnb}~>=e=nZDIquyT4|9L&#W-tgu4E1JsNcTSUlKhJYe@B* zA*T;Grl=ycAl=*|J0TR~{BV=(Gr~-j3@H5klN3(k0fkO&-d|~?%jsItM*Ry%1(in5 zQe8YKdGOt+^k%^r`$|_ZsbMoZE+N7B=w+xbXAkbBVhH_o>cL~qm3JBI6Z>JMVhaS2 z5@lBK-};R_)Jd{Hq1v`z--=90XyT?LOHt9+Tu#=QY0Bw_Qq=8&U+syf4p$Wy7hhxc z&ac$={v39;^;6gO!?X?pgVAZZG}hhcU6Q?iO>#|~h5^Ejbt3GHR51B8lWs5b&$Q9j ze)6TJF7Z7y0fg` z%%7SfU$j_ic$%NVrjQW}HewW(S;@EKx9#*rDkajj&Jg#Kx%3ttSG+JKx4b$fz;yEV zu}io61t~B4nE;Q=_7|6z4;(*_JF$o7+Z#9DUueLOOK;wK<@wZ6r{ZN}^5lpCVRij^1Oe z(__|(M|I>6_>WbhjVUEnUR(z+XdP)Z*VkXAE;wxR_IgwQfvY}^RJ8?;=tobc9^N!u z$AXG5Uj2>A>U&7gCwGV0Vl)q3b9~i7U&yh>|0X|wUdON@?8U}>h}&1;|24}J-~Xb9 zW6Y<+BsZ3%g@TMt8nWXx6gUq& zJ#e8Toz&pXg(;|F8+Dg*aJ?rR-8161{!HM76g6>5ce+Jxc2+&)24QJ&^E40x)u)p&0wQ{qKKx!itTwZ1=zjvc+ZwLzL7xiC4z7VYWY zNRsM0$KQ0rP*TWUahLsDBhxTO{FZKC{*TCf`|x*6f@$fNuOwK9ZYX)aa;3t(;R`Dl z?DalroIbLl~HeRiPdNHHz4#(lI zO4IouMaUR~N5-}(Tpi@G67o<~5AY#M9wJ}gqO0 z9;Wr|rxo&Uzo!PDn6aIw-~LN1`I7f%PiTzK{wnAC`=ET80`{93O!$Pe{O{_8FVV+b zDc?V8+(dKY+Z{2#lE^bMgnXzAc+hzgk}+;2?Or?PeZ~1f*7NC^Z<(Cw#A@x6ZrP=UbsH-hp{lw8(wQ zU6f#UDWSn8$TMbdsb98nNrew*HH)`z=DH14Ag0bvPf7e_D~UtA$~a^H&9~n1D(H%h z?asqG{U^=t8LMv8cx7#2@F}GXcJ!rLikuzWCtl)kICN*#iQwlIJA^M#6H@*#ZsXv} zv9K&YNoC9TnXCEvTn_?vO9_*o!!ZgA!&7yPvMLr84WA86eF*J`OC*mtQu>}GCPbN= zPiC%r(d#YBU%U7HOf+&1O$A#hrfp48NT|e0}t&ely!`q+s>v=ZL06 z4IZMvz_rGn{Rlb^XCHs_CLZOMK^;r6srvPZM*TF6f^OqM-h2Pq{i;a?SGQ? zGJh+yI$b>P7?p3|I`PrZdgAK^RnO0g>IEF-q|uaTC+PE{jXfLY(#%<}fAXP9*084% zG%oi)@G^h2;#KCNKUHY!3kvW@sty&KMk}~LNp}Os(5WQqwBdnxzW<`fnRb_=LaH`htXJJJVgS>P zk=Lt7jZbIJrU|m_nuJ$Hx|n|zv{rpjsLGjq^eLByNS*$gZ^zgI{Z~=A@vS?&4^nxQ zK?-V*L9j$`f4G+UxFXn-q9_INmI^^1JY;b*i!F zufoHl!otrdUNM9!T^%31D4qJ&;eDVuWCs}rUiBs((Yx^S0+$~ZrIHD=O&Sr@l1|c; zeTOOY%pWlb=ZR4jFH)qBxo;Wo)UbJIAHW`i?6ll{!;$w=Uw(7b*VMy#gJk7QQssNU zAnMgOU@I034tK04>KLvzZTI9hq5+0S~pVPCnd?OT17{NyUN z!QJXsWAt7988!geO}#0Y+}=52Yi5Y&dFcn!mnJ9s@^{9e`^fzRZ0Cq%KR=RCi}c_N z4W9i&yZjS<2?g7u3&UF*-)$Ziry1xwttk1E#w+6|go;TqLZw!PovMwCtK-sS(^3}V z9{CgXW8k>%j>r_l=^6i%X47amzfPMNm@)^Hc>GC+s>PLb<1_K zlb7BdJVmV?8Lne6KKSoxTF?oG7KfA@DI&j>r!$^_ob z(9pv*CLkLM6q+9D>_1lGax2jj#n;n*k3C6=U?Xe;1&O|} zX54a|bXUmVF(&Rshp+!?z)$!E<>r&^pg9X#W;>&3)$N9@?UXic=C}j;PYo)!*Vvob z<;=quchcWom3n6e&dfCqpJOm$+=GH_N2a45=OB4)I`V zfpZ5}CWwm-O;z%?&>W09D3sI4$k1>p4sQ<}6cQqbyA!1Q7bgF@k&>-<+lK7*#n1Zs zRw1<h!#7?6ASan+oP6GYA+8$-gH$)$esVr)IgR*9`yqgM&-MHL_9SI zb-wbQn*3#|v=fWW)g((O>kD*S&^JvUvG;_rD{0v5NM8^pSdf+c&C`hucs(T!qkdDa z9z#Rz+jjCX*2Vzn#-EWn4h9}rgveLE9qKZhW+O|Yh?e_%IX*rkJ$SWIcdm(T;ahJ`L*&t*JrQu z&G-ifIx-W+CSi7Bv-o_Ibn1R=HtP`g_PG8u<|k0o1b=+EH}{h9uXI_jMn9PRCgeeT z;gAg`g)Y7R$lx-?uYL;Wz4>EQFX{FNt{86Tp0Nt?Jal-(21?%5VS{KJtaCOu>N4)N z`tAD�x}b@%`?-CitIR0M-g`rlCfmy(kumd2Zq!vf1U~TcDOUS10x(OUrq$^Bo9e zbG`h1=EBV=wGU7B2Xq-5rW^L$E*oAtF!D_%Wj3D!o6j{v7!maROKh`^;Svp-s!3&!ic*wIamfuR z+beOrcMnjU%f-aL!?uEO%fAyJIk->^(&QtR%}@Z6#}pFlrR68R7_wK9{ryrjgn@|F@yY|BzXCpkQfnew|E z`g_XEq*r{_H+f~ecIa} zdh_5pz-sy#TeyApzwzDSY-ddfZGp8}K}GW>>q{;dl0>0~*T9|TVCuxazCJ$Jix*#d z`A(pBZ-B!$eR`k@&fP`4iA^d;A8-`rZwr#IX&@MKAqW|m;UpoeRQ%29cFU7JOG?GY z|9?~K=tcEOTGAWVUjPdWOBA<;fYYs{Qp=ngh3ZhWqR zzJEUr|LmfDm+qk6N2tQIG_$nat9TywCf}FX{;*nkI^xEX@*S&F-L%IAxS}0z1(T=c&#m(4Fd8shOSa2ZBxU^LjH~T{o8)nL~uTYxPc=7E;JhhhdLKzj)YOcF$UiFeteK^I1_*y|4DdKYzTQwYtZ&vgeHrF3O@j54^m(~cQNgGpcn#>2kCYRmhp<{eB_Aqp< zv2D}6+nIudvGfTNuhO(^el2Gy^-sUG`-#Gq%a^Y5&~FRB;1d$sb5WmS5w%e|>1tzW z*srC_$gX_Ud;P$<@Gr6u@5OB3hQ9jHMSptuNWo4lId6g#`eaS*&~Y@Fh^aMGA!wxZ zJq!r%v%7%=fsICM*Y}46gENf{4ab?4yKmnpEkE;H^tTRdR4)wP1HOuFYgB+e@F{re z4Mbp2Fu!G;XG7f(DOMH1Q!qcuC03VRb{ER@o#wKX!#k^pyM6y!p}>X&dJ-U?Oa zr1w#9A^C9iq%c0R&VCv7U*o}l!z_t#wZ$LhO>{ZbdAJyi%ZQ%eTW24l*O5RPHZ|4s zt7pAKPG6qYI9hw+pjtYnuDHaF<$s0SO*Wc(x6j+kyx0sJRO0FmfXZhP=>8!UTPKpP zm3i~c>sK%wg8J?|L7|xClRrwqzdU};Cv#ScL5g}raVd!pVR7y!fItA$%dZ>Z3cz@^p zzTY{2%yj|Ro{PQqTKkFnxu5%KPpR%S3TNKEaRK8P4zZH0lv~}%p%WnWyOHBcP&X`{ zY;FEM_%+BY>aQz)a`>;$jWIo;TML4;r|?8y+E4WF-LT%fVuevG_+$`RP@4VS8`FAgq&0?;>&2s1h@ZQ9V1%o2&MV& z$}fHj-Y}u{`G5XYd=PD|xtcR2rV57JJdcQt=v@oaT>C-(u3lZdx~2T=Yg#+CbwvxQ zy^#a>-~ZhQ(e|pJZP!X=6N%_`CCz8-j&9SMkUw2m_rLSeV<{u)=ULY`0#$<-@*8jeIcfs#RzH^w{*Z3qpFPHfC zT(tSj{H=&$$p5|tW`o}^&Q?PgVi&MkKAipNJFNR_&yi*JD~`c(&Qz(IL`s>{^2_7( zpI7Q$GR6v;R7JKka$hry=dc|66f}Z3wrbiFOAz^r209t+Bx-Gl5}D9qcWc>y;gGh3ln-?z1yG%|$wLyDX%e)$|?g z_2|Ew=<{Do`@i@M_yj~2))UcuLF*OrZwDW?^Lih4DRK;qt8|gax%OGs&hODvCzea9p6u1LewXr<`=`t6^b4!3oBgLQ z_km2OHg<#vi+3Hf7y;85tLD@5in*G?iFE5Ik_dXO`C={j?T}vTW>X!M_EFvT#f*tDb|AYZd9Xr|M<;C=q zqT-GVJMb6i<}T}5TceBQm+&YM9Rv7*3S$5qwCracEWRG|3B)LUAVx`+`P_F87$B;+ z&&x!!mq90>^O~H{_B0N{0va-_Mo0exR4qEY;qFdQjpti)0=d(_7yC!yoJ_EFrkc4k z;5;;5tkK55;n-)2@fJb1?UptbH(nmU4IwEMMa{k!&%*jd#m{`A#G&@Zi5kBuR% zLDt0U)J^N@tfo0y)U$37+9QqIsZG_o7czt)pcqAA5A;1l27p-I>im2uAr(=c>{83f zN6&Wr^@!)@W2c@=lZS_OOA%hQ^%5Y7b@_f&LlkOlk5lcfr>LL?)W=E{kmhijP2BN_ z_TB{Tm>Y*AbRV^YZNjc zwbw(pn78h3u1%VO#E~2!uLTc%ugQ~XkyxI;x`NqOA}aC(OP?W5A@Yg-y!=vPqf}at zAvgS5IJTr`_wVjBmNJ-BDrqYNg{&2Ud<2%v_#zJ*__dUA;V#C<$7cu$!$D!7#J$br z&Xt5+!+kOvu71*+P^X9$3 zC0i*2M{8(Ms%n$*Wm}8&gilcRZ zw)vIb!vk8c_S$%x-li9tA-n7$b7LcB`;%~+%qivZ5WAR{bZB^pVFMD{N-cnAP zoq|Z|BjWd_WtS`(FeYJns1b&zESLk#0!DiJ@{ekM_R6W}K=^RTv z?S6*}e4t3!!q*P#eqxH`s?jj14%8r{9z*dkPa&`c&S8qC@d`eiV}Y|qJ{tq6vB&#= zTC=I%S;;qgFNNsT=qj++jDc>a59EmPf(NN2-`Xa(TipH9SU(-@ujn`puQ`76;$7O&tG!88}cM?Q7n*239Vkrv=hHon2HDgz&LvS1Ht6*xBjTy9lhBvLTnlU4Pq6l{_!4UeuSvG zGZB)KK9ZkJxCJFT=1Zsi8QO}#7@Uh>4-Mw#8PuR7QcDV;27Ip%up8B9^|=HFr1%M$m%htQhX?V10}8$@ckj)r%9#{d|7#7}Q-)LI{qJ7Gw6pFzfT$?IZPmO9 z->Z7uJQ$yF#(H2@j3?y``&os1w7g{fd;3>6i_@a8OU-#b1rx0b?Q8h6;yav}Fq9(E zC&xawy_F#`*_T6cYtzjX8j2^+CN={#RX&}+Y(5&DkKV09ip5grjc?6d!nN9bI}3^M#Dvc@uwF*DhW6eB($P zj#FUWG6AZz$s$gF`Wr!3NPhcozSVPq!Rl+JPVTFQ60C-Szoq>xHx-sF2ygui3M29e zM}4F?wVvL7zddE{WgJM!sSte0BNZ1)It#x?vry1vm&pgj5p4fm!GNPdT?MjxoNpS(zmsb07U_%HFLr=GK zK!EVVXLIss7ZkTSSJH!E?#4nMGoWhx1*CPg;X9f<-c+|9YW1aRf9c~Uf+~_M5}t^U zgn})0b>qF@J8<3p&ED-8zdq%kK&bU9l65q-pLAJ2JDbwUd#il}qJietaTm zg;+dp{Pm!=lp)>Qev#ExsZAt4H|P4@p2-(YxIesw`?dJtG_Rd<(yn(`ru#3#@vN-! zC&WK^C3ek%triw?*IRb|Aew=HE*lk*Ej;%hw-q4S!+uw2#CCqyX_?%iV3-IVJoD;r zk-cN-(!9UO>Q3G?vr47;%GnrVe^I%>;tenbsHajMuA659rA-yGWxTptWG<($sL#qj zD8j+Zj{kfU1z`zy^u}Gt^}N#LsWgQpq?m(pnxK4-*?jX%=9^xp25+~0_v9x(n6@`w z^;8AYOF>3&`P*5jI#2`FhhEuYBy#c-ikILOkcDe8b_@R@U3;uE!iGB5u?e2+^Q*cB zdHciO3H~=GT>*W$D%Yr|8aD85@d3h}_~*Dx-0;@4yOx@r1Wi7v6~X4?9{%Wb#MRox z-25)ZjyvJ>WPC~BtFDM<)=~ClBQQ>3kQtATH*TTH|n_@ z@$T{0i<(wQ1wmYZ11OHd;J_}Q{b-qOSEqSIk~7ee#s*@~HPk$7EQ5LzfOaq_R^tiF z#1qugL4qI2G|mZ0C**<&D<0~p0ZK#RG?*r~?=E9#LBEI@t}4#Y54b^P_MbF+QJ^R* zYkM%wt=@ee8@6Nue7kk%R>u4XBX#@RwAO;|mbc@Z{aHIbRX1mR)&m_mL~x47O$ss& z{5ZM8D!&bV?#A`H%S#!)!3Jq#-b`CxCOG?Vn#sTJy3)0_GFku3ojs(V|EOFcT{JC- zBeAg7saqY4|`=6(kgJ9gbN^Jnp`~*En z2~E+pJq<(CEL_M=JJeHt4D@(y52-Fzy}@7Z$FVt$thKbw zJ$zH?3*eU}hMz=bXduFvXDnU!RbdIEd{LiOp@5a7fYFMCI49nW3SDVN4@>($DEBVP zf(K8O^l2pFLWAyw(98%zaDE%xjU(h`LxE1e4M=iWo&2^%3@5okK2 zK;PFVim65nFF5bGS#ZvR8CyxtV{)p8_4_w%A2!o(x!RDUwf}WD|5*zeq-XzPk3< z?@w44e*anEN;Tszk7OcAib+hkA;%VqEzrKRyblG?D0E`kY6rYb+oYPNF{y z7WeLTnpo^MZ%q#@G!}lGZ~b)-XN-0`{0{328eV_)TBn5D;=0>#wjZeyh}e&L^Q$>|N5Y&aypSyXfRLk~9K@aNK1wIPy?-5zhg& zW@7r}BpeM9i)ajwM4r|G&cH^~_sZ80#q7XL=oF%Qh`4qB(n8kucUAP_N)J=Cnm)ok z%9s!`+pKu?khg3JNH%NVaJ->WvW}vp_g+rp>Y_70p(@fhlQ2(q?KCs>5aB)(@nle3&P6Hm z{N|UI1y1`c?ZtlscCV5L)FCHxKiAv{gv|gt$4~R?O3-`Z7T=Kg??rbZ*AJvTIHXsK zn{ZQP^*b}Kd4F={d>vPYQ{A8n|2;gsN$NwQz0jKG)F8`Iaa*b)LkdLT4a~u+|)QdDH-*ldS}~ZdDAcJQR~3fsm(6VRn}l@0~i(G#_YaZA%Ip)J$~0lA0524tL}8dxI1=mkM&FPq2+N zROzYyQTje%ABn8;Q3)(phx5aPhE4Q_jLn=9K_6;p6Qlm69nV}{p94@ zFPVn??@4+Itk!>JchoDtqH^sD3)NE0rhg6pY6$9K3|YPU+#}LU`YHz@s_+ly(28=D zB(74@pK^+<6rnTA0pJz;+hZS;{{wUGGI~z=Dz7%5{-9L7Oq#|+%HGG1C1_U) zP(h3n*82MTMT?k5u=;!Ez16}6tJ%Hvcg6z`Nq^W^*sx>|r$47WLKGp=SW;{vdFTFelJ19j|(4KcM+|0FUuk!0lO)8%Y!2uy{h8XDAdL0P44STU`X zlQxx|lq))yT2{o(*aPtr>B7XBxiV5}{p;Rp@f%D0_L4+Qlw+dmPnNx3twCr$+ZPj$ zFg~-b+{!P1*H&i&o&r`$jq!liW1v4vIk|S>@MhEpIxD~@g7wG{Hh&m1?zRN?yX>rR zL1?WYZuvl8>Tx7iM*rvJj8MoZwfjF1pY@a8dXm|>%=o&+T8A6CGtsj&@1SaH!n$W4 zK2S8VID8J%WC?muPO0!n-ZUG6^mYT)ULimfmu5>*&p*El0#^fw{Y7=V30F!O1WLkF zO*nT#($>Za1_;PMLW;}Fw__fj0OG!kj8@E(?0>>y-Ai0BySZ6a`lU(wL>?`fPoQ~g zCbF*!Ji?g_?=b}b7$a%%n`$4jsC2)k0kS(_wnf^BEX&F-)fuu=yxKCt0s7kCcc<9K|60V*63&w@f2hW}P0OCl!_^yqQt-9E@5QvI##+Y#bGWwNkQL@yZ@q-6%787vGyS+3^k!0M`sLj~dPpJjX>EEN zy|{-w2Q^F?sMJ!+)-;+Zm{1A<*FVBOu#gIUKes)7B3WwmB;H3R-O$5F($*K!x#vU5$f z<^YhyJ1>G_p5KL?`A(s(Nj#vwCzHkjJfxfTJ+3M(uc*xP^5Tw?%hM;{$pm;MAspDr z`dyaNN65i(iL@lZCsy7M(sdoBD0kmePBH~b_+{mbACsT&VN=sCq!qV4yW5>3P&KX?%mN9^2VJ6!WyD+HXuayKPnO+bb7ds`xyfBL@Dy@0WuogpMx#At z|4A$%7nl`hzStagRf^Jt>hFRQHQEJj zA$9@S#YllxOp^U=pBj*H+>FB`(}P&pxB&+>6?Ew!pQs$9iDxO7^$rdNE0=WCQSh$(s=Fz zIcQuU4n`1iO$1?sI{4l~n88qwmzd(n*K1cXGv3slrtkI24gvM+;nh3#_c?Ya z>#6>RKm&m1hX$Zi1v)aX6DiSQzVz0wu=|{e!~!D^{Du7)t>UCyOEV@Y4ECp5y0SCN zV0A4mleDC?6sLs3lyDA@jGUKY4lE=h8%U1mKtn(^aZTw%&`ZW^PzUk8o12@vbVpKB zfx?AcZmAiq0k<+3qAX+0I`oy^(q96DX}T1x5Mh_oHPwdp-r~+K&C=Tl+?#qsw518e z(|4m42`OXTPYjy2d^Sz)umh&ym*NmN$c1w+0+u~fI_Vq9uqIrn zAh%i~g6b2>I1sDaK9K|@OCERC?WB{WGm~;SlhN?!T)urtNDI$XI!VNKRTxvI`4dXd+BV%YhRToafNc7@w^auhZ@OA zZDu`hHga)fvq4tj{*9av+G{jac!~H&800stzB#*5e(y8yO|fs}ZztyG<9QgC6w+_i zp9Rgf?pHrmLI{`~DPUE|_LNeB-Ns8$cnTcGD6qp39X;{aWukd2tN4Isi^+qFoB6HQ zgMH4~TT7Fb^|4~9-GSRuXPfEHqWDA<%6pTJ_K0W8cvkveaV9Gu__hG~waPw$3*xE* zUBb0XE9rSMOJ|iY`?kY?eBn`VhAdVPhQ8iZO0Z7ErlH1LbFKeUfRJ0IDWE+6{xz>V zv?)y;L}-3zx3t5F{lAZcxiU`8YCP0VX7X@*K4@rU1WW1yH@S3+K4455r{WBNVjS@S zQ^H47Lq3>aQECCu%jn^`H)x|K+;h0SDi=2l3m~BqBXI?*_uI6#Lj%IS^|ix$P1`3Q zEiJ1|{TzUs^qbYBt-lFaPIY-pN7fQ+s*tjc~mzE!|14VZQZqAz=tTl0lPkc{FiHTs&P%?J~}vA{3~I zNzh6&9tzp2%z4pXC5 zJ)@z0eF5OM39a;oQn%*^Ba$oQ(ZYhnNuqfmz8WDop^K`;aWlwgk~R^X@_}ZA!IC1$ z_9A!Kz?Bq|z1TY;R6em-0gn`vLbF2qzub7&8?aJHbA&%APNi?0Kx^Bm!?J!ZCnqmh3}fCI z459ot!X3Azuu=ZjW?3&oXx@PfT5y?p`~FIVgDW)~LAnTxv|!a7Ln7Vb|HB#W+2nr2 z5_6*VjrfRyVqKOtfcyi`QD$tdHPnz^AH@l=fRnX0abOjp0jza#TWlwUXoAfv38APD ze7BimGj(w5B(y8kr_Z)zj35GY8;t}rH%^7dxZye1Llu&%xBEjPTq82+pK-E6lOeoO zol1yeR|iE>S_MV-zj9V2O=Iob!7HW^utHmx>Q|zRUH9P)G@*BUSxQh8@V~HG=1-JT z7Vrc8A>)xQF4+`hIt3+?Q<&rtflj_tNYlBj66lTmDSba&Bf@yMWM`Gw0y2q0WgA0UAIfYuXJtBl8j<138XHMQZEyA^PGO&-D@~Ihr`cE#Pe6<)1HXYj_M@1-f)$`B6Podi3&vJ97{)RoDiN>D4eZOyOt_7Eb z9K>;I8xQH2N&V%TttY_mk@yj{x26emolcdPqk6lZ9COkhUGu!93U7cmLeU089bU&1 zDP>P{7;Z8_evriTd(~LpBWq$~bhl=5=cGE7#ksdjsqJcg;}c- zY)HXVQKZ1hZhHPuYa)<$aFEbM|8A~X z{%=EwdMeWUl{;6?#lp8Sr4;G@hE3Sd1Sdw^upj~~WQ6V+RK4zaU2k?FDbAXrq2id) z^QZwbB{OTWM5ufT+ZRu^U;F5Fr{4D2X5Ih%YEk)G8|mnZA)$U5U0N zLw{FPS3@8S_N_k=#m+yGA7K^_zrnbDP<$zj)Zw`pvhxy#wCJ>PO?VD1F^?yl!=t&0QcH*wm=f%~ zd&6kT-n?lcrycwF=IuJUk@cAJw5Q15A>|c@8R4ksiltD(-MBP1Mf7CoN9RRPQB^{b zvWk{R2hADk0i2bk3(k>f-)UG;XFYKWU1>0w5eB*7^QV+newD`YE?D;57F{}f02_E+ z8vhEhe-kl9KN?x~b2h0iV0IqEvn?`e`igF6h2th{L3)DvS`oSF+e%k{54Ch_=En`+ zR$XS>l1P|J`Rg-j-i+Tz=;#k+qE-_yRIOo<;2y2lGnvho3Vo*u&V*qOsN)2bTQ=(4 ztj|vTAJc2?PP#Z5R{OXxu9DhT0<%kez)lqW86`H?5lAK z3iGN)f`$MpXMPV`iuoVbP%rK+8i8|;AH$mU3;|Y%Ok$b@!f-U9WBzIa>X?1j9K#2D zds*f;G!3;{gL+ED?J(4cDG2O43Pd1irNu)n-AGBUnBSm1m-mMhk_4+?66l>cP2|azIUm#oj;|E(Fr$Y^lLcIJk2%6_K({xPG2wNOy8R=Xy$*`SnEv6f zb&u$uYD{HqE8no#9=LARa%y#2Cdlk}@5|ok6_^ZArUg!u|17@ya)ZGVHbr+zFmz1y^89P<*YH z=@LXMtpnd=Ou$BW2Ei)s!L67QLcGVS!b{(r({j5cg1AE|jmvqm{ZF!Ois*&`_ZT$m7JuL7CLy_9^Bs?sMrmI&-MA_^vY zBP%)5-%*{|Iq{DA4y|ja?DWvfk-r<3%2wMvUf3Il8@38C3-c8HHu+fDtjH}fI+{LT z!drB32#43i86)jaRvF{NXv;L=RPhE3)|&aHZ_{AwT=&A4EM~0$-Qj}^H~Utvl8#L{ z^3?Di^zfXZg(|)o zBD_ILz-d2d-DVe{fhhf%cTAkuTFWZAdpb;B2>s`+5Rt#6vh+66`oPTj+Bd{anoy|V zyZ8fzZ;bK~MPd#?ud`{4U8ME!G${*3weu^HaCH8vqHI3;;W6zq4hrzr!$0!o)HayH zBWafF-qMgsQwAtdiLYyRlBQ$%XVIP?M^YmV%~k2hx2yl&H0ld8N79h*Xk9K!>G5C&`NwWDAkj0ufYlyaK$#;SCZQvSj1H-{_IpN%%W zcq82Xx^ocqf%DV<#AfHRIjJ2lcn0op<+%JjW(HBzBN6+b@_F?w%63ENj@YK}Ir$X| zryoB?a8uA-=a2eC_8ImpykRlC;r{QwsuHNNjwi`cU>_Y z*B2e`&h$b1>LJ-vWlAXT2~ zuGd?ag|m$01!iY9EMz-Cjw8NfH)wXoFjTKp*gDr#A+9yrPm%WZb@UtA%{HqB=y*wo zl)fiGiOCr=3q>tj2U<+j_rmU-FjHInP3O!I?HTPWhy6XVB{>Z#BSZ1?t)gTs;a08b zm#uBub`+{ND+XS&@ikZHf^A4%`b)bv-Yt(wky@fsO3dVNx z@Eg?|N5p=lZlk_U6|#y_<@O6cB9cNU8fjc2auT@$S^5jGA*NA#TQZ}^q3^pa)Y~4Q zj-yV_O=zWw(@X+Lksb3FE9%RPXH21OaTs9B^Ud$sL8XblhvUB=VfJ#4bm|uG*NK$j z4%P88N4YOI=T`+K?)VYtUp=D!MlkYGt2%+g=>w%EQ(<#?hB>3Xa?V>*V3x$78o&II)RDEc~-UOE^r`{^VJLc-PFegr0;~&H1^Xcb{%5(u+xk@6Kz|>e)cI zZW;v(v*}4dyWWh^cAXt!nqAN@hM)xtNns4?rrL{7i6!ueizr&l4j@6cWa zeM{xtQO*xE%Lsmcdol<7&B4Rw=Cvrd6pTudA z_4&{dxYymRtPDSRINp>h^)*Bh4bgcRS4UCdl6WfLeXT2}_n%Dw$LiG$GJPi!3nAD> z2IczuEXe{k!Y)JKrjxV}u){TFI#aH@8?ml%d$QN}R{n$r5o%1%jG4Au5V%~mnq6dn zVKO@);x?Ahi`3SiU>E(;>g=Y+soAnNpW|m4p z9uC{f*M7y`gOgN_K}wO0l+c>T!9>$%2YvpEc!F{9)^tlwNfuoheUjdp_hSpKa?Mn( z=xnBbvAudpqwm*}k2xD{QrG?n#!ZjnSX|HoC7~LRDPzlzmf3r=s`a+7a)FlxEH0GV z;^okm8sboxUiKmFZ9Xxobhh7*Evl$_p6}_^#YPXz{0ND$yML};Eig>jM!6x;6Rkvh za8FV81^v81_k*(1lOWkDxj2=Bbqcu*H&T?0DSR5bidvmm8PA;!q8k%Wt)od?XkhAk zlk!@N$LkkwTw+SyRJ>OBOWP;AijAR-k5;aEs1IqB3-=eZYpgc#ruqayr!lY`BdFpR z0k4!7F28L5=T7B5Dhi7V7S{6_rD0Jy`|%B$%T9njsA7MeM`GwT>i+gj8E)0rR?wpy zsrh|TX`^g?*%4Yos;9= z1QQW%Bxk|7tozU)F&%Dgo4QMlRAV@#rAS(%mWyOmwI*R(it`q5Ijd95yY~WVe>VnD_4v~?|}gnrO5l) z(ki0u56ep<8WPn0#sIjoxwgb^`#Q4i;mE^=(LR;zUp_19YlC4KK;*drMu!GKx3}ck zB+ywj&v(+ks+ypd;{sYR1S)DZZ+ZRgG}A~DeDX$P0thrBem$ya+8&Gw`svmFpU1iNWQ zXt?m^jJrY6$)zr4QxwY1Yen#NZfXnXKW7r$4KF?FxEZ?%o#b+`xGNo`k( z&q{i-Fc3j+dw!$qa)OD7XU)5$ZN142qHLc~^(3iUnCltsc_vm@yz2}
|R_XbiY_7@p7Qx{iaX3HQy?6Va|&M-FJPFX2+CfE9wk<7uFQiaZ%#mxy? z=!KL?Lsxb+u`}JWX(N)_5sO<;^)dN4H4>Ar;llLCmYtIHI(Y=i1zypeH;Dp3_$^jk zi1{AIe$A}H zJX}Q9d)A03k>Nu%vp{!$-8xoAfxb@uqEn6WYM;i#@65yg%`;E1Mq(d2n{vKL;`xwp zgZuBX8jF4I7}(m9J%P4uU^`@N{C^B*|lpK#sc7z3`K^TYopuaG3 z*EA9JOdGa+BG(Y}Ip9~bQmiRP))c-nY}3U8+u`n` z@URk32uv}?v9&=tc@}C3Mr^szVQDL0Y-_GNlGQz*CR+O?rU_Z2S*P z4y$(cnK=DEvZ?;*IlGnjuOKGQ%!9o&5~~GitKIb6=Y*V&EHS5wgj|lpxK{YCPg?%0 z6Z{9ur0eL?KZU>Z{W(RD;KCwJTvLNhzqBmv!ZyWN-jLBkhczE@c|Z3evGtdNgB-XN7|Kaf3SHPIP2yZXSkGs>3KZ@$CPm&eVk3^Fm~T$!KA%g_kVe z!r(_0=G5_BkF0|jWi#g!Ou-DwFr$KR(^ii={Y`O6u^Z~?)y7Es}6k z44B?0Qh#(J0zzy?yze2$@N*1VAX@>erT@%$MdlH)RQ|kX6invm)ALA z5AuJl0V$Dq0{xQk_<~yOf)7Eq=B4!gSl4!6i1im+#Z?`+*?W(Pjvxhp)8qS);F@Y&mW=-$RCO*gl18?C-XHN+L;q4wJsT zx=8EPd^Znu=7_f{Hu6PRDCeMGHh3(gpp}H0tW*&52E1&nhojM_8uOv;S<@4JkGUF| ze(t)(W4rA>B#No}@H2R(@#cBlTc8&;jPaVNbBbST4q*I+`z~Zjsdx$(Egi+)Q4odu z@~6?bO#fCbd45vL(#FSZ(5*+8*)#^if)1OkhHRdfd4`NZ10^mZPrv8qGPULAU>-L^ z$E7s`{yt^U6g~39!$sLfox(c?qU?W1YtzsdGelO7zOy1_iF<89E-EV{hqdVp%iK-a z6rWc#8*o@x#j2Gz@y?B|cvcCfvu3-My~k@DEuW_FPCMPK4CbgC>UBI$QbYC&fvls2 zFHIbah$kf&|CQ6Rf3n0nVrL4v9em?|@UbRMI7h;6ymwg5{DiSHhT}p9u{|oYd>z97 z-cf79HaNFX&k0ogZks%@nW!EdgwTX;p~~pub%Ib6uKF`nDmnSH&97OEsCDf2jxGxK zP_#vu4zK31yfQgISQyWrVuCV66I50|O_=}B>*+oWnrXqkCO*GPp=6`Ro9U0SnV^=4 zdMF+XT=@6kFj?DyQTKt{=!k_W3uWd0ja;#G{=Vkcaw1C&v4`JD3qSt+mQu3G@5stc zq*q;85b|IU%`_`FjWqpFHcmm3gD`SQQN{gj*oY2nPef4GdPviyIEGBWbtIPRCVYN? zU&M}FwL9x^3EF?K>V=2}E)*FSho8kX-h+%w*; zb{VXC2!=}BptL5-t!C_J3_srNKP$~;u+mIy)3!h#UWnlEnnQmSS%Fc>vCqqJwLcoj z2pL%D9GwZ@TxB+Di_*$gR&)z9mkv&*$J zu)Rl7$Y??=c*ZYDSv92X$cdV=#{Axz5 z_BJ@hV7((5ln87HC`(@WGSdu)3oXotZ(I{uxB%Jw!_6u6m1}ZJuTu7dBKMWxr|_=K zj#n4AY1jijn7?xU29;WZ9P5y{mb`x!dLB7oyaRd| zV4P7KbS!>Ue%RhZKy>G!(4VQkgsrWum@j|Cw7jy$WB8Fsl>OAo(Avje79cJl2$YAW za1wS?tU551J=&I+CqYB^He;LnXB|7Yo@)0$p7Vf4{>1lPwK)^Z>TLg#w|)*wQKU-a7 z9Tjtp^J1lLzPQmBtyQHa)`s~mg>ezC#$Q;%`>W!s%y5?*?#!nizMT5`-bP;wp*|>O_>x4Renx}NaW_Hd|G}%`4ap1kHlXt_s_vEy;VK990R5W^erfba(te6kTqibk5{7oSF>QY6y8T?tWR83}<2RiNQC zoN?iNT6^ZM_NqEk?41DC?vW}s&&KWTxj(vl_vj^r8Zhn#2BLQ4DFUz;9Ed$1j=LYD zq@YO7*~gCo!#zpNP0{NFxI2AgV?-6CP+6M++?n7#CH5@VoYbeDuZcR4Qdo(9j7}~a zWgaPuyZi?xh(_eBkG=0u`Koin^!Y2BAcZq-{TBDa?8#q3M*kd3JF~bE4K8d!T3YaY zmUw?3*W!`BStUluX@CM?H5MgsYD5*VlGe37T05Mi4n%jqQ1$#3%R84}?xa^*E7+CC z=wPXWV4c>@R6(mvaiisp>&JG7RjRy~Lw<%la#La;&D-#gbPRY+lx4y`LT|1QhbuV^ z@H{g&_1ecN&izr*&9fvzz)I{(mJ;r==I{X=p3^{N8TA~N_3fv3z=LIO2|d*`6#Zv7 zQu)%GI}$iI;tzm-kAg`iRKiM>l3(c%c=_#i>o41JwjX_4_Y)FNT;Z>2Q=xQw%yBlcc#uCh|sP z2H{HJ0)v{F*QCF;8Mxp0*nO2;~18s&jdJ~_@+5Rlc zPTu>-JT!mAS>Hi-uk5wO;+H_3BK#NFmSAq*PND={Mx(q;rWJ1=y{dCgXBJ;%J1=8H z-!e{dl{a=l!cVJS?b-{iUKjDI=6d;JS%at~A7)$2`NUB|-dd{9c6qwgO>fPXe+u$; zG^W#QwnrCCEah%y>ZnTCFMcjNRsG$?+3{HZ`NHUL*8IKBa&6N#D?i+buFuilQbf;U z)o1~PT5Ba<);)imx67H$PzKldQ2UKwPjdf?hvA-=)pFv{lPfJ)Z?jwb=pKa6X~Hj8 z^h=?&7Y#oaTDwTx6-es|>c?vYG9J@&%AyyHI(_(IhHwArlWgx1z zUgI-OTyFtsO{Lg!Dbq~O{Kl*2_&0RSXeUx?u$^bz>3I99;H)%Vo%VyG(NeGRNb9f1 zgz&=WwqLfl=$!Yf$Tf2#%_a}-J`$=h-vNP|Fl$^ABK5|f&^P#LkLhnm9p8YU$S7~;U%#Di*2C3P2utr!%-4Q!&GCej0ihd!lj2vUQe7eWB-kUz zJifkJBG~g#i208sz}1RqVh;un>meI*Es*WyEv-_*$daGY0)@b-{s$HNuC!68kS^(g z-IaSXcO8q%bq>l~?p0i+;s-$-QGn7WB@ytOrXMc7*VJ9=iBBS(AdCXC^CHt?jHMpa(tfti@TS@jlly)=c zgK9bS*{wO#u#y)BA0{#$s+HGNeJjtyi?uy3kNF@MV^?tM!&KC#VV7TXZL8#YljIR_ zFSDR4&8gEs2x^>mC4$iqZS1pFJ7(msU}Z45D9SpYV=TK%nEkzv?Q+S;bH9XN&qKdF zHu6H*+J?)8PnNe8qjh?z)5p#?H8wG0V+x)j0PSl~(dEwWMCRDpl}?>DjLg2+^2IF` z8JnYOtWVp05dmOH-$TmzW32t2+cs>W%~R&A+|!k&Mg-%a_;nS52;;u~1P?=WLj6mF zVUhLS5+k;fb&Y#ky%U=DBXrFkY`&rY1bX};X>4Arl>-;>`TFlgl7{iu4X9zUPHy|M zz2i@~$r29r0If&ssG6bUGgFLBxba@VNC~nRWj&sJm}Jf2jub=AJuVSN)esJaZ8>1g zc!I`Ls!t!C$S1WF+=p8}B!(w^p=E_Rtv?qi(z34LrD3=FsUD@U9yH>%nn_Z@*2ci4 zif3oaY&1*pqjkd{3$L(?BQwuu4B#~`TxfF&4wI96Qt=DSyO49lY@-IS>H1zzJ#6cI zci$@x2Xhb(fT`E;a971<9x1@e7oiax@gmWYWYDb!MmTO>sf`7-`!6tEb<1i?>;Wu| z`+NThk+7RwL@SH{xl^jXCI~RqQczrPTTtOPojB zw(?g#xYt>cae`7Vc`0kf5}GWZ0b*#+@v3Wz%l-4&T}3C;`9ElSb(=2}g1WFy@=4VD z|2a|s8ZuxFfKDU3<1h7gS-9^4m?rsG|00Mg`k>g+?@-7vIry$rSu4mL*FJt(>lJf- zui+5wVH*-eJFN_n74&~c;+nEV1jaB-{TIpbOA!^G>Q*xPi?D=_E{RQyd_VXtIiR$! zw5r3pJ{dtybFx0K6s5pY6B-uNBHTgNts#tc4dGy^$xv)N-)6J0^al04B0J9n9xNvaQ2E3Pd7MW8 z<`!>>Jw~fJZL6{7NrQJeIyCjZiMXDOoqXZRa=Xa-lG43^X7uXf8`EmUWX4YtWFtx> zoxXm~CL9J|pS%<2ai$Or&vY0Fm~5l<1t8KIXD{^A0@?VNo&gEDnTqK!xj!iEk64k> zz$k1C`e@eY`S4hCb#Y9R`TG;2w@3fn>Sh7MTSZ&n8FQN-k`Ab~M+J5{vlG5)NmTgO zhHN>L8fjHOks$x^rF9{c&im^=XY(R4STauz;v_2^%bSoOe(IjX=axC+llXVpClO@$ zKcw5}l7*mypF*w9QAhW@^3xi!>DBbUkeTH9Oa=4Xx_19BsJH z4NN&t<+!v5FGn8Ut_w}C_RN>nnN)(Fp$Po^HMVgmUhK$UrtCC!Ae&G`=CS^CGrjrd z&+m*zwS6;sA0`=`M10h-~)N4s|{XPuT7b|WY z^93$Kb_edu(WViQZwh!ieUVOXR~{Pk_eN@-Auj$C}DFnVY~CJ zB6=h~p7?+a1^FRTdNdKKaW zQ+!U$5XT48?yE4HEuUcHlP+;TTvyu8;px7&VO>?@w0T_jLEKprWwzta0PXt6&5m)N zlXfkiO#*rU!9jn8dCL4(J*27!%PoWZucoUt*D4O|_1%R39@O*`M_(Cp7}@%aV!*m0 za@$V-ZNt9Q*FD(Ib$O->v0Mov@?|Dnr6I=0nDb#yy$w7J6sPiB7IM1O-bY1ny6E-$ z^HR~LHAyc)K|6eUH){EAB;}Q@C&q+nj9$Ts-+U zYt4N{dsCpp~5U+)=W1k4LV9U}=zn{g*m1Vc|J{PuFQWE57mPx)Ddc zSxyy|B_Pfwk%u&Y&rNk8T#Ya9XW)^qyWj5RILX=hEv>Uu+a5vSnTHQp|UC#C<_Q zr$Svpmp2`QzIxd&CN2k}Hc_@^L+@vg{9QCI1(lyUT;+v|X`PC*_SKEh8Xsz2=(ceE zntkRiIdc>sdW(tq{>kcDc~}GmX?gQZi{t6onD@pWv5Y0-!39c~o|K@V%lm(5X$=Z6 z#q#SxI;g6>@qjFz`@v*cFq1^61NL(pKi)-?V17;(+PV{`829bZkx-8qeWT6F{WTsO zNXk-SIr8uk7iwFV;pcvUaf|U8TY5)R^D)&J=T=0QUlL z;^&IP*G0d^BowyjX}%t}QO+D0U2Z-OES`aVsUO6a2=-gSzI$KNEy%A&KR|M&BQ*TXYb@?f{8Jb>H64`~io~h$)(rw!o)dht;qA zjtv-3<~H=U`soC|cr`_n$E8K_BHCjaD;@~Y@E%yN0s`$LFGaLjB1m_(LK8zP$A$k( zxCxACN~XYEKh3LXi7{NW9>!|<`fd0U_xp{y9e0C?cYIW;=w?^V@+koF>+SMQ_KD{E zs#2vtZH;Z2xC3y;j!ZYq)6~Kh&WhihEo6%;+lGD>uS;1D?FIvC zU8&FOJh1jog+qjc>`5VA;4m5r{;H3fkh#CMJC2>8tl>8^)?$KmcL z=w@utIF&^;yTkPS)7wM=3Qo5D8C=MEw)@l--!`C=rSDDj0jX^DLZ~!|L&Xj*{CKBQ zk2=Ble2tzE(exEP-!#_41X`x{{!y0k`o=GNTE{Frw?t&r-rJhsg^S^8?a|^4oyDn| zb(#8Y#gzYa)#3_Ik92wED7-_O88A2PnHGn4X0JF4dP~~!+j8iqCn5b^$+(mg`{pPNbwSRMy*kb&9xtsaauscm;>k+fWEo5c!-Mm+jc!wGp7#@}R5H zYxSxSt^Cin*T#76Y{^>v*kKN70XOO>*p3<1zG@Qsl z(*{R<+v|qcK@s!jdNo3LX?~8jz2f!lH&I-EknukWQvSO{vZn`^4G%Y8mWFe+NAVVL zJM}$Do>7f*+rj+VZ$ybVY}wk+MsZf_znpUO6|{L-5oZmB6pXZ#6Kr97(B+!c# z>fSamI^v7G&Puc3*-lDKR)rif&-%U56PY z$fuDuYx!Ewc19Uiz+PFqH_hzZ)Jp(1* zb>#Prd>OK0=(ZT%y!o~GOv4V7HZZj}Z8HL82ii{?beh8-@im=cwAxgE^qF}jOJv7& z?Z+#NO%7t#Lum*s&_95%WqT{p?LY+BT_#+80+~F1qH*eI={GDF@_{h6g^`Q>a94E8 zF-)N7Y+*|ZXa#SR82`SG8;QdyF5568?#@?);(rl7a(UiwS`~?hwn%IMrTtd_Y*pcCjA4^aPf>#%ad7$ zIFlZ|pefRDLm~55?u?5*uEgEXIP&8|41GAfS0M4`0esIG??KAoq|3C*Khu;9i*%pf z{aCyE`c^B^1m0KfUCtM6KH=d)>51Zpd>6lkL31rWF$s)*zNw*Hq&sZi@Oq%&&s6Oi z-^bc*ufFxG5-C#JnOW;b<#H28BVD? zokdF#g-@u-{q$S)N)CWUS3O-IH%(*>%XZT8;ESsP?6 zOMYQJY_TJHKMKP!Az|-w)Y%d6Grf{@`9e(bAmQt?xu@l>PIU}kjWPEA|P0 zX8LAI0dgJu0W4~L-J!)T0!9j51+kLQdjE_6V-KlDJoUopX90t3GgW zosh7IFY!zeWQI=h6O5Go9ep%gwir|crv-=XdddEj>K|>=l7S-9-{c+3U&%rqH$mBZ z8J_q40%{Y@c#`aa*FJG(m;=jwf23>iOQOM5bl2m`kOirCIaWnaf|sP9zzfB73NH-e z;W||A3bwCK&0 zm8Bfv0n>RfR|O5CigCH(JG_vo$e&U`<{Ql1LPf0H%`Yp=*18DXKq(0#Js61NCG!9w zS((>QUw(~^%(F9OsDzGg`+zzyn)>?td-1aDls?{>kcD03)W?u%g(|`Ywcc;vd8`11#td)D(r+ zcm~mRPgv3^5lZQ0fIRpNs$L;CD1*QX`Bu4gvpsE63bz*#1}oI^d;jOS4_r3K-yeQ> zxi?I29{N2*B#~)DMz^iRSb+r~8vpK;4?;#9Z14KL5OUFNMkl_X9(_lH=;_O@UhL>a zRZ>OV2v43!e*fzvTi#~cdPrfJj;icmvAlc|;yJ0}IUSsu)i~;1icJh7HbJ1ZK%Gf; z+FD^~gZNYZhUj()Cfp6 zhfI9(hKq!8;9V%!$F}}7^r?M{kFV6--89gW}oDE$1C&kQFMNY*?Ms+tc>H(~kvv+cMbE|IHl%UQyz64fkiWAaMCc&1e4W-T@ixJ*}KcCLVrGT`)#X)D** zp6UFv8R-HzgqlopFGK#OIXE{+gFZ^%#=GXG+Ko|UUX7GC;`Jx?9pQ4(CpH~#Y6S@E zzs>bclH@eDrkZceBM4?R0Qk-ejcq9q>?KKv4tUSNPES8Mc=j-}&->`x&Xs<@c1J&P zsq}^SeJ&{(x<7CDCKWHjGcU<_SUul(NXv@)m1No~JeiR9?#Tr$85A6_;Zf(Um#p2# z(EK|kb@CZOrr1Xlt*(hD(i6m=u76G$$VnMLd6E0h#(U>Omnt&kF-Z0vhF*jwy)KWv zF?969^-9xO0bwPhcIL{atHK6xE4@s?rOgu37No3@(XXwR%R*9RhXIPFJBr-j7Yptv zf9_K_mI-VKex02J(9fesvdY&;BOX?ld(JLOHtA~8TfF#FcTv4(MHT@V$_ecW@sX~> z9pZomg{T86g~=9Xd7-%u=I=kHT1HNo=m~wzjLwTTu341C=R`p0ES<$Y_ObC`T}>t7 z3A^LvSz+d#Tn3rPYfd(3V$>oD!Zx4O!;tU(et>Esn4{F_SK^gG*(7mn~yo;W>21gz>ONJs!~YB*ivxIm|76}pXEJwJvS&M zMCTJJS+ z4mxr!^=b50-Umx)x~m|QPDM?B>xQ1NM1hH2>EZI?z0K@^2kp%#&AokUfOlo*UX&Kx zdDH2wSbZlWMBBIBGZ9FkLbSijoohYX_(B##ke_lOQku|}{pnAL>^)_M;D^e=vvhov z?|X=BZLvbj9yN!)8#^hJa}Be}n2kt$S;Rdc0@rk#`!P9{3|)_!3t5C1jtn#6Ksq88>JJIU5N4_3fOm z3g@zl4I~iPE>cZFDyqKCZSj5ux1z9Iehbbzpzauifs&6TjCU^B6l_KkW4uN!7>2_ssW9U*2CcfX)wp_6Ld(Vc^$(L*e%6tNFK zV&IG_*M_m!vS}6@nZ^JEw9S-$Q4&f^<=Sz3Z5GoN8Mi8L+h!iPjPuRCn8-2Zq|0$0 zH8z>#$ZXu7F@@>=agWMz?ASm1NLF=Mk`>t@Y~&kTNf9fHfiV{0;e!1sBX4Tyvk$RT zG<2fPwU2BO5=eR67_I8*;BUQ>^+_6`60i3^PJX|lE^#H+P=LP6H1c|X6m88B4T~o> zm6TPVvg$%$%EhA3aj&IU%Avo)ScXHFdk&}wtrgm$&8f5ULa>f*t|Eg20bwsov_H4o zl!Xpk^QsAW;j!fBl@)$aS(#IR05zG2H5yZ08o>!yEel)Y7~2>WJa8hZFwp<#{E!=b zx{*U6OT!kS?Gnidw_a(B74bQ(Dtq~V1c*!Lz1Hyb=arN;1{ogSwlGqUb;Q2{DTI~y zY8yY0(t@UO=O2?ivUGLztoW4Sq`AtMXm~qHSHVwI=M*R)f^E7*YK4I!gVT3E%X3=p zUlF3&>qKY(R=dI_vN4Q5EHejF_^-wfhS&kJEEv}NT){kW51CY0RpSD}=D`ES|e*)xcR=V8WVIEQ%!eb5+Q zsmCz)EjbO#O#`W$o-_%d>&tkBNs3+TzeUQZ#k+r($^W$SOJsm#K6B<^a$+CHAetKN zM}*46I%sGN)lU~0%0k0lvS*r5A%0i7*kL7!1s%eefjCP=J4}kW z#&=~mpb@FFd*98U-v5jqeE299C(b+3ojWoy9XoXN8a45i3+_875^e5QUG}0obn#8A zEv_cpv^x-Hi~i0zZG&@%ik?5>|COM%b)vwGHXhtUMYDI=SQc ziHv1Nl2FYqiRp=Ay|UBuVW1bL9YOww$C|Hb&2{gSy62)RzMp$1irF|DvDF6Yd*D&n zdETvM)emVo%Q&vZfjsQ8L0Zn`iCE1I4b0ZAA;y(AKB2I!ZMVy&2{Wtrr`I;DuZA*l zg7K`n{r$+p8S6#jmBPvOS%r!sPR|%Qw>~MhCkwhf8p&%$$*HY0K2>GWCCIp`e?uBv zEk?z%s#@bjiF+v0S@OTI+`5y?kgE!WaQDtdwf~Vz1BIQAyrD_>nD#=e7Zx?~h2btzew?whZVQi4*;MGhF4dQqrv8zGJ6 z5=V3%mz>Jt-YE!}kb>%X2@rq7hr%b-*vLCZXn}@#jT`;9sa^;N+&Y-!E%*Nvy3Z$s zb^f{hn+0}9eWnB>km2HEGYVRA8pAeGHwdLbn)`xUG|K}o^3J`VUmmC^;SvJSEl|$J zNinMR$eQv({@~sT)PS{SztHODkdlh~tCYKD897Po zQ6i@tp}(lWY$N)eC_@L0Y}Ri5WT&)1p%|YbtXbKHioFH8KEfC(&wnZ>ohKy_tApz) zy$aXBTS9@H_GV=VAFfUf6rE|E-;>-w=VrsVlDPbd1GfjxZk7os$r650O-M45Mp7M& zCC&$i|t*ZfOLz%tl@?w8P z0NStDW|dj*%G7>Oxg{zA|9bHYHX!V<|87y=Xd7CVZnwIBX29=<7MJ_JzWAwa-17=} z$#l({SXTWEH5J*_k3I`{ne%=_X^Pdx$gGi5l-$mm2^wGRh(+CNrbYZMy<<6!;1IFv zJ;&cBL^4Bu6b3IqK2AlgeiuKPk=gP3m87@X65RL>;dL_P2wDe(XLT*`?*CkyZTza; zZsjkVxO^C+uqHN%@!*O3SiF#OrxZ1HarM-oJf@~%6zhqQC@z4KilSd4M%?>EcD;*F zi#@c@3~Y~Kv6<_b?i!?_0S>TE7B3vucpF9F_SlHbi&oM5E0eXcg|g+-=%D^oV=uVA29S!HYumoHteyn!p{%0V6uK2?(*Xt_i| zA&vV0?-Cc?fA!*46@NrFY9Vc!0g3cvZG%K$=S`%E@I}B-)lSL1-|E9A zj-KT$q^J5?ez}#Pp&oBB;i)jjIb0K&!=0qry0M@8tO&J;m=-p`>BQH80y}W;17dZk zseDQbm*}g03b@wzZk`_wl7Q5;E>i_J!+Lp*#;pV}P@w4y^M_|5Mya^t57}wMCFg@I z{O)K8*kN%^<@DsDJE^F~s|t0~4xkCw3yGRYhj9WFx4Wc^ApV5$F3u#tXaR#7tk^Od zLwV)Bp<1zj{E~dNuWkwWHgZw;S#NIuoV9?|C8)gz35uaPz2TV(xBIm#Jnwi+>`&Zr!^byYQ3tmh<-L z<=*UL$j-AXGVw~A5U-DHR-@bkin&9IMY`X%x3^&;Zz%4vP=8zA0rtF(3M5}7TfcBs z=xTHYd+F@_xhEyZ9kce+1~WV!d^6BGG_A=8FA+C<{c4xu zOQOX6-Cyz8uZ%emTQ?g4?ANW|zf*3hvRG~C;H1vY=qghi`{wTMNm2#sE^(<+)-fX< zpg;qzJP?$wS)Yv2h^`#K6|Q!06`dWMj=;)PabJx#RI~2cJgUd1%xTs`fi>MuA_|yL zpJ(H?#Ue5xRdTFd&R~|Xd4InxlNzIQMWM*Qth{{9sGZ)w0>)`)*R zz@Mvpzeua^mrmpTSL5hJEKCRr?|SN3pr49>urRGW=d?7t4X*Oqp2NC!OqsU&v3NE9 z{RBfx@()MdLGpi=G!TG;W%y7w1PTEH0s>)@f$FYwE8=FeNpWetVe)7C2PvT}UC@vr{y}xb5SPSan8R~&P z6`+>2V<>y{dY*~`Q~Y3siLT1-#TJ65No|+ne~1`1DB8ov1+fz zK&OAX=2ATxCjPW~?BLQoO{(~;A+6Em8d_n+2x|YJeq$Uzx$;5z*%NSD<$PD2xnp#a zN{-law=}4nY#IV^+NHyJe{$hCY!So?BP+71vk|0R>pFW8wj>W>^9>ljui}!KgAHvz z!+lx(D^YipfAJE+v)4SCP6sp2MjbWj_<~%FBKum&2(&vxe0>i$Fi$_xplSeGW3ppL zlbO&{I`)uqY)e0Vmxzo=@Vi->KtFQMzd|DhuC*ji^qZHmng=~PZDBVoXYCT8;V{g9|ZnK8O6UQt^c}GM(Ps>`={UkM8Bq@=O_cvI11)EN7qEt5QccH~l^ z7*HRCR&}($iN-vqrKi8QL!J*{fYc%n3(coiCYZC+x3IMT(`L5VoyG1O3R|93u$M~K z3{YiWH-GM@q}|NR2?_W5GcJpW44vtC;Y>a@`f!AY$U-g-1EPb>C90fI5({sPuZ_h~s-b(;D?>Rd6#uEw}z>cw;o zI`acZX{21W1P*~$!rR`;QkNeUR{!msl99MI7e2;xV2#1jSm}Sl4QuvD!KsG{Vs;O$ zfBwvKwt|dcIYavqjnM-q(itZ3%s3A&SynMsYybS<3lw21a!0VB+J$dut~kQrmqYHu zs`8^)mf;b&M+9D_$TkF&S4=TxUUyr+auD zp)=*yf6&wPEC{!Waixy^LDL?6EBd&VY8*}vY`dQ&%dLT9NzsH{OF$9K%e#qIskW%izrQR_zW#pmtiN7+Zd{tsri@BSg12%( zbmEQ9d>je%{^3gE{)M4=y}zc&zl2G+P6>w-K#^Xtz)ejVl+2PG}F+&NsS4-zo40C(GQoymXOI${+sic*BwDAltW$ zR>n$d$SCv;$NgX?ssHq94RXal{Ey^_@2@=d+=2-D$Ag*zH!YlG@VKBG6lMg(lY4YkJntY2=NGKwm$7v6`Zx1B0nCnHr1>H%{`> zKcLW-*z*e*A9jnQmc4(}T>y%wyH*XTg)+tFyH7)uuJUTZuJv^8#I+}%J`_xTa7*XL zHY2}Y*2i}Wca>RrjT|ZN>Tw)?b>7NczBzw??_}o+VST_*9RY+(xLOsj#+KOwHpU-c z`Q0$f2VP|1v{!e2eOc0Y@GL!knc`mhtt&4|%k?Ohi>_wJJA+ITog(VwkG0E%HjG|7 zPncKV>|3a=K*ec3E&jQCNBH~a|2lZZ=)eOIt@Hn*;UAi8GXH9f7K&`yI13>9c$b2Y zAzFwSSflvHxFhd3qY!-bkaMZ>wHl0_0?lEU2Ox{={!ZoPbQvxYZBGFLmn%7ca%7&YvgO8L>q=r zHNECKTlO-e-=cs!koe7=ohURu^x!7ymR;R-?{-)=6)gBE8L%J?_++(QB_;&qu=|oI zB18RX*QdG=CP@{9bKAE)ft}(ynN_ZWI0rcLg*4$uMo{2hxgT5LEsYjqLJ!f&`T)#n zx6q5yIf~Jx{-~nRLqG@;{-}7{DULRbikZn0=bOs@6Nt&ka?u_oC3!Ijn%p}2^ zx(iEzLV}wIh_lh=MM=1V%Js`Y2ID6E!~$$DKRDT=6*MZrrb;>al|}Unvof$ve0Cg_ z^UmvQn4{l~IO9V`I?bD9=FORe{_k~DWfv{QI>Fn2{`JuE;#tqxbySQFnoAt75w%+U z1bJIZvQIVB ztRC)2yP-~v&YeF-9S}`eql&Lv#pXqkC<#!jpLF#Reb(nhiH#OoE|h}Ix0bZ(e%>hD zns8@z3x>*NVzma@X)!HZ6XPOF?dP^${Ak~m9I>;*aHFPmLgZlQ<}vk+^l;P<+zT|1 zL#HzeYnhJ!F<4sKG~561QWo?@fW6Xr*nq0`$;uC_mBSX{hUfV2dr^aML5zv?;(k#b zkv=jkNk&%9Px@4r2H}zUbI0xdTNX?ozH-tLscph0*2b%Cn}JKMG7$yDhyLr437^tZ zTyEn3@dYmGD&2kUm?E>~&y5!0f?FF^n$_*S6iC-2i)bkqd&0`;(bG!jv@EH$sZpYz z-#+@Byf&raIxCOs6u zja|rdrI8Gg^!E7uWhP%PfIo@TOad8r)8;tCz^kQm(pf1_BPMbSX zYbUCKxkPe%)>OQW95P1nA-k_i#GK}dpEUapYxE_)e8Kw;C9m8U*d8q$61najI2 zL`-nDXKINW^_E#Po%LadB?J>&67S^e`qC)IHx|yt`wGdWxu$ClI+N>MW^7s=`c{c( zS#41MtQhR++m1k{U=g4AFb%&8W%3trDF26Z@&6`z{=Y&edI(EWIU&&1-Cp4lwV6X+ zRj=Co!=Djnb+vL@FXyeU!7QJY>b{n>e#*S4IOlW==}t4072&#e+ck0jr(7PR#E+pz z4u9t!i@#8SzYjLC2}%M7y;hor0*NJ1BltJi#UrP(zBK+ab!#3NOGUL^S2yL^vq_X# z1Yuqay#*X}+)f|YU~=8E3(R59$P-|4UEx-{OIEZ+sIEe#Vd(%DP5un5*i*L(?z#z>jkHjlM(7DNj2aN_uu8#*QS zU2p$gWG;DVk6VQ|QG&f(CyoH7s!qB|WOE$@m3r7hQCF(zHR!#%$xt#$38@sIQM z7Z*KVzO>_p^tb$?tZXxJwLy7CEnPu_z(8-sw52}ba8F8UJT4T2B1>iZkCh;EP*h(I zb*Sbe-_~`foIZt>6Tv4HI2c1`>_q{Y;0`$&9wbdCG^nW^%e~Fm7}+$ug%z< zBaQjdwkRZB-R7JLN>8rvu zsXq{tq1bQR16Zi7f}}KXoxN6WE&#C>yrP2?nv zKFbiI0U0PL5IGwfC|Y$hwC3gM2tXPX1sV^-o`WgsMJm6z-}k1a3~7mw)98gfBR zNKAXwS`~PDhnnZ2?8}AhX-vTK7RK6-1KOt*G}1>-`1f%8Z^uXHF8a`2tm{Xt!s=m? z`Q)F%i3Q_G5A)LfY#*C*`ztlBHLxeJVH?Ez?YvQsXQ_E(w(M!R&;_L`oL3vA{OWUF z(TRLK%4g+hFc*-}c={#H3s-YSPlpSTKO}x0Ok!(3l|j=$4~CJnvg1K8#kcMHsb!nT z>lvzHZ{oQwW|ZKXW-?YbESY+D*kL#Cf`}I5k?JD(5NFFPMNKVtXT<15PHEVt?@7W| zIGPypjb1MCsNU_>JGqEgex@P>1>akog~+G3NhS8SdE7tKg9q~Ltkb7PV#5NZknl+w z=3r}q5Ogr@^(z3~c^`ya4PqA(MXuoJ{WJI=h zCy9pS$>e|Nn13d5ck;`!D*PePi%x8LS^V~$Jm(azuC8jmeEIU;kCzw8UXh1;Q9nc; z+UIq%%caJI(Og7G90#tZM-o2-fOP`%vgq2Am`m2 z)$AyVQt6r_igaD6Ekq&jUTCXeCj>ks5TSU1Ah>!#`fAP((HP~7Dd*p1ojI;iDDGC7sJWuN&Jwr3BO})TTw0y>IIfCsq_;#zeoRCE!wz{9@`P@ zlZ*?iNq+TOvG|7d#&xC8mTO9SY7hh=xgX8*r?97L5T(dhIaIH5Ahx!v3Fg-+4UyUa zA<%eyTxn(iylX3rFCu{}l>qpBhlYpCS^QnU#?pmo8-B9o9Adfp6d0PXH{4Dr<3s=@ zEI9SLQluvbqzo&Yr2FG#CQ{M>5V}5Uq9d33Vfw}eGBt+DURfO?pnQF$ ztz31dDI2tn^g(LN3UQkG_%PlLw=zg9TQvZ>Dh-Y2Y&m8StKDM^Omwrjdr7KpA)H_` z<{nA)!eB4TuxM~~kF<)e9`ICaOrMne4tf3n3{jo|84;6T9p7xafAc!{83Si0;8rsg zVUQO~+88O*zZ%@^qRFxT4rY6)<>k-s>Go-TBf43Nc31}sOr_a|0&uaO*HA%_Yy>z7 z@_&*2y${r!O2ak)r)$Wg@ZKo{#5yHZ%vtN)!&Abhf$*3&$kmf&$CjIrGW-dXF<$%aYiSCyr$Kz32Z_PC>rAQd&6+6JXy3V*961&)LCsSI4mz<+FTW z2vTAL^;s8!C zc<^eS>+zoZr$(~}2+RHLq!~@|fFG-}$vs&K(7j{UHp%p1!=&SZk~q377y#zh=WmXo z2FI8q^L>y`FabDgf~y8Zpd^{-nm_#sJaQFdywGM!;s=3{y@I?Q$BRwjecv$<{}7m~ zQ|(NrxGq)7v`p{#^MUYX*_*Iz%?j=|!$_7?xyE_t4~rfXU0R%qLUDBqGs>RCL8V6E z+XeUu7lPjF=~?k1SQx7TN*|y+n%wf0Nc=+O{j(t!@;czuKT8^RvJc)T$TTeaHy%a>| z!!`|n9!Rbbumvl|_W*;W79#yv{76%rj9rKSt1D7_)t%rbgoD~|F)v%&Ym9HzMq}rb z+8Aj64Q^5Y%)@s8gCXL0GPp~N*Km*$!s3x@V%RkfDmi)f_(_$Y<93L9>=5FQ5H+fx z9UI}JaqG}W+z@b&ipl#ykfOyZKd`4Z4=YW6LZ6ks&uY}82?tlDee${;Y`=w<2Dz7tHn&0E)Ν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�uGwx+oW7l`& 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 literal 0 HcmV?d00001 diff --git a/docs/_static/itwt_30s_current.png b/docs/_static/itwt_30s_current.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8890149f402e65068f79391bd7e4e4d99bd044 GIT binary patch literal 69190 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

I06Xy4SNo!{nYTX zzSpn(>ig3D_uQYZyySv(?7$u%qk!gU^U^M&^9~$62~z;R*i?f;O7LUY49zI9GWKtX zG9Xra_Mi~efa7sA#G|RCrXe*|m8GLc4g(vsOve1Drc{Etb_kPda~oyzIqyD#6@(4Z z(r1jpP}LqLi6Gp2Bd?do6#MgwY&H3Cu1w*qF$_QB*3{*Y|=isxfB;HSxoGMh;_ z%}iJ&uudQm7IW<+c1}WZ`J3~VwyzZdmecfl0$hRG}wjZL}lVDT|B=! z<@L9vV+VWF+VfYX(+E(-_!xzK{4{5!flU1+y{PF{`{08QzK*2j$s2FH@$vfl`p%y< z5c@#8AoMb>_5Jt0_r16KdtF^!*UdNI{0IR*ZehG;uf;cpaiMHz_VfRL{rq<~PXaEH zfJ|fnfQ?fXRjD5#N|?x`K7au-8bHH|BYof((cBY~mCVHpx!xND91ukSQqnMc+g7ga zZA53NYDNGH*4ma){kCYI)jQ=x6Cftl#1w5)Gu z5mkdNYu($~k3`-T40Ybpg=qm0zHi?lBr8gjfTW!=9%t#kvriH(9i?LO2+<|c>l|1M zQz75A9@>`57hHgbb0S@^dUYW0;w6jG9-27|n66G-%t1PAHRnt*CyQV9_O`<4$Oxa; z#L6~97)y})??`WZ+go^+HX!^8G@L;MZJ^DLz(k7a zau@_mLJ2SzB4vA>{-#pCG1Rn~*0~BB$oGtnsiqWdea zxhAb%xhg%s;khs)X(H|J=}k{Ry*?c11stLb3$}yMLLf+AFZeW`cJJClZMFK;M*zt< z`=*b;D5hbEqHtq|xk;}AvCY8FTYVmy$sk<{+tal-+?X~z^$gdjAtQ{jhGE3`(_O<+ zkQ5a@d{u!*z`N0gnr6kXBPTo3I&ekbTC`VS55)ax%($9;1J+pA432yBOZFL9;kzOj z?jew?rlLk{D7;7PZ*-S z4i4g$tQc%L)iVF7r=EJ{d*1V&Z?PY_zwsNt@%g=b_n!as(@$Uj!yo?eEw|iq%L7!& zri=DqIRQj9Ui;^~wr}5l5s`3Xv*Q2{xrE^76X97 zh0b3?`*alRJ1|TUi~|THS{Wm;Fro~^h>{F81f~ptL~fvo@8e>A3M%pg4im7n)1Vy& zbsV#k>+tIVYNr zlfgZb7SaN@t&=st7$jcejZ$bYnnnq#dp(4|lSC#ZdZm*F=AvYE;2@4{MA%6f9FK$d*(|l#<0X z5ANQTZn)tZ5chbPovJX8jKZ`vgEe95I*IAc`c>Cobvem_#Pbsh-MzRS4QC%wPDSZ7 zNIph2-$U(#&=Q(xAyqeb?2b8`A2S2fG9m2dn_q>gMnXT9)~sHZTAtd$7~N_8_ATkw z+ekcXYlTS{q;-U(K6K9yDZ$a0_U_*v=0?lAxHA^t)Sr`IT*Ica_xJ`RQdS6tHnCn| zt(a>@anPScNLa{qz#e%h`!I(M;G;2$Xc$TNp+_DE?$8wZ7ezMd_dNk23eza( zp;)Q63}HyKP8X7J1twOzbl&)?>muyAc?f|BLe@hFYfm@T5tc6jrkER2b{m?MlD_7y zl^3r~+c!Lg%LX`8s^`o_7oVlj5m8*=m}b5bw7dqG<6TcYBR>gWUoB=owPA}`Y8aYC zyK9_V2g965??NN~10loqz(*XG{c%Q5aMKffGdv z7~o+zqQReBXs^zB%Z{j=SvkV6TFt^1Ej8yQpSe;UC~!k$&|0BT37?Laz9^o=K5`Au zcOLFZj)Wh)sI4O~VxlU>VgpiN*FefA@MMUbB8Ac_%yN@d9j>dc<=I4~p%vp51?LCT z9Q;E}oU>scz?Tu|)*_-dWiifKdQoXc;mM zr9P>jlBNbqe}_OQNdct*XLf)}CW2AayaIB~Bws{-h#pKnmi8{8Zd5;|J1U9Xv6|=5 zFeCt=?WTrQ9*#syf%ihh)nvrBX~x$tFmDn4K(N(o#*)DZ=az{cM%v66i9kOA(d$o* zl!u>B+tx{l+d>fzqSk!8Ee!+EnxV`bHUZDITcx!K;x0kcj$MVhX#jJRjMO}ZIdkTQ zucQJEW%rIfAxWF#auI#TZI!AfbQ0f!yA}P}K^E=6-GrR_>V)8~ShX}AKY9$p!5;{k z4qS=30-kK!wYX^FT@DbCB&fwhwu{{x6=z{ zB)#gD*QL*Y`D^UmTqI;l=U3Om)Inh8nvV(0F?I67dZ`PBpo?wY3dR!j{KhI6w|%#Z zk_tk{>61vCm^&pd%&i>Lq*8Y+K>-6W(Yx=tC+1#;599zPQhJGcd*?gf$DS0&x^=*p z6xXKq=7V7h$%R-?&$cOM@l!->Dl|xmry1WQryLVMDLSZj`p19tC%~VdQRRTp*o&{a zD)MVIm&jN(H#XBNV*m!A;346aQ8{3kX*i4^_y{o;ot)BX40g?MJ|^E5;fLaibOf^& z95dbVson1!avL3(RzFDM8sGn4e zq8NjH;661(>4MqozGSXy;2y~YIA)(A{d#__mWaO`h6^p=0TaMKDB?pC7Oilw*DqcP z{&xTe%#`gJAt+#RO?~>vJKvc40XCCiXRvSSM0Xz+HO@;*F%`BO5aE1)Mz<|4q4ef;sqZ&b5+@i+vF z6n^>3U;gl>O~KJc9!BiF;+wnYyC6J2QV1jy2H9!$v3;A+vWQr=e^TP&@dWUq9X*S>$^X0)jPx%r22qG{@ z2;ea!I_>twgfAKeHcZ5dB~&78)A)UC@ev>(#z3iu>|X(6Duj{rBF*?Ric8b*h4xZ8feolO2n{;{U^Q)!6~IcV;{tCB7N?QUkoHS zn&x!tDTosDVjt!cS#<5{l~gF+i{#fEd!h8Wppje}w8Y~_4`ANuOZPtfAp5Lf0%3=s zSRvq%M;}NzWmPnpx*&}LIIF3hwR7txgo|Fzql7(zSdf<_QvxX1Tk?pCs@W5W6ND!> z7eCrF&!n2uy{Yr&%hJ9h2bfd^MI*1^e1;-_qG${F`m|Mc$%cgKIW9s70oi0)k`BdBeOnb=2#0{ z>VL5@mkG8?`91iN_TBXqX1GE20%o*{Yk{F0)ZZBx@Q&>pIrGYN!>zALkKA=ndiKeu z(lu9IhsIHo_U?LtW6OxKW~LmTJ44Mk0mXDb6WX58%@Jk(T>CX%I{nsN6#bKGtj{&a=|R^iB<5C!d`yKTrCP_0H{SU8efQn>`i_o{2DOh5eBc9L zJ9X;Rd`(^CQH^(Xb=AFi49!x0uNL7w&CSgVHBWhs*UmB<%~`YKU|yflM8F&x7sNHCtRh^_Q8MXtdxCJr5plOw3# z5MCLP1W6_&&`n_LJ$CFg+JiQJRB-M=DLZdVB+N`9x80yMv)wc zkc8qM_Gvl(4m;*`b`7QDXiW2)n&>81L(a=6)qal=_lb1IJVi2Jff)Q^_PH9Jm3Z?D z;UGq__-*XNbb9-%R-~%>CKymfYKI_w|DK0K!qXgS48415K}=>ArZpM(Yj3>`GY-*h z*q5uTYSW4K=5%=Xexy@02N4x!a_Lo9qd?jusVgwm#}2=&_YFG{CckEE-v zy*xc~-(Bgt>u*TS)avrwBpdoK+H@*Brb+@9KJdO@ zN&oc4FO$SLp4MG_aeDuI-kSdWFaJtc25^o!iL1MNd(wU!;1xvV9U*thfENP*^phBj zk_T}vLtr?~ocn>lN^zOj!*i?Bm+?7iK4vLsl>O=Et1pT^Hs84C3Czcsz|guZE;$aP z?7}xUf|jH79swKx!w@+uwl&T&=z*jBQZ%TX)X_Z@J`Be#t!PN+(eil9^BV&{_0Ji8 ztKD`Lxk2y$AIoIaEPYf?Xl56;R!gcYR&iL;2W#Gr&|G>&*7V&sE#O7(V|D~5oH z6p(qor=FG4aU$*>g0Fm+Nf&$t@FUam8DlD$@Vn|PoHa6pm99Ha;d?-;DntdHgb|eB zQ6EJz8mG;wwqTRiatZm&;d^bcv>2de#ixRfui(Dxqkk;sg79<9lWa5$Uq6L{++_OY3zwu{z!cmJOmCqiP_#$jY9}9^L(O={ z^mzfn5XUKI7)guVFZ^BmidUp3pLmqHjB-8xB!qwlOuYuNU~~ZoiZDY>;TNn+{a7u` zt?AMP&GP5a4f8b%=Ch{U^!&3M=)BoNLC2I@35Zy_{JgYm*{bx&BX>mrNtazlVJ`Xj z7Kb^%#nibP;Y_N?ZKe&5kq6G-Ot@*Z#bJo|S=UkCc!a(=RfZ zFgS+P-ZP{of$iOlWPnCuX5m3Y87GKvu}ZAw3ms?z^K5wpiG7Iw0FNb6LMqpI%6p~0 zIUtoL9m{%~2v)#nV*tOzOX*jsD-!Pj@_b5rOyR&2ajocyB@1&K&&L#CRaBWw6n=yV z8wRVtrI@nM;1uI)XV)ZyR)R*NQ&6egToc>y<_J@2R`_D{5e(xLE&yp%lq?ltwbj}h zGQ}zIrbJcWKnN&iC|^UE*(_veB-l}ETDg9iZXv*4NmlRxrZ1U{CO?V1rATCUN_!H<8!Fd?9 zlaIu8qOA?{P%p%LL0Ur32m7ED;s7^^t#+o05Kqi-g#H>)Ga-|PXjx(SgYSC}(O)~$ zWos`=TOe$z`%@rem{cGZYcMB0@bIG${-*T8j=lJWR8*Brg$vG`f94PrvG;QzBz?4< zB~F38VuQF}eX*pB{0IO{-n4zk)*u)hDg>BuU?Ln7mjYKLqn$jkpKR(n&}vLyUgwcYd7!gCptA@BNTxW4FipAB>ap%Y+i(&$D#9Wo)d`JQ|2?;rce_qMmu@|GYA&dx%nCz=guUzB|hEzsgnOI3&u ze&83=Km6lYBNxQ>yOxpB{JWG+lqHy-+d6vKM>P9WElB)Z!5WAg(HENsUGl>Q0|Tn1YG=SCHS|jhA=?Vr4==D%~(A5ddWL*RtAzuS|Bt4 zqpBN4=-6*17ibpJ8wbr%S!R74Lhm0XG;l@%jh6`L4IDT`PzEpt#W#Xv2EZEoq_@ zY6x{XKo$;9)ps5?f!RrOn1o|4c_2Ew_wG9eUcpF2ScrgxV#R`nFrgeiath#u-9Yrg z#n8sA-7^mfQIpXLvaOBV*Zd*VZK7K32^`>MNP0cQ*lPyR*RTy!(9%V7Baur9+s)U8 zzhx)2u#_~>J_j&k6NG_}ebJ-LOsI8@$`Es_5 zQ%*6(g9i?&Xk}70XH$>AUy9c=9O&-WMhfiE>dM1vAI{*#pckFo#2b_utd1-}yL9 zgo2u{x-?Z%+FajR*8hV@KKu~Fx$A{=0YF32`lB|JXwqjz4^X_a<4kdatY1_TKCNee?93Wg`jW5@fj7UcL8jnLBgl%<1Qh7b9>&1!2#<9jyo= z3K_5)ZYyM#CH{j14={AzMXfH9D>Xk^1FRX7&EDPpE-8({#@c;@97x7`u& z{l_2>!<-*`Y%Rh8%!;|X>84v*cVy}#@y}npBJ8hk2-7IF-$n7tdfGJkR7Y|JVd)J! z>Jh3iXYr04w0rj@iNn)>!~8i|wFsjZtuLmDE(LS_{WrfJlTuT-`e!#$RiQOX{Lx&+ z{FsmR(`&DX`OvP~s}&?uyBfvy|R2vR- zqc8i%NPgs*l5*Ct(*^VH!EaWHKP{Wo0Hd;;PebgJg_n@22CyFXe@?mYGNBTnh3_BMlqe*KAH`D z2LXstis2>lBg|TuI_xKX9AkVrI6kdP+K;Kgghj_th)r2vjM>3Tn3nCZQfZXNX{Q1L zdJuvpqnSbC*1_g3V8JttVIPq;MwD1vN&k)nN1xCNY`&ck*K}Q+KyJo%!SBW|Y^|z&!R6tk4fZXoDfMaKSCf zjq|0^$cUXn7?PR%9qm0)x-G=iXuIwyF^DQ>nf%8dLgK>|r1`QQKhOxKyH29Z^lzvM zDP^Wu?1qV2(nrdYY9npL->-0(Rzx?azg%bCxmVP{cmCE+dmvyKm5*EE@rsD0}UpdayeB1 z0=xtn=FUNzdh9VY1@KK1Cq5z>vUw6lbSV)F3`>tVw~@JsM9!}g6XzyiMl+{Zhl?&a z5A!M7AP6=N4z7EAO&B`Bu9#FujyNw21T1);F6X1*0p5ax-G&JRZ5geBD^@u$kHJJb zamm_en$vv0QET_!b$2-KxE0~lQ%(yH+;Xy_F%5B-M@$#B?F-m!!nlU;juF}K5*(`u0LH-l%qn||mc+OlO| z9M34YTY!dDO48nbN~1JTUBI&btWvbh{IK%mRblxFRLdnCcn)>euD$xltW)rXO2;31 z|GUxrHiTVUx5YYj%}pItt!^arH;D%x$CiUTX}AA7f0srvweAAI9TWy5{2a(hr4A_zL&Kt&`(vL*VEP1dP*J z7?X`yGhkjkG$lYvP#9G2;o?XQCbT(0hR{mdSXCgJG8(u7b&>qU8FS$vkxRXefRmMI z^EFDz_I%7*RoNvVzgh%lG83#yCXl>g5aVq6L-h_!WO!F7`!SeDQ%KF0XK+!fUiV>2 z+lMn+e~kW-6ojU~9@Uw)r2}Tw>(K7S|B<5j;IxXuFnjK_u#>8+hDJ&dr=cpl1?`^Q zO}v-qvBR=-p%XGxa${g>bE$`AC~PP7tzwovV{~tV9yXPN1V!INJ;nblfu6%c+RtWC zJ!laaKIjPjfB;w*s2uZ)c_bF?GbGulAG5qI{8(S#3|w==!KQ=kLf8Q@Bd7p4WTEOI zyhB{D!%Iw%EH(M$;~&U@p?6V`@W=OULNnn$;F68zrXNY-WRh9hw1SzCMl`$SK*S3m zXz94(b!ZCMLvkh!wLfU~Z~YRWn7ZH+c731TU&4Tz1g@Li$P(x{yJqMBeu~A#Pe-V!Khp><9PbkKuv0>wO7>MOu z&~OnZbd+}h%R6toJzV*+m(uUNuypa#=-3^i+=yl`QB>?JFP|RzI+}=xYhezH$VM)X zcng<~;oOe7ps12L!R+M$+!`A8BRPXij6XI64vO63jJ_c8Q(=gokqJg2$!na6HORmx z%igG&8ojodJP#|ujsV-6Z@m-dSO+mLrO)%jDJPx4x!c*aYfp@-TePSS+^4AH!S-<4 ziD!g{-5W8HR)$wzby?WFaZA{|c~5xfAH5Tyq9}ajo8KTzbtGK*;unV-e*Oy>_Fz~; z$n^2di&C|R>nI1-+xv}QfK-i1< zDi=oi1IpAKbW<_L@$fzO!Yp_O_<%jgIYI-7vo<}3Xa}bS>x1$u2%32F(7+KOfOS!E zcDVD-N5ZOACx@S3^OJaw)rgxrTEf45_Oqb`AyQ*PD_ZI(g&zISF!pZNn4|)<1P5}c z<%KgGt#uqBC7+IzmsN%~O2ZVDRkQX-!s0pe=@B8!%`KSO(DA{VvM4KfiOyQ-j? zl-xf;#Ep^}l5R{oga}FCq2C}e2!pgHgUMCu!7SlL>n3RmQSz6d_4Hvo*ExZSEDM5U zZJ`OY4-@PLQK3!t(sVY4)Rqsyl~Bi|DB99wW$uO&WfwM41t&U9G!rBdQr{%w_=^3)ir(l?X0vwsxFx!HjgXNA?L3JxDo|v56+kZs|Y+30^PG z{MmD7#i$%J%S}oH+bOkx6pPu-IQr>zGeiI01F=I&boz~y=1Zt5szzg!NIEkf7!w|A z349%B9>Q7yNpqDqW&5end};HMnaNO_u3I(Gzjf@4(q= z@kt|UhO|ACY^eFG4ozSerauLc3UXuS0pGIm4(68ZXcD_lg@|?!t;Y$=xXBE@?9z*4 z?W}ePa47`8j0HbI;-R})X<~9Oh+FTzlPbm25f~^wi5bm3PP*Nz9hhk2mx&04Y?wxA zjpn2_#yb#$FSx)6$;5`amQ;|ZlZ`;a!OTY3R!y6MrnjAFG;j}wCA!Gi#BFUL7Q9H~ zGq?ev)n}*aO>M;eJDdk?`sVeRNNG9ye2Apm6G-r~N^tyA4709oMmXV=lfo}VLw`x}mi17EZv_7# z+Hu-kn}x4yStP1$RK0CAat?2HeBgCg@KiNLh=Zhtw2Ol;u$vQM1fpF<1hq2Gef~ z^I{TmKMbV?MpIgo7Y=OQNk739Xb1D>a!QV;2?3VHkq=D>BFqpWrb^!|9RROXhQ!Na z@r-#A*8Nxh8)m^3Y93-iD-9{B$}nUU&XQrUI`0h4H1ts?W^`0S>{2XJ>k#E2$(c_v zf+SLmz0yRzuI?VF;sEc4pqg`nO72m?zTMJ{2Aqo{EHV@BbjWK`GeJy~QWv&ollLU7 zxe$gFi`$w#3Qjp7ma*|ey%S-3M$3FzjM<7Bus1n4iLqJ)a*s)7s0&be)(M_mtF&ddR z_C8DsMO-`mxcT8ge@SR+Y7Q4*2D<5{yIIf@e;Cx5ra8vWhE1{5117H?%HP*f0^)D~ z{^K!nY&W5l2kEQ+iE=8O4g&XV7}kRU$kcV1(74ww431>N(`fKo;jNx-w z2osNC?cn<$bFh!9%sWXSJehsND==Zb;LKHF?Z%CSxF3vbw2X5Xopm~Gj*_EvAT(i8 z97iBm+tM7hV8JW`95ypn-pIUX(`G+rT(_$(E3OQG@qu@TPkr_)^cQHdp4DLTi?9q( zWw{pZ^|3Wufa6fO?~XeNxy6|e9?c_<$LKCZlW@_Q=Y?0j>_yD)J=C#k3nd7AZtJ{n zPkrd+otF5?LBm%AD#P4ZM9Kak@Ti;(%m!dSmF4M3tQNLw9>>bi%i69hn~o#C1)hRs zfO*Uq&pn&VjF;}^*Z8t=82x%n;O~r^3qifu-#sC0KOYSLK(OV5w0%7$CQyol@FLsE&Muu}D;#9W6&jAbc2mJCc*hXqKJUAJIek z>TYbL)5y2bK zppDV46&9=vJ)8{=@x1e`VB|VT`|S`+WbP380ZcaqIE?G+7GQo`AES+AP*#r4&1wo~ zzTmRZxMw_Eef9OstC~BZ!oaSL8d%rebQ8Ehzj)s`s!lhNNc*VJY>>bhKvzq*6payk zS(tPS@=Dn|W)7{>S@7>v3Iys~aUTqQh-#w-R^-#Z;mA*H+Cg=J;~C3HIA!J1aMlUS zqcA5LScZNOpTS-qi(oF@Xp+VFDf(@1`rI%VpWZ1atYp1(g@Ze{glYt>0q)ti zcR%~I0gwZ6$%P+tD z784h3*L)JQ)XhQ3WThMCYsfFO@JvuDq)w?Bs){L%W6x&NpPq=Wnkxq&7hI7TEA zmV6!+`Dr1VvRFX*?2&Fl+Gw<&XsLlXLXlXv`~aDensl0K&vchCYbcHJoX?xgCY{tz z60bviB-**C+FeK+CB7HykBB{psV9t6c>sc}iAr0u^{QgnE7#RNlnw_`&ov*6V=~I7 zaTACvYmkfff-ZqX>cXc@#-{yOU&%0LHE00Cgor@IF$zWEtxv~Ia^MGXksA&yVI8B! zP?SU=Xsk@WBe~I6wKFAqiHw?-dsjqBl?JrE8?B{zA@&4f>X6JEh|y!xe=Tb~oz23J z<~_bE?OTa87f#4qVqa{)H_7M(azA!n{Rf6T%JgNxo$MK1T(T6H4@-Z@XcCDQULUuBr^XU@A?G2O{nuH^g!M4SUiAU$`&z$oXE@`;We{V`Y6NAB!)Qv`ZlH$^ zoYt<{h7-Cv3Qoh|N0wR}0?6^l9Y@IVjZqj9qv=M}yk)d*6 zE2HAD+>uPoB4dq|!|3#(W-D|(2Zx0Y>+0&7PCW6%b=O^Y-Amv0wzqxL1VU?GedHq_ z`K0AbrWRX-J|J^Xq)tBhCyyI&y+d*q)S<1vRC$_t4)vDG0 zJ^0{*XImy^`t<3ImOil!nDvtd8?V0l>Q{Akc2-3r$)|!{Z~}p@te$%}s6GMpBvM9nscDpA zLh6M{#jJN0ry7$jeT^HxXo(hkPrm@HBw^xDp56q z-FxhWLfNmrN5q7n)E7&DKumh5d};+|v;Wz|sv_oZ5ECq#2o(%!2pVv`%qPmK zrLP@Wxi?5f7$ah@Vp??!SZH883wd8DVfg8T)r?8G`mV>6>wu@`cjlb6FdybQwti2j zYNMFt?){-=U?`Qlz3H;?N~9~meyD+8`y=b6FZuxsqvvQ3su8G-eDaf@{D{Qf4E0+n zmY6BFs1_k%S6et-p~Q9T*PS49IovyB5?}r5SO3UjjNkq4cYn_ec(c@P&yw)I*9`TF zii*z3&)X-@uU)(Llpp@^hp$sZvQF29FcXV3+7B7X*=L{q;N<5fe?KY%0r|32iJ@f> zMC`&kq_7K%v}yoFAX`kb0+E$GRR2>DKuMipq`B0VYIciN2%vUu_bB(KB8#noftCq@ zHpO#BMM-O8jtC1eO3V

4b(FBkz9Y(UEM445qqRjRxEMa34e%l{zb*1&u^zT)R@S zB~0ACtr7>WW;6-JKt8!2ytf32iLS==Fa~3HPj`u^`wE8~HPdY`@_3)Gbn>CuA*RfyAH*bTDqCI}zPf%#|$Pmy>f5t4X` z=rS5eSIEM5!3_`_)Gpp{w2ymynAZZ}xslU67tixE5 z;*IMt`4}@_Lo`<_QYz*hq&!VD-8h+x$XCfFx=kMylrS=_LKq7_q8TlVaT^j{22<#V zAWS1dC_0DfyM%)Q^Nm5!S3^-{X!_2~ov;kX2n2l;I2vSOm054q)D>ka&P5p`jumLo zZwI0YEt>d%mm$!vcyGa(lN3QP4F%nHnJ>M zEC41(tXaTt3;_seLEz{g{m~ERw98mxkwswUCTc(>G6u_o*cbg03<-P^d3a8=;(hwV z3`mF*z`78CRtQii@cwB0<%|2h02ZnsOXfKkqdq7FA>n8HF31!PU z0*AB0ngj>zh7HBa1hi#oA;Or#E!W?GnXf#&=5<%0X_kZ^U41n*zz)RvVN5{y($~Kg z=StJx8I(x5^x|{aLb^VD=O@= zE+3|mLK8+Lf_|{J=;Z+Wn`lK)%M;QO0iDRFfBdg!CC(Ysk%V07{{H*#KbM@Dv5)-4 zM?R@ZYjUwg8H}wyVK0EpM zQ5i@9#7tYZCIy{{R*Y5B64Y_MAQ9xTaN~}95<e?-6Sud1V{TY-wQxYxf-P*kowK+hF2gdqhYYvBJ%hz2yeyCbcmzFQHMGn9 zI#k_}&YYE4{E?TaDOrb#Tj`g64TvWc#Zbo)B8P-UEhXaP?rspXSZoqTl50d6qfwX` zh1rVixiAaQrm$y;)b7cUgDD~o2D`Nd7^4pYc~A(4RV&v9L{h+-Q~G(Xb>7lN<3$7f`pUW5ATtYSniycrQ3|l`_Qwz zC*qrM;{MoQ{#A?8Wa^;?2BPse9h5Qp-8tcA@yoBV^bhUJEoHKi@-rwZEBhh?~HHd!zQir_55JVLwEB^Uj@oXKm2-x`)?b(kezvso?#tsflp= zt+#-p8W=Vtw|x=V8h!jm*1~4aBT= zAP(Gp|J_7--HDlUluE)S2=S#1dn|0(z6)O={;lH|!!UZO4h-{h?!^`90iWi3%*0%Y zWt#02*lXpJe-Wxb{7-W0(DP@%7joY45~8vO2^D51Mxq{jU^3;HtgMftt}=xZZ@cZbOD)^(ejtA8%H6wn zFZlS!KmOOg%Q7kw{|pnGIxyd%`AbG8qsbI{)E{EaE${ap`=|yp_4&;2qcRZKc9sO) zOAVZ~yy%*7D45v4Y_<5g?WR5gyoIsvsa zAi!*1?_a!VF(u+3$JyTw;mHaweBmWXQ!oa6MkTwHn!a`w}kwHWz z;lqGEGU9kb{82j=&(fsJw@0i4$4o-?bd>XLlRkTDg!dtTM6;$$!D`bISza6&D~;K~ z2u>y?DuAv7wUKx@01ht6RgktBJLi12qs)9ebVI}!x|!}GO~g&9=(8nz9EN>Td+{FE z0}zjbioP|$s)^D1Tv1Er{-~A2{->FC)VdIKn6|K=2)eI)?LSpGh$uA3fO&|`psDe` z7@A8tmnYb6V9SHWw?GiVfJWLn}L9=A)q)QeKRyZfF_%n_T~&SO%asbbO+| zHPp_j3Kcn+x-9F@7>Wz3F@H@EV$PPgtU2>x03%nP{iCX?s$HpGjlz9F)GBnQUwiGf zFSFK_MBn0ynPQ7N+%vt9aZD|gD53ZI)OOW8zVn^$ycv2tq+|X)?|IMXEZFG1U;5IQ z{zSjZnP;8(FhyJkJ?CLtGK@@{`eQPM9@Ttwtb3pR(2Vu883+;%>)!=O-&rIbMExi+ z`NObOmx&UPQof5a@RqroHs!!W`km|O|cP&<(*`AAmArCTd% z>(*UpNF(&GJxbveU5Ervrr>xC+iWx0kM9ye7n0+0uLZ{ui6gK{G4B0Hh3VppnERj{ zMqK%f&c3{8T7hswbfeQ0*qXQE-WjVO!$C=ZU@%L8cO=(^jBDLnz<*Wo4yw#7z|QwUO^=r3ERrI;uKQ`{Z=E1w=5;88Ci1F3^OReLBN%;&T$?IIwsNCL{0 z5MlP1M3*mG78WgE5(7Dm-s))Gi!;71tl_ylYMISoL$iUwo{&>AgW<3S-D-H4jok3_ zmCiH>1k)bTi4&Oodcbuxz!KhDh$fz2>LBQPWkD#$+&qf8t{wkhaZXu`XjIdWCago# z>@c70W8S=Zd*Axjw|*$TXyb+ zh#>8T^2Pm0fWw2xAlnatJ2){8W+Ls(gO7?T4*VKI^hHijlg1~w+4Tx{hMC$$Uh%P}Dh zgy(L~18WH=#NLgEx=E;0QdaU-o9L$x#gy^T_U{HhGI0G2CWtw4E_C5rfH^KojlvlM z(A|fG#-fIOGFvbs&MDbiL00KCKd&TeB0eusl<>`FtJ>Rd{u$yOHe|wI<4d7#9TfAs z@rGZJ;8q9$Plb!GyfWIjhjGf9ALNnIFeGvkeEaJd;?}HOmn`}Y39kZ${ZQyoK#_3i z5VxYTwZ#T_zr@yo>1;K?!O|!oV$`6-NvWS&N2rY zjqotPN9HC|Fn6M#MA-;$&SgXJxh;-~pK<-jbR4GbGI^1S$GvLeb?448@C>au++wQD z;yGj583?C@k4(A{ymtZWd(=Fc!~4}Le2*0%G;hTpe6cQ;g&{RJ`Jb9*d_A`~7o7-L zv2h;GH_V)MrWx31!ye|V&`Jfgapfysfi|7KRW0|rtA7;l>%fdOXZCywnodx@WPfOG zCx4xYsRd}+d)UlP;kCH90<$=qVj(OwQFE@8>H{q`Fk%Sl(B@8Ce2~vn)>jQ`x?SW-hClq!F_}kS>7}QIeLHth@U4rr znHAPIqF&;-e9_r6Ny=)#G{W|_YzVb+-#8LLPFP%FC@#)HB&3|`IpM)I`@&V1tf0Qo zb|hgWBq-I!2H?qJIiU{dvB=$HeF&X=*APzlp`LK%nF~XHWe#Did)cRh$d}@(aQ;cN z!>&!+$e8Z|R->W0zY>Cjgf8RMk0Lc;A*yjn^dtn9R`2aMi4 z1qM2ds39^xYDJ}(6^3E5b7w9@GXe%A-x+;YScJ0@X$)?mz zcIKR`g+P;H*Ss1v2XP{vhk1A({nVsq%`?NCz1h4D&4Jbii<&Uh+6t~7O2A`C-4a;0 zTvl9B8;aV7B%AkYVzknfgi~TY!ZSIXPxtIlcWjIf>uZSRTf}R+W~uzh4|!*FigQjM zTpEWdmJajQ4}uQnz;S4EpTZKjAu}{~z%fTc4Rlx?u^*0IdBdVXpbQ5v=RXAxfBKv% zy5O=tm4}Pg)AlodW6Z*L0?ur|CHVb})zd>02&ek$oPHXVA!bn%%m2VSeuD#!l{Z-D zi&GJ{!cNG#o{<5OlAL2{fpa%OlwWuF?7x4B=kPgV4l;t$=qsiAJ^T0bGG>s4JxcJ) zwLgGih+DqTQ3(^SwZK5$^{zjqYo6l@Fq9T7S-LO^m%H~g5|uTK_R)$NY9vgXUJ-X* zEF=m`|E%yF$A8jo9uSNvmy-8}{hIeQG~P{x1599OL^*?m{xiN5+KkS6Gy!l4v5j>X z;m8=09FRLkI)1Z#f$m&|MsFIC~TH*pIMFZM? z5dRDI(-WwzG%X(|9A<~bgt6`ztfSPyoUo#*4FZ-?uI^NkbJUvvC995ax5_;(8 z(pe-9j-MIwYZitDB`x9Mt=EKMw1GKgd12NiZwO;OO(CmeLwIcW_Gp%=sa+gumoH?a zsPVAn*6YLm&6tx24PLS8vRI>MPSsG@|3&K(jgSdj9P&=S0OV#5jO^yH;XA9th3B3S z=9j|U=A0a6=Qf6a`uA%wi{*!t<`st(%U(#Wrt&a&aCO-GqaC3QGtvvrnir~f$-HE_u{0a7~^p#hD!EMxby|X;fA05ces1!Ksc^8KP+DS>d=eEG^eaJeB~Pt zqs~*VgT-vfXbb>w@h}$>6lZ4$iOda@G);O=I`4JEKrMDDwTX3=5bZP%xJUU0DhV4> zd)|3xQC+tteCmr|XAxrhV?kba$+_W?bsI>2>}HYAQW~HQ4=EP^^5FrEfC)oX6ot7U zgONc+!p3VQ@@eLgzSqahEinMWHioc~Yqu`YWT~+mLIiJ%l6Ay2D2i>l(_buNNh$br zPsCB)ji6&NjO^3#s3%ANU~JR*;XMDt zmKh=@A=a(tY5T32a5&Ncu0x1BseY^mYVEcIR8TOR9rTAOrrXFt9n{9+yA3@y7{Nqd z=PDhJOtT0vV=z16R!+&0{SBL8Fj?V0zI9#fizeVa*7+Cy_3zORDddUfn}fDegt^v| z{}Tk0qzHsi7;svO)aVHWk#TgRDYX!KK9^`OC&F=d!vNEGsfv~yPZt75WFTZTzI4Ts z#p^0a;L0ZBHU^&X`O_D(I3EqIEl4_9{65ecTBzk?g;|ps zhqEfe<^x2iH4cYW3r@sYyca47Y_n&D9s9arq%)Kkf$!*WIYPVQlE>uhnRDqY@#>_@V3SPa$-}$-$!U;v;zvLF z(ZB88^ON_>qzv_2L9srGUlWDZmM*zGTzlI`LPvH@_`Ns09P?UxbiUm~V$nB$@Z<1; zD_)IVwg5j0yN#jAeD^2!km0)~{QDRFJ=S5GHDfx?rv>5f{_$VJjdyPifAit@V?Np) zX3m>UEuQV68`IUCQ@SEj%1ZRFxmS2(di*xTRt90^ zXLD_`V1hCOOVPl;ATSJpcJd%H`l#dsSreEHc~(@jEzME6;D-#)To1>M{tKMAR}&D= z$GyY(jMNWG8@0Gde376Tu-W?&kAamf7zB{sAkE)M{0<5Gd=`uok3b~&>4+&=p_)4H zvu`kHOQA@~rDBni@lzP+XH?K~Cqb(^=#-J5J6-w?4N`GTG8oNp&W|2NnU7<%?@_Pd znglp~(0`NC$iH*DIp8O^4I@)Og;6RS7Gs36sF$_C(fIU6RjHLPF1 zDJDk_5&-bT6C2r^I+wzWsMF2uluECLNwlD0EamUG@Yv&zBSk^%Aj+FD7ZnnUJW5#U zL8`90o1p~&&9yMh_F*cnx)WYLK?ODVGnT{Dl!PrldEMBxG2v43Z`OR&K3FKyDJ4VJ zCPXQ%=I4+T68FugYo8f~C1I85Gn^>QV*QKX`yetBRT&bmj1swTH)?JOdy(5YiTL^WD@3}Yc=BUx~@Car(@lbvtzNNL}z@Fz7VKxOvjWWz5V8#7p zy7YGu{yqwB&0aJwq^Pj#bhS~czg$x#9Ub%@+VMb8w9HKEcQ~o4nHcgX2OL+p6W%i^QdaW7jzVGMyKc zGQaZzMC~#GPmgat6`18((X#wGnD9CS(@HDDDUx=bD)NM>>%Uw9gR8tB3Aj;(Z73*g z`z0h^XS;mA$gJ;ATcpuYB-}{?+IU|c%mI-jY2}xPFJ>(vRo=HqJ5EGp)KDk25zE(saoB9HFtx)BzLd59_Z#qp&v)ydO4_JZ1nLEBzJFk zT#wI$CLrHn}EIqx&VfeG|-br1y+Lc{kdkJ?)p8Yf8(?Z41#cz)HWHR9o;A`?cR z_c)GR5FwnCu+WzFUm1XPOWPssd=3ZZlI(L>1YiB!U0sDFCU;^+Z~h*Zd2^U=GSSV@ zd$bCVAgqiV_Jsl&UK`d9>9-%BRywK;5@cw~@UuJBSBGVhov_p^R-?E4c;)SbY;Iz9 z_%jHuK%(2im%Kj?BZ~L3CERhq~|@~;R)voO?X++!-^w@j8Z-_o8*5^CTwE0 zS*b?eM#AGPjcHuF`!;y;#C;IN1ph4|vE}%VPXy^=z2lMvj={McTYLc#0#y=o@RKuL zpCwKP#&}L}JK*~e1KLnNd^8oC+K0~<{E?(-&fT?9pRxI9tCymI36gFZ)5r5uj_ET58b!}i_9VWz3qaef7H!!p4TD~jW$)wvtq zFx;WqZ3xd;*?wcuo~ng1l;&}sv_X&k2H|@U6T)srVXVv((aM$KJ7Kvs)U?|7oWkY_ zh6d6#QiTLLNJfxnq6U1K{!w*{c3U6z*(WoYez)(sFQcMP41uOMR`hdssq@01O|hr? z)=L75pcJL0FoIpD2&r3Exv4Ucmi}I=RE}hqy_(s}U!g3?0?;)?Bn1I>nG7ZnwoKy;tW> zk+Rd-0()QUA%Wds%?S@2lbmz~iLG_A+1H$ykNC2})y)Wa@yC(~xf~5fGbCdS#3R<- z-k)p*>RVifq8@nsb_?x=ufz7q4MmcTG2_JY@Uvx&-RSx`!~YCOWxY`Q#mPw*&<8Pn zp7YKU?Uecby>V@=k@jS94Oc;{g}J^ae6{&gQDCI+abJv|j?+@&)(5x=Sz6NCw=KzD z9`g*mv(6nNgP&p}F1Bm?2~y2e%&!8T_n!?PuQ2-j2f};v@7KmE0|LLXDfl2*A>WNW zP95iXXY8xHIZ1tb-8%dD_MMfx)6??#qg5Dz% z-`fEKPQ*KdG@hdU+~>agJLt@U18k?4>YaZ$wjjcauohQjM<+jV>3bn5^T!EgeN&D4 zy!rSral=+4+BwiOtYo5aquu-%D(ycO4G`pafA84pSDEa#l>MbuTcf?aJd>#|wf*_X zN8ccgx&NB66>&U1^QIV?Kiu|5lf9Ot1<%?+N6Tiwqg0I*o8eO3;^V~u0DNrP^C+B* zaad@(S*VmolkH%dUJ9t7;i7eDVTp*aU-L@$Yr~rPm~hdJq><8h^wr~IrWwsD5X-Qs zhL;oHmJhNo(V}@j*9VSJ1rb`Ajw=b}Ln?i)QR6eSR^XN^`Xnw#|2F;JOI*C7 zFy$G_H`H8tlQ0}n%x5Ke;|_Xt?-DdB5{6Q1qOG2yEbp%=0H8$k(Y{yT$w%kj9qX(g zTQTBDwFmp?=))b1_+#I*JqM4r*4xg)&_{8_3=1mwB2Y*2I=&sLdvbiLiwmXeekkA5 z$uX4jr8ih79P1~LMd?u#7T%*vqFEq?9|@Q)fLE2PH&*V48a0-7)sYq$Edka67FfA~u%A#j;L= z3CqX6<8e?)qNWYcMqf*TA~opx6HD?^q1e(eL8`fcHYAfSFC8e|hhOf4IhWRodsfsU z9Hc6C=SA1|AsJ}ak6UCl`$5XHN*D&bM(>XXg7TyB@FJVrAL|n=y7J{igHeumLf`PT z>Q#q)??5S$oSqv3O{4>QLL2NYBXDzOxapra@y32yc*=?se z>@s5^R|{OU9O$AVL)I;wY}8yT8^yY>%OJ8Oe+;a#OP}1$Uz=A=-ig-!?C1_7o!+T^ z;0w42Z)iZaB*92%#}mz?%B5ZPe04FzQrKdzGgyt4x^{iaQ!7=fHy={NeHCktu1LE5 zoLHN9MIwfokKqhS#;P}7U^&?L#@n4A+8)Kf41|M$8x_MnHfJ%177tkcasfqU^x%Q4 z75OM94r-xdduC`i^6Fmnm^%42&n-a|Eu!+dcViSoy+1G0IEC=Jn;|IH(TT%Eh{u5# zPZyxM+hVc&E3hm2#ub9=NhGIx*uk=#!q68B#lX~n2~B1u+iAJQW>FlL#qgHgq9u1V zCG{|YqgLOM&tTq5!H_83&kRMBX+E6mpFIS6mYBIsxS9%svWeP5p?D7i7^g8+OTVjQ zn*PPtj)oq)J`|Q@e=8qU+PYD%C$Ab-u~as@NJ~5a$rg#b^F<>3`_p`}htBGoygG80 zcsz}5-RGL+z?uhf%=oe&s7$}+Lcjie3m;nM%n`1(AoU#n$&8jn8Q$~S6CNg=9E_|? z<4E?A<-#Dghc*w-5)LD&KL}Q7b}0cCLmr8MJkx!(-QgUpP|4$+ii*kBiAQ9H?Fllf zMr;o=-xl&KRL|Pn$pDzLisH3 z)!R4jh094L;4Silo$8a;{b+}JeMP!H2~f9ryPr84DQaG@GwCa)iy@a+LWIg^130g6 z(d%k}?;hgJ3njPv^Wv7hvin70`eMYd58DAt0bVDSDtSCIh4p7W&!Q}8zr(0AvFEEi znD@DvNzSCW2xXtx1j(BfxUVxDR^tXvIuuZ$cG~=`+Msy#DZFnq-~G)9f1MTvc=g(H zab61mq<%?|#IfekQ&@;Fxuduvvi*=3BXb{%7^L4BehIuMw{S(g3~1 zA3AHH9C*@G{r%C=(Bl+d10utkLn81KSiC({X&$J;R>7Fzba!NU+ZP?;#c7iRk6|8! ze?NS}U8_Mit++R4fxyB{Pm!`WGpqP1y#%xZtHNyG=VKXsQF3HbSK7Fo#IaA0RW+~C z{lrKi=Z*{e2n`hT=Hjqp4x`w!ZO8B*J3IL);3i0^p1d_{4+4EVi&tjuv6 z9k0{Ja*H8x@ZjAOQI6iC2)Dt%>eC7)MmHLRhY#$;9u8r?)yV>d{oFYZwW7xP7`}9s8;JR2(2%{9q~C`+ zZrrz#EV(a;P@Z+`q4Gvwtt{<-O`1jqY_$d4)}v$%OL;W7g>yU!)pAxv8Dmi;HK2v? z+gwelpA`{5hgCyGe_~Na7Dm;_Y2a*_xbZnsd{0a&sktD-kJ&^fMJsY7jV!w(e`Q!F z8dtp}h;GXsC%Mk_XgXlKUq;!=XjwRTVc~E#Z@O^x( z=>Q8$cla_mNCyE7^k7U0CPC?kkq)tB7^&gT1sWRYO7GOz0Kw?d;88EUY*_0l; zZc!iE`SnP6i-!J~-Xl|TiTBeBjfU&4Q(hsF%Tyw0^gHV-npv0zcwc!qXLo}y>QW4` z`E|1l2x&MK*l!lYIKDlUhsU0Hit2jUfi__{ikFvgc)eoF9h}tW=7Q@ccs_gBkd^Co z1dG^NHfXOnCz=vA7sVIHlGe_Qjg|IZ7F9;Xt$J>EYmb;#+j!?Tsuo~K;p0^aq;wA( zOnmutjXjRc=XQpYtmnuAAN;zt1$!>a+$(4oW=9k8Y<556OZ3exd`ay-<614KV(wtM z!v$j*!58oT!fZN0xvK<)wl2B@>4}6r=o`ltRONHj!}gX;Hq#?0u!0=4}EPo6E~mDYAw&nVoh{VlB_alTZt<_&9~k#xhiNXGR|;A ztoSDHq7+9T`|Y}I<5MKk>FyzB@GN6HJ7^%oD70LxH1ac!eOqS7$kH}vGGxM8$@?@fU z{&e|W&{(BAymp5#n-$yGY8n>R^qfYtu7GV)`%S63FyWPBu^O86EOzDN(eD%h38Mv? zED3+6&l<>@Yjs9G(K#jur&@CwS?+deYa1s6=k1Vg1F0%qT_N?lRD*S>Mru7`sP#~s z3B~0^AYL)`a=s8MWz%kcN3kWGwZP#1q1$FCqit+MnmQY8pONJm$QJ9qGED+!EROMo zd}m3Zmyd>Vab`ZmgPNE;)H9dtv*s$KKu`<=w^ zd6duAbk0lB9rXO2Eg#72pmBRqMw{_=s(kijr=8{lJsw6J(t~mt_(ZU-;q=3;=|Y73 zN$ca3#|Kk#_H>s(k|;ZP^^=Q0q+y4GrQO{6+?Ia1@AC%`1lqqehM>w3L|dF$KFksp zw!w2og7AvuzFN)BH&D6>Tnra-b)4F&kEaP7Gp0#{=>hzVfBHp4M(!e^Mw0hx?785( zD*lRKEr`^?o_=sJ#a;Fy`5qu-3yu&M;pt0}<-F~8Sn9#nRV`_}sspGxs=6=KeW-A! zwYMk0X^ur?;R8T|99_c@_oP=z;)%i^^aBav;j9!X)`t9bX3n2bGgNvYNQH%I+P*+In%tnJY}O%@h86| zWjJiCxfxB4N9B%vT(wS6M(H1Y6$qB%emO(w!ubZ9AAv8GA=ATeb=U_#R25-3^tzZT zpHN1PKJfMVlvz1d(dYf`LC5r)rTe(G9-2a4;9VK)^J2g=>CY`&aJ?S_t@P!*JF1{>iS!eYA~D22v2^+P(n5{ecurP20=%T($n<|D)nqyTDOI}q zqb@P%dwsePa$IGuc>M&`{R1iIiC2`3M_}RYW~iHUGbR&H@9nCrSDHFY2y4Ns4@?q` z*=YRd;gJJC8g0(#>Lf?Ytw+=EI z?agf3KzqZ5zZG*`q^l}JE>qy+SamrU2-L5VT){=U-*Ay_{*zc`IC;e=r?4P-^fDK( z9?bQ&e%^Dq50+1V@p#xm0mAIyAzEj6)nzWAx0u6-Ugt8&uA~yEr`QMH2JX}HP!wCAHhzQS>i|9 zcR6Nwc>B4e^*~mv2M2sIKSyTjJYoI9ULP{~I!0Zr)Pd(sgba8dK^eI{idq(vl=aFO z3rc|S0NktTdWk*=TdFntf=@1LbX(^zta=S)<`NN0(RtbJLiLH@4uCYBdkOPiBvQ_Q z2lli@UcvcMSpnQu!%$FFruJ~MQ24(Zp0)FAkptfZpEQU&ZxXA}8WwtZaSKOp$)GDw z9LTSsc)KYE9UX9jkDPIWz#LiOtmIs%tiT@#p+OeJ^i2+6GVj1KrWOePFVQ0NqmQx% zCM6EUTSr*jQ^1#aFgcSP#K1ysUCa-tmhfMyHy@9TOH=i5z|yoIL2d}jArCIaK^*C| zrxFo9=X`*En+5cSXp1{htk+%~!2Kv5TOmL}(#d>6Uqh`6_&&DOcHr*2F`)0nFAqn^ zhPWG(T4b?!p~D@@3CdfoZPs@sefDC~U_cnvO^?j)>6hK=^?^!+qx#6)xsVr*Vm$Vmb|w5c^3}%tbDrLYmJD zZf*_)mpqw*?JMVRBuHAbmmtm57sdy=ekdbHqx<5wdELG@Gep|2Sg!jy9(H^%OPbsI zCT>TT88xRpkDnL5tu-b}quqG%jzytPQW_Zq|6C!6f=59~URqkFS#7)}M2?UESLoSG zK2FGa(oonKmkDd_n1lmkMQ=P-2uFcNZ~X8>LX#T?`VjN;&{CJv5&HHYYlC7_wcm)z zdQQ^KyLkwG)PP${&chz;XbOvpGDmEyZyt^s^%lN|hc-o+;P_o3G4ykvkb+JkT7}DC}9rsccNqckd&t#P& zR&T2<^miRw;!Gk>tId=rtDQ_X8+8IQw`pOBOZ5HvWX@VmmI5Atm0ry<1^8z*#;}!5 z*S`8=+Gh0#Y=gMMuX_U#lG(v>HW2c$taBEqr*H%m3ALiR{-KCK)D#O)iJ5b4>WN*E zd{;(jF=T;C6;jV4&~ZGvccds&K|659=rJXVcu330mbqy_HaY(^3+s#`Y=$t%@Q=|_ zGkn>jjYFf&(p9y^<;!rW`RrR5a~Cy9u;`5k6js5SO?i!@J^eNh#!&ThH*u4yp{K}Z)gDV%I|^{7ZtIc~9^}^n7vccKP|G8HgpK#<$!RgeFDaL1 zn|#w-z7Xz`5`AQ21Lnc&z2&6PIYCSIz-CGBuC$AN-OXXYVgV%0FbMvb#{vJcO%u{I z=?sbjbn;di8ClorNq2JU9c4W|zd*Efz;~)gcV1L(Gu%+P1pSyVock()->=s6=HsC9 zWxOa5S{xHv2wp{DmEV`*9|<=6e?*grj~5tdF$Pw%gLLX+Kxb>pykCA)W0G&(qX#)2 z%X1A?542h)=EjFI<|~)dpmP5-SqC%F5{a$)`^m#<_cgsAcjaqJs(d4wF+ega)dQK! zV$%;Q&Wc~<;_ao-E%LI}1#IC;5s+6OI+q{!8R13Qs_Yk(LiYxKVXSlHIW#rpSZegC z4DQ*DC*cs0^I{qKDQeocB_!*1W9t4+0~!p)X-JE@BceFMviJ0b3Z2)ReOZ%QBf!SqG1Q1~_DOWHjfd=h z(Ef(9PIZuR#sb+vpkb#4lmyql%yGBgXSIoN#GPa^H!`wAd-qLG*f!I>L-C!wqH6jO znMysTc|7s94eJnny2hD6(QdLW3gm9nV7=o2@8mYY(+nE&{qP8@5E0e2{f3EJ4uNE0 z87+hy`sh$iBEgVZ_Qf`|OdzP>{j>W-^M{CNC|TM}i~G#CtJI6LU_Kx{_-pcf6Y4VerT7GCl3s~P>J1;8{1C#kT=&Bn< zcCcXcjvP8m3LsN0h|6rG6y`E&(y>nM zC9xkop|bPvO1SN5RO8GYSfH?V9H`PWH@A zN1AMizj(tx`yHU{fiJS|j$SOLHKar;rNd{Bo3kJZLo$*M zooQ#jMmZS^?X8*hWW9mB{`;o2@b;|V9_ufUxk$5-Av`4f6YcnzEU0(0cXFa4$=TpL@jDZ^YStyd zYrDk>D%Rr{GQ)tR0KgZ57yR)v;XFY`{+Gp_ZfYdnaibf^(LhzXZ^lE#!H{NwrYY3+ zZ9DV0hQCA3<*+;mA2qskJ}9i{)ux|oxdCZ1IhjEH=1NeP^-0ObBJg3(jF%w46vcE- z26n=7NmL6&ShsV82B~GUKJC|LoM2v=x~JW|c)}wO2CPp+ebG1m*Xlu7aLkdIbgPZV zD6@VcklUrt>os{@!Hsy|NcqpCW+k}>psq_=R{;hTSz0H!zab@xJ>@@|vY!P*Jzqp) z#x~U9{*?oW`H?)L*fULOSQglTydAHdh|ipCGUBz~Y?Py!tDM)R29Hp_Iov=ZSF zX|Xq5LJg8?O;e`|6LC}V%8-(+m+4+ixRal|AuZbnDGBxK!nir`L_!Lt5KfZ)T@l+U zo?g#R@-W|P#UaK57HV+I92SvdrV^qp^AZ`pkZX~guKHXvIehPeZnI(gV*Me)fS#Vr z#(6LTZ@S(TI%=x}7KJl-|JAE6OMq=SW$m*Ms)VNory&u%HgCPP6zIz#l_C6*IRfXI zPutiu@}~zIxPxpLCwffx7kKKtn(x6OB)zP#*DP}p7GGor-WZLA)zsCiC$A$?NGL^} zcF5ts`U+Apy)XzK2lLO9m!_#<9p7g7?5Cz!;Kxjai!!Zvees#EGmIDicJ;(ZN9_~;b+9HREN?BYb^Zn{~+ zNi;C?Jgx|ut(8c5HH5J`PPi{){~knt;7_qiHHsa_;>Nf_0<{)2W$I^vIo03WvPThS z^*6p$O2z}Csc?Z)tnBmDY|@oKLTjNC^6`QUaT9-~#uhT4=I*g5K9PZX8H?7x;!#q! z8X6&BE9nszF39LBAsxcXMSDeh*YQ96h(PE~mZWmhLr&M;+Wjn{5*vLh&D=vAjP*?a zYJh1t-Tuf-3UY;mV=2cb1I)uFZcF$Ws!`G?qe7tk9En-5pRNWHCql`H+G*o}K4O$T zax)XiYd(G8|5C`*e=`!SZK0l??M~QBSJ`;2nKH2(Jf(S9OYFQvgM7(ZpCukR+S?^c znuwL>6Qb}%zxZ1OIky}{yc%@I076nwV^X8k?h1>cv|OFxcOksI@oXqFyZKC4BaKE+ zm13(SL|yLFrmSi*lUzLcYPA{va8zd8oCFWkRg35b3o?WQ1_VBu4h%Z$*{th6Q-{EF zXz6C-V%4=PUdj}w3S4u_Yc*d`};lr92Et5 z5ouzGo*>AS2@Mc|a*76Aco3+Xl96_ehB;r+)ODH;BP`?s>DkmCWcn%lDt%CBCO%;I zotW6E1uEbS2M*B`2#XrMGVf=__IvGwL{kpcefs;(;72{i+4g}+9gzsje&Sy$ty6s* zM>|Bm8_TUqzHdQA&f1`|PQK^mR&^H$TyBQokLgZTUeP6;GHGDmnUQI`q7O(9*1RRX)sL$R@Cl^zq z_mWtT?bj3F?7N1MHK_9BJG-J<(lSDLQ7xee3aQz71f(|>SSD1&V$g7WiiA_@=M7u% zZ;{lZ1yWKGi}`7_px53<4K8c7MdzHX%(c>ynZZki1rF8Wf`smU6_nx{L*j57GP|F~ zaHaiz40IzN8b36P`O<(oGimr*EnGMcb3Lk&YT*PwNL{020e;?yjy*}yn$lEcDiz(6 zWIAhot@%ZfYVH+r#0!Yw95PZWQxHMda#yTPdC-H61R7rqO9ytx2v6N~4wSHl%YE21c6Sdmx0C(Fubo0`rV{v^~?v-p_z8i8aO%c zGZ}!4x!cY2rMHJz96l@}9qQ~;W$r4I2MkB~kCg%L4z{*Y-c=Ug8-Va1Dn|N8F|S#W z%PG6(yT8(~g%pxhW!PF;8>}Z#8ikT4nyBvy+NJ~p|5Dg*y6`&3BL-Ca?Yi7VOj}KL@vIL!PBkPdjWn)Yb5imvgrv~ zq85zXt`yH`;!{p}FjlXhDTQY)@rtJ8k7Vt6Em&x%_82WT3u4wRk}?g)p=yWD5`C)Y zK#hCoXR4IN5MrK8xnfh)MK`+x!3U)o9j=hg9cS9g`&CykM+)v441MdJgh`E-gk(4~ z(m#;6BY`bZud%;Y`*O?~OUZ|^doUg=k-e<1<7o?onss8H%|`$Nca>1apv4Q(q-BMqx4_!V-?EHL#J7WkX)_=R(Au zQ=od#bigZV15mL!Mr;i7&ZIbKsTpHcPsG}Knvvby1S2>N$&hv+OLvNga1;g%L%urp z`Xr-^&(6=_j~=c-`x0b6JfcRRb0M$P(P1(-eG8m3LwlK8@noh?!G-%Q1@W4&vLJ!% zLym_L*44%b>UXP0=O_$^fEoXe;8?it&$aVl^fSgRQDMA~=5(89-}i$Y=}_R*X}ai& z-=Na`3cidbb+WIusA7*Q<-~8Fk6R`w>u}3^sE?>mx`h~y-=wnDfjbemDVv1VRtZW1+oG-!w8L+!pIaw4ha6T!Q7<4K#EiptD|-cJEu z7!*qwF@1=lnq*M|>BB*{yM0Ux?W~&CU4i3W#95Xu0E3za2+20k^r^jRx64gK#!pDL z(k}+suZH6&oy2A{Lo$P0QI_Qik8HF0T|z8ca(JXo*Cn=U>vNc?rmnEuvN|3g3B2}oGatEcJiL<$acGk1@8LVDG21WrbAtj{t(E5 zFBZdjHlu{|=EMgKM%)!;X;(b5a2{u$2ugN!h8`v2Y*Z{TYy5x6!Kct}Gp|@=rttP) zU?|^u4LcffKn2P)U>(~?lbDEEiGM=Iu9&MY|6u{iBu_Eq4B=-S?AQE*N$~xnwVUmd z^ZF2DYsSZ*8)*dzeIOtDiy#Qq6b@5rO)5QFm}Koqtxg)$FVUN(uoU47XFyI`{(Esh z(a6hy1jD4Pu-a0cq(eh-lz#qbwlGBCwr$2rV4&JWL!w1U&mASoEp&}!ra@BBEX4J0 z!NP*Sdr-~!Fd&Y?)!vFg8dOa&#qa`Ie4o_b_~-1BE=jQD4k!29&38AnGP{DXo}Vf7 z39DDsy_5DG9Q40DFCf0AXxEwbP^1l0aTzK}Pq}hPw=f6OOeBQUmUmTAo8W259bwyU zn9VDYbnM|ogmj2KWklG%`@s^CDw698F%t7#LkGLdd$0NEMxa>|TWUz8Ku!NH_+waJWOnPGS;vuy?k?hjuxtQ*$LDg3`e^$%InhBM1!fsefiL^aDIp|&BQHgdP z3DRf^+Y_5ZN5L0RoenCgO1tb~w*V`nuKswG5W#r#r zy*U59u%FJ+#g6^HUPW+Y!$5UPGvuq=k*#e^nAVwob7QbII7Bri5iweIFdzq)_!{MU^4=;)~^MpS= z{}_U&J_t@tNqsWF&u61a)(b6U{?qPGY&%PQZTK_X3`*8@z{CeP*ByUa8$jh?2$2n| zT`XBKNR}u;ciMBKDZjVUJ{Pyxh2{^5yj{!{J1Y_`^I%2SS}6%9SAC{KYesutU86ch z@_J&Ru*Tb?W%`|`SK+#FT3yYuQcTum(j!0xCKwgQpfHx!;hgi&yzN>I!FJYQJe6EU zMY-bGY7t7jHkRE9Y``{9mT;h7#V*&YexL|3iYvNqzK3d_a>Eu9#=heT*GsTc(;v&^NOb*x>? z7ZNzyn8{FzUpFEJgL-o><-Kupn+E1^vN(YQb!JLFgz(8SS)Ou3u~%|r=>qoO7URWx zam0jg2x$B@>C*|K0FI6{)aa$~=B6JI{J$b=6o%%ds^HxnAL)hidoIiicrQl2t0@M`8;>i`{K-WWGsl}YVZ%YaoK>_q{3_E! z{(GVf5wKDnysVF)a*z#VTmiWT-zErau1w>~;7s^m#&n6Sc=r@A;}$Zd5L02R1>5G^ zs!IE%qO-MUp8AKFB?YrIVsbR~>p-|d$szTT&eyX;f7(?EMJEg9WMdAv`jgTbEV~pC z_|u;}Mb_kmO7V=mq|85b6f7#LOW_@^dD3IYsRK3rJ^Ry{^CgOkST(Htk>}HEZE_dn zcJE!ge8-j${8vT~4pzQ+2vZ{3Vljfavo}@X;#3{%qDnG6OiTLbQ%?t(gM&o0Se0OS z6i6vCWv*!*nm3S?u)dv70dN^A|cYXD87D8>_S) zfCv}J0+o0!qWo@3Dz41d4K=q3-j6ihqDs^Gpqu6cw)?2-j3ElBkp~$1cK#6<-YbQr z><=gVno>hAU#Ti6ww=MTd?p$&ZY;-ju1ByAN9tSOAXpyK-GrN?G?)aZ`cqBn*c2%- zXByxa%*BM0jdG8?9j`H-#roWREi9M(2_`u0_;~vAjU;V^EU=Dx9zc}Dpof~)^Q?;q zOc-v{F|hm~^{QO)z&DS&rk)jG788m8k$iQ1f{3GhjZrp+1eeBTZ%ci;peTu4hdmPe zG5y_`8?YRZ)@s&YkL?fMq193;f1|_eLN)_(x+c&F(@%#h3RCn zEz$O-;uTM!JVJ_)JKmFtFC#1c^#!|u`age&Ab&(#Cr%a`^?lvI(;9s=$V^|vVzG&_lW zID~MztiI3o?z7o6)mJdc@5;kF@cAD6CWQFnN+KkI?YL%!y=0#061>s%E399>US?*v zmPEyJydz^Xi%>fo7Nw#-Nym2UueyIE8N>Iv#A-rSz%w1d(Z8M7n4Egv(L+7q?`us) zU{kBd9oKDlIoihBS`8ahsRBmUupecunDM9hR6_!pCYP~%Go8=IW_J`xqotc0&CmvGpzNm*UvI zp4_7e?}eg?)BpK`RF5Je%oO-4mFaSqs2P>$uteXmj>}*Q{J=Jh@SX>CXW!47zOz+3 zrcWdsykD?6i3d%!jLEqxU^-Mwu0X-$xsc5`D~y<6Lt>P8{DVOXtkjW1j6tp{-*Wex zI#dj#~>mjdZHyeKOK|wnlL!K;`?UEvuM0YG)^bUN> z@ekZ=Fp|T-YLc^G{Bmi7D=?(q{P@?rxRk!%pJ|M9a<(5JWGTWk@oBmh5gt80((oFW z^yCT?iG)+P`j3|$A|OD7CSYRTUh1&FKS{Ub5fM%ibl;B_ysSRhEdg>kl8QwsyNM-U$TAMtmkbnOWnw(lVcC z*d|&ZP_pxDW`KBuReTZkF>!eJTiQY=N(KqDjt{T2M3N_nwo6j`=d_&3t9PoTF;ja* zpGtN+p&=)cp|e=Oc?VZ{RfbZX624}`q<*T-X}kgG#SG~!b9;S znUNpKLi#~N!b4|CqDtWoUt841RZ^i!k;DjXYWNHF3Pt@|l6s00BJmS~^gBR=*lD(^kPP4#VhhD+oetig(a6?_c{Jweb9<=(w$sdX6s(5A77s>Bn0*bMNhzAhyQh;yVhT)&q8Wn zDgDP?;4i`D{|w0gb@{FvF6`jYP@U`fdWV6L5gCW^U_<~c0m_6%yTxTxPfw4304(@J zwL#BWXJ@BTRA--GNl{VJ&E*g=;PIqx(wCW<+I-H7D!c9N=~(||Cb{#bwY(uy?$_M9Hn+o>I?0`1rLx^t9ft;R^xU^}d!ME5)Iot?gSy+H_WJlSmK6E>*Wl4;*F=F2Ug$cz z1!#15-j)KNn}E-oeCwA{Rno)%kP~OSZ->QSU0;WIdU?sp$jW%t)z%G4NJuy-a&HCR z0$z_4^)CmxIxoGzH(8_g_-vJ{S5$XihcuZboxA_hi&s5 zWL*D<*in4jRqU*{oGsk(y$B#~*Av-4XzIMJXnF#Hhpfx+c)ntc;!LH8_WERhJYD@{ zwZ(aQ<8^K0wU0cS-znH9nWsXd#_0OK>;08WRZYz`!}Cu`bcIffQ@$807nhrf6Y(9HngI%3!1IN)qo~$vKd>i~9cYPg#}kH%Up!Um#lpgB%BUcWy=hQ~UGh z9l+bpyZh3Zo@)j3YkJpXdbGerH`Kv!MqORqkcrjW+M4NIQ$az&f|p4W@ckb6uACZY z>yd5TzyR=>cf`cRL|k?QHZ?XX)FB<*7N*;^=9QF`oH=JduX^2`ZvYOE?A`nBO`jCa zGe+3D`2H@G^9h~zs@PF}!MmF1*GTAl@T6!F64~Ft>3SG&dmqq$834$Jwzjs8Cd!zi z|D}|D-y73^y2>us?mB~p|C~+j`>eg;8{WS#Sd`^;oxbssS>?S)cb?$r{jx*+e*FIX zgTgRjX<69{MT*Q`I1bZ#jrZdf!#Z6+95azTdJ&La+CE$9)!4 zpZm?Uq$0p!6C&CCb2TvJIN-iGY?!@WPfcxJ0QmMIz)Cr!4_18kZa&C5;|Xg#S5iSQ zM8A&qy~zhMUAMo#Jx@014&8Q~`vO#ZwJ7)T+nKZTf0!6T0I=LxsYYqPGh9`Cp7?02>UVO-$TZ1&p^L}l)mZJaLmu;rm$mc?ML ze64J`rAI&<4EJNp?(;e0KS7S~Ubt?e)#X?L{O*&FX}Q*A%qgrL`tWy^@2w&Q>znjp z!g`|3Z)|oRBqStK&_2rE-ab;-T|?DtEaI*x@zYch^xm#BxW8WSuL$}Nz1gL|rRJhw ztQtPAs3MH47Mb{PpOQQ4_I}A-ZFby|X+Q+ZI@q^g4&uB5qN;pOt%b^F5bEr>I&rgQPn`#iuhyiuVShB}WuI(?5wM1_Zc1PI=f5Y?`pK4)OlMbf9!@8ys&IQX@DJPN58hNY}rqYm*+%x zhA#sNQ&$K=h9%8BA#trb{0da73!P-ts<$}Ub#^_h1BdHpb|_QcB2AfK3g;>13R-ca zHHk39^=s*Py%<0#zkKo%TgD! z@YRfscfLQD1lsb&Kj$pT?Hd72B2uk6I5-$&j#zt2&V5_KL2QZBgm6L6>vW7_P7eb+ zE89C;PEB5hEzvlhwCh0N{4ql?{67@bvr162Ce-AYoekCtS=&BVJiQX*GtZ_otSB3~ zKyi#zt!U!~(BY%K?{&KU^{n87T^F?^q#yZTOe5(JI`8%f>!(cCaq==Nmgz`yX6<^- zpieammD_I>n;$L(ogd8>aXtB5@xZ45Q@!SBzUP?xD!wM9WO?kTq9_UgZkv2`8?1g? zP4XebcWo5iy*r#gee>a7WovwuiyrZ5WB_J6jnZ1PomvHtWlTnld$E&xzSYkvXveqQ z?=b-%Cs{XM+pk9H?7{qQ-unBiyF8aV9v&VG>m6PPC5D!jqpRkd{+$#JGoY4T@G0up zzwnJ*n2IM`XtRkBGVKtVOH8yC#Z8bWS;*iEI8?A=k&T@HFR&u>chprNRh(4*1uJqv zV2D^KLh+dSA1DV6srVOHddL{a*vWt~nL=LFyi?KSmm<8}i2Q$G zkQ50s7PwmKr`TP$f1Bq22RPFD(YDb3#h!mVQ7A$Zf{v*&N%_B8`ltPW`zJ+mks(A< zV<13nAdfHq@4x@=QZS@-K$XIb=@X^|+xP#g`nRv$&X9g$A3PMg)7bwDn*N`a!R1>d zF*GD00WwaE|90swNc(HjKdl`=Lxw?KW&Gf|C@)o3I7`B zpd>v(`M(|ZZ{`1toU%|BMm1IBf3lDNR#}R~f%~ske!^&mC?fVDEIHA`PT>BccgzEctsc)9c^w427n{kFC*FB zM|>NP6Y1&|S`Av1y$dvp8?Gz1$!|TxFFjnHZ?{!lYmfLkGvJfG z4|ye%U%da}PWAfx3>a7Mdio8($HyOi5AS*i2fmG}cV10^aZ;gM*Yldb>PX9<(lXz- zX)q)?2i&(zc9?@>y*A(`7sbcw{q5D+u6Zk%4(oxfuf9XuzT>vG34HK-gI|ZZ@-OT7 z23WTP=PxdOX)<4)XJ}e=YIy}eI`utu<>lqaiUe;h$3Jj?@T8YLE41VJwjsdx zl3KL9A(uY$<(aA@0ePvZ1cvmvi1hGbCwgPkXXfkCPk{@c)HiS{a@z&Ih0uEG0F%>q z&&iYipD?h&@XtbI-(cO7B=))a9%TJd?;SJY0F+v%KUm?PV^HCLr4GDRf2U9xWB%Tj z;2}YkqD*4qz~nm;UIm;^1UG2V*MrB}C7;gu`TlRFbj&Ij^td;cY=3lgM4QQBJ@5Aq zguz>>1NeG^(z)!%ynAv-kIni1SB#%UMWO`WNCI!Z zA<=%?!ZUqqJ+AaR`rE56=?{9XZro5qJJA5&t06Fu?@G1Fa2#I;zP}z+{>@3)h10k- zEs}kIFDy*X8$Z2s>s|g-f0?`Wq9E_v^{747|E(`jHIx50jh*z~XFCTg#sME%gM))p z@x4?@3h@JNfCm$q;S+r4?au|;U{YW&!6Ha(J zv+&TUhEo&)uQ!rxM5qkLS{EkYS#?qmr!JHPdoT0AP;>|Q8m|AcO}X)Q*R-+ifp@Tb zK_gniX}{hs@3v%h8Y%*Cl5mL`4g zeBSTu-|vJg-hwrJz$u9LO2_@WS0~Yr5+9{dCHIXQ5Pp^634d^pqYQ+tLG z);|%ynVlJ~k362=RkPI%AEVzNz_-r9V{xvY;^^IV@6~m$8Ny_r3R9-@jQ|lbL7o%$&XVIs0V1pxRA+K^aG`P+*&R{rgDs zIJ$NO@_S*tCk)NH(x4e$`1dwBwO*MbSxVqg1;_I1gh8{D(d_)Z=wm1rcgyxKwP;8> zW_qnB@Zfr*Q)1>g0$w;VAQc$*m^$&R)4PCgw`D#4_lDnPq$MozFl_zqb|NS+^}^Wv zhrl7|%>VDcPDuW{OCfbgb+_bXNL;<&jyvziXV$^!AC)zc{QAkPB?^$tbSw<{1wrK{ z5e#MRfPTh&tw~`NrDD*ULraRbBA3@oo8O5(6_f37q;r4Zw|u`8)EqEjyXiM#uyl6V zd)d>ZsrwI*FL_BMHxUsvVv>qR+yp3l$=-K3Np=2BQ<4J%0H$cpZJ{T`HV-Z&Uzx} zR$n~1ogn}60&jcI#pjJicoxGSmiXNc1D}WCI4n}m#Z*0-wPx9f+jnc9MO_5xRBBdd zX!->F-qRht@lol*4Wv?Z8O_e6tWMdjy9wONv<6n<+ekrjWsleTV!YlE^6%5RKR4WF zW^(KfZg>(8eh%6mV8Mu}EF@=beAzO7h=NoIs^*Kog>vFHYZ=;akcI`u~(pP`%J9}L*1i%759hM7O z@H`dAb%r)cn!oQYszGgSz*WDu0Bgm0RtPi3%U zQF=>3^P`9&MM*r{zv#Am_3tqOg^tVsIeIjMKdvb4eAu=oPu}S~jdOm;iH43Ug!kMN zGkffhpfes}PH<>f&S%qgW^OahV;=D^qb7WKh$+dPh4mTTt}jG_xs{07ArW$*I3a*#Nfj)n^~(XdNBP(3Y(Fz}|jv45xzh zzw%Qb-X3Hhu$aRvOW?S@BIqN==fAWRJK^u}q*}F7HMS`%dd`pQbI@SXe5A^7Q3eE7 z2~0oKZfu7H&s?Me*!e&BT@@XfBNtsy_}9Ic58n{?n!P&7dl}lDp7__QT=w)1g#3?`Q_!dLA`04o!rR zZ-Q(i(wZhR^l>D%=bKuo=6rg*B8_Ij!My_TEJ@YMmu}Rkxv8RH#gJ-f&=fb@W4{-U z*}5!pbV7dK`xHHiDNL)THaiFG8#s?adiFMX50q*e12nwh+J3`bZaL02Es+c!wJFrRi5qqEZFdkN-fd zuNfrlL6N8Jq5sPGx^?c+#m$c$_e}5<Z9rF|UxB=?l#tf8%S>tAFA4S@s|=Q|rqW2B9im28L_r zJxO52rS;zJsB>mC2`!n)R(38sXL1nDVOxNNKF!5@%EQ~Cxj-$0C61ZNb6RCwv~&|x zp5LMi=f)G13i}DGFP|)rRDeMN=&YQq2!@`wmd)>o5ty;e6xvk5uj$lf-ZIJOYlIBp z10?k^3pD(gm+nRM-pmw~(-yf13Q=w=NIgy2!>x~=_OF}ae1V}{-{hy*v!i>W%Fzk_ zT$$B<8>Al_{&c9;_YP9=X>&y<#k`wsIngVkAKEkF1*y;xrt|g|Zq7bi+t69(xsR|W zbN&t9nem3p-9?FqlU{3b>Y|e}TA=;x0rJ(9&>kh#ST{Hqr%GK-`}Cx_aYVRS5h(Sw zhP{-%Qu{_j-J=uF+QQ{PBll73QHzfVO|bQb`re%4FTY|{-vKt$UlO?GHg3rEwZ#r1 z-ab74+c2Ou^xK5x!pV}!2hjv5Rs!*B4n7_rVQnb3!||L^_T0i zY-L^?&6XX@^}8ogAUSZ<%X=x86#+|DDuU?N~L>q`l!QXT?Pt=w}PBklCGOmz@i59&vp zK8uMoxr@@NV0A^0uEJca|F+t*CGL1Q8*x^jnkuLe(qkG>qwdA;P_SIn!BD#r5@4Py zd?ZZos~h!^dOY;~)P9vyz9RbV^U$&pM>6W$<(kQgM4?+?*Zos$y0sfk$YLSpMBHBWSQDXLm$QbK&f!#5rTmz`r_0#|PK@-^f#=7$KFhXWvad2ojC;)w zpvpTYPn#w{|IJjLC0?z(^VZRR-nib&-fMfg0O5sc$(j$E5rsnPFA6P3fWM@SPRKZ# zPM5ZN2O|#(q2?kv4{s*^MSp>NH<}X4{f)zE+KTXos2VZfNIZ=$BAyssVYYy0v1iQQ z-c33-1az;{;Y8A25$xs}EM6@&d}rbUE#bx@yD3lHuk1AA(E);Vhc>IC5oxU7ON#)* z*IOc8x8l`2s3}qpz3>h`bGbKP+}s5b?fCtPba6ub%Y78%IU1fc${4WXVa{&2DZFqt zzF1aS;`*Ktu!lbpShzk>{9q#_9dgOKXI3F79Zd-bk1as`8aQ*Ef3|hJ%fAt0E zb@j_ya;Npv0h#D~zcZTMJg}Otx1l{dUBpS1Uc;8)T<$BPwbFcT->-|gil{~j;oe&U z)r26MOQ%wg!GsO#h#~!N4t9RN<=E$1>K>1F4wGS)_iI(e1BSWD9VP4>R~nt>-kCY1 zpybPV#fnWr_IzN?Dy)egJQ#E?5_Haog9GdNa0K_ZAyf5D{>wON{)LK~krKVjFBP60 zgE`WA|hEAEpt*4ZHUibVKg5C&Q?D}HEnuzlo0O{ z(ma1R8On=Ix@worzJ6Q8w4mS1j5iWEc!N8K$7RMGDn;S=>cu_yp?=*Hn_qi?w)Z2! zfL}fpMe?<=Dk_vi9vu7@+d+x#q+##%n}< z8Ec~E1YBIOljkB<_1JHc2Rw_eB#sw89b{hkbO1FZr8MByVauc9{#$PXBn|z1jhLZr zZ?6-!ghtvGg}nlE1b@~R5p zr|aR8Agb1s_89VebeYMkU$F{T@G~wcL>=eJDUOd1WyV5CHqesE z1d>IgE;E7E00yBXFk1U;E#9#@?h4nJ|nB~>GIACWs&qedH{Ys2|gZb%<_NQqRo407C)Br~MZ}i^Y23{W@Pl?%Uk&YNGpk>zNV#)@l>)Nvk z#%{Sh^5!hL;Pt*I`jMk(pbw)83urWpjfy3ck;aQ8F;se~dS$Fk!reY+9SCn@*?#wC zV&69%Y$?GJKXC;~LW%?YK{UwxF=7NLYLcyOju2Eh8*p()| zD2pVYW(e>Q0PTk4a7yYzE5;ee_u=-qYS29iwdO4T zk6DH{c89aYf{0#?1N^Y6Xc_riHQreyJHvLq1z!}4a^q%5NwJw_2Igpvj;&hac;n`M zU0KW0y#D+@-nvhzS7Kkij2<% z>LzVuHd@}q+;X$)Ua2QUnyV3H!3|A-#Dc^`z26UhTX>hLWpFxtAT;-bL~ijMP%}vKPBn>!c!e&`j z-r_jqu;gYUK==W8TT9i!rLZ^9@GI?DE3f5m9zn)#!|?>f+~@Jl$r*66d@bxmzQ)Dit+p1PNO`2WuIPau?Ib}oRbt6G8XXnP0`?Yl z!=LC3$!(Mi(jwk*OXR`o9ezz$K?~cu$RZh?|D!T=JB$2_#6B&X^bNKL7Wu_{1iI;b z0p_ZkGB2NNcB(oKSm%s2F<-B`91j}?iJ6Z}_%*7g;)cf;{z*3c_c}aNBTbW~hAH!R zL__yKoORM}b(Pudpq@U(lww=<;P!&Jq+MF}l((qLCUv#OFyCvF2^#){QD}o^BF#T^ zm!)Q1j6W@d=zProLuv(z`~|CBS?4*iV*imMy42B29RNjOr*q*2LJu&|3~F}d;U8`aVdkY_4z__)FPHULRc6Amq4^V zf3_cqfcD7vr0A$IK@<9g6Uh-DKb%NpmKJ4UpahElThZt9yTv#=3r6RM1&ToDhg{%& zU1gW=vWa!a!SHbefRR2jDYJC^BDh4#b%9e%vsa%KOp zc=KO1<%EMaahM#3a8ZDyUR^q{Z)|Auzt7TJ_#XwyESTK%--otxix}eIKCdY;O#uT+ ziG9A{|G#~t`YY2c$NMPDC;f+RMnQsC)WQ{wmH_%#X3W7F|1Bz{97%Yd0Y@9XkBq+6@p8&nGlCf*I*_ z;i+1g*mQpu0Ti0(=I=Z!=-iuze#-*0RHS#NZ7 z$f&3oCR`;fR1%K|x7toQ=SBmRi(6=r4bvvvonrTwNI@x&(B1@Bsnv9eo@S4>cIHR! z2{%Vr7Ov4|^^JY#8)RehT+A}{w$D#Taf>N|+~IUCf)IF%@EN>Tf_@)Qv)Cl%*zkkO z>_h?Kq-644y(GA~HyZR_8}hUi19Af5>A&mBZE6^3XsBndZ}35LjKjjcAAVj3GZwjd zPuKl&_M+R89bSf*{r2IPmF$yR=S&(tNshO~{+*T=~uT%gDU)tAu59mf;yBpkLxst>V(fXi zR7<(k_*4|zNKmRbRG*-t+e=syyBjU|6A}`Ll=SVmUx|5Q#T2twJY@*7yo_=Gn4`BP zUXZvBo(FC>j!ikg82zI9{nw^{d*F@_&EUh8-mx-`|5>dLRr0kx5*PvE0T=$%n{r*VZP{)x;;@p7;8klZq&T z)(C>WbWz`V?U4mqBkVGnP?`kpT(Kxn1Yrg7Nd1B23hp)?J0Rdf@bg@ zYW!@~<@s(!QFboM7$it|o+kXJucu>A2D_POwgzpC0Tk@#PCj~e7I_iQ-1UkIB~>0l zGo+#{VNvP)a{{@UftG>Ksv6ngQ;8^m;mz{3%USxsgH(cFP|2x@Sk`S)Kx(q!vfW(-)JB`Tdl#dF&TW>$#D62TH81V%7l0vI#N}LM5zT)fyOVH zu@YJqmW}j{h)j69l*VD(_n&zAf8f57x0A~_rlG{f!7<8jrdjwT%Q`FziJ*|KY_<5&8#%m`hnZcnUT*;1r{IYK% z7dUae@%S&$20)%p>_l#kvk_xugbMPoLVN0fAalEm0EUZ-#um|7+z$i5*&iv;>H2mx zb$xk1XekS$n@5pU?3Awky&8aesNheXTH?UHdr@VXT4FAR{0n(-v^hA)o`Tag(Y`D( zS5+#+-ANnxT2%bU53PJ}Z0XYb5ItNs|3JVF=)LkLedKm{e_9%^@Zv~@8*GyGt*Wug zpn}c8fhay^eTd{bD;pQy?Ke4eU%mX&BBc0k+JP&&guFb2pkL7Q6cPY_wEFmh_&|#< zdfH-AYBJiWx0%1FMLuKR2RTjta)wlPwI>vs9gQ7axmUdxIMh7NDOvO5tZ&~t@zq)y zn)`qO5^Ae%xaZ#793oW~c|DNI2UyfpXMQ4btmd9uh|;qf9xpP`Cws-hSbOQauC^2F zFbBpj)LSqTU}XPA#9gqT)T4#+`m6lr^hvK3Z9}tXxeR>YyE|EM=LrH{&vLeG%Jymw zYoZ_M-MbLomzyd1;Jdz?7x(?3KpDhf(>E7h4xB7RsXFKVr@RvL7}K%5Bt*_9YV9Lq zv}EC`WIx^yyrloXe>;SXS^qpe79H@fDIe9ZT5>*LcGP#<3AT7MhRO_ zKY2SW$zg+oYOEEUATlaM;Y#G$(ZNYx$H_o2-TE$i;iC~404T}G3zh93^Cdf=$_4<` zLM(B%HlYu&g2Z$VPH#5%p00;YK6n?bPy7L+NY>2V;Zxw#@5Ew&ZP2EI9QV{D}gVUnC6 zN%ts_9AXPVX+PXSbUF~6w0}AeW(onbm;GHHrLG(@Zh{ytboNr$+qbrmS>&Pb=yT!) zzWj6Tq(0haUK;Cw%@y+jhaZ!u zZ4!~JGFs$6gUVtfxN~?+mtJhLO;dUIiS9F`pTmA#K?wQ1Hn7aQ-Tak9>8h?UW_5>u zj(PRx;=J>d&fKAKmtU5b_PupXYZ=$oh!rOl6QT>+qE1W?l;L<~oi+Zdza}zfef`8? z=Od*sj^^yn8=AbP0GCfftEn=xCAdxCn;iMD_V&fW-#v9vb$q4oWsbb5MY-Wk-{%0L zw#by8aSg@;x1UWoYuGJ1g0s3Ey&V$0a1>g3$FE&?+PlX}x_I-)hi$Qz)s6Lhq~dU0 z>0Z4=r)>Be=@lxEt#nKO+%j;w*-u`+e`=zeqP+7!8xz&THHlG$ht`xSMoeSL>6* z@5u*4_##VQzq|{aUmu$B5BUy-A*E2DFs0(){Z2uA=j2BX&sK$>6_RB?ky45mkD^@G znmxmdpC65~)>p!|wE*>+IW`6|PJ4W~5+yhZwAc*M7Ao-C zOfL(@5^qgYCo0$A#>IEyPH)>W4uc_W-l_8DQhgss<` z;K{9IIUn2(T7egLnQzzQYw`OrvDg6QNEDCbja zYC?7t}fPjr5jCzWvoY--(WYwinhu z<()nPAqjIP!yk54*LB|g*X{UU%*9V{qj*0z5u@}Gpzd7cV=H9&9(wDx$B5!A^?6b6 z9eZc(5zJ3@>b8PD0@A~~KQe(KHRaMbyzufP*o7e)F@5m@%%)*$W zOL@;}OUO`R6I?|kE#m(r;Hqmhtd8r+wF+BCN&*5pupxKJG=WwZ(_AXxIua8X5KV5g z@SI&VUewH^p^Bb@vaJBB)bX#Lo{E#3xC}MRXY83ej1R|(ptoWL*B{v^QD%jcj@;4v zpshzSl=sgM6tWmynjVe@^H}GChbu^N79x1OB~g{P&c<0BM{M2-6ZR=mZ{1p9yU}!51bs zp7uDxS6#KuY9Nyu!4=~E9Odq^W5fxXrFn~%yen?j+|CS(;=cNv+(fne;tQ_iaP#vk z`pS-v)XMFO-W$J!Ya=JTf9*f)UQ&UpUKgU+_W}FtPu(0g)C_jLEOHWXTwe+IO6@%t zHeQCL4nW_fT3vhR|bky_Pmj3}cyou8dTeCbM;o{u+(>N)Y8iur^ly(}r&G ztHM!r;edp5Who))SaY?!ilj6d+kD3}>IL=URXv+KJXXUt7pA2p@swEkN}qIycOy3`ko!FPp5$RW1i@4H_#VM8~S z%6rRGV|p!l0^Cb8fh_zn1dt?*N-ZHO6;Hywzj%08y7B{F~%?1?Z41ZKW%aM2zT&-i zU-2R+oI8aNe*Gc8qTWG%X^V)}nSRvPg{SvSzaBE5<2t+u_Zcj3>G9EtxW!5{s~RXD z3rs(h#t-yAO*IBANw0>FylaVuewSty(urkoex$HjYSd9JP1f z&N_XHx%_~VU)@O0V(5Q0ttJ$pDC)GS2wob^%&%{a@cANzsgA5GsSfY?wM#20W`lCBH@bc9v)vIUn^)ZD`)~}B~DJ7CjUrLX3|K;E-u=R_E&`S zEzjPL;0lzGh9{?wqO*MdpeK5|(Et;4VW2wd)#3~*TrrvH>B#@)>fEwEP5~? z6`a|=XJ;<6w>sgipY#(&Nf9e(iAYK5H8;YLd%?>&T&qn6HFzC|Xs|;(Cmf^C!H8^Z z34HdJKPvRIJH^Ab$r?GTC%D#vKyPKLh9KX!iMkppKnjsN*N%v( z@n$;LLzXGxgGjjADEHJfiytg?03}Wb1HkJ|RN%37KUtc7%SaO4{LKvR2Kj=IQ981) z!oC*liQU_6Elm0G2Z*bxxK6yR(0JbC(+OP3o@ewSrPtZB| z-%F@aa8fYfLJCKz8V?Vgf0l=!ubDw?eEU%VR?Oq?o+0jqXu*rNNtS>ZV1_VhcNb^v z+FLRJBeXxloipxw;Xk{B6wBn`kAP^p{U{+b)6SkkVj0fCBgV$5=W3<IZ7og}p#LKi2S>*jac9_ER@-n>X(H0cZHS}w`?0mdDF*Q}M`SfHh1z?$`y6yCx z#Hx2)Po%meX}dJ&Eu|47x$SWNbz7w%OZ!QELvQ(v34R)n6dUGp{EYZ?KdQvmeNzPV z=-VrJ*&Kt!#o!UIv|kc+-<2)J#5)x1nn6nyv4nyPl5Cvxl*$m}o@MiA2YQr? zc(Bz9`~E!XRGui~v-<8E3gGG2D1lSyvQ-D}uJi6*B5F}>>7x6x&P6r#-y)%_JwI1v zmEz&49-Jt;;2~E=bkizToHe}E+}L*(P`ZqQ`mEOic$Q#&BOyqaRP2fj7c?`DR;`3q zkfEgmZN>B!au;h$9AZP7ss+Wl9HaZf$`gA*ND{nBkJWs_`lE)XxvJ-GFarH0KCvt{ z$ygTEtYjUqabh3)oCrlJMpn=DLn$Xuw02Qoh8$0*mb)KA+UV)zta#{2F2$Y#fi(E_ z(P36WLxc%&3K$JijdL-RzF5cGP%h~3Ylixr(=o=aoRMt_CdS2*I_y&feka=fJwe29 zFWh|*ZphytASl!nAz{n#sJwd?POgx@R#aSjqCMx@uVB|yME!>{|={RI$i7MfUvnNlJS02-5QX(|!b@t>;xPNCzp z{f4O(c{-j0q(Y?SXl&k18}L*VRin9~1Ci$kbg&HUM?5&Bgzy#*g^2m=FTUY)grA5m}PngN;V|mS7&$F?Huy6(~&PSxkezK`i(Oe_ddW)T&QtnQHI!_U+{R;La~fM&#^Y`7US)3{*sR0~+q9Gzm| zv$yFF5Ax2psC>UF(`{l0LDbPjDhd!KEP0#4%))+h9pCW+^{<-)zs234{S^oEJ zx8WuImm)#I57*(nHfSGvDP7HP!VI zTcHAYUWo9WN{&@sKy4N~*N)A&7lhMI6UlFUZ#O?8I$=6jq}7jqSMa_lvEFoP&E+bb z2j{DR6@wqaTbV51*VC&S!DJGj>{QWv$<4Hdw}_nQyS-a#-<1MjK<~zh%%>$5CPT7|%Bct?Zy9tqkg_W`y&% zfwvJ?WZZWIrpPD0EWx*KI(=YSaCUW3@8<;@T1W;yD*_+HEu*QsFfpt-4B`+^xTXkr z!^$>KK#p;22B3^qxBZmgx1jd6gf^#!8-&5eiOci>D^G^i1S!Oi_JyH!tp6N^j^TU4 z`k0dN>5pOgFY_C-YSko1eofNYCOvPh5fDk)(2+~ol@N#Bf1RA%1dzN%5L)#`_tcuP z>oqmNB5`(kX}DOs8O3Wq1mktT3YnZ1LpP#<;D&xDU}mj5n4Wrg3It<)nTIVTf&6dD!Vljv!6dg#K#4&|~nZEA-+W&6*)>z1Igx*}wKBMKuGu z4uoo~yr}gO($*x3(0Hf+QtY=l%xPTnT}8b6o_^AI0DXE)y;PN_r*8W}O0C;KNbOzJ zSU#ad^f1CBMM%yN2ezCW5=-99FV^)hIi7~4)kXljFFfes5qGl3pTYP1d1qZ<$*>WO z2GVT6)z9V#z4LNdlTnqrBFlKxRWP5u5l_?-_HO=k7c2Ahm*5eU{I+#K;dhGF^nMoY zN)+OSLXr2Iy1%F;%$BHb@=xHfTMjhi!o(zMuHcoW?dx zr|;E1+RHv`$UB@YA3L4#w|1_cot5qFwzeg;h)f-&Q?ao(;}p};-;;RDWV5||;s;|tlrH}hTB z(itK_Y(`|V=rZ2jYVn7gYhKZh&lxJ4h*y|!FpH|9Gv$8{MgC-};89Te1xC$DWSo8<&RgcI1vHbi_nOB@1FW0$x z(!NooQ*b>uIs#>!0!fT}n6Vub!NrkEJyVM*xzuzg?)q^!z|$VernEX%^d3D2m;H{*b-DLW@Sbnpl;?Z|Vt%c#93$~w<1H_Qo}ygc=g^P!yi-v- z!;k8p^BpB=Y)RxI5h%wv*eB4`gs+7TR1CIjYvDe*aX$2F2+UH!*A;~g3_p%*5=JKs ziSqF8M~G&A3Qo+()<{c*@c;P({RlK9$2F_(#J2=byffvqw%X}OG6^xW9*5)`i+egL zTqCD7hK)ubglUl=_7Z3GeTw0v=6;8(4e2=H{)vosv_V2j_u45spqiZnIsFBQ_?Gq7 z`{{1yeB4nSWB>wX$UAi8r(}!~lwtT}pA9&y(#evq0*Si43v`-7d@S7R-l97kWdjNijZN?D&uhrVUMq zc3yD(n~_XU^$+H4O+#)ta-$~VvOziuEIHyR3MXnkl{5)fK0X-H#7pm>SV!^ntnqQg zV1I;Z!p~Ef4)b}&<|eCt1)F3Ne9&?tXRyLP!ub!HE9~RAT6U|^FxJ@c?k1xAHf)C8 za>92w%@TLK0j9WW@0t7cI7VX%N&&cUWeX{hj*%wWVi|o{&Cs&^U`uztM10t?hht!t z@D*d=M4Y+9RN~~% zC9>Ua{9Dw+DkJdS1=&hM4!_%4cj32l64T4(!!_O?q0@}tVq9tmY>Rn(ExOr4gJtQc zzx+Ty51D3yT{L}wlu-Q!?T+fP?g7kOY7oM|wp#h>c3w2PE8KWopdIBt?CZar*M&~xAS#`A8{==9Ox88od*)~M;D5?ux_FfJk zN)-;kiiBV&6YgiVAKQsuld3vz?)>h2@8|3L|;LT`yL!r->Ak8v9FW6OWVE#p?Doj07@pRvHY$NvC#0$s1A;zkW^gN zo#r7*x>m~}2F(ezB?Lum8!fzP40U}U8K%zg_Q6TS8Qxi76fXSv5LYhw)Ry1Z_z_>@ z_rK{H_{l0c`&qo*TDzoMygZ+qQ8-{bw9MoM^s!cc#lJ8F_+aMuF@$f9Z*+B_Ey&8L z7|*v@8e~X$1V@^d}c zopu4(G5c>p_8K4?(ORh=$`x4d_V(yQ^D(r-BzAA;o#wlw8oe%Le>A9h`kJk|^H4|d zDU0@7yBk1Uxkrth!$!RmEw(T@(s7NqSnWw zF5<;qf4!oWZ+pBWzZ+(YH~_1ko=m`J00R6RI>Ya+NzOuzS?F`83 z5~p_LS%1!0~5O-ML z>3KW79X^*;X9Jrs-gqLA*77?nwZuIM!}8R<2@);sB0>l8{nU9`Ev!TcyuH78AL0S* zfnc$)De-hngC+-=(?6={E2ERrNZ!^g`8JJ~;)JNC$e~)Kd@{efOVIN>bDuVQDHUp2 z3!LOx!|YaKsUxN)d$LutzTp?!sFs$OOA`$6znj<6u{E&yrITQoPSJ{A|H2mypbxfL z!f3w*A_7TCEW$fE+ljpIzIWK5n-W9?={H_hj^=8BPQ#N<=J$luOaHVw8t8_ibvN0S z%t0KD|fj27s|( zr3RroRDQitvb(*xxd|F3x56XqVDC<{>V^km@r5<+evn9_=yk+A?T-(ekYgp0!`$qI zKDW@VDZj==PmvA4-B&vv0=BoH7PrA(RE}4zII;xP$V@J_xr^LP(xh>j$g*zH6V3Ot zw%a1??)MoWalL2L%85pj=-3oGU3T5E#f!E^hOLjEape<+%R6gGd3Zdwj!#CO80hQ2 zl+?ZdM6O=TY8)bK^l?UE;sUsU4-a$jukNA&9;d6U$}9cY`89$B;#j8<-u$&n zGR1v@eMyD^EFkNRO#Nee?IqC=_k!IQoH!zSGNoj{_vE}cK^els1=pXFS@kh{U!ECn zJ&YS1<7{eW^~#avPzXCN1h3&zF=1C0R&l8{BNm4X374kPQu=c~Auq9o#1j}}7>j-F zF2Z}Tb8v{f)+Mso*M?CYf0O#5Nv!axI)o9mI?l|MA1ofTrV#PFpHk?K%v#+ts#E`= z5YzHu)5`&UKtxIzsk4!txcvFHA|Kng$+qvoBP)mz8@(t6i(tLO~Pndh)>u!87%qsEHKnw7~;Ul#ux z#3(meCbS5BU7Bu9rtelE49h4iNF6t_rL>Kp| zqB{qua2>M{RaZYr&*O1_{a|_%oc^wYD|kzqMmpu)?A(74GO^s#)jNXI#H*@OGD&_QrBCKLLB3p@KXhW9j>4eP<>@H& zK|*x7252);of+%w{E;D~`{~H1 z2km(ql$L2+{K8+ zwn~cm!ni@#f}0Y4bR@$We=bWPYpXgpJLn%l;OpRyV1_#o<%70mJBW*kz6~JT?==tY z!vq#4F`F6~YPFTy1$t1`*+}XqQLAULP z;Tyg$jA7P+O$WYDEsdkTC&utB(h{% z=ZTVn!Ki_Pf|JjLOX?|~qB*18mAkpdYV+U~|Ur!4py z=T$_^dV+qeOW-=!hQETSkIpeLgsK;;<*vUowD+10^y@dYHtOsr$gmSB4;Gyo-CrmA zWwok+;*n-0V!wY4K~G&*5&_qP!E_>9J*=MZO={UIx^#96CUg=N0|T`)vD3T{49eiZ zSgf_L$5-T*EdnY<>o^t1Ez;lS98#gwy7#v`WLH{LNI37cPHbVn$aj}-j;caq<<4$Tpnkh> zvH}=>O^PHbPrZ|74>QCP8x}JsDWvcBGOf}nLH15*6oUS&m|F`kMy5>FN^Qh>C(FV+ z2&Igr>0Jqn&IS7clczbXjVZ4iDD&Oc!b=dPC_DtFaqia3g-CM0$9L_ozd{N5 zUT&UrUi7d$Zx^({%yFm+N)81?q_yPP{Vuczt(hy!*#cwG3<%F+ANgceAz4w)4a>Mo>_@AY{2_$Z(1 zlOJm6PEMmas#hc*r_Srv!UyD#;g(xZY9?JgXZ=XTI(M`l{@SQWjnTCmy*#^}A&t{P z$C{|FDCN)WyicC*%ujKhTqTEk3tsjTz7tO#mLjlZ@E@I#9wFdi0vNBL`^Ajz4K%@0or#WRY310dEg}d)OU}k(f zG1}l4Je*?2HrtNv!a7agW)SuIn6VhfbSRGB;N(V0BpUa54s(vfTQ} zsB)IjXx)Xa;^|Gg+AFirU0Q5=z^zxX3&dZR&7(Q!eBY#RZ9zd12*VrwDLp?Zvogyz z6-R4RoQ)XyK{%=)!n=KkNhe%*c&f?cgXvEW+@If_X&5C|OxFV;1$+Q+jvp?p{*O}4 zGX7*#9)s^c&af*LhW|-qLmgw}4|aI{83wrg?B%T7>BY=wOz3M7M1Ow59VHGkA^NZyedd_VRTi!^ zZKc=pFg$|q8O34k2w>a8fL%bwi- z17JX(ziDl5?!Yovhn2nhEL7a&AKFFO zcaIq6Y}VYWFtcuYOg6varfW%PH(UWrDgtIPN?$SMW))Cd5Q-E4RRYEB*dl_EOjEe4 z_?bNEZ%bG9vjz$g%69D88(OexZrQPeRW%wG%%6{?bSs4z3ZtOakD#S@$zu$Lt!|o@ zoA|;ZW6x#{DfFvcb+QJQEUStFXbYif4NaYdMWO5!=SR4=Ag~C=LBcnbp{!bkyg{GA zOIfh(F^6D9Y}@dz;Xw=s1AUZ~uBIesVGQFLV2(chna|P}jR>i5|2=o(Av83uFyiyD z!Pv3ehzWF3r9ZAEUZ9}GYYA7uw}nTinH(LplKBf zs-JSRDE}A}`cXg(*D}sukEyt7g0b?9FeWoC3NnLO%X<)pEk8S8sZ?IN_VGu7MKQTl zb)mnx5u9%Y1}K~e%6bM2A+ob6&M91KEw=wm4$2tH1N~=8qJY~FjI`RWs^B8J2FQjIgQ3aIoP(NTH0L%b@ZY>th&-ECSL7T~yJNeyCOhVtT4@nWopm z8VUiNQ-lTe^1k9|!~vP1?^Ghf1NG2@4{*ODL@;Eo`U$NxbhJx&(08pX8l%$dny&g1 z*6J8@I7FxO3dxu1Mj>L&wd=J3FLUsC4h}1H_k~8nVw;*#mXIDht= zL&d3xcb$Inad<)S2zF6+yeJ>IlNgVI3^EWl<3$}n0cOF`Ru&29?a>fnK-U2D!?qQ? zVGr{h+ux&2zWmfaf$FW!ZsbJ1t8?dIq;cbw9iO3;eSwN zl+cI(@C9H%cOikSKj7>q|4Fa;coNX^=d_IPN#=$JocTy|JmG2h*QiD(+L$mzHns^3 z1tO!sOM<0$FT?a19@`^Av1w{88n2yjkj@3nPL>tUO;-;`Cu^hk}Jwo`5RxPb_+2nhS zV5rDe=!B7Kq07Odm`m{Ku=hc%6ilnIKG)UN#p)dz(5#m}fVFZEX558!sFiRdl^BVk z&WRD?1sa-~aZk_0BU1-&W9NmzuEXyj zH@2Ax8}<-Vrj@FP_YC&KNXMJQgO6F$5sJMG8+d2nEy1I)BmZ7#eiT_18xWWDx@B zEQILuE`1?!{vka0;QjQo2n%y#3{5HqzCDC!)KUPTo44l^wp6#IHtagkf+wewxlw3B z&;vK-VNE^r+;b2D`@^nXd!q7EK*H(l+4E5<_aflj53I5Y$ygs|kepmqjY3dS5NZ&z z9NPfn$U|W3Lm6vt5eH#eayRhMy&!;kWTZOvA48l(H0J4Cq)~}qfEN114}m^6NM=?glq)Id^`~53@8v=F{&GU7$EeghveJg5tL5D zIJn(1&6Rquz=glDaX9jwDD z_MR~xM!_eGu$$a$gj({4w1^Ji#X_2h7U}^6PBAQx-zJB~if1U_hJ%TFCgmDyP8V65 z2&8zh3JW_4S}i7Rm`>R6sn4($rAj2%eI- z3{Gb;2hue?HVSWsGBK?YF8m8_rj^&?g31^|+6Ar@v2IFB%EKuqpN#TMK?oE<=}-=1 z8}1|j3V06#&m4q8X+cXzYsgh`)=K0YqA;0DW%!HuAwHC`-c*_lH7g@G#nPr@(C5mn z2g5M%swP~tgMD>eD?`vLE!k0Uq|eHLdT7)8{0L=p9`qikLJcsB_{g|Q%8SF2qD4_S zHVjI|UvJ;oL?1ZX0WQ)Gv_;Q(RQ8x3k;BAh+Z+e?Y^(#%Wg*^Cy>&%=I+kn$UP00^_rcN2%VfhF#=}>^!%BXh(=kLDUf;<9 z?hQiA*DakBHl1~1n9Fl2yDD^gllL)~L%?07VFE=)y6+w^79LT#VbRiM<`AB>eaCL9 z6rM@36udXhZ81cu7@lYWfswr7I2OatdiuJfa^ij{1Mo)$XN7CMv0CwcmppTfG3|mb zl;D}^$B;&HHPy8Udj@=k7|m*^mNt#Od$yAUvkwJFPmp|Z7-eNB(o62>CFE=?XLul}4*e z@q5-R1X>7>)toweIwLcN)`u?gM@9%O>4ZS15T1()wSXe;(WZ&!h5T5+`#NEET6OXu zV8>HItAF>l@aO|~h7LEcqfYpeIkn;BxwAtF%Z`lq`w$?484Ytn@w2?V%9sEJ*`+d|>Lpwi=H@iNXo6gMuQp;bb@go!NL%|&o7Buoh~!z9U1 zklC;yqGZ}cc1xI!Bdk=SNaP^QHtatT#_{sZP|EOsEXES_6lN&H55|7du0%Ld9&Ql)AqiTo%fD{3l2CzfqQ&5$C5r)ye8 zCUQIF6P# zd79xKn~5>+L2w*5c^QvT9Yq8dma(xOLX3=h9P55Ff>h`Jec%b3p;5MMx_HU_Eyq$> zGp!tE3fy3h1%wy5XT%Uz&ptd-k36&*!34#1s4;Y6Ew04VW+`PEehI>MpSdS^j&e{C z3W2?SMvVdZFlDsZ;{VUydw^MXT?M+k>Q>!bId-njQQcBYtz=8GWy!KlFt)LA0)q#P z$p!|7$IQTdW`@TbmZ+?ip>gy^9`(@%33@U z^yxzDX)-X3r2@j&3<^d$ibn%6>YJ7~rWOnh3r+Ru^y#zg!8xDG36ZK|Pe(ySL{h0I zd}!D99g%*!2SK$N1%1!1Evcq}7mcw!e&C5T-bYq01hz^%64T7{I09UEC7JA~gVf?- z)t*A>7(;=aMPO@Wz6z`-0dJ?7+l*Gw&W)Li>@cuS<|&wrxh3psuw5)whaV($qVSv|74S6P?#WX#tRePe9X1qX$?nxqhwz-th%ri$bs`wi>qXEk-ZcjX4?|8fj$rW;myH}q%0!7)bmzNcdOyVa61pcJqzCp9*3e@$9fVLp1a`z zsM2#o+d?4##(MH(&5a}`Xa+v3*FZ-|P0nHELy_S8>%GZ+!fY&nPr zt-ZZHLJ-F%P}1=@n|7TlX@K9rS@yxvf~55Js#53jGSgpqrZO zF#y7o$!xj2d39mwUi!+J$>DJ_ zv_g$T{b1o^sc~c843^(PnBXuLTTkWAWAQ615a$XZpGU!%LTK~gHZ5IMCt2g9>&%^_|&msy!oGlxQC zhO1GC?=)>eoguQEVvdk=?%dh%3}|tjBVPLunWGL9Q*OVtPTzd>9yW?zgl-{ZL%~J} zgV3rMo*Edusd!a%^c?te5lep8y<@2fE7bK`r+H>5$Vg{TIzfE6VKs+N9*3!NW(V1r zCOCs)00G@_7_DR~RtoZy^wl(qf>KMAW67hW+=j&;Spz~3)297OEN9JlJG5d>AlS5% zIqSs9^O9TkJ#5C>J%g90k1RrjOhBOZe8|<|iM)gG1guIBqBifiGOcJtDI{D?0m0nr z=Lx@PW&`3p#J!u%_cCWaH1aGJuh2!9drY1HApXNU*zbezq*7AEqTWG_eOCeH0nf%} z(j?O%HVT)ftsB>cHO_Gv8gUB21A|&@^exVgpeP~q0WaaVfKoF-A7qq0z^_>5k1LW{8i>sfdTkOiGbD zlV`@HWAj7sTa)&Y#b^x*@49uX(rExHvwJHIBJw=M4-H1&>gL4Wy|Z80tv}j~xXj)uiv-ka`eI+Pg^ieC=-LzetSu zc=U56+2RxuTG{{N*tK>VQZY&AjR~*d@GmpAY2mA3ufD-h0zqk< zK3=`&IfaV44dmec_-T&|-WK60J@5c2zm zdN-~5dtdcEsRukee5y5FfAuwZ393jtN?L6ctlc|yvC01w9+{ccKHfvP9HEvNIv%GV z_S=0|h8Rt|r--q5o`oS^(uolSpjpSj`d=tar)C8Cdmnl*jj#r8d(n&2=GAPxk^32nAXE+K8J#+DBt3;?efO1DBS;m~(c{OU zaVg#Y;uiy}nRNOrp<->_q`U4#5l0cj!x92I$`}XCGnaS=z+Cfb7|m{&+znS>i=s1{ z4j_Ow;B9=x%Wh$V`5@;^oKIKpyoyY4?Xm8M2pt<@Uh^FoFQ79uDv{vw1jd#g*Eu+3 zs_?p6ynbZIl8(4n=qhODD$Y_7Pumd8Yf!p!jB9?ro;_B*D7zSYAVOch>+6h{&HwE2 z+O}~6LhnR+1&XJN;At`qPP*n5=AcUp^OYe4p2VuZe%;2jna$2;PoGHV+WOKOl4zNbBrIDs#zxDRpQGn_fy?hFjOaSyk zZ`c`V=m-WV;h-nNWEy%4tMMx6@$sCIQ9@Y9@lXd%1=l3ho|vrxYbD;OzTWoq;G^fk z(|n{O@9Q0m{ZPvYnU#+BP{&}A^FE+Wg**l!ln?RG_J>iZCsE1(AG8vvQNN0v9=TzR z5Bm=uCgiY&tYO>n%&{@Ntt*law4j`yJ9RF7=5t?2s|oX~hGsRBir2kUL#)X*_D=N? znq`=2c*E(hi6A`jeK(3qC+D&Z4G*yX)`0G2{&cED5m^pxyYku_2$}3n=S&s>o$?24VGXII z^8=2?IWCMTG(|nidUKfj97@mv2DVLG@L)qz_4;jHyCyYZY}m~nr}dnhGK5E~lzEWH zRDky;6)=r$t~lR%{%7jB z*iUs5?-L9LazRexSqQ+?#8?gC;iJP;@Fsz6h){$dHn zax#NOF+zwC1|p6af;Y$69y7QfpmQ*Of(KxN8}4`oR&$sVUXwP6`7DR4X-!#`6I^(E08ln`5@ETC%z!G#-VRo<01Rd{BS>)AS{38@qJ{|X+Rk1 zMghT+EyKQ8&p8b1QyUy`1j1Y_HMpe=Yug3tLfL>}8V;qv3AYW!!8YZZkbH&)L*nz} z2ah5&W938;TZMOM&oz5eEtz{xVPWiGE+&~Krw%EVI;fBS8N02k+bc5bAUMd0^+eRM z$$3S~y0m%AR>I7%kirZ`u_k-2#UzTPhfMV$)VnXJsKQ5`C3t0Ez08pw0;-~3e-`i_ zxCj-dP@Pg4g2okCUN@s~cslzGuy8K`n@tFFsZXPLV7drXGB#T`ym8)f5;HKE0w?UZ zLZu9E1_p(Ui2@9Bq%{w%GE>@)+ixQU>qxqo!}E6AE7EG_-1NKs#Fcm9b{nx>-ZPBA ze!F+46vcS~fxx-cGTv?h1#$HFQAZ4)88&| z$&68X`rK~TAeg9OAwYot!bAZKD{m#Rka^Q__czp|m7YP!EGI-}9)V`8x{l4VWZkMI zwJOR~Ct-r^c)Fr00ZNq$9;JBxW?4rfuwf%r)eU5EBC?P$jfFhxm(9+@D*a5x0A8VK zU|~qfQLM^O@9WM&k(fKr7bdGMeKpL4b6QZ27l4KRHj~=|%A$gsig!-DW{sBT3h5-m zf79me>B^nE(h3ft?8bs$!G`tSjmxlH_oW8LVRoTO$^}fpLGh~$yf-w(vu=v)qXKmp zg2Exs@pzTt=@=j+bNlWq(-!7!98Y9F#)f&6_kN!BqGb0FLZ>2-4WBs&!Sr@1pb_iH z!Fz^mG3SieP_Q@%kA@ofy!CoKAmDff+3U;*_0k(|N>eD($2c(anEM=v@h>CPs7Qwf zz_%HcD8nBYYM?KC7Spo5K(vdcxxSG(V?RqhMur=9T^nVe!UJ^n7B;rml3M(5nk4n>H1l^3MQ1PcCJ(Hy1_rB8RJ&24CxErMW1VKM zssisiz}sQ=h3v=6<=(Y|p*fsiG{#(Xox-5RU-!9iU{uOsP%0_I(@j0%hn^$j!Xh*b z*qRnyfp$MQxB{i3_0;j$tnFSvGj`QBkp7#b7NfDB2;75SnJU@@01J3{!3^Lle$Y=R z6&S@upWR32VU!bih_-Ltnp$pJj<*EE7Ro>Y58x>>5uQV+9*4%vgQp^gnV-rTAF*=q ztcdTSAE@bUfH$Fm`_asXsMlbDWC>{hg!0|UUYPQh! z3U5c@P}!ZwOB{WLC5Ch^E?XJ&5mOF-@RAU=dl6$({Z)G~aG<2O5=DR~YFQ(xe6PJW zojh_N^^t~Je!wfKjnJyYXF5`@H5N=T5clJ_cPtbR%3)3gAFXBd&%uzzF?gCH73CWXvRS*XF*0;VftzX;10Kisgs`pLc zvY@gQAR*-#$u{AA`E~Xs z62%JL!sw0-~@3VIub4o#a0A(rpb{iua%Z2s02Jn1|sd9T$$X zar+z_dK=OeSK_KBq~SdAu6-yX0~b*kumtP6Hl^PT7ONr~%twupLfL@Z&?@!9z-7TI zCJP8`OXp}zA(R}vcs>}{G#(SP&{Sc)cB5$d<{5W_ zG189dGb;$E!t9cUrb(v?Q*@A%Gn1)vs5cE`1+FE8B!`t!&xCczc_ezWObKJ;>8CCQ zDf^9Wh;bk^TbA+7aJu&JNIy?t7MM>x7;lEqj{R8Gt;>JqFgxAPGBsmx6_8Dr>LFcu z7^&7$`ILgb%uEK*(}txPh7pj0X>?#s>utXnmfHzj?pk$a?Dmyz#{3lZ(D)Bewr+Gq zakT^&iyo(*uBq6>d;HMRRL@4-jbtxsCL9c&frn!tJxwnB0XEUj;{B4T6bYO1T2jVT z9F%iB5U~^w8YsghAdmwH0Xg`@qv;F+-!g=UE6hMehAcONKK$^*i~}zR<5b9#1;gqP z*7116+oFa_hD=S&Ll}h78TL|MT1g2!S%lJb;!Q&S;o!=8JU}Zsk7b0kvRL-$uijy+nH#D3_ZvA@3U@P*JUeOJM?K3#7HK2#7^WI}?YhYtpRyNR?0C8e4^ z*P}$99Xgvv5NO8Vto<{NV{2YbROp!zQ04^F#6beH**D^~Ru0<0lI1W28L3;0p?zotB_ufsY4I!SfmgoZX#%E;+ zvggi_c!0KCqpC02>=?pA2bura9|2v88M4xGe*8;YuF`pe8>cX`loKx0MS9jUgvNCw z#TaGdw;RfPIKRiNW(sJTMV!x!yMq3d;ce7&V7?&fLwG@{7;I#nPvFUH!-JFI33&-o zehABfb{{6=+=AYicyG~2L#3cvz!7lMKkBh=+6uT+uii)#CLG52V|v~aGAQ~y;{R#C zh=MaVfRY~zjJa~U969(Dpp*Rjf)CU^_!AY_E^ElrV;DX5A34PQyN{rl_V1rf1@Le6 zdXzwvLBl#d30_4pDg_r}MFMU;;|k6h-Il&mguy_bF{t#Xhwk}0b}8>J&I^LS*ngOC z!E*dwbMC8&Y2z;I7wGa-q@d3tn|LSf;zw^doq-2lOb_EFUj`lBKp(%4RKPWOP>1jo zn8J6QjqKuw`(^}-Lb#XnX;Oow6!T`e3vke!XwK8j2$)Su*pi0vz-Ux6+Q7YH1A2+^ zV70U~5q^1r^PYwS9}L+PS8MUKedWtvB}@zYiHE3&hgxrE9-MC^*8h~RAZ$7mB0%7<^)NNzJv8ZphCbJqbiWMcBVSt`asw=#^OML}#@tt- zB#jb&I1K>iP?|L2MS=@>fHcyCAR5=o8LLJwX})K=)D{XQBjOa^GWT`OPR$gTuU~)i z2j23Qf7j61c!arLVjBU|%fBu|;M)y>%L>Rhg*XBSgv3qJ86$zLO8lU-bA%`$Z$o&) zwvAOJLZ&iiQU*T?&w%z&uC%^WzWqqiiTh!sHRY+%OE?fnduD zA-a-Qh@Pe>iH{pZr)kS)<=mgs%}XN^vPqauJE1RC5TP0Rr`1qmJc_`BVa8tYR#0eu zQ$L{>d}9!diwY$2Va0_Jm12!E{cxn?<;3-e@4Xjc4r?;RP$B)?@zd#aZv&wqs4StB z5S9aT0X)HIv>35_AnHd3a5#1VVJl;H663g!1(M;1asg|j4;k}wOl)hWYr@w)682`F z9fA@W|NSVXH&cuUF~x>gU<<85Em^oR_#Lt2pBv8$uD@ z1s)(y(G>LpTW8k=GfRJM-VpXf7Z(bgOw1)i=FMq`yY^v^0U4(nATDK)FCp*}oeUGJ%j)AoM+UwJ! z_uT`|Oa_j5zKa=uyqwn%;=xxp?#?b?B@}BYW7tF~isXv*Td`2CficVMNlA@2#F+4^ zvz#X~u@|OGh!r>zGEV%;a8}4TPem9zc0~jUa131Vz5@ANd2M>x%Wp;57(~b_BSc~y z8+*sn@qGt4`Fta1pfsd?dmmyy!zhAip7|EenNsN-B5#BsZhd|iIiwX+%=4;s>p6^V zqfcTUJ*S|7{Tr^uM=qRuMqn`=tR2b(LWDtS3-bb0m>2%iUf>4vRR&(vbI98bWS(=K zP2eG|V^7h<*boBDG*)2Jvf|b2COpu+8$~+<9PMAwtf<#}iiNB(1S=cQGuLs_GX+&v z#H(p=+sP3(b>v2NAD%0&3RA0&#bBNE(P8AwMg={zJ=fA4xG0SBDCa9lyX=(5N#5XN z4f`5e^bB1*o1T7bFLQ(^gr%tBl@UKGk&tlNl$Vq&D(9C1tg1qRY;;##a|0)xuK_O^ zSKzE;Gr`1QdV24p2(!biN5<%2V&Q6Hp)O#k0^+|M#tOa16u^X>9isT%-}9(Vww9iM$1}N<>%;KqFYyyRz+102s{zA)qB(+v(tgc;_uD$+-w3hRo z#t3&3|ECZVPn1Mu>7N(FC9W^1bY3*_p1t?!|cHNZhfkiNgyo5?*(TL@Z5doP%el@x+bc70N+m zCrPX@JuWSxulz{=WRCkbOJ{b^hKJc5-AQ!H%P|9 z{y9Ao3v=*gUkB%=!4Fe8myi?PW6h&D@QS;F+_e`)zT2! z5w%PJ}c;SJv@)4}3bgvm=B!%u>HeiAM|3*(6lLKP4jDG7`vLL?+5d}hNKgbw11 z1nUMn_nB0a#??)V1*}t32wT&%JErvn0YegoDTsbcz#y0qvMOScl?*Bo9u0Rep5L<- z6i6Kx0X zlX<8lrqmy`LwKu*$EAAi34Ez1do1|tci)rX3Y!SU0Tvb12c6Cs3`7^FcFaY&on#z_ zMwOv3nc2jYyw2SuN{9lG=ZZud%%63ZP#$2A6ae9Y@DT-c1uy4Vc2$YesMjk`_8ik; zmU9rEUMu5l%b6!Fgwe~8Ix>OQn#YKd9vdC73WQx|6(L9_shixfX<=1~@}D|UShorD zP|~uQBhT(D8pJNoMp~3U8;=dGGRw3C}Ph553Iv?>3KZkBXc}U zw$M&e-mW7#KwZQbpP#uH8*_m1O?%*=#fWAA5rPti7qL*~s0CmxxX0WNKTt?pEUZQO>||1wsWM-?h&Q zWpQ=^2xf{_*N*GW12U@$^`s=dmRRkMbnpNN7w+D}fo`=ZWKW0r7d&$aoIOJ3xr-c9w_(!`V158tvA5t=uS{zZ>f6q? z@tyTXpB1`Y!e$n-p%C8q6zh{l6j{_L&2%NaBlM6ls7S<>4cX4{I{kA&foM)=C`zm& zZc_)9Eh-hDEisx3`{62M--cD^aNT?Ae(ffAA56__4HZ*VSng z2_cS`96`|oH<%lG6YqiUTvWnkJ$f?~s7op1UJ%)e<68OqnIJ?23@lmCxZJiJ@fDo;M7i-=F?9;4IP}oaIu9@ zQIZs}+1zyT&U?(QoimGMmjA$CX#^hI~OosArrc7&Ro- zC}R_M%nHxx7A5H$bL-wijWF^u*J8kg`ZZ`}nVhnAyzd-4qt1thxqu;+X$;aM7CeIf zWL|ViF=lbka&syojwSxtOneFa7dFx}`=k~q7Jc^Z_O4TL6Ok8F-w> z0&rmm@By-#ZC=NojEdkxdc z(jmgX%(P~I{UtvFqZilKGv|h={6RZ&$PdZ@t|@t46=8_(l~W6hWgP$nE|f*gAQX_2 zZo;BSHD1PXLJld+_ZhYi&ez@jwJ-hjyO6P_K>hj8?zyYDAw`*0BEJXZ0a`?;THvu-s?2d-nRBGyNo zXKXw@MSS=J4?T`YK;mDXUUl2c(j9lalq@ZSFai{gsZq*LBCHXnf%WCHU->GbG~{lF z?Nvi$f8m#Yp0Tkh*nbS)Y+iNuK9UNb`Z60o8#pTwB@0Ou{*!+8C*O%su@d6z*dY9K zQ!rgN50c8Xcc3SIk8wa?6a9jzAXLiFwH8mX!PrfvkL-Oq;&ZzR z<+$dW-RY&b+>FrGqCh&50jjL+6)2e`n0O7U6T8?Qxzse{sSP zsQvpNMd}$B@3+8{jP*6}|Py`7TunjOc&#ow0dWT%Lih-2Hc7Ak2-;@N8^G0 zGK*8d$X|=fv~PJglwazI&eO&${YZq4ww^jf=C2bRy4aLfvnONMwryz{o*U0uId%Lv z>z%hn1UjIF+qOdyq9()I)P?Mq%9PJ+O^BFAyNFTbJYihDoWV1Ra(56bznoTP=)Gt=carlj&H?*6 zB5kqmN7#?+E33+N6M}Ozko8p=+5HR(|8ss}Op}BNJ#ha$DCwpaCNz=v#4WvOb%a|Q zj!b74`^xNyW6@pai}y7^MCx83td}(qgx zY4fft()vxDt#tU95GRQTh6|p%uWOd%3+yc_k&ji9=Bo*%MkbuK;Rj6{T*og z-$IimcofQ}*%tNG*Y-?{r!0pAtOe#Wzyc3+@ ztz`*LpH?hemKxa1=lKw(_cc}KDYDG;V>vdxCv+&<@vuCts~+@KPqvpPQbu}u_%QMB z{p8?>p2Ty*P81%>*?=u`ZZWe4G3?$u!DhPCCr(LdVAQf}>|FF+L4OQIqX7Y6+xpF< zY3wBvR}X^x3FsumnRaD7GK(@i0I`3Bc-IYN>QK2c#ph&nl)f@9H-gFl?Ub(P&73}6 zM|i~~ZsB2sr7;wtk-m}eP|$0NxjD~dmL=Jl9=P_KVPJ0L?nXH7IMI#pKTLQq)@!^u zrXX}PvM@9SmK27@ z=9=SwTHzOkK?S0~hJE8@SD{FjGUhQXdmi#N0l_xZ$&KAT%#U+oCK^w#ZYG8DnpLYq zxoW*|3gM?GO_L5&Wy+I?-KRojcup!%ZdNky%?P4H9Dde8**=trIWqawz{E0UTOS85 z)*?9QEh{HQ^J?a824#U%zhwH_xP5DERyI~#5V}vm>|iRT3QWNPxtE1+v80i(6c4g1 z*lGw183rS4BjgN_{bdkK<^c-H^c8v(0%7}s2Xf0$GQcaDrL}1twT(O=V{r4^jN|PCkxF?>9N206YWyWBSlR~)wEJFaM zF2|tP&5UFdgLra;2sj&K0^SUbI0e>HW{{5;B1DN#Q7^C`9qvw#?d=wX@zXoq4gC1x zciP;C@)?=nxM7%vLcTAngb5Sd)Y7WeQw2`LXeK23oRic?2I3ukTqY?{xOMy4MMCIo z#5q(LbMPS$`#$whDxN7&`pk6_8)rjXp>FWsemL)9ma`s$By-4J?geLTmRE9;%c^MvKo=aVAXTbmj+E_2V=$n)i?!wHm3%9WJ^HOG|7edS} z@&B!7*aJdovmv75G4J#TdN+U)WnC(~DmAnk;BfvOm1ADIoI?9+U!6}wsoa-S20pOE zhEMi}N8Fz$^l=;o!uOq9PmlKsI#1i!%_&WPoCA2!(!0JN`&f9<{`8ZHNhms{;*S5^ zPKPGK;~-jpW&t=oafP|vPfTdN7}e`3+rtaYj23CjA>+$`tT0dvUg+{yemM11ank&`PXF# zd>bL~f)x-JT-m_Dz{ZoOPyg`v_*4T#bOwtvWQyo*7qpxx=oY~MNV6>G!0?FcW&s6Z zgrR#^;$%jSOyJ=q2n?$M{=2v=q(Bsu1yHTaGUKO|;yZE%0T6HzU68s^XI#xZvp)O8 z7c2!XUNV)?wt}8?OyZMWh!=CSoXxZ_2a)Q>B99Z3^t!|SH}&@S?S>c@VgMADY-#yi zj-`4MVaPn|69|`%!T8bn`O(x;MMfbQYb!CWMAoFOtLszW+5PDx^kO}E=$odS!d2Sc zaW?f_cp^>pji!r3Qqno{>sO_nE3qo~wvknd6Kqi!WZsilJ0{4UGsHo3Q!p9BcO+aJ zn{w&mvAwBw*+$ZCj*{-MJ#8UgetP6$sx2K#r>9^V5YY;ApEp*MH{TPeoA6%ji9GoV z6T(--h9BD4v+ESBFKK*#wedEpKLPtqbU>hV$)gWO!z*%NmPUuH1 z8`K+D)gfS?Ppz#DY2^f75ZW9go)Tmd4ZjQpcAd=V3~tSO@1x z;n{QcU>c}trjKP=SQcwSLuPTJmtvfXe*Pp`b%rCw?m*|EG}eDE&F#rjow|`(HaIfQ zA#t6@@N9Ksxin;toJ_d!Jw1IR8#Zh3>=;tSOyFHeC|PZ(3!w?HVfOQnOf(ZZ6o1O; zK*ajHfG87;F`%p%!%g}p&z4z79XyNBJ)X%x6)db%LEiPC@X0h&h#v(2en*@9wF*5@ zl%zcC&@!=}X;|{0l%aGX1+q~(q)_J-LLawm#6Jo}A>8sjPNJtW-(MP^{kAPFi!$si zg>Uw*l*6%QA`IiS-Nj27u;_rRbOHgEvW~%!6vb_p0@d+?AM6O%6l=f%m%E9_&NEPz zbX#x?i&aMdvigL8J!MWULUju$)j@l>5ek9@z4)Vmr?8g9WOY+#D0`Grk+BJ3V7pmg`OZxf8rU&urPClL_}3Bn!FgA(vn+qS8-kM` z?3duA20mw3fQyeI*i%TuNO?>kH>o4)=bmSVjFZkp+pN4036Diou!a?0~lkBR^fB4_3{|Cka(BdhO$Cj;=3z~iUW^? zmvcZhF@FEXEYp^gZgLmaHT8 z7dUa#`T{Sbi`iP&E3st6heIzur&7uU?$D6*TOh{>sK-4kDs0jR*F^S*-*hDQe>ntt z6i~Cvz}*Ui_VT{-E-lWyJ3NUo2vPBJsh9G5YVck9;24=TI;ES#o?0iZP)`jTzJ;yI zOQtx{rr#X|mv!n5ab-;D^6&{Sn4#{=U%wwT$#{|N)R4W-1P`c*0XNPIrv4hrs4R*% z8P0haYn}|1FS+q*8*rMUpYa96DTl@zO6~M(^iyduoO>P~md6O?I~qs~jh-UpIiAV4 zsK+*q02nj;j~go9B_tU!8)8MSiuA^WArpRDu_BMs-$w!hJnNiA)U>jML=B{~mT$9A zr%+67$nfRGOAu#3S-Nxi?_~)53qs(ZqkwR3SpVw3`rrqDesFYRnF}^hm&Fy98&{C1 z?21vj;Gfv-f(dG%G^T%DA|i!haVyQ(q0I7u<(^O{$)Lo+kd3I%O873ZGgeafbUrf| zLa4NwSf8Dd!0|7X5=9%@i!Sk|!gGWYSWYGn5tmV5wV*`97@@wNRO-pD!(_y< zi=MJ;O5AR;RgIjxKTX!mrrNceu;h{nYv@F3nCVEXHdm#)9yk$s{_XqAU$Q-|t|Hv2 z6d|0GRA+~KI3c==!=r}Nj@1a7>@hgj)&tyTVpH&ou3v!yaSm%1gp)HDDhOGc>OO-xrpZv9438cIq6&c!V9W!|*_@T%~Cj zX)5<@m`kGr2(?{U^Em`*rtef5x^RS1&u|KL7X-E{bq{j-bABPc<<&Q&DfTq1YTz_p z&JQRe5EloIq}4T~fCU!Q2od?3Mi|a)+PQsoYRUJcg^}}Vl*}|T_tE~dz@wj3kYxQj zIm8LGrWKt_Z+YDfXjZ71!)tPE1&!+1(mvE5b88(EHtz^xLbj|MO zv||~{*VuW+xr!8~<>dLVC#-5Vbsv8`4RxN0tSLE;$Zf7EOK*GaO;{3JIq2;KnZ>Th zve=jEi)T|~8b~KOlcECQqXMn4thORuvuRb@(lm`Vs4eAYIAknWO&G(uR5^JV+#|Iv zo{%^#x1=&PvA^f0JuBJg(37@qctxOM``JUOve=edau?HKP8_dBVH{&#?i??OwvG!ftUh&8G zy;zs@PkkY4Na2$=csaz3ML{l1)0T}It=ljz;@t6GMJqu&SlQ7nN>N{s5jv7>yw4bX zCIDtYnZF3}zI`!VWARcbjA2lJY`z8_-jh}d$*gns$x-r*hX!h>d?+MJw;Z*5EhJ}r zq(c7Cj~D{qZ8NvnF<~OewTYO0%JKM)!oBY~TmFvmWE16WZqW`Oq@XdM(NOkXvB^&R zJQMD1Wf6`%lTIo`YVc7haDD{4_4rO$-yO6i=||A%#lMa_uCq4wZWQmbGC!)EV8&0BqQim!7U@fLc{u zv&tyT%_Sw(zJ{VgQOjxua|3qZS$wy&$M=05{vl>C(+X7)Av4ur&Mp5;+6tVdoLb532tI}`f( zi!nk(vpy~53ue9Y9xv!6vXi!GhO@wU;Ht;PJs30-O12%)lIM53>jy^>eYRcj#qZH! z%J4thb8dVfSmIswp2YX4JFCnxdPc)iNMB;i4w!LSXS7EL-S-ujm2*?NA`Ipb#zQYz zd@Sv;Jz)`QV<=!g^u?wA^A|kJ`kcuK;N8dyan6=m!3GH9I9$7?)jZ0%$Cn?9TAiUO$deS6Q-7n}Rcm8Qm zTr#{l&hh}43NdJ)M@N^DmRWCn1!ql_<_5qC_Oel@NoX{f1Rmp+G5LgiD$l-;azeR0 zYiyRy?UT#KIE!UDb#ve`sgXTT2BcH;xabagQV=m7sVOZqJ5LJpLVs@?ey8)=yB*Fec#_Y%EtMH)Oy#Q znUF==NZr0Qqd<@P4WpRCb3s5w>TDlHm~Y|WEJ9B>^I#6^=Jdo6-Xg4>D0}Dd@=PH_ zdyrUbJE=km6qujtBCAYKY_6@8_>yU+f^fF+l3Exup(ZFo#re%xddU7nD%9zLqj-1@ zVI9Ng!QqNS>Zs_@Sa-+Q=U%ePdp49iA}-cJT)1nuPM3mmw(47|6; zE^F2ta~hrl=Gd5L)o_`y&lCepfg4H%mB@y*G`mQxlZO4}r&zZNav`1DwvDsyWSp@^ zd1moN_M5dqB~cGVKr1#)hVT}i3f6vDx+$=*T0$2mGw0nfwaTomQm0aE|JnU`t9I> zC4B^CDMMK+rvj4%D75-=&>t(v8jatJlLkDq*|T4fO4LqUEA?npfdbKgMIr6`3MxDk z5K$lSU;?z5iwn-R0vT1=+4#h^)#$(9>_G+>KRK5820RvNq_E+>Br(R3^)%pSoj$W& z`{Gyv$^jVXMyO@|@{|2^-1bMB?Oa=j?*u&f6gRjZf?nVnPpD7&7C6QeFX{A>wcI*F z;SD&`9yh!v&N?sC2;Orf9>_ymAh&^^_BXmollI(8TyVavTjesZ(AU>&+(YZ%ir>V{t<17${hG;u)->pT5XF`xiKEJCvo;XXarMKZTs@NJU(K zoB!>fp=VhaGu#tzy&+{YrLLapc@E_9?Pv>Jn`HmQ@`jbj29zdHpd4?AxRTK!Dt1f^ z%FxD0q=J$-k0)goS{~`bRgjpga>ExGN0#-H-iT**hPjM{5#ZAZ{H1Bxn)K@L+m^0A z=Ru7_)PY|Octz+JpM9?kzE_0@zn-&18k(EpOsZLoY%?=uX)EEoXf8x)Ohf_nGabMEINssDf%QTdKp+!@mV77 z;*&h+)6l9Q8H&~JC!WPyG9-zco(Kr5`wOf$TmFmnTMOlbac3rxtQxY3WY#8I3xv#&Kx@72qI5XvT0Pqdvd^oa~2dW*^s(iPN&+Ykcv zhrjT6kVYAl3`x4Gi&rjL!JY-JF2>%nzcYR23l9ZgW*BS4>&li9ge567PyevI!x#+1 zIMdddKJej=upTOGG&hjNgfj#B*pxkk2ggmYAplAA8PjJ!_XzMq(Sa*CcB1a!3&r#@ zgy)~94;`GqJxxCK+2Uw=fxNSs_l zbDdV1Z6*6Lrre(af%oRUcR!ZC&L^i)rlfyL5YKY<3cy*6XNE-p3**V({l_1d9{>x) zF#eWEqlZHPz+u^Vu)DaC%|&$I zzKb7}aBq(ARlrwJi?PMX7T-reSNXB~Vu`|*eGvqXJ6Z%T;;ib1p%Ib_dg1hD7YO4m z;SxV~T%kUs0PbgBEfF2p(<=TN!r`WMKeOVj+)CmFt!c`HigL>TAOx))yx?+X2m z@mtP8aCwe{7FcWW5)#%F<8V&m8?g5+;LX~$AS2_ux8fO< z#wb9Pz>>u}g{6EZB*2(UdLb_GvcjYlSdVb>UwFK%()VqKA89pTxhTa;p`7tB8x2ov z!@}0bUH`HjnCZoy%?H3rML=X+^}}OXKjG(yfb5`A|#M%Lov69SuY)@G~WJu zu%(vsz$+`^W^^ME5MFCPqk8^Er5h_>P6SAOE}+^<~Pi&+WfU!*VKi z_CZ(%gklWzi~AnBX-e9Rz)*;ru3@z-SB(lm35FZ-4@TzxZ~9H>6E$Vsq#xD||4;$+ zUc7DzKIpv?k7G|B4^>Vxr7we1EF|iZO1SKE@KkEyJN%A6i|R_?aL`X+h)NVRNl&Z? zZECDj(avcwk}t!1BV|8?r>eRvt=qma4fYSQ@1v6Wpmyla9K1ri*b*E~G7~9#;k#yn z3kA@Ap*)hRfPG#QgcRrDjTj~!uzjP$?p-WWW?DlPu(pqbB&WeLiMNB4dI5 zkut)FH5L|0)-X>37ti(4s7aVNjm4x=|G&G{UGRPR5v{L*{>r~dxE3H_&3N`{R>Z(sk88BH(>yf7-U!G#-w ziGNuT5{9s>Y65~1MK}cLE@P4m2NPYyeF=-S#;?Y^$ALvIR2MFPv{^{pEkorQ{gCR2 zE(j&AO{<6>{#ds!dLWZa%vZG>_+0*Htr3F^ozk)stx%u;iV&mhWfwNqcV5<&c_kaV zc3*X6+Ov~PE~K%W7#~V!Pn{v<<`5f>m!%=B)qSL6-9X&s22MHG0#(iCFjJ|jeAE#> zBoQ4ajcCEm=Bs%(mm1jDVroy(fC90X#2DyG>Yj#hFJJ}I+N7eOqAX5TQf|aenTE#D z!|ZUY(sb)>x1{YmwlSyVekcDs;HUjrh<|0kTEwfwOXD6RVJ{9}lq`gmleM!Y072F}~-kVQgmff~iz+ zBJwyPbYpD%-*@Z`du}p;T0~c;HcSmvr8XG4oSyzkaxc~Up``0f~-WBZYfjxtdl%$<&u zkEq(X4lekf*G(X0xux5eKOW}-OsEMAI|Au#f3u|Yma)A((_tW#j| zjg|L93b#mW7c3J_01kUlz`Ye|{Md0MF z?PY?P>QXk|FqKe&7GO7?OJ^v=Q#;9b*0Tnn=nv1J?mmw9rJ*Wg8i0&FH)IMXXICgk z%Y2VMa4*L182oG*FaE?Qz6Z1!XPkZFobfN~eq@gDDpbD=QW%NT3Cx>z==TDZxp?CO#t>O6#ZgZCY0^pFWwICY+dnXqym z#6#Z|Ut+JCJVe8W>n7mFSnV6nU8ht@-5DG-fLWivgtzAo`86*3q)Dud25c|nF5zJX z@~qT=NPIxQ{O16yQ?KhYo>v-mP6HRRl6#p-f0%po@|2mgh_PoW!OKbsWF^1CKi%N+Ba$7ZAKl@T6}eYvK>R?Ja2y z311E!JO~M3pCX3?uQu5U2klN1X`q*P3W440^x0PWQ5FYW_HocEl(R(ajpw| zt&=d{60-844rhBQ@qQHGRf5fZA)Xy3;hKYwNmHC_Wu`m;FS2jOxpm*C19Y!r4g(aT zF9q=K1(pd1`5=2v;UQiIS_t#-B4H2|A;uYRrZ=*RWflO#booYM!8pv|0Dp$Zf`IM~ zgzh|pZc*vKqF)N$Pd@qN4X=64Yra5YnQ4C%to>QBVnxqKKl;%h`Op9PKmU(MAAR)Z z9XocM=-nW$ z`lUbo+Sk7JUAEQS+}!`3_rB+suD|yBegEaZ{Fnd!`Okm;b%LX=u5RRafA@F)MvcY2>6Ws&`m%0b3gZi=jy``|L_lg3|?RPpZ?Q-`hWkix>P*wzyJQ*e(cA7?1NwW z(wAPnYuB!$DpBmyE&R!!{K?OL{No>g+g*3v^(xCfS6jdNo4@&Auejoh<8OGw8}3|! zlj9+iYt_|PUw!aHANtUbu3o*m)Bbur7hEre&7b|*pZzpRlZK-3H~BR-HdgZszwirx z{1ZR%6MuQrO*ifRR+KfX%sBZssr)$}mlUU`tIwW0dn0(uZUJ!@i?LLKWx|SO5wOU> zbKU3#7Qi$DmiOXtEQ-50GL+{F<#{UzhO|sKWLBq-Ai8)rytGV1XM@)VA>}QLds&wR zO#-GzC3_CRWuf}S_hbwJ-QwJ`3`EN2xn-&7wms20O24(zN#Ex20%)mw)vIn#ySHsl zTefb%dr-#-q?M^yQ<^q#@@{MxE2{`5BH^&#gH`(c15~o*LEx{5IqQNoIuNf zX4tb)1|ckkJFB#nl+>klq?^^N?>y|^vBvuR;xSB3d0blO}e*%uWhf`Vw3?Wu1 zF-&JzO$zH)pm3C@x4z-K)3v*{(D!oot~9b&hB#y>Eu(?hkt>L{jBPbE0E02_N+zwF za0xP0MM_fs_V;!&51Hj>5~X7T<*bJ6Urvh3O@!jeM#Lksd+2HKfJd1~Ffs5YkFal= zOw%BjXq^H^!pF>9wVW=?0wKgoYY&;KPtm3QU)gaTilw$ zr9NM>6Q!}1?3-@LRk6{XUdLxnz9+5nz9*h!-$@ncS(K-J2Tz1m-;R~jhav)p_fFf-&=r|CxG_ zRbro%i7XeiAbw$?zLhF(3og7`WRFPyekhf7%fmIcLA8fv4>tpeE`vWnaHFC z)HZ3$n0uemt^!oxY7iQ}(I4M&Z1z`Nur38Q?#6d5@6i$JqnA8$?L;B6gyG%eeT6ss zB8>ePG5n6-V$c9(l@R=RW?j;h>;eyH+wS-_ALDY)ttXqaMOgTd_f!b==sIuq*?C&3 z&Ck~7q)C&UifrDfEym<`+v4J(iiEe$LYN46?0MfN~A}nPtvHUgNCyZp$z_@W3;80&OZ4k;J!3A zUUEo&%`D=yOnad$(#EVbnXziC)x%}CvW!g3jeU*9Ngcu~t32AX!}OYZxz9U#){S^l zDfNFSyp)LV^g-1m7CLRmCUM#dT8&%IRbt(uTow{2^mvX?F3!e$@_OJll?yBJE+@nF zGj-{?_a0HJw8NUCK0nSQEYEXLx69SxxwgDYF)rD%qmagBS==0_bxSX@HhgA?tChK4 zOEJW02(uH8Ifub){9RLj!SMN*+4=@cmy!44GlSVNHZk4U*>8 z=R+9eJPWIm1Sc(IIBe!Du<@}$4l&foIF4M*t3{j;d*UH+!E< zrxTWa*Sp^J{sRXNT+`IlG_V9N`=G+`e0>-h8L9i=2S4~@-%4F77b*cN2TS$aKihCD z#bPo4)vtc_yPvDAPk;K;Z`!zV<2m13f|CkNTU*;Ym96{kyYKclzxmDodr5h+-hT`> zpZw$}fAB|sCdefWU^l9%cjp6zJLLUC6%1@eadtNHOwEL(4vUsfu+UBE z8W(t@zM&xM!q$=y$_@oxH4>xP z#2TL#+ocZ~vtJ}jw5dWADfi+n7On3q_)=%o4>zzsX4X(R5Cc?LB=uf-23KJ5_pxDk zk`$)$8@(cI8iD3y?TR<%r}wZsS)rLnwBFn25C|1os7}kNr;|DYk1=rXfPK*_iT{m; zVQUCt^P~VSMc9wr?v^2kxf>2WZz6{~LTiu|%6El?)YdE=^JKcvb7HuF?S=BCgcd{? zh*FouO`M{J6sc4xXt$gjFWt#uy5XKeyUeK+<*JdhNH)PZjHz8!*90?HC?_ZR1Qs3V zHoQkPN@aO1e851_%JhXQ9U7}6vk1(2c6v0`GhS!OP?-um6&!9%0f;7JDutM80n$UT z07LQ|iX7e`UH4`<(cN9bcQo6$U#j5m02DgJ$>`TCo6ms@W6we8*-{^;Qk%oyRKp@z zB^&+5*xWsag-ZD62K5XD;HV1#@E*U#4sgx!@JyIcugqSB#Qig@4LnsSK+GL2GCyQZ z13w~+L56OhQG9}{G6zn>MDG9-fapZr?i}8p1+rs#X2{UMFrSCm<20AHZQqt2f0|A2 zqyaXhzd2NJkWb16ZgO2Jqr8^BQouOaCuMs z;%%P_iV#Hk>#JTFZUI}{aqWB4ze*;eTu3Mi^jzG^)~wBfE7TwLc+<=0mgj>4uI&lx zXq|%LaiBkb4=XMA6w(!Lr7gTdyV4ClES6`QKt(W&wHfnfmG;$dwz1eDipOQkl~Jj;Zy|KiA4#%8y%$5Fs8pUlxL%no;gucGXg?RB zM)_yzkak)gOL5>beUOGo7b8;{-viDR(}1jJZcb0UW$dUe*!(kf+P3{$#0MU#`f*qwoo|(bAG89 z`mCZ7sfVFW-q)ihOf%>U^KAUGO=ndQ%^6P0TssEe$rL{Mx<&&^fdlinH%x&YXO2j0 zoO6mhC!yT&*RWJ>QLBrS`|u8Xs4)z`fmKJys2=O~&W`l(V~?fReebK&b=U8~AjO_O zj70nPJ`|_kOW*rC2V;*Nat^{hp-%9DvC$FeeE~Za84|}i2c@o-bouo_oijG($Z|+K zdW}3Y$4eZ^QQpj8aYhewkb_5Hu8SyvfM2Xb`02%-^!hLDO$9f$UUD^&68wAbc`6+u z%i%*W+6@%sG4LwNsBl`ZumB>lR^~ighn5XRRv9VvhtDRj87HyK9MJ)D>_ZKi%Z)C@ znLMeWN$w~W{SI8tU0E6Kq36F8%=IQzR#r}`C@A16=>E#D{L1fd-@g5%9s)fBot>Sl ztE;QW6_gdgtx@6q$AA3C|4K!|dN>EI@!D&z-EVz*JQVEz=5PMyE$@Brd;h(H_J8;f z|KSf5q&fJxI5afW@cY02`@f<`K(C5*cXf5Gx_I&8S``J`(8IEA+qP4m_{1lE=-GX+ zzt*SR{Or1FYimcJf5iXriDQ22Ti^Pr=Nj)%{nStWxp27@PAW7i3!67@KD*>md3LSO z2btFx+zx`H}5Bnj{dqJ0gpBSGkHJi&6bF9#yTV4(n3?HJ6+6Ga| z7QNI?OyJKVA#$;Bv4V8@W)>8d3`B*MlU+eHr8BY)>gAEd&9E51i?h}#k&T!5zO>}! zbU}}7#hdg^K`qP1BEvzb=55h)Y02?A@A#WnSkzhkE%j4ZLsMfggd#3gJsU%wC&6js zTFd8Tv{)`ww89f25n!=v)Nm7>x#N|Eqkf4r&lFgf7>}eP1R=^zv6(WcHE{J(Xwy}@ zz&rfMRU0(kii1$gt!2ClVP0CvVjAKX@G>sdaoQ*T1$}qW^jW1XC^COTNTp1cN)UET z{W1;b(l}8WfO`;2w)IgQ!(d-EyZI% zOtQ>dJ}^uCQpWgH<{-wrN@81tSjLIaUxeUidHv}pa}&5j+X^ODsQ11I-i2TwoPe+T znFKz;2zQjCi-htw&mjWo~TCM(KdH@%w77Ylo6lA9~CuU zwBL(`_!HJ|JH^E#2Eyo=(@3eyShKxdu2G(e0=AV&rYt#Ip$;q>{`FTtgu)aHYp!8O z!bWk(eJqA~SyzZ`;*(==ZWw?NvmPz9)@b*G9@4Hj=Unp!rKDfL%jdrAJh;G^Lpy0b zKFdh{ z&=<>#1B}rU&X@El`Wm-*fqLCHAffV>)!82fb0H8g@O!kdSUdH2-%YsID=&!4PWzoj z9!i0o5+2+ZZ|tvvr=_gfd5CFr4!9S1PVrcW+>5#3yMnbN3gn;-y2F*#t6{`(2Hcq2 zCC`PnZfT6Lv~2uwGQIfYVR$NhS+t8!rHL7ggYMezfLowrRs;9+j4envs9XABIO#37 z-W-DSIbfK+_$ORdf6gH!UWf*v*38)w`KAZ3=K|zuriZg)|R*!<> zItV@@+_~p_@;dpW*(){n1+9#68MO zBRm9oV1_!Js|dGc9P(ce9xZ{0Xow73r3N)>n=`=-&owG3C#)uftIUS}!3C}`r<+yGV@n}EhBg@%Wti1p{Ka4VlhX+yRQ_j=vyUibMeTehD0qd$7@FY4|1 zjo5bb#21f`s}0q*SoUhVYzf{&-Ynz z@P%At1I-bMUos5Fy5AgOfL|c5L@o$7j1&66XP5(jT~eW>Ab`k}T+ks&@K8qJJ0XNe z9en4n%)`YiF_lnx@S4{me+gpmn`Xk&tRo}flP~g?pR6qIWDEqNpx`J2F|H%Fg@-~l2HP$Wokq~EWwp)zHm2@m*qHI3*k>%YTwoG z%FKv_aBGGo!;a>#vdEKcb3rQ-#MAzAD}?@9Hm*5J`Dz9iSrj$dHQG>6lm{!U1z~3# znP&$$y4jFsi=6ABU>r0ZV0nmAmX?%|DB9PXV&!f^b4*${GXe`NJh()-gcrk3F)wO8 zz;TjzSdPE|-p)1T6Gr3~AT5>CbjmDGGRq=XvT~TD#I>AF?$anib0`3LJ{yK411X@O zg0wURVW<2wo(i*$DDas3yaL#Y521SiE8F82pjs56=ue3zaDb&yHV;)dyh>$IIB7BU z{R;MPkR<_2e}?K#yMhlCA8!`(=loNy3P$3iXa?|D#1oahK~d(7@e&^8hRs}lXr_A5}pu8U{^` z^q^WW^M3l`C5_RyrLM*c&>+2Qv5x2$Z$%r?Aaw<<*co05;|k*!hSDECaXW*Xg0tNY zWs?rsKWR+BTWO54DmFfk@kub_eg9iCg_WO zJkt`+WZ0rL`M%V{*X>KZ$HP!qg_V7EKK$oPi+vI&goPFOS1*W{ee=h8je#uw@v+Jq zJ+xT7lL_>E&lVj0vL@fo{x05T`nl)i(HAqdIll_&Q4fDqVC}oG@y&APtH_Oj3FYmJ zbqO1VUHcv-`7DlGl{7^KCE}I15%_6)G_r&qix70k8QsYSFL#Tf#`t`f+G9^mz$kkr zI2@V^Cj|n|0e`-VEQSL4UbIJ<5WoWf;GXX;&Z&Gc=9FiG#UdKqvU`rh8iZ9TY1)U= zU0=R4O^uC%TMKwE>eIS4t5X+;rp`k@1c+5fZ)n6hui|_sv&h*`NWaz4s|8Y^52ya} z3u%z^jHJ~vpGLxq2MI%+A**841)Zy|t|co|6DTR3dF~RzG;~g$Pf8ki2H6?mFEbeD zhDdDU`BkwV@$Sw;e<&63ac|rYzWI&mmYc6n`=8vGzWCLz6K*;g!oHCMjd&ESbA&@e zE8!_Kc%_%&X@{Dp@A>XK(!R%^NQY0JKmmYGLKDl&tJ99FujK&O<>{%%AB84Wr>l4E zinQnt-FFvZQxj>$>b3A9c(ozA)LoP(LYEpj1Xow;>gGE3>J103oxj)~84V-El3q*m z#gja=Sw&DKOM^ri-bwkB>2XCgqd;bXlk|{f8~jg0qdZ$2bVh<|0K5n*4&H+VAl|6d zQOCiZ8`I{q?Wv{PzKB5IxF(_XUwh?^shvY}!#il7e2@2CA2dT98Y2VJF-JjN#4q|5 zJciE9Adg71w(Q!;oXyXTPfTC?P#`nzEqq z`}MDX{gr?42Y>J%cJJPONDqh4waCBY9q;(-x4rFcA6J<7zDk2a^io}pQt!k&-}%n} z_0vE7(|`7!_q^wqEu%N&SAX?afA8ZT|Jd7(9XqyDfnINb?WrK#bI(0@s7Ux@9V#LJ z@jw2@-+lMH-~C(9)rar@{_p>s-jpLpj$HX%b>Tf5wjTSX(qXvMul?Gu{f-Kc<5LN^ z>Z+>_yI*Db^5wnWf4;W9=X<{AD}Vd9fBX7p!|8?_Zg^6~NJYZ7mM+`;$6%v!W?vka zuu|cB``h3CkqsL*oY&*DRF6uB`%m;nsVwOQ64p!4pYN}{{hxdVGbt^dtZk^ffO2r1 z;R?Z&Ao7ShL9nHs5?*6BWguWWi$MDZ%OtEu5M|256&%LJa|r>aWDr~G3uY!E=8kPk z#a#HVTdPnI&C*v|8_y-aJg}q|DL=SCS>+H1UxIqD5NXZ_{H1RGmSB~TBa~t#b{~f+ zR?Q|c%6+&e%7zF$dxe)Ecrap8VFs=m>}O{Q#Q@%DlW$>;49;t^-&;` zlb$IpI$CKmqDHgSD@>!a5Mxe_MOSREOTdDC1`XivjKbFF?oRQdFN`LkO!^C3MTeU!CI+2 zAfb{GeE=UBW05+_(FmObf$T}%M0SILm-=jpVPhK-jP65#M zW*DG?GPOkid5d;zJL`?jx@JS!5uJDhs3}5u5hMOnH^uCheT)x*G$?LWjj4G>BSILK zQs;%|3RfX>G7xcglKCs}Xe|O-*}$2!k^~D|)~qCjKM5FsuL|;%A#5BTR*|nF>lv}s zt{>)f4u%cyiM1oGnITDmC)*GAb-L4uqaU<>VV!7_pJkVxqo{pJ@}c&3Cqt3YSgrd z=TSP~Z@oYc8X;brP(vs=U;K*ttv3Wp>!gh9zc#)Ya9)PZxcJmeaR6gm34%5`&5J zlCR9CEt{@LH(poAK8gp^D2MgVK!e057)$g~Z0zQc*P$T}^5rCZ=O^=YI__fX8FB{- z@+dGE8-oXHxPy;~r^}Z&rtR!`>|_62D`##2xD2nsUB~j$TW(H6cp_@qBUnM7*Rjtd z*VfHGzgiB&rQhN{{dHDUgl>D;%hC?&t0Bu&A7h^)8{`vv9|_}Pcwy__| z!diBrWR#MRz)Nfsoi$FlLd`T-PR6)=O#^Zh$|Lwx*+4jVKFYS3o7i$Q;XfZ%NVc-Lq%UZuZ`@--qTc7|wJrdr0)0`2Nznepb1- z^c`^=+3D}qV;y>0{;@t7n)R*Jr68~Jpu)41&C2>O^(uU`whRyZdwu5pC0JZ~-*J93 z*r*(R-~%7{x%a*AeLpXJmSE#p4Eb8B*FJsW3txDRW$f?L{Y%?>uFo$>0kNWrLVjlF z&Yi7~Jo-dz5!bq@-~#PL@o+J~0Qf#jpr@fRi!77HAai3O@XUL$X_ilJ?1lCRqv3Zf zE*W4fA=iWiIT)xPAbi|XD2{L%JES#Uf-ZsKYgi!ptDx%AU;4$`r41Svuc9ghELLb7 z@FbV!v)%<$<27IvmsV-nXyU-Qh#Q8HjFN_S0C(`J<#ohS5~I%v=qe0u3^O&Ko0|=t zHIzpNSE^D1!z&@SNOy5Lo7Gh!qNg&VtWyvKIshm1kRmf$EWoU0upG&i9FKyaj7pel zZ88MO)mA|}MTX;eN&&j(fXrd>cYj0`o7WUnWXg_t4kb$u$PB_TjRA9?(G$K3Q=+H> zt~RSsT!Gb0SO^GLotZimW^F56{JN*P++glp%_0cTvp2=hIXoWh_<#W++!J#vbJuGk zv!=`8`7q-NYE5_siZH4%6b9kqLZ@J~85g2h&SAhV(ZSz`t z76M+|`SvsfEW9-imYRlBZWtei-W$7_OJiU*FKNo!WGOly`k zV*T?J^SN~B=&3-vw% z#%;dvB$gYWLWy5oS6cMq1rdN3AU4q#u!1i6TSn(gc*Lq2(xwfYQz=YYOI_x{aYq$+ zh_XDuDZL%-7g;0BE%@ce|26B@rBx^g?)h==i~DrE%p#^z(ajk%JqQZ1w~6*Zk+gEv zY7YC_lujKxk|xY{W7nupfkj-9$>#X(3FNb*!!e$D&Vm^o90D?|Pu9HI)wI4&mQJMM zg`pUe+0$IB28K+B5H(JnrD;XWS~AS-N_XA$`Pq2R;aP~`SGThPocQ7PtwYG(LemSJ|f*Y?FpWsJqjH z=!u@{jNs03%K3CUa`<5Cyx5WTIhy1bMZ96ZGN?#TxWRwF3j>;^zZuQ3n|evK26H=T zu!EqufC#*CeDWGgm>Dl$Q=hK7W_M~LxrB7I$h;RY3N6QafAIqA8-R`y|6V~SHXk{i z%1@t5S8U&&+7OT{3Hedjuf)hS$9Jv%HI<}0Wjv-mH<87;lgCmog1zVdgpO{@JPU6+ zb!LhmV{ohvMxe{X_!}#Z!opLAr*dI=PZL*ka^HZjO+hc2&R8=%Wlkzm%eu9x{oFY= zO4nu{M%I+dPX@OP9@6sWWwlf^kxKE}u4t%D%P{OyUB`JgF=u`Po6&wF4H&@ zG>I^OzO|M88ly1{dazWKC-D?LbpL~C|NaBaIZ6&~jZcnoNbn%^f@CNd9^4!*e5=8W zQPbKopgHEOxG=)pfGg0p>M9QVqrNzC;V~{F2~eWJN4YHz`0+UxZADf~yzLVh^FrAb zsCEIMPQ!NypHD6DLcKSmC|Kg$|AC8+WL@|_P}e`GLgDux+`Qz5&!4Z%^WDGX^-x+a zE%&Vo(f?Q-OV9qPbt%N_Em?a1x&A)icrP8pbG`TMd*4cV`+w;e?4Lg`q^?Wfd7%mj z8d>@Dx|TJkanH}Gz2~rSPqQe@I>U+yK4e37Q2{4zK!9Cnu(VJ_SV7SjA1l1ej9o$z zu0R?=uj|rMpip2au()lSCb@6sC`4@tlXX-umIy7N zjZ&-^0LD(@Ey?1u3^6hkM}gXOwN<#Bi^P*o@!kG26l;cFK+FUYOvW~~!dsIhu7nI2 zT2X|Z=X?k`^aTJ(AK0KSb10_`555bEE^*TG&-0LI5t=O@3`}8_ijgN`JPO^8(xJ^` z87oqMUJnL`CPvEe7&OCH@^OMyt|%YP^Ie6_8s<<|LfM1SItGOx4J?LAm~AV#wxfXo z#+e}2VBMBu4CN?u8HND8DL&KpB1|KPV#bUCbLxRnR10)=YD%BHk&{pyJG^*x~? z+|6dk*g>c7_(A0*u?a&*)3`EFKC3m_EaeuQFI+ z6jB9qtwI`0np;?G(wYq$)7BkZ)BO+Jm1dbYg$!}mzcj==0AJu3eL}IB0>3YuKcBkV z&(naI?L08&z)MBUuD>3=M*PXmlYYy1!Y&|3-PAhkAv2HDipxz=;3 z_4Jt#LI(SLBh4~y0R^oxQs%RTFktM&$@9xQ0&`b=}e$3MJN(pK|z;SS*^8tSIfcQiSdE-@WT&7 zTXLzhw=cYwE?-RdC}V}xvUW{+?8%3af3o@08mr(W$+G^??xCHAg)S#8c@83_movN> ztbOT$FbO+l&@Dj4Tt@~eK@xD|1OLrb71mzh8DXQ8Gfc}u?%j&hz@gQVfFPjDBVby? zhTwIiNI&%S%Sr9z)8= zv(|6kowjXTmkvJtMC!)7pck7V!9!5&C}V#uub>|St$0R%<`5dWP5%&1;VXf1&>k}# zHq|oM2+E%SVMu5JOTSz|x@JT|4tyD7|Dwhp4MQ?$73)f9{kqjn;DOnmSYOc1a#ExR zpQQ}(@)3&6uH1CKts}kW)!z+_@aALj7uRQq0O%x*ylK_#oT;%D%Eg7uvqdp3;V}%{ zRUhPX8pR+Tdt`R zBq8Bl1ctWFl+n&0c+6q~(5_h(y6%Ai(z)l-X0k%M9$9r5P4Jx3C&xm%DhT`H``||& z8fPT1yjDIKi2$r?aiXOyD!So$6JOxba0#9>PkeWdr5>=bptG)TQ$UM{(I@6to@_#b zY3Q+gWi{{uU3fjx1oF^4jKwu5os8%N`WI=C?8Nv) z59wZs(3A|wWLT)dV6!zPZFcdpE<)G{ipg_Hq4zWImaN$YWsK-h=hcF7UFA|hyr|sMX)dpgYlA3Yx-~xiQWzus|(jlc46No&h>Sr z>78%6HPzz#J$$??-Ff#3ETXU;EFonO`2z0c1qCgHNVbb-eba0$VUJp}_H^COk};!< zm{UV^WbRqG1;Q5%hLDEk)bZvBvGM>T30h?dRv7v@YbXf7bTc+1f)EKGi3elCDrajU zP^y?H0P)OCom#8>CzFd!h!9LOU;s9V5yBq~&$=@uP}tgENg8Y*z#*W#2a%&~iLXqr zk~;Ki<#1DLMa~#)yc(Y)B*O}5-z-cytuiV;3J3HnJXy@AFmexw8~x0mE`eQuNSi6l z+~=VTi7O}{hI4rcpSjAFqU@!iTjhlI$gFZ~O4R)8@a%FK<*KVI5z5A4OnM8jd@|n! zU|NB&J_iBLVTU2^Xj%k3!SMCPmNpm|`vpR7y}5{Uc<9?}4(wc!o5J z1c(Mw7Z65r^P>n(SqRTi|5zF=8>TD76XSiUtF8eYFu37y#)VaKd2`HzDdXI@Se(LB zq8ADnEBwwgFQq7X=HE_#Bk!rBm0I)z$zqWGVWaq_h`o@@1fTzJhPhwXX6iyie0ym{V+IGhMq3f&_alqSg zCm0x0$PHI%JP_LgcP$g%GuK)6pZ;VDre3mI;>d^kyHQ+6u}n6G!nmw)ISC!AgCQO} zaTh7^_JZL24|W$)vUr1My~UF)uKaU}#9;2&XCegm!yJLbYQ zZk8Ywxs#`kvev;-kVBki@)v2P?fEt9r}WXb#SP8Vp=2@!H^6719VN`edORJ?aej>o zVC)fd#=(^-(naf?GrZ-Fm))M>sNp*!LuudB`%+iWPzdZ%KkLPjgs>%C=y#mrOj`lg!*dg+DvHTOf#Oqan6ZipT#)J z4hgWx3%59T zKo5BFSwR>W$mc8SDyUN)872iv@E2GYp^5d)wP|HT1Me?z#zt>=w0+<7<|WXwe83y} zz}X$^w`>PzM^Y8@aMjN3%#EAO@4-_&#u;5JL!lhx+$$AQ_y1k@q8roO-}YwsMh$%` zrlWZ5y4nA6@YvC`qP`m50xX%MX~u6jb`e8|v~++ypbNaeh48LQ_;$H??7E_G9y~F` zI@=p3{?b|auAYZ5Sb%FF13U+>Qy3;iB5nv7;lj8hB-Hgmn*fSO%0jdO%)}jGnR9J$ zndTmV`9El~_^68rtm8Xe)5XGHGis_-=j|^M3PvYXAbU)bWs@-}o~ZX)_2ug_1ioz$ zkfy)jOY5fsZW)KYX<=~*xZos=*et?o7by}c!|{v|(I7vuIAYPUAY4Yqm_`ik;&TNh z7m~uXE6dMeN#TqCTqfD(R9B)T-ZK2<13icsW7?oj>o`W!$YSl}NysqU6h`K~VdSj=}7DB_o0*eaY zb1=9C7_tJ>JYgcz1>s~}Zfvtm#^^Hv#?8Z8K$k`wqlP)Li3qoECG}uchbZ$W+Mk7i zk3ty7*hn``xeA2bIn3!={%7Pyz>-MMXg72FtMJhmpFjvhFttOB0TvnM04l<+7G1(= z5YjDgSb;*7m+(`F@UN%2d)A8tGB)0+Kq`K)Yu#`e&mNh=9qd7bDlA&Pbe$XCF^?dg zjoOxN2Tu#uI~m0^MBlj$%O~wvQVPDH+nBcf>Va`y7YLJ55Ku{xIk+#$&FouuY@#PH zX!hdl+jo#U=F^I%W&Gf-XIy+u+c&SrEL`9)s^g3U&lGdCfB*4dkTObRqHW7PEDBf7 zZ@`ava=XCJD>tWF2)YRo#PUNYPNk-%=Cq4Vg$vBXG|c1pv9r*>GLPCm#DOl#^Iv^p|q>nj-PG zf^b*}c@P#)R5*0iu+~-)GO~pbm)*N|L~7w3S8Po^csjm*&%H2p>HtT}IQVi$-PUx+ zZMUUy1fOHakA|RV1~8=jNWd(b@8i01$M7q#(8d`(h5&Rs%I$BXto36j^`gGSl_os2f zK3o7DZFogSdtjPm_XOAvFM@bF}IsnaVAky9W;tIDB@7fT(l(MD_Hw%fb2TL z(0bi}R)QDB4c%q#QPPkBZPSWtx64ps*RJ1?&YwQb*oNq@qjBvkFcMY??pG4$w{`R8 z^s-xTK^PrQ!^En$pFhj~00lgSa6A!pDAeq|K*eS-3PD0#x&`fFJ&9j*B_O2{L{GZ3 zUIj!et+Z5wRzOmG^FDRNIX2u4++#cjW=OgseKIZ3D4;^gMB$LisRsSPYrYS~F=2Vf zP=I3c#k(J*vT=;m*_egx6iV#?LiIJ*U&DThm8rM?=JZ#8`61}QQE(ZW06m{$kAnPz zUIe@x9TjEkimGCN0b`?RtZ!A1c+R-8JvH9Ue59a~xdMSmRCS(Rt3kXefHy556U_X*KOX zus=Qe@T2q>;eJwznj>_sHjU{Cn7~*=_*ex>Mh-k(w{CrU%bR{6ojQFgeeR22W<3HQ z;8aQSj`4w>)Qbn{MwANsGeD~RC-*%;xb!&QkUBQcufnrA2%gYa=&8!Z*>h*oM?U_E zv}yf1!pf>R)R!<@JS79{u^GSsF@+~lqX88{_gQy@JIKlSr^um|y9_I~jMbA#g^$Vy9faw~1{i>z4qk{dfXFNy z$gMC3H~Oh;Fjo34Q5}Wh*f+)CX$V&(1hfk4@G7jx<1mQ+!QrsRmeYoPGVYlJaiShi z8dva9Op;JeA$(}v^)N%JnFLE0bevbgce95GT0>+?kr)@{{V1y;M#gH`iJP>M46)83 z3_2;!GgQ!!lX>1X%t$YTbD;;s_}T?0U5S-a&U*+RSp5}@uxkZ=gaV^b!My8M)*HoJ z2=*`tKFB0;Y<_R3ZwyPG6FiBq7#3khS&1@cIEP_^c@LyQz}2ETk?{EOP=Trp zsjIn01(*Hv{ILd^u>S5Lg@j?^R`j4<-DN!EHf z>xcDHy)Iq1bsfUn*))O|XY2ZwbOM|y2ltjOTb*`nTTfchHawzPosoiAI-qdL*a1td zzi3bE21pWXoatt^15aZA8~s;wGn}LZdKQKl;Nd?|HUyI3HGkb+LtYsd6`4I%kGiOhw zuYc{{R7S=>_W_KNImn*6q@@*AwC6RAU^WXJ8&<4NdmnumugzZOj@e-CRgbTSg3~O1nc4hj*_x^Dx@_N$;Sr>-cxo+J{!!Ha;W2`ahK}yGt z98Mh<&Y^^I5KyEim5h!de4N$;UA zwmUl1la3yFI<+BGj}pohWdMprrHjHuV_R)?L(pgtls-YLHA(;|H)`vVGSsqXa6Fy3 z(36^$uS~1gHo}{#)6-Ay$I10-9 zj9@7jhv;h=<#OPbUI#;XSm+s#kjO!gGTyGzOtKCQXJEc#lQ>Hos3OMWzC-cbJ#XjQ zE~d3>TbL)5KxnC+`PkRRu-khEC7wVG9GD*`91ZC4&IC$TFZ(=t+uQLlSMz-!U?l$= z#qf6e#7Xw>od`uiyq_(pObsjRg6ADQ{&X708)VW2eerp+O^&cN^}h$ZW5)a0q z|MS5(RT!kPnL4KNO+%sF*qUP>2yH@`1GfYmAoR&I%6b4l)&OnLuZ&U$a#5IX06dfr zZY|-H$PSt?kMLkTw`WeBBn0^inxP{46CNC!xqMxQz_$?s*{XX%4MK8FgfF*X5oDVN zL2#DC6vCM7L!m^14w+*yl|@WEELI*PXJt*O1VF%8V7h>1I$8`}N?v8YPgU9^!x z5P>XG*l|Z8)ii&`;;V@0hBy08#FVPUxNucaWXy2VY^g~U*<1&KQ=zdjg*;CIH$zF0 z_|SRXsJLwnXDCM~*UhWtUW=<1^C5`I)Zi$tVbb$rg^@wbE?Rp+VWJ~b9`b|0wV;cb zA1%*C&AlpIzzY(+c&Qvg;7vE^bBGUg0=mw9m`xt5`V=rD;t0D*iVOcOR?KeB%^PrI;ybp~$oc32<^go1ED<(kaGuE!4l!QJpMlG2O2yABd2u}`;O#zPz1Q{8d zdnn3PLQIQDWoGsA((9q(IP2zK>L*8aSeJ4TZ@(+d$P}^=A-x^84IxH|sm9w;hk~I} zs}-p7JZcJA#!?E{nh7hdQRDnWz=jXn{rfjguSY*`=##~g`M<{bKxL%eRn|*dF#SebRx`^qt1h>#( zW1ix<-znmK8Jn*d9u-->Xhzm*ma%yoV6Law@Yvqko;sNimCgfC9|R`A31+P}Yp8^q z`%mE&`GY_F017B^QDNP@{@T?4+8a<@mZj46uC%ahd79-1pr_@WeU+b|p#KVKxpay)Tl3Cy4!3wFra;30vckzJ1cFF@!6WZmk(lH?zw$8@f5R1h-3`!Msi*MNB{S_% zkIm?rmE29B1Y3u(_Y(OPWC&W;P?sKg@+tNlY)7bMzYSqqV<>7WaFc|n%p$c|wi;SA zi(7AsAJ>48W-`EyVmf=~C?!xT@%*-NAnC=MyZ>bNFVyp2N8^+6T)5KGrw~P z{pca-#G$7!9MLNC={QyHBR-#c9YZ#`z?=@pbJ~#JIwVa8!ZPMp$q;2TxpJqxuHCxgho@5MFz{a^&uvb}?CVK8ignPTr zon(imWr>9V=)oCo@L!xL!y5^zGMBvP1bZ=d`J(jJ*DWl)aZeJUVJ@MsR?IzrTmzc= zveKHUT#xV$h=EG9u>-6ks-ZkEEBH)|rBCXUC^CV*(bT` z|8MsfDf|l>ma=~-GMh^aWdytig=LyK+<-C`iJVu&GO{=%)Js_IONL&=ca#M~T+F)R zYK?m=npmlRvmO?w6XJtiYlretU4TbEz zf$`ZVAmaM~L4~0j&kU)N5l&E82#MDXFEET7cPRv1Xw1Ch?vu#EZzOVzLj}O9_$A@W zQGW({2^jU`=>ovOK!J;n^4~tFT$qu|&AuviQ=~xj&?v(`9F77Q9imMLDmP{^Uz#1v z!v#%S7#nI`0JEMUUnJ2BPBdf417&42T8*MT`Wr+Zr7{x)umqym4D<}7F~(um zwZ>)3(p7t|2v3B<@jODU=a^WRq&Jit^VIXN93k~w>v@#R>c~#T(Lx9t^Xv=hPGfkJ z3}-R>O)0{iI2s-a+BrcOf`Xt*^7_pi(`vFex!**q=u=OT0v91*8lkm950d6;%7xGh zXdN&sA{d?J70lfWq^m#T`f5nL-S!fS8VZWjqamcYQTBr${Rm?roRZKlH*Dt! zV=?JNUH!69!pl&&-2+yMC&l^<^K%|mrZ04LrZGGztp3#BKbk&s=a(32W@k~OH)efQ zPYUD9lNm=3R(Np%gUYUg2!M(4st8E4xEpIt7`O(x9q{Xs8*t^k+kT`+G`5a!I zlG61kDi}q;>jgtTte^j($Utw_;H5fzC{OBV!b+H9&>-p*RrGj|;6W%5j+(t^fB0xm zc&3L^0W?CRP}*Itj;Fi?s6sy#sx&?+IL4k9V5kvC1!lo@|ICF#gz*WA6l*ZrkVQbB zAYe2=y#kb1+;>M&%5u>cEy;#Tu3WW(FBS;14&&fq$OQ_Bh~T;eSw21fgCR{Az2Ob43Ex|;Xy56Eb1yDO2WvRQg0#CsD zG&0Z^3jED4e@Qxa;85x$ymA2}NYl!dzzAjU!Vo=&c3KhR(tjBqbiK;-u?w$3BVnZu zZwPOI#;Z6(1RTlpJO_-Sz9?Oc!~QZ5!*fenAJfo5579LoNO~{|uAJd8znyHZu889(`O7^z(lc3?;`L^`H{e)6s09nPE8&_YwJw0^az0nt^ zR1cP&Q>hbHUA=?+We&XItN~Nkj)u2V3_}~pv{r`^<^(#KKL$UvWZe; z6G@FQ6_uoq{Ni2!n)}kFjBi>-q|}UCh1@cYhekRv&&K{7w6LOrfm+GGfeU4-^wgFEmk9-`-2A1VkQ!spo^)`9Ue zcj-IcZ*OmJxr0Ll{~OmE-tdMyJu}0y&(#m_k-+069(?#GfAS|k>zN#uU3$m*Jx9Zn z)ICN0(t7*)`j)-o6|cB^sU7=eKYd5V2N`e*Z`GU!{w<~FT^fV+U#cA0=D(GT74w2G z_B}&dkhe;TEE14k0-`{#kf`<#cSAry_~xT4&IQ9H#d?r)b)U^@E~grW1vjxRTh&A^^rjGe@-U3a zaS|vRdV&=vGI0>v(tf@V!Fh_lDWC&47?vSCf<8{%wKt&<2nis7v`~cMnq7+F(o^1n zF(^<)95VeEChm%Nqarh$z32F-C#PV}Tx;FT6I!tVftBHz8O%!oUJKUJDcCa*b1kOO z^RQ0Yr~)UeODNIjAj^Eph-#+H+E*@M7R~#aN!HS+z-DgyQbVl}=qgYiE6H{4;aAi2 z3m*xD7q1qU_$K!DjG-+Ss%QrRXbwVbXuu%h3x%qAQs-hNXO5ju(=Lt^mpo6{T}2(S z$a*kB=`og?^I@>~Irq+DIl^BVsg=#J;@AzzDMvtEwQd!RWRA3@wVCkDTxUF2#vv0# zQ8OfqJ~|Hop1&e2b8cHIZy>AbKudFYSZFW)@ob6>s?F=SrFC`9Y}W24L~b@sR?enI z&cz7j1!cuKS0U39DHL=RZNF*{VQ?cfjsna4=-CvLgoR2TiPTs( z;L9*`#J%!TgmwNZgwMOsW&XLUR7=|x;7eHzaGb$2g>Ya(h%&6{?#HPoMtz!WH-@hW z2-gaYgt35aH+%$V00yX-p{kGh9>Q!8DAzmxz z3@u`wdAaq%#i(1Mr4wOx)tXU+E-ljtDvVEyZ8?J1x|U7swK|R!ekL_kHc$sm@xI0f z&wCgm>4FE*u`7;qBbI@e-HeSMIadf$()!3=1Wvn`Nr~Rk1ztPU7%v|L9-h1K8uKoc zk+n@pUXd=wVQ{R=7^=9*|5*@Nno+2(OPe-rNbMKSa+-I0x?%UV2%sAnE5-@l)q;Hr zgM)Z9!#mzHgt3*qL@M`&y5_KI(5uv5z{$9PyWQ5SWT@8_yRJ)Hw?jvu1>1I985^qeW`d%v4irW! zj!ci)+tAz!351P_OyNP;#>Q*+NomXg8fhbR?*BU5nOfjABz=m@tdX6hm->SZtI}Bv zR+(68N5o_BHsCuK8{*5MU3yx?r%36I>D^(9$5Zf~{=T8Ke)Ssmbq%rirya!wj|Vdk z7{FusTSjyAcKTi{Vtc`7_Y=7`rFFq?081!vbU?ax2F1XPmAnMLIIBQ=aUICd;E?pg zx>WAi>&9NKH7G4Lz)Zfb&~8|lb5u`A+OoR3bpO}!_!;3qXC}ycH8^?-JUB&N4$A-3 z$^5vVs{|V2c~pApZ9_r8<^oROre_X~Vs!GakscY-xt&l~h$=OA287(!ZHY;oKjTsX}XO>n0U|jT<+f^F;DD zzxmDo`!%n5%@=m;*m2@-{^oDq;=y^I6Y{Z-ee8!-4&L>ycfFrbxf&1s^ZbsrYu8?U z)0^J(=}X_yn{v%H*BtO5zy}|E@Ycv!K* z3Hq(y`mJ~0cH3?D-+c4UkACfIU;C~zr_XHt?46%|!`{7nZ}K2QpWS}@?e~4y z34|#@P-L_@tn}~OK)pmR%ma7T}wJfeO79#|5vCTPGA_PGi?5!a9u3U(M z7BQEowU2->2BT?*=t9K1mcM8irgkT!l@Nv)`q`9Wk5=p*C-#xbjPnFU7uGfKnbBt~O$J80F-FE9et8+jS8(3>>yR_ZGEU~+e#Ttu#-~U& z-xdOge4U$-35y5uSdhsCX-izvGd4!LV=puAlq=M;1|3(=!bLm}>X5)5JT6pK;Tf4u z6DSxHgd{0^no^Ql=%e#t3)y;%wJGDI!}epK`(iqHpcvi_4=pP%MR=49@Z9}3zUi#x zW%wabuqL^qFs`6voVH4a`=m@y>s5j>S&0COEdi8s-;UN{a0Nwum<_}2q~|pp0|4K@m|Lg#!T-P)rh?1!4G7=0l5MRqz4rTGpVpB2+RRu|hZ83cr%!(7O9=Mx z0_v|cyAbJ-UEhWz+PO@~TEai>(ZTQ(Q9kG{e?wWb+c5^mBK-KvJZTh>q=^eG0QEKC{an6^^s9KqI=j0V_fUHC8{Yz);T!Ii=1&ykZ>6_sZ{nMSAp+hiFkA!`cycXcv08 zGw#H1ah0J(C+Va7DVD96$oh|wBG?;FIWa=o{H^>914i|}dk0NWEpZP%^rilG1uG_Q1rtR&T-5$zp`i+_?`EF8wAp70!D(n zhH+OwZx)y*>sDE-Db%n=N7GQpg>?Qv!M^dPL{T6qdgErQm=1 z^y#g7H~j1=<9ZAXf%4EiJqn-vm%sepd+xdCj^Fv6 z-}yC91-}FD2A;hOfBeUP{0q38qziLtG#ufF=A z%8jRvUw{4ePuVxt5o|L1u`h;m>8VlivEG-wm#&(vmy5(O{EFpH3Db}7&45F843)nrLo zy{0L(p6e#7hy&z_%z#hMk}z<;i~A@Px@Ewos+8&AM~Hs70pAcU`H(&gUG;AMj?7w% zu6=HENiR?$5PXc!)!{LR)y<8~jDRs9@Pz_EQD9soj7w4)A!a<+?QaNLDOP4ZTb@~> zC9Mn4Y~e6_L9h%m_7H?oMpblcVP?*| zz;iT;EE!V*7i31F2dxBf=_5tr7bqF)DFlDMICB{W`kZ3GFk4&Tt9az1pf1;pmHIE6 zzwEw!fI&o^9_pocXw$k)aTwMpAr>pyJg#Cq$_8Omj@GNV!+}kInuSI(hpZ9h7tb1+ zu^sybVEt$eyYbFu5o47Q?xQ+LkC{(*8F}`D=U^8NU105iUcj1F$y`XD6cT(dXaMWT zIW?u`0G94U2%*M-D->jxqgw=(f0YyzXn3rx*1r~5l)b2*=iG3kz4-6i@OflX1Mk9~ zYlW;4>C)CMyV9#)b9=&imzu#b_ioKHzBV?!pCy}76X}94o=550|5WP1`rO05FhjFU z)jUOdXEWA`w;rVc1VF{QY!J@1lP(quCxuo8Q~8WM#M)f53hh=J)^%WioDJS1D7N(+CR+*| z&)^ji=gUDR(bzSxB%D^TW{(~_OsEkDeL_!;qG+nk&P&f3k6DCFznsC8zJ-uUKLQz1 zDgu}6G4P_^=sWlt0<>d{wZYpenn=La4J*>FE4Q$*`aQ39QzJhZlTEIl$z~psw zGS3GO1`Optp33d)>H#Yu*@v`OE4^W>B`C+G+!Mzt5I)1OKt2EP!XwN){aR~RYDS?5 z_&rl7IvwBg$2*vO$HCf{KRb8AT!58K1`PNVf1i1s5T$hf{#cvu(&J-+Z*mFCC>Hfv zm^K&RxwQUoRCVdy#eyXR5Jl$dnd{OTxcQBj7r)5g;48gPr2GT>(rpY(`9r}zQKr)pO~+Z#?x=JONL0pMSt_63o@*rSJQS+j0Lsoc{iM|DxYqzH8TX zm3{WZFCi9g=$p0WehUTvn{K*kuS&ozx7_l`zJ2?y)01E*(|z~dcl-O_|NeKmFT_*G z|N5{0`W+iLu0Qu@fA(iTtpf1SLl3=F<=|I-DhG{?je~kd?9--An_B$DIwr%&zVxLpy;_AtPl{n@zy9mL{@d1Xf1t;ZLw~+wGxlsSyrA#$k{5Jo$y%|j z3FD3gN@0;|SP@H$A}r+)LJ6{}g^v}e+y@d|k#{7p`cUN8YW=V!e)txI%e%h3SU2tH zdX@258Nac{;AL>V(YRJah4NTILFf^JZB*uoP~sDn6*urHSZ5o!tcnVFgzYkfooXyN z(_~3pcNWK5K^tyHRiN>T z)8To)jD}^*Qp`}W=(`!1kOH|yTL`itU{a^Ct^&r`dH1|{XpziZILWl#*I{Tufv~SE zjEBA{qyu+XfkNFRjK7i?YA?M?RK;ccKp$A>?NE`JM<~&9s|%X7#I!I0D0vm0JjFP* z^y#fqptnu?ti|5y+&80jRh}RY#4Z7(b}ik8#~HsoPd1qtFUpv2EnwyGYz_N4I53*w zT{9s*(}Y%V&txtNoO&npE*bK)ATtLZ)mY{gs>ZRN4YDDUhp8Ds#!O;UWX{R6F*CBM z0V{FX4b&4@@(t5-56Ei5P(lG0M{LOXqvLcnvQZgUh{O$i3GZMY^_(&7w26qsJn5mp zUqfPnmEi?4Btn?ZAY2YmBs_GKLv}@o8U`Po-^?O!7*9F4rJ`o|p5s^P41P*WDk7nL z*r!-X{H1Q;tdJ2Z2krY}=~b;Jf=K8s7%;aUqpS`CQC?3=A;|1(Q@ zW?9Yf#dMXK8Yh@hTp1_W109H0c$W{%x97P;b~fM>hpN(t6&tptE7^>zC&}?sk{>P8 zwh1iao_7&ssh47LkLsdd3iqWbm!+m{g0g8Pw{4~?DwD4G!ua$U^GOIKh5>QkaGz#2 zxc2pQ;}II<8K>Rj1*xvBM`3GW(`#*7w{}$;Xg$Uza`4^G0hm=Q)^M&vH;vO50S2xB z`Irye)N*Q{4Ht?q4Cj#Vjwhy{@6xmWL6Rr*v3Z+*%!9|)rxL<1vS1DJPFZSW^SR+o z!cL_Pbvf{C0R#&hDh*b$IoC-8g`yuqMSPA~vwOmVdvkO`I%Hp**6@TorNVS^j#Yq` zg!iCXeE0HqHcD$J6p8jKQIzU9$KmubV%^yj)J`~RM>_%|m+8{yj6-5PvCmDq$5m5N z!%${9Kc_Rbw|4+jaWuAv&_^y{=Gq%FdzLhg#+>p?Yk*>e#+O%csCbBzSgq}c?puf^l zbEi3v?wc!P50U2uO-i3x{^H>|v77!tk z!4DXJq;F!{?FXT5NBm7Y%)hDjufB43y8YIh(pnO?^bhu?2Of9`8b42%^U5&x z40DE&M!-t=z(9Xbx(FWik#hQ)T|49Kl|Hg)Z6sxL6XzRUQ9&Q1`+D>NBe0|&fFWQh-0{|2aqVvSaQWQS^jznQZ+_XE*~otorQPbjQx}t6 zE=oS{rLv*7K;eAn&Yj2nZecwIANarrevV9^b>4s7>t6TylP6DZf9k2HuK(We{oXJC z!Y};7AG;6aw}1P$f8Bi@hYlUu4bGRm=RNQFWkaA8>h&@_`yKazJow;)xB8ADQnsVu zztoQ}eBleP(W{|i;Cd*ArRH-5%_El)oArC=ug~dX)D9Iz*&rvKsTUE4SXIUSp1bp z>Q;_tJTQbs#^lCfs|C5NgtxKmA;cP^?z>Y{2n~gL3j~9KdQcALpoI*9SSyM`jR)5? zk|{~cv#Ara^o?vhB@WvxHlb87R^&1^;ZCHE;huOmkG0)>4U%MASDzUii@Qmy~U}l`m0w~PFlR`fosRt@<=M-<1NH-Z? zz*^W#2+Is-L{yN|J%?3#m@HSvPhF(y(zI*$PS8{Zi%qO368S#0JaN_AvFV>hfZ->#bqL;3X1@Xri9SXrX10=X9VD>ko6*Ke*x zNT*zBHF@*P)5a^W;=G3*QnTU-q8z^5G(s4Pb%YWGjAl^ys_CO+bY2wb`I!CUubCy5 zF4svW2=IabGEy-ighB@u@5#)wH(W3A@zQ$0G28LJE87&*iY1BzBZM|IHZ+FE>&1Jn z!_&knK`B+?EP_XDu8T%J@!CWdc{lS@Q65|aK?5FUE35RRXJA#!#?aU^10B&S>>eNm zA~)fBV4WcjqV71^d8Y7;m};5T8@Ob2a}#Ml2mL+z$dhT;t}79a%G2@lJ*jIkwe|vi?M7%-P!WF=rU54x>x_jK zr;+n4`ncH9Y$-({N-;)+;c{TIdgYq5oQ=fC4jzs^T8rKZ!_ZdIr&Y@uI8&#BL+Xf; zC$!Uz%uE+;Lo=i$%yBu2NH^!DD44s~Ls&C-U?vQtJHpQ&X8^j$KRZW>fR^-41v(5) z0t=y-5`40LX}ola`;=1vl`mvzPW4y)EFPaZ9b9$AV$1_53;b3&N}5fIho+gT#WHfB_KA6RJf9tg%V5SxuxT5b}R`*QQiM z+sk2w;$9E5f7-JA2-^~9&;;2ig&bKnB&1l~16eZsDkm?BUNeg+I}jPcpN{9T0S zchnzm$5a!-IlUW zdAPt{Mh{Ok>E<2Z^(r>7cah}dKx*gkSZPZ{2+*g1xgDS#n{p})TMCa2)oK*6PG>^g z8X!Z~Bac6n9(?@apc|$rR>>7Pqh6-V{Xha&1xQ}4C}C*f!PZvJ1R-3Oc{<+K2d~Bu zz??V-w&1)}ATQi>^B(qzaCVV<37JcKCJqN4py9d{1)=m>!%+Z?Hk>PIh?GSOS@c^z z$+I{-lXm5QA;$pUFg!6v_klTg8sNgC>KdXP!fIfj;lb{;D~G=1;Dhxftr=+TC`D$0 zz~-@#8c+VO_fp7r)AiEk^QE3DjJwZc>ARi^L!kUwy60aN4a;3xcIo-^y<^CeKTGBO zyVMW&gj{<6*`M7H;?L536^*6O&#w2`-_54w&r*5+nqAAErF-`Iy6djnxAgtr+FvpL z1zju`7cv{cVVe^7()e>(Geuaq)WBjP z5-C1Hq;o3NtY8lZ0?F8nNH_-qs2jw!Jjm5u+n%~E5igDPiXtH-q0n;>^aXaTMs@u5 z6xp$nVT31yJ{EtO8~G4+R8TCX0OCPUTG3U44EqR5K?N0r&=d)jmk>!@C-IU@!&oqa zK!g|rijIUb2hf&?Z;|w{Lj#1JxW6NMk&V*LXDU;+H-on0Gsr#f^TS^x@hIqgDs*Fr zC+q-04gt!!(Sn|5KS~IjF~7n9STR3>(Ga4Db>_>YLcMbt{g%kedR0CNk6`bDeda}o zCNK>Q1g2VtB=RyvkqKg}hl~h#?opQZ;Xff*7!C$ajd~=m3L9GPjFq0w)da3h#T@9- zKxk@dBn5O8xWkySGI}7D1YTj(eu!^|eYqz_Wle=RT87!XUx5itt5!9q##PHm>o^&w zo0lSxc*3p%7>#6#9d(EfB`AScY}){e%D7}WDtX|GW1vozFBPmJ3a9&Y0-WHJULmbu z!JvSPhl3fsCw|s(nsJu3%7dhG2#L$V2M(SjT&!yl>vvms-$B*?6&(C9#b~B|k!-Lc2!F%f% z2VN_%I9Auy(kFyhU|h9$3c41;X<%AF5pmCxDV&YB*3uXr8HD_5(&sYEtbvpsf8>!g zPK>wb(@02`uUJLD_W?J1NZ2I`v*%i5o*b8DP#)R^B7jGHjP)a!SfoM21fmO;Wf9<` zEaFJK>3R|O#S2Q%7V~3WCW~-QswDB=aSmbpjd%Yh0$LqeoYtg+hmTML9!5GXz8yb# zHr{XIbomM3A??#}qea=ZGb4d;dTa!Rp60+I)}7u8+!H0Uz*R#hM5`2q8g-wy=?k9> zDRLgomSvWpFi6l(rh!VJqu^;D9+LTP_5>h|=J^g&4;&3daa~bUoNK~;p7>(aX+L7- z{VUC*PE%itDbhZnqKAa9vA+E-9SNF1+a@Fs;31ev6MQDPg&VCzh0uZCj@IiUXw?C?Gmo)Px= zX!t^5W}K&wx2CC$GbC789*6X`Y*>@}Nh9sKO<}+RW`S7@-u-oBV~DB1wSZ-5hV`!p zhbWUYMjyuYX7M+hXJk$Ng0xcv*W*NSaL|!R`?K|l5)2(HB^+;lTAlzUVyw;yFJ|kU zPl4o)KYmmtr85~kycsZ&z&b;`YT^x3fp>QIfMX-E=b|6)ipf`0QWwx_#2xvC2Cf3$ zCJlt{1vHDK2B~f`bh!rg8o2J{q1&@V?+DPK$Fx*Lla}j$s6( z9{>3$zT0DXpOFFTL=n-!+AwU(q!p87N1TDjc%WlBi>{n_+6C5D7S<}@sS721$dm5j z)25zhHBpf>ARt)itVfmhr7QR+?OV)Jl(1peHWx6gR%!4(z4`Ewf{_8PBV-y4X>qm{ ziclZ8yKeKA)PRC##w*VWiq!hh0{6zaN6$3JCy*5z4dq*HsgXd+{(Ub*^kZbi*3t=Eh^#ixr78V0kx56 zLdGF{C0M3kbH~oKdG+da=a(K$?Y%Qu8rDfdu_$k>w)L2i$PI{el{(q8z@iS9D9XtU zaVC+L6QW6{@eEXQ&PFrkgo_$DFByUaaf<9v)Jvyg9J7q`99c`eWpB%|vKI);lF3eC zJrQ;aq^61V#P+-i!Rfc*T^p4@GDzW`*Z;16Y>AU}%Vnxli9^CMqN))B|_n z1q2w{QGtmxfp&r+xaTA?0g-Q*9`iczLYSs|FlOc(p;@834CbI^UWRDPJdW{Zgp@JR zR#@#23ialgMaTIvPCaH`j%<^3B70Z7q0izIeRkeTN#&xzrZUM0Xqz@DAJ%>Dk03M+ zvF9SPtI2E_u6SaYmHQ!TNVC}b^f8zn;b7t%@4)N8HyDjd6Ju4m@uX-&gv6z4Jv-Dh z!*1jn1mRNZILY}Co_R4(KO$QZ&jBZG(Ki@E5n)-ONM2Emw`3lnv8ann*wdcrNwfK( za|~NlS#Y;A`^a(z*V`Zuip;r+naXC*U|%RLo`Yd%oPrhLPF3{?;|n9ezkmSK6JcDd zRRv!L4fQwV*xiUFU$c#d36qp@_J58J`r%2=@!T zny;h3C8?2ebv5Sq@57T-1w8deX1!BsQaPK2u`ZzOjbjORjj4Q3^Sun=r3YB52xw8h zV#l_0mh(3{+j}@apgwS2PgKmQ%8Q<-IHV2Lna!mEb46-9>J;%y9Cq-ADyrB=b{`2I z?dma5I1+b5A>+LzIH{D!G&3H8R)Vh0xhWLkS0&icw)XY`1T}CJ>UGr+EaU3OqXQ3&6w?$pB2pS;;;qE1h6&CfM6CGE7~} z-xNxXLYTdu6tS(B2Q!4$j3VHiZ#_qQ;5O$VdAO;#tP&^vo@6d;f0{M4o-nZ>M_Oul z>W{QPXaq>6!9lu>eC8MO4u~7hkE3%;QV+gRzw2EYN!*Op5je*)*OWzY^SDRB^OD3% z_x?=zfd66Gh|k~{WxOw+(Rv)|XQ^NMSp;vo5!iCzo|i(mCyY2-i*C3jJ%&|&3_4tf z;j4u;($_kdE?~r}B)eZ3iiGJ|^`@ICa?XXy9BtXUA@w|U81G4n6t)u=@um_!HR2io z{-THidl>K#q)n7EPn?jUPa1{~VCch9`Pu!(fh_B+6^} za%N*-6meu4ccL`o7f|A|{5@bq>B-5_^s!HVGQ%;FZ}>847=oW!7jg33qR-H%Io4x2 ze9p61h8f(4KJpPtXhc(860X!6?a>d)*&A7jW8rqzkH96BEsU5>AOo^o7+EL-D#aM% z7ms6X4pe$2!f}OSoOPA8Q~;+)HxH@yz6n}Z}_dslhB*M2=E9Vvi9~taLM(P9SXW@OA9z=q6+WK|s>~!Y{aOMoJ+BN_t!pMQym;$-W0ZyK-4x5QSOe;3Wt$W!AU^TC$-v zOF=mZyo8nVK?7Krv2O%gVEnf0!>6uth0$3Sp~7NVhoeOo@*)vH&<{dGZ!${*{eVz} zHPpIzYCZPU{%;}g`Sm+C!u(J~Uh(4e;ZHvTV}nph^dSs(P6cRiU?A;I!#zOgdgc>bbbFoPu1|QaOye*vnp=I2d zU#({0W(9WkVJ)ZnGJ@F4;2s0tmkGGBd<9l0~RltJKtbZgqT$zNJ&iX7lMw;m5Pq~=i8S{l`(|V+6 zJkDvlW@8ebl?YNLCa@J6Dg+Z63kXK`8di{L8MX3z{zoaf;LXgX=g-aXvvXqr7|V7D zpu)+S%GOvar=L^Z>H1x}fIUhb7+r@;{p<<$22fBzLN2!?{3sWLc_<%z;Ae>e%QJ;P zQ%G6xj8fv56DMO0$a6m~=f%%*ZJ8!(LfC0Eu%xN46~=uhgaDD9OF<{cy!uU2;W{rO za7_`?Ctj5-G^UlD7qXhPo?EwWLCLQG_f)_ud4V+m0uJ?ca2V$*GQnLWbcOq5dMg&k z=r@WWy&mTFY zR}sm)3f}jke!UJ9P{>oIF-#Ne25(g!SX1CI@^J|Hd90O&J=zO4Q=){^ujrGj*qOr< zsDd49-uWX_4=H8e{KoG`VI#B@rDG4Crab4>oIZMjGaQD~AYLGalaK$+=Lo?9=Rx>J z(uN*f#f*dc`K#eX!%hRwfAq(GG+jw7ya^;uoH(97{E-iH4#aR+i02SErCV_c z1IJB2#WC+PRA9ztY33n}MWUp{oi;!#{w%#K956ol4*x`9tII-EfSu(*Y|kgkLlGDLZ;*Yj!5^)HT;>a~qE>Bd`bQy?VN6N3ld zj*BRM@()--z~2a54PFAn3~UP3O?5TthHI`&$4<4T&W>)vQCFm{&Yn;_+%GY2+!beK zsT8RX3dzzq*D33pin@tVO7H-!Bt&h`728o*8L4Amq!rofpzqw&n{4}z!J&D@5TkC# z=)5^l9ysZ8+kjv8RoVjxXwR~oQv)0(pna;yW#Fk9#{}QdP;Z(Y38>mcT=ogb+dOm3 z+Hy32V@avBYrYXmKX6ksvh2A0x|}2OD~pkqULTe@;U{MXKJg0=@&Si4NHpd(Jw5@2OlV@W%+~w0(<^ z?gN=evO6 zC@iE%%IrqYwi=>Z+5!lr(iPVI^t3S)8CbG`U;cd=0^c48xU^pI#S#H+Sy>Vi{<(n7 z#je;Hiwwd5VuRT#8DKn&prG{tg2;M;C}=UyEV@=@Ju*xg3U+dc3(qCg+%HFfG<}>z zP=U%8ykyuOfRMd5!H#s)kPPyI#6xaXFC^lvADT;it{u6;LpFFRxNK# zy@W9>KtO7%AQVzGM}%z|FPD$dCIVO>-Zo#%@iDm{wDJudZ) zr1zaI$5K3oR}0Su9Fo(5902e{kXVFAH(?vAI3U3jq8o{qFTpzH>BM6D48kLTHvj@0 zM;Tx~=9nN2gr=lr;zPg}<8r`M_tG3nUp;y39lz^Kf#YoFNLsdSMH;83lY}qnkz2WG zS86|e9L04CT*8uzQloO=d@0;nXCBVuIAamSI^Z+k6&A8ji@cK33WzGVnF1_6vKD}~ z$_7tj4GJgU6JaRMbZOnAKGu`C<65(hJV_f$3g9erXFatro{x%g?%J)5I~)8&WhKMIEHf{9rWxup?=7?sU|>qwnbla3clZa4d# zN||#y=85)2ge!5}5SxWL1ZDa+2+pk8vYB%Xx?&EcSadJo)W?bF%a&DzfZ#qHmx=&}dELSac!49^9^c`0r=sgvO(A&7w3;g#iXtR?EUk9vIg7(+AEvJzz?@SB<=bdHB$ z0yGSo%2-uq=go;ak7DMUM(7{Gy1Kx+(1pNbVButEh85>b+DZp$*EHL}8G3v2TC?hdI9kBOpMwm{YJ`U_PI8X<~Rhn7=hBLHjm}X;ReH`-G(|I1F z3$y|Jxr%crI=lDMU)CgaL~ot{G*e0UT=04WgpGn%CVF8!0^4ycs6~-+XVZ(%+s)1w% z0Lt)8ue1zAdaOm>rtFh6&yYJk9SkYTM%s8ETeodlfprT%`lOod<>%-Jbxg4D=>EI! z=5Sk#4fK)TGMy+1)a|^PbYqIOT;IF~oYXMH`k_5jqzha3CTTdzL-STQHK*#``E=mK zX%3q_msS!|IEqKOmgmzd%DfZiDEh3(>Od6Um2SnITIkevP7`0fqA4>{KzrQCJPqG9 z5l0M?*Fxb1f2GAtS&UaW3kSixv_=97z#`_;_W0lk<38^xKR8W}gBgqdNJ9-fp5zc% z>AH2QY{t6eU3=kuyKQ5xRlpg4HApVi8AW(GrkbKL8%`eZ6Ar$sG!cnxXg}*b;HV*R^(4h%M zrJTk*Q3`$`T{JDYhDALp(lO-*4~tYO(fee*Rd}-EGLIIscHV}_J zL&(Ei7ce4>;6W=?c%WiU8bdBH)1t$&%T?fm#wxx2^B5w+$iVN**JTKNyCLw;Qb4BQ z$P$oDKw&Yvz#$~8wIDPG`x)SR0iOtQU>p)C-NVXrk{pF#g*(BrbQSO^1My5q2ntRWz(gXg z=PJB7jMcHlMW2x&v%0ty;DlKP91Llq&k{YUUU)}nnWyxewtUMg;)HXk(U5i5WmwXaO#fryap^khG*FSdLU??2(};VNHkn=W+;I zG%!n;h{9E5lVN;X2rryDi@RH4fzjD9`eL{P`VgBgiBqS)HLF%f-13=oo#2`{=;%J$&ROXqijRD;n9u(HJ-o8QK;n!Sg;$ zF&kqAwqfN2yGmGR{iJ>LekkAc`NFx2@gozHyD0#U-}@Aslih0+GYrnM8NQ04ur`GM zjB^N73`vSGMhCzRg*myn&(wiJK*%0Aw7?OCfJ{!Llx6tt8gvC)-h=~zGW2b+fK~Dl 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 diff --git a/docs/_static/esp32-s2-devkitc-1-v1-block-diags.png b/docs/_static/esp32-s2-devkitc-1-v1-block-diags.png deleted file mode 100644 index a19c87eddcbec0a9c756ace2790cb1b404cd426d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73587 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 z 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 diff --git a/docs/_static/esp32-s2-devkitc-1-v1-isometric.png b/docs/_static/esp32-s2-devkitc-1-v1-isometric.png deleted file mode 100644 index 7c57f1cfd200e272e0458b0627c2445f93188297..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 297765 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

whU-}y&ZY-NvIP3B0C$XfNLi#Z87 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≀aHr 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%0A~9eOn2Z!~Jq+#C%#!4Xk| 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∓AqVfOPl{ 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⁢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 z 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

qkkOV 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

KEeTcu;}?-P>J)Wzc<#n+DxKeE+~ID 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�Z6pRdgG&`fs|~7@nRZRTPMFb+YF)bWTzs^t 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� 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 |f3wgTG5N_R%*v;o~ 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

S0ugNCpPkpO5AWF#Urt*- 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 diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index 1b8048d2848..c6a13e768e3 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -123,7 +123,7 @@ If you have one of {IDF_TARGET_NAME} official development boards listed below, y ESP32-S2-Saola-1 <../hw-reference/esp32s2/user-guide-saola-1-v1.2> ESP32-S2-DevKitM-1 - ESP32-S2-DevKitC-1 <../hw-reference/esp32s2/user-guide-s2-devkitc-1> + ESP32-S2-DevKitC-1 ESP32-S2-Kaluga-Kit <../hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit> .. only:: esp32c3 diff --git a/docs/en/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst b/docs/en/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst deleted file mode 100644 index d14331f64b9..00000000000 --- a/docs/en/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst +++ /dev/null @@ -1,313 +0,0 @@ -================== -ESP32-S2-DevKitC-1 -================== - -:link_to_translation:`zh_CN:[中文]` - -This user guide will help you get started with ESP32-S2-DevKitC-1 and will also provide more in-depth information. - -ESP32-S2-DevKitC-1 is an entry-level development board. This board integrates complete Wi-Fi functions. Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S2-DevKitC-1 on a breadboard. - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-isometric.png - :align: center - :alt: ESP32-S2-DevKitC-1 with the ESP32-S2-SOLO Module - :figclass: align-center - - ESP32-S2-DevKitC-1 with the ESP32-S2-SOLO Module - -The document consists of the following major sections: - -- `Getting Started`_: Overview of ESP32-S2-DevKitC-1 and hardware/software setup instructions to get started. -- `Hardware Reference`_: More detailed information about the ESP32-S2-DevKitC-1's hardware. -- `Hardware Revision Details`_: Revision history, known issues, and links to user guides for previous versions (if any) of ESP32-S2-DevKitC-1. -- `Related Documents`_: Links to related documentation. - - -Getting Started -=============== - -This section provides a brief introduction of ESP32-S2-DevKitC-1, instructions on how to do the initial hardware setup and how to flash firmware onto it. - - -Description of Components -------------------------- - -.. _user-guide-s2-devkitc-1-v1-board-front: - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitC-1 - front - :figclass: align-center - - ESP32-S2-DevKitC-1 - front - -The key components of the board are described in a clockwise direction. - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - Key Component - - Description - * - On-board module (ESP32-S2-SOLO or ESP32-S2-SOLO-U in the above figure) - - ESP32-S2-SOLO series modules with an on-board PCB antenna or a connector for an external antenna. This series of modules have multiple options for flash and PSRAM size. For more information, please refer to :ref:`user-guide-s2-devkitc-1-v1-ordering-info`. - * - 3.3 V Power On LED - - Turns on when the USB power is connected to the board. - * - USB-to-UART Bridge - - Single USB-to-UART bridge chip provides transfer rates up to 3 Mbps. - * - Pin Headers - - All available GPIO pins (except for the SPI bus for flash) are broken out to the pin headers on the board. For details, please see :ref:`user-guide-s2-devkitc-1-v1-header-blocks`. - * - ESP32-S2 USB Port - - ESP32-S2 full-speed USB OTG interface, compliant with the USB 1.1 specifications. The interface is used for power supply to the board, for flashing applications to the chip, and for communication with the chip using USB 1.1 protocols. - * - Reset Button - - Press this button to restart the system. - * - Boot Button - - Download button. Holding down **Boot** and then pressing **Reset** initiates Firmware Download mode for downloading firmware through the serial port. - * - USB-to-UART Port - - A Micro-USB port used for power supply to the board, for flashing applications to the chip, as well as the communication with the chip via the on-board USB-to-UART bridge. - * - RGB LED - - Addressable RGB LED, driven by GPIO18. - * - 5 V to 3.3 V LDO - - Power regulator that converts a 5 V supply into a 3.3 V output. - - -Start Application Development ------------------------------ - -Before powering up your ESP32-S2-DevKitC-1, please make sure that it is in good condition with no obvious signs of damage. - - -Required Hardware -^^^^^^^^^^^^^^^^^ - -- ESP32-S2-DevKitC-1 -- USB 2.0 cable (Standard-A to Micro-B) -- Computer running Windows, Linux, or macOS - -.. note:: - - Be sure to use an appropriate USB cable. Some cables are for charging only and do not provide the needed data lines nor work for programming the boards. - - -Hardware Setup -^^^^^^^^^^^^^^ - -Connect the board with the computer using **USB-to-UART Port** or **ESP32-S2 USB Port**. In subsequent steps, **USB-to-UART Port** will be used by default. - - -Software Setup -^^^^^^^^^^^^^^ - -Please proceed to `ESP-IDF Get Started `_, where Section `Installation Step by Step `_ will quickly help you set up the development environment and then flash an application example into your ESP32-S2-DevKitC-1. - - -Contents and Packaging ----------------------- - -.. _user-guide-s2-devkitc-1-v1-ordering-info: - -Ordering Information -^^^^^^^^^^^^^^^^^^^^ - -The development board has a variety of variants to choose from, as shown in the table below. - -.. list-table:: - :header-rows: 1 - :widths: 41 24 9 8 18 - - * - Ordering Code - - On-board Module [#]_ - - Flash - - PSRAM - - Antenna - * - ESP32-S2-DevKitC-1-N8R2 - - ESP32-S2-SOLO-2 - - (Recommended) - - 8 MB - - 2 MB - - PCB on-board antenna - * - ESP32-S2-DevKitC-1U-N8R2 - - ESP32-S2-SOLO-2U - - (Recommended) - - 8 MB - - 2 MB - - External antenna connector - * - ESP32-S2-DevKitC-1 - - ESP32-S2-SOLO - - 4 MB - - --- - - PCB on-board antenna - * - ESP32-S2-DevKitC-1U - - ESP32-S2-SOLO-U - - 4 MB - - --- - - External antenna connector - * - ESP32-S2-DevKitC-1R - - ESP32-S2-SOLO - - 4 MB - - 2 MB - - PCB on-board antenna - * - ESP32-S2-DevKitC-1RU - - ESP32-S2-SOLO-U - - 4 MB - - 2 MB - - External antenna connector - -.. [#] The ESP32-S2-SOLO-2 and ESP32-S2-SOLO-2U modules use chip revision v1.0, and the rest use chip revision v0.0. For more information about chip revisions, please refer to `ESP32-S2 Series SoC Errata`_. - - -Retail Orders -^^^^^^^^^^^^^ - -If you order a few samples, each ESP32-S2-DevKitC-1 comes in an individual package in either antistatic bag or any packaging depending on your retailer. - -For retail orders, please go to https://www.espressif.com/en/contact-us/get-samples. - - -Wholesale Orders -^^^^^^^^^^^^^^^^ - -If you order in bulk, the boards come in large cardboard boxes. - -For wholesale orders, please go to https://www.espressif.com/en/contact-us/sales-questions. - - -Hardware Reference -================== - -Block Diagram -------------- - -The block diagram below shows the components of ESP32-S2-DevKitC-1 and their interconnections. - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-block-diags.png - :align: center - :scale: 70% - :alt: ESP32-S2-DevKitC-1 (click to enlarge) - :figclass: align-center - - ESP32-S2-DevKitC-1 (click to enlarge) - - -Power Supply Options -^^^^^^^^^^^^^^^^^^^^ - -There are three mutually exclusive ways to provide power to the board: - -- USB-to-UART Port and ESP32-S2 USB Port (either one or both), default power supply (recommended) -- 5V and G (GND) pins -- 3V3 and G (GND) pins - - -.. _user-guide-s2-devkitc-1-v1-header-blocks: - -Header Block ------------- - -The two tables below provide the **Name** and **Function** of the pin headers on both sides of the board (J1 and J3). The pin header names are shown in :ref:`user-guide-s2-devkitc-1-v1-board-front`. The numbering is the same as in the `ESP32-S2-DevKitC-1 Schematic`_ (PDF). - - -J1 -^^^ - -=== ========= ========== ========================================================================== -No. Name Type [#]_ Function -=== ========= ========== ========================================================================== -1 3V3 P 3.3 V power supply -2 3V3 P 3.3 V power supply -3 RST I CHIP_PU -4 4 I/O/T RTC_GPIO4, GPIO4, TOUCH4, ADC1_CH3 -5 5 I/O/T RTC_GPIO5, GPIO5, TOUCH5, ADC1_CH4 -6 6 I/O/T RTC_GPIO6, GPIO6, TOUCH6, ADC1_CH5 -7 7 I/O/T RTC_GPIO7, GPIO7, TOUCH7, ADC1_CH6 -8 15 I/O/T RTC_GPIO15, GPIO15, U0RTS, ADC2_CH4, XTAL_32K_P -9 16 I/O/T RTC_GPIO16, GPIO16, U0CTS, ADC2_CH5, XTAL_32K_N -10 17 I/O/T RTC_GPIO17, GPIO17, U1TXD, ADC2_CH6, DAC_1 -11 18 [#]_ I/O/T RTC_GPIO18, GPIO18, U1RXD, ADC2_CH7, DAC_2, CLK_OUT3, RGB LED -12 8 I/O/T RTC_GPIO8, GPIO8, TOUCH8, ADC1_CH7 -13 3 I/O/T RTC_GPIO3, GPIO3, TOUCH3, ADC1_CH2 -14 46 I GPIO46 -15 9 I/O/T RTC_GPIO9, GPIO9, TOUCH9, ADC1_CH8, FSPIHD -16 10 I/O/T RTC_GPIO10, GPIO10, TOUCH10, ADC1_CH9, FSPICS0, FSPIIO4 -17 11 I/O/T RTC_GPIO11, GPIO11, TOUCH11, ADC2_CH0, FSPID, FSPIIO5 -18 12 I/O/T RTC_GPIO12, GPIO12, TOUCH12, ADC2_CH1, FSPICLK, FSPIIO6 -19 13 I/O/T RTC_GPIO13, GPIO13, TOUCH13, ADC2_CH2, FSPIQ, FSPIIO7 -20 14 I/O/T RTC_GPIO14, GPIO14, TOUCH14, ADC2_CH3, FSPIWP, FSPIDQS -21 5V P 5 V power supply -22 G G Ground -=== ========= ========== ========================================================================== - - -J3 -^^^ - -=== ==== ===== ============================================================ -No. Name Type Function -=== ==== ===== ============================================================ -1 G G Ground -2 TX I/O/T U0TXD, GPIO43, CLK_OUT1 -3 RX I/O/T U0RXD, GPIO44, CLK_OUT2 -4 1 I/O/T RTC_GPIO1, GPIO1, TOUCH1, ADC1_CH0 -5 2 I/O/T RTC_GPIO2, GPIO2, TOUCH2, ADC1_CH1 -6 42 I/O/T MTMS, GPIO42 -7 41 I/O/T MTDI, GPIO41, CLK_OUT1 -8 40 I/O/T MTDO, GPIO40, CLK_OUT2 -9 39 I/O/T MTCK, GPIO39, CLK_OUT3 -10 38 I/O/T GPIO38, FSPIWP -11 37 I/O/T SPIDQS, GPIO37, FSPIQ -12 36 I/O/T SPIIO7, GPIO36, FSPICLK -13 35 I/O/T SPIIO6, GPIO35, FSPID -14 0 I/O/T RTC_GPIO0, GPIO0 -15 45 I/O/T GPIO45 -16 34 I/O/T SPIIO5, GPIO34, FSPICS0 -17 33 I/O/T SPIIO4, GPIO33, FSPIHD -18 21 I/O/T RTC_GPIO21, GPIO21 -19 20 I/O/T RTC_GPIO20, GPIO20, U1CTS, ADC2_CH9, CLK_OUT1, USB_D+ -20 19 I/O/T RTC_GPIO19, GPIO19, U1RTS, ADC2_CH8, CLK_OUT2, USB_D- -21 G G Ground -22 G G Ground -=== ==== ===== ============================================================ - -.. [#] P: Power supply; I: Input; O: Output; T: High impedance. -.. [#] GPIO18 is not pulled up on boards with an ESP32-S2-SOLO-2 or ESP32-S2-SOLO-2U module. - - -Pin Layout -^^^^^^^^^^ - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-S2-DevKitC-1 (click to enlarge) - :figclass: align-center - - ESP32-S2-DevKitC-1 Pin Layout (click to enlarge) - - -Hardware Revision Details -========================= - -This is the first revision of this board released. - - -Related Documents -================= - -* `ESP32-S2 Series Chip Revision v1.0 Datasheet`_ (PDF) -* `ESP32-S2 Series Chip Revision v0.0 Datasheet `_ (PDF) -* `ESP32-S2 Series SoC Errata`_ (PDF) -* `ESP32-S2-SOLO-2 & ESP32-S2-SOLO-2U Module Datasheet `_ (PDF) -* `ESP32-S2-SOLO & ESP32-S2-SOLO-U Module Datasheet `_ (PDF) -* `ESP32-S2-DevKitC-1 Schematic`_ (PDF) -* `ESP32-S2-DevKitC-1 PCB Layout `_ (PDF) -* `ESP32-S2-DevKitC-1 Dimensions `_ (PDF) -* `ESP32-S2-DevKitC-1 Dimensions source file `_ (DXF) - You can view it with `Autodesk Viewer `_ online - -For further design documentation for the board, please contact us at `sales@espressif.com `_. - -.. _NRND: https://www.espressif.com/en/products/longevity-commitment?id=nrnd -.. _ESP32-S2 Series Chip Revision v1.0 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s2-v1.0_datasheet_en.pdf -.. _ESP32-S2 Series SoC Errata: https://espressif.com/sites/default/files/documentation/esp32-s2_errata_en.pdf -.. _ESP32-S2-DevKitC-1 Schematic: https://dl.espressif.com/dl/schematics/esp-idf/SCH_ESP32-S2-DEVKITC-1_V1_20220817.pdf diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index 44c994e89c7..1a55c6f1cca 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -123,7 +123,7 @@ ESP32-S2-Saola-1 <../hw-reference/esp32s2/user-guide-saola-1-v1.2> ESP32-S2-DevKitM-1 - ESP32-S2-DevKitC-1 <../hw-reference/esp32s2/user-guide-s2-devkitc-1> + ESP32-S2-DevKitC-1 ESP32-S2-Kaluga-Kit <../hw-reference/esp32s2/user-guide-esp32-s2-kaluga-1-kit> .. only:: esp32c3 diff --git a/docs/zh_CN/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst b/docs/zh_CN/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst deleted file mode 100644 index 117a7a74252..00000000000 --- a/docs/zh_CN/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst +++ /dev/null @@ -1,313 +0,0 @@ -================== -ESP32-S2-DevKitC-1 -================== - -:link_to_translation:`en: [English]` - -本指南将帮助你快速上手 ESP32-S2-DevKitC-1,并提供该款开发板的详细信息。 - -ESP32-S2-DevKitC-1 是一款入门级开发板,具备完整的 Wi-Fi 功能。板上模组大部分管脚均已引出至两侧排针,开发人员可根据实际需求,轻松通过跳线连接多种外围设备,同时也可将开发板插在面包板上使用。 - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-isometric.png - :align: center - :alt: ESP32-S2-DevKitC-1(板载 ESP32-S2-SOLO 模组) - :figclass: align-center - - ESP32-S2-DevKitC-1(板载 ESP32-S2-SOLO 模组) - -本指南包括如下内容: - -- `入门指南`_:简要介绍了 ESP32-S2-DevKitC-1 和硬件、软件设置指南。 -- `硬件参考`_:详细介绍了 ESP32-S2-DevKitC-1 的硬件。 -- `硬件版本`_:介绍硬件历史版本和已知问题,并提供链接至历史版本开发板的入门指南(如有)。 -- `相关文档`_:列出了相关文档的链接。 - - -入门指南 -======== - -本小节将简要介绍 ESP32-S2-DevKitC-1,说明如何在 ESP32-S2-DevKitC-1 上烧录固件及相关准备工作。 - - -组件介绍 --------- - -.. _user-guide-s2-devkitc-1-v1-board-front: - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-annotated-photo.png - :align: center - :alt: ESP32-S2-DevKitC-1 - 正面 - :figclass: align-center - - ESP32-S2-DevKitC-1 - 正面 - -以下按照顺时针的顺序依次介绍开发板上的主要组件。 - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - 主要组件 - - 介绍 - * - 板载模组(上图中为 ESP32-S2-SOLO 或 ESP32-S2-SOLO-U) - - ESP32-S2-SOLO 系列模组,可搭载 PCB 板载天线或外部天线连接器,支持多种 flash 和 PSRAM 大小。更多信息,详见 :ref:`user-guide-s2-devkitc-1-v1-ordering-info`。 - * - 3.3 V Power On LED(3.3 V 电源指示灯) - - 开发板连接 USB 电源后,该指示灯亮起。 - * - USB-to-UART Bridge(USB 转 UART 桥接器) - - 单芯片 USB 转 UART 桥接器,可提供高达 3 Mbps 的传输速率。 - * - Pin Headers(排针) - - 所有可用 GPIO 管脚(除 flash 的 SPI 总线)均已引出至开发板的排针。请查看 :ref:`user-guide-s2-devkitc-1-v1-header-blocks` 获取更多信息。 - * - ESP32-S2 USB Port(ESP32-S2 USB 接口) - - ESP32-S2 USB OTG 接口,支持全速 USB 1.1 标准。该接口可用作开发板的供电接口,可烧录固件至芯片,也可通过 USB 协议与芯片通信。 - * - Reset Button(Reset 键) - - 复位按键。 - * - Boot Button(Boot 键) - - 下载按键。按住 **Boot** 键的同时按一下 **Reset** 键进入“固件下载”模式,通过串口下载固件。 - * - USB-to-UART Port(USB 转 UART 接口) - - Micro-USB 接口,可用作开发板的供电接口,可烧录固件至芯片,也可作为通信接口,通过板载 USB 转 UART 桥接器与 ESP32-S2 芯片通信。 - * - RGB LED - - 可寻址 RGB 发光二极管,由 GPIO18 驱动。 - * - 5 V to 3.3 V LDO(5 V 转 3.3 V LDO) - - 电源转换器,输入 5 V,输出 3.3 V。 - - -开始开发应用 ------------- - -通电前,请确保 ESP32-S2-DevKitC-1 完好无损。 - - -必备硬件 -^^^^^^^^ - -- ESP32-S2-DevKitC-1 -- USB 2.0 数据线(标准 A 型转 Micro-B 型) -- 电脑(Windows、Linux 或 macOS) - -.. 注解:: - - 请确保使用适当的 USB 数据线。部分数据线仅可用于充电,无法用于数据传输和编程。 - - -硬件设置 -^^^^^^^^ - -通过 **USB 转 UART 接口** 或 **ESP32-S2 USB 接口** 连接开发板与电脑。在后续步骤中,默认使用 **USB 转 UART 接口**。 - - -软件设置 -^^^^^^^^ - -请前往 `ESP-IDF 快速入门 `_,在 `详细安装步骤 `_ 小节查看如何快速设置开发环境,将应用程序烧录至 ESP32-S2-DevKitC-1。 - - -内含组件和包装 --------------- - -.. _user-guide-s2-devkitc-1-v1-ordering-info: - -订购信息 -^^^^^^^^ - -该开发板有多种型号可供选择,详见下表。 - -.. list-table:: - :header-rows: 1 - :widths: 35 25 10 10 20 - - * - 订购代码 - - 搭载模组 [#]_ - - Flash - - PSRAM - - 天线 - * - ESP32-S2-DevKitC-1-N8R2 - - ESP32-S2-SOLO-2 - - (推荐) - - 8 MB - - 2 MB - - PCB 板载天线 - * - ESP32-S2-DevKitC-1U-N8R2 - - ESP32-S2-SOLO-2U - - (推荐) - - 8 MB - - 2 MB - - 外部天线连接器 - * - ESP32-S2-DevKitC-1 - - ESP32-S2-SOLO - - 4 MB - - --- - - PCB 板载天线 - * - ESP32-S2-DevKitC-1U - - ESP32-S2-SOLO-U - - 4 MB - - --- - - 外部天线连接器 - * - ESP32-S2-DevKitC-1R - - ESP32-S2-SOLO - - 4 MB - - 2 MB - - PCB 板载天线 - * - ESP32-S2-DevKitC-1RU - - ESP32-S2-SOLO-U - - 4 MB - - 2 MB - - 外部天线连接器 - -.. [#] ESP32-S2-SOLO-2 和 ESP32-S2-SOLO-2U 模组使用 v1.0 版本芯片,其余模组使用 v0.0 版本芯片。更多关于芯片版本的信息,请参考 `《ESP32-S2 系列芯片勘误表》`_。 - - -零售订单 -^^^^^^^^ - -如购买样品,每个 ESP32-S2-DevKitC-1 将以防静电袋或零售商选择的其他方式包装。 - -零售订单请前往 https://www.espressif.com/zh-hans/company/contact/buy-a-sample。 - - -批量订单 -^^^^^^^^ - -如批量购买,ESP32-S2-DevKitC-1 将以大纸板箱包装。 - -批量订单请前往 https://www.espressif.com/zh-hans/contact-us/sales-questions。 - - -硬件参考 -======== - -功能框图 --------- - -ESP32-S2-DevKitC-1 的主要组件和连接方式如下图所示。 - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-block-diags.png - :align: center - :scale: 70% - :alt: ESP32-S2-DevKitC-1(点击放大) - :figclass: align-center - - ESP32-S2-DevKitC-1(点击放大) - - -电源选项 -^^^^^^^^ - -以下任一供电方式均可给 ESP32-S2-DevKitC-1 供电: - -- USB 转 UART 接口供电或 ESP32-S2 USB 接口供电(选择其一或同时供电),默认供电方式(推荐) -- 5V 和 G (GND) 排针供电 -- 3V3 和 G (GND) 排针供电 - - -.. _user-guide-s2-devkitc-1-v1-header-blocks: - -排针 ----- - -下表列出了开发板两侧排针(J1 和 J3)的 **名称** 和 **功能**,排针的名称如图 :ref:`user-guide-s2-devkitc-1-v1-board-front` 所示,排针的序号与 `ESP32-S2-DevKitC-1 原理图`_ (PDF) 一致。 - - -J1 -^^^ - -==== ========= ========= ========================================================================= -序号 名称 类型 [#]_ 功能 -==== ========= ========= ========================================================================= -1 3V3 P 3.3 V 电源 -2 3V3 P 3.3 V 电源 -3 RST I CHIP_PU -4 4 I/O/T RTC_GPIO4, GPIO4, TOUCH4, ADC1_CH3 -5 5 I/O/T RTC_GPIO5, GPIO5, TOUCH5, ADC1_CH4 -6 6 I/O/T RTC_GPIO6, GPIO6, TOUCH6, ADC1_CH5 -7 7 I/O/T RTC_GPIO7, GPIO7, TOUCH7, ADC1_CH6 -8 15 I/O/T RTC_GPIO15, GPIO15, U0RTS, ADC2_CH4, XTAL_32K_P -9 16 I/O/T RTC_GPIO16, GPIO16, U0CTS, ADC2_CH5, XTAL_32K_N -10 17 I/O/T RTC_GPIO17, GPIO17, U1TXD, ADC2_CH6, DAC_1 -11 18 [#]_ I/O/T RTC_GPIO18, GPIO18[#]_, U1RXD, ADC2_CH7, DAC_2, CLK_OUT3, RGB LED -12 8 I/O/T RTC_GPIO8, GPIO8, TOUCH8, ADC1_CH7 -13 3 I/O/T RTC_GPIO3, GPIO3, TOUCH3, ADC1_CH2 -14 46 I GPIO46 -15 9 I/O/T RTC_GPIO9, GPIO9, TOUCH9, ADC1_CH8, FSPIHD -16 10 I/O/T RTC_GPIO10, GPIO10, TOUCH10, ADC1_CH9, FSPICS0, FSPIIO4 -17 11 I/O/T RTC_GPIO11, GPIO11, TOUCH11, ADC2_CH0, FSPID, FSPIIO5 -18 12 I/O/T RTC_GPIO12, GPIO12, TOUCH12, ADC2_CH1, FSPICLK, FSPIIO6 -19 13 I/O/T RTC_GPIO13, GPIO13, TOUCH13, ADC2_CH2, FSPIQ, FSPIIO7 -20 14 I/O/T RTC_GPIO14, GPIO14, TOUCH14, ADC2_CH3, FSPIWP, FSPIDQS -21 5V P 5 V 电源 -22 G G 接地 -==== ========= ========= ========================================================================= - - -J3 -^^^ - -==== ==== ===== ================================================================ -序号 名称 类型 功能 -==== ==== ===== ================================================================ -1 G G 接地 -2 TX I/O/T U0TXD, GPIO43, CLK_OUT1 -3 RX I/O/T U0RXD, GPIO44, CLK_OUT2 -4 1 I/O/T RTC_GPIO1, GPIO1, TOUCH1, ADC1_CH0 -5 2 I/O/T RTC_GPIO2, GPIO2, TOUCH2, ADC1_CH1 -6 42 I/O/T MTMS, GPIO42 -7 41 I/O/T MTDI, GPIO41, CLK_OUT1 -8 40 I/O/T MTDO, GPIO40, CLK_OUT2 -9 39 I/O/T MTCK, GPIO39, CLK_OUT3 -10 38 I/O/T GPIO38, FSPIWP -11 37 I/O/T SPIDQS, GPIO37, FSPIQ -12 36 I/O/T SPIIO7, GPIO36, FSPICLK -13 35 I/O/T SPIIO6, GPIO35, FSPID -14 0 I/O/T RTC_GPIO0, GPIO0 -15 45 I/O/T GPIO45 -16 34 I/O/T SPIIO5, GPIO34, FSPICS0 -17 33 I/O/T SPIIO4, GPIO33, FSPIHD -18 21 I/O/T RTC_GPIO21, GPIO21 -19 20 I/O/T RTC_GPIO20, GPIO20, U1CTS, ADC2_CH9, CLK_OUT1, USB_D+ -20 19 I/O/T RTC_GPIO19, GPIO19, U1RTS, ADC2_CH8, CLK_OUT2, USB_D- -21 G G 接地 -22 G G 接地 -==== ==== ===== ================================================================ - -.. [#] P:电源;I:输入;O:输出;T:可设置为高阻。 -.. [#] 搭载 ESP32-S2-SOLO-2 或 ESP32-S2-SOLO-2U 的开发板未上拉 GPIO18。 - - -管脚布局 -^^^^^^^^ - -.. figure:: ../../../_static/esp32-s2-devkitc-1-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-S2-DevKitC-1 管脚布局(点击放大) - :figclass: align-center - - ESP32-S2-DevKitC-1 管脚布局(点击放大) - - -硬件版本 -========== - -无历史版本。 - - -相关文档 -======== - -* `ESP32-S2 系列芯片 v1.0 版本技术规格书`_ (PDF) -* `ESP32-S2 系列芯片 v0.0 版本技术规格书 `_ (PDF) -* `《ESP32-S2 系列芯片勘误表》`_ (PDF) -* `《ESP32-S2-SOLO-2 & ESP32-S2-SOLO-2U 模组技术规格书》 `_ (PDF) -* `《ESP32-S2-SOLO & ESP32-S2-SOLO-U 模组技术规格书》 `_ (PDF) -* `ESP32-S2-DevKitC-1 原理图`_ (PDF) -* `ESP32-S2-DevKitC-1 PCB 布局图 `_ (PDF) -* `ESP32-S2-DevKitC-1 尺寸图 `_ (PDF) -* `ESP32-S2-DevKitC-1 尺寸图源文件 `_ (DXF) - 可使用 `Autodesk Viewer `_ 查看 - -有关本开发板的更多设计文档,请联系我们的商务部门 `sales@espressif.com `_。 - -.. _不推荐用于新设计: https://www.espressif.com/zh-hans/products/longevity-commitment -.. _ESP32-S2 系列芯片 v1.0 版本技术规格书: https://www.espressif.com/sites/default/files/documentation/esp32-s2-v1.0_datasheet_cn.pdf -.. _《ESP32-S2 系列芯片勘误表》: https://espressif.com/sites/default/files/documentation/esp32-s2_errata_cn.pdf -.. _ESP32-S2-DevKitC-1 原理图: https://dl.espressif.com/dl/schematics/esp-idf/SCH_ESP32-S2-DEVKITC-1_V1_20220817.pdf From 34a7bc558e3cb584935045f88725bb5186e06921 Mon Sep 17 00:00:00 2001 From: zwx Date: Thu, 23 May 2024 16:02:15 +0800 Subject: [PATCH 455/548] feat(eth) configure eth mac using esp_read_mac * Closes https://github.com/espressif/esp-idf/issues/13808 --- .../protocol_examples_common/eth_connect.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/common_components/protocol_examples_common/eth_connect.c b/examples/common_components/protocol_examples_common/eth_connect.c index 74f3cb3b24c..8e89dbe28eb 100644 --- a/examples/common_components/protocol_examples_common/eth_connect.c +++ b/examples/common_components/protocol_examples_common/eth_connect.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -13,6 +13,7 @@ #include "driver/spi_master.h" #endif // CONFIG_ETH_USE_SPI_ETHERNET #include "esp_log.h" +#include "esp_mac.h" #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -153,11 +154,12 @@ static esp_netif_t *eth_start(void) ESP_ERROR_CHECK(esp_eth_driver_install(&config, &s_eth_handle)); #if !CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET /* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually. - 02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control. + We set the ESP_MAC_ETH mac address as the default, if you want to use ESP_MAC_EFUSE_CUSTOM mac address, please enable the + configuration: `ESP_MAC_USE_CUSTOM_MAC_AS_BASE_MAC` */ - ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) { - 0x02, 0x00, 0x00, 0x12, 0x34, 0x56 - })); + uint8_t eth_mac[6] = {0}; + ESP_ERROR_CHECK(esp_read_mac(eth_mac, ESP_MAC_ETH)); + ESP_ERROR_CHECK(esp_eth_ioctl(s_eth_handle, ETH_CMD_S_MAC_ADDR, eth_mac)); #endif // combine driver with netif s_eth_glue = esp_eth_new_netif_glue(s_eth_handle); From 371ae9577c4a13dd3b497e85c78bd6689450969c Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 28 May 2024 14:25:20 +0800 Subject: [PATCH 456/548] fix(uart): remove unnecessary wait when sending message to ring buffer --- components/esp_driver_uart/src/uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index 98a0b912e6d..b746a86c624 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -1396,7 +1396,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const void *src, size_t si static bool uart_check_buf_full(uart_port_t uart_num) { if (p_uart_obj[uart_num]->rx_buffer_full_flg) { - BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); + BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 0); if (res == pdTRUE) { UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; @@ -1510,7 +1510,7 @@ esp_err_t uart_flush_input(uart_port_t uart_num) UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); vRingbufferReturnItem(p_uart->rx_ring_buf, data); if (p_uart_obj[uart_num]->rx_buffer_full_flg) { - BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); + BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 0); if (res == pdTRUE) { UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; From 24de52e1106c98cce4e2e442771d0a6e3b614fee Mon Sep 17 00:00:00 2001 From: Shyamal Khachane Date: Thu, 25 Jul 2024 08:11:52 +0530 Subject: [PATCH 457/548] fix(esp_wifi): Handle PMKID mismatch or absence in OWE Compute keys incase PMKID does not match or PMKID is absent in association response --- components/wpa_supplicant/src/rsn_supp/wpa.c | 181 ++++++++++--------- 1 file changed, 95 insertions(+), 86 deletions(-) diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index 4e4e1893638..aef17fc9c0d 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -2868,7 +2868,8 @@ int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_i struct wpa_sm *sm; sm = get_wpa_sm(); - wpabuf_free(sm->owe_ie); //free the dh ie constructed in owe_build_assoc_req + /* Deallocate the dh ie buffer constructed in owe_build_assoc_req */ + wpabuf_free(sm->owe_ie); sm->owe_ie = NULL; struct wpa_ie_data *parsed_rsn_data; @@ -2882,121 +2883,129 @@ int owe_process_assoc_resp(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_i goto fail; } + if (!dh_ie && parsed_rsn_data->num_pmkid == 0) { + wpa_printf(MSG_ERROR, "OWE: Assoc response should either have pmkid or DH IE"); + goto fail; + } + + /* Check for PMK caching */ + if (sm->cur_pmksa && parsed_rsn_data && parsed_rsn_data->num_pmkid == 1 && parsed_rsn_data->pmkid) { + if (os_memcmp(parsed_rsn_data->pmkid, sm->cur_pmksa->pmkid, OWE_PMKID_LEN) == 0) { + wpa_printf(MSG_DEBUG, "OWE: Using PMK caching"); + wpa_sm_set_pmk_from_pmksa(sm); + goto done; + } else { + /* If PMKID mismatches, derive keys again */ + wpa_printf(MSG_DEBUG, "OWE : Invalid PMKID in response"); + } + } + + if (dh_ie == NULL) { + wpa_printf(MSG_ERROR, "OWE: No Diffie Hellman IE in association response"); + goto fail; + } if (dh_ie && MIN_DH_LEN(dh_len)) { wpa_printf(MSG_ERROR, "OWE: Invalid Diffie Hellman IE"); goto fail; } - if (!dh_ie && parsed_rsn_data->num_pmkid == 0) { - wpa_printf(MSG_ERROR, "OWE: Assoc response should either have pmkid or DH IE"); + + /* If STA or AP does not have PMKID, or PMKID mismatches, proceed with normal association */ + dh_len += 2; + + dh_ie += 3; + dh_len -=3; + group = WPA_GET_LE16(dh_ie); + + /* Only group 19 is supported */ + if ((group != sm->owe_group) || (group != OWE_DH_GRP19)) { + wpa_printf(MSG_ERROR, "OWE: Unexpected Diffie-Hellman group in response"); goto fail; } - if (!sm->cur_pmksa) { /* No PMK caching */ - if (dh_ie == NULL) { - goto fail; - } - dh_len += 2; + prime_len = OWE_PRIME_LEN; - dh_ie += 3; - dh_len -=3; - group = WPA_GET_LE16(dh_ie); + /* Set peer's public key point and calculate shared secret */ + sh_secret = crypto_ecdh_set_peerkey(sm->owe_ecdh, 0, dh_ie+2, dh_len-2); + sh_secret = wpabuf_zeropad(sh_secret, prime_len); + if (!sh_secret) { + wpa_printf(MSG_ERROR, "OWE: Invalid peer DH public key"); + goto fail; + } - /* Only group 19 is supported */ - if ((group != sm->owe_group) || (group != OWE_DH_GRP19)) { - wpa_printf(MSG_ERROR, "OWE: Unexpected Diffie-Hellman group in response"); - goto fail; - } + wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", sh_secret); + pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0); + if (!pub) { + wpa_printf(MSG_ERROR, "No own public key"); + goto fail; + } - prime_len = OWE_PRIME_LEN; + /* PMKID = Truncate-128(Hash(C | A)) */ + addr[0] = wpabuf_head(pub); + len[0] = wpabuf_len(pub); + addr[1] = dh_ie + 2; + len[1] = dh_len - 2; - /* Set peer's public key point and calculate shared secret */ - sh_secret = crypto_ecdh_set_peerkey(sm->owe_ecdh, 0, dh_ie+2, dh_len-2); - sh_secret = wpabuf_zeropad(sh_secret, prime_len); - if (!sh_secret) { - wpa_printf(MSG_ERROR, "OWE: Invalid peer DH public key"); - goto fail; - } + int res = sha256_vector(2, addr, len, pmkid); + if (res < 0 ) { + goto fail; + } - wpa_hexdump_buf_key(MSG_DEBUG, "OWE: DH shared secret", sh_secret); - pub = crypto_ecdh_get_pubkey(sm->owe_ecdh, 0); - if (!pub) { - wpa_printf(MSG_ERROR, "No own public key"); - wpabuf_free(sh_secret); - goto fail; - } + hash_len = SHA256_MAC_LEN; - /* PMKID = Truncate-128(Hash(C | A)) */ - addr[0] = wpabuf_head(pub); - len[0] = wpabuf_len(pub); - addr[1] = dh_ie + 2; - len[1] = dh_len - 2; + pub = wpabuf_zeropad(pub, prime_len); + if (!pub) { + goto fail; + } - int res = sha256_vector(2, addr, len, pmkid); - if (res < 0 ) { - goto fail; - } + /* prk = HKDF-extract(C | A | group, z) */ + hkey = wpabuf_alloc(wpabuf_len(pub) + dh_len - 2 + 2); + if (!hkey) { + goto fail; + } - hash_len = SHA256_MAC_LEN; + wpabuf_put_buf(hkey, pub); /* C */ + wpabuf_free(pub); - pub = wpabuf_zeropad(pub, prime_len); + wpabuf_put_data(hkey, dh_ie + 2, dh_len - 2); /* A */ + wpabuf_put_le16(hkey, sm->owe_group); /* group */ - /* prk = HKDF-extract(C | A | group, z) */ - hkey = wpabuf_alloc(wpabuf_len(pub) + dh_len - 2 + 2); + res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), wpabuf_head(sh_secret), wpabuf_len(sh_secret), prk); + if (res < 0 ) { + goto fail; + } - wpabuf_put_buf(hkey, pub); /* C */ - wpabuf_free(pub); + hash_len = SHA256_MAC_LEN; - wpabuf_put_data(hkey, dh_ie + 2, dh_len - 2); /* A */ - wpabuf_put_le16(hkey, sm->owe_group); /* group */ + wpabuf_free(hkey); + wpabuf_clear_free(sh_secret); - res = hmac_sha256(wpabuf_head(hkey), wpabuf_len(hkey), wpabuf_head(sh_secret), wpabuf_len(sh_secret), prk); - if (res < 0 ) { - goto fail; - } + wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len); - hash_len = SHA256_MAC_LEN; + /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */ + res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *)info, + os_strlen(info), pmk, hash_len); + if (res < 0 ) { + goto fail; + } - wpabuf_free(hkey); - wpabuf_free(sh_secret); + forced_memzero(prk, SHA256_MAC_LEN); + wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, OWE_PMKID_LEN); - wpa_hexdump_key(MSG_DEBUG, "OWE: prk", prk, hash_len); + os_memcpy(sm->pmk,pmk,hash_len); + sm->pmk_len = hash_len; + wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len); - /* PMK = HKDF-expand(prk, "OWE Key Generation", n) */ - res = hmac_sha256_kdf(prk, hash_len, NULL, (const u8 *)info, - os_strlen(info), pmk, hash_len); - if (res < 0 ) { - goto fail; - } + pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, pmkid, NULL, 0, + sm->bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt); - forced_memzero(prk, SHA256_MAC_LEN); - wpa_hexdump(MSG_DEBUG, "OWE: PMKID", pmkid, OWE_PMKID_LEN); - - os_memcpy(sm->pmk,pmk,hash_len); - sm->pmk_len = hash_len; - wpa_hexdump_key(MSG_DEBUG, "OWE: PMK", sm->pmk, sm->pmk_len); - - pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len, pmkid, NULL, 0, - sm->bssid, sm->own_addr, sm->network_ctx, sm->key_mgmt); - goto done; - } else { /* PMK caching */ - if (parsed_rsn_data && sm->cur_pmksa) { - if (parsed_rsn_data->num_pmkid == 1 && parsed_rsn_data->pmkid) { - if (os_memcmp(parsed_rsn_data->pmkid, sm->cur_pmksa->pmkid, OWE_PMKID_LEN) == 0) { - wpa_printf(MSG_DEBUG, "OWE: Using PMK caching"); - wpa_sm_set_pmk_from_pmksa(sm); - goto done; - } else { - wpa_printf(MSG_DEBUG, "OWE : Invalid PMKID in response"); - goto fail; - } - } - } - } done: os_free(parsed_rsn_data); return 0; fail: os_free(parsed_rsn_data); + wpabuf_free(pub); + wpabuf_free(hkey); + wpabuf_clear_free(sh_secret); return -1; } #endif // CONFIG_OWE_STA From 81cdaa3aceae0c143721f88ac977a0442ef0f7c1 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 15 Jul 2024 15:32:22 +0800 Subject: [PATCH 458/548] fix(bt/controller): Removed an improper assertion in ACL link driver It can be triggered on peripheral SNIFF mode when RX window is adjusted on ESP32. --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 1d3d9bfd298..b814f26bbb3 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 1d3d9bfd298ed3b6916d561dc54317041841ec9e +Subproject commit b814f26bbb3d726418c0f80f9f91153dfd978f85 From dce5170cdb67f8618e42b407ebd00661bf9b765d Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Wed, 17 Jul 2024 14:32:35 +0800 Subject: [PATCH 459/548] fix(riscv): fix a that affected mintstatus CSR value in the CLIC --- .../include/esp_private/interrupt_clic.h | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/components/riscv/include/esp_private/interrupt_clic.h b/components/riscv/include/esp_private/interrupt_clic.h index 4089ef8abc8..095cff6af2f 100644 --- a/components/riscv/include/esp_private/interrupt_clic.h +++ b/components/riscv/include/esp_private/interrupt_clic.h @@ -79,20 +79,32 @@ extern "C" { /* Align the level to the left, and put 1 in the lowest bits */ #define NLBITS_TO_BYTE(level) (((level) << NLBITS_SHIFT) | ((1 << NLBITS_SHIFT) - 1)) +/** + * @brief In the minstatus CSR, the `mil` field is present from bit 24 to bit 31 (included) + */ +#define MINTSTATUS_MIL_S 24 +#define MINTSTATUS_MIL_V 0xFF + #if INTTHRESH_STANDARD -/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ -#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel)) + /* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ + #define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel)) -/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ -#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel))) + /* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ + #define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel))) + + /* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */ + #define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V)) #else -/* For the non-standard intthresh implementation the threshold is stored in the upper 8 bits of CLIC_CPU_INT_THRESH reg */ -/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ -#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel) << CLIC_CPU_INT_THRESH_S) + /* For the non-standard intthresh implementation the threshold is stored in the upper 8 bits of CLIC_CPU_INT_THRESH reg */ + /* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */ + #define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel) << CLIC_CPU_INT_THRESH_S) + + /* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ + #define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel >> CLIC_CPU_INT_THRESH_S) & CLIC_CPU_INT_THRESH_V)) -/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */ -#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel >> CLIC_CPU_INT_THRESH_S) & CLIC_CPU_INT_THRESH_V)) + /* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */ + #define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V)) #endif //INTTHRESH_STANDARD /* Helper macro to set interrupt level RVHAL_EXCM_LEVEL. Used during critical sections */ @@ -151,7 +163,7 @@ FORCE_INLINE_ATTR uint32_t rv_utils_get_interrupt_level(void) { const uint32_t mintstatus = RV_READ_CSR(MINTSTATUS_CSR); /* Extract the level from this field */ - return CLIC_THRESH_TO_INT(mintstatus); + return CLIC_STATUS_TO_INT(mintstatus); } /** From 01086e0307815f9bfc719cad96162e057315b7c9 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 18 Jul 2024 16:46:29 +0530 Subject: [PATCH 460/548] fix(nimble): Add host callback to provide security key --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 46ae5865554..9372de75dee 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 46ae5865554f2fd7df829b6b9b5ca24522b9ad76 +Subproject commit 9372de75deea015234e6b1d51dd63356a3c88683 From d2e4722f5b34ae18845d3b69b52ac4d3e5b3e1c5 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Wed, 24 Jul 2024 16:56:17 +0200 Subject: [PATCH 461/548] fix(freertos): Incorrect assert in FreeRTOS port layer when not in ISR context This commit fixes an issue where in the FreeRTOS port layer would cause the portASSERT_IF_IN_ISR() assert check to fail even when the system is not in an interrupt context. --- .../riscv/include/freertos/portmacro.h | 16 ++++++++++++++++ .../FreeRTOS-Kernel-SMP/portable/riscv/port.c | 10 ++++++++-- .../xtensa/include/freertos/portmacro.h | 15 +++++++++++++++ .../portable/xtensa/port.c | 10 ++++++++-- .../riscv/include/freertos/portmacro.h | 12 ++++++++++++ .../FreeRTOS-Kernel/portable/riscv/port.c | 6 ++++++ .../xtensa/include/freertos/portmacro.h | 8 ++++---- .../FreeRTOS-Kernel/portable/xtensa/port.c | 9 +++++---- .../port/test_freertos_isinisrcontext.c | 19 ++++++++++++++++++- .../test_apps/freertos/pytest_freertos.py | 10 ++++++++++ 10 files changed, 102 insertions(+), 13 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h index 7ffcb5e6d4e..ba635dcfeef 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h @@ -113,6 +113,13 @@ typedef spinlock_t portMUX_TYPE; /**< Spi BaseType_t xPortCheckIfInISR(void); +/** + * @brief Assert if in ISR context + * + * - Asserts on xPortCheckIfInISR() internally + */ +void vPortAssertIfInISR(void); + // ------------------ Critical Sections -------------------- #if ( configNUMBER_OF_CORES > 1 ) @@ -187,6 +194,15 @@ void vPortTCBPreDeleteHook( void *pxTCB ); #define portENABLE_INTERRUPTS() vPortClearInterruptMask(1) #define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x) +/** + * @brief Assert if in ISR context + * + * TODO: Enable once ISR safe version of vTaskEnter/ExitCritical() is implemented + * for single-core SMP FreeRTOS Kernel. (IDF-10540) + */ +// #define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + + // ------------------ Critical Sections -------------------- #if ( configNUMBER_OF_CORES > 1 ) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index ea2e46c41d5..955587ba427 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -168,6 +168,12 @@ BaseType_t xPortCheckIfInISR(void) return uxInterruptNesting; } +void vPortAssertIfInISR(void) +{ + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortCheckIfInISR() == 0); +} + // ------------------ Critical Sections -------------------- #if ( configNUMBER_OF_CORES > 1 ) @@ -373,7 +379,7 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters) { - __asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (inital) frame + __asm__ volatile(".cfi_undefined ra"); // tell to debugger that it's outermost (initial) frame extern void __attribute__((noreturn)) panic_abort(const char *details); static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0"; pxCode(pvParameters); @@ -440,7 +446,7 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC HIGH ADDRESS |---------------------------| <- pxTopOfStack on entry | TLS Variables | - | ------------------------- | <- Start of useable stack + | ------------------------- | <- Start of usable stack | Starting stack frame | | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP) | | | diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h index 2e87cd39f9c..422ad609774 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h @@ -95,6 +95,13 @@ typedef spinlock_t portMUX_TYPE; /**< Spi BaseType_t xPortCheckIfInISR(void); +/** + * @brief Assert if in ISR context + * + * - Asserts on xPortCheckIfInISR() internally + */ +void vPortAssertIfInISR(void); + // ------------------ Critical Sections -------------------- UBaseType_t uxPortEnterCriticalFromISR( void ); @@ -161,6 +168,14 @@ void vPortTCBPreDeleteHook( void *pxTCB ); #define portSET_INTERRUPT_MASK_FROM_ISR() portSET_INTERRUPT_MASK() #define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK() +/** + * @brief Assert if in ISR context + * + * TODO: Enable once ISR safe version of vTaskEnter/ExitCritical() is implemented + * for single-core SMP FreeRTOS Kernel. (IDF-10540) + */ +// #define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + /* Note: XTOS_RESTORE_INTLEVEL() will overwrite entire PS register on XEA2. So we need to set the value of the INTLEVEL field ourselves */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index d5010bf708d..4cd6918472f 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -139,7 +139,7 @@ BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *lock, BaseType_t timeout) void vPortExitCriticalIDF(portMUX_TYPE *lock) { /* This function may be called in a nested manner. Therefore, we only need - * to reenable interrupts if this is the last call to exit the critical. We + * to re-enable interrupts if this is the last call to exit the critical. We * can use the nesting count to determine whether this is the last exit call. */ spinlock_release(lock); @@ -204,6 +204,12 @@ BaseType_t xPortCheckIfInISR(void) return ret; } +void vPortAssertIfInISR(void) +{ + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortCheckIfInISR() == 0); +} + // ------------------ Critical Sections -------------------- #if ( configNUMBER_OF_CORES > 1 ) @@ -614,7 +620,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, | Coproc Save Area | (CPSA MUST BE FIRST) | ------------------------- | | TLS Variables | - | ------------------------- | <- Start of useable stack + | ------------------------- | <- Start of usable stack | Starting stack frame | | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP) | | | diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h index 5df719405c4..f1b0257d544 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/include/freertos/portmacro.h @@ -166,6 +166,13 @@ void vPortClearInterruptMaskFromISR(UBaseType_t prev_int_level); */ BaseType_t xPortInIsrContext(void); +/** + * @brief Assert if in ISR context + * + * - Asserts on xPortInIsrContext() internally + */ +void vPortAssertIfInISR(void); + /** * @brief Check if in ISR context from High priority ISRs * @@ -478,6 +485,11 @@ void vPortTCBPreDeleteHook( void *pxTCB ); #define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR() #define portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level) vPortClearInterruptMaskFromISR(prev_level) +/** + * @brief Assert if in ISR context + */ +#define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + /** * @brief Used by FreeRTOS functions to call the correct version of critical section API */ diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 068668e9657..29cc3fe0963 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -462,6 +462,12 @@ BaseType_t xPortInIsrContext(void) #endif /* (configNUM_CORES > 1) */ } +void vPortAssertIfInISR(void) +{ + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortInIsrContext() == 0); +} + BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) { /* Return the interrupt nesting counter for this core */ diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h index 109bea6d28b..14091c9c052 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/include/freertos/portmacro.h @@ -141,12 +141,9 @@ typedef uint32_t TickType_t; BaseType_t xPortInIsrContext(void); /** - * @brief Asserts if in ISR context + * @brief Assert if in ISR context * * - Asserts on xPortInIsrContext() internally - * - * @note [refactor-todo] Check if this API is still required - * @note [refactor-todo] Check if this should be inlined */ void vPortAssertIfInISR(void); @@ -427,6 +424,9 @@ void vPortTCBPreDeleteHook( void *pxTCB ); #define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR() #define portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level) vPortClearInterruptMaskFromISR(prev_level) +/** + * @brief Assert if in ISR context + */ #define portASSERT_IF_IN_ISR() vPortAssertIfInISR() /** diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index e1cba7ab3e6..9722a2c3087 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -8,7 +8,7 @@ * * SPDX-License-Identifier: MIT * - * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2023-2024 Espressif Systems (Shanghai) CO LTD * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -395,7 +395,7 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, | Coproc Save Area | (CPSA MUST BE FIRST) | ------------------------- | | TLS Variables | - | ------------------------- | <- Start of useable stack + | ------------------------- | <- Start of usable stack | Starting stack frame | | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP) | | | @@ -449,7 +449,8 @@ BaseType_t xPortInIsrContext(void) void vPortAssertIfInISR(void) { - configASSERT(xPortInIsrContext()); + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortInIsrContext() == 0); } BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) @@ -489,7 +490,7 @@ BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TY void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) { /* This function may be called in a nested manner. Therefore, we only need - * to reenable interrupts if this is the last call to exit the critical. We + * to re-enable interrupts if this is the last call to exit the critical. We * can use the nesting count to determine whether this is the last exit call. */ spinlock_release(mux); diff --git a/components/freertos/test_apps/freertos/port/test_freertos_isinisrcontext.c b/components/freertos/test_apps/freertos/port/test_freertos_isinisrcontext.c index b3b90552b7b..3c0446f5a75 100644 --- a/components/freertos/test_apps/freertos/port/test_freertos_isinisrcontext.c +++ b/components/freertos/test_apps/freertos/port/test_freertos_isinisrcontext.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,3 +58,20 @@ TEST_CASE("xPortInIsrContext test", "[freertos]") } #endif + +#if !CONFIG_FREERTOS_SMP // TODO: Enable when IDF-10540 is fixed + +static void testint_assert(void) +{ + esp_rom_printf("INT!\n"); + portASSERT_IF_IN_ISR(); +} + +TEST_CASE("port must assert if in ISR context", "[ignore]") +{ + esp_err_t err = esp_register_freertos_tick_hook_for_cpu(testint_assert, xPortGetCoreID()); + TEST_ASSERT_EQUAL_HEX32(ESP_OK, err); + vTaskDelay(100 / portTICK_PERIOD_MS); + esp_deregister_freertos_tick_hook_for_cpu(testint_assert, xPortGetCoreID()); +} +#endif // !CONFIG_FREERTOS_SMP diff --git a/components/freertos/test_apps/freertos/pytest_freertos.py b/components/freertos/test_apps/freertos/pytest_freertos.py index 6baa6ba7811..d21d9dad708 100644 --- a/components/freertos/test_apps/freertos/pytest_freertos.py +++ b/components/freertos/test_apps/freertos/pytest_freertos.py @@ -39,3 +39,13 @@ def test_task_notify_wait_too_high_index_fails(dut: Dut) -> None: dut.expect('assert failed: xTaskGenericNotifyWait', timeout=5) dut.expect('uxIndexToWait < [0-9]+', timeout=5) dut.expect_exact('Rebooting...') + + +@pytest.mark.supported_targets +@pytest.mark.generic +@pytest.mark.parametrize('config', ['default'], indirect=True) +def test_port_must_assert_in_isr(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests.') + dut.write('\"port must assert if in ISR context\"') + dut.expect('assert failed: vPortAssertIfInISR', timeout=5) + dut.expect_exact('Rebooting...') From 3469d50a8b48897aae3c1291333f5c511bb7352a Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Fri, 26 Jul 2024 09:38:40 +0530 Subject: [PATCH 462/548] fix(nimble): Zero initialize variable to avoid garbage value --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 9372de75dee..c0363f26cf6 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 9372de75deea015234e6b1d51dd63356a3c88683 +Subproject commit c0363f26cf6484830779292035fe309c1ec0eb94 From 917bcc2cd8b5fecbc14c2eace916b84a709b9ff5 Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Fri, 5 Jul 2024 19:24:53 +0800 Subject: [PATCH 463/548] fix(bt/nimble): split hci log in nimble --- .../host/nimble/esp-hci/src/esp_nimble_hci.c | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c index 605b831211c..49d976865e7 100644 --- a/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c +++ b/components/bt/host/nimble/esp-hci/src/esp_nimble_hci.c @@ -21,6 +21,8 @@ #include "freertos/semphr.h" #include "esp_compiler.h" #include "soc/soc_caps.h" +#include "bt_common.h" +#include "hci_log/bt_hci_log.h" #define NIMBLE_VHCI_TIMEOUT_MS 2000 #define BLE_HCI_EVENT_HDR_LEN (2) @@ -61,6 +63,13 @@ void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, ble_hci_rx_acl_hs_arg = acl_arg; } +void esp_vhci_host_send_packet_wrapper(uint8_t *data, uint16_t len) +{ +#if (BT_HCI_LOG_INCLUDED == TRUE) + bt_hci_log_record_hci_data(data[0], &data[1], len - 1); +#endif + esp_vhci_host_send_packet(data, len); +} int ble_hci_trans_hs_cmd_tx(uint8_t *cmd) { @@ -75,7 +84,7 @@ int ble_hci_trans_hs_cmd_tx(uint8_t *cmd) } if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { - esp_vhci_host_send_packet(cmd, len); + esp_vhci_host_send_packet_wrapper(cmd, len); } else { rc = BLE_HS_ETIMEOUT_HCI; } @@ -112,7 +121,7 @@ int ble_hci_trans_hs_acl_tx(struct os_mbuf *om) len += OS_MBUF_PKTLEN(om); if (xSemaphoreTake(vhci_send_sem, NIMBLE_VHCI_TIMEOUT_MS / portTICK_PERIOD_MS) == pdTRUE) { - esp_vhci_host_send_packet(data, len); + esp_vhci_host_send_packet_wrapper(data, len); } else { rc = BLE_HS_ETIMEOUT_HCI; } @@ -181,11 +190,26 @@ static void controller_rcv_pkt_ready(void) } } +void bt_record_hci_data(uint8_t *data, uint16_t len) +{ +#if (BT_HCI_LOG_INCLUDED == TRUE) + if ((data[0] == BLE_HCI_UART_H4_EVT) && (data[1] == BLE_HCI_EVCODE_LE_META) && ((data[3] == BLE_HCI_LE_SUBEV_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) + || (data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) || (data[3] == BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT))) { + bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &data[2], len - 2); + } else { + uint8_t data_type = ((data[0] == 2) ? HCI_LOG_DATA_TYPE_C2H_ACL : data[0]); + bt_hci_log_record_hci_data(data_type, &data[1], len - 1); + } +#endif // (BT_HCI_LOG_INCLUDED == TRUE) +} + /* * @brief: BT controller callback function, to transfer data packet to the host */ static int host_rcv_pkt(uint8_t *data, uint16_t len) { + bt_record_hci_data(data, len); + if(!ble_hs_enabled_state) { /* If host is not enabled, drop the packet */ ESP_LOGE(TAG, "Host not enabled. Dropping the packet!"); From 21b861e9dff135931e017812c0dbcb67a0403978 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 26 Jul 2024 11:02:06 +0800 Subject: [PATCH 464/548] change(psram): improved xip psram docs on p4 --- components/esp_psram/esp32p4/Kconfig.spiram | 9 +++++++-- docs/en/api-guides/external-ram.rst | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/components/esp_psram/esp32p4/Kconfig.spiram b/components/esp_psram/esp32p4/Kconfig.spiram index b83d0acefde..f17fb795eec 100644 --- a/components/esp_psram/esp32p4/Kconfig.spiram +++ b/components/esp_psram/esp32p4/Kconfig.spiram @@ -57,7 +57,7 @@ menu "PSRAM config" PSRAM config SPIRAM_XIP_FROM_PSRAM - bool "Enable Executable in place from (XiP) from PSRAM feature" + bool "Enable Executable in place from (XiP) from PSRAM feature (READ HELP)" default n select SPIRAM_FETCH_INSTRUCTIONS select SPIRAM_RODATA @@ -70,7 +70,12 @@ menu "PSRAM config" does not have to be placed in IRAM. Therefore codes that need to be executing during Flash operations can continue working normally. - Enabling this option will have better performance (see External RAM documentation for more details). + Because P4 flash and PSRAM are using two separate SPI buses, moving flash content to PSRAM will + actually increase the load of the PSRAM MSPI bus, so the exact impact on performance will be dependent + on your app usage of PSRAM. For example, as the PSRAM bus speed could be much faster than flash bus speed, + if the instructions and data that are used to be in flash are not accessed very frequently, you might + get better performance with this option enabled. We suggest doing performance profiling to determine + if enabling this option. config SPIRAM_FLASH_LOAD_TO_PSRAM bool diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index e0f779f78a5..d9d7e905921 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -184,8 +184,7 @@ Remaining external RAM can also be added to the capability heap allocator using The :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` option enables the executable in place (XiP) from PSRAM feature. With this option sections that are normally placed in flash ,``.text`` (for instructions) and ``.rodata`` (for read only data), will be loaded in PSRAM. - With this option enabled, the cache will not be disabled during an SPI1 flash operation, so code that requires executing during an SPI1 Flash operation does not have to be placed in internal RAM. Because P4 Flash and PSRAM are using two separate SPI buses, moving Flash content to PSRAM will actually increase the load of the PSRAM MSPI bus, so the access speed is relatively slower. The exact impact on performance will be very dependent on your apps usage of PSRAM, and we suggest doing performance profiling to determine if enabling this option will significantly impact your app's performance. - + With this option enabled, the cache will not be disabled during an SPI1 flash operation, so code that requires executing during an SPI1 flash operation does not have to be placed in internal RAM. Because P4 flash and PSRAM are using two separate SPI buses, moving flash content to PSRAM will actually increase the load of the PSRAM MSPI bus, so the exact impact on performance will be dependent on your app usage of PSRAM. For example, as the PSRAM bus speed could be much faster than flash bus speed, if the instructions and data that are used to be in flash are not accessed very frequently, you might get better performance with this option enabled. We suggest doing performance profiling to determine if enabling this option. Restrictions ============ From e8660cd99d8f2a031ee28d187ecb9e8d3ecfa267 Mon Sep 17 00:00:00 2001 From: zwx Date: Mon, 24 Jun 2024 15:39:34 +0800 Subject: [PATCH 465/548] fix(ieee802154): refactor the next opteration logic for multiple events --- .../ieee802154/driver/esp_ieee802154_dev.c | 139 ++++++++++++------ .../ieee802154/include/esp_ieee802154.h | 11 +- .../private_include/esp_ieee802154_dev.h | 2 + 3 files changed, 103 insertions(+), 49 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index c5371814796..d893cceef6e 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -63,6 +63,8 @@ static uint8_t *s_tx_frame = NULL; static uint8_t s_rx_frame[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1][IEEE802154_RX_FRAME_SIZE]; static esp_ieee802154_frame_info_t s_rx_frame_info[CONFIG_IEEE802154_RX_BUFFER_SIZE + 1]; +static bool s_needs_next_operation = false; + static uint8_t s_rx_index = 0; static uint8_t s_enh_ack_frame[128]; static uint8_t s_recent_rx_frame_info_index; @@ -71,7 +73,7 @@ static intr_handle_t s_ieee802154_isr_handle = NULL; static esp_err_t ieee802154_sleep_init(void); static esp_err_t ieee802154_sleep_deinit(void); -static void next_operation(void); +#define NEEDS_NEXT_OPT(a) do {s_needs_next_operation = a;} while(0) static esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca); #if !CONFIG_IEEE802154_TEST @@ -355,6 +357,8 @@ static IRAM_ATTR void next_operation(void) if (s_pending_tx.frame) { // Here the driver needs to recover the setting of rx aborts, see function `ieee802154_transmit`. ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); + // Clear the RX abort event again for avoiding the risk if there are still some rx abort events created after last isr process. + ieee802154_ll_clear_events(IEEE802154_EVENT_RX_ABORT); ieee802154_transmit_internal(s_pending_tx.frame, s_pending_tx.cca); s_pending_tx.frame = NULL; } else @@ -376,7 +380,7 @@ static void isr_handle_timer0_done(void) #if !CONFIG_IEEE802154_TEST if (s_ieee802154_state == IEEE802154_STATE_RX_ACK) { esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); - next_operation(); + NEEDS_NEXT_OPT(true); } #else esp_ieee802154_timer0_done(); @@ -394,23 +398,19 @@ static void isr_handle_timer1_done(void) static IRAM_ATTR void isr_handle_tx_done(void) { event_end_process(); - if (s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { - ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); - } else { - if (s_ieee802154_state == IEEE802154_STATE_TEST_TX) { - ieee802154_transmit_done(s_tx_frame, NULL, NULL); - next_operation(); - } else if (s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA) { - if (ieee802154_frame_is_ack_required(s_tx_frame) && ieee802154_ll_get_rx_auto_ack()) { - ieee802154_set_state(IEEE802154_STATE_RX_ACK); + if (s_ieee802154_state == IEEE802154_STATE_TEST_TX) { + ieee802154_transmit_done(s_tx_frame, NULL, NULL); + NEEDS_NEXT_OPT(true); + } else if (s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA) { + if (ieee802154_frame_is_ack_required(s_tx_frame) && ieee802154_ll_get_rx_auto_ack()) { + ieee802154_set_state(IEEE802154_STATE_RX_ACK); #if !CONFIG_IEEE802154_TEST - receive_ack_timeout_timer_start(200000); // 200ms for receive ack timeout + receive_ack_timeout_timer_start(200000); // 200ms for receive ack timeout #endif - } else { - ieee802154_transmit_done(s_tx_frame, NULL, NULL); - next_operation(); - } + NEEDS_NEXT_OPT(false); + } else { + ieee802154_transmit_done(s_tx_frame, NULL, NULL); + NEEDS_NEXT_OPT(true); } } } @@ -426,6 +426,7 @@ static IRAM_ATTR void isr_handle_rx_done(void) // auto tx ack only works for the frame with version 0b00 and 0b01 s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]); ieee802154_set_state(IEEE802154_STATE_TX_ACK); + NEEDS_NEXT_OPT(false); } else if (ieee802154_frame_is_ack_required(s_rx_frame[s_rx_index]) && ieee802154_frame_get_version(s_rx_frame[s_rx_index]) == IEEE802154_FRAME_VERSION_2 && ieee802154_ll_get_tx_enhance_ack()) { s_rx_frame_info[s_rx_index].pending = ieee802154_ack_config_pending_bit(s_rx_frame[s_rx_index]); @@ -439,15 +440,16 @@ static IRAM_ATTR void isr_handle_rx_done(void) ieee802154_ll_enhack_generate_done_notify(); ieee802154_set_state(IEEE802154_STATE_TX_ENH_ACK); #endif + NEEDS_NEXT_OPT(false); } else { // Stop current process if generator returns errors. ieee802154_set_cmd(IEEE802154_CMD_STOP); ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); + NEEDS_NEXT_OPT(true); } } else { ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); + NEEDS_NEXT_OPT(true); } } } @@ -455,7 +457,7 @@ static IRAM_ATTR void isr_handle_rx_done(void) static IRAM_ATTR void isr_handle_ack_tx_done(void) { ieee802154_receive_done((uint8_t *)s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); + NEEDS_NEXT_OPT(true); } static IRAM_ATTR void isr_handle_ack_rx_done(void) @@ -464,10 +466,10 @@ static IRAM_ATTR void isr_handle_ack_rx_done(void) ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); ieee802154_rx_frame_info_update(); ieee802154_transmit_done(s_tx_frame, (uint8_t *)&s_rx_frame[s_rx_index], &s_rx_frame_info[s_rx_index]); - next_operation(); + NEEDS_NEXT_OPT(true); } -static IRAM_ATTR void isr_handle_rx_abort(void) +static IRAM_ATTR void isr_handle_rx_phase_rx_abort(void) { event_end_process(); uint32_t rx_status = ieee802154_ll_get_rx_status(); @@ -485,11 +487,6 @@ static IRAM_ATTR void isr_handle_rx_abort(void) case IEEE802154_RX_ABORT_BY_NO_RSS: case IEEE802154_RX_ABORT_BY_UNEXPECTED_ACK: case IEEE802154_RX_ABORT_BY_RX_RESTART: - IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); -#if CONFIG_IEEE802154_TEST - esp_ieee802154_receive_failed(rx_status); -#endif - break; case IEEE802154_RX_ABORT_BY_COEX_BREAK: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX); #if CONFIG_IEEE802154_TEST @@ -502,6 +499,38 @@ static IRAM_ATTR void isr_handle_rx_abort(void) esp_ieee802154_ed_failed(rx_status); break; case IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT: + case IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK: + case IEEE802154_RX_ABORT_BY_ENHACK_SECURITY_ERROR: + return; + default: + IEEE802154_ASSERT(false); + } + NEEDS_NEXT_OPT(true); +} + +static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(void) +{ + event_end_process(); +#if CONFIG_IEEE802154_TEST + uint32_t rx_status = ieee802154_ll_get_rx_status(); +#endif + ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason(); + switch (rx_abort_reason) { + case IEEE802154_RX_ABORT_BY_RX_STOP: + case IEEE802154_RX_ABORT_BY_TX_ACK_STOP: + case IEEE802154_RX_ABORT_BY_ED_STOP: + case IEEE802154_RX_ABORT_BY_SFD_TIMEOUT: + case IEEE802154_RX_ABORT_BY_CRC_ERROR: + case IEEE802154_RX_ABORT_BY_INVALID_LEN: + case IEEE802154_RX_ABORT_BY_FILTER_FAIL: + case IEEE802154_RX_ABORT_BY_NO_RSS: + case IEEE802154_RX_ABORT_BY_UNEXPECTED_ACK: + case IEEE802154_RX_ABORT_BY_RX_RESTART: + case IEEE802154_RX_ABORT_BY_COEX_BREAK: + case IEEE802154_RX_ABORT_BY_ED_ABORT: + case IEEE802154_RX_ABORT_BY_ED_COEX_REJECT: + return; + case IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT: case IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); #if !CONFIG_IEEE802154_TEST @@ -521,7 +550,7 @@ static IRAM_ATTR void isr_handle_rx_abort(void) default: IEEE802154_ASSERT(false); } - next_operation(); + NEEDS_NEXT_OPT(true); } static IRAM_ATTR void isr_handle_tx_abort(void) @@ -543,12 +572,14 @@ static IRAM_ATTR void isr_handle_tx_abort(void) case IEEE802154_TX_ABORT_BY_RX_ACK_RESTART: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_INVALID_ACK); + NEEDS_NEXT_OPT(false); break; + // The above events are only used in test mode. case IEEE802154_TX_ABORT_BY_RX_ACK_TIMEOUT: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX_ACK); ieee802154_ll_disable_events(IEEE802154_EVENT_TIMER0_OVERFLOW); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_NO_ACK); - next_operation(); + NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_TX_COEX_BREAK: #if CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE @@ -557,22 +588,22 @@ static IRAM_ATTR void isr_handle_tx_abort(void) IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); IEEE802154_TX_BREAK_COEX_NUMS_UPDATE(); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_COEXIST); - next_operation(); + NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_TX_SECURITY_ERROR: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_SECURITY); - next_operation(); + NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_CCA_FAILED: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_ABORT); - next_operation(); + NEEDS_NEXT_OPT(true); break; case IEEE802154_TX_ABORT_BY_CCA_BUSY: IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX_CCA); esp_ieee802154_transmit_failed(s_tx_frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); - next_operation(); + NEEDS_NEXT_OPT(true); break; default: IEEE802154_ASSERT(false); @@ -588,17 +619,33 @@ static IRAM_ATTR void isr_handle_ed_done(void) esp_ieee802154_energy_detect_done(ieee802154_ll_get_ed_rss()); } - next_operation(); + NEEDS_NEXT_OPT(true); +} + +IEEE802154_STATIC IRAM_ATTR void ieee802154_enter_critical(void) +{ + portENTER_CRITICAL(&s_ieee802154_spinlock); +} + +IEEE802154_STATIC IRAM_ATTR void ieee802154_exit_critical(void) +{ + portEXIT_CRITICAL(&s_ieee802154_spinlock); } static void ieee802154_isr(void *arg) { + ieee802154_enter_critical(); ieee802154_ll_events events = ieee802154_ll_get_events(); IEEE802154_PROBE(events); ieee802154_ll_clear_events(events); + if (events & IEEE802154_EVENT_RX_ABORT) { + // First phase rx abort process, will clear RX_ABORT event in second. + isr_handle_rx_phase_rx_abort(); + } + if (events & IEEE802154_EVENT_RX_SFD_DONE) { // IEEE802154_STATE_TX && IEEE802154_STATE_TX_CCA && IEEE802154_STATE_TX_ENH_ACK for isr processing delay IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_RX || s_ieee802154_state == IEEE802154_STATE_RX_ACK || s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); @@ -619,7 +666,7 @@ static void ieee802154_isr(void *arg) } if (events & IEEE802154_EVENT_TX_DONE) { - IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TEST_TX || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK); + IEEE802154_ASSERT(s_ieee802154_state == IEEE802154_STATE_TX || s_ieee802154_state == IEEE802154_STATE_TX_CCA || s_ieee802154_state == IEEE802154_STATE_TEST_TX); isr_handle_tx_done(); @@ -653,8 +700,8 @@ static void ieee802154_isr(void *arg) } if (events & IEEE802154_EVENT_RX_ABORT) { - isr_handle_rx_abort(); - + // Second phase rx abort process, clears RX_ABORT event. + isr_handle_tx_ack_phase_rx_abort(); events &= (uint16_t)(~IEEE802154_EVENT_RX_ABORT); } @@ -689,20 +736,14 @@ static void ieee802154_isr(void *arg) events &= (uint16_t)(~IEEE802154_EVENT_TIMER1_OVERFLOW); } + if (s_needs_next_operation) { + next_operation(); + s_needs_next_operation = false; + } // all events should be handled IEEE802154_ASSERT(events == 0); - -} - -IEEE802154_STATIC IRAM_ATTR void ieee802154_enter_critical(void) -{ - portENTER_CRITICAL(&s_ieee802154_spinlock); -} - -IEEE802154_STATIC IRAM_ATTR void ieee802154_exit_critical(void) -{ - portEXIT_CRITICAL(&s_ieee802154_spinlock); + ieee802154_exit_critical(); } void ieee802154_enable(void) @@ -816,6 +857,7 @@ static inline esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) { + ESP_RETURN_ON_FALSE(frame[0] <= 127, ESP_ERR_INVALID_ARG, IEEE802154_TAG, "Invalid frame length."); #if !CONFIG_IEEE802154_TEST ieee802154_enter_critical(); if ((s_ieee802154_state == IEEE802154_STATE_RX && ieee802154_ll_is_current_rx_frame()) @@ -844,6 +886,7 @@ static inline bool is_target_time_expired(uint32_t target, uint32_t now) esp_err_t ieee802154_transmit_at(const uint8_t *frame, bool cca, uint32_t time) { + ESP_RETURN_ON_FALSE(frame[0] <= 127, ESP_ERR_INVALID_ARG, IEEE802154_TAG, "Invalid frame length."); uint32_t tx_target_time; uint32_t current_time; IEEE802154_RF_ENABLE(); diff --git a/components/ieee802154/include/esp_ieee802154.h b/components/ieee802154/include/esp_ieee802154.h index 27db5ca49b2..51adf6ce00b 100644 --- a/components/ieee802154/include/esp_ieee802154.h +++ b/components/ieee802154/include/esp_ieee802154.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -136,8 +136,12 @@ esp_err_t esp_ieee802154_receive(void); * |-----------------------------------------------------------------------| * @param[in] cca Perform CCA before transmission if it's true, otherwise transmit the frame directly. * + * @note During transmission, the hardware calculates the FCS, and send it over the air right after the MAC payload, + * so you just need to prepare the length, mac header and mac payload content. + * * @return * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. * - ESP_FAIL on failure due to invalid state. * */ @@ -477,6 +481,10 @@ esp_err_t esp_ieee802154_receive_handle_done(const uint8_t *frame); * |-----------------------------------------------------------------------| * @param[in] frame_info More information of the received frame, refer to esp_ieee802154_frame_info_t. * + * @note During receiving, the hardware calculates the FCS of the received frame, and may drop it if the FCS doesn't match, only the valid + * frames will be received and notified by esp_ieee802154_receive_done(). Please note that the FCS field is replaced by RSSI and LQI + * value of the received frame. + * */ extern void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info); @@ -547,6 +555,7 @@ esp_err_t esp_ieee802154_receive_at(uint32_t time); * * @return * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. * - ESP_FAIL on failure due to invalid state. * */ diff --git a/components/ieee802154/private_include/esp_ieee802154_dev.h b/components/ieee802154/private_include/esp_ieee802154_dev.h index ace28cd5f78..9eddc87a3ff 100644 --- a/components/ieee802154/private_include/esp_ieee802154_dev.h +++ b/components/ieee802154/private_include/esp_ieee802154_dev.h @@ -93,6 +93,7 @@ esp_err_t ieee802154_mac_deinit(void); * * @return * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. * - ESP_FAIL on failure due to invalid state. * */ @@ -130,6 +131,7 @@ esp_err_t ieee802154_receive_handle_done(const uint8_t* frame); * * @return * - ESP_OK on success. + * - ESP_ERR_INVALID_ARG on an invalid frame. * - ESP_FAIL on failure due to invalid state. * * Note: The transmit result will be reported via esp_ieee802154_transmit_done() From 0417d48a9dd22b988efcefa59335862f03c47a7b Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 1 Jul 2024 17:11:33 +0800 Subject: [PATCH 466/548] feat(mipi_dsi): update low level functions to include underrun interrupt --- components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 29 ++++----- components/esp_lcd/dsi/mipi_dsi_priv.h | 5 +- .../mipi_dsi_lcd/main/test_mipi_dsi_panel.c | 6 +- .../hal/esp32p4/include/hal/mipi_dsi_brg_ll.h | 59 ++++++++++++++++++- components/soc/esp32p4/include/soc/reg_base.h | 2 + 5 files changed, 78 insertions(+), 23 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index e3d0e8a8b93..e4fcdc7e543 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -32,12 +32,12 @@ struct esp_lcd_dpi_panel_t { esp_lcd_panel_t base; // Base class of generic lcd panel esp_lcd_dsi_bus_handle_t bus; // DSI bus handle uint8_t virtual_channel; // Virtual channel ID, index from 0 - uint8_t cur_fb_index; // Current frame buffer index - uint8_t num_fbs; // Number of frame buffers + uint8_t cur_fb_index; // Current frame buffer index + uint8_t num_fbs; // Number of frame buffers uint8_t *fbs[DPI_PANEL_MAX_FB_NUM]; // Frame buffers uint32_t h_pixels; // Horizontal pixels uint32_t v_pixels; // Vertical pixels - size_t frame_buffer_size; // Frame buffer size + size_t fb_size; // Frame buffer size, in bytes size_t bits_per_pixel; // Bits per pixel lcd_color_rgb_pixel_format_t pixel_format; // RGB Pixel format dw_gdma_channel_handle_t dma_chan; // DMA channel @@ -126,7 +126,7 @@ static esp_err_t dpi_panel_create_dma_link(esp_lcd_dpi_panel_t *dpi_panel) // create DMA link lists dw_gdma_link_list_config_t link_list_config = { - .num_items = DPI_PANEL_LLI_PER_FRAME, + .num_items = DPI_PANEL_MIN_DMA_NODES_PER_LINK, .link_type = DW_GDMA_LINKED_LIST_TYPE_SINGLY, }; for (int i = 0; i < dpi_panel->num_fbs; i++) { @@ -191,21 +191,21 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); // DMA doesn't have requirement on the buffer alignment, but the cache does uint32_t alignment = cache_line_size; - size_t frame_buffer_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8; + size_t fb_size = panel_config->video_timing.h_size * panel_config->video_timing.v_size * bits_per_pixel / 8; uint8_t *frame_buffer = NULL; for (int i = 0; i < num_fbs; i++) { - frame_buffer = heap_caps_aligned_calloc(alignment, 1, frame_buffer_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + frame_buffer = heap_caps_aligned_calloc(alignment, 1, fb_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(frame_buffer, ESP_ERR_NO_MEM, err, TAG, "no memory for frame buffer"); dpi_panel->fbs[i] = frame_buffer; ESP_LOGD(TAG, "fb[%d] @%p", i, frame_buffer); // preset the frame buffer with black color // the frame buffer address alignment is ensured by `heap_caps_aligned_calloc` - // while the value of the frame_buffer_size may not be aligned to the cache line size + // while the value of the fb_size may not be aligned to the cache line size // but that's not a problem because the `heap_caps_aligned_calloc` internally allocated a buffer whose size is aligned up to the cache line size - ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), + ESP_GOTO_ON_ERROR(esp_cache_msync(frame_buffer, fb_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), err, TAG, "cache write back failed"); } - dpi_panel->frame_buffer_size = frame_buffer_size; + dpi_panel->fb_size = fb_size; dpi_panel->bits_per_pixel = bits_per_pixel; dpi_panel->h_pixels = panel_config->video_timing.h_size; dpi_panel->v_pixels = panel_config->video_timing.v_size; @@ -282,6 +282,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ mipi_dsi_brg_ll_set_underrun_discard_count(hal->bridge, panel_config->video_timing.h_size); // use the DW_GDMA as the flow controller mipi_dsi_brg_ll_set_flow_controller(hal->bridge, MIPI_DSI_LL_FLOW_CONTROLLER_DMA); + mipi_dsi_brg_ll_set_multi_block_number(hal->bridge, DPI_PANEL_MIN_DMA_NODES_PER_LINK); mipi_dsi_brg_ll_set_burst_len(hal->bridge, 256); mipi_dsi_brg_ll_set_empty_threshold(hal->bridge, 1024 - 256); // enable DSI bridge @@ -381,7 +382,7 @@ static esp_err_t dpi_panel_init(esp_lcd_panel_t *panel) .burst_len = 16, .width = DW_GDMA_TRANS_WIDTH_64, }, - .size = dpi_panel->frame_buffer_size * 8 / 64, + .size = dpi_panel->fb_size * 8 / 64, }; for (int i = 0; i < dpi_panel->num_fbs; i++) { link_list = dpi_panel->link_lists[i]; @@ -419,7 +420,7 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int uint8_t cur_fb_index = dpi_panel->cur_fb_index; uint8_t *frame_buffer = dpi_panel->fbs[cur_fb_index]; uint8_t *draw_buffer = (uint8_t *)color_data; - size_t frame_buffer_size = dpi_panel->frame_buffer_size; + size_t fb_size = dpi_panel->fb_size; size_t bits_per_pixel = dpi_panel->bits_per_pixel; // clip to boundaries @@ -434,11 +435,11 @@ static esp_err_t dpi_panel_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int uint8_t draw_buf_fb_index = 0; // check if the user draw buffer resides in any frame buffer's memory range // if so, we don't need to copy the data, just do cache write back - if (draw_buffer >= dpi_panel->fbs[0] && draw_buffer < dpi_panel->fbs[0] + frame_buffer_size) { + if (draw_buffer >= dpi_panel->fbs[0] && draw_buffer < dpi_panel->fbs[0] + fb_size) { draw_buf_fb_index = 0; - } else if (draw_buffer >= dpi_panel->fbs[1] && draw_buffer < dpi_panel->fbs[1] + frame_buffer_size) { + } else if (draw_buffer >= dpi_panel->fbs[1] && draw_buffer < dpi_panel->fbs[1] + fb_size) { draw_buf_fb_index = 1; - } else if (draw_buffer >= dpi_panel->fbs[2] && draw_buffer < dpi_panel->fbs[2] + frame_buffer_size) { + } else if (draw_buffer >= dpi_panel->fbs[2] && draw_buffer < dpi_panel->fbs[2] + fb_size) { draw_buf_fb_index = 2; } else { do_copy = true; diff --git a/components/esp_lcd/dsi/mipi_dsi_priv.h b/components/esp_lcd/dsi/mipi_dsi_priv.h index eebf93e2e89..bb6fd2fe63c 100644 --- a/components/esp_lcd/dsi/mipi_dsi_priv.h +++ b/components/esp_lcd/dsi/mipi_dsi_priv.h @@ -29,9 +29,8 @@ #define DSI_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT #endif -#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of supported frame buffers for DPI panel - -#define DPI_PANEL_LLI_PER_FRAME 1 // NOTE: we assume ONE DMA link item can carry the WHOLE image (1920*1080) +#define DPI_PANEL_MAX_FB_NUM 3 // maximum number of frame buffers that can be maintained by the driver +#define DPI_PANEL_MIN_DMA_NODES_PER_LINK 1 // NOTE: we assume 1 DMA link item can carry the WHOLE image #ifdef __cplusplus extern "C" { diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c index eec61a14b7f..a31d26e01fd 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_panel.c @@ -222,16 +222,16 @@ TEST_CASE("MIPI DSI with multiple frame buffers (ILI9881C)", "[mipi_dsi]") uint16_t *fbs[3]; TEST_ESP_OK(esp_lcd_dpi_panel_get_frame_buffer(mipi_dpi_panel, 3, (void **)&fbs[0], (void **)&fbs[1], (void **)&fbs[2])); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 9; i++) { uint16_t color_byte = rand() & 0xFFFF; int x_start = rand() % (MIPI_DSI_LCD_H_RES - 100); int y_start = rand() % (MIPI_DSI_LCD_V_RES - 100); for (int j = y_start; j < y_start + 100; j++) { for (int k = x_start; k < x_start + 100; k++) { - fbs[i][j * MIPI_DSI_LCD_H_RES + k] = color_byte; + fbs[i % 3][j * MIPI_DSI_LCD_H_RES + k] = color_byte; } } - esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, fbs[i]); + esp_lcd_panel_draw_bitmap(mipi_dpi_panel, x_start, y_start, x_start + 100, y_start + 100, fbs[i % 3]); vTaskDelay(pdMS_TO_TICKS(1000)); } diff --git a/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h b/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h index 7c399550bbc..adfdacad701 100644 --- a/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h +++ b/components/hal/esp32p4/include/hal/mipi_dsi_brg_ll.h @@ -14,6 +14,7 @@ #include "hal/lcd_types.h" #define MIPI_DSI_LL_GET_BRG(bus_id) (bus_id == 0 ? &MIPI_DSI_BRIDGE : NULL) +#define MIPI_DSI_LL_EVENT_UNDERRUN (1 << 0) #ifdef __cplusplus extern "C" { @@ -35,6 +36,46 @@ static inline void mipi_dsi_brg_ll_enable(dsi_brg_dev_t *dev, bool en) dev->en.dsi_en = en; } +/** + * @brief Enable DSI bridge interrupt for specific event mask + * + * @param dev Pointer to the DSI bridge controller register base address + * @param mask Event mask + * @param enable True to enable, False to disable + */ +static inline void mipi_dsi_brg_ll_enable_interrupt(dsi_brg_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +/** + * @brief Clear DSI bridge interrupt for specific event mask + * + * @param dev Pointer to the DSI bridge controller register base address + * @param mask Event mask + */ +__attribute__((always_inline)) +static inline void mipi_dsi_brg_ll_clear_interrupt_status(dsi_brg_dev_t *dev, uint32_t mask) +{ + dev->int_clr.val = mask; +} + +/** + * @brief Get interrupt status for DSI bridge + * + * @param dev Pointer to the DSI bridge controller register base address + * @return Interrupt status + */ +__attribute__((always_inline)) +static inline uint32_t mipi_dsi_brg_ll_get_interrupt_status(dsi_brg_dev_t *dev) +{ + return dev->int_st.val; +} + /** * @brief Set the number of 64-bit words in one dma burst transfer * @@ -242,7 +283,7 @@ static inline void mipi_dsi_brg_ll_enable_ref_clock(dsi_brg_dev_t *dev, bool en) * @param dev Pointer to the DSI bridge controller register base address * @param controller Flow controller */ -static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t* dev, mipi_dsi_ll_flow_controller_t controller) +static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t *dev, mipi_dsi_ll_flow_controller_t controller) { dev->dma_flow_ctrl.dsi_dma_flow_controller = controller; } @@ -255,9 +296,21 @@ static inline void mipi_dsi_brg_ll_set_flow_controller(dsi_brg_dev_t* dev, mipi_ * @param dev Pointer to the DSI bridge controller register base address * @param number Number of blocks */ -static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t* dev, uint32_t number) +static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t *dev, uint32_t number) { dev->dma_flow_ctrl.dma_flow_multiblk_num = number; + dev->dma_frame_interval.dma_multiblk_en = number > 1; +} + +/** + * @brief Get the FIFO depth of the DSI bridge + * + * @param dev Pointer to the DSI bridge controller register base address + * @return FIFO depth + */ +static inline uint32_t mipi_dsi_brg_ll_get_fifo_depth(dsi_brg_dev_t *dev) +{ + return dev->fifo_flow_status.raw_buf_depth; } /** @@ -266,7 +319,7 @@ static inline void mipi_dsi_brg_ll_set_multi_block_number(dsi_brg_dev_t* dev, ui * @param dev Pointer to the DSI bridge controller register base address * @param std YUV-RGB conversion standard */ -static inline void mipi_dsi_brg_ll_set_yuv_convert_std(dsi_brg_dev_t* dev, lcd_yuv_conv_std_t std) +static inline void mipi_dsi_brg_ll_set_yuv_convert_std(dsi_brg_dev_t *dev, lcd_yuv_conv_std_t std) { switch (std) { case LCD_YUV_CONV_STD_BT601: diff --git a/components/soc/esp32p4/include/soc/reg_base.h b/components/soc/esp32p4/include/soc/reg_base.h index 4c2bbc2c7eb..9a4b6fc0654 100644 --- a/components/soc/esp32p4/include/soc/reg_base.h +++ b/components/soc/esp32p4/include/soc/reg_base.h @@ -59,7 +59,9 @@ #define DR_REG_DDRPHY_BASE (DR_REG_HPPERIPH0_BASE + 0x9D000) #define DR_REG_PVT_BASE (DR_REG_HPPERIPH0_BASE + 0x9E000) #define DR_REG_CSI_HOST_BASE (DR_REG_HPPERIPH0_BASE + 0x9F000) +#define DR_REG_CSI_BRG_BASE (DR_REG_HPPERIPH0_BASE + 0x9F800) #define DR_REG_DSI_HOST_BASE (DR_REG_HPPERIPH0_BASE + 0xA0000) +#define DR_REG_DSI_BRG_BASE (DR_REG_HPPERIPH0_BASE + 0xA0800) #define DR_REG_ISP_BASE (DR_REG_HPPERIPH0_BASE + 0xA1000) #define DR_REG_RMT_BASE (DR_REG_HPPERIPH0_BASE + 0xA2000) #define DR_REG_BITSCRAM_BASE (DR_REG_HPPERIPH0_BASE + 0xA3000) From 10d68e943a395ca0099c65497d25461bd65d4f13 Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 13 Jun 2024 11:54:38 +0800 Subject: [PATCH 467/548] feat(psram): support APS3204L --- components/esp_psram/esp32s3/esp_psram_impl_quad.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esp_psram/esp32s3/esp_psram_impl_quad.c b/components/esp_psram/esp32s3/esp_psram_impl_quad.c index 12a428d3d77..3496a90bc5f 100644 --- a/components/esp_psram/esp32s3/esp_psram_impl_quad.c +++ b/components/esp_psram/esp32s3/esp_psram_impl_quad.c @@ -62,6 +62,7 @@ static const char* TAG = "quad_psram"; #define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD) #define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID(id) == 0x26) +#define PSRAM_IS_2T_APS3204(id) ((((id) >> 21) && 0xfffff) == 1) // IO-pins for PSRAM. // WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines @@ -327,6 +328,8 @@ esp_err_t esp_psram_impl_enable(void) //psram init if (PSRAM_IS_64MBIT_TRIAL(s_psram_id)) { s_psram_size = PSRAM_SIZE_8MB; + } else if (PSRAM_IS_2T_APS3204(s_psram_id)) { + s_psram_size = PSRAM_SIZE_4MB; } else { uint8_t density = PSRAM_SIZE_ID(s_psram_id); s_psram_size = density == 0x0 ? PSRAM_SIZE_2MB : From a0dbe28c9f30f54582a56f139fddf571d93062a4 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Thu, 13 Jun 2024 11:34:13 +0800 Subject: [PATCH 468/548] refactor(usb-serial-jtag): usb-serial-jtag driver simplification to fix rom print coexistence --- .../src/usb_serial_jtag.c | 155 +++++++----------- .../src/usb_serial_jtag_vfs.c | 9 +- 2 files changed, 68 insertions(+), 96 deletions(-) diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c index 790aed174cf..bf96f06d014 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c @@ -19,35 +19,31 @@ #include "esp_check.h" #include "esp_private/periph_ctrl.h" +/* + Note: Before you add a workaround for an issue in this driver, please please try + to figure out the actual root cause first. The USB-serial-JTAG is a simple device, + it shouldn't need anything more than a simple, straightforward driver. +*/ + #if !SOC_RCC_IS_INDEPENDENT #define USJ_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define USJ_RCC_ATOMIC() #endif -typedef enum { - FIFO_IDLE = 0, /*!< Indicates the fifo is in idle state */ - FIFO_BUSY = 1, /*!< Indicates the fifo is in busy state */ -} fifo_status_t; - -// The hardware buffer max size is 64 +// The hardware buffer max size is 64, both for RX and TX. #define USB_SER_JTAG_ENDP_SIZE (64) -#define USB_SER_JTAG_RX_MAX_SIZE (64) +#define USB_SER_JTAG_RX_MAX_SIZE (USB_SER_JTAG_ENDP_SIZE) typedef struct { intr_handle_t intr_handle; /*!< USB-SERIAL-JTAG interrupt handler */ - portMUX_TYPE spinlock; /*!< Spinlock for usb_serial_jtag */ - _Atomic fifo_status_t fifo_status; /*!< Record the status of fifo */ // RX parameters RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler */ - uint32_t rx_buf_size; /*!< TX buffer size */ - uint8_t rx_data_buf[USB_SER_JTAG_ENDP_SIZE]; /*!< Data buffer to stash FIFO data */ // TX parameters - uint32_t tx_buf_size; /*!< TX buffer size */ RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler */ - uint8_t tx_data_buf[USB_SER_JTAG_ENDP_SIZE]; /*!< Data buffer to stash TX FIFO data */ + uint8_t tx_stash_buf[USB_SER_JTAG_ENDP_SIZE]; /*!< Data buffer to stash TX FIFO data */ size_t tx_stash_cnt; /*!< Number of stashed TX FIFO bytes */ } usb_serial_jtag_obj_t; @@ -55,13 +51,6 @@ static usb_serial_jtag_obj_t *p_usb_serial_jtag_obj = NULL; static const char* USB_SERIAL_JTAG_TAG = "usb_serial_jtag"; -static size_t usb_serial_jtag_write_and_flush(const uint8_t *buf, uint32_t wr_len) -{ - size_t size = usb_serial_jtag_ll_write_txfifo(buf, wr_len); - usb_serial_jtag_ll_txfifo_flush(); - return size; -} - static void usb_serial_jtag_isr_handler_default(void *arg) { BaseType_t xTaskWoken = 0; @@ -69,77 +58,70 @@ static void usb_serial_jtag_isr_handler_default(void *arg) usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY) { + //Clear interrupt so we won't be called until the next transfer finishes. + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); + // Interrupt tells us the host picked up the data we sent. // If we have more data, we can put it in the buffer and the host will pick that up next. - // Send data in isr. - // If the hardware fifo is available, write in it. Otherwise, do nothing. + // We expect the TX FIFO to be writable for this. If it's not, somehow someone else + // (ROM print routines?) have snuck in a full buffer before we got here. In that case, + // we simply ignore the interrupt, a new one will come if the buffer is empty again. if (usb_serial_jtag_ll_txfifo_writable() == 1) { - // We disable the interrupt here so that the interrupt won't be triggered if there is no data to send. - + // Retrieve data from either the stash buffer or, if that's empty, from the ring buffer. size_t queued_size; - uint8_t *queued_buff = NULL; - bool is_stashed_data = false; + uint8_t *queued_buf = NULL; if (p_usb_serial_jtag_obj->tx_stash_cnt != 0) { // Send stashed tx bytes before reading bytes from ring buffer - queued_buff = p_usb_serial_jtag_obj->tx_data_buf; + queued_buf = p_usb_serial_jtag_obj->tx_stash_buf; queued_size = p_usb_serial_jtag_obj->tx_stash_cnt; - is_stashed_data = true; } else { // Max 64 data payload size in a single EndPoint - queued_buff = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, USB_SER_JTAG_ENDP_SIZE); + queued_buf = (uint8_t *)xRingbufferReceiveUpToFromISR(p_usb_serial_jtag_obj->tx_ring_buf, &queued_size, USB_SER_JTAG_ENDP_SIZE); } - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); - - if (queued_buff != NULL) { - - // Although tx_queued_bytes may be larger than 0, we may have - // interrupted before xRingbufferSend() was called. - // Copy the queued buffer into the TX FIFO - - // On ringbuffer wrap-around the size can be 0 even though the buffer returned is not NULL - if (queued_size > 0) { - portENTER_CRITICAL_ISR(&p_usb_serial_jtag_obj->spinlock); - atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_BUSY); - uint32_t sent_size = usb_serial_jtag_write_and_flush(queued_buff, queued_size); - portEXIT_CRITICAL_ISR(&p_usb_serial_jtag_obj->spinlock); - - if (sent_size < queued_size) { - // Not all bytes could be sent at once; stash the unwritten bytes in a tx buffer - // stash_size will not larger than USB_SER_JTAG_ENDP_SIZE because queued_size is got from xRingbufferReceiveUpToFromISR - size_t stash_size = queued_size - sent_size; - memcpy(p_usb_serial_jtag_obj->tx_data_buf, &queued_buff[sent_size], stash_size); - p_usb_serial_jtag_obj->tx_stash_cnt = stash_size; - } else { - p_usb_serial_jtag_obj->tx_stash_cnt = 0; - // assert if sent_size is larger than queued_size. - assert(sent_size <= queued_size); - } + if (queued_buf != NULL && queued_size > 0) { + // We have some data to send. Send it. + uint32_t sent_size = usb_serial_jtag_ll_write_txfifo(queued_buf, queued_size); + usb_serial_jtag_ll_txfifo_flush(); + + // Check if we were able to send everything. + if (sent_size < queued_size) { + // Not all bytes could be sent at once; stash the unwritten bytes in a buffer + // This will happen if e.g. the rom output functions manage to sneak a few bytes into the + // TX FIFO before this interrupt triggers. Note stash_size will not larger than + // USB_SER_JTAG_ENDP_SIZE because queued_size is obtained from xRingbufferReceiveUpToFromISR. + size_t stash_size = queued_size - sent_size; + memcpy(p_usb_serial_jtag_obj->tx_stash_buf, &queued_buf[sent_size], stash_size); + p_usb_serial_jtag_obj->tx_stash_cnt = stash_size; + } else { + p_usb_serial_jtag_obj->tx_stash_cnt = 0; } - if (is_stashed_data == false) { - vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buff, &xTaskWoken); + // Return the buffer if we got it from the ring buffer. + if (queued_buf != p_usb_serial_jtag_obj->tx_stash_buf) { + vRingbufferReturnItemFromISR(p_usb_serial_jtag_obj->tx_ring_buf, queued_buf, &xTaskWoken); } } else { + // No data to send. // The last transmit may have sent a full EP worth of data. The host will interpret // this as a transaction that hasn't finished yet and keep the data in its internal // buffers rather than releasing it to the program listening on the CDC serial port. // We need to flush again in order to send a 0-byte packet that ends the transaction. usb_serial_jtag_ll_txfifo_flush(); - // Note that since this doesn't re-enable USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY, the - // flush will not by itself cause this ISR to be called again. + + // We will also disable the interrupt as for now there's no need to handle the + // TX interrupt again. We'll re-enable this externally if we need data sent. + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } - } else { - atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE); - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); } } if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { - // read rx buffer(max length is 64), and send available data to ringbuffer. - // Ensure the rx buffer size is larger than RX_MAX_SIZE. + // Acknowledge interrupt usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); - uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(p_usb_serial_jtag_obj->rx_data_buf, USB_SER_JTAG_RX_MAX_SIZE); - xRingbufferSendFromISR(p_usb_serial_jtag_obj->rx_ring_buf, p_usb_serial_jtag_obj->rx_data_buf, rx_fifo_len, &xTaskWoken); + // Read RX FIFO and send available data to ringbuffer. + uint8_t buf[USB_SER_JTAG_RX_MAX_SIZE]; + uint32_t rx_fifo_len = usb_serial_jtag_ll_read_rxfifo(buf, USB_SER_JTAG_RX_MAX_SIZE); + xRingbufferSendFromISR(p_usb_serial_jtag_obj->rx_ring_buf, buf, rx_fifo_len, &xTaskWoken); } if (xTaskWoken == pdTRUE) { @@ -155,17 +137,15 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se ESP_RETURN_ON_FALSE((usb_serial_jtag_config->rx_buffer_size > USB_SER_JTAG_RX_MAX_SIZE), ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "RX buffer prepared is so small, should larger than 64"); ESP_RETURN_ON_FALSE((usb_serial_jtag_config->tx_buffer_size > 0), ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "TX buffer is not prepared"); p_usb_serial_jtag_obj = (usb_serial_jtag_obj_t*) heap_caps_calloc(1, sizeof(usb_serial_jtag_obj_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - p_usb_serial_jtag_obj->rx_buf_size = usb_serial_jtag_config->rx_buffer_size; - p_usb_serial_jtag_obj->tx_buf_size = usb_serial_jtag_config->tx_buffer_size; p_usb_serial_jtag_obj->tx_stash_cnt = 0; - p_usb_serial_jtag_obj->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; if (p_usb_serial_jtag_obj == NULL) { ESP_LOGE(USB_SERIAL_JTAG_TAG, "memory allocate error"); - err = ESP_ERR_NO_MEM; - goto _exit; + // no `goto _exit` here as there's nothing to clean up and that would make the uninstall + // routine unhappy. + return ESP_ERR_NO_MEM; } - p_usb_serial_jtag_obj->rx_ring_buf = xRingbufferCreate(p_usb_serial_jtag_obj->rx_buf_size, RINGBUF_TYPE_BYTEBUF); + p_usb_serial_jtag_obj->rx_ring_buf = xRingbufferCreate(usb_serial_jtag_config->rx_buffer_size, RINGBUF_TYPE_BYTEBUF); if (p_usb_serial_jtag_obj->rx_ring_buf == NULL) { ESP_LOGE(USB_SERIAL_JTAG_TAG, "ringbuffer create error"); err = ESP_ERR_NO_MEM; @@ -183,7 +163,6 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se USJ_RCC_ATOMIC() { usb_serial_jtag_ll_enable_bus_clock(true); } - atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE); // Configure PHY #if USB_SERIAL_JTAG_LL_EXT_PHY_SUPPORTED @@ -242,37 +221,29 @@ int usb_serial_jtag_write_bytes(const void* src, size_t size, TickType_t ticks_t ESP_RETURN_ON_FALSE(src != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "Invalid buffer pointer."); ESP_RETURN_ON_FALSE(p_usb_serial_jtag_obj != NULL, ESP_ERR_INVALID_ARG, USB_SERIAL_JTAG_TAG, "The driver hasn't been initialized"); - size_t sent_data = 0; BaseType_t result = pdTRUE; - const uint8_t *buff = (const uint8_t *)src; - if (p_usb_serial_jtag_obj->fifo_status == FIFO_IDLE) { - portENTER_CRITICAL(&p_usb_serial_jtag_obj->spinlock); - atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_BUSY); - sent_data = usb_serial_jtag_write_and_flush(src, size); - portEXIT_CRITICAL(&p_usb_serial_jtag_obj->spinlock); - } - - // Blocking method, Sending data to ringbuffer, and handle the data in ISR. - if (size - sent_data > 0) { - result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*)(buff + sent_data), size - sent_data, ticks_to_wait); - } else { - atomic_store(&p_usb_serial_jtag_obj->fifo_status, FIFO_IDLE); - } + result = xRingbufferSend(p_usb_serial_jtag_obj->tx_ring_buf, (void*)src, size, ticks_to_wait); + // Re-enable the TX interrupt. If this was disabled, this will immediately trigger the ISR + // and send the things we just put in the ringbuffer. usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY); return (result == pdFALSE) ? 0 : size; } +//Note that this is also called when usb_serial_jtag_driver_install errors out and as such should +//work on a half-initialized driver as well. esp_err_t usb_serial_jtag_driver_uninstall(void) { if (p_usb_serial_jtag_obj == NULL) { - ESP_LOGI(USB_SERIAL_JTAG_TAG, "ALREADY NULL"); + ESP_LOGE(USB_SERIAL_JTAG_TAG, "uninstall without install called"); return ESP_OK; } - /* Not disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */ - //Disable tx/rx interrupt. + /* Don't disable the module clock and usb_pad_enable here since the USJ stdout might still depends on it. */ + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); - esp_intr_free(p_usb_serial_jtag_obj->intr_handle); + if (p_usb_serial_jtag_obj->intr_handle) { + esp_intr_free(p_usb_serial_jtag_obj->intr_handle); + } if (p_usb_serial_jtag_obj->rx_ring_buf) { vRingbufferDelete(p_usb_serial_jtag_obj->rx_ring_buf); diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c index 9446a6d24ed..ea400bbb65d 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_vfs.c @@ -121,6 +121,11 @@ static void usb_serial_jtag_tx_char(int fd, int c) do { if (usb_serial_jtag_ll_txfifo_writable()) { usb_serial_jtag_ll_write_txfifo(&cc, 1); + if (c == '\n') { + //Make sure line doesn't linger in fifo + usb_serial_jtag_ll_txfifo_flush(); + } + //update time of last successful tx to now. s_ctx.last_tx_ts = esp_timer_get_time(); break; } @@ -155,10 +160,6 @@ static ssize_t usb_serial_jtag_write(int fd, const void * data, size_t size) } } s_ctx.tx_func(fd, c); - if (c == '\n') { - //Make sure line doesn't linger in fifo - usb_serial_jtag_ll_txfifo_flush(); - } } _lock_release_recursive(&s_ctx.write_lock); return size; From 03447f582761a298526ca3e0e5cf08ea9af1f34c Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 29 Jul 2024 11:46:52 +0800 Subject: [PATCH 469/548] fix(usb_serial_jtag): Fix issue that use u32_reg read/write cannot be used to modify fifo regs --- .../soc/esp32c6/include/soc/usb_serial_jtag_struct.h | 9 ++++----- .../soc/esp32h2/include/soc/usb_serial_jtag_struct.h | 9 ++++----- .../soc/esp32p4/include/soc/usb_serial_jtag_struct.h | 9 ++++----- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/components/soc/esp32c6/include/soc/usb_serial_jtag_struct.h b/components/soc/esp32c6/include/soc/usb_serial_jtag_struct.h index 523b58eda2d..e83480db9de 100644 --- a/components/soc/esp32c6/include/soc/usb_serial_jtag_struct.h +++ b/components/soc/esp32c6/include/soc/usb_serial_jtag_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,7 @@ typedef union { * can check USB_SERIAL_JTAG_OUT_EP1_WR_ADDR USB_SERIAL_JTAG_OUT_EP0_RD_ADDR to know * how many data is received, then read data from UART Rx FIFO. */ - uint32_t rdwr_byte:8; - uint32_t reserved_8:24; + uint32_t rdwr_byte:32; }; uint32_t val; } usb_serial_jtag_ep1_reg_t; @@ -131,7 +130,7 @@ typedef union { */ uint32_t test_enable:1; /** test_usb_oe : R/W; bitpos: [1]; default: 0; - * USB pad oen in test + * USB pad one in test */ uint32_t test_usb_oe:1; /** test_tx_dp : R/W; bitpos: [2]; default: 0; @@ -290,7 +289,7 @@ typedef union { */ uint32_t serial_out_afifo_reset_rd:1; /** serial_out_afifo_rempty : RO; bitpos: [4]; default: 1; - * CDC_ACM OUTOUT async FIFO empty signal in read clock domain. + * CDC_ACM OUTPUT async FIFO empty signal in read clock domain. */ uint32_t serial_out_afifo_rempty:1; /** serial_in_afifo_wfull : RO; bitpos: [5]; default: 0; diff --git a/components/soc/esp32h2/include/soc/usb_serial_jtag_struct.h b/components/soc/esp32h2/include/soc/usb_serial_jtag_struct.h index f9dc6fa69f0..07f916eeff5 100644 --- a/components/soc/esp32h2/include/soc/usb_serial_jtag_struct.h +++ b/components/soc/esp32h2/include/soc/usb_serial_jtag_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,7 @@ typedef union { * can check USB_SERIAL_JTAG_OUT_EP1_WR_ADDR USB_SERIAL_JTAG_OUT_EP0_RD_ADDR to know * how many data is received, then read data from UART Rx FIFO. */ - uint32_t rdwr_byte:8; - uint32_t reserved_8:24; + uint32_t rdwr_byte:32; }; uint32_t val; } usb_serial_jtag_ep1_reg_t; @@ -131,7 +130,7 @@ typedef union { */ uint32_t test_enable:1; /** test_usb_oe : R/W; bitpos: [1]; default: 0; - * USB pad oen in test + * USB pad one in test */ uint32_t test_usb_oe:1; /** test_tx_dp : R/W; bitpos: [2]; default: 0; @@ -290,7 +289,7 @@ typedef union { */ uint32_t serial_out_afifo_reset_rd:1; /** serial_out_afifo_rempty : RO; bitpos: [4]; default: 1; - * CDC_ACM OUTOUT async FIFO empty signal in read clock domain. + * CDC_ACM OUTPUT async FIFO empty signal in read clock domain. */ uint32_t serial_out_afifo_rempty:1; /** serial_in_afifo_wfull : RO; bitpos: [5]; default: 0; diff --git a/components/soc/esp32p4/include/soc/usb_serial_jtag_struct.h b/components/soc/esp32p4/include/soc/usb_serial_jtag_struct.h index 11e17067a28..0d4bb3143d3 100644 --- a/components/soc/esp32p4/include/soc/usb_serial_jtag_struct.h +++ b/components/soc/esp32p4/include/soc/usb_serial_jtag_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,8 +23,7 @@ typedef union { * USB_DEVICE_OUT_EP1_WR_ADDR USB_DEVICE_OUT_EP0_RD_ADDR to know how many data is * received, then read data from UART Rx FIFO. */ - uint32_t rdwr_byte:8; - uint32_t reserved_8:24; + uint32_t rdwr_byte:32; }; uint32_t val; } usb_serial_jtag_ep1_reg_t; @@ -131,7 +130,7 @@ typedef union { */ uint32_t test_enable:1; /** test_usb_oe : R/W; bitpos: [1]; default: 0; - * USB pad oen in test + * USB pad one in test */ uint32_t test_usb_oe:1; /** test_tx_dp : R/W; bitpos: [2]; default: 0; @@ -290,7 +289,7 @@ typedef union { */ uint32_t serial_out_afifo_reset_rd:1; /** serial_out_afifo_rempty : RO; bitpos: [4]; default: 1; - * CDC_ACM OUTOUT async FIFO empty signal in read clock domain. + * CDC_ACM OUTPUT async FIFO empty signal in read clock domain. */ uint32_t serial_out_afifo_rempty:1; /** serial_in_afifo_wfull : RO; bitpos: [5]; default: 0; From 777e58f80e59cc22d2f5bd5fbf7d543cafda5799 Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 5 Jun 2024 20:46:44 +0800 Subject: [PATCH 470/548] feat(bluetooth/controller): storage ble controller log to flash on ESP32C6 and ESP32H2 --- components/bt/controller/esp32c6/Kconfig.in | 18 +++ components/bt/controller/esp32c6/bt.c | 131 +++++++++++++++++++- components/bt/controller/esp32h2/Kconfig.in | 18 +++ components/bt/controller/esp32h2/bt.c | 129 +++++++++++++++++++ 4 files changed, 295 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 9de74d8f05f..ddcfbba132e 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -342,6 +342,24 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY help Only operate in dump mode +config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + bool "Storage ble controller log to flash(experimental)" + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on BT_LE_CONTROLLER_LOG_ENABLED + default n + help + Storage ble controller log to flash. + +config BT_LE_CONTROLLER_LOG_PARTITION_SIZE + int "size of ble controller log partition(Multiples of 4K)" + depends on BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + default 65536 + help + The size of ble controller log partition shall be a multiples of 4K. + The name of log partition shall be "bt_ctrl_log". + The partition type shall be ESP_PARTITION_TYPE_DATA. + The partition sub_type shall be ESP_PARTITION_SUBTYPE_ANY. + config BT_LE_LOG_CTRL_BUF1_SIZE int "size of the first BLE controller LOG buffer" depends on BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 10d15761568..464553f558e 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -184,6 +184,124 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#include "esp_partition.h" +#include "hal/wdt_hal.h" + +#define MAX_STORAGE_SIZE (CONFIG_BT_LE_CONTROLLER_LOG_PARTITION_SIZE) +#define BLOCK_SIZE (4096) +#define THRESHOLD (3072) +#define PARTITION_NAME "bt_ctrl_log" + +static const esp_partition_t *log_partition; +static uint32_t write_index = 0; +static uint32_t next_erase_index = BLOCK_SIZE; +static bool block_erased = false; +static bool stop_write = false; +static bool is_filled = false; + +void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) +{ + log_partition = NULL; + assert(MAX_STORAGE_SIZE % BLOCK_SIZE == 0); + // Find the partition map in the partition table + log_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + assert(log_partition != NULL); + // Prepare data to be read later using the mapped address + ESP_ERROR_CHECK(esp_partition_erase_range(log_partition, 0, BLOCK_SIZE)); + write_index = 0; + next_erase_index = BLOCK_SIZE; + block_erased = false; + is_filled = false; + stop_write = false; +} + +int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) +{ + if (len > MAX_STORAGE_SIZE) { + return -1; + } + + if (stop_write) { + return 0; + } + + if (((write_index) % BLOCK_SIZE) >= THRESHOLD && !block_erased) { + // esp_rom_printf("Ers nxt: %d,%d\n", next_erase_index, write_index); + esp_partition_erase_range(log_partition, next_erase_index, BLOCK_SIZE); + next_erase_index = (next_erase_index + BLOCK_SIZE) % MAX_STORAGE_SIZE; + block_erased = true; + } + + if (((write_index + len) / BLOCK_SIZE) > (write_index / BLOCK_SIZE)) { + block_erased = false; + } + + if (write_index + len <= MAX_STORAGE_SIZE) { + esp_partition_write(log_partition, write_index, addr, len); + write_index = (write_index + len) % MAX_STORAGE_SIZE; + } else { + uint32_t first_part_len = MAX_STORAGE_SIZE - write_index; + esp_partition_write(log_partition, write_index, addr, first_part_len); + esp_partition_write(log_partition, 0, addr + first_part_len, len - first_part_len); + write_index = len - first_part_len; + is_filled = true; + // esp_rom_printf("old idx: %d,%d\n",next_erase_index, write_index); + } + + return 0; +} + +void esp_bt_read_ctrl_log_from_flash(bool output) +{ + esp_partition_mmap_handle_t mmap_handle; + uint32_t read_index; + const void *mapped_ptr; + const uint8_t *buffer; + uint32_t print_len; + uint32_t max_print_len; + + print_len = 0; + max_print_len = 4096; + esp_err_t err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); + if (err != ESP_OK) { + ESP_LOGE("FLASH", "Mmap failed: %s", esp_err_to_name(err)); + return; + } + + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + r_ble_log_async_output_dump_all(true); + stop_write = true; + + buffer = (const uint8_t *)mapped_ptr; + esp_panic_handler_reconfigure_wdts(5000); + if (is_filled) { + read_index = next_erase_index; + } else { + read_index = 0; + } + + esp_rom_printf("\r\nREAD_CHECK:%ld,%ld,%d\r\n",read_index, write_index, is_filled); + esp_rom_printf("\r\n[DUMP_START:"); + while (read_index != write_index) { + esp_rom_printf("%02x ", buffer[read_index]); + if (print_len > max_print_len) { + esp_panic_handler_reconfigure_wdts(5000); + print_len = 0; + } + + print_len++; + read_index = (read_index + 1) % MAX_STORAGE_SIZE; + } + + esp_rom_printf(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); + esp_partition_munmap(mmap_handle); + esp_bt_ctrl_log_partition_get_and_erase_first_block(); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* This variable tells if BLE is running */ @@ -567,7 +685,6 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) uint8_t hci_transport_mode; memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "invalid controller state"); return ESP_ERR_INVALID_STATE; @@ -668,6 +785,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); #else +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_ctrl_log_partition_get_and_erase_first_block(); +#endif ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); #endif // CONFIG_BT_CONTROLLER_LOG_DUMP if (ret != ESP_OK) { @@ -703,6 +823,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGW(NIMBLE_PORT_LOG_TAG, "controller_sleep_init failed %d", ret); goto free_controller; } + ESP_ERROR_CHECK(esp_read_mac((uint8_t *)mac, ESP_MAC_BT)); swap_in_place(mac, 6); r_esp_ble_ll_set_public_addr(mac); @@ -1088,16 +1209,23 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) { +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_controller_log_storage(len, addr, end); +#else for (int i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); } if (end) { esp_rom_printf("\n"); } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } void esp_ble_controller_log_dump_all(bool output) { +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_read_ctrl_log_from_flash(output); +#else portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_SAFE(&spinlock); @@ -1106,6 +1234,7 @@ void esp_ble_controller_log_dump_all(bool output) r_ble_log_async_output_dump_all(output); BT_ASSERT_PRINT(":DUMP_END]\r\n"); portEXIT_CRITICAL_SAFE(&spinlock); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index f68a615b7c2..d68caa226cf 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -333,6 +333,24 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY help Only operate in dump mode +config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + bool "Storage ble controller log to flash(experimental)" + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on BT_LE_CONTROLLER_LOG_ENABLED + default n + help + Storage ble controller log to flash. + +config BT_LE_CONTROLLER_LOG_PARTITION_SIZE + int "size of ble controller log partition(Multiples of 4K)" + depends on BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + default 65536 + help + The size of ble controller log partition shall be a multiples of 4K. + The name of log partition shall be "bt_ctrl_log". + The partition type shall be ESP_PARTITION_TYPE_DATA. + The partition sub_type shall be ESP_PARTITION_SUBTYPE_ANY. + config BT_LE_LOG_CTRL_BUF1_SIZE int "size of the first BLE controller LOG buffer" depends on BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index 5e2b1fb66b7..ef6f18e2dc4 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -176,6 +176,124 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#include "esp_partition.h" +#include "hal/wdt_hal.h" + +#define MAX_STORAGE_SIZE (CONFIG_BT_LE_CONTROLLER_LOG_PARTITION_SIZE) +#define BLOCK_SIZE (4096) +#define THRESHOLD (3072) +#define PARTITION_NAME "bt_ctrl_log" + +static const esp_partition_t *log_partition; +static uint32_t write_index = 0; +static uint32_t next_erase_index = BLOCK_SIZE; +static bool block_erased = false; +static bool stop_write = false; +static bool is_filled = false; + +void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) +{ + log_partition = NULL; + assert(MAX_STORAGE_SIZE % BLOCK_SIZE == 0); + // Find the partition map in the partition table + log_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + assert(log_partition != NULL); + // Prepare data to be read later using the mapped address + ESP_ERROR_CHECK(esp_partition_erase_range(log_partition, 0, BLOCK_SIZE)); + write_index = 0; + next_erase_index = BLOCK_SIZE; + block_erased = false; + is_filled = false; + stop_write = false; +} + +int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) +{ + if (len > MAX_STORAGE_SIZE) { + return -1; + } + + if (stop_write) { + return 0; + } + + if (((write_index) % BLOCK_SIZE) >= THRESHOLD && !block_erased) { + // esp_rom_printf("Ers nxt: %d,%d\n", next_erase_index, write_index); + esp_partition_erase_range(log_partition, next_erase_index, BLOCK_SIZE); + next_erase_index = (next_erase_index + BLOCK_SIZE) % MAX_STORAGE_SIZE; + block_erased = true; + } + + if (((write_index + len) / BLOCK_SIZE) > (write_index / BLOCK_SIZE)) { + block_erased = false; + } + + if (write_index + len <= MAX_STORAGE_SIZE) { + esp_partition_write(log_partition, write_index, addr, len); + write_index = (write_index + len) % MAX_STORAGE_SIZE; + } else { + uint32_t first_part_len = MAX_STORAGE_SIZE - write_index; + esp_partition_write(log_partition, write_index, addr, first_part_len); + esp_partition_write(log_partition, 0, addr + first_part_len, len - first_part_len); + write_index = len - first_part_len; + is_filled = true; + // esp_rom_printf("old idx: %d,%d\n",next_erase_index, write_index); + } + + return 0; +} + +void esp_bt_read_ctrl_log_from_flash(bool output) +{ + esp_partition_mmap_handle_t mmap_handle; + uint32_t read_index; + const void *mapped_ptr; + const uint8_t *buffer; + uint32_t print_len; + uint32_t max_print_len; + + print_len = 0; + max_print_len = 4096; + esp_err_t err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); + if (err != ESP_OK) { + ESP_LOGE("FLASH", "Mmap failed: %s", esp_err_to_name(err)); + return; + } + + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + r_ble_log_async_output_dump_all(true); + stop_write = true; + + buffer = (const uint8_t *)mapped_ptr; + esp_panic_handler_reconfigure_wdts(5000); + if (is_filled) { + read_index = next_erase_index; + } else { + read_index = 0; + } + + esp_rom_printf("\r\nREAD_CHECK:%ld,%ld,%d\r\n",read_index, write_index, is_filled); + esp_rom_printf("\r\n[DUMP_START:"); + while (read_index != write_index) { + esp_rom_printf("%02x ", buffer[read_index]); + if (print_len > max_print_len) { + esp_panic_handler_reconfigure_wdts(5000); + print_len = 0; + } + + print_len++; + read_index = (read_index + 1) % MAX_STORAGE_SIZE; + } + + esp_rom_printf(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); + esp_partition_munmap(mmap_handle); + esp_bt_ctrl_log_partition_get_and_erase_first_block(); +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* This variable tells if BLE is running */ @@ -637,6 +755,9 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); #else +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_ctrl_log_partition_get_and_erase_first_block(); +#endif ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); #endif // CONFIG_BT_CONTROLLER_LOG_DUMP if (ret != ESP_OK) { @@ -1055,16 +1176,23 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) { +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_controller_log_storage(len, addr, end); +#else for (int i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); } if (end) { esp_rom_printf("\n"); } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } void esp_ble_controller_log_dump_all(bool output) { +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_read_ctrl_log_from_flash(output); +#else portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL_SAFE(&spinlock); @@ -1073,6 +1201,7 @@ void esp_ble_controller_log_dump_all(bool output) r_ble_log_async_output_dump_all(output); BT_ASSERT_PRINT(":DUMP_END]\r\n"); portEXIT_CRITICAL_SAFE(&spinlock); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED From 565053406b94832f6c870798278cda2880d18cc9 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 6 Jun 2024 12:03:23 +0800 Subject: [PATCH 471/548] feat(bluetooth/controller): storage ble controller log to flash on ESP32C2 --- components/bt/controller/esp32c2/Kconfig.in | 18 ++ components/bt/controller/esp32c2/bt.c | 228 ++++++++++++++++---- 2 files changed, 206 insertions(+), 40 deletions(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index 75355ed098e..e522e416034 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -294,6 +294,24 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY help Only operate in dump mode +config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + bool "Storage ble controller log to flash(experimental)" + depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY + depends on BT_LE_CONTROLLER_LOG_ENABLED + default n + help + Storage ble controller log to flash. + +config BT_LE_CONTROLLER_LOG_PARTITION_SIZE + int "size of ble controller log partition(Multiples of 4K)" + depends on BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + default 65536 + help + The size of ble controller log partition shall be a multiples of 4K. + The name of log partition shall be "bt_ctrl_log". + The partition type shall be ESP_PARTITION_TYPE_DATA. + The partition sub_type shall be ESP_PARTITION_SUBTYPE_ANY. + config BT_LE_LOG_CTRL_BUF1_SIZE int "size of the first BLE controller LOG buffer" depends on BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 8333a8a2b11..ccf0251da4b 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -192,6 +192,9 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer const uint8_t *our_priv_key, uint8_t *out_dhkey); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); +#endif // #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* Local variable definition *************************************************************************** @@ -200,6 +203,188 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +static esp_err_t esp_bt_controller_log_init(void) +{ + esp_err_t ret = ESP_OK; + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + uint8_t buffers = 0; + bool task_create = true; + +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + task_create = false; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_ctrl_log_partition_get_and_erase_first_block(); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + ret = ble_log_init_async(bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size); + return ret; +} + +static void esp_bt_ontroller_log_deinit(void) +{ + ble_log_deinit_async(); +} + +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#include "esp_partition.h" +#include "hal/wdt_hal.h" + +#define MAX_STORAGE_SIZE (CONFIG_BT_LE_CONTROLLER_LOG_PARTITION_SIZE) +#define BLOCK_SIZE (4096) +#define THRESHOLD (3072) +#define PARTITION_NAME "bt_ctrl_log" + +static const esp_partition_t *log_partition; +static uint32_t write_index = 0; +static uint32_t next_erase_index = BLOCK_SIZE; +static bool block_erased = false; +static bool stop_write = false; +static bool is_filled = false; + +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) +{ + log_partition = NULL; + assert(MAX_STORAGE_SIZE % BLOCK_SIZE == 0); + // Find the partition map in the partition table + log_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, PARTITION_NAME); + assert(log_partition != NULL); + // Prepare data to be read later using the mapped address + ESP_ERROR_CHECK(esp_partition_erase_range(log_partition, 0, BLOCK_SIZE)); + write_index = 0; + next_erase_index = BLOCK_SIZE; + block_erased = false; + is_filled = false; + stop_write = false; +} + +static int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) +{ + if (len > MAX_STORAGE_SIZE) { + return -1; + } + + if (stop_write) { + return 0; + } + + assert(log_partition != NULL); + if (((write_index) % BLOCK_SIZE) >= THRESHOLD && !block_erased) { + // esp_rom_printf("Ers nxt: %d,%d\n", next_erase_index, write_index); + esp_partition_erase_range(log_partition, next_erase_index, BLOCK_SIZE); + next_erase_index = (next_erase_index + BLOCK_SIZE) % MAX_STORAGE_SIZE; + block_erased = true; + } + + if (((write_index + len) / BLOCK_SIZE) > (write_index / BLOCK_SIZE)) { + block_erased = false; + } + + if (write_index + len <= MAX_STORAGE_SIZE) { + esp_partition_write(log_partition, write_index, addr, len); + write_index = (write_index + len) % MAX_STORAGE_SIZE; + } else { + uint32_t first_part_len = MAX_STORAGE_SIZE - write_index; + esp_partition_write(log_partition, write_index, addr, first_part_len); + esp_partition_write(log_partition, 0, addr + first_part_len, len - first_part_len); + write_index = len - first_part_len; + is_filled = true; + // esp_rom_printf("old idx: %d,%d\n",next_erase_index, write_index); + } + + return 0; +} + +void esp_bt_read_ctrl_log_from_flash(bool output) +{ + esp_partition_mmap_handle_t mmap_handle; + uint32_t read_index; + const void *mapped_ptr; + const uint8_t *buffer; + uint32_t print_len; + uint32_t max_print_len; + esp_err_t err; + + print_len = 0; + max_print_len = 4096; + err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); + if (err != ESP_OK) { + ESP_LOGE("FLASH", "Mmap failed: %s", esp_err_to_name(err)); + return; + } + + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + ble_log_async_output_dump_all(true); + stop_write = true; + esp_bt_ontroller_log_deinit(); + portEXIT_CRITICAL_SAFE(&spinlock); + + buffer = (const uint8_t *)mapped_ptr; + if (is_filled) { + read_index = next_erase_index; + } else { + read_index = 0; + } + + esp_rom_printf("\r\nREAD_CHECK:%ld,%ld,%d\r\n",read_index, write_index, is_filled); + esp_rom_printf("\r\n[DUMP_START:"); + while (read_index != write_index) { + esp_rom_printf("%02x ", buffer[read_index]); + if (print_len > max_print_len) { + vTaskDelay(2); + print_len = 0; + } + + print_len++; + read_index = (read_index + 1) % MAX_STORAGE_SIZE; + } + esp_rom_printf(":DUMP_END]\r\n"); + esp_partition_munmap(mmap_handle); + esp_bt_ctrl_log_partition_get_and_erase_first_block(); + err = esp_bt_controller_log_init(); + assert(err == ESP_OK); + +} +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) +{ +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_controller_log_storage(len, addr, end); +#else + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + if (end) { + esp_rom_printf("\n"); + } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +} + +void esp_ble_controller_log_dump_all(bool output) +{ +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + esp_bt_read_ctrl_log_from_flash(output); +#else + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +} #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* This variable tells if BLE is running */ @@ -566,20 +751,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble rom commit:[%s]", r_ble_controller_get_rom_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - interface_func_t bt_controller_log_interface; - bt_controller_log_interface = esp_bt_controller_log_interface; - uint8_t buffers = 0; -#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED - buffers |= ESP_BLE_LOG_BUF_CONTROLLER; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED - buffers |= ESP_BLE_LOG_BUF_HCI; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - ret = ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); -#else - ret = ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); -#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + ret = esp_bt_controller_log_init(); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); goto controller_init_err; @@ -617,7 +789,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED controller_init_err: - ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED ble_controller_deinit(); modem_deint: @@ -646,7 +818,7 @@ esp_err_t esp_bt_controller_deinit(void) controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED ble_controller_deinit(); @@ -996,30 +1168,6 @@ uint8_t esp_ble_get_chip_rev_version(void) return efuse_ll_get_chip_wafer_version_minor(); } -#if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED -static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) -{ - for (int i = 0; i < len; i++) { - esp_rom_printf("%02x ", addr[i]); - } - if (end) { - esp_rom_printf("\n"); - } -} - -void esp_ble_controller_log_dump_all(bool output) -{ - portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - - portENTER_CRITICAL_SAFE(&spinlock); - esp_panic_handler_reconfigure_wdts(5000); - BT_ASSERT_PRINT("\r\n[DUMP_START:"); - ble_log_async_output_dump_all(output); - BT_ASSERT_PRINT(":DUMP_END]\r\n"); - portEXIT_CRITICAL_SAFE(&spinlock); -} -#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - #if (!CONFIG_BT_NIMBLE_ENABLED) && (CONFIG_BT_CONTROLLER_ENABLED) #if CONFIG_BT_LE_SM_LEGACY || CONFIG_BT_LE_SM_SC #define BLE_SM_KEY_ERR 0x17 From 30ff46717f29204befde885a399e2a0be00e5430 Mon Sep 17 00:00:00 2001 From: zwl Date: Fri, 14 Jun 2024 11:56:10 +0800 Subject: [PATCH 472/548] feat(bluetooth/controller): support switching log output mode on ESP32-C6 and ESP32-H2 --- components/bt/controller/esp32c6/bt.c | 153 +++++++++++++++++++------- components/bt/controller/esp32h2/bt.c | 131 ++++++++++++++++------ 2 files changed, 212 insertions(+), 72 deletions(-) diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 464553f558e..699e85feb8b 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -176,6 +176,9 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer const uint8_t *our_priv_key, uint8_t *out_dhkey); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); +#endif // #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* Local variable definition *************************************************************************** @@ -184,6 +187,83 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +enum log_out_mode { + LOG_DUMP_MEMORY, + LOG_ASYNC_OUT, + LOG_STORAGE_TO_FLASH, +}; + +bool log_is_inited = false; +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY +uint8_t log_output_mode = LOG_DUMP_MEMORY; +#else +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +uint8_t log_output_mode = LOG_STORAGE_TO_FLASH; +#else +uint8_t log_output_mode = LOG_ASYNC_OUT; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + +void esp_bt_log_output_mode_set(uint8_t output_mode) +{ + log_output_mode = output_mode; +} + +uint8_t esp_bt_log_output_mode_get(void) +{ + return log_output_mode; +} + +esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode) +{ + esp_err_t ret = ESP_OK; + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + bool task_create; + uint8_t buffers = 0; + + if (log_is_inited) { + return ret; + } + +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + + switch (log_output_mode) { + case LOG_DUMP_MEMORY: + task_create = false; + break; + case LOG_ASYNC_OUT: + case LOG_STORAGE_TO_FLASH: + task_create = true; +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + if (log_output_mode == LOG_STORAGE_TO_FLASH) { + esp_bt_ctrl_log_partition_get_and_erase_first_block(); + } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + break; + default: + assert(0); + } + + ret = r_ble_log_init_async(bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size); + if (ret == ESP_OK) { + log_is_inited = true; + } + + return ret; +} + +void esp_bt_ontroller_log_deinit(void) +{ + r_ble_log_deinit_async(); + log_is_inited = false; +} + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #include "esp_partition.h" #include "hal/wdt_hal.h" @@ -200,7 +280,7 @@ static bool block_erased = false; static bool stop_write = false; static bool is_filled = false; -void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) { log_partition = NULL; assert(MAX_STORAGE_SIZE % BLOCK_SIZE == 0); @@ -216,7 +296,7 @@ void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) stop_write = false; } -int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) +static int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) { if (len > MAX_STORAGE_SIZE) { return -1; @@ -260,10 +340,11 @@ void esp_bt_read_ctrl_log_from_flash(bool output) const uint8_t *buffer; uint32_t print_len; uint32_t max_print_len; + esp_err_t err; print_len = 0; max_print_len = 4096; - esp_err_t err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); + err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); if (err != ESP_OK) { ESP_LOGE("FLASH", "Mmap failed: %s", esp_err_to_name(err)); return; @@ -273,6 +354,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output) portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_reconfigure_wdts(5000); r_ble_log_async_output_dump_all(true); + esp_bt_ontroller_log_deinit(); stop_write = true; buffer = (const uint8_t *)mapped_ptr; @@ -299,7 +381,8 @@ void esp_bt_read_ctrl_log_from_flash(bool output) esp_rom_printf(":DUMP_END]\r\n"); portEXIT_CRITICAL_SAFE(&spinlock); esp_partition_munmap(mmap_handle); - esp_bt_ctrl_log_partition_get_and_erase_first_block(); + err = esp_bt_controller_log_init(log_output_mode); + assert(err == ESP_OK); } #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -773,23 +856,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif // CONFIG_SW_COEXIST_ENABLE #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - interface_func_t bt_controller_log_interface; - bt_controller_log_interface = esp_bt_controller_log_interface; - uint8_t buffers = 0; -#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED - buffers |= ESP_BLE_LOG_BUF_CONTROLLER; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED - buffers |= ESP_BLE_LOG_BUF_HCI; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); -#else -#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_ctrl_log_partition_get_and_erase_first_block(); -#endif - ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); -#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + ret = esp_bt_controller_log_init(log_output_mode); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); goto modem_deint; @@ -853,7 +920,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) modem_deint: esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - r_ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED esp_phy_modem_deinit(); modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); @@ -889,7 +956,7 @@ esp_err_t esp_bt_controller_deinit(void) r_ble_controller_deinit(); esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - r_ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED #if CONFIG_BT_NIMBLE_ENABLED @@ -1209,32 +1276,36 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) { + if (log_output_mode == LOG_STORAGE_TO_FLASH) { #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_controller_log_storage(len, addr, end); -#else - for (int i = 0; i < len; i++) { - esp_rom_printf("%02x ", addr[i]); - } - if (end) { - esp_rom_printf("\n"); + esp_bt_controller_log_storage(len, addr, end); +#endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + } else { + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + + if (end) { + esp_rom_printf("\n"); + } } -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } void esp_ble_controller_log_dump_all(bool output) { + if (log_output_mode == LOG_STORAGE_TO_FLASH) { #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_read_ctrl_log_from_flash(output); -#else - portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - - portENTER_CRITICAL_SAFE(&spinlock); - esp_panic_handler_reconfigure_wdts(5000); - BT_ASSERT_PRINT("\r\n[DUMP_START:"); - r_ble_log_async_output_dump_all(output); - BT_ASSERT_PRINT(":DUMP_END]\r\n"); - portEXIT_CRITICAL_SAFE(&spinlock); + esp_bt_read_ctrl_log_from_flash(output); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + } else { + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + r_ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); + } } #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index ef6f18e2dc4..3d764d58f77 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -168,6 +168,9 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer const uint8_t *our_priv_key, uint8_t *out_dhkey); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end); +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); +#endif // #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED /* Local variable definition *************************************************************************** @@ -176,6 +179,82 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; +enum log_out_mode { + LOG_DUMP_MEMORY, + LOG_ASYNC_OUT, + LOG_STORAGE_TO_FLASH, +}; + +bool log_is_inited = false; +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY +uint8_t log_output_mode = LOG_DUMP_MEMORY; +#else +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +uint8_t log_output_mode = LOG_STORAGE_TO_FLASH; +#else +uint8_t log_output_mode = LOG_ASYNC_OUT; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + +void esp_bt_log_output_mode_set(uint8_t output_mode) +{ + log_output_mode = output_mode; +} + +uint8_t esp_bt_log_output_mode_get(void) +{ + return log_output_mode; +} + +esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode) +{ + esp_err_t ret = ESP_OK; + interface_func_t bt_controller_log_interface; + bt_controller_log_interface = esp_bt_controller_log_interface; + bool task_create; + uint8_t buffers = 0; + + if (log_is_inited) { + return ret; + } + +#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED + buffers |= ESP_BLE_LOG_BUF_CONTROLLER; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED +#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + buffers |= ESP_BLE_LOG_BUF_HCI; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED + + switch (log_output_mode) { + case LOG_DUMP_MEMORY: + task_create = false; + break; + case LOG_ASYNC_OUT: + case LOG_STORAGE_TO_FLASH: + task_create = true; +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + if (log_output_mode == LOG_STORAGE_TO_FLASH) { + esp_bt_ctrl_log_partition_get_and_erase_first_block(); + } +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + break; + default: + assert(0); + } + + ret = r_ble_log_init_async(bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size); + if (ret == ESP_OK) { + log_is_inited = true; + } + return ret; +} + +void esp_bt_ontroller_log_deinit(void) +{ + r_ble_log_deinit_async(); + log_is_inited = false; +} + #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #include "esp_partition.h" #include "hal/wdt_hal.h" @@ -192,7 +271,7 @@ static bool block_erased = false; static bool stop_write = false; static bool is_filled = false; -void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) +static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) { log_partition = NULL; assert(MAX_STORAGE_SIZE % BLOCK_SIZE == 0); @@ -208,7 +287,7 @@ void esp_bt_ctrl_log_partition_get_and_erase_first_block(void) stop_write = false; } -int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) +static int esp_bt_controller_log_storage(uint32_t len, const uint8_t *addr, bool end) { if (len > MAX_STORAGE_SIZE) { return -1; @@ -252,10 +331,11 @@ void esp_bt_read_ctrl_log_from_flash(bool output) const uint8_t *buffer; uint32_t print_len; uint32_t max_print_len; + esp_err_t err; print_len = 0; max_print_len = 4096; - esp_err_t err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); + err = esp_partition_mmap(log_partition, 0, MAX_STORAGE_SIZE, ESP_PARTITION_MMAP_DATA, &mapped_ptr, &mmap_handle); if (err != ESP_OK) { ESP_LOGE("FLASH", "Mmap failed: %s", esp_err_to_name(err)); return; @@ -265,6 +345,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output) portENTER_CRITICAL_SAFE(&spinlock); esp_panic_handler_reconfigure_wdts(5000); r_ble_log_async_output_dump_all(true); + esp_bt_ontroller_log_deinit(); stop_write = true; buffer = (const uint8_t *)mapped_ptr; @@ -291,7 +372,8 @@ void esp_bt_read_ctrl_log_from_flash(bool output) esp_rom_printf(":DUMP_END]\r\n"); portEXIT_CRITICAL_SAFE(&spinlock); esp_partition_munmap(mmap_handle); - esp_bt_ctrl_log_partition_get_and_erase_first_block(); + err = esp_bt_controller_log_init(log_output_mode); + assert(err == ESP_OK); } #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -743,23 +825,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) #endif // CONFIG_SW_COEXIST_ENABLE #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - interface_func_t bt_controller_log_interface; - bt_controller_log_interface = esp_bt_controller_log_interface; - uint8_t buffers = 0; -#if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED - buffers |= ESP_BLE_LOG_BUF_CONTROLLER; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED - buffers |= ESP_BLE_LOG_BUF_HCI; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - ret = r_ble_log_init_async(bt_controller_log_interface, false, buffers, (uint32_t *)log_bufs_size); -#else -#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_ctrl_log_partition_get_and_erase_first_block(); -#endif - ret = r_ble_log_init_async(bt_controller_log_interface, true, buffers, (uint32_t *)log_bufs_size); -#endif // CONFIG_BT_CONTROLLER_LOG_DUMP + ret = esp_bt_controller_log_init(log_output_mode); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); goto modem_deint; @@ -822,7 +888,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) modem_deint: esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - r_ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED modem_clock_deselect_lp_clock_source(PERIPH_BT_MODULE); modem_clock_module_disable(PERIPH_BT_MODULE); @@ -856,7 +922,7 @@ esp_err_t esp_bt_controller_deinit(void) r_ble_controller_deinit(); esp_ble_unregister_bb_funcs(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - r_ble_log_deinit_async(); + esp_bt_ontroller_log_deinit(); #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED #if CONFIG_BT_NIMBLE_ENABLED @@ -1176,16 +1242,19 @@ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t po #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) { + if (log_output_mode == LOG_STORAGE_TO_FLASH) { #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_controller_log_storage(len, addr, end); -#else - for (int i = 0; i < len; i++) { - esp_rom_printf("%02x ", addr[i]); - } - if (end) { - esp_rom_printf("\n"); + esp_bt_controller_log_storage(len, addr, end); +#endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + } else { + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + + if (end) { + esp_rom_printf("\n"); + } } -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } void esp_ble_controller_log_dump_all(bool output) From 29d8e723b89b4e4eb2e66542b59b43882435fdc8 Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 18 Jun 2024 10:27:34 +0800 Subject: [PATCH 473/548] feat(bluetooth/controller): support switching log output mode on ESP32-C2 --- components/bt/controller/esp32c2/bt.c | 86 +++++++++++++++++++++------ 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index ccf0251da4b..5a635a83a2f 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -203,13 +203,44 @@ static void esp_bt_ctrl_log_partition_get_and_erase_first_block(void); static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; -static esp_err_t esp_bt_controller_log_init(void) +enum log_out_mode { + LOG_DUMP_MEMORY, + LOG_ASYNC_OUT, + LOG_STORAGE_TO_FLASH, +}; + +bool log_is_inited = false; +#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY +uint8_t log_output_mode = LOG_DUMP_MEMORY; +#else +#if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +uint8_t log_output_mode = LOG_STORAGE_TO_FLASH; +#else +uint8_t log_output_mode = LOG_ASYNC_OUT; +#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE +#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY + +void esp_bt_log_output_mode_set(uint8_t output_mode) +{ + log_output_mode = output_mode; +} + +uint8_t esp_bt_log_output_mode_get(void) +{ + return log_output_mode; +} + +esp_err_t esp_bt_controller_log_init(uint8_t log_output_mode) { esp_err_t ret = ESP_OK; interface_func_t bt_controller_log_interface; bt_controller_log_interface = esp_bt_controller_log_interface; + bool task_create; uint8_t buffers = 0; - bool task_create = true; + + if (log_is_inited) { + return ret; + } #if CONFIG_BT_LE_CONTROLLER_LOG_CTRL_ENABLED buffers |= ESP_BLE_LOG_BUF_CONTROLLER; @@ -218,20 +249,35 @@ static esp_err_t esp_bt_controller_log_init(void) buffers |= ESP_BLE_LOG_BUF_HCI; #endif // CONFIG_BT_LE_CONTROLLER_LOG_HCI_ENABLED -#if CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - task_create = false; -#endif // CONFIG_BT_LE_CONTROLLER_LOG_DUMP_ONLY - + switch (log_output_mode) { + case LOG_DUMP_MEMORY: + task_create = false; + break; + case LOG_ASYNC_OUT: + case LOG_STORAGE_TO_FLASH: + task_create = true; #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_ctrl_log_partition_get_and_erase_first_block(); + if (log_output_mode == LOG_STORAGE_TO_FLASH) { + esp_bt_ctrl_log_partition_get_and_erase_first_block(); + } #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + break; + default: + assert(0); + } + ret = ble_log_init_async(bt_controller_log_interface, task_create, buffers, (uint32_t *)log_bufs_size); + if (ret == ESP_OK) { + log_is_inited = true; + } + return ret; } -static void esp_bt_ontroller_log_deinit(void) +void esp_bt_ontroller_log_deinit(void) { ble_log_deinit_async(); + log_is_inited = false; } #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE @@ -350,24 +396,26 @@ void esp_bt_read_ctrl_log_from_flash(bool output) } esp_rom_printf(":DUMP_END]\r\n"); esp_partition_munmap(mmap_handle); - esp_bt_ctrl_log_partition_get_and_erase_first_block(); - err = esp_bt_controller_log_init(); + err = esp_bt_controller_log_init(log_output_mode); assert(err == ESP_OK); } #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, bool end) { + if (log_output_mode == LOG_STORAGE_TO_FLASH) { #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_controller_log_storage(len, addr, end); -#else - for (int i = 0; i < len; i++) { - esp_rom_printf("%02x ", addr[i]); - } - if (end) { - esp_rom_printf("\n"); + esp_bt_controller_log_storage(len, addr, end); +#endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + } else { + for (int i = 0; i < len; i++) { + esp_rom_printf("%02x ", addr[i]); + } + + if (end) { + esp_rom_printf("\n"); + } } -#endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } void esp_ble_controller_log_dump_all(bool output) @@ -751,7 +799,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ESP_LOGI(NIMBLE_PORT_LOG_TAG, "ble rom commit:[%s]", r_ble_controller_get_rom_compile_version()); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED - ret = esp_bt_controller_log_init(); + ret = esp_bt_controller_log_init(log_output_mode); if (ret != ESP_OK) { ESP_LOGW(NIMBLE_PORT_LOG_TAG, "ble_controller_log_init failed %d", ret); goto controller_init_err; From ba97f7d755c53ed0ff33b762d67401cad88d36b2 Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 23 Jul 2024 17:29:26 +0800 Subject: [PATCH 474/548] fix(ble): fixed wdt issue when print key controller info on ESP32-C6 and ESP32-H2 --- components/bt/controller/esp32c6/bt.c | 4 ++++ components/bt/controller/esp32h2/bt.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 699e85feb8b..2346cf0b3b8 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -1281,6 +1281,9 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b esp_bt_controller_log_storage(len, addr, end); #endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } else { + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(1000); for (int i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); } @@ -1288,6 +1291,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b if (end) { esp_rom_printf("\n"); } + portEXIT_CRITICAL_SAFE(&spinlock); } } diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index 3d764d58f77..90b7530b2a1 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -1247,6 +1247,9 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b esp_bt_controller_log_storage(len, addr, end); #endif //CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE } else { + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(1000); for (int i = 0; i < len; i++) { esp_rom_printf("%02x ", addr[i]); } @@ -1254,6 +1257,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b if (end) { esp_rom_printf("\n"); } + portEXIT_CRITICAL_SAFE(&spinlock); } } From 6e11307d1626c04685156c92fbb37dfb07385b9b Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 24 Jul 2024 17:09:07 +0800 Subject: [PATCH 475/548] fix(ble): fixed tx memory leak issue when controller disable --- components/bt/porting/transport/src/hci_transport.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/bt/porting/transport/src/hci_transport.c b/components/bt/porting/transport/src/hci_transport.c index df8b5db009c..29c2e001311 100644 --- a/components/bt/porting/transport/src/hci_transport.c +++ b/components/bt/porting/transport/src/hci_transport.c @@ -72,6 +72,7 @@ hci_transport_controller_evt_tx(uint8_t *hci_ev, void *arg) uint32_t len; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + r_ble_hci_trans_buf_free(hci_ev); return -1; } @@ -85,6 +86,7 @@ hci_transport_controller_acl_tx(struct os_mbuf *om, void *arg) { uint16_t len; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + os_mbuf_free_chain(om); return -1; } From b9b3479a20629c20076fd9828881f58267e76461 Mon Sep 17 00:00:00 2001 From: Vilem Zavodny Date: Fri, 26 Jul 2024 07:47:53 +0200 Subject: [PATCH 476/548] fix(esp_lcd): Fix I2C receive without param --- components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c b/components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c index e8a50d8ee44..b3269947714 100644 --- a/components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c +++ b/components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c @@ -121,10 +121,10 @@ static esp_err_t panel_io_i2c_rx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, voi lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base); bool send_param = (lcd_cmd >= 0); - int write_size = 0; - uint8_t write_buffer[CONTROL_PHASE_LENGTH + CMD_LENGTH] = {0}; - if (send_param) { + int write_size = 0; + uint8_t write_buffer[CONTROL_PHASE_LENGTH + CMD_LENGTH] = {0}; + if (i2c_panel_io->control_phase_enabled) { write_buffer[0] = i2c_panel_io->control_phase_cmd; write_size += 1; @@ -136,9 +136,12 @@ static esp_err_t panel_io_i2c_rx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, voi memcpy(write_buffer + write_size, cmds + (sizeof(cmds) - cmds_size), cmds_size); write_size += cmds_size; } + + ESP_GOTO_ON_ERROR(i2c_master_transmit_receive(i2c_panel_io->i2c_handle, write_buffer, write_size, buffer, buffer_size, -1), err, TAG, "i2c transaction failed"); + } else { + ESP_GOTO_ON_ERROR(i2c_master_receive(i2c_panel_io->i2c_handle, buffer, buffer_size, -1), err, TAG, "i2c transaction failed"); } - ESP_GOTO_ON_ERROR(i2c_master_transmit_receive(i2c_panel_io->i2c_handle, write_buffer, write_size, buffer, buffer_size, -1), err, TAG, "i2c transaction failed"); return ESP_OK; err: return ret; From 873ae74e0b6d5afd1d6717ea7f9ec30717cc9432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Tue, 23 Jul 2024 15:44:40 +0200 Subject: [PATCH 477/548] fix(vfs): FATFS mount immediately after format if mount failed --- components/fatfs/vfs/vfs_fat_sdmmc.c | 2 +- components/fatfs/vfs/vfs_fat_spiflash.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/fatfs/vfs/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c index 7c65324dfff..075a5ca1631 100644 --- a/components/fatfs/vfs/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -140,7 +140,7 @@ static esp_err_t s_f_mount(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8 } ESP_LOGW(TAG, "mounting again"); - res = f_mount(fs, drv, 0); + res = f_mount(fs, drv, 1); if (res != FR_OK) { err = ESP_FAIL; ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res); diff --git a/components/fatfs/vfs/vfs_fat_spiflash.c b/components/fatfs/vfs/vfs_fat_spiflash.c index 2057f194cf8..7b5fb2491cc 100644 --- a/components/fatfs/vfs/vfs_fat_spiflash.c +++ b/components/fatfs/vfs/vfs_fat_spiflash.c @@ -104,7 +104,7 @@ static esp_err_t s_f_mount_rw(FATFS *fs, const char *drv, const esp_vfs_fat_moun } ESP_LOGI(TAG, "Mounting again"); - fresult = f_mount(fs, drv, 0); + fresult = f_mount(fs, drv, 1); ESP_RETURN_ON_FALSE(fresult == FR_OK, ESP_FAIL, TAG, "f_mount failed after formatting (%d)", fresult); } else { if (out_flags) { From 5fc18ffc048a494e140c63c4bc8a80a1b4535d52 Mon Sep 17 00:00:00 2001 From: Peter Marcisovsky Date: Thu, 14 Dec 2023 17:14:55 +0100 Subject: [PATCH 478/548] feat(usb/host): multiconfiguration support - usb host reads device's configuration on request - a control transfer is sent - memory is allocated for a new descriptor - user must manually free the memory --- components/usb/include/usb/usb_host.h | 31 ++- .../usb_host/main/multiconf_client.h | 22 +++ .../usb_host/main/multiconf_client_async.c | 179 ++++++++++++++++++ .../test_apps/usb_host/main/test_app_main.c | 2 + .../usb_host/main/test_usb_host_async.c | 65 +++++++ components/usb/usb_host.c | 139 ++++++++++++++ 6 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 components/usb/test_apps/usb_host/main/multiconf_client.h create mode 100644 components/usb/test_apps/usb_host/main/multiconf_client_async.c diff --git a/components/usb/include/usb/usb_host.h b/components/usb/include/usb/usb_host.h index ba44c584d17..823a42b1585 100644 --- a/components/usb/include/usb/usb_host.h +++ b/components/usb/include/usb/usb_host.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -346,6 +346,35 @@ esp_err_t usb_host_get_device_descriptor(usb_device_handle_t dev_hdl, const usb_ */ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc); +/** + * @brief Get get device's configuration descriptor + * + * - The USB Host library only caches a device's active configuration descriptor. + * - This function reads any configuration descriptor of a particular device (specified by bConfigurationValue). + * - This function will read the specified configuration descriptor via control transfers, and allocate memory to store that descriptor. + * - Users can call usb_host_get_config_desc_free() to free the descriptor's memory afterwards. + * + * @note This function can block + * @note A client must call usb_host_device_open() on the device first + * @param[in] client_hdl Client handle - usb_host_client_handle_events() should be called repeatedly in a separate task to handle client events + * @param[in] dev_hdl Device handle + * @param[out] config_desc_ret Returned configuration descriptor + * @param[in] bConfigurationValue Index of device's configuration descriptor to be read + * @note bConfigurationValue starts from index 1 + * @return esp_err_t + */ +esp_err_t usb_host_get_config_desc(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl, uint8_t bConfigurationValue, const usb_config_desc_t **config_desc_ret); + +/** + * @brief Free a configuration descriptor + * + * This function frees a configuration descriptor that was returned by usb_host_get_config_desc() + * + * @param[out] config_desc Configuration descriptor + * @return esp_err_t + */ +esp_err_t usb_host_get_config_desc_free(const usb_config_desc_t *config_desc); + // ----------------------------------------------- Interface Functions ------------------------------------------------- /** diff --git a/components/usb/test_apps/usb_host/main/multiconf_client.h b/components/usb/test_apps/usb_host/main/multiconf_client.h new file mode 100644 index 00000000000..b5af74db74f --- /dev/null +++ b/components/usb/test_apps/usb_host/main/multiconf_client.h @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +typedef struct { + SemaphoreHandle_t dev_open_smp; + uint8_t bConfigurationValue; +} multiconf_client_test_param_t; + +/** + * @brief Multiconfiguration client task + */ +void multiconf_client_async_task(void *arg); + +/** + * @brief Get configuration descriptor + */ +void multiconf_client_get_conf_desc(void); diff --git a/components/usb/test_apps/usb_host/main/multiconf_client_async.c b/components/usb/test_apps/usb_host/main/multiconf_client_async.c new file mode 100644 index 00000000000..26e67069a9a --- /dev/null +++ b/components/usb/test_apps/usb_host/main/multiconf_client_async.c @@ -0,0 +1,179 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_err.h" +#include "esp_log.h" +#include "test_usb_common.h" +#include "multiconf_client.h" +#include "mock_msc.h" +#include "dev_msc.h" +#include "usb/usb_host.h" +#include "unity.h" + +/* +Implementation of a multi-configuration client used for USB Host Tests. + +- The multi-configuration client will: + - Register itself as a client + - Receive USB_HOST_CLIENT_EVENT_NEW_DEV event message, and open the device + - Get active configuration descriptor + - Start handling client events + - Wait for a request from main task to read a configuration descriptor + - Compare the obtained configuration descriptor with the active configuration descriptor + - Free the memory used for storing the configuration descriptor + - Close the device + - Deregister control client +*/ + +const char *MULTICONF_CLIENT_TAG = "Multi config Client"; + +#define CLIENT_NUM_EVENT_MSG 5 + +typedef enum { + TEST_STAGE_WAIT_CONN, + TEST_STAGE_DEV_OPEN, + TEST_STAGE_WAIT, + TEST_STAGE_CHECK_CONFIG_DESC, + TEST_STAGE_DEV_CLOSE, +} test_stage_t; + +typedef struct { + // Test parameters + multiconf_client_test_param_t test_param; + // device info + uint8_t dev_addr; + usb_speed_t dev_speed; + // Client variables + usb_host_client_handle_t client_hdl; + usb_device_handle_t dev_hdl; + // Test state + test_stage_t cur_stage; + test_stage_t next_stage; + const usb_config_desc_t *config_desc_cached; +} multiconf_client_obj_t; + +static multiconf_client_obj_t *s_multiconf_obj; + +static void multiconf_client_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg) +{ + multiconf_client_obj_t *multiconf_obj = (multiconf_client_obj_t *)arg; + switch (event_msg->event) { + case USB_HOST_CLIENT_EVENT_NEW_DEV: + TEST_ASSERT_EQUAL(TEST_STAGE_WAIT_CONN, multiconf_obj->cur_stage); + multiconf_obj->next_stage = TEST_STAGE_DEV_OPEN; + multiconf_obj->dev_addr = event_msg->new_dev.address; + break; + default: + abort(); // Should never occur in this test + break; + } +} + +void multiconf_client_async_task(void *arg) +{ + multiconf_client_obj_t multiconf_obj; + // Initialize test params + memcpy(&multiconf_obj.test_param, arg, sizeof(multiconf_client_test_param_t)); + // Initialize client variables + multiconf_obj.client_hdl = NULL; + multiconf_obj.dev_hdl = NULL; + // Initialize test stage + multiconf_obj.cur_stage = TEST_STAGE_WAIT_CONN; + multiconf_obj.next_stage = TEST_STAGE_WAIT_CONN; + multiconf_obj.dev_addr = 0; + + // Register client + usb_host_client_config_t client_config = { + .is_synchronous = false, + .max_num_event_msg = CLIENT_NUM_EVENT_MSG, + .async = { + .client_event_callback = multiconf_client_event_cb, + .callback_arg = (void *) &multiconf_obj, + }, + }; + TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_register(&client_config, &multiconf_obj.client_hdl)); + s_multiconf_obj = &multiconf_obj; + + // Wait to be started by main thread + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ESP_LOGD(MULTICONF_CLIENT_TAG, "Starting"); + + bool exit_loop = false; + bool skip_event_handling = false; + while (!exit_loop) { + if (!skip_event_handling) { + TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_handle_events(multiconf_obj.client_hdl, portMAX_DELAY)); + } + skip_event_handling = false; + if (multiconf_obj.cur_stage == multiconf_obj.next_stage) { + continue; + } + multiconf_obj.cur_stage = multiconf_obj.next_stage; + + switch (multiconf_obj.next_stage) { + case TEST_STAGE_DEV_OPEN: { + ESP_LOGD(MULTICONF_CLIENT_TAG, "Open"); + // Open the device + TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, usb_host_device_open(multiconf_obj.client_hdl, multiconf_obj.dev_addr, &multiconf_obj.dev_hdl), "Failed to open the device"); + + // Get device info to get it's speed + usb_device_info_t dev_info; + TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_info(multiconf_obj.dev_hdl, &dev_info)); + multiconf_obj.dev_speed = dev_info.speed; + + multiconf_obj.next_stage = TEST_STAGE_WAIT; + skip_event_handling = true; + break; + } + case TEST_STAGE_WAIT: { + // Give semaphore signalizing that the device has been opened + xSemaphoreGive(multiconf_obj.test_param.dev_open_smp); + break; + } + case TEST_STAGE_CHECK_CONFIG_DESC: { + ESP_LOGD(MULTICONF_CLIENT_TAG, "Check config descriptors"); + // Get mocked config descriptor + const usb_config_desc_t *config_desc_ref = dev_msc_get_config_desc(multiconf_obj.dev_speed); + TEST_ASSERT_EQUAL_MESSAGE(multiconf_obj.config_desc_cached->wTotalLength, config_desc_ref->wTotalLength, "Incorrect length of CFG descriptor"); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE(config_desc_ref, multiconf_obj.config_desc_cached, sizeof(usb_config_desc_t), "Configuration descriptors do not match"); + + // Free the memory used to store the config descriptor + TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_config_desc_free(multiconf_obj.config_desc_cached)); + multiconf_obj.next_stage = TEST_STAGE_DEV_CLOSE; + skip_event_handling = true; + break; + } + case TEST_STAGE_DEV_CLOSE: { + ESP_LOGD(MULTICONF_CLIENT_TAG, "Close"); + vTaskDelay(10); // Give USB Host Lib some time to process all transfers + TEST_ASSERT_EQUAL(ESP_OK, usb_host_device_close(multiconf_obj.client_hdl, multiconf_obj.dev_hdl)); + exit_loop = true; + break; + } + default: + abort(); + break; + } + } + TEST_ASSERT_EQUAL(ESP_OK, usb_host_client_deregister(multiconf_obj.client_hdl)); + ESP_LOGD(MULTICONF_CLIENT_TAG, "Done"); + vTaskDelete(NULL); +} + +void multiconf_client_get_conf_desc(void) +{ + // Get configuration descriptor, ctrl transfer is sent to the device to get the config descriptor + TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_config_desc(s_multiconf_obj->client_hdl, s_multiconf_obj->dev_hdl, s_multiconf_obj->test_param.bConfigurationValue, &s_multiconf_obj->config_desc_cached)); + + // Go to next stage + s_multiconf_obj->next_stage = TEST_STAGE_CHECK_CONFIG_DESC; + ESP_ERROR_CHECK(usb_host_client_unblock(s_multiconf_obj->client_hdl)); +} diff --git a/components/usb/test_apps/usb_host/main/test_app_main.c b/components/usb/test_apps/usb_host/main/test_app_main.c index 93e2510374c..de47f0b0f3f 100644 --- a/components/usb/test_apps/usb_host/main/test_app_main.c +++ b/components/usb/test_apps/usb_host/main/test_app_main.c @@ -33,6 +33,8 @@ void tearDown(void) vTaskDelay(10); // Clean up USB Host ESP_ERROR_CHECK(usb_host_uninstall()); + // Short delay to allow task to be cleaned up after client uninstall + vTaskDelay(10); test_usb_deinit_phy(); // Deinitialize the internal USB PHY after testing unity_utils_evaluate_leaks(); } diff --git a/components/usb/test_apps/usb_host/main/test_usb_host_async.c b/components/usb/test_apps/usb_host/main/test_usb_host_async.c index c7329d91fa1..0dac7076f5b 100644 --- a/components/usb/test_apps/usb_host/main/test_usb_host_async.c +++ b/components/usb/test_apps/usb_host/main/test_usb_host_async.c @@ -14,6 +14,7 @@ #include "dev_msc.h" #include "msc_client.h" #include "ctrl_client.h" +#include "multiconf_client.h" #include "usb/usb_host.h" #include "unity.h" @@ -21,6 +22,7 @@ #define TEST_MSC_NUM_SECTORS_PER_XFER 2 #define TEST_MSC_SCSI_TAG 0xDEADBEEF #define TEST_CTRL_NUM_TRANSFERS 30 +#define B_CONFIGURATION_VALUE 1 // --------------------------------------------------- Test Cases ------------------------------------------------------ @@ -275,3 +277,66 @@ TEST_CASE("Test USB Host async API", "[usb_host][full_speed][low_speed]") vTaskDelay(10); } } + +/* +Test USB Host Asynchronous API single client + +Purpose: + - Test that client can read configuration descriptor by request + +Procedure: + - Install USB Host Library + - Create a task to run a multiconfig client + - Create a task to handle system events + - Start the MSC client task. It will open the device and start handling client events + - Wait for the main task requests client to read configuration descriptor + - Compare the requested configuration descriptor with the active configuration descriptor + - Wait for the host library event handler to report a USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS event + - Free all devices + - Uninstall USB Host Library +*/ +static void host_lib_task(void *arg) +{ + while (1) { + // Start handling system events + uint32_t event_flags; + usb_host_lib_handle_events(portMAX_DELAY, &event_flags); + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) { + printf("No more clients\n"); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FINISHED, usb_host_device_free_all()); + } + if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) { + break; + } + } + + printf("Deleting host_lib_task\n"); + vTaskDelete(NULL); +} + +TEST_CASE("Test USB Host multiconfig client (single client)", "[usb_host][full_speed][high_speed]") +{ + SemaphoreHandle_t dev_open_smp = xSemaphoreCreateBinary(); + TaskHandle_t client_task; + + multiconf_client_test_param_t multiconf_params = { + .dev_open_smp = dev_open_smp, + .bConfigurationValue = B_CONFIGURATION_VALUE, + }; + + xTaskCreatePinnedToCore(multiconf_client_async_task, "async client", 4096, (void*)&multiconf_params, 2, &client_task, 0); + TEST_ASSERT_NOT_NULL_MESSAGE(client_task, "Failed to create async client task"); + // Start the task + xTaskNotifyGive(client_task); + + TaskHandle_t host_lib_task_hdl; + xTaskCreatePinnedToCore(host_lib_task, "host lib", 4096, NULL, 2, &host_lib_task_hdl, 0); + TEST_ASSERT_NOT_NULL_MESSAGE(host_lib_task_hdl, "Failed to create host lib task"); + + // Wait for the device to be open + xSemaphoreTake(dev_open_smp, portMAX_DELAY); + multiconf_client_get_conf_desc(); + + // Cleanup + vSemaphoreDelete(dev_open_smp); +} diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index b2e5ed137a9..18909d4ab2c 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -10,6 +10,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to #include #include +#include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -52,6 +53,9 @@ static portMUX_TYPE host_lock = portMUX_INITIALIZER_UNLOCKED; #define ENABLE_ENUM_FILTER_CALLBACK #endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK +#define SHORT_DESC_REQ_LEN 8 +#define CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE + typedef struct ep_wrapper_s ep_wrapper_t; typedef struct interface_s interface_t; typedef struct client_s client_t; @@ -349,6 +353,12 @@ static bool endpoint_callback(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event, return yield; } +static void get_config_desc_transfer_cb(usb_transfer_t *transfer) +{ + SemaphoreHandle_t transfer_done = (SemaphoreHandle_t)transfer->context; + xSemaphoreGive(transfer_done); +} + // ------------------------------------------------ Library Functions -------------------------------------------------- // ----------------------- Public -------------------------- @@ -945,6 +955,135 @@ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, con return usbh_dev_get_config_desc(dev_hdl, config_desc); } +// ----------------- Descriptors Transfer Requests -------------------- + +static usb_transfer_status_t wait_for_transmission_done(usb_transfer_t *transfer) +{ + SemaphoreHandle_t transfer_done = (SemaphoreHandle_t)transfer->context; + xSemaphoreTake(transfer_done, portMAX_DELAY); + usb_transfer_status_t status = transfer->status; + + // EP0 halt->flush->clear is managed by USBH and lower layers + return status; +} + +static esp_err_t get_config_desc_transfer(usb_host_client_handle_t client_hdl, usb_transfer_t *ctrl_transfer, const int bConfigurationValue, const int num_bytes) +{ + const usb_device_desc_t *dev_desc; + ESP_ERROR_CHECK(usbh_dev_get_desc(ctrl_transfer->device_handle, &dev_desc)); + + usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)ctrl_transfer->data_buffer; + USB_SETUP_PACKET_INIT_GET_CONFIG_DESC(setup_pkt, bConfigurationValue - 1, num_bytes); + ctrl_transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(num_bytes, dev_desc->bMaxPacketSize0); + + // IN data stage should return exactly num_bytes (SHORT_DESC_REQ_LEN or wTotalLength) bytes + const int expect_num_bytes = sizeof(usb_setup_packet_t) + num_bytes; + + // Submit control transfer + esp_err_t ret = usb_host_transfer_submit_control(client_hdl, ctrl_transfer); + if (ret != ESP_OK) { + ESP_LOGE(USB_HOST_TAG, "Submit ctrl transfer failed"); + return ret; + } + + // Wait for transfer to finish + const usb_transfer_status_t status_short_desc = wait_for_transmission_done(ctrl_transfer); + if (status_short_desc != USB_TRANSFER_STATUS_COMPLETED) { + ESP_LOGE(USB_HOST_TAG, "Get config descriptor transfer status: %d", status_short_desc); + ret = ESP_ERR_INVALID_STATE; + return ret; + } + + // Check IN transfer returned the expected correct number of bytes + if ((expect_num_bytes != 0) && (ctrl_transfer->actual_num_bytes != expect_num_bytes)) { + if (ctrl_transfer->actual_num_bytes > expect_num_bytes) { + // The device returned more bytes than requested. + // This violates the USB specs chapter 9.3.5, but we can continue + ESP_LOGW(USB_HOST_TAG, "Incorrect number of bytes returned %d", ctrl_transfer->actual_num_bytes); + return ESP_OK; + } else { + // The device returned less bytes than requested. We cannot continue. + ESP_LOGE(USB_HOST_TAG, "Incorrect number of bytes returned %d", ctrl_transfer->actual_num_bytes); + return ESP_ERR_INVALID_RESPONSE; + } + } + return ESP_OK; +} + +esp_err_t usb_host_get_config_desc(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl, uint8_t bConfigurationValue, const usb_config_desc_t **config_desc_ret) +{ + esp_err_t ret = ESP_OK; + HOST_CHECK(client_hdl != NULL && dev_hdl != NULL && config_desc_ret != NULL, ESP_ERR_INVALID_ARG); + + // Get number of configurations + const usb_device_desc_t *dev_desc; + ESP_ERROR_CHECK(usbh_dev_get_desc(dev_hdl, &dev_desc)); + + HOST_CHECK(bConfigurationValue != 0, ESP_ERR_INVALID_ARG); + HOST_CHECK(bConfigurationValue <= dev_desc->bNumConfigurations, ESP_ERR_NOT_SUPPORTED); + + // Initialize transfer + usb_transfer_t *ctrl_transfer; + if (usb_host_transfer_alloc(sizeof(usb_setup_packet_t) + CTRL_TRANSFER_MAX_DATA_LEN, 0, &ctrl_transfer)) { + return ESP_ERR_NO_MEM; + } + + SemaphoreHandle_t transfer_done = xSemaphoreCreateBinary(); + if (transfer_done == NULL) { + ret = ESP_ERR_NO_MEM; + goto exit; + } + + ctrl_transfer->device_handle = dev_hdl; + ctrl_transfer->bEndpointAddress = 0; + ctrl_transfer->callback = get_config_desc_transfer_cb; + ctrl_transfer->context = (void *)transfer_done; + + // Initiate control transfer for short config descriptor + ret = get_config_desc_transfer(client_hdl, ctrl_transfer, bConfigurationValue, SHORT_DESC_REQ_LEN); + if (ret != ESP_OK) { + goto exit; + } + + // Get length of full config descriptor + const usb_config_desc_t *config_desc_short = (usb_config_desc_t *)(ctrl_transfer->data_buffer + sizeof(usb_setup_packet_t)); + + // Initiate control transfer for full config descriptor + ret = get_config_desc_transfer(client_hdl, ctrl_transfer, bConfigurationValue, config_desc_short->wTotalLength); + if (ret != ESP_OK) { + goto exit; + } + + // Allocate memory to store the configuration descriptor + const usb_config_desc_t *config_desc_full = (usb_config_desc_t *)(ctrl_transfer->data_buffer + sizeof(usb_setup_packet_t)); + usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); + if (config_desc == NULL) { + ret = ESP_ERR_NO_MEM; + goto exit; + } + + // Copy the configuration descriptor + memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength); + *config_desc_ret = config_desc; + ret = ESP_OK; + +exit: + if (ctrl_transfer) { + usb_host_transfer_free(ctrl_transfer); + } + if (transfer_done != NULL) { + vSemaphoreDelete(transfer_done); + } + return ret; +} + +esp_err_t usb_host_get_config_desc_free(const usb_config_desc_t *config_desc) +{ + HOST_CHECK(config_desc != NULL, ESP_ERR_INVALID_ARG); + heap_caps_free((usb_config_desc_t*)config_desc); + return ESP_OK; +} + // ----------------------------------------------- Interface Functions ------------------------------------------------- // ----------------------- Private ------------------------- From 613ad211c6e1a696751b690ef5033b8d7b280645 Mon Sep 17 00:00:00 2001 From: Peter Marcisovsky Date: Tue, 16 Jul 2024 11:32:22 +0200 Subject: [PATCH 479/548] refactor(usb_host): Update USB Host multiconfig public API - previous usb_host_get_config_desc_free() - updated usb_host_free_config_desc() --- components/usb/include/usb/usb_host.h | 4 ++-- .../usb/test_apps/usb_host/main/multiconf_client_async.c | 2 +- components/usb/usb_host.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/usb/include/usb/usb_host.h b/components/usb/include/usb/usb_host.h index 823a42b1585..b9a1c4dabb1 100644 --- a/components/usb/include/usb/usb_host.h +++ b/components/usb/include/usb/usb_host.h @@ -352,7 +352,7 @@ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, con * - The USB Host library only caches a device's active configuration descriptor. * - This function reads any configuration descriptor of a particular device (specified by bConfigurationValue). * - This function will read the specified configuration descriptor via control transfers, and allocate memory to store that descriptor. - * - Users can call usb_host_get_config_desc_free() to free the descriptor's memory afterwards. + * - Users can call usb_host_free_config_desc() to free the descriptor's memory afterwards. * * @note This function can block * @note A client must call usb_host_device_open() on the device first @@ -373,7 +373,7 @@ esp_err_t usb_host_get_config_desc(usb_host_client_handle_t client_hdl, usb_devi * @param[out] config_desc Configuration descriptor * @return esp_err_t */ -esp_err_t usb_host_get_config_desc_free(const usb_config_desc_t *config_desc); +esp_err_t usb_host_free_config_desc(const usb_config_desc_t *config_desc); // ----------------------------------------------- Interface Functions ------------------------------------------------- diff --git a/components/usb/test_apps/usb_host/main/multiconf_client_async.c b/components/usb/test_apps/usb_host/main/multiconf_client_async.c index 26e67069a9a..811a1dbdc14 100644 --- a/components/usb/test_apps/usb_host/main/multiconf_client_async.c +++ b/components/usb/test_apps/usb_host/main/multiconf_client_async.c @@ -146,7 +146,7 @@ void multiconf_client_async_task(void *arg) TEST_ASSERT_EQUAL_MEMORY_MESSAGE(config_desc_ref, multiconf_obj.config_desc_cached, sizeof(usb_config_desc_t), "Configuration descriptors do not match"); // Free the memory used to store the config descriptor - TEST_ASSERT_EQUAL(ESP_OK, usb_host_get_config_desc_free(multiconf_obj.config_desc_cached)); + TEST_ASSERT_EQUAL(ESP_OK, usb_host_free_config_desc(multiconf_obj.config_desc_cached)); multiconf_obj.next_stage = TEST_STAGE_DEV_CLOSE; skip_event_handling = true; break; diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index 18909d4ab2c..7094839db63 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -1077,7 +1077,7 @@ esp_err_t usb_host_get_config_desc(usb_host_client_handle_t client_hdl, usb_devi return ret; } -esp_err_t usb_host_get_config_desc_free(const usb_config_desc_t *config_desc) +esp_err_t usb_host_free_config_desc(const usb_config_desc_t *config_desc) { HOST_CHECK(config_desc != NULL, ESP_ERR_INVALID_ARG); heap_caps_free((usb_config_desc_t*)config_desc); From 0d7d3b5dbbb28773114ddcbdbf5de3822a6cbccc Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Tue, 9 Jul 2024 14:10:16 +0200 Subject: [PATCH 480/548] fix(usb/host): Fix occasional ISOC scheduler skipping transfers --- components/usb/hcd_dwc.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 8dc0ecc9ab9..f8ab81965db 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -60,10 +60,11 @@ #define XFER_LIST_LEN_CTRL 3 // One descriptor for each stage #define XFER_LIST_LEN_BULK 2 // One descriptor for transfer, one to support an extra zero length packet -// Same length as the frame list makes it easier to schedule. Must be power of 2 +// Periodic transfer descriptor lists: Same length as the frame list makes it easier to schedule. Must be power of 2 // FS: Must be 2-64. HS: Must be 8-256. See USB-OTG databook Table 5-47 #define XFER_LIST_LEN_INTR FRAME_LIST_LEN -#define XFER_LIST_LEN_ISOC FRAME_LIST_LEN +#define XFER_LIST_LEN_ISOC 64 // Implement longer ISOC transfer list to give us enough space for additional timing margin +#define XFER_LIST_ISOC_MARGIN 2 // The 1st ISOC transfer is scheduled 2 (micro)frames later so we have enough timing margin // ------------------------ Flags -------------------------- @@ -2148,7 +2149,7 @@ static inline void IRAM_ATTR _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_t assert(interval > 0); assert(__builtin_popcount(interval) == 1); // Isochronous interval must be power of 2 according to USB2.0 specification int total_num_desc = transfer->num_isoc_packets * interval; - assert(total_num_desc <= XFER_LIST_LEN_ISOC); + assert(total_num_desc <= XFER_LIST_LEN_ISOC - XFER_LIST_ISOC_MARGIN); // Some space in the qTD list is reserved for timing margin int desc_idx = start_idx; int bytes_filled = 0; // Zeroize the whole QTD, so we can focus only on the active descriptors @@ -2204,19 +2205,8 @@ static void IRAM_ATTR _buffer_fill(pipe_t *pipe) if (pipe->multi_buffer_control.buffer_num_to_exec == 0) { // There are no more previously filled buffers to execute. We need to calculate a new start index based on HFNUM and the pipe's schedule uint16_t cur_frame_num = usb_dwc_hal_port_get_cur_frame_num(pipe->port->hal); - start_idx = cur_frame_num + 1; // This is the next frame that the periodic scheduler will fetch - uint16_t rem_time = usb_dwc_ll_hfnum_get_frame_time_rem(pipe->port->hal->dev); - - // If there is not enough time remaining in this frame, consider the next frame as start index - // The remaining time is in USB PHY clocks. The threshold value is time between buffer fill and execute (6-11us) = 180 + 5 x num_packets - if (rem_time < 195 + 5 * transfer->num_isoc_packets) { - if (rem_time > 165 + 5 * transfer->num_isoc_packets) { - // If the remaining time is +-15 PHY clocks around the threshold value we cannot be certain whether we will schedule it in time for this frame - // Busy wait 10us to be sure that we are at the beginning of next frame/microframe - esp_rom_delay_us(10); - } - start_idx++; - } + start_idx = cur_frame_num + 1; // This is the next frame that the periodic scheduler will fetch + start_idx += XFER_LIST_ISOC_MARGIN; // Start scheduling with a little delay. This will get us enough timing margin so no transfer is skipped // Only every (interval + offset) transfer belongs to this channel // Following calculation effectively rounds up to nearest (interval + offset) @@ -2458,9 +2448,7 @@ static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) total_actual_num_bytes += transfer->isoc_packet_desc[pkt_idx].actual_num_bytes; // A descriptor is also allocated for unscheduled frames. We need to skip over them desc_idx += buffer->flags.isoc.interval; - if (desc_idx >= XFER_LIST_LEN_INTR) { - desc_idx -= XFER_LIST_LEN_INTR; - } + desc_idx %= XFER_LIST_LEN_ISOC; } // Write back the actual_num_bytes and statue of entire transfer assert(total_actual_num_bytes <= transfer->num_bytes); From 1a6f1e67c6d9f885a989d6c01eb85d4b144d20a4 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Mon, 15 Jul 2024 16:02:56 +0800 Subject: [PATCH 481/548] feat(ulp): include sdkconfig macros in cmake build --- components/ulp/cmake/CMakeLists.txt | 19 ++++++++++--------- components/ulp/project_include.cmake | 11 ++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 97b8d2eccce..d6117e5a955 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -5,8 +5,8 @@ project(${ULP_APP_NAME} ASM C) add_executable(${ULP_APP_NAME}) set(CMAKE_EXECUTABLE_SUFFIX ".elf") -option(ULP_COCPU_IS_RISCV "Use RISC-V based ULP" OFF) -option(ULP_COCPU_IS_LP_CORE "Use RISC-V based LP Core" OFF) +# Import all sdkconfig variables into the cmake build +include(${SDKCONFIG_CMAKE}) function(create_arg_file arguments output_file) # Escape all spaces @@ -20,7 +20,7 @@ endfunction() message(STATUS "Building ULP app ${ULP_APP_NAME}") # Check the supported assembler version -if(NOT (ULP_COCPU_IS_RISCV OR ULP_COCPU_IS_LP_CORE)) +if(CONFIG_ULP_COPROC_TYPE_FSM) check_expected_tool_version("esp32ulp-elf" ${CMAKE_ASM_COMPILER}) endif() @@ -28,6 +28,8 @@ endif() set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py) get_filename_component(sdkconfig_dir ${SDKCONFIG_HEADER} DIRECTORY) + + foreach(include ${COMPONENT_INCLUDES}) list(APPEND component_includes -I${include}) endforeach() @@ -41,9 +43,9 @@ list(APPEND ULP_PREPROCESSOR_ARGS -I${IDF_PATH}/components/esp_system/ld) target_include_directories(${ULP_APP_NAME} PRIVATE ${COMPONENT_INCLUDES}) # Pre-process the linker script -if(ULP_COCPU_IS_RISCV) +if(CONFIG_ULP_COPROC_TYPE_RISCV) set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_riscv.ld) -elseif(ULP_COCPU_IS_LP_CORE) +elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE) set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/lp_core_riscv.ld) else() set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/ulp_fsm.ld) @@ -69,8 +71,7 @@ target_link_options(${ULP_APP_NAME} PRIVATE SHELL:-T ${CMAKE_CURRENT_BINARY_DIR} # To avoid warning "Manually-specified variables were not used by the project" set(bypassWarning "${IDF_TARGET}") -set(bypassWarning "${CONFIG_ESP_ROM_HAS_LP_ROM}") -if(ULP_COCPU_IS_RISCV) +if(CONFIG_ULP_COPROC_TYPE_RISCV) #risc-v ulp uses extra files for building: list(APPEND ULP_S_SOURCES "${IDF_PATH}/components/ulp/ulp_riscv/ulp_core/ulp_riscv_vectors.S" @@ -98,7 +99,7 @@ if(ULP_COCPU_IS_RISCV) target_compile_definitions(${ULP_APP_NAME} PRIVATE IS_ULP_COCPU) target_compile_definitions(${ULP_APP_NAME} PRIVATE ULP_RISCV_REGISTER_OPS) -elseif(ULP_COCPU_IS_LP_CORE) +elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE) list(APPEND ULP_S_SOURCES "${IDF_PATH}/components/ulp/lp_core/lp_core/start.S" "${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S" @@ -172,7 +173,7 @@ else() endif() -if(ULP_COCPU_IS_LP_CORE) +if(CONFIG_ULP_COPROC_TYPE_LP_CORE) set(ULP_BASE_ADDR "0x0") else() set(ULP_BASE_ADDR "0x50000000") diff --git a/components/ulp/project_include.cmake b/components/ulp/project_include.cmake index b3e35dca962..2e6f5e96209 100644 --- a/components/ulp/project_include.cmake +++ b/components/ulp/project_include.cmake @@ -30,6 +30,7 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs) string(REPLACE ";" "|" ulp_s_sources "${ulp_s_sources}") idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER) + idf_build_get_property(sdkconfig_cmake SDKCONFIG_CMAKE) idf_build_get_property(idf_path IDF_PATH) idf_build_get_property(idf_target IDF_TARGET) idf_build_get_property(python PYTHON) @@ -41,17 +42,11 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs) elseif(IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3") if(CONFIG_ULP_COPROC_TYPE_RISCV STREQUAL "y") set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-ulp-riscv.cmake) - set(ULP_IS_RISCV ON) else() set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-${idf_target}-ulp.cmake) - set(ULP_IS_RISCV OFF) endif() elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE) set(TOOLCHAIN_FLAG ${idf_path}/components/ulp/cmake/toolchain-lp-core-riscv.cmake) - set(ULP_IS_LP_CORE_RISCV ON) - if(CONFIG_ESP_ROM_HAS_LP_ROM) - set(CONFIG_ESP_ROM_HAS_LP_ROM ON) - endif() endif() externalproject_add(${app_name} @@ -67,10 +62,8 @@ function(ulp_embed_binary app_name s_sources exp_dep_srcs) -DIDF_TARGET=${idf_target} -DIDF_PATH=${idf_path} -DSDKCONFIG_HEADER=${SDKCONFIG_HEADER} + -DSDKCONFIG_CMAKE=${SDKCONFIG_CMAKE} -DPYTHON=${python} - -DULP_COCPU_IS_RISCV=${ULP_IS_RISCV} - -DULP_COCPU_IS_LP_CORE=${ULP_IS_LP_CORE_RISCV} - -DCONFIG_ESP_ROM_HAS_LP_ROM=${CONFIG_ESP_ROM_HAS_LP_ROM} ${extra_cmake_args} BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/${app_name} --target build BUILD_BYPRODUCTS ${ulp_artifacts} ${ulp_artifacts_extras} ${ulp_ps_sources} From 1adbfa6822fb3c05e2a4a278dc953f3cd7c9bb35 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 30 Jul 2024 13:16:15 +0800 Subject: [PATCH 482/548] ci(system): disable c5 system tests --- components/esp_system/test_apps/.build-test-rules.yml | 2 +- .../esp_system/test_apps/esp_system_unity_tests/README.md | 4 ++-- components/heap/test_apps/.build-test-rules.yml | 1 + components/heap/test_apps/heap_tests/README.md | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/esp_system/test_apps/.build-test-rules.yml b/components/esp_system/test_apps/.build-test-rules.yml index e59aab60e35..e0343c14e30 100644 --- a/components/esp_system/test_apps/.build-test-rules.yml +++ b/components/esp_system/test_apps/.build-test-rules.yml @@ -6,7 +6,7 @@ components/esp_system/test_apps/console: components/esp_system/test_apps/esp_system_unity_tests: disable: - - if: (CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1) + - if: IDF_TARGET == "esp32c5" or (CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1) components/esp_system/test_apps/linux_apis: enable: diff --git a/components/esp_system/test_apps/esp_system_unity_tests/README.md b/components/esp_system/test_apps/esp_system_unity_tests/README.md index 3a502b1f86f..bf47d80ec64 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/README.md +++ b/components/esp_system/test_apps/esp_system_unity_tests/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/heap/test_apps/.build-test-rules.yml b/components/heap/test_apps/.build-test-rules.yml index 1e3b8ecd8cf..a90d37a1f28 100644 --- a/components/heap/test_apps/.build-test-rules.yml +++ b/components/heap/test_apps/.build-test-rules.yml @@ -2,6 +2,7 @@ components/heap/test_apps/heap_tests: disable: + - if: IDF_TARGET == "esp32c5" - if: IDF_TARGET == "linux" - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 - if: CONFIG_NAME == "psram_all_ext" and SOC_SPIRAM_SUPPORTED != 1 diff --git a/components/heap/test_apps/heap_tests/README.md b/components/heap/test_apps/heap_tests/README.md index b8fe0d892df..5b39ff96532 100644 --- a/components/heap/test_apps/heap_tests/README.md +++ b/components/heap/test_apps/heap_tests/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | \ No newline at end of file From 951bdd70a2a9417b7a348d026f4abafead200d37 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 30 Jul 2024 15:40:19 +0800 Subject: [PATCH 483/548] fix(ci): fix the readme check of c5 mp --- .../bootloader_support/test_apps/rtc_custom_section/README.md | 4 ++-- components/driver/test_apps/legacy_timer_driver/README.md | 4 ++-- components/efuse/test_apps/README.md | 4 ++-- components/esp_driver_gptimer/test_apps/gptimer/README.md | 4 ++-- components/esp_driver_uart/test_apps/rs485/README.md | 4 ++-- components/esp_driver_uart/test_apps/uart/README.md | 4 ++-- examples/peripherals/timer_group/gptimer/README.md | 4 ++-- examples/peripherals/timer_group/legacy_driver/README.md | 4 ++-- examples/system/sysview_tracing/README.md | 4 ++-- examples/system/sysview_tracing_heap_log/README.md | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/components/bootloader_support/test_apps/rtc_custom_section/README.md b/components/bootloader_support/test_apps/rtc_custom_section/README.md index a79fcf4c5ea..46d16c788ce 100644 --- a/components/bootloader_support/test_apps/rtc_custom_section/README.md +++ b/components/bootloader_support/test_apps/rtc_custom_section/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/driver/test_apps/legacy_timer_driver/README.md b/components/driver/test_apps/legacy_timer_driver/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/driver/test_apps/legacy_timer_driver/README.md +++ b/components/driver/test_apps/legacy_timer_driver/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/efuse/test_apps/README.md b/components/efuse/test_apps/README.md index c75201fb88f..351f5fdebc7 100644 --- a/components/efuse/test_apps/README.md +++ b/components/efuse/test_apps/README.md @@ -1,3 +1,3 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_gptimer/test_apps/gptimer/README.md b/components/esp_driver_gptimer/test_apps/gptimer/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/esp_driver_gptimer/test_apps/gptimer/README.md +++ b/components/esp_driver_gptimer/test_apps/gptimer/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_uart/test_apps/rs485/README.md b/components/esp_driver_uart/test_apps/rs485/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/esp_driver_uart/test_apps/rs485/README.md +++ b/components/esp_driver_uart/test_apps/rs485/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_uart/test_apps/uart/README.md b/components/esp_driver_uart/test_apps/uart/README.md index bf47d80ec64..3a502b1f86f 100644 --- a/components/esp_driver_uart/test_apps/uart/README.md +++ b/components/esp_driver_uart/test_apps/uart/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/examples/peripherals/timer_group/gptimer/README.md b/examples/peripherals/timer_group/gptimer/README.md index b5b3aff407e..7ff20c6a7d9 100644 --- a/examples/peripherals/timer_group/gptimer/README.md +++ b/examples/peripherals/timer_group/gptimer/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # Example: General Purpose Timer diff --git a/examples/peripherals/timer_group/legacy_driver/README.md b/examples/peripherals/timer_group/legacy_driver/README.md index 3a595073c07..fb7f50aab6f 100644 --- a/examples/peripherals/timer_group/legacy_driver/README.md +++ b/examples/peripherals/timer_group/legacy_driver/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # Example: General Purpose Timer diff --git a/examples/system/sysview_tracing/README.md b/examples/system/sysview_tracing/README.md index 41936bec3bb..1b65d621793 100644 --- a/examples/system/sysview_tracing/README.md +++ b/examples/system/sysview_tracing/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # Example: Application Level Tracing - SystemView Tracing (sysview_tracing) This test code shows how to perform system-wide behavioral analysis of the program using [SEGGER SystemView tool](https://www.segger.com/products/development-tools/systemview/). diff --git a/examples/system/sysview_tracing_heap_log/README.md b/examples/system/sysview_tracing_heap_log/README.md index 8ad1b3955df..573ce63a6fd 100644 --- a/examples/system/sysview_tracing_heap_log/README.md +++ b/examples/system/sysview_tracing_heap_log/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | # SystemView Heap and Log Tracing Example From da2fb9de49288be1073432c80582f2187c00f46e Mon Sep 17 00:00:00 2001 From: aditi Date: Fri, 5 Jul 2024 15:51:13 +0530 Subject: [PATCH 484/548] fix(wpa_supplicant):Deinit old dpp authentication data after receiving config. --- components/wpa_supplicant/esp_supplicant/src/esp_dpp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c b/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c index 9279f340dc6..639c7bbf39e 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_dpp.c @@ -87,7 +87,7 @@ static uint8_t esp_dpp_deinit_auth(void) static void esp_dpp_call_cb(esp_supp_dpp_event_t evt, void *data) { - if (evt == ESP_SUPP_DPP_FAIL && s_dpp_ctx.dpp_auth) { + if (s_dpp_ctx.dpp_auth) { esp_dpp_deinit_auth(); } s_dpp_ctx.dpp_event_cb(evt, data); @@ -178,7 +178,7 @@ static void esp_dpp_rx_auth_req(struct action_rx_param *rx_param, uint8_t *dpp_d own_bi, rx_param->channel, (const u8 *)&rx_param->action_frm->u.public_action.v, dpp_data, len); os_memcpy(s_dpp_ctx.dpp_auth->peer_mac_addr, rx_param->sa, ETH_ALEN); - + wpa_printf(MSG_DEBUG, "DPP: Sending authentication response."); esp_dpp_send_action_frame(rx_param->sa, wpabuf_head(s_dpp_ctx.dpp_auth->resp_msg), wpabuf_len(s_dpp_ctx.dpp_auth->resp_msg), rx_param->channel, OFFCHAN_TX_WAIT_TIME); @@ -845,7 +845,7 @@ esp_err_t esp_supp_dpp_init(esp_supp_dpp_event_cb_t cb) return ESP_FAIL; } if (s_dpp_ctx.dpp_global) { - wpa_printf(MSG_ERROR, "DPP: failed to init as init already done."); + wpa_printf(MSG_ERROR, "DPP: failed to init as init already done. Please deinit first and retry."); return ESP_FAIL; } From fa7fb662c1b1844c0fe92f5c4cb28b82d6563a1b Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Tue, 30 Jul 2024 16:44:37 +0800 Subject: [PATCH 485/548] fix(wifi/mesh): fix the beacon timeout issue in mesh --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index ce181b3e947..da2c33977ea 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit ce181b3e947d3d8495c17b9881930816bb94ed58 +Subproject commit da2c33977ea14edb9ea4d1dbaea0901a28dea470 From 18a4191adf6e5863c6415443e984c4c6b9c98bc5 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Tue, 30 Jul 2024 11:47:26 +0800 Subject: [PATCH 486/548] fix(ble/bluedroid): Fix incorrect state issue when unregistering BLE GATTC application --- .../bluedroid/api/include/api/esp_bt_main.h | 7 +++++-- .../bluedroid/api/include/api/esp_gattc_api.h | 8 ++++++-- .../bt/host/bluedroid/bta/gatt/bta_gattc_act.c | 17 ++++++++++------- .../host/bluedroid/bta/gatt/bta_gattc_utils.c | 14 ++++++++++---- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/components/bt/host/bluedroid/api/include/api/esp_bt_main.h b/components/bt/host/bluedroid/api/include/api/esp_bt_main.h index b13ae94d0ea..a626ec65513 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_bt_main.h +++ b/components/bt/host/bluedroid/api/include/api/esp_bt_main.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,7 +55,10 @@ esp_bluedroid_status_t esp_bluedroid_get_status(void); esp_err_t esp_bluedroid_enable(void); /** - * @brief Disable bluetooth, must prior to esp_bluedroid_deinit(). + * @brief Disable Bluetooth, must be called prior to esp_bluedroid_deinit(). + * + * @note Before calling this API, ensure that all activities related to + * the application, such as connections, scans, etc., are properly closed. * * @return * - ESP_OK : Succeed diff --git a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h index 13bf16a3281..0c274e20321 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gattc_api.h @@ -299,10 +299,14 @@ esp_err_t esp_ble_gattc_app_register(uint16_t app_id); /** * @brief This function is called to unregister an application - * from GATTC module. + * from the GATTC module. * * @param[in] gattc_if: Gatt client access interface. * + * @note Before calling this API, ensure that all activities + * related to the application, such as connections, scans, ADV, + * are properly closed. + * * @return * - ESP_OK: success * - other: failed @@ -608,7 +612,7 @@ esp_gatt_status_t esp_ble_gattc_get_db(esp_gatt_if_t gattc_if, uint16_t conn_id, * * @param[in] gattc_if: Gatt client access interface. * @param[in] conn_id : connection ID. - * @param[in] handle : characteritic handle to read. + * @param[in] handle : characteristic handle to read. * @param[in] auth_req : authenticate request type * * @return diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index b2302fa469f..543b9b04bf4 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -63,7 +63,7 @@ static void bta_gattc_cmpl_sendmsg(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPLETE *p_data); static void bta_gattc_pop_command_to_send(tBTA_GATTC_CLCB *p_clcb); -static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg); +void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg); static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, BD_ADDR bda); static void bta_gattc_cong_cback (UINT16 conn_id, BOOLEAN congested); static void bta_gattc_req_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type, tGATTS_DATA *p_data); @@ -154,7 +154,7 @@ void bta_gattc_disable(tBTA_GATTC_CB *p_cb) APPL_TRACE_DEBUG("bta_gattc_disable"); if (p_cb->state != BTA_GATTC_STATE_ENABLED) { - APPL_TRACE_ERROR("not enabled or disable in pogress"); + APPL_TRACE_ERROR("not enabled or disable in progress"); return; } @@ -227,7 +227,7 @@ void bta_gattc_register(tBTA_GATTC_CB *p_cb, tBTA_GATTC_DATA *p_data) if ((p_buf = (tBTA_GATTC_INT_START_IF *) osi_malloc(sizeof(tBTA_GATTC_INT_START_IF))) != NULL) { p_buf->hdr.event = BTA_GATTC_INT_START_IF_EVT; p_buf->client_if = p_cb->cl_rcb[i].client_if; - APPL_TRACE_DEBUG("GATTC getbuf sucess.\n"); + APPL_TRACE_DEBUG("GATTC getbuf success.\n"); bta_sys_sendmsg(p_buf); status = BTA_GATT_OK; } else { @@ -841,6 +841,9 @@ void bta_gattc_close(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) (* p_cback)(BTA_GATTC_CLOSE_EVT, (tBTA_GATTC *)&cb_data); } + // Please note that BTA_GATTC_CLOSE_EVT will run in the BTC task. + // because bta_gattc_deregister_cmpl did not execute as expected(this is a known issue), + // we will run it again in bta_gattc_clcb_dealloc_by_conn_id. if (p_clreg->num_clcb == 0 && p_clreg->dereg_pending) { bta_gattc_deregister_cmpl(p_clreg); } @@ -1672,7 +1675,7 @@ void bta_gattc_fail(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) ** Returns void ** *******************************************************************************/ -static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg) +void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg) { tBTA_GATTC_CB *p_cb = &bta_gattc_cb; tBTA_GATTC_IF client_if = p_clreg->client_if; @@ -2118,7 +2121,7 @@ void bta_gattc_process_indicate(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_CL_COMPL bta_gattc_proc_other_indication(p_clcb, op, p_data, ¬ify); } } else if (op == GATTC_OPTYPE_INDICATION) { - /* no one intersted and need ack? */ + /* no one interested and need ack? */ APPL_TRACE_DEBUG("%s no one interested, ack now", __func__); GATTC_SendHandleValueConfirm(conn_id, handle); } @@ -2235,7 +2238,7 @@ static void bta_gattc_req_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYP ** ** Function bta_gattc_init_clcb_conn ** -** Description Initaite a BTA CLCB connection +** Description Initiate a BTA CLCB connection ** ** Returns void ** @@ -2252,7 +2255,7 @@ void bta_gattc_init_clcb_conn(UINT8 cif, BD_ADDR remote_bda) return; } - /* initaite a new connection here */ + /* initiate a new connection here */ if ((p_clcb = bta_gattc_clcb_alloc(cif, remote_bda, BTA_GATT_TRANSPORT_LE)) != NULL) { gattc_data.hdr.layer_specific = p_clcb->bta_conn_id = conn_id; diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c index 2265e28293c..b47a9d97334 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c @@ -160,7 +160,7 @@ UINT8 bta_gattc_num_reg_app(void) ** ** Function bta_gattc_find_clcb_by_cif ** -** Description get clcb by client interface and remote bd adddress +** Description get clcb by client interface and remote bd address ** ** Returns pointer to the clcb ** @@ -322,12 +322,18 @@ void bta_gattc_clcb_dealloc(tBTA_GATTC_CLCB *p_clcb) } } +extern void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB *p_clreg); void bta_gattc_clcb_dealloc_by_conn_id(UINT16 conn_id) { tBTA_GATTC_CLCB *p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); if (p_clcb) { + tBTA_GATTC_RCB *p_clreg = p_clcb->p_rcb; bta_gattc_clcb_dealloc(p_clcb); + // there is a workaround: if there is no connect, we will reset it. + if (p_clreg && p_clreg->num_clcb == 0 && p_clreg->dereg_pending) { + bta_gattc_deregister_cmpl(p_clreg); + } } } @@ -517,7 +523,7 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1); memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len); } else { - APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memery.", __func__, __LINE__); + APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__); return FALSE; } } else { @@ -525,7 +531,7 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) memset(cmd_data, 0, sizeof(tBTA_GATTC_DATA)); memcpy(cmd_data, p_data, sizeof(tBTA_GATTC_DATA)); } else { - APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memery.", __func__, __LINE__); + APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__); return FALSE; } } @@ -919,7 +925,7 @@ BOOLEAN bta_gattc_conn_dealloc(BD_ADDR remote_bda) ** ** Function bta_gattc_find_int_conn_clcb ** -** Description try to locate a clcb when an internal connecion event arrives. +** Description try to locate a clcb when an internal connection event arrives. ** ** Returns pointer to the clcb ** From 3f82f6e93b5093c3b8770763f9f10068f3526e24 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Thu, 25 Apr 2024 19:13:46 +0300 Subject: [PATCH 487/548] feat(esp_system): Print backtrace for both CPUs when cache error does not determine CPU --- .../esp_system/port/arch/xtensa/panic_arch.c | 1 + components/esp_system/port/panic_handler.c | 19 ++++++-- .../system/panic/main/include/test_panic.h | 4 ++ .../system/panic/main/test_app_main.c | 2 + .../test_apps/system/panic/main/test_panic.c | 43 +++++++++++++++++++ tools/test_apps/system/panic/pytest_panic.py | 36 ++++++++++++++++ 6 files changed, 101 insertions(+), 4 deletions(-) diff --git a/components/esp_system/port/arch/xtensa/panic_arch.c b/components/esp_system/port/arch/xtensa/panic_arch.c index feb128fa149..5c2dd2f9d9b 100644 --- a/components/esp_system/port/arch/xtensa/panic_arch.c +++ b/components/esp_system/port/arch/xtensa/panic_arch.c @@ -340,6 +340,7 @@ static inline void print_cache_err_details(const void *f) break; case EXTMEM_DCACHE_WRITE_FLASH_ST: panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n"); + panic_print_str("The following backtrace may not indicate the code that caused Cache invalid access\r\n"); break; case EXTMEM_MMU_ENTRY_FAULT_ST: vaddr = REG_READ(EXTMEM_CACHE_MMU_FAULT_VADDR_REG); diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index 4f27c1061d9..de55b1cd8ec 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -151,9 +151,20 @@ static void panic_handler(void *frame, bool pseudo_excause) busy_wait(); } else if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 && core_id == 0) { busy_wait(); - } else if (panic_get_cause(frame) == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()) { - g_exc_frames[core_id] = NULL; // Only print the backtrace for the offending core - busy_wait(); + } else if (panic_get_cause(frame) == PANIC_RSN_CACHEERR) { + // The invalid cache access interrupt calls to the panic handler. + // When the cache interrupt happens, we can not determine the CPU where the + // invalid cache access has occurred. + if (esp_cache_err_get_cpuid() == -1) { + // We can not determine the CPU where the invalid cache access has occurred. + // Print backtraces for both CPUs. + if (core_id != 0) { + busy_wait(); + } + } else if (core_id != esp_cache_err_get_cpuid()) { + g_exc_frames[core_id] = NULL; // Only print the backtrace for the offending core + busy_wait(); + } } #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD else if (panic_get_cause(frame) == ETS_ASSIST_DEBUG_INUM && @@ -183,7 +194,7 @@ static void panic_handler(void *frame, bool pseudo_excause) #if __XTENSA__ if (!(esp_ptr_executable(esp_cpu_pc_to_addr(panic_get_address(frame))) && (panic_get_address(frame) & 0xC0000000U))) { /* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size - * Incase the PC is invalid, GDB will fail to translate addresses to function names + * In case the PC is invalid, GDB will fail to translate addresses to function names * Hence replacing the PC to a placeholder address in case of invalid PC */ panic_set_address(frame, (uint32_t)&_invalid_pc_placeholder); diff --git a/tools/test_apps/system/panic/main/include/test_panic.h b/tools/test_apps/system/panic/main/include/test_panic.h index 6454d9db824..64dd22a5bc7 100644 --- a/tools/test_apps/system/panic/main/include/test_panic.h +++ b/tools/test_apps/system/panic/main/include/test_panic.h @@ -59,6 +59,10 @@ void test_assert(void); void test_assert_cache_disabled(void); +void test_assert_cache_write_back_error_can_print_backtrace(void); + +void test_assert_cache_write_back_error_can_print_backtrace2(void); + void test_illegal_access(void); void test_capture_dram(void); diff --git a/tools/test_apps/system/panic/main/test_app_main.c b/tools/test_apps/system/panic/main/test_app_main.c index df1a35ba202..f1da4f2fd50 100644 --- a/tools/test_apps/system/panic/main/test_app_main.c +++ b/tools/test_apps/system/panic/main/test_app_main.c @@ -114,6 +114,8 @@ void app_main(void) HANDLE_TEST(test_name, test_ub); HANDLE_TEST(test_name, test_assert); HANDLE_TEST(test_name, test_assert_cache_disabled); + HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace); + HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace2); #if CONFIG_IDF_TARGET_ESP32 HANDLE_TEST(test_name, test_illegal_access); #endif diff --git a/tools/test_apps/system/panic/main/test_panic.c b/tools/test_apps/system/panic/main/test_panic.c index 2e1e47aca33..982049c07bf 100644 --- a/tools/test_apps/system/panic/main/test_panic.c +++ b/tools/test_apps/system/panic/main/test_panic.c @@ -7,10 +7,12 @@ #include #include #include +#include #include "esp_partition.h" #include "esp_flash.h" #include "esp_system.h" +#include "spi_flash_mmap.h" #include "esp_private/cache_utils.h" #include "esp_memory_utils.h" @@ -20,6 +22,7 @@ #include "freertos/task.h" #include "hal/mpu_hal.h" +#include "rom/cache.h" /* Test utility function */ @@ -177,6 +180,46 @@ void IRAM_ATTR test_assert_cache_disabled(void) assert(0); } +const char TEST_STR[] = "my_tag"; +void test_assert_cache_write_back_error_can_print_backtrace(void) +{ + printf("1) %p\n", TEST_STR); + *(uint32_t*)TEST_STR = 3; // We changed the rodata string. + // All chips except ESP32S3 stop execution here and raise a LoadStore error on the line above. +#if CONFIG_IDF_TARGET_ESP32S3 + // On the ESP32S3, the error occurs later when the cache writeback is triggered + // (in this test, a direct call to Cache_WriteBack_All). + Cache_WriteBack_All(); // Cache writeback triggers the invalid cache access interrupt. +#endif + // We are testing that the backtrace is printed instead of TG1WDT. + printf("2) %p\n", TEST_STR); // never get to this place. +} + +void test_assert_cache_write_back_error_can_print_backtrace2(void) +{ + printf("1) %p\n", TEST_STR); + *(uint32_t*)TEST_STR = 3; // We changed the rodata string. + // All chips except ESP32S3 stop execution here and raise a LoadStore error on the line above. + // On the ESP32S3, the error occurs later when the cache writeback is triggered + // (in this test, a large range of DRAM is mapped and read, causing an error). + uint8_t temp = 0; + size_t map_size = SPI_FLASH_SEC_SIZE * 512; + const void *map; + spi_flash_mmap_handle_t out_handle; + esp_err_t err = spi_flash_mmap(0, map_size, SPI_FLASH_MMAP_DATA, &map, &out_handle); + if (err != ESP_OK) { + printf("spi_flash_mmap failed %x\n", err); + return; + } + const uint8_t *rodata = map; + for (size_t i = 0; i < map_size; i++) { + temp = rodata[i]; + } + // Cache writeback triggers the invalid cache access interrupt. + // We are testing that the backtrace is printed instead of TG1WDT. + printf("2) %p 0x%" PRIx8 " \n", TEST_STR, temp); // never get to this place. +} + /** * This function overwrites the stack beginning from the valid area continuously towards and beyond * the end of the stack (stack base) of the current task. diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index 8e1315fca33..b83105b76f6 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -533,6 +533,42 @@ def test_assert_cache_disabled( ) +def cache_error_log_check(dut: PanicTestDut) -> None: + if dut.is_xtensa: + if dut.target == 'esp32s3': + dut.expect_exact("Guru Meditation Error: Core / panic'ed (Cache disabled but cached memory region accessed)") + dut.expect_exact('Write back error occurred while dcache tries to write back to flash') + dut.expect_exact('The following backtrace may not indicate the code that caused Cache invalid access') + else: + dut.expect_exact("Guru Meditation Error: Core 0 panic'ed (LoadStoreError)") + else: + dut.expect_exact("Guru Meditation Error: Core 0 panic'ed (Store access fault)") + dut.expect_reg_dump(0) + if dut.target == 'esp32s3': + dut.expect_reg_dump(1) + dut.expect_cpu_reset() + + +@pytest.mark.generic +@pytest.mark.supported_targets +@pytest.mark.parametrize('config', ['panic'], indirect=True) +def test_assert_cache_write_back_error_can_print_backtrace( + dut: PanicTestDut, config: str, test_func_name: str +) -> None: + dut.run_test_func(test_func_name) + cache_error_log_check(dut) + + +@pytest.mark.generic +@pytest.mark.supported_targets +@pytest.mark.parametrize('config', ['panic'], indirect=True) +def test_assert_cache_write_back_error_can_print_backtrace2( + dut: PanicTestDut, config: str, test_func_name: str +) -> None: + dut.run_test_func(test_func_name) + cache_error_log_check(dut) + + @pytest.mark.esp32 @pytest.mark.generic @pytest.mark.parametrize('config', ['panic_delay'], indirect=True) From ca967c9f96eaf48ed854c6f15b576e343933cabc Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Mon, 29 Apr 2024 20:07:33 +1000 Subject: [PATCH 488/548] fix(lwip): Fixed compilation error referencing undefined POSIX interface API Closes https://github.com/espressif/esp-idf/issues/13577 --- components/lwip/CMakeLists.txt | 4 ++++ components/lwip/port/if_index.c | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 components/lwip/port/if_index.c diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index d0526fd4bad..44858861535 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -102,6 +102,10 @@ if(CONFIG_LWIP_ENABLE) "port/sockets_ext.c" "port/freertos/sys_arch.c") + if(CONFIG_LWIP_NETIF_API) + list(APPEND srcs "port/if_index.c") + endif() + if(CONFIG_LWIP_PPP_SUPPORT) list(APPEND srcs "lwip/src/netif/ppp/auth.c" diff --git a/components/lwip/port/if_index.c b/components/lwip/port/if_index.c new file mode 100644 index 00000000000..d7dcf25e717 --- /dev/null +++ b/components/lwip/port/if_index.c @@ -0,0 +1,17 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "lwip/if_api.h" + +unsigned int if_nametoindex(const char *ifname) +{ + return lwip_if_nametoindex(ifname); +} + +char *if_indextoname(unsigned int ifindex, char *ifname) +{ + return lwip_if_indextoname(ifindex, ifname); +} From ae0a230843091654553f5bff01f350bf80f9b2ae Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 6 Jun 2024 19:20:19 +0000 Subject: [PATCH 489/548] feat(tools): update qemu version to esp_develop_9.0.0_20240606 --- tools/tools.json | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index 5b90890fc0e..09e6053d6fc 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -896,31 +896,31 @@ "versions": [ { "linux-amd64": { - "sha256": "e7c72ef5705ad1444d391711088c8717fc89f42e9bf6d1487f9c2a326b8cfa83", - "size": 14714724, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-xtensa-softmmu-esp_develop_8.2.0_20240122-x86_64-linux-gnu.tar.xz" + "sha256": "071d117c44a6e9a1bc8664ab63b592d3e17ceb779119dcb46c59571a4a7a88c9", + "size": 13611248, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-xtensa-softmmu-esp_develop_9.0.0_20240606-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "77c83f2772f7d9b0c770722c2cebf3625d21d8eddbccfea6816f3d8f4982ea86", - "size": 14239876, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-xtensa-softmmu-esp_develop_8.2.0_20240122-aarch64-linux-gnu.tar.xz" + "sha256": "43552f32b303a6820d0d9551903e54fc221aca98ccbd04e5cbccbca881548008", + "size": 15247720, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-xtensa-softmmu-esp_develop_9.0.0_20240606-aarch64-linux-gnu.tar.xz" }, "macos": { - "sha256": "897126a12aeac1cc7d8e9a50626cdf0bc4812fd4bceb77b07ff4a81b86deaaa4", - "size": 3379992, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-xtensa-softmmu-esp_develop_8.2.0_20240122-x86_64-apple-darwin.tar.xz" + "sha256": "0096734280ce04f558cd9bd72f35db39667f80d44309a35565f2f8c02d1f9cc3", + "size": 3707956, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-xtensa-softmmu-esp_develop_9.0.0_20240606-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "9134f6dc653c6dd556a6c9c2d80b9eca0c437a8f625e994f9285aadf7b2e7d6f", - "size": 3200756, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-xtensa-softmmu-esp_develop_8.2.0_20240122-aarch64-apple-darwin.tar.xz" + "sha256": "fb4ca6be7b1a4dbcf153879cf0582300f974371def0826c0c5b728f12812ad08", + "size": 3456764, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-xtensa-softmmu-esp_develop_9.0.0_20240606-aarch64-apple-darwin.tar.xz" }, - "name": "esp_develop_8.2.0_20240122", + "name": "esp_develop_9.0.0_20240606", "status": "recommended", "win64": { - "sha256": "fc49844b506697542558d3fcb2fe64171b3d28f47e59000ebe8e198d32091d45", - "size": 32225200, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-xtensa-softmmu-esp_develop_8.2.0_20240122-x86_64-w64-mingw32.tar.xz" + "sha256": "281659f7a1d49761ac6f54d0aeb14366cb93c002f21948b847a0e15c0b8f5425", + "size": 33957256, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-xtensa-softmmu-esp_develop_9.0.0_20240606-x86_64-w64-mingw32.tar.xz" } } ] @@ -949,31 +949,31 @@ "versions": [ { "linux-amd64": { - "sha256": "95ac86d7b53bf98b5ff19c33aa926189b849f5a0daf8f41e160bc86c5e31abd4", - "size": 16275380, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-x86_64-linux-gnu.tar.xz" + "sha256": "47120e826cfec7180db8cb611a7a4aed2e9b2191c2a739194f8ce085e63cdd8d", + "size": 14454468, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-riscv32-softmmu-esp_develop_9.0.0_20240606-x86_64-linux-gnu.tar.xz" }, "linux-arm64": { - "sha256": "4089f7958f753779e5b4c93fe2469d62850a1f209b0bda8b75d55fe4a61ca39b", - "size": 15796904, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-aarch64-linux-gnu.tar.xz" + "sha256": "3b6221a8b1881d2c9b9fa0b0bf8d7065c84153d2a54e429307bde9feae235c27", + "size": 16542756, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-riscv32-softmmu-esp_develop_9.0.0_20240606-aarch64-linux-gnu.tar.xz" }, "macos": { - "sha256": "e9cc3c1344f6bf1ffa3748a4c59d88f9005c2689cc0583458cea35409a73c923", - "size": 3502440, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-x86_64-apple-darwin.tar.xz" + "sha256": "3afa55d5abea52ccf18d0bc41fe819d568bd4ee1582989b1ee9b1ee4a609a31e", + "size": 3751096, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-riscv32-softmmu-esp_develop_9.0.0_20240606-x86_64-apple-darwin.tar.xz" }, "macos-arm64": { - "sha256": "b3f23e294cf325f92e5e8948583cc985d55d5d2ba3d79c04c9d09f080b62954d", - "size": 3219984, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-aarch64-apple-darwin.tar.xz" + "sha256": "69ba5154594fb2922d5490a49ea6b4925c024c6c37f875b42f9885f513e0bcdd", + "size": 3409264, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-riscv32-softmmu-esp_develop_9.0.0_20240606-aarch64-apple-darwin.tar.xz" }, - "name": "esp_develop_8.2.0_20240122", + "name": "esp_develop_9.0.0_20240606", "status": "recommended", "win64": { - "sha256": "36008768c7ce91927e73de5e4298625087c01208e6122d886e578d400fd93b5c", - "size": 35229220, - "url": "https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-x86_64-w64-mingw32.tar.xz" + "sha256": "f49bb5c8f4d6e2cfbf7eeec21eb8ef190a57307778705bc689536ac13bde511c", + "size": 36274632, + "url": "https://github.com/espressif/qemu/releases/download/esp-develop-9.0.0-20240606/qemu-riscv32-softmmu-esp_develop_9.0.0_20240606-x86_64-w64-mingw32.tar.xz" } } ] From 4168fa28f4f40b4b2a677355a6b8432459a3ad68 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 6 Jun 2024 21:22:51 +0200 Subject: [PATCH 490/548] feat(esp_eth): enable openeth in QEMU for ESP32-S3 --- components/esp_eth/src/openeth/esp_openeth.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/components/esp_eth/src/openeth/esp_openeth.h b/components/esp_eth/src/openeth/esp_openeth.h index 5eb13d57776..2aab7410c1b 100644 --- a/components/esp_eth/src/openeth/esp_openeth.h +++ b/components/esp_eth/src/openeth/esp_openeth.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,17 +8,12 @@ #include "sdkconfig.h" #include "soc/interrupts.h" -#if CONFIG_IDF_TARGET_ESP32C3 - -/** - * @brief Since ESP32-C3 target in QEMU doesn't support Wifi, reuse its interrupt source for ethernet +/* + * For targets which don't have an ethernet MAC and the associated interrupt source, + * we can reuse the Wifi interrupt source for ethernet, since QEMU doesn't emulate Wifi (yet). + * We also map the EMAC registers to an unused address range. */ +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 #define ETS_ETH_MAC_INTR_SOURCE ETS_WIFI_MAC_INTR_SOURCE - - -/** - * @brief Use an empty I/O range for the ethernet registers - */ #define DR_REG_EMAC_BASE 0x600CD000 - -#endif // CONFIG_IDF_TARGET_ESP32C3 +#endif From acb201e5b2497846a440a2039f6abe03dbe319fe Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 6 Jun 2024 21:24:23 +0200 Subject: [PATCH 491/548] feat(tools): enable idf.py qemu integration for ESP32-S3 --- tools/idf_py_actions/qemu_ext.py | 39 ++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/tools/idf_py_actions/qemu_ext.py b/tools/idf_py_actions/qemu_ext.py index 27797e087a8..6bd38426237 100644 --- a/tools/idf_py_actions/qemu_ext.py +++ b/tools/idf_py_actions/qemu_ext.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import atexit import binascii @@ -10,7 +10,9 @@ import sys import time from dataclasses import dataclass -from typing import Any, Dict, List +from typing import Any +from typing import Dict +from typing import List from click.core import Context @@ -90,6 +92,39 @@ class QemuTarget: '00000000000000000000000000000000000000000000000000000000000000000000000000000000' '00000000000000000000000000000000000000000000000000000000000000000000000000000000' '000000000000000000000000000000000000000000000000')), + 'esp32s3': QemuTarget( + 'esp32s3', + 'qemu-system-xtensa', + 'qemu-xtensa', + '-M esp32s3', + # Chip revision 0.3 + binascii.unhexlify( + '00000000000000000000000000000000000000000000000000000000000000000000000000000c00' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000000000000000000000000' + '000000000000000000000000000000000000000000000000')), } From 9e38f78ea2210fc162c1475353d66792a22fccd1 Mon Sep 17 00:00:00 2001 From: wanlei Date: Fri, 12 Apr 2024 17:42:32 +0800 Subject: [PATCH 492/548] fix(spi_slave_hd): fix seg mode potential iwdt timeout when multi task call --- .../esp_driver_spi/src/gpspi/spi_slave_hd.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c index 22a53255cff..c9518d70826 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave_hd.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave_hd.c @@ -51,8 +51,8 @@ typedef struct { QueueHandle_t tx_ret_queue; QueueHandle_t rx_trans_queue; QueueHandle_t rx_ret_queue; - QueueHandle_t tx_cnting_sem; - QueueHandle_t rx_cnting_sem; + SemaphoreHandle_t tx_cnting_sem; + SemaphoreHandle_t rx_cnting_sem; spi_slave_hd_trans_priv_t tx_curr_trans; spi_slave_hd_trans_priv_t rx_curr_trans; @@ -335,16 +335,14 @@ static IRAM_ATTR void spi_slave_hd_intr_segment(void *arg) awoken |= intr_check_clear_callback(host, SPI_EV_CMD9, callback->cb_cmd9); awoken |= intr_check_clear_callback(host, SPI_EV_CMDA, callback->cb_cmdA); - bool tx_done = false; - bool rx_done = false; + bool tx_done = false, rx_done = false; + bool tx_event = false, rx_event = false; portENTER_CRITICAL_ISR(&host->int_spinlock); - if (host->tx_curr_trans.trans && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_SEND)) { - tx_done = true; - } - if (host->rx_curr_trans.trans && spi_slave_hd_hal_check_disable_event(hal, SPI_EV_RECV)) { - rx_done = true; - } + tx_event = spi_slave_hd_hal_check_disable_event(hal, SPI_EV_SEND); + rx_event = spi_slave_hd_hal_check_disable_event(hal, SPI_EV_RECV); + tx_done = host->tx_curr_trans.trans && tx_event; + rx_done = host->rx_curr_trans.trans && rx_event; portEXIT_CRITICAL_ISR(&host->int_spinlock); if (tx_done) { From 5b4b867a9ce965749b0cf2cd81915c447918d2b5 Mon Sep 17 00:00:00 2001 From: Myk Melez Date: Wed, 26 Jun 2024 15:34:23 -0700 Subject: [PATCH 493/548] fix(pthread): Remove TLS pointer/deletion callback from correct thread Originally, pthread_internal_local_storage_destructor_callback was only called from pthread_exit on the thread whose TLS is being destroyed. In b3755b751ed42d98c933a919c744dc6455f5ee68, pthread_internal_local_storage_destructor_callback started being called from pthread_join and pthread_detach on a different thread (whichever one called one of those functions). But pthread_internal_local_storage_destructor_callback is still calling vTaskSetThreadLocalStoragePointer and vTaskSetThreadLocalStoragePointerAndDelCallback with a NULL xTaskToSet argument, which causes those functions to set the TLS pointer and deletion callback for the current thread, not the thread whose TLS is being destroyed. This commit makes pthread_internal_local_storage_destructor_callback call vTaskSetThreadLocalStoragePointer and vTaskSetThreadLocalStoragePointerAndDelCallback with the handle of the thread whose TLS is being destroyed. --- components/pthread/pthread_local_storage.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/pthread/pthread_local_storage.c b/components/pthread/pthread_local_storage.c index 19cb73a98d8..80b562edb53 100644 --- a/components/pthread/pthread_local_storage.c +++ b/components/pthread/pthread_local_storage.c @@ -147,7 +147,9 @@ static void pthread_cleanup_thread_specific_data_callback(int index, void *v_tls free(tls); } -/* this function called from pthread_task_func for "early" cleanup of TLS in a pthread */ +/* this function called from pthread_task_func for "early" cleanup of TLS in a pthread + and from pthread_join/pthread_detach for cleanup of TLS after pthread exit +*/ void pthread_internal_local_storage_destructor_callback(TaskHandle_t handle) { void *tls = pvTaskGetThreadLocalStoragePointer(handle, PTHREAD_TLS_INDEX); @@ -157,9 +159,9 @@ void pthread_internal_local_storage_destructor_callback(TaskHandle_t handle) calling it again... */ #if !defined(CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS) - vTaskSetThreadLocalStoragePointer(NULL, PTHREAD_TLS_INDEX, NULL); + vTaskSetThreadLocalStoragePointer(handle, PTHREAD_TLS_INDEX, NULL); #else - vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, + vTaskSetThreadLocalStoragePointerAndDelCallback(handle, PTHREAD_TLS_INDEX, NULL, NULL); From e03435898314fea13f094c99d3903aef9d186e1e Mon Sep 17 00:00:00 2001 From: zwx Date: Wed, 3 Jul 2024 15:07:18 +0800 Subject: [PATCH 494/548] fix(esp_netif): netif should return only valid addr --- components/esp_netif/lwip/esp_netif_lwip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_netif/lwip/esp_netif_lwip.c b/components/esp_netif/lwip/esp_netif_lwip.c index 4f1b2903b8a..bf5560f4964 100644 --- a/components/esp_netif/lwip/esp_netif_lwip.c +++ b/components/esp_netif/lwip/esp_netif_lwip.c @@ -2152,7 +2152,7 @@ int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[]) if (p_netif != NULL && netif_is_up(p_netif)) { for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (!ip_addr_cmp(&p_netif->ip6_addr[i], IP6_ADDR_ANY)) { + if (ip6_addr_isvalid(netif_ip6_addr_state(p_netif, i)) && !ip_addr_cmp(&p_netif->ip6_addr[i], IP6_ADDR_ANY)) { memcpy(&if_ip6[addr_count++], &p_netif->ip6_addr[i], sizeof(ip6_addr_t)); } } From 6b83cc254df493b638cb1c5b578bd1c18f6241c2 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Wed, 5 Jun 2024 08:04:44 +0200 Subject: [PATCH 495/548] fix(esp_netif): Fix missing IPv6 autoconfig for PPP netifs Closes https://github.com/espressif/esp-idf/issues/13713 --- components/esp_netif/lwip/esp_netif_lwip_ppp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/esp_netif/lwip/esp_netif_lwip_ppp.c b/components/esp_netif/lwip/esp_netif_lwip_ppp.c index db5e9f44f5e..7e4a61a17f3 100644 --- a/components/esp_netif/lwip/esp_netif_lwip_ppp.c +++ b/components/esp_netif/lwip/esp_netif_lwip_ppp.c @@ -165,7 +165,7 @@ static void on_ppp_notify_phase(ppp_pcb *pcb, u8_t phase, void *ctx) #endif // PPP_NOTIFY_PHASE /** - * @brief PPP low level output callback used to transmit data using standard esp-netif interafce + * @brief PPP low level output callback used to transmit data using standard esp-netif interface * * @param pcb PPP control block * @param data Buffer to write to serial port @@ -263,6 +263,10 @@ esp_err_t esp_netif_start_ppp(esp_netif_t *esp_netif) } #endif // CONFIG_LWIP_PPP_SERVER_SUPPORT +#if ESP_IPV6_AUTOCONFIG + ppp_ctx->ppp->netif->ip6_autoconfig_enabled = 1; +#endif + ESP_LOGD(TAG, "%s: Starting PPP connection: %p", __func__, ppp_ctx->ppp); #ifdef CONFIG_LWIP_PPP_SERVER_SUPPORT esp_err_t err = ppp_listen(ppp_ctx->ppp); From ec130b0a6430b19a6b9c9ec7a80d91baf8a314d3 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Mon, 5 Feb 2024 20:03:40 +0800 Subject: [PATCH 496/548] fix(usb_otg): Fix bug that usb_otg console cannot work on esp32s3 --- components/esp_system/port/cpu_start.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index cdfd523063e..61d5238adf8 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -219,7 +219,7 @@ void IRAM_ATTR call_start_cpu1(void) #if CONFIG_ESP_CONSOLE_NONE esp_rom_install_channel_putc(1, NULL); esp_rom_install_channel_putc(2, NULL); -#else // CONFIG_ESP_CONSOLE_NONE +#elif !CONFIG_ESP_CONSOLE_USB_CDC esp_rom_install_uart_printf(); esp_rom_output_set_as_console(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM); #endif From 3e4fcf66ef396fc0587af898721f3920674e86c0 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Tue, 23 Jul 2024 16:19:24 +0200 Subject: [PATCH 497/548] fix(freertos): Fixed memory leak issue in vTaskDeleteWithCaps() vTaskDeleteWithCaps() leaked memory when a task uses the API to delete itself. This commit adds a fix to avoid the memory leak. Closes https://github.com/espressif/esp-idf/issues/14222 --- .../linux/include/freertos/portmacro.h | 8 +- .../linux/include/freertos/portmacro_idf.h | 13 +- .../freertos/esp_additions/idf_additions.c | 131 ++++++++++++++++-- .../include/freertos/idf_additions.h | 5 + .../freertos/misc/test_idf_additions.c | 65 ++++++++- 5 files changed, 207 insertions(+), 15 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h index f4ee05e14e9..02cbdedada7 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/linux/include/freertos/portmacro.h @@ -244,6 +244,12 @@ static inline BaseType_t xPortInIsrContext(void) return xPortCheckIfInISR(); } +static inline void vPortAssertIfInISR(void) +{ + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortInIsrContext() == 0); +} + // xPortInterruptedFromISRContext() is only used in panic handler and core dump, // both probably not relevant on POSIX sim. //BaseType_t xPortInterruptedFromISRContext(void); @@ -301,7 +307,7 @@ extern void vPortCancelThread( void *pxTaskToDelete ); * are always a full memory barrier. ISRs are emulated as signals * which also imply a full memory barrier. * - * Thus, only a compilier barrier is needed to prevent the compiler + * Thus, only a compiler barrier is needed to prevent the compiler * reordering. */ #define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" ) diff --git a/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h b/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h index a4b75c066a5..bff384a77db 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h +++ b/components/freertos/FreeRTOS-Kernel/portable/linux/include/freertos/portmacro_idf.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -104,6 +104,17 @@ static inline BaseType_t xPortInIsrContext(void) return xPortCheckIfInISR(); } +static inline void vPortAssertIfInISR(void) +{ + /* Assert if the interrupt nesting count is > 0 */ + configASSERT(xPortInIsrContext() == 0); +} + +/** + * @brief Assert if in ISR context + */ +#define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + #if CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP /* If enabled, users must provide an implementation of vPortCleanUpTCB() */ extern void vPortCleanUpTCB ( void *pxTCB ); diff --git a/components/freertos/esp_additions/idf_additions.c b/components/freertos/esp_additions/idf_additions.c index 4bd428981f6..ee02e838cc4 100644 --- a/components/freertos/esp_additions/idf_additions.c +++ b/components/freertos/esp_additions/idf_additions.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,8 @@ #include "freertos/timers.h" #include "freertos/idf_additions.h" #include "esp_heap_caps.h" +#include "esp_log.h" +#include "freertos/portmacro.h" /* -------------------------------------------- Creation With Memory Caps ------------------------------------------- */ @@ -81,21 +83,128 @@ #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + static void prvTaskDeleteWithCapsTask( void * pvParameters ) + { + TaskHandle_t xTaskToDelete = ( TaskHandle_t ) pvParameters; + + /* The task to be deleted must not be running */ + configASSERT( eRunning != eTaskGetState( xTaskToDelete ) ); + + /* Delete the WithCaps task */ + vTaskDeleteWithCaps( xTaskToDelete ); + + /* Delete the temporary clean up task */ + vTaskDelete( NULL ); + } + void vTaskDeleteWithCaps( TaskHandle_t xTaskToDelete ) { - BaseType_t xResult; - StaticTask_t * pxTaskBuffer; - StackType_t * puxStackBuffer; + /* THIS FUNCTION SHOULD NOT BE CALLED FROM AN INTERRUPT CONTEXT. */ + /*TODO: Update it to use portASSERT_IF_IN_ISR() instead. (IDF-10540) */ + vPortAssertIfInISR(); - xResult = xTaskGetStaticBuffers( xTaskToDelete, &puxStackBuffer, &pxTaskBuffer ); - configASSERT( xResult == pdTRUE ); + TaskHandle_t xCurrentTaskHandle = xTaskGetCurrentTaskHandle(); + configASSERT( xCurrentTaskHandle != NULL ); - /* Delete the task */ - vTaskDelete( xTaskToDelete ); + if( ( xTaskToDelete == NULL ) || ( xTaskToDelete == xCurrentTaskHandle ) ) + { + /* The WithCaps task is deleting itself. While, the task can put itself on the + * xTasksWaitingTermination list via the vTaskDelete() call, the idle + * task will not free the task TCB and stack memories we created statically + * during xTaskCreateWithCaps() or xTaskCreatePinnedToCoreWithCaps(). This + * task will never be rescheduled once it is on the xTasksWaitingTermination + * list and will not be able to clear the memories. Therefore, it will leak memory. + * + * To avoid this, we create a new "temporary clean up" task to delete the current task. + * This task is created at the priority of the task to be deleted with the same core + * affitinty. Its limited purpose is to delete the self-deleting task created WithCaps. + * + * This approach has the following problems - + * 1. Once a WithCaps task deletes itself via vTaskDeleteWithCaps(), it may end up in the + * suspended tasks lists for a short time before being deleted. This can give an incorrect + * picture about the system state. + * + * 2. This approach is wasteful and can be error prone. The temporary clean up task will need + * system resources to get scheduled and cleanup the WithCaps task. It can be a problem if the system + * has several self-deleting WithCaps tasks. + * + * TODO: A better approach could be either - + * + * 1. Delegate memory management to the application/user. This way the kernel needn't bother about freeing + * the memory (like other static memory task creation APIs like xTaskCreateStatic()) (IDF-10521) + * + * 2. Have a post deletion hook/callback from the IDLE task to notify higher layers when it is safe to + * perform activities such as clearing up the TCB and stack memories. (IDF-10522) */ + if( xTaskCreatePinnedToCore( ( TaskFunction_t ) prvTaskDeleteWithCapsTask, "prvTaskDeleteWithCapsTask", configMINIMAL_STACK_SIZE, xCurrentTaskHandle, uxTaskPriorityGet( xTaskToDelete ), NULL, xPortGetCoreID() ) != pdFAIL ) + { + /* Although the current task should get preemted immediately when prvTaskDeleteWithCapsTask is created, + * for safety, we suspend the current task and wait for prvTaskDeleteWithCapsTask to delete it. */ + vTaskSuspend( xTaskToDelete ); + + /* Should never reach here */ + ESP_LOGE( "freertos_additions", "%s: Failed to suspend the task to be deleted", __func__ ); + abort(); + } + else + { + /* Failed to create the task to delete the current task. */ + ESP_LOGE( "freertos_additions", "%s: Failed to create the task to delete the current task", __func__ ); + abort(); + } + } - /* Free the memory buffers */ - heap_caps_free( puxStackBuffer ); - vPortFree( pxTaskBuffer ); + #if ( configNUM_CORES > 1 ) + else if( eRunning == eTaskGetState( xTaskToDelete ) ) + { + /* The WithCaps task is running on another core. + * We suspend the task first and then delete it. */ + vTaskSuspend( xTaskToDelete ); + + /* Wait for the task to be suspended */ + while( eRunning == eTaskGetState( xTaskToDelete ) ) + { + portYIELD_WITHIN_API(); + } + + BaseType_t xResult; + StaticTask_t * pxTaskBuffer; + StackType_t * puxStackBuffer; + + xResult = xTaskGetStaticBuffers( xTaskToDelete, &puxStackBuffer, &pxTaskBuffer ); + configASSERT( xResult == pdTRUE ); + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); + + /* Delete the task */ + vTaskDelete( xTaskToDelete ); + + /* Free the memory buffers */ + heap_caps_free( puxStackBuffer ); + vPortFree( pxTaskBuffer ); + } + #endif /* if ( configNUM_CORES > 1 ) */ + else + { + /* The WithCaps task is not running and is being deleted + * from another task's context. */ + configASSERT( eRunning != eTaskGetState( xTaskToDelete ) ); + + BaseType_t xResult; + StaticTask_t * pxTaskBuffer; + StackType_t * puxStackBuffer; + + xResult = xTaskGetStaticBuffers( xTaskToDelete, &puxStackBuffer, &pxTaskBuffer ); + configASSERT( xResult == pdTRUE ); + configASSERT( puxStackBuffer != NULL ); + configASSERT( pxTaskBuffer != NULL ); + + /* We can delete the task and free the memory buffers. */ + vTaskDelete( xTaskToDelete ); + + /* Free the memory buffers */ + heap_caps_free( puxStackBuffer ); + vPortFree( pxTaskBuffer ); + } /* if( ( xTaskToDelete == NULL ) || ( xTaskToDelete == xCurrentTaskHandle ) ) */ } #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ diff --git a/components/freertos/esp_additions/include/freertos/idf_additions.h b/components/freertos/esp_additions/include/freertos/idf_additions.h index b9fb9c47a08..5e50dd1ba3c 100644 --- a/components/freertos/esp_additions/include/freertos/idf_additions.h +++ b/components/freertos/esp_additions/include/freertos/idf_additions.h @@ -339,6 +339,11 @@ uint8_t * pxTaskGetStackStart( TaskHandle_t xTask ); * @brief Deletes a task previously created using xTaskCreateWithCaps() or * xTaskCreatePinnedToCoreWithCaps() * + * @note It is recommended to use this API to delete tasks from another task's + * context, rather than self-deletion. When the task is being deleted, it is vital + * to ensure that it is not running on another core. This API must not be called + * from an interrupt context. + * * @param xTaskToDelete A handle to the task to be deleted */ void vTaskDeleteWithCaps( TaskHandle_t xTaskToDelete ); diff --git a/components/freertos/test_apps/freertos/misc/test_idf_additions.c b/components/freertos/test_apps/freertos/misc/test_idf_additions.c index aea2ecb2f8e..ced4941398c 100644 --- a/components/freertos/test_apps/freertos/misc/test_idf_additions.c +++ b/components/freertos/test_apps/freertos/misc/test_idf_additions.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,7 +43,17 @@ static void task_with_caps(void *arg) vTaskSuspend(NULL); } -TEST_CASE("IDF additions: Task creation with memory caps", "[freertos]") +static void task_with_caps_self_delete(void *arg) +{ + /* Wait for the unity task to indicate that this task should delete itself */ + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + /* Although it is not recommended to self-delete a task with memory caps but this + * is done intentionally to test for memory leaks */ + vTaskDeleteWithCaps(NULL); +} + +TEST_CASE("IDF additions: Task creation with memory caps and deletion from another task", "[freertos]") { TaskHandle_t task_handle = NULL; StackType_t *puxStackBuffer; @@ -62,6 +72,57 @@ TEST_CASE("IDF additions: Task creation with memory caps", "[freertos]") vTaskDeleteWithCaps(task_handle); } +TEST_CASE("IDF additions: Task creation with memory caps and self deletion", "[freertos]") +{ + TaskHandle_t task_handle = NULL; + StackType_t *puxStackBuffer; + StaticTask_t *pxTaskBuffer; + + // Create a task with caps + TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCoreWithCaps(task_with_caps_self_delete, "task", 4096, (void *)xTaskGetCurrentTaskHandle(), UNITY_FREERTOS_PRIORITY + 1, &task_handle, UNITY_FREERTOS_CPU, OBJECT_MEMORY_CAPS)); + TEST_ASSERT_NOT_EQUAL(NULL, task_handle); + // Get the task's memory + TEST_ASSERT_EQUAL(pdTRUE, xTaskGetStaticBuffers(task_handle, &puxStackBuffer, &pxTaskBuffer)); + TEST_ASSERT(esp_ptr_in_dram(puxStackBuffer)); + TEST_ASSERT(esp_ptr_in_dram(pxTaskBuffer)); + // Notify the task to delete itself + xTaskNotifyGive(task_handle); +} + +#if ( CONFIG_FREERTOS_NUMBER_OF_CORES > 1 ) + +static void task_with_caps_running_on_other_core(void *arg) +{ + /* Notify the unity task that this task is running on the other core */ + xTaskNotifyGive((TaskHandle_t)arg); + + /* We make sure that this task is running on the other core */ + while (1) { + ; + } +} + +TEST_CASE("IDF additions: Task creation with memory caps and deletion from another core", "[freertos]") +{ + TaskHandle_t task_handle = NULL; + StackType_t *puxStackBuffer; + StaticTask_t *pxTaskBuffer; + + // Create a task with caps on the other core + TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCoreWithCaps(task_with_caps_running_on_other_core, "task", 4096, (void *)xTaskGetCurrentTaskHandle(), UNITY_FREERTOS_PRIORITY + 1, &task_handle, !UNITY_FREERTOS_CPU, OBJECT_MEMORY_CAPS)); + TEST_ASSERT_NOT_EQUAL(NULL, task_handle); + // Get the task's memory + TEST_ASSERT_EQUAL(pdTRUE, xTaskGetStaticBuffers(task_handle, &puxStackBuffer, &pxTaskBuffer)); + TEST_ASSERT(esp_ptr_in_dram(puxStackBuffer)); + TEST_ASSERT(esp_ptr_in_dram(pxTaskBuffer)); + // Wait for the created task to start running + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + // Delete the task from another core + vTaskDeleteWithCaps(task_handle); +} + +#endif // CONFIG_FREERTOS_NUMBER_OF_CORES > 1 + TEST_CASE("IDF additions: Queue creation with memory caps", "[freertos]") { QueueHandle_t queue_handle; From 3fc2c00dabcd0249a521855097fe335974d51b34 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 12 Jul 2024 16:07:16 +0800 Subject: [PATCH 498/548] fix(parlio): fix cache sync issue on P4 --- components/esp_driver_parlio/src/parlio_tx.c | 14 +++++++------ .../test_apps/parlio/main/test_parlio_tx.c | 20 ++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index 20a0fdc4bca..e27e2de320d 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -389,10 +389,12 @@ static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const { size_t prepared_length = 0; uint8_t *data = (uint8_t *)buffer; + uint32_t mount_bytes = 0; parlio_dma_desc_t *desc_nc = tx_unit->dma_nodes_nc; while (len) { - uint32_t mount_bytes = len > DMA_DESCRIPTOR_BUFFER_MAX_SIZE ? DMA_DESCRIPTOR_BUFFER_MAX_SIZE : len; + assert(desc_nc); + mount_bytes = len > PARLIO_MAX_ALIGNED_DMA_BUF_SIZE ? PARLIO_MAX_ALIGNED_DMA_BUF_SIZE : len; len -= mount_bytes; desc_nc->dw0.suc_eof = (len == 0); // whether the last frame desc_nc->dw0.size = mount_bytes; @@ -402,11 +404,6 @@ static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const desc_nc = PARLIO_GET_NON_CACHED_DESC_ADDR(desc_nc->next); prepared_length += mount_bytes; } - -#if CONFIG_IDF_TARGET_ESP32P4 - // Write back to cache to synchronize the cache before DMA start - esp_cache_msync((void *)buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M); -#endif // CONFIG_IDF_TARGET_ESP32P4 } esp_err_t parlio_tx_unit_wait_all_done(parlio_tx_unit_handle_t tx_unit, int timeout_ms) @@ -570,6 +567,11 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p t->payload = payload; t->payload_bits = payload_bits; t->idle_value = config->idle_value & tx_unit->idle_value_mask; +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + // Write back to cache to synchronize the cache before DMA start + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)payload, (payload_bits + 7) / 8, + ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "cache sync failed"); +#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // send the transaction descriptor to progress queue ESP_RETURN_ON_FALSE(xQueueSend(tx_unit->trans_queues[PARLIO_TX_QUEUE_PROGRESS], &t, 0) == pdTRUE, diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c index 061fefae122..a1fd71d8883 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_tx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -109,7 +109,7 @@ TEST_CASE("parallel_tx_unit_trans_done_event", "[parlio_tx]") parlio_transmit_config_t transmit_config = { .idle_value = 0x00, }; - uint8_t payload[64] = {0}; + __attribute__((aligned(64))) uint8_t payload[64] = {0}; for (int i = 0; i < 64; i++) { payload[i] = i; } @@ -155,7 +155,7 @@ TEST_CASE("parallel_tx_unit_enable_disable", "[parlio_tx]") parlio_transmit_config_t transmit_config = { .idle_value = 0x00, }; - uint8_t payload[128] = {0}; + __attribute__((aligned(64))) uint8_t payload[128] = {0}; for (int i = 0; i < 128; i++) { payload[i] = i; } @@ -210,8 +210,9 @@ TEST_CASE("parallel_tx_unit_idle_value", "[parlio_tx]") parlio_transmit_config_t transmit_config = { .idle_value = 0x00, }; - uint8_t payload[8] = {0}; - for (int i = 0; i < 8; i++) { + uint32_t size = 64; + __attribute__((aligned(64))) uint8_t payload[size]; + for (int i = 0; i < size; i++) { payload[i] = i; } for (int j = 0; j < 16; j++) { @@ -255,15 +256,16 @@ TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]") parlio_transmit_config_t transmit_config = { .idle_value = 0x00, }; - uint8_t payload[8] = {0}; - for (int i = 0; i < 8; i++) { + uint32_t size = 64; + __attribute__((aligned(64))) uint8_t payload[size]; + for (int i = 0; i < size; i++) { payload[i] = 0x1B; // 8'b00011011, in PARLIO_BIT_PACK_ORDER_MSB, you should see 2'b00, 2'b01, 2'b10, 2'b11 on the data line } - TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 8 * sizeof(uint8_t) * 8, &transmit_config)); + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config)); TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1)); // check if the level on the clock line is low TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); - TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 8 * sizeof(uint8_t) * 8, &transmit_config)); + TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, size * sizeof(uint8_t) * 8, &transmit_config)); TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1)); TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO)); From cd6b3ab9fbf57a66a754877698de0b9938ab0435 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 26 Jul 2024 17:59:19 +0800 Subject: [PATCH 499/548] feat(isp_ccm): support isp color correction matrix (v5.3) --- components/esp_driver_isp/CMakeLists.txt | 1 + .../esp_driver_isp/include/driver/isp.h | 1 + .../esp_driver_isp/include/driver/isp_awb.h | 2 +- .../esp_driver_isp/include/driver/isp_ccm.h | 70 +++++++++++++++++++ components/esp_driver_isp/src/isp_ccm.c | 55 +++++++++++++++ .../test_apps/isp/main/test_isp_driver.c | 35 ++++++++++ components/hal/esp32p4/include/hal/isp_ll.h | 35 ++++++++++ components/hal/include/hal/isp_hal.h | 15 ++++ components/hal/include/hal/isp_types.h | 9 +++ components/hal/isp_hal.c | 25 +++++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 +++ components/soc/esp32p4/include/soc/soc_caps.h | 2 + docs/doxygen/Doxyfile_esp32p4 | 2 + docs/en/api-reference/peripherals/isp.rst | 33 +++++++++ 14 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 components/esp_driver_isp/include/driver/isp_ccm.h create mode 100644 components/esp_driver_isp/src/isp_ccm.c diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index 7ce185791b9..b3b04938f62 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -11,6 +11,7 @@ set(requires) if(CONFIG_SOC_ISP_SUPPORTED) list(APPEND srcs "src/isp_core.c" "src/isp_af.c" + "src/isp_ccm.c" "src/isp_awb.c") endif() diff --git a/components/esp_driver_isp/include/driver/isp.h b/components/esp_driver_isp/include/driver/isp.h index 38088eb9388..7a36bb172c7 100644 --- a/components/esp_driver_isp/include/driver/isp.h +++ b/components/esp_driver_isp/include/driver/isp.h @@ -15,3 +15,4 @@ #include "driver/isp_af.h" #include "driver/isp_awb.h" #include "driver/isp_bf.h" +#include "driver/isp_ccm.h" diff --git a/components/esp_driver_isp/include/driver/isp_awb.h b/components/esp_driver_isp/include/driver/isp_awb.h index 2846e9778bb..ee85513e947 100644 --- a/components/esp_driver_isp/include/driver/isp_awb.h +++ b/components/esp_driver_isp/include/driver/isp_awb.h @@ -177,7 +177,7 @@ typedef struct { /** * @brief Prototype of ISP AWB event callback * - * @param[in] handle ISP AWB controller handle + * @param[in] awb_ctlr ISP AWB controller handle * @param[in] edata ISP AWB event data * @param[in] user_data User registered context, registered when in `esp_isp_awb_env_detector_register_event_callbacks()` * diff --git a/components/esp_driver_isp/include/driver/isp_ccm.h b/components/esp_driver_isp/include/driver/isp_ccm.h new file mode 100644 index 00000000000..451c69bcba0 --- /dev/null +++ b/components/esp_driver_isp/include/driver/isp_ccm.h @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "driver/isp_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Color Correction Matrix configurations + * + */ +typedef struct { + float matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]; /*!< The color correction matrix in float, range (-4.0, 4.0) */ + bool saturation; /*!< Whether to use saturation when the float data in the matrix is out of the range, + * For example, if one of the matrix data is 5.0, + * When saturation is true, and final value will be limited to 4.0, and won't rise error + * When saturation is false, `esp_isp_ccm_configure` will rise ESP_ERR_INVALID_ARG error + */ +} esp_isp_ccm_config_t; + +/** + * @brief ISP Color Correction Matrix (CCM) configuration + * + * @note This function is allowed to be called before or after `esp_isp_ccm_enable`, + * but it only takes effect until `esp_isp_ccm_enable` is called + * + * @param[in] proc Processor handle + * @param[in] ccm_cfg CCM configurations, set NULL to de-configure the ISP CCM + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid + */ +esp_err_t esp_isp_ccm_configure(isp_proc_handle_t proc, const esp_isp_ccm_config_t *ccm_cfg); + +/** + * @brief Enable ISP CCM function + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + */ +esp_err_t esp_isp_ccm_enable(isp_proc_handle_t proc); + +/** + * @brief Disable ISP CCM function + * + * @param[in] proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + */ +esp_err_t esp_isp_ccm_disable(isp_proc_handle_t proc); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_isp/src/isp_ccm.c b/components/esp_driver_isp/src/isp_ccm.c new file mode 100644 index 00000000000..5fb45984884 --- /dev/null +++ b/components/esp_driver_isp/src/isp_ccm.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "esp_log.h" +#include "esp_check.h" +#include "freertos/FreeRTOS.h" +#include "driver/isp_core.h" +#include "driver/isp_ccm.h" +#include "esp_private/isp_private.h" + +static const char *TAG = "ISP_CCM"; + +/*--------------------------------------------------------------- + CCM +---------------------------------------------------------------*/ +esp_err_t esp_isp_ccm_configure(isp_proc_handle_t proc, const esp_isp_ccm_config_t *ccm_cfg) +{ + ESP_RETURN_ON_FALSE(proc && ccm_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + bool ret = true; + portENTER_CRITICAL(&proc->spinlock); + ret = isp_hal_ccm_set_matrix(&proc->hal, ccm_cfg->saturation, ccm_cfg->matrix); + portEXIT_CRITICAL(&proc->spinlock); + ESP_RETURN_ON_FALSE(ret, ESP_ERR_INVALID_ARG, TAG, "invalid argument: ccm matrix contain NaN or out of range"); + + return ESP_OK; +} + +esp_err_t esp_isp_ccm_enable(isp_proc_handle_t proc) +{ + ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + portENTER_CRITICAL(&proc->spinlock); + isp_ll_ccm_clk_enable(proc->hal.hw, true); + isp_ll_ccm_enable(proc->hal.hw, true); + portEXIT_CRITICAL(&proc->spinlock); + + return ESP_OK; +} + +esp_err_t esp_isp_ccm_disable(isp_proc_handle_t proc) +{ + ESP_RETURN_ON_FALSE(proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + + portENTER_CRITICAL(&proc->spinlock); + isp_ll_ccm_enable(proc->hal.hw, false); + isp_ll_ccm_clk_enable(proc->hal.hw, false); + portEXIT_CRITICAL(&proc->spinlock); + + return ESP_OK; +} diff --git a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c index 3ed34672425..d2f660ea5dc 100644 --- a/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c +++ b/components/esp_driver_isp/test_apps/isp/main/test_isp_driver.c @@ -118,3 +118,38 @@ TEST_CASE("ISP AWB driver basic function", "[isp]") TEST_ESP_OK(esp_isp_disable(isp_proc)); TEST_ESP_OK(esp_isp_del_processor(isp_proc)); } + +TEST_CASE("ISP CCM basic function", "[isp]") +{ + esp_isp_processor_cfg_t isp_config = { + .clk_hz = 80 * 1000 * 1000, + .input_data_source = ISP_INPUT_DATA_SOURCE_CSI, + .input_data_color_type = ISP_COLOR_RAW8, + .output_data_color_type = ISP_COLOR_RGB565, + }; + isp_proc_handle_t isp_proc = NULL; + TEST_ESP_OK(esp_isp_new_processor(&isp_config, &isp_proc)); + TEST_ESP_OK(esp_isp_enable(isp_proc)); + + esp_isp_ccm_config_t ccm_cfg = { + .matrix = { + {5.0, 0.0, 0.0}, + {0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0} + }, + .saturation = false, + }; + // Out of range case + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_isp_ccm_configure(isp_proc, &ccm_cfg)); + // saturation case + ccm_cfg.saturation = true; + TEST_ESP_OK(esp_isp_ccm_configure(isp_proc, &ccm_cfg)); + TEST_ESP_OK(esp_isp_ccm_enable(isp_proc)); + // Allow to be called after enabled + ccm_cfg.matrix[0][0] = -1.1; + TEST_ESP_OK(esp_isp_ccm_configure(isp_proc, &ccm_cfg)); + TEST_ESP_OK(esp_isp_ccm_disable(isp_proc)); + + TEST_ESP_OK(esp_isp_disable(isp_proc)); + TEST_ESP_OK(esp_isp_del_processor(isp_proc)); +} diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index fbac2e908c4..8792659fcbb 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -100,6 +100,22 @@ typedef union { uint32_t val; } isp_ll_awb_rgb_ratio_t; +/*--------------------------------------------------------------- + CCM +---------------------------------------------------------------*/ +#define ISP_LL_CCM_MATRIX_INT_BITS (2) +#define ISP_LL_CCM_MATRIX_FRAC_BITS (10) +#define ISP_LL_CCM_MATRIX_TOT_BITS (ISP_LL_CCM_MATRIX_INT_BITS + ISP_LL_CCM_MATRIX_FRAC_BITS + 1) // including one sign bit + +typedef union { + struct { + uint32_t fraction: ISP_LL_AWB_RGB_RATIO_FRAC_BITS; + uint32_t integer: ISP_LL_AWB_RGB_RATIO_INT_BITS; + uint32_t sign: 1; + }; + uint32_t val; +} isp_ll_ccm_gain_t; + /** * @brief Env monitor mode */ @@ -790,6 +806,25 @@ static inline void isp_ll_ccm_enable(isp_dev_t *hw, bool enable) hw->cntl.ccm_en = enable; } +/** + * @brief Set the Color Correction Matrix + * + * @param[in] hw Hardware instance address + * @param[in] fixed_point_matrix Color Correction Matrix in fixed-point format + */ +static inline void isp_ll_ccm_set_matrix(isp_dev_t *hw, isp_ll_ccm_gain_t fixed_point_matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]) +{ + hw->ccm_coef0.ccm_rr = fixed_point_matrix[0][0].val; + hw->ccm_coef0.ccm_rg = fixed_point_matrix[0][1].val; + hw->ccm_coef1.ccm_rb = fixed_point_matrix[0][2].val; + hw->ccm_coef1.ccm_gr = fixed_point_matrix[1][0].val; + hw->ccm_coef3.ccm_gg = fixed_point_matrix[1][1].val; + hw->ccm_coef3.ccm_gb = fixed_point_matrix[1][2].val; + hw->ccm_coef4.ccm_br = fixed_point_matrix[2][0].val; + hw->ccm_coef4.ccm_bg = fixed_point_matrix[2][1].val; + hw->ccm_coef5.ccm_bb = fixed_point_matrix[2][2].val; +} + /*--------------------------------------------------------------- Color ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_hal.h b/components/hal/include/hal/isp_hal.h index fd291e7ec51..d8566a9ec49 100644 --- a/components/hal/include/hal/isp_hal.h +++ b/components/hal/include/hal/isp_hal.h @@ -88,6 +88,21 @@ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t m */ void isp_hal_bf_config(isp_hal_context_t *hal, isp_hal_bf_cfg_t *config); +/*--------------------------------------------------------------- + Color Correction Matrix +---------------------------------------------------------------*/ +/** + * @brief Set Color Correction Matrix + * + * @param[in] hal Context of the HAL layer + * @param[in] saturation Whether to enable saturation when float data overflow + * @param[in] flt_matrix 3x3 RGB correction matrix + * @return + * - true Set success + * - false Invalid argument + */ +bool isp_hal_ccm_set_matrix(const isp_hal_context_t *hal, bool saturation, const float flt_matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]); + /*--------------------------------------------------------------- AWB ---------------------------------------------------------------*/ diff --git a/components/hal/include/hal/isp_types.h b/components/hal/include/hal/isp_types.h index a664d8001a7..d36b8a09fc4 100644 --- a/components/hal/include/hal/isp_types.h +++ b/components/hal/include/hal/isp_types.h @@ -100,6 +100,15 @@ typedef enum { ISP_BF_EDGE_PADDING_MODE_CUSTOM_DATA, ///< Fill BF edge padding data with custom pixel data } isp_bf_edge_padding_mode_t; +/*--------------------------------------------------------------- + CCM +---------------------------------------------------------------*/ +#if SOC_ISP_CCM_SUPPORTED +#define ISP_CCM_DIMENSION SOC_ISP_CCM_DIMENSION ///< ISP Color Correction Matrix dimension +#else +#define ISP_CCM_DIMENSION 0 ///< Not support CCM +#endif + /*--------------------------------------------------------------- AWB ---------------------------------------------------------------*/ diff --git a/components/hal/isp_hal.c b/components/hal/isp_hal.c index 7d33af5c5d7..37e69fd772d 100644 --- a/components/hal/isp_hal.c +++ b/components/hal/isp_hal.c @@ -70,6 +70,31 @@ uint32_t isp_hal_check_clear_intr_event(const isp_hal_context_t *hal, uint32_t m return triggered_events; } + +/*--------------------------------------------------------------- + Color Correction Matrix +---------------------------------------------------------------*/ +bool isp_hal_ccm_set_matrix(const isp_hal_context_t *hal, bool saturation, const float flt_matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION]) +{ + isp_ll_ccm_gain_t fp_matrix[ISP_CCM_DIMENSION][ISP_CCM_DIMENSION] = {}; + hal_utils_fixed_point_t fp_cfg = { + .int_bit = ISP_LL_CCM_MATRIX_INT_BITS, + .frac_bit = ISP_LL_CCM_MATRIX_FRAC_BITS, + .saturation = saturation, + }; + int err_level = saturation ? -1 : 0; + /* Transfer the float type to fixed point */ + for (int i = 0; i < ISP_CCM_DIMENSION; i++) { + for (int j = 0; j < ISP_CCM_DIMENSION; j++) { + if (hal_utils_float_to_fixed_point_32b(flt_matrix[i][j], &fp_cfg, &fp_matrix[i][j].val) < err_level) { + return false; + } + } + } + isp_ll_ccm_set_matrix(hal->hw, fp_matrix); + return true; +} + /*--------------------------------------------------------------- AWB ---------------------------------------------------------------*/ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bfe0ed76641..4e1d152e601 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -803,6 +803,10 @@ config SOC_ISP_BF_SUPPORTED bool default y +config SOC_ISP_CCM_SUPPORTED + bool + default y + config SOC_ISP_DVP_SUPPORTED bool default y @@ -835,6 +839,10 @@ config SOC_ISP_BF_TEMPLATE_Y_NUMS int default 3 +config SOC_ISP_CCM_DIMENSION + int + default 3 + config SOC_ISP_DVP_DATA_WIDTH_MAX int default 16 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 55f3b8565ae..f774eaf9a8c 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -321,6 +321,7 @@ /*-------------------------- ISP CAPS ----------------------------------------*/ #define SOC_ISP_BF_SUPPORTED 1 +#define SOC_ISP_CCM_SUPPORTED 1 #define SOC_ISP_DVP_SUPPORTED 1 #define SOC_ISP_NUMS 1U @@ -330,6 +331,7 @@ #define SOC_ISP_SHARE_CSI_BRG 1 #define SOC_ISP_BF_TEMPLATE_X_NUMS 3 #define SOC_ISP_BF_TEMPLATE_Y_NUMS 3 +#define SOC_ISP_CCM_DIMENSION 3 #define SOC_ISP_DVP_DATA_WIDTH_MAX 16 /*-------------------------- LEDC CAPS ---------------------------------------*/ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index cd1724d538f..01cc245bcd5 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -27,6 +27,8 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_types.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_af.h \ + $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_awb.h \ + $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_ccm.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \ $(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \ diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 15220418a28..ed4e7250859 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -15,8 +15,10 @@ Terminology - RAW: Unprocessed data directly output from an image sensor, typically divided into R, Gr, Gb, and B four channels classified into RAW8, RAW10, RAW12, etc., based on bit width - RGB: Colored image format composed of red, green, and blue colors classified into RGB888, RGB565, etc., based on the bit width of each color - YUV: Colored image format composed of luminance and chrominance classified into YUV444, YUV422, YUV420, etc., based on the data arrangement + - BF: Bayer Domain Filter - AF: Auto-focus - AWB: Auto-white balance + - CCM: Color correction matrix ISP Pipeline ------------ @@ -59,6 +61,7 @@ The ISP driver offers following services: - `Enable and disable ISP processor <#isp-enable-disable>`__ - covers how to enable and disable an ISP processor. - `Get AF statistics in one shot or continuous way <#isp-af-statistics>`__ - covers how to get AF statistics one-shot or continuously. - `Get AWB statistics in one shot or continuous way <#isp-awb-statistics>`__ - covers how to get AWB white patches statistics one-shot or continuously. +- `Configure CCM <#isp-ccm-config>`__ - covers how to config the Color Correction Matrix. - `Register callback <#isp-callback>`__ - covers how to hook user specific code to ISP driver event callback function. - `Thread Safety <#isp-thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver. - `Kconfig Options <#isp-kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver. @@ -304,6 +307,36 @@ Note that if you want to use the continuous statistics, you need to register the /* Delete the awb controller and free the resources */ ESP_ERROR_CHECK(esp_isp_del_awb_controller(awb_ctlr)); +.. _isp-ccm-config: + +Configure CCM +^^^^^^^^^^^^^ + +Color Correction Matrix can scale the color ratio of RGB888 pixels. It can be used for adjusting the image color via some algorithms, for example, used for white balance by inputting the AWB computed result, or used as a Filter with some filter algorithms. + +To adjust the color correction matrix, you can refer to the following code: + +.. code-block:: c + + // ... + // Configure CCM + esp_isp_ccm_config_t ccm_cfg = { + .matrix = { + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + }, + .saturation = false, + }; + ESP_ERROR_CHECK(esp_isp_ccm_configure(isp_proc, &ccm_cfg)); + // The configured CCM will be applied to the image once the CCM module is enabled + ESP_ERROR_CHECK(esp_isp_ccm_enable(isp_proc)); + // CCM can also be configured after it is enabled + ccm_cfg.matrix[0][0] = 2.0; + ESP_ERROR_CHECK(esp_isp_ccm_configure(isp_proc, &ccm_cfg)); + // Disable CCM if no longer needed + ESP_ERROR_CHECK(esp_isp_ccm_disable(isp_proc)); + .. _isp-callback: Register Event Callbacks From 7e93518073aa9874bf757b3b2d79796577d74b94 Mon Sep 17 00:00:00 2001 From: zwx Date: Wed, 22 May 2024 11:28:24 +0800 Subject: [PATCH 500/548] feat(openthread): add task switching lock holder check --- components/openthread/include/esp_openthread_lock.h | 13 ++++++++----- components/openthread/src/esp_openthread_lock.c | 7 ++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/components/openthread/include/esp_openthread_lock.h b/components/openthread/include/esp_openthread_lock.h index 19f504541a6..c2ad28fad99 100644 --- a/components/openthread/include/esp_openthread_lock.h +++ b/components/openthread/include/esp_openthread_lock.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,10 +35,10 @@ void esp_openthread_lock_deinit(void); /** * @brief This function acquires the OpenThread API lock. * - * @note Every OT APIs that takes an otInstance argument MUST be protected with this API lock - * except that the call site is in OT callbacks. + * @note Every Openthread APIs that takes an otInstance argument MUST be protected with this API lock + * except that the call site is in Openthread callbacks. * - * @param[in] block_ticks The maxinum number of RTOS ticks to wait for the lock. + * @param[in] block_ticks The maximum number of RTOS ticks to wait for the lock. * * @return * - True on lock acquired @@ -63,7 +63,7 @@ void esp_openthread_lock_release(void); * * @note Please use esp_openthread_lock_acquire() for normal cases. * - * @param[in] block_ticks The maxinum number of RTOS ticks to wait for the lock. + * @param[in] block_ticks The maximum number of RTOS ticks to wait for the lock. * * @return * - True on lock acquired @@ -75,6 +75,9 @@ bool esp_openthread_task_switching_lock_acquire(TickType_t block_ticks); /** * @brief This function releases the OpenThread API task switching lock. * + * @note This API must be called after `esp_openthread_task_switching_lock_acquire` or + * `esp_openthread_lock_acquire` and will cause a crash if the current task is not the task switching lock holder. + * This error could be caused by calling OpenThread APIs without locking OpenThread stack. */ void esp_openthread_task_switching_lock_release(void); diff --git a/components/openthread/src/esp_openthread_lock.c b/components/openthread/src/esp_openthread_lock.c index ba7c63d4115..7e35da6c21b 100644 --- a/components/openthread/src/esp_openthread_lock.c +++ b/components/openthread/src/esp_openthread_lock.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -45,6 +45,11 @@ void esp_openthread_task_switching_lock_release(void) { ESP_RETURN_ON_FALSE(s_openthread_task_mutex, , OT_PLAT_LOG_TAG, "Failed to release the lock because the mutex is not ready"); + if (xSemaphoreGetMutexHolder(s_openthread_task_mutex) != xTaskGetCurrentTaskHandle()) { + ESP_LOGE(OT_PLAT_LOG_TAG, "Task %s is attempting to release the OpenThread task switching lock but never acquired it.", + pcTaskGetName(xTaskGetCurrentTaskHandle())); + assert(false); + } xSemaphoreGiveRecursive(s_openthread_task_mutex); } From cf36c11b813aa5af3b4a42f2cf51bb35a4a12985 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Mon, 1 Jul 2024 12:11:41 +0800 Subject: [PATCH 501/548] feat(lp-core): added support for using ETM events as wake-up source --- .../include/esp_private/etm_interface.h | 1 + .../hal/esp32c5/include/hal/lp_aon_ll.h | 18 +++ .../hal/esp32p4/include/hal/lp_core_ll.h | 9 ++ components/hal/include/hal/lp_core_types.h | 41 ++++++ .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32c6/include/soc/soc_caps.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 3 + components/ulp/CMakeLists.txt | 4 + components/ulp/lp_core/include/lp_core_etm.h | 60 ++++++++ components/ulp/lp_core/lp_core.c | 2 +- .../ulp/lp_core/lp_core/lp_core_utils.c | 10 +- components/ulp/lp_core/lp_core_etm.c | 90 ++++++++++++ .../ulp/test_apps/lp_core/main/CMakeLists.txt | 4 + .../test_apps/lp_core/main/test_lp_core_etm.c | 130 ++++++++++++++++++ docs/doxygen/Doxyfile | 1 + docs/doxygen/Doxyfile_esp32c5 | 3 +- docs/doxygen/Doxyfile_esp32c6 | 1 + docs/doxygen/Doxyfile_esp32p4 | 1 + docs/en/api-reference/system/ulp-lp-core.rst | 10 +- .../api-reference/system/ulp-lp-core.rst | 10 +- 21 files changed, 400 insertions(+), 7 deletions(-) create mode 100644 components/hal/include/hal/lp_core_types.h create mode 100644 components/ulp/lp_core/include/lp_core_etm.h create mode 100644 components/ulp/lp_core/lp_core_etm.c create mode 100644 components/ulp/test_apps/lp_core/main/test_lp_core_etm.c diff --git a/components/esp_hw_support/include/esp_private/etm_interface.h b/components/esp_hw_support/include/esp_private/etm_interface.h index 04c02964f92..a3924a064b1 100644 --- a/components/esp_hw_support/include/esp_private/etm_interface.h +++ b/components/esp_hw_support/include/esp_private/etm_interface.h @@ -27,6 +27,7 @@ typedef enum { ETM_TRIG_PERIPH_MCPWM, /*!< ETM trigger source: MCPWM */ ETM_TRIG_PERIPH_ANA_CMPR, /*!< ETM trigger source: Analog Comparator */ ETM_TRIG_PERIPH_TSENS, /*!< ETM trigger source: Temperature Sensor */ + ETM_TRIG_PERIPH_LP_CORE, /*!< ETM trigger source: Low-Power Core */ } etm_trigger_peripheral_t; /** diff --git a/components/hal/esp32c5/include/hal/lp_aon_ll.h b/components/hal/esp32c5/include/hal/lp_aon_ll.h index dc65bb3225e..e3552371355 100644 --- a/components/hal/esp32c5/include/hal/lp_aon_ll.h +++ b/components/hal/esp32c5/include/hal/lp_aon_ll.h @@ -92,6 +92,24 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp) } } +/** + * @brief Get the flag that marks whether LP CPU is awakened by ETM + * + * @return Return true if lpcore is woken up by soc_etm + */ +static inline bool lp_aon_ll_get_lpcore_etm_wakeup_flag(void) +{ + return REG_GET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG); +} + +/** + * @brief Clear the flag that marks whether LP CPU is awakened by soc_etm + */ +static inline void lp_aon_ll_clear_lpcore_etm_wakeup_flag(void) +{ + REG_SET_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_ETM_WAKEUP_FLAG_CLR); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/lp_core_ll.h b/components/hal/esp32p4/include/hal/lp_core_ll.h index d67c0c52bbf..b045f4703cf 100644 --- a/components/hal/esp32p4/include/hal/lp_core_ll.h +++ b/components/hal/esp32p4/include/hal/lp_core_ll.h @@ -148,6 +148,15 @@ static inline void lp_core_ll_request_sleep(void) PMU.lp_ext.pwr1.sleep_req = 1; } +/** + * @brief Clear the ETM wakeup interrupt sources on the LP core + * + */ +static inline void lp_core_ll_clear_etm_wakeup_status(void) +{ + LP_SYS.sys_ctrl.lp_core_etm_wakeup_flag_clr = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/lp_core_types.h b/components/hal/include/hal/lp_core_types.h new file mode 100644 index 00000000000..046840a7e14 --- /dev/null +++ b/components/hal/include/hal/lp_core_types.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_LP_CORE_SUPPORTED + +#if SOC_LP_CORE_SUPPORT_ETM +/** + * @brief LP-Core event types enum + */ +typedef enum { + LP_CORE_EVENT_ERR_INTR, /*!< Exception triggered on LP-Core */ + LP_CORE_EVENT_START_INTR, /*!< LP-Core clock has been turned on */ + LP_CORE_EVENT_MAX, /*!< Maximum number of LP-Core events */ +} lp_core_etm_event_type_t; + +/** + * @brief LP-Core task types enum + */ +typedef enum { + LP_CORE_TASK_WAKEUP_CPU, /*!< LP-Core wake-up task */ + LP_CORE_TASK_MAX, /*!< Maximum number of LP-Core tasks */ +} lp_core_etm_task_type_t; + +#endif //SOC_LP_CORE_SUPPORT_ETM + +#endif //SOC_LP_CORE_SUPPORTED + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 4361773ea58..58b38d4fc92 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1486,3 +1486,7 @@ config SOC_CAPS_NO_RESET_BY_ANA_BOD config SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR bool default y + +config SOC_LP_CORE_SUPPORT_ETM + bool + default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 257529c9232..7976d24688c 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -591,3 +591,4 @@ /*------------------------------------- ULP CAPS -------------------------------------*/ #define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */ +#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bfe0ed76641..e8453b4e6e6 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1734,3 +1734,7 @@ config SOC_LCDCAM_CAM_PERIPH_NUM config SOC_LCDCAM_CAM_DATA_WIDTH_MAX int default 16 + +config SOC_LP_CORE_SUPPORT_ETM + bool + default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 55f3b8565ae..e552ad07515 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -684,3 +684,6 @@ #define SOC_LCDCAM_CAM_SUPPORT_RGB_YUV_CONV (1) #define SOC_LCDCAM_CAM_PERIPH_NUM (1U) #define SOC_LCDCAM_CAM_DATA_WIDTH_MAX (16U) + +/*------------------------------------- ULP CAPS -------------------------------------*/ +#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */ diff --git a/components/ulp/CMakeLists.txt b/components/ulp/CMakeLists.txt index dd159c8a60d..24ea46461d8 100644 --- a/components/ulp/CMakeLists.txt +++ b/components/ulp/CMakeLists.txt @@ -69,6 +69,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE) if(CONFIG_SOC_LP_SPI_SUPPORTED) list(APPEND srcs "lp_core/lp_core_spi.c") endif() + + if(CONFIG_SOC_LP_CORE_SUPPORT_ETM) + list(APPEND srcs "lp_core/lp_core_etm.c") + endif() endif() idf_component_register(SRCS ${srcs} diff --git a/components/ulp/lp_core/include/lp_core_etm.h b/components/ulp/lp_core/include/lp_core_etm.h new file mode 100644 index 00000000000..5550906adbf --- /dev/null +++ b/components/ulp/lp_core/include/lp_core_etm.h @@ -0,0 +1,60 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include "esp_err.h" +#include "esp_etm.h" +#include "hal/lp_core_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LP-Core ETM event configuration + */ +typedef struct { + lp_core_etm_event_type_t event_type; /*!< LP-Core ETM event type */ +} lp_core_etm_event_config_t; + +/** + * @brief LP-Core ETM task configuration + */ +typedef struct { + lp_core_etm_task_type_t task_type; /*!< LP-Core ETM task type */ +} lp_core_etm_task_config_t; + +/** + * @brief Create a ETM event for LP-Core + * + * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` + * + * @param[in] config LP-Core ETM event configuration + * @param[out] out_event Returned ETM event handle + * @return + * - ESP_OK: Get ETM event successfully + * - ESP_ERR_INVALID_ARG: Get ETM event failed because of invalid argument + * - ESP_FAIL: Get ETM event failed because of other error + */ +esp_err_t lp_core_new_etm_event(const lp_core_etm_event_config_t *config, esp_etm_event_handle_t *out_event); + +/** + * @brief Create a ETM task for LP-Core + * + * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` + * + * @param[in] config LP-Core ETM task configuration + * @param[out] out_task Returned ETM task handle + * @return + * - ESP_OK: Get ETM task successfully + * - ESP_ERR_INVALID_ARG: Get ETM task failed because of invalid argument + * - ESP_FAIL: Get ETM task failed because of other error + */ +esp_err_t lp_core_new_etm_task(const lp_core_etm_task_config_t *config, esp_etm_task_handle_t *out_task); + +#ifdef __cplusplus +} +#endif diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c index e578e077acd..84f6d9c32b6 100644 --- a/components/ulp/lp_core/lp_core.c +++ b/components/ulp/lp_core/lp_core.c @@ -126,7 +126,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg) } #endif - if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART | ULP_LP_CORE_WAKEUP_SOURCE_LP_IO | ULP_LP_CORE_WAKEUP_SOURCE_ETM)) { + if (cfg->wakeup_source & (ULP_LP_CORE_WAKEUP_SOURCE_LP_UART | ULP_LP_CORE_WAKEUP_SOURCE_LP_IO)) { ESP_LOGE(TAG, "Wake-up source not yet supported"); return ESP_ERR_INVALID_ARG; } diff --git a/components/ulp/lp_core/lp_core/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index bcc84daa477..0eecf4006dd 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -15,6 +15,10 @@ #include "hal/uart_ll.h" #include "hal/rtc_io_ll.h" +#if !CONFIG_IDF_TARGET_ESP32P4 +#include "hal/lp_aon_ll.h" +#endif + #if SOC_ETM_SUPPORTED #include "hal/etm_ll.h" #endif @@ -52,7 +56,11 @@ void ulp_lp_core_update_wakeup_cause(void) if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_ETM) \ && etm_ll_is_lpcore_wakeup_triggered()) { lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_ETM; - etm_ll_clear_lpcore_wakeup_status(); +#if CONFIG_IDF_TARGET_ESP32P4 + lp_core_ll_clear_etm_wakeup_status(); +#else + lp_aon_ll_clear_lpcore_etm_wakeup_flag(); +#endif } #endif /* SOC_ETM_SUPPORTED */ diff --git a/components/ulp/lp_core/lp_core_etm.c b/components/ulp/lp_core/lp_core_etm.c new file mode 100644 index 00000000000..16be0fc5da2 --- /dev/null +++ b/components/ulp/lp_core/lp_core_etm.c @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "sdkconfig.h" +#include "lp_core_etm.h" +#include "esp_private/etm_interface.h" +#include "esp_err.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/soc_etm_source.h" + +#define LP_CORE_ETM_EVENT_TABLE(event) \ + (uint32_t [LP_CORE_EVENT_MAX]){ \ + [LP_CORE_EVENT_ERR_INTR] = ULP_EVT_ERR_INTR, \ + [LP_CORE_EVENT_START_INTR] = ULP_EVT_START_INTR, \ + }[event] + +#define LP_CORE_ETM_TASK_TABLE(task) \ + (uint32_t [LP_CORE_TASK_MAX]){ \ + [LP_CORE_TASK_WAKEUP_CPU] = ULP_TASK_WAKEUP_CPU, \ + }[task] + +const static char* TAG = "lp-core-etm"; + +static esp_err_t lp_core_del_etm_event(esp_etm_event_t *event) +{ + free(event); + return ESP_OK; +} + +static esp_err_t lp_core_del_etm_task(esp_etm_task_t *task) +{ + free(task); + return ESP_OK; +} + +esp_err_t lp_core_new_etm_task(const lp_core_etm_task_config_t *config, esp_etm_task_handle_t *out_task) +{ + esp_etm_task_t *task = NULL; + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(config && out_task, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(config->task_type < LP_CORE_TASK_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid task type"); + task = heap_caps_calloc(1, sizeof(esp_etm_task_t), MALLOC_CAP_DEFAULT); + ESP_GOTO_ON_FALSE(task, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM task"); + + uint32_t task_id = LP_CORE_ETM_TASK_TABLE(config->task_type); + ESP_GOTO_ON_FALSE(task_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported task type"); + + // fill the ETM task object + task->task_id = task_id; + task->trig_periph = ETM_TRIG_PERIPH_LP_CORE; + task->del = lp_core_del_etm_task; + ESP_LOGD(TAG, "new task @%p, task_id=%"PRIu32, task, task_id); + *out_task = task; + return ESP_OK; + +err: + if (task) { + lp_core_del_etm_task(task); + } + return ret; +} + +esp_err_t lp_core_new_etm_event(const lp_core_etm_event_config_t *config, esp_etm_event_handle_t *out_event) +{ + esp_etm_event_t *event = NULL; + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(config && out_event, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + ESP_GOTO_ON_FALSE(config->event_type < LP_CORE_EVENT_MAX, ESP_ERR_INVALID_ARG, err, TAG, "invalid event type"); + event = heap_caps_calloc(1, sizeof(esp_etm_event_t), MALLOC_CAP_DEFAULT); + ESP_GOTO_ON_FALSE(event, ESP_ERR_NO_MEM, err, TAG, "no memory for ETM event"); + + uint32_t event_id = LP_CORE_ETM_EVENT_TABLE(config->event_type); + ESP_GOTO_ON_FALSE(event_id != 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "not supported event type"); + + // fill the ETM event object + event->event_id = event_id; + event->trig_periph = ETM_TRIG_PERIPH_LP_CORE; + event->del = lp_core_del_etm_event; + *out_event = event; + return ESP_OK; + +err: + if (event) { + lp_core_del_etm_event(event); + } + return ret; +} diff --git a/components/ulp/test_apps/lp_core/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/main/CMakeLists.txt index 0e152e7969c..5072dec7e3e 100644 --- a/components/ulp/test_apps/lp_core/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/main/CMakeLists.txt @@ -8,6 +8,10 @@ if(CONFIG_SOC_LP_SPI_SUPPORTED) list(APPEND app_sources "test_lp_core_spi.c") endif() +if(CONFIG_SOC_LP_CORE_SUPPORT_ETM AND CONFIG_SOC_ETM_SUPPORTED) + list(APPEND app_sources "test_lp_core_etm.c") +endif() + set(lp_core_sources "lp_core/test_main.c") set(lp_core_sources_counter "lp_core/test_main_counter.c") diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core_etm.c b/components/ulp/test_apps/lp_core/main/test_lp_core_etm.c new file mode 100644 index 00000000000..4e640ac0f5e --- /dev/null +++ b/components/ulp/test_apps/lp_core/main/test_lp_core_etm.c @@ -0,0 +1,130 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "lp_core_test_app_counter.h" +#include "ulp_lp_core.h" +#include "test_shared.h" +#include "unity.h" +#include "test_utils.h" +#include "esp_log.h" +#include "driver/gptimer.h" +#include "lp_core_etm.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +extern const uint8_t lp_core_main_counter_bin_start[] asm("_binary_lp_core_test_app_counter_bin_start"); +extern const uint8_t lp_core_main_counter_bin_end[] asm("_binary_lp_core_test_app_counter_bin_end"); + +static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) +{ + TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, + (firmware_end - firmware_start)) == ESP_OK); + + TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK); + +} + +#define STOP_TEST_ITERATIONS 50 +#define TIMER_PERIOD_MS 10 + +static int timer_cb_count; + +static bool on_gptimer_alarm_cb(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx) +{ + timer_cb_count++; + if (timer_cb_count >= STOP_TEST_ITERATIONS) { + gptimer_stop(timer); + } + return false; +} + +/** + * @brief Test connects ULP wakeup source to a GP timer alarm ETM event. + * At every wakeup the ULP program increments a counter and in the + * end we check that the ULP woke-up the expected number of times. + */ +TEST_CASE("LP core can be woken up by ETM event", "[ulp]") +{ + // GPTimer alarm ---> ETM channel A ---> ULP wake-up + printf("allocate etm channel\r\n"); + esp_etm_channel_config_t etm_config = {}; + esp_etm_channel_handle_t etm_channel_a; + TEST_ESP_OK(esp_etm_new_channel(&etm_config, &etm_channel_a)); + + esp_etm_task_handle_t lp_core_task = NULL; + + lp_core_etm_task_config_t lp_core_task_config = { + .task_type = LP_CORE_TASK_WAKEUP_CPU, + }; + TEST_ESP_OK(lp_core_new_etm_task(&lp_core_task_config, &lp_core_task)); + + printf("create a gptimer\r\n"); + gptimer_handle_t gptimer = NULL; + gptimer_config_t timer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1 * 1000 * 1000, // 1MHz, 1 tick = 1us + }; + TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimer)); + + printf("get gptimer etm event handle\r\n"); + esp_etm_event_handle_t gptimer_event = NULL; + gptimer_etm_event_config_t gptimer_etm_event_conf = { + .event_type = GPTIMER_ETM_EVENT_ALARM_MATCH, + }; + TEST_ESP_OK(gptimer_new_etm_event(gptimer, &gptimer_etm_event_conf, &gptimer_event)); + + printf("connect event and task to the channel\r\n"); + TEST_ESP_OK(esp_etm_channel_connect(etm_channel_a, gptimer_event, lp_core_task)); + + printf("enable etm channel\r\n"); + TEST_ESP_OK(esp_etm_channel_enable(etm_channel_a)); + + printf("set timer alarm action\r\n"); + gptimer_alarm_config_t alarm_config = { + .reload_count = 0, + .alarm_count = TIMER_PERIOD_MS * 1000, // 10ms per alarm event + .flags.auto_reload_on_alarm = true, + }; + TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config)); + + printf("register alarm callback\r\n"); + gptimer_event_callbacks_t cbs = { + .on_alarm = on_gptimer_alarm_cb, + }; + TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL)); + + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_ETM, +#if ESP_ROM_HAS_LP_ROM + .skip_lp_rom_boot = true, +#endif //ESP_ROM_HAS_LP_ROM + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_counter_bin_start, lp_core_main_counter_bin_end); + + printf("enable and start timer\r\n"); + TEST_ESP_OK(gptimer_enable(gptimer)); + TEST_ESP_OK(gptimer_start(gptimer)); + + // Wait for more than the expected time for the test to complete + // To ensure that the ULP ran exactly as many times as we expected + vTaskDelay((TIMER_PERIOD_MS * STOP_TEST_ITERATIONS * 2) / portTICK_PERIOD_MS); + + TEST_ASSERT_EQUAL(STOP_TEST_ITERATIONS, timer_cb_count); + TEST_ASSERT_EQUAL(STOP_TEST_ITERATIONS, ulp_counter); + + TEST_ESP_OK(gptimer_disable(gptimer)); + TEST_ESP_OK(gptimer_del_timer(gptimer)); + + TEST_ESP_OK(esp_etm_del_task(lp_core_task)); + TEST_ESP_OK(esp_etm_del_event(gptimer_event)); + TEST_ESP_OK(esp_etm_channel_disable(etm_channel_a)); + TEST_ESP_OK(esp_etm_del_channel(etm_channel_a)); +} diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 4f7e79e3e0c..50539c457b6 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -264,6 +264,7 @@ INPUT = \ $(PROJECT_PATH)/components/hal/include/hal/uart_types.h \ $(PROJECT_PATH)/components/hal/include/hal/efuse_hal.h \ $(PROJECT_PATH)/components/hal/include/hal/eth_types.h \ + $(PROJECT_PATH)/components/hal/include/hal/lp_core_types.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps_init.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_trace.h \ diff --git a/docs/doxygen/Doxyfile_esp32c5 b/docs/doxygen/Doxyfile_esp32c5 index 82c15ca68e1..faf09ce4a4c 100644 --- a/docs/doxygen/Doxyfile_esp32c5 +++ b/docs/doxygen/Doxyfile_esp32c5 @@ -1,4 +1,4 @@ -# TODO: IDF-9197 Use beta3 in doc temprory +# TODO: IDF-9197 Use beta3 in doc temporary INPUT += \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/soc_caps.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/clk_tree_defs.h \ @@ -6,6 +6,7 @@ INPUT += \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/mp/include/soc/uart_channel.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \ + $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \ diff --git a/docs/doxygen/Doxyfile_esp32c6 b/docs/doxygen/Doxyfile_esp32c6 index ddd75aad3c7..cc8eb9578a4 100644 --- a/docs/doxygen/Doxyfile_esp32c6 +++ b/docs/doxygen/Doxyfile_esp32c6 @@ -1,6 +1,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \ + $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index cd1724d538f..b219cec3289 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -2,6 +2,7 @@ INPUT += \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_spi.h \ + $(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_etm.h \ $(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \ $(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \ diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index 8f8b08efbbb..430fe5fa787 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -233,10 +233,16 @@ Main CPU API Reference .. include-build-file:: inc/lp_core_i2c.inc .. include-build-file:: inc/lp_core_uart.inc -.. only:: CONFIG_SOC_LP_SPI_SUPPORTED +.. only:: SOC_LP_SPI_SUPPORTED .. include-build-file:: inc/lp_core_spi.inc +.. only:: SOC_LP_CORE_SUPPORT_ETM + + .. include-build-file:: inc/lp_core_etm.inc + +.. include-build-file:: inc/lp_core_types.inc + LP Core API Reference ~~~~~~~~~~~~~~~~~~~~~~ @@ -247,7 +253,7 @@ LP Core API Reference .. include-build-file:: inc/ulp_lp_core_print.inc .. include-build-file:: inc/ulp_lp_core_interrupts.inc -.. only:: CONFIG_SOC_LP_SPI_SUPPORTED +.. only:: SOC_LP_SPI_SUPPORTED .. include-build-file:: inc/ulp_lp_core_spi.inc diff --git a/docs/zh_CN/api-reference/system/ulp-lp-core.rst b/docs/zh_CN/api-reference/system/ulp-lp-core.rst index 06e805e6629..02b5aae14c3 100644 --- a/docs/zh_CN/api-reference/system/ulp-lp-core.rst +++ b/docs/zh_CN/api-reference/system/ulp-lp-core.rst @@ -197,10 +197,16 @@ API 参考 .. include-build-file:: inc/lp_core_i2c.inc .. include-build-file:: inc/lp_core_uart.inc -.. only:: CONFIG_SOC_LP_SPI_SUPPORTED +.. only:: SOC_LP_SPI_SUPPORTED .. include-build-file:: inc/lp_core_spi.inc +.. only:: SOC_LP_CORE_SUPPORT_ETM + + .. include-build-file:: inc/lp_core_etm.inc + +.. include-build-file:: inc/lp_core_types.inc + LP 内核 API 参考 ~~~~~~~~~~~~~~~~~~~~~~ @@ -211,7 +217,7 @@ LP 内核 API 参考 .. include-build-file:: inc/ulp_lp_core_print.inc .. include-build-file:: inc/ulp_lp_core_interrupts.inc -.. only:: CONFIG_SOC_LP_SPI_SUPPORTED +.. only:: SOC_LP_SPI_SUPPORTED .. include-build-file:: inc/ulp_lp_core_spi.inc From dccd6b0259b091dcfcddec5a47b178207b20a3c2 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 19 Jul 2024 15:24:22 +0800 Subject: [PATCH 502/548] change(lp_core): changed wakeup time calc to use a precomputed tick value Previously we would calculate the wakeup ticks upon every wakeup using the lp-timer clock frequency, but this caused the binary to pull in software division functions, increasing the binary size. This value is now precalculated by the hp-core when we configure the ULP. This saves about 1k bytes. --- components/ulp/Kconfig | 2 +- components/ulp/lp_core/lp_core.c | 1 + .../ulp/lp_core/lp_core/lp_core_startup.c | 6 +++--- .../include/ulp_lp_core_lp_timer_shared.h | 21 +++++++++++++++++++ .../include/ulp_lp_core_memory_shared.h | 3 ++- .../shared/ulp_lp_core_lp_timer_shared.c | 15 ++++++++++++- 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/ulp/Kconfig b/components/ulp/Kconfig index 94167bd5dfa..d1092b9a768 100644 --- a/components/ulp/Kconfig +++ b/components/ulp/Kconfig @@ -75,7 +75,7 @@ menu "Ultra Low Power (ULP) Co-processor" config ULP_SHARED_MEM depends on ULP_COPROC_TYPE_LP_CORE hex - default 0x8 + default 0x10 help Size of the shared memory defined in ulp_lp_core_memory_shared.c. Size should be kept in-sync with the size of the struct defined there. diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c index e578e077acd..0af75f33c86 100644 --- a/components/ulp/lp_core/lp_core.c +++ b/components/ulp/lp_core/lp_core.c @@ -120,6 +120,7 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg) ESP_LOGI(TAG, "LP timer specified as wakeup source, but no sleep duration set. ULP will only wake-up once unless it calls ulp_lp_core_lp_timer_set_wakeup_time()"); } shared_mem->sleep_duration_us = cfg->lp_timer_sleep_duration_us; + shared_mem->sleep_duration_ticks = ulp_lp_core_lp_timer_calculate_sleep_ticks(cfg->lp_timer_sleep_duration_us); /* Set first wakeup alarm */ ulp_lp_core_lp_timer_set_wakeup_time(cfg->lp_timer_sleep_duration_us); diff --git a/components/ulp/lp_core/lp_core/lp_core_startup.c b/components/ulp/lp_core/lp_core/lp_core_startup.c index 4d87b07fd1a..b43f234df1f 100644 --- a/components/ulp/lp_core/lp_core/lp_core_startup.c +++ b/components/ulp/lp_core/lp_core/lp_core_startup.c @@ -20,10 +20,10 @@ void lp_core_startup() ulp_lp_core_memory_shared_cfg_t* shared_mem = ulp_lp_core_memory_shared_cfg_get(); #if SOC_LP_TIMER_SUPPORTED - uint64_t sleep_duration = shared_mem->sleep_duration_us; + uint64_t sleep_duration_ticks = shared_mem->sleep_duration_ticks; - if (sleep_duration) { - ulp_lp_core_lp_timer_set_wakeup_time(sleep_duration); + if (sleep_duration_ticks) { + ulp_lp_core_lp_timer_set_wakeup_ticks(sleep_duration_ticks); } #endif //SOC_LP_TIMER_SUPPORTED diff --git a/components/ulp/lp_core/shared/include/ulp_lp_core_lp_timer_shared.h b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_timer_shared.h index dda58dc843c..6743ebd6031 100644 --- a/components/ulp/lp_core/shared/include/ulp_lp_core_lp_timer_shared.h +++ b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_timer_shared.h @@ -31,6 +31,27 @@ uint64_t ulp_lp_core_lp_timer_get_cycle_count(void); */ void ulp_lp_core_lp_timer_set_wakeup_time(uint64_t sleep_duration_us); +/** + * @brief Set the next wakeup alarm in LP timer ticks + * + * @note This only sets the alarm for a single wakeup. For periodic wakeups you will + * have to call this function again after each wakeup to configure the next time. + * + * @note If ulp_lp_core_cfg_t.lp_timer_sleep_duration_us is set the ulp will automatically set + * the next wakeup time after returning from main and override this value. + * + * @param sleep_duration_ticks + */ +void ulp_lp_core_lp_timer_set_wakeup_ticks(uint64_t sleep_duration_ticks); + +/** + * @brief Converts from sleep duration in microseconds to LP timer ticks + * + * @param sleep_duration_us Sleep duration in microseconds + * @return uint64_t Number of LP timer ticks to sleep for + */ +uint64_t ulp_lp_core_lp_timer_calculate_sleep_ticks(uint64_t sleep_duration_us); + /** * @brief Disables the lp timer alarm and clears any pending alarm interrupts * diff --git a/components/ulp/lp_core/shared/include/ulp_lp_core_memory_shared.h b/components/ulp/lp_core/shared/include/ulp_lp_core_memory_shared.h index c76f4d8e2b4..890b1ddca92 100644 --- a/components/ulp/lp_core/shared/include/ulp_lp_core_memory_shared.h +++ b/components/ulp/lp_core/shared/include/ulp_lp_core_memory_shared.h @@ -12,7 +12,8 @@ extern "C" { #endif typedef struct { - uint64_t sleep_duration_us; /* Configured sleep duration for periodic wakeup, if set the ulp will automatically schedule the next wakeup */ + uint64_t sleep_duration_us; /* Configured sleep duration for periodic wakeup, if set the ulp will automatically schedule the next wakeup */ + uint64_t sleep_duration_ticks; /* Configured sleep duration, in LP-timer clock ticks, if set it allows us to skip doing integer division when configuring the timer */ } ulp_lp_core_memory_shared_cfg_t; /** diff --git a/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c b/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c index d3947b338b0..b39e5ba0f2c 100644 --- a/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c +++ b/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c @@ -42,7 +42,15 @@ uint64_t ulp_lp_core_lp_timer_get_cycle_count(void) void ulp_lp_core_lp_timer_set_wakeup_time(uint64_t sleep_duration_us) { uint64_t cycle_cnt = ulp_lp_core_lp_timer_get_cycle_count(); - uint64_t alarm_target = cycle_cnt + sleep_duration_us * (1 << RTC_CLK_CAL_FRACT) / clk_ll_rtc_slow_load_cal(); + uint64_t alarm_target = cycle_cnt + ulp_lp_core_lp_timer_calculate_sleep_ticks(sleep_duration_us); + + lp_timer_hal_set_alarm_target(alarm_target); +} + +void ulp_lp_core_lp_timer_set_wakeup_ticks(uint64_t sleep_duration_ticks) +{ + uint64_t cycle_cnt = ulp_lp_core_lp_timer_get_cycle_count(); + uint64_t alarm_target = cycle_cnt + sleep_duration_ticks; lp_timer_hal_set_alarm_target(alarm_target); } @@ -53,4 +61,9 @@ void ulp_lp_core_lp_timer_disable(void) lp_timer_ll_clear_lp_alarm_intr_status(lp_timer_context.dev); } +uint64_t ulp_lp_core_lp_timer_calculate_sleep_ticks(uint64_t sleep_duration_us) +{ + return (sleep_duration_us * (1 << RTC_CLK_CAL_FRACT) / clk_ll_rtc_slow_load_cal()); +} + #endif //SOC_LP_TIMER_SUPPORTED From 8d22f1c609a919cde09068a551b5004d67573cbc Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 31 Jul 2024 12:01:38 +0800 Subject: [PATCH 503/548] fix: fixed occasional wdt issue in multi-connection scenarios on ESP32H2 --- components/bt/controller/esp32c6/Kconfig.in | 4 ++-- components/bt/controller/esp32h2/Kconfig.in | 4 ++-- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index ddcfbba132e..07089db18e2 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -343,12 +343,12 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY Only operate in dump mode config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - bool "Storage ble controller log to flash(experimental)" + bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY depends on BT_LE_CONTROLLER_LOG_ENABLED default n help - Storage ble controller log to flash. + Store ble controller logs to flash memory. config BT_LE_CONTROLLER_LOG_PARTITION_SIZE int "size of ble controller log partition(Multiples of 4K)" diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index d68caa226cf..d188d03230b 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -334,12 +334,12 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY Only operate in dump mode config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - bool "Storage ble controller log to flash(experimental)" + bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY depends on BT_LE_CONTROLLER_LOG_ENABLED default n help - Storage ble controller log to flash. + Store ble controller logs to flash memory. config BT_LE_CONTROLLER_LOG_PARTITION_SIZE int "size of ble controller log partition(Multiples of 4K)" diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index 2085541b6e9..3396205d486 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit 2085541b6e9963640e4090401faaf2061758d847 +Subproject commit 3396205d48647372568ba67e41c4e08917ef1038 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 9e29a8b39fe..85174c19ced 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 9e29a8b39fe81ac82064dc4525e56e0faa9e1b8a +Subproject commit 85174c19ced288f48254b01957609b8423c757bf From 5509cda7cae1dc8facb38f32ae1c38a9947ce182 Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 31 Jul 2024 12:17:27 +0800 Subject: [PATCH 504/548] fix: fixed directed adv can't be conneted when adv filter is 0x2 on ESP32C2 --- components/bt/controller/esp32c2/Kconfig.in | 4 ++-- components/bt/controller/esp32c2/bt.c | 21 ++++++++++--------- .../bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 5 ----- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index e522e416034..2ce4ca02500 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -295,12 +295,12 @@ config BT_LE_CONTROLLER_LOG_DUMP_ONLY Only operate in dump mode config BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - bool "Storage ble controller log to flash(experimental)" + bool "Store ble controller logs to flash(Experimental)" depends on !BT_LE_CONTROLLER_LOG_DUMP_ONLY depends on BT_LE_CONTROLLER_LOG_ENABLED default n help - Storage ble controller log to flash. + Store ble controller logs to flash memory. config BT_LE_CONTROLLER_LOG_PARTITION_SIZE int "size of ble controller log partition(Multiples of 4K)" diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 5a635a83a2f..9f158e84c43 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -420,18 +420,19 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b void esp_ble_controller_log_dump_all(bool output) { + if (log_output_mode == LOG_STORAGE_TO_FLASH) { #if CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE - esp_bt_read_ctrl_log_from_flash(output); -#else - portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; - - portENTER_CRITICAL_SAFE(&spinlock); - esp_panic_handler_reconfigure_wdts(5000); - BT_ASSERT_PRINT("\r\n[DUMP_START:"); - ble_log_async_output_dump_all(output); - BT_ASSERT_PRINT(":DUMP_END]\r\n"); - portEXIT_CRITICAL_SAFE(&spinlock); + esp_bt_read_ctrl_log_from_flash(output); #endif // CONFIG_BT_LE_CONTROLLER_LOG_STORAGE_ENABLE + } else { + portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED; + portENTER_CRITICAL_SAFE(&spinlock); + esp_panic_handler_reconfigure_wdts(5000); + BT_ASSERT_PRINT("\r\n[DUMP_START:"); + ble_log_async_output_dump_all(output); + BT_ASSERT_PRINT(":DUMP_END]\r\n"); + portEXIT_CRITICAL_SAFE(&spinlock); + } } #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index fc65dbee209..eefd7794e62 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit fc65dbee2093051bdf8dd45fd4346811a39a4ff8 +Subproject commit eefd7794e627dca4fa20f2d8e43385c1360d9a58 diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 336246649c2..007732f4e28 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -583,8 +583,6 @@ r_ble_ll_adv_scan_req_rxd = 0x40000c98; r_ble_ll_adv_scan_rsp_legacy_pdu_make = 0x40000c9c; r_ble_ll_adv_scan_rsp_pdu_make = 0x40000ca0; r_ble_ll_adv_scheduled = 0x40000ca4; -r_ble_ll_adv_set_adv_params = 0x40000cb0; -r_ble_ll_adv_set_enable = 0x40000cb4; r_ble_ll_adv_set_random_addr = 0x40000cb8; r_ble_ll_adv_sm_deinit = 0x40000cc4; r_ble_ll_adv_sm_event_init = 0x40000cc8; @@ -689,8 +687,6 @@ r_ble_ll_ctrl_rej_ext_ind_make = 0x40000ec0; r_ble_ll_ctrl_reject_ind_send = 0x40000ec4; r_ble_ll_ctrl_rx_chanmap_req = 0x40000ec8; r_ble_ll_ctrl_rx_conn_param_req = 0x40000ecc; -r_ble_ll_ctrl_rx_conn_param_rsp = 0x40000ed0; -r_ble_ll_ctrl_rx_conn_update = 0x40000ed4; r_ble_ll_ctrl_rx_enc_req = 0x40000ed8; r_ble_ll_ctrl_rx_enc_rsp = 0x40000edc; r_ble_ll_ctrl_rx_feature_req = 0x40000ee0; @@ -780,7 +776,6 @@ r_ble_ll_hci_rd_local_version = 0x4000106c; r_ble_ll_hci_scan_set_enable = 0x40001070; r_ble_ll_hci_send_adv_report = 0x40001074; r_ble_ll_hci_send_dir_adv_report = 0x40001078; -r_ble_ll_hci_send_ext_adv_report = 0x4000107c; r_ble_ll_hci_send_noop = 0x40001084; r_ble_ll_hci_set_adv_data = 0x40001088; r_ble_ll_hci_set_le_event_mask = 0x4000108c; From 8b8bb72ad496a13d163072015ad61fa02e2807e2 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 15 May 2024 19:07:58 +0800 Subject: [PATCH 505/548] feat(uart): support uart module sleep retention on c6/h2/p4 --- .../esp_driver_uart/include/driver/uart.h | 7 + components/esp_driver_uart/src/uart.c | 114 +++++++++++++- .../test_apps/uart/main/CMakeLists.txt | 14 +- .../uart/main/test_uart_auto_lightsleep.c | 15 +- .../test_apps/uart/main/test_uart_retention.c | 148 ++++++++++++++++++ .../test_apps/uart/pytest_uart.py | 19 ++- .../test_apps/uart/sdkconfig.ci.release | 1 + .../test_apps/uart_vfs/main/test_app_main.c | 2 +- components/esp_hw_support/sleep_modes.c | 4 +- .../esp_hw_support/sleep_system_peripheral.c | 15 +- components/hal/esp32/include/hal/uart_ll.h | 8 +- components/hal/esp32c2/include/hal/uart_ll.h | 8 +- components/hal/esp32c3/include/hal/uart_ll.h | 8 +- components/hal/esp32c5/include/hal/gpio_ll.h | 2 + components/hal/esp32c6/include/hal/gpio_ll.h | 2 + components/hal/esp32c6/include/hal/uart_ll.h | 10 +- components/hal/esp32c61/include/hal/gpio_ll.h | 2 + components/hal/esp32c61/include/hal/uart_ll.h | 6 +- components/hal/esp32h2/include/hal/gpio_ll.h | 2 + components/hal/esp32h2/include/hal/uart_ll.h | 10 +- components/hal/esp32p4/include/hal/gpio_ll.h | 2 + components/hal/esp32p4/include/hal/uart_ll.h | 13 +- components/hal/esp32s2/include/hal/uart_ll.h | 10 +- components/hal/esp32s3/include/hal/uart_ll.h | 8 +- components/soc/esp32/uart_periph.c | 21 +-- components/soc/esp32c2/uart_periph.c | 2 - components/soc/esp32c3/uart_periph.c | 20 +-- components/soc/esp32c5/beta3/gdma_periph.c | 6 +- .../beta3/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32c5/beta3/include/soc/soc_caps.h | 2 + .../include/soc/system_periph_retention.h | 10 -- .../esp32c5/beta3/system_retention_periph.c | 10 -- components/soc/esp32c5/beta3/uart_periph.c | 43 ++++- components/soc/esp32c5/mp/gdma_periph.c | 6 +- components/soc/esp32c5/mp/uart_periph.c | 3 - components/soc/esp32c6/gdma_periph.c | 2 +- .../esp32c6/include/soc/Kconfig.soc_caps.in | 8 + .../include/soc/retention_periph_defs.h | 9 +- components/soc/esp32c6/include/soc/soc_caps.h | 2 + .../include/soc/system_periph_retention.h | 24 +-- .../soc/esp32c6/system_retention_periph.c | 10 -- components/soc/esp32c6/uart_periph.c | 55 ++++++- components/soc/esp32c61/uart_periph.c | 3 - components/soc/esp32h2/gdma_periph.c | 2 +- .../esp32h2/include/soc/Kconfig.soc_caps.in | 8 + .../include/soc/retention_periph_defs.h | 11 +- components/soc/esp32h2/include/soc/soc_caps.h | 3 + .../include/soc/system_periph_retention.h | 24 +-- .../soc/esp32h2/system_retention_periph.c | 10 -- components/soc/esp32h2/uart_periph.c | 54 ++++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../include/soc/retention_periph_defs.h | 20 ++- components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../include/soc/system_periph_retention.h | 10 -- .../soc/esp32p4/system_retention_periph.c | 10 -- components/soc/esp32p4/uart_periph.c | 73 ++++++++- components/soc/esp32s2/uart_periph.c | 20 +-- components/soc/esp32s3/uart_periph.c | 21 +-- components/soc/include/soc/gdma_periph.h | 3 - components/soc/include/soc/i2c_periph.h | 4 +- components/soc/include/soc/regdma.h | 1 + components/soc/include/soc/uart_periph.h | 17 +- docs/en/api-reference/peripherals/uart.rst | 4 + docs/zh_CN/api-reference/peripherals/uart.rst | 4 + tools/ci/check_copyright_ignore.txt | 4 - 65 files changed, 704 insertions(+), 274 deletions(-) create mode 100644 components/esp_driver_uart/test_apps/uart/main/test_uart_retention.c diff --git a/components/esp_driver_uart/include/driver/uart.h b/components/esp_driver_uart/include/driver/uart.h index 2ade613f599..903bd670597 100644 --- a/components/esp_driver_uart/include/driver/uart.h +++ b/components/esp_driver_uart/include/driver/uart.h @@ -46,6 +46,13 @@ typedef struct { lp_uart_sclk_t lp_source_clk; /*!< LP_UART source clock selection */ #endif }; + struct { +#if SOC_UART_SUPPORT_SLEEP_RETENTION + uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the HP UART registers before entering/after exiting sleep mode. + By this approach, the system can power off HP UART's power domain. + This can save power, but at the expense of more RAM being consumed */ +#endif + } flags; /*!< Configuration flags */ } uart_config_t; /** diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index b746a86c624..cfc22442461 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -5,6 +5,7 @@ */ #include #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_intr_alloc.h" @@ -32,6 +33,7 @@ #include "esp_rom_gpio.h" #include "clk_ctrl_os.h" #include "esp_pm.h" +#include "esp_private/sleep_retention.h" #ifdef CONFIG_UART_ISR_IN_IRAM #define UART_ISR_ATTR IRAM_ATTR @@ -95,10 +97,11 @@ static const char *UART_TAG = "uart"; // Check actual UART mode set #define UART_IS_MODE_SET(uart_number, mode) ((p_uart_obj[uart_number]->uart_mode == mode)) -#define UART_CONTEXT_INIT_DEF(uart_num) {\ - .hal.dev = UART_LL_GET_HW(uart_num),\ - INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)\ - .hw_enabled = false,\ +#define UART_CONTEXT_INIT_DEF(uart_num) { \ + .port_id = uart_num, \ + .hal.dev = UART_LL_GET_HW(uart_num), \ + INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \ + .hw_enabled = false, \ } typedef struct { @@ -155,9 +158,15 @@ typedef struct { } uart_obj_t; typedef struct { + _lock_t mutex; /*!< Protect uart_module_enable, uart_module_disable, retention, etc. */ + uart_port_t port_id; uart_hal_context_t hal; /*!< UART hal context*/ DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) bool hw_enabled; +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + bool retention_link_inited; /*!< Mark whether the retention link is inited */ + bool retention_link_created; /*!< Mark whether the retention link is created */ +#endif } uart_context_t; static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; @@ -181,9 +190,13 @@ static uart_context_t uart_context[UART_NUM_MAX] = { static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED; +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +static esp_err_t uart_create_sleep_retention_link_cb(void *arg); +#endif + static void uart_module_enable(uart_port_t uart_num) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_acquire(&(uart_context[uart_num].mutex)); if (uart_context[uart_num].hw_enabled != true) { if (uart_num < SOC_UART_HP_NUM) { HP_UART_BUS_CLK_ATOMIC() { @@ -194,6 +207,28 @@ static void uart_module_enable(uart_port_t uart_num) uart_ll_reset_register(uart_num); } } + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Initialize sleep retention module for HP UART + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { // Console uart retention has been taken care in sleep_sys_periph_stdout_console_uart_retention_init + assert(!uart_context[uart_num].retention_link_inited); + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = uart_create_sleep_retention_link_cb, + .arg = &uart_context[uart_num], + }, + }, + .depends = BIT(SLEEP_RETENTION_MODULE_CLOCK_SYSTEM), + }; + if (sleep_retention_module_init(module, &init_param) == ESP_OK) { + uart_context[uart_num].retention_link_inited = true; + } else { + ESP_LOGW(UART_TAG, "init sleep retention failed for uart%d, power domain may be turned off during sleep", uart_num); + } + } +#endif } #if (SOC_UART_LP_NUM >= 1) else { @@ -205,14 +240,24 @@ static void uart_module_enable(uart_port_t uart_num) #endif uart_context[uart_num].hw_enabled = true; } - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_release(&(uart_context[uart_num].mutex)); } static void uart_module_disable(uart_port_t uart_num) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_acquire(&(uart_context[uart_num].mutex)); if (uart_context[uart_num].hw_enabled != false) { if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Uninitialize sleep retention module for HP UART + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + assert(!uart_context[uart_num].retention_link_created); // HP UART sleep retention should have been freed at this moment + if (uart_context[uart_num].retention_link_inited) { + sleep_retention_module_deinit(module); + uart_context[uart_num].retention_link_inited = false; + } +#endif + HP_UART_BUS_CLK_ATOMIC() { uart_ll_enable_bus_clock(uart_num, false); } @@ -226,7 +271,7 @@ static void uart_module_disable(uart_port_t uart_num) #endif uart_context[uart_num].hw_enabled = false; } - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + _lock_release(&(uart_context[uart_num].mutex)); } esp_err_t uart_get_sclk_freq(uart_sclk_t sclk, uint32_t *out_freq_hz) @@ -799,6 +844,31 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf uart_module_enable(uart_num); +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Create sleep retention link if desired + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { + _lock_acquire(&(uart_context[uart_num].mutex)); + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + if (uart_config->flags.backup_before_sleep && !uart_context[uart_num].retention_link_created) { + if (uart_context[uart_num].retention_link_inited) { + if (sleep_retention_module_allocate(module) == ESP_OK) { + uart_context[uart_num].retention_link_created = true; + } else { + // Even though the sleep retention module create failed, UART driver should still work, so just warning here + ESP_LOGW(UART_TAG, "create retention module failed, power domain can't turn off"); + } + } else { + ESP_LOGW(UART_TAG, "retention module not initialized first, unable to create retention module"); + } + } else if (!uart_config->flags.backup_before_sleep && uart_context[uart_num].retention_link_created) { + assert(uart_context[uart_num].retention_link_inited); + sleep_retention_module_free(module); + uart_context[uart_num].retention_link_created = false; + } + _lock_release(&(uart_context[uart_num].mutex)); + } +#endif + soc_module_clk_t uart_sclk_sel = 0; // initialize to an invalid module clock ID if (uart_num < SOC_UART_HP_NUM) { uart_sclk_sel = (soc_module_clk_t)((uart_config->source_clk) ? uart_config->source_clk : UART_SCLK_DEFAULT); // if no specifying the clock source (soc_module_clk_t starts from 1), then just use the default clock @@ -1711,6 +1781,20 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) periph_rtc_dig_clk8m_disable(); } #endif + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // Free sleep retention link for HP UART + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM && uart_num < SOC_UART_HP_NUM) { + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + _lock_acquire(&(uart_context[uart_num].mutex)); + if (uart_context[uart_num].retention_link_created) { + assert(uart_context[uart_num].retention_link_inited); + sleep_retention_module_free(module); + uart_context[uart_num].retention_link_created = false; + } + _lock_release(&(uart_context[uart_num].mutex)); + } +#endif uart_module_disable(uart_num); return ESP_OK; } @@ -1866,3 +1950,17 @@ void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout) p_uart_obj[uart_num]->rx_always_timeout_flg = false; } } + +#if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP +static esp_err_t uart_create_sleep_retention_link_cb(void *arg) +{ + uart_context_t *group = (uart_context_t *)arg; + uart_port_t uart_num = group->port_id; + sleep_retention_module_t module = UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num); + esp_err_t err = sleep_retention_entries_create(uart_reg_retention_info[uart_num].regdma_entry_array, + uart_reg_retention_info[uart_num].array_size, + REGDMA_LINK_PRI_UART, module); + ESP_RETURN_ON_ERROR(err, UART_TAG, "create retention link failed"); + return ESP_OK; +} +#endif diff --git a/components/esp_driver_uart/test_apps/uart/main/CMakeLists.txt b/components/esp_driver_uart/test_apps/uart/main/CMakeLists.txt index 22ab1202d2a..27ff3d84b7d 100644 --- a/components/esp_driver_uart/test_apps/uart/main/CMakeLists.txt +++ b/components/esp_driver_uart/test_apps/uart/main/CMakeLists.txt @@ -1,7 +1,19 @@ +set(srcs "test_app_main.c" + "test_uart.c") + +if(CONFIG_PM_ENABLE) + list(APPEND srcs "test_uart_auto_lightsleep.c") +endif() + +# Only if the target supports uart retention and the sdkconfig.ci.xxx contains at least PM_ENABLE=y +if(CONFIG_SOC_UART_SUPPORT_SLEEP_RETENTION AND CONFIG_PM_ENABLE) + list(APPEND srcs "test_uart_retention.c") +endif() + # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE idf_component_register( - SRCS "test_app_main.c" "test_uart.c" "test_uart_auto_lightsleep.c" + SRCS ${srcs} REQUIRES esp_driver_uart unity esp_psram test_utils esp_driver_gpio esp_pm PRIV_INCLUDE_DIRS . WHOLE_ARCHIVE diff --git a/components/esp_driver_uart/test_apps/uart/main/test_uart_auto_lightsleep.c b/components/esp_driver_uart/test_apps/uart/main/test_uart_auto_lightsleep.c index b409deafd81..a7df3a10bdc 100644 --- a/components/esp_driver_uart/test_apps/uart/main/test_uart_auto_lightsleep.c +++ b/components/esp_driver_uart/test_apps/uart/main/test_uart_auto_lightsleep.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,15 +27,14 @@ #if CONFIG_XTAL_FREQ_40 #define MIN_FREQ 10 +#elif CONFIG_XTAL_FREQ_48 +#define MIN_FREQ 12 #elif CONFIG_XTAL_FREQ_32 #define MIN_FREQ 8 #elif CONFIG_XTAL_FREQ_26 #define MIN_FREQ 13 #endif -#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) -#if CONFIG_PM_ENABLE - TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]") { uart_port_param_t port_param = {}; @@ -82,10 +81,8 @@ TEST_CASE("uart tx won't be blocked by auto light sleep", "[uart]") uart_driver_delete(port_num); free(data); -#if CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP - //When PD_CPU enabled, retention may cause 14K memory leak. Workaround to release the memory - sleep_cpu_configure(false); +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + pm_config.light_sleep_enable = false; + TEST_ESP_OK(esp_pm_configure(&pm_config)); #endif } -#endif // CONFIG_PM_ENABLE -#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4) diff --git a/components/esp_driver_uart/test_apps/uart/main/test_uart_retention.c b/components/esp_driver_uart/test_apps/uart/main/test_uart_retention.c new file mode 100644 index 00000000000..692d24f72f8 --- /dev/null +++ b/components/esp_driver_uart/test_apps/uart/main/test_uart_retention.c @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "unity.h" +#include "driver/uart.h" +#include "esp_pm.h" +#include "esp_private/sleep_cpu.h" +#include "esp_clk_tree.h" +#include "esp_sleep.h" + +// UART retention test only need to be done on HP UART + +static const uart_port_t uart_num = UART_NUM_1; + +static void uart_init(bool backup_before_sleep) +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_DEFAULT, + .flags.backup_before_sleep = backup_before_sleep, + }; + + TEST_ESP_OK(uart_driver_install(uart_num, 256, 0, 20, NULL, 0)); + TEST_ESP_OK(uart_param_config(uart_num, &uart_config)); + TEST_ESP_OK(uart_set_loop_back(uart_num, true)); +} + +TEST_CASE("uart restored correctly after auto light sleep", "[uart][hp-uart-only]") +{ + // Configure dynamic frequency scaling: + // maximum and minimum frequencies are set in sdkconfig, + // automatic light sleep is enabled if tickless idle support is enabled. + uint32_t xtal_hz = 0; + esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz); + esp_pm_config_t pm_config = { + .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, + .min_freq_mhz = xtal_hz / 1000000, +#if CONFIG_FREERTOS_USE_TICKLESS_IDLE + .light_sleep_enable = true, +#endif + }; + TEST_ESP_OK(esp_pm_configure(&pm_config)); + + uart_init(true); + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 5; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = 0; + // Polling to read the data back to avoid getting into auto light sleep + while (size < len) { + int bytes = uart_read_bytes(uart_num, (void *)((uint32_t)rx_data + size), 1, 0); + size += bytes; + } + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + vTaskDelay(pdMS_TO_TICKS(1000)); // auto light sleep + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + + pm_config.light_sleep_enable = false; + TEST_ESP_OK(esp_pm_configure(&pm_config)); +} + +TEST_CASE("uart restored correctly after manually enter light sleep", "[uart][hp-uart-only]") +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); + sleep_cpu_configure(true); + + uart_init(true); + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 5; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20)); + TEST_ASSERT_EQUAL(len, size); + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + printf("Going into sleep...\n"); + TEST_ESP_OK(esp_light_sleep_start()); + printf("Waked up!\n"); + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + TEST_ESP_OK(sleep_cpu_configure(false)); +} + +TEST_CASE("uart won't be powered down in light sleep if retention not created", "[uart][hp-uart-only]") +{ + // Prepare a TOP PD sleep + TEST_ESP_OK(esp_sleep_enable_timer_wakeup(1 * 1000 * 1000)); + sleep_cpu_configure(true); + + uart_init(false); // backup_before_sleep set to false, sleep retention module will be inited, but not created + + // Ensure UART is fully idle before starting loopback RX/TX test + TEST_ESP_OK(uart_wait_tx_done(uart_num, portMAX_DELAY)); + vTaskDelay(pdMS_TO_TICKS(20)); // make sure last byte has flushed from TX FIFO + TEST_ESP_OK(uart_flush_input(uart_num)); + + for (int i = 0; i < 3; i++) { + char tx_data[20] = {0}; + char rx_data[20] = {0}; + int len = sprintf(tx_data, "Hello World %d!\n", i); + uart_write_bytes(uart_num, tx_data, len); + int size = uart_read_bytes(uart_num, rx_data, len, pdMS_TO_TICKS(20)); + TEST_ASSERT_EQUAL(len, size); + rx_data[len] = '\0'; + printf("%s", rx_data); + TEST_ASSERT_TRUE(strcmp(tx_data, rx_data) == 0); + + printf("Going into sleep...\n"); + TEST_ESP_OK(esp_light_sleep_start()); // sleep without powering down TOP domain + printf("Waked up!\n"); + } + + TEST_ESP_OK(uart_driver_delete(uart_num)); + TEST_ESP_OK(sleep_cpu_configure(false)); +} diff --git a/components/esp_driver_uart/test_apps/uart/pytest_uart.py b/components/esp_driver_uart/test_apps/uart/pytest_uart.py index 4c94d856523..e1be06ea5f9 100644 --- a/components/esp_driver_uart/test_apps/uart/pytest_uart.py +++ b/components/esp_driver_uart/test_apps/uart/pytest_uart.py @@ -28,15 +28,18 @@ def test_uart_single_dev(case_tester) -> None: # type: ignore dut = case_tester.first_dut chip_type = dut.app.target - for uart_port in input_argv.get(chip_type, []): - for case in case_tester.test_menu: - dut.serial.hard_reset() - dut._get_ready() - dut.confirm_write(case.index, expect_str=f'Running {case.name}...') + for case in case_tester.test_menu: + if 'hp-uart-only' not in case.groups: + for uart_port in input_argv.get(chip_type, []): + dut.serial.hard_reset() + dut._get_ready() + dut.confirm_write(case.index, expect_str=f'Running {case.name}...') - dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) - dut.write(f'{uart_port}') - dut.expect_unity_test_output() + dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) + dut.write(f'{uart_port}') + dut.expect_unity_test_output() + else: + dut._run_normal_case(case, reset=True) @pytest.mark.esp32s3 diff --git a/components/esp_driver_uart/test_apps/uart/sdkconfig.ci.release b/components/esp_driver_uart/test_apps/uart/sdkconfig.ci.release index 673b6f8f748..a6be7c649be 100644 --- a/components/esp_driver_uart/test_apps/uart/sdkconfig.ci.release +++ b/components/esp_driver_uart/test_apps/uart/sdkconfig.ci.release @@ -1,5 +1,6 @@ CONFIG_PM_ENABLE=y CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y CONFIG_COMPILER_OPTIMIZATION_SIZE=y CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_uart/test_apps/uart_vfs/main/test_app_main.c b/components/esp_driver_uart/test_apps/uart_vfs/main/test_app_main.c index 6ee4144067a..6ab21f1f673 100644 --- a/components/esp_driver_uart/test_apps/uart_vfs/main/test_app_main.c +++ b/components/esp_driver_uart/test_apps/uart_vfs/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated, the threadhold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (400) +#define TEST_MEMORY_LEAK_THRESHOLD (500) void setUp(void) { diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 60e08b84515..e30bc2038bc 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -986,7 +986,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m /* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode. In order to avoid the leakage of the SPI cs pin, hold it here */ #if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359: related rtcio ll func not supported yet +#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 if(!(pd_flags & RTC_SLEEP_PD_VDDSDIO)) { /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ gpio_ll_hold_en(&GPIO, SPI_CS0_GPIO_NUM); @@ -1030,7 +1030,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m /* Unhold the SPI CS pin */ #if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359: related rtcio ll func not supported yet +#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 if(!(pd_flags & RTC_SLEEP_PD_VDDSDIO)) { gpio_ll_hold_dis(&GPIO, SPI_CS0_GPIO_NUM); } diff --git a/components/esp_hw_support/sleep_system_peripheral.c b/components/esp_hw_support/sleep_system_peripheral.c index 2f37fb1542c..97cbafd73b4 100644 --- a/components/esp_hw_support/sleep_system_peripheral.c +++ b/components/esp_hw_support/sleep_system_peripheral.c @@ -10,6 +10,7 @@ #include "sdkconfig.h" #include "soc/soc_caps.h" #include "soc/system_periph_retention.h" +#include "soc/uart_periph.h" #include "esp_sleep.h" #include "esp_log.h" @@ -52,13 +53,17 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_tee_apm_retention_init } #endif -static __attribute__((unused)) esp_err_t sleep_sys_periph_uart0_retention_init(void *arg) +#if CONFIG_ESP_CONSOLE_UART +static __attribute__((unused)) esp_err_t sleep_sys_periph_stdout_console_uart_retention_init(void *arg) { - esp_err_t err = sleep_retention_entries_create(uart_regs_retention, ARRAY_SIZE(uart_regs_retention), REGDMA_LINK_PRI_SYS_PERIPH_HIGH, SLEEP_RETENTION_MODULE_SYS_PERIPH); + esp_err_t err = sleep_retention_entries_create(uart_reg_retention_info[CONFIG_ESP_CONSOLE_UART_NUM].regdma_entry_array, + uart_reg_retention_info[CONFIG_ESP_CONSOLE_UART_NUM].array_size, + REGDMA_LINK_PRI_SYS_PERIPH_HIGH, SLEEP_RETENTION_MODULE_SYS_PERIPH); ESP_RETURN_ON_ERROR(err, TAG, "failed to allocate memory for digital peripherals (%s) retention", "UART"); - ESP_LOGD(TAG, "UART sleep retention initialization"); + ESP_LOGD(TAG, "stdout console UART sleep retention initialization"); return ESP_OK; } +#endif static __attribute__((unused)) esp_err_t sleep_sys_periph_iomux_retention_init(void *arg) { @@ -119,8 +124,10 @@ static __attribute__((unused)) esp_err_t sleep_sys_periph_retention_init(void *a err = sleep_sys_periph_tee_apm_retention_init(arg); if(err) goto error; #endif - err = sleep_sys_periph_uart0_retention_init(arg); +#if CONFIG_ESP_CONSOLE_UART + err = sleep_sys_periph_stdout_console_uart_retention_init(arg); if(err) goto error; +#endif err = sleep_sys_periph_iomux_retention_init(arg); if(err) goto error; err = sleep_sys_periph_spimem_retention_init(arg); diff --git a/components/hal/esp32/include/hal/uart_ll.h b/components/hal/esp32/include/hal/uart_ll.h index 218fd52ccd9..02134517e7a 100644 --- a/components/hal/esp32/include/hal/uart_ll.h +++ b/components/hal/esp32/include/hal/uart_ll.h @@ -312,7 +312,7 @@ FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_ * * @param hw Beginning address of the peripheral registers. * @param buf The data buffer. - * @param wr_len The data length needs to be writen. + * @param wr_len The data length needs to be written. * * @return None */ @@ -535,7 +535,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -600,7 +600,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -894,7 +894,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32c2/include/hal/uart_ll.h b/components/hal/esp32c2/include/hal/uart_ll.h index 67eda746fe2..7c5e3d12ed0 100644 --- a/components/hal/esp32c2/include/hal/uart_ll.h +++ b/components/hal/esp32c2/include/hal/uart_ll.h @@ -339,7 +339,7 @@ FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_ * * @param hw Beginning address of the peripheral registers. * @param buf The data buffer. - * @param wr_len The data length needs to be writen. + * @param wr_len The data length needs to be written. * * @return None */ @@ -518,7 +518,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -583,7 +583,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -881,7 +881,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index 9b83168323e..f9f00ad85a8 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -342,7 +342,7 @@ FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_ * * @param hw Beginning address of the peripheral registers. * @param buf The data buffer. - * @param wr_len The data length needs to be writen. + * @param wr_len The data length needs to be written. * * @return None */ @@ -521,7 +521,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -586,7 +586,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -884,7 +884,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32c5/include/hal/gpio_ll.h b/components/hal/esp32c5/include/hal/gpio_ll.h index 75d809bc73b..d064b782687 100644 --- a/components/hal/esp32c5/include/hal/gpio_ll.h +++ b/components/hal/esp32c5/include/hal/gpio_ll.h @@ -426,6 +426,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -437,6 +438,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index 0b701fde431..67676fbb41f 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -395,6 +395,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -406,6 +407,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32c6/include/hal/uart_ll.h b/components/hal/esp32c6/include/hal/uart_ll.h index 88759dde2e6..cbbf308bdc7 100644 --- a/components/hal/esp32c6/include/hal/uart_ll.h +++ b/components/hal/esp32c6/include/hal/uart_ll.h @@ -61,6 +61,10 @@ extern "C" { #define UART_LL_PCR_REG_GET(hw, reg_suffix, field_suffix) \ (((hw) == &UART0) ? PCR.uart0_##reg_suffix.uart0_##field_suffix : PCR.uart1_##reg_suffix.uart1_##field_suffix) +// UART sleep retention module +#define UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num) ((uart_num == UART_NUM_0) ? SLEEP_RETENTION_MODULE_UART0 : \ + (uart_num == UART_NUM_1) ? SLEEP_RETENTION_MODULE_UART1 : -1) + // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1 << 0), @@ -704,7 +708,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -771,7 +775,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -1102,7 +1106,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32c61/include/hal/gpio_ll.h b/components/hal/esp32c61/include/hal/gpio_ll.h index 743b72952ef..d4c5ac80eb9 100644 --- a/components/hal/esp32c61/include/hal/gpio_ll.h +++ b/components/hal/esp32c61/include/hal/gpio_ll.h @@ -396,6 +396,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -407,6 +408,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32c61/include/hal/uart_ll.h b/components/hal/esp32c61/include/hal/uart_ll.h index bb7873e317f..fb2dc72b858 100644 --- a/components/hal/esp32c61/include/hal/uart_ll.h +++ b/components/hal/esp32c61/include/hal/uart_ll.h @@ -556,7 +556,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -623,7 +623,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -929,7 +929,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h index 96da5be885a..bdd8bcca234 100644 --- a/components/hal/esp32h2/include/hal/gpio_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -439,6 +439,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, gpio_num_t gpio_ * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 |= GPIO_HOLD_MASK[gpio_num]; @@ -450,6 +451,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, gpio_num_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { LP_AON.gpio_hold0.gpio_hold0 &= ~GPIO_HOLD_MASK[gpio_num]; diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index 9e018b2bdb9..14cbbfb14f4 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -57,6 +57,10 @@ extern "C" { #define UART_LL_PCR_REG_GET(hw, reg_suffix, field_suffix) \ (((hw) == &UART0) ? PCR.uart0_##reg_suffix.uart0_##field_suffix : PCR.uart1_##reg_suffix.uart1_##field_suffix) +// UART sleep retention module +#define UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num) ((uart_num == UART_NUM_0) ? SLEEP_RETENTION_MODULE_UART0 : \ + (uart_num == UART_NUM_1) ? SLEEP_RETENTION_MODULE_UART1 : -1) + // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1 << 0), @@ -554,7 +558,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -621,7 +625,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -928,7 +932,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index ff3e0ea90e7..2cfb6467b74 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -472,6 +472,7 @@ static inline void gpio_ll_get_drive_capability(gpio_dev_t *hw, uint32_t gpio_nu * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) { uint64_t bit_mask = 1ULL << gpio_num; @@ -497,6 +498,7 @@ static inline void gpio_ll_hold_en(gpio_dev_t *hw, uint32_t gpio_num) * @param hw Peripheral GPIO hardware instance address. * @param gpio_num GPIO number, only support output GPIOs */ +__attribute__((always_inline)) static inline void gpio_ll_hold_dis(gpio_dev_t *hw, uint32_t gpio_num) { uint64_t bit_mask = 1ULL << gpio_num; diff --git a/components/hal/esp32p4/include/hal/uart_ll.h b/components/hal/esp32p4/include/hal/uart_ll.h index e3f5a40d6ee..70560c235d7 100644 --- a/components/hal/esp32p4/include/hal/uart_ll.h +++ b/components/hal/esp32p4/include/hal/uart_ll.h @@ -45,6 +45,13 @@ extern "C" { #define UART_LL_FSM_IDLE (0x0) #define UART_LL_FSM_TX_WAIT_SEND (0xf) +// UART sleep retention module +#define UART_LL_SLEEP_RETENTION_MODULE_ID(uart_num) ((uart_num == UART_NUM_0) ? SLEEP_RETENTION_MODULE_UART0 : \ + (uart_num == UART_NUM_1) ? SLEEP_RETENTION_MODULE_UART1 : \ + (uart_num == UART_NUM_2) ? SLEEP_RETENTION_MODULE_UART2 : \ + (uart_num == UART_NUM_3) ? SLEEP_RETENTION_MODULE_UART3 : \ + (uart_num == UART_NUM_4) ? SLEEP_RETENTION_MODULE_UART4 : -1) + // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1 << 0), @@ -817,7 +824,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -884,7 +891,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -1215,7 +1222,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32s2/include/hal/uart_ll.h b/components/hal/esp32s2/include/hal/uart_ll.h index 601cafeeeed..4dfbeb95432 100644 --- a/components/hal/esp32s2/include/hal/uart_ll.h +++ b/components/hal/esp32s2/include/hal/uart_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -298,7 +298,7 @@ FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_ * * @param hw Beginning address of the peripheral registers. * @param buf The data buffer. - * @param wr_len The data length needs to be writen. + * @param wr_len The data length needs to be written. * * @return None */ @@ -476,7 +476,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -541,7 +541,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -832,7 +832,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/hal/esp32s3/include/hal/uart_ll.h b/components/hal/esp32s3/include/hal/uart_ll.h index 1924c241111..3dd538ec505 100644 --- a/components/hal/esp32s3/include/hal/uart_ll.h +++ b/components/hal/esp32s3/include/hal/uart_ll.h @@ -326,7 +326,7 @@ FORCE_INLINE_ATTR void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_ * * @param hw Beginning address of the peripheral registers. * @param buf The data buffer. - * @param wr_len The data length needs to be writen. + * @param wr_len The data length needs to be written. * * @return None */ @@ -505,7 +505,7 @@ FORCE_INLINE_ATTR void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num } /** - * @brief Configure the transmiter to send break chars. + * @brief Configure the transmitter to send break chars. * * @param hw Beginning address of the peripheral registers. * @param break_num The number of the break chars need to be send. @@ -569,7 +569,7 @@ FORCE_INLINE_ATTR void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcont * @brief Configure the software flow control. * * @param hw Beginning address of the peripheral registers. - * @param flow_ctrl The UART sofware flow control settings. + * @param flow_ctrl The UART software flow control settings. * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. * * @return None. @@ -860,7 +860,7 @@ FORCE_INLINE_ATTR bool uart_ll_is_hw_cts_en(uart_dev_t *hw) * @brief Configure TX signal loop back to RX module, just for the testing purposes * * @param hw Beginning address of the peripheral registers. - * @param loop_back_en Set ture to enable the loop back function, else set it false. + * @param loop_back_en Set true to enable the loop back function, else set it false. * * @return None */ diff --git a/components/soc/esp32/uart_periph.c b/components/soc/esp32/uart_periph.c index b9a590fe185..c9f0a2f4b4e 100644 --- a/components/soc/esp32/uart_periph.c +++ b/components/soc/esp32/uart_periph.c @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/uart_periph.h" @@ -49,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -83,7 +74,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { @@ -117,6 +107,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART2_INTR_SOURCE, - .module = PERIPH_UART2_MODULE, } }; diff --git a/components/soc/esp32c2/uart_periph.c b/components/soc/esp32c2/uart_periph.c index a23ff14937d..e43bcd0daf6 100644 --- a/components/soc/esp32c2/uart_periph.c +++ b/components/soc/esp32c2/uart_periph.c @@ -41,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -75,6 +74,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, }; diff --git a/components/soc/esp32c3/uart_periph.c b/components/soc/esp32c3/uart_periph.c index d4262c6776f..73eb978cbe7 100644 --- a/components/soc/esp32c3/uart_periph.c +++ b/components/soc/esp32c3/uart_periph.c @@ -1,16 +1,8 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/uart_periph.h" @@ -49,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -83,6 +74,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, }; diff --git a/components/soc/esp32c5/beta3/gdma_periph.c b/components/soc/esp32c5/beta3/gdma_periph.c index f17b916be20..49006182010 100644 --- a/components/soc/esp32c5/beta3/gdma_periph.c +++ b/components/soc/esp32c5/beta3/gdma_periph.c @@ -49,7 +49,7 @@ static const regdma_entries_config_t gdma_g0p0_regs_retention[] = { g0p0_regs_map0[0], g0p0_regs_map0[1], \ g0p0_regs_map0[2], g0p0_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x01), \ G0P0_RETENTION_MAP_BASE_1, G0P0_RETENTION_MAP_BASE_1, \ G0P0_RETENTION_REGS_CNT_1, 0, 0, \ g0p0_regs_map1[0], g0p0_regs_map1[1], \ @@ -76,7 +76,7 @@ static const regdma_entries_config_t gdma_g0p1_regs_retention[] = { g0p1_regs_map0[0], g0p1_regs_map0[1], \ g0p1_regs_map0[2], g0p1_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x01), \ G0P1_RETENTION_MAP_BASE_1, G0P1_RETENTION_MAP_BASE_1, \ G0P1_RETENTION_REGS_CNT_1, 0, 0, \ g0p1_regs_map1[0], g0p1_regs_map1[1], \ @@ -103,7 +103,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in index 51f555389be..fdfe6872e2b 100644 --- a/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/beta3/include/soc/Kconfig.soc_caps.in @@ -635,6 +635,10 @@ config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_COEX_HW_PTI bool default y diff --git a/components/soc/esp32c5/beta3/include/soc/soc_caps.h b/components/soc/esp32c5/beta3/include/soc/soc_caps.h index 4e8f3f99af9..de79e2fbada 100644 --- a/components/soc/esp32c5/beta3/include/soc/soc_caps.h +++ b/components/soc/esp32c5/beta3/include/soc/soc_caps.h @@ -497,6 +497,8 @@ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ + /*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/ #define SOC_COEX_HW_PTI (1) diff --git a/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h b/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h index b0cafd51bfd..23c82b29538 100644 --- a/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h +++ b/components/soc/esp32c5/beta3/include/soc/system_periph_retention.h @@ -48,16 +48,6 @@ extern const regdma_entries_config_t tee_apm_regs_retention[TEE_APM_RETENTION_LI #define TEE_APM_HIGH_PRI_RETENTION_LINK_LEN 1 extern const regdma_entries_config_t tee_apm_highpri_regs_retention[TEE_APM_HIGH_PRI_RETENTION_LINK_LEN]; -/** - * @brief Provide access to uart configuration registers retention - * context definition. - * - * This is an internal function of the sleep retention driver, and is not - * useful for external use. - */ -#define UART_RETENTION_LINK_LEN 3 -extern const regdma_entries_config_t uart_regs_retention[UART_RETENTION_LINK_LEN]; - /** * @brief Provide access to timer group configuration registers retention * context definition. diff --git a/components/soc/esp32c5/beta3/system_retention_periph.c b/components/soc/esp32c5/beta3/system_retention_periph.c index d2a9863ca6c..52822f92720 100644 --- a/components/soc/esp32c5/beta3/system_retention_periph.c +++ b/components/soc/esp32c5/beta3/system_retention_periph.c @@ -44,16 +44,6 @@ const regdma_entries_config_t tee_apm_highpri_regs_retention[] = { }; _Static_assert((ARRAY_SIZE(tee_apm_regs_retention) == TEE_APM_RETENTION_LINK_LEN) && (ARRAY_SIZE(tee_apm_highpri_regs_retention) == TEE_APM_HIGH_PRI_RETENTION_LINK_LEN), "Inconsistent TEE_APM retention link length definitions"); -/* UART0 Registers Context */ -#define N_REGS_UART() (((UART_ID_REG(0) - UART_INT_RAW_REG(0)) / 4) + 1) -const regdma_entries_config_t uart_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), UART_INT_RAW_REG(0), UART_INT_RAW_REG(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* uart */ - /* Note: uart register should set update reg to make the configuration take effect */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO26_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC30_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32c5/beta3/uart_periph.c b/components/soc/esp32c5/beta3/uart_periph.c index 154038a7b65..49af724e269 100644 --- a/components/soc/esp32c5/beta3/uart_periph.c +++ b/components/soc/esp32c5/beta3/uart_periph.c @@ -5,6 +5,7 @@ */ #include "soc/uart_periph.h" +#include "soc/uart_reg.h" /* Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc @@ -41,7 +42,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { // HP UART1 @@ -75,7 +75,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { // LP UART0 @@ -109,6 +108,44 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_LP_UART_INTR_SOURCE, - .module = PERIPH_LP_UART0_MODULE, + }, +}; + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + */ +#define N_REGS_UART(uart_num) (((UART_ID_REG(uart_num) - UART_INT_RAW_REG(uart_num)) / 4) + 1) +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), \ + UART_INT_RAW_REG(uart_num), UART_INT_RAW_REG(uart_num), \ + N_REGS_UART(uart_num), 0, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); + +const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM] = { + [0] = { + .regdma_entry_array = uart0_regdma_entries, + .array_size = ARRAY_SIZE(uart0_regdma_entries), + }, + [1] = { + .regdma_entry_array = uart1_regdma_entries, + .array_size = ARRAY_SIZE(uart1_regdma_entries), }, }; diff --git a/components/soc/esp32c5/mp/gdma_periph.c b/components/soc/esp32c5/mp/gdma_periph.c index 3217ef607cf..9385a76ed59 100644 --- a/components/soc/esp32c5/mp/gdma_periph.c +++ b/components/soc/esp32c5/mp/gdma_periph.c @@ -56,7 +56,7 @@ static const regdma_entries_config_t gdma_g0p0_regs_retention[] = { g0p0_regs_map0[0], g0p0_regs_map0[1], \ g0p0_regs_map0[2], g0p0_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, \ - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x01), \ G0P0_RETENTION_MAP_BASE_1, G0P0_RETENTION_MAP_BASE_1, \ G0P0_RETENTION_REGS_CNT_1, 0, 0, \ g0p0_regs_map1[0], g0p0_regs_map1[1], \ @@ -90,7 +90,7 @@ static const regdma_entries_config_t gdma_g0p1_regs_retention[] = { g0p1_regs_map0[0], g0p1_regs_map0[1], \ g0p1_regs_map0[2], g0p1_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x01), \ G0P1_RETENTION_MAP_BASE_1, G0P1_RETENTION_MAP_BASE_1, \ G0P1_RETENTION_REGS_CNT_1, 0, 0, \ g0p1_regs_map1[0], g0p1_regs_map1[1], \ @@ -125,7 +125,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_AHB_DMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/soc/esp32c5/mp/uart_periph.c b/components/soc/esp32c5/mp/uart_periph.c index e641d11f747..13a83fce13b 100644 --- a/components/soc/esp32c5/mp/uart_periph.c +++ b/components/soc/esp32c5/mp/uart_periph.c @@ -41,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { // HP UART1 @@ -75,7 +74,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { // LP UART0 @@ -109,6 +107,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_LP_UART_INTR_SOURCE, - .module = PERIPH_LP_UART0_MODULE, }, }; diff --git a/components/soc/esp32c6/gdma_periph.c b/components/soc/esp32c6/gdma_periph.c index c5795713ea1..fd24fad766c 100644 --- a/components/soc/esp32c6/gdma_periph.c +++ b/components/soc/esp32c6/gdma_periph.c @@ -84,7 +84,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 4361773ea58..34cf3fa3268 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -619,6 +619,10 @@ config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH bool default y +config SOC_I2C_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_LP_I2C_NUM int default 1 @@ -1255,6 +1259,10 @@ config SOC_UART_HAS_LP_UART bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y diff --git a/components/soc/esp32c6/include/soc/retention_periph_defs.h b/components/soc/esp32c6/include/soc/retention_periph_defs.h index 47b33960179..e0d6c4da4cc 100644 --- a/components/soc/esp32c6/include/soc/retention_periph_defs.h +++ b/components/soc/esp32c6/include/soc/retention_periph_defs.h @@ -34,6 +34,8 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_ADC = 11, SLEEP_RETENTION_MODULE_I2C0 = 12, SLEEP_RETENTION_MODULE_RMT0 = 13, + SLEEP_RETENTION_MODULE_UART0 = 14, + SLEEP_RETENTION_MODULE_UART1 = 15, /* Modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_WIFI_MAC = 26, @@ -64,6 +66,8 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_ADC = BIT(SLEEP_RETENTION_MODULE_ADC), SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), + SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), + SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), /* modem module, which includes WiFi, BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_WIFI_MAC = BIT(SLEEP_RETENTION_MODULE_WIFI_MAC), SLEEP_RETENTION_MODULE_BM_WIFI_BB = BIT(SLEEP_RETENTION_MODULE_WIFI_BB), @@ -85,7 +89,10 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_GDMA_CH2 \ | SLEEP_RETENTION_MODULE_BM_ADC \ | SLEEP_RETENTION_MODULE_BM_I2C0 \ - | SLEEP_RETENTION_MODULE_BM_RMT0) + | SLEEP_RETENTION_MODULE_BM_RMT0 \ + | SLEEP_RETENTION_MODULE_BM_UART0 \ + | SLEEP_RETENTION_MODULE_BM_UART1 \ + ) #ifdef __cplusplus } diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 257529c9232..308d0565d90 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -253,6 +253,7 @@ #define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE (1) #define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) #define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) +#define SOC_I2C_SUPPORT_SLEEP_RETENTION (1) /*-------------------------- LP_I2C CAPS -------------------------------------*/ // ESP32-C6 has 1 LP_I2C @@ -491,6 +492,7 @@ #define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */ #define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */ +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) diff --git a/components/soc/esp32c6/include/soc/system_periph_retention.h b/components/soc/esp32c6/include/soc/system_periph_retention.h index 6c84932742d..539b3500d35 100644 --- a/components/soc/esp32c6/include/soc/system_periph_retention.h +++ b/components/soc/esp32c6/include/soc/system_periph_retention.h @@ -17,7 +17,7 @@ extern "C" /** * @brief Provide access to interrupt matrix configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -27,7 +27,7 @@ extern const regdma_entries_config_t intr_matrix_regs_retention[INT_MTX_RETENTIO /** * @brief Provide access to hp_system configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -37,7 +37,7 @@ extern const regdma_entries_config_t hp_system_regs_retention[HP_SYSTEM_RETENTIO /** * @brief Provide access to TEE_APM configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -47,19 +47,9 @@ extern const regdma_entries_config_t tee_apm_regs_retention[TEE_APM_RETENTION_LI #define TEE_APM_HIGH_PRI_RETENTION_LINK_LEN 1 extern const regdma_entries_config_t tee_apm_highpri_regs_retention[TEE_APM_HIGH_PRI_RETENTION_LINK_LEN]; -/** - * @brief Provide access to uart configuration registers retention - * context defination. - * - * This is an internal function of the sleep retention driver, and is not - * useful for external use. - */ -#define UART_RETENTION_LINK_LEN 3 -extern const regdma_entries_config_t uart_regs_retention[UART_RETENTION_LINK_LEN]; - /** * @brief Provide access to timer group configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -69,7 +59,7 @@ extern const regdma_entries_config_t tg_regs_retention[TIMG_RETENTION_LINK_LEN]; /** * @brief Provide access to IOMUX configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -79,7 +69,7 @@ extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_L /** * @brief Provide access to spimem configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -89,7 +79,7 @@ extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK /** * @brief Provide access to systimer configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. diff --git a/components/soc/esp32c6/system_retention_periph.c b/components/soc/esp32c6/system_retention_periph.c index b9645c39a43..4ff06bdbcbf 100644 --- a/components/soc/esp32c6/system_retention_periph.c +++ b/components/soc/esp32c6/system_retention_periph.c @@ -44,16 +44,6 @@ const regdma_entries_config_t tee_apm_highpri_regs_retention[] = { }; _Static_assert((ARRAY_SIZE(tee_apm_regs_retention) == TEE_APM_RETENTION_LINK_LEN) && (ARRAY_SIZE(tee_apm_highpri_regs_retention) == TEE_APM_HIGH_PRI_RETENTION_LINK_LEN), "Inconsistent TEE_APM retention link length definitions"); -/* UART0 Registers Context */ -#define N_REGS_UART() (((UART_ID_REG(0) - UART_INT_RAW_REG(0)) / 4) + 1) -const regdma_entries_config_t uart_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), UART_INT_RAW_REG(0), UART_INT_RAW_REG(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* uart */ - /* Note: uart register should set update reg to make the configuration take effect */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO30_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC34_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32c6/uart_periph.c b/components/soc/esp32c6/uart_periph.c index c353d5e3b3c..22c7f99d119 100644 --- a/components/soc/esp32c6/uart_periph.c +++ b/components/soc/esp32c6/uart_periph.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "soc/uart_periph.h" +#include "soc/uart_reg.h" /* Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc @@ -41,7 +42,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { // HP UART1 @@ -75,7 +75,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { // LP UART0 @@ -109,6 +108,54 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_LP_UART_INTR_SOURCE, - .module = PERIPH_LP_UART0_MODULE, + }, +}; + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + * + * UART_INT_ENA_REG, UART_CLKDIV_SYNC_REG, UART_RX_FILT_REG, UART_CONF0_SYNC_REG, UART_CONF1_REG, + * UART_HWFC_CONF_SYNC_REG, UART_SLEEP_CONF0_REG, UART_SLEEP_CONF1_REG, UART_SLEEP_CONF2_REG, + * UART_SWFC_CONF0_SYNC_REG, UART_SWFC_CONF1_REG, UART_TXBRK_CONF_SYNC_REG, UART_IDLE_CONF_SYNC_REG, + * UART_RS485_CONF_SYNC_REG, UART_AT_CMD_PRECNT_SYNC_REG, UART_AT_CMD_POSTCNT_SYNC_REG, UART_AT_CMD_GAPTOUT_SYNC_REG, + * UART_AT_CMD_CHAR_SYNC_REG, UART_MEM_CONF_REG, UART_TOUT_CONF_SYNC_REG, UART_ID_REG + */ +#define UART_RETENTION_ADDR_MAP_REGS_CNT 21 +#define UART_RETENTION_REGS_BASE(i) UART_INT_ENA_REG(i) +static const uint32_t uart_regs_map[4] = {0x7fff6d, 0x10, 0x0, 0x0}; +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_UART_LINK(0x00), \ + UART_RETENTION_REGS_BASE(uart_num), UART_RETENTION_REGS_BASE(uart_num), \ + UART_RETENTION_ADDR_MAP_REGS_CNT, 0, 0, \ + uart_regs_map[0], uart_regs_map[1], \ + uart_regs_map[2], uart_regs_map[3] \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); + +const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM] = { + [0] = { + .regdma_entry_array = uart0_regdma_entries, + .array_size = ARRAY_SIZE(uart0_regdma_entries), + }, + [1] = { + .regdma_entry_array = uart1_regdma_entries, + .array_size = ARRAY_SIZE(uart1_regdma_entries), }, }; diff --git a/components/soc/esp32c61/uart_periph.c b/components/soc/esp32c61/uart_periph.c index 4058abaecf5..5e3c90c8cce 100644 --- a/components/soc/esp32c61/uart_periph.c +++ b/components/soc/esp32c61/uart_periph.c @@ -41,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { // HP UART1 @@ -75,7 +74,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, #if 0 //TODO: [ESP32C61] IDF-9329, IDF-9341 { // LP UART0 @@ -109,7 +107,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_LP_UART_INTR_SOURCE, - .module = PERIPH_LP_UART0_MODULE, }, #endif }; diff --git a/components/soc/esp32h2/gdma_periph.c b/components/soc/esp32h2/gdma_periph.c index c5795713ea1..fd24fad766c 100644 --- a/components/soc/esp32h2/gdma_periph.c +++ b/components/soc/esp32h2/gdma_periph.c @@ -84,7 +84,7 @@ static const regdma_entries_config_t gdma_g0p2_regs_retention[] = { g0p2_regs_map0[0], g0p2_regs_map0[1], \ g0p2_regs_map0[2], g0p2_regs_map0[3]), \ .owner = ENTRY(0) | ENTRY(2) }, - [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x00), \ + [1] = { .config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_GDMA_LINK(0x01), \ G0P2_RETENTION_MAP_BASE_1, G0P2_RETENTION_MAP_BASE_1, \ G0P2_RETENTION_REGS_CNT_1, 0, 0, \ g0p2_regs_map1[0], g0p2_regs_map1[1], \ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 21529f05101..f4097d1e6fa 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -619,6 +619,10 @@ config SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH bool default y +config SOC_I2C_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_I2S_NUM int default 1 @@ -1251,6 +1255,10 @@ config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_COEX_HW_PTI bool default y diff --git a/components/soc/esp32h2/include/soc/retention_periph_defs.h b/components/soc/esp32h2/include/soc/retention_periph_defs.h index 353bc1c2bc9..bcc1b969311 100644 --- a/components/soc/esp32h2/include/soc/retention_periph_defs.h +++ b/components/soc/esp32h2/include/soc/retention_periph_defs.h @@ -22,7 +22,7 @@ typedef enum periph_retention_module { * TEE, APM, UART, IOMUX, SPIMEM, SysTimer, etc.. */ SLEEP_RETENTION_MODULE_SYS_PERIPH = 3, /* Timer Group by target*/ - SLEEP_RETENTION_MODULE_TG0_WDT = 4, + SLEEP_RETENTION_MODULE_TG0_WDT = 4, SLEEP_RETENTION_MODULE_TG1_WDT = 5, SLEEP_RETENTION_MODULE_TG0_TIMER = 6, SLEEP_RETENTION_MODULE_TG1_TIMER = 7, @@ -35,6 +35,8 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_I2C0 = 12, SLEEP_RETENTION_MODULE_I2C1 = 13, SLEEP_RETENTION_MODULE_RMT0 = 14, + SLEEP_RETENTION_MODULE_UART0 = 15, + SLEEP_RETENTION_MODULE_UART1 = 16, /* Modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BLE_MAC = 28, @@ -64,6 +66,8 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_I2C0 = BIT(SLEEP_RETENTION_MODULE_I2C0), SLEEP_RETENTION_MODULE_BM_I2C1 = BIT(SLEEP_RETENTION_MODULE_I2C1), SLEEP_RETENTION_MODULE_BM_RMT0 = BIT(SLEEP_RETENTION_MODULE_RMT0), + SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), + SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), /* modem module, which includes BLE and 802.15.4 */ SLEEP_RETENTION_MODULE_BM_BLE_MAC = BIT(SLEEP_RETENTION_MODULE_BLE_MAC), SLEEP_RETENTION_MODULE_BM_BT_BB = BIT(SLEEP_RETENTION_MODULE_BT_BB), @@ -84,7 +88,10 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_ADC \ | SLEEP_RETENTION_MODULE_BM_I2C0 \ | SLEEP_RETENTION_MODULE_BM_I2C1 \ - | SLEEP_RETENTION_MODULE_BM_RMT0) + | SLEEP_RETENTION_MODULE_BM_RMT0 \ + | SLEEP_RETENTION_MODULE_BM_UART0 \ + | SLEEP_RETENTION_MODULE_BM_UART1 \ + ) #ifdef __cplusplus } diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 80c5b528022..715821f8afc 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -257,6 +257,7 @@ #define SOC_I2C_SLAVE_CAN_GET_STRETCH_CAUSE (1) #define SOC_I2C_SLAVE_SUPPORT_I2CRAM_ACCESS (1) #define SOC_I2C_SLAVE_SUPPORT_SLAVE_UNMATCH (1) +#define SOC_I2C_SUPPORT_SLEEP_RETENTION (1) /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1U) @@ -493,6 +494,8 @@ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ + // TODO: IDF-5679 (Copy from esp32c6, need check) /*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/ #define SOC_COEX_HW_PTI (1) diff --git a/components/soc/esp32h2/include/soc/system_periph_retention.h b/components/soc/esp32h2/include/soc/system_periph_retention.h index 6c84932742d..539b3500d35 100644 --- a/components/soc/esp32h2/include/soc/system_periph_retention.h +++ b/components/soc/esp32h2/include/soc/system_periph_retention.h @@ -17,7 +17,7 @@ extern "C" /** * @brief Provide access to interrupt matrix configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -27,7 +27,7 @@ extern const regdma_entries_config_t intr_matrix_regs_retention[INT_MTX_RETENTIO /** * @brief Provide access to hp_system configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -37,7 +37,7 @@ extern const regdma_entries_config_t hp_system_regs_retention[HP_SYSTEM_RETENTIO /** * @brief Provide access to TEE_APM configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -47,19 +47,9 @@ extern const regdma_entries_config_t tee_apm_regs_retention[TEE_APM_RETENTION_LI #define TEE_APM_HIGH_PRI_RETENTION_LINK_LEN 1 extern const regdma_entries_config_t tee_apm_highpri_regs_retention[TEE_APM_HIGH_PRI_RETENTION_LINK_LEN]; -/** - * @brief Provide access to uart configuration registers retention - * context defination. - * - * This is an internal function of the sleep retention driver, and is not - * useful for external use. - */ -#define UART_RETENTION_LINK_LEN 3 -extern const regdma_entries_config_t uart_regs_retention[UART_RETENTION_LINK_LEN]; - /** * @brief Provide access to timer group configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -69,7 +59,7 @@ extern const regdma_entries_config_t tg_regs_retention[TIMG_RETENTION_LINK_LEN]; /** * @brief Provide access to IOMUX configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -79,7 +69,7 @@ extern const regdma_entries_config_t iomux_regs_retention[IOMUX_RETENTION_LINK_L /** * @brief Provide access to spimem configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. @@ -89,7 +79,7 @@ extern const regdma_entries_config_t spimem_regs_retention[SPIMEM_RETENTION_LINK /** * @brief Provide access to systimer configuration registers retention - * context defination. + * context definition. * * This is an internal function of the sleep retention driver, and is not * useful for external use. diff --git a/components/soc/esp32h2/system_retention_periph.c b/components/soc/esp32h2/system_retention_periph.c index da52fbe53fc..d9f3c5b469f 100644 --- a/components/soc/esp32h2/system_retention_periph.c +++ b/components/soc/esp32h2/system_retention_periph.c @@ -44,16 +44,6 @@ const regdma_entries_config_t tee_apm_highpri_regs_retention[] = { }; _Static_assert((ARRAY_SIZE(tee_apm_regs_retention) == TEE_APM_RETENTION_LINK_LEN) && (ARRAY_SIZE(tee_apm_highpri_regs_retention) == TEE_APM_HIGH_PRI_RETENTION_LINK_LEN), "Inconsistent TEE_APM retention link length definitions"); -/* UART0 Registers Context */ -#define N_REGS_UART() (((UART_ID_REG(0) - UART_INT_RAW_REG(0)) / 4) + 1) -const regdma_entries_config_t uart_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), UART_INT_RAW_REG(0), UART_INT_RAW_REG(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) | ENTRY(2) }, /* uart */ - /* Note: uart register should set update reg to make the configuration take effect */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) | ENTRY(2) } -}; -_Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO27_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_FUNC31_OUT_SEL_CFG_REG - GPIO_FUNC0_OUT_SEL_CFG_REG) / 4) + 1) diff --git a/components/soc/esp32h2/uart_periph.c b/components/soc/esp32h2/uart_periph.c index a23ff14937d..7e44499e1e6 100644 --- a/components/soc/esp32h2/uart_periph.c +++ b/components/soc/esp32h2/uart_periph.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "soc/uart_periph.h" +#include "soc/uart_reg.h" /* Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc @@ -41,7 +42,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -75,6 +75,54 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, + }, +}; + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + * + * UART_INT_ENA_REG, UART_CLKDIV_SYNC_REG, UART_RX_FILT_REG, UART_CONF0_SYNC_REG, UART_CONF1_REG, + * UART_HWFC_CONF_SYNC_REG, UART_SLEEP_CONF0_REG, UART_SLEEP_CONF1_REG, UART_SLEEP_CONF2_REG, + * UART_SWFC_CONF0_SYNC_REG, UART_SWFC_CONF1_REG, UART_TXBRK_CONF_SYNC_REG, UART_IDLE_CONF_SYNC_REG, + * UART_RS485_CONF_SYNC_REG, UART_AT_CMD_PRECNT_SYNC_REG, UART_AT_CMD_POSTCNT_SYNC_REG, UART_AT_CMD_GAPTOUT_SYNC_REG, + * UART_AT_CMD_CHAR_SYNC_REG, UART_MEM_CONF_REG, UART_TOUT_CONF_SYNC_REG, UART_ID_REG + */ +#define UART_RETENTION_ADDR_MAP_REGS_CNT 21 +#define UART_RETENTION_REGS_BASE(i) UART_INT_ENA_REG(i) +static const uint32_t uart_regs_map[4] = {0x7fff6d, 0x10, 0x0, 0x0}; +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_UART_LINK(0x00), \ + UART_RETENTION_REGS_BASE(uart_num), UART_RETENTION_REGS_BASE(uart_num), \ + UART_RETENTION_ADDR_MAP_REGS_CNT, 0, 0, \ + uart_regs_map[0], uart_regs_map[1], \ + uart_regs_map[2], uart_regs_map[3] \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) | ENTRY(2) }, \ +} + +static const regdma_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); + +const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM] = { + [0] = { + .regdma_entry_array = uart0_regdma_entries, + .array_size = ARRAY_SIZE(uart0_regdma_entries), + }, + [1] = { + .regdma_entry_array = uart1_regdma_entries, + .array_size = ARRAY_SIZE(uart1_regdma_entries), }, }; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bfe0ed76641..b5b3eda07d0 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1555,6 +1555,10 @@ config SOC_UART_HAS_LP_UART bool default y +config SOC_UART_SUPPORT_SLEEP_RETENTION + bool + default y + config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND bool default y diff --git a/components/soc/esp32p4/include/soc/retention_periph_defs.h b/components/soc/esp32p4/include/soc/retention_periph_defs.h index 34219a85e0b..1460d3d5bf7 100644 --- a/components/soc/esp32p4/include/soc/retention_periph_defs.h +++ b/components/soc/esp32p4/include/soc/retention_periph_defs.h @@ -25,6 +25,12 @@ typedef enum periph_retention_module { SLEEP_RETENTION_MODULE_TG1_WDT = 4, SLEEP_RETENTION_MODULE_TG0_TIMER = 5, SLEEP_RETENTION_MODULE_TG1_TIMER = 6, + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_UART0 = 7, + SLEEP_RETENTION_MODULE_UART1 = 8, + SLEEP_RETENTION_MODULE_UART2 = 9, + SLEEP_RETENTION_MODULE_UART3 = 10, + SLEEP_RETENTION_MODULE_UART4 = 11, SLEEP_RETENTION_MODULE_MAX = 31 } periph_retention_module_t; @@ -40,6 +46,12 @@ typedef enum periph_retention_module_bitmap { SLEEP_RETENTION_MODULE_BM_TG1_WDT = BIT(SLEEP_RETENTION_MODULE_TG1_WDT), SLEEP_RETENTION_MODULE_BM_TG0_TIMER = BIT(SLEEP_RETENTION_MODULE_TG0_TIMER), SLEEP_RETENTION_MODULE_BM_TG1_TIMER = BIT(SLEEP_RETENTION_MODULE_TG1_TIMER), + /* MISC Peripherals */ + SLEEP_RETENTION_MODULE_BM_UART0 = BIT(SLEEP_RETENTION_MODULE_UART0), + SLEEP_RETENTION_MODULE_BM_UART1 = BIT(SLEEP_RETENTION_MODULE_UART1), + SLEEP_RETENTION_MODULE_BM_UART2 = BIT(SLEEP_RETENTION_MODULE_UART2), + SLEEP_RETENTION_MODULE_BM_UART3 = BIT(SLEEP_RETENTION_MODULE_UART3), + SLEEP_RETENTION_MODULE_BM_UART4 = BIT(SLEEP_RETENTION_MODULE_UART4), SLEEP_RETENTION_MODULE_BM_ALL = (uint32_t)-1 } periph_retention_module_bitmap_t; @@ -49,7 +61,13 @@ typedef enum periph_retention_module_bitmap { | SLEEP_RETENTION_MODULE_BM_TG0_WDT \ | SLEEP_RETENTION_MODULE_BM_TG1_WDT \ | SLEEP_RETENTION_MODULE_BM_TG0_TIMER \ - | SLEEP_RETENTION_MODULE_BM_TG1_TIMER) + | SLEEP_RETENTION_MODULE_BM_TG1_TIMER \ + | SLEEP_RETENTION_MODULE_BM_UART0 \ + | SLEEP_RETENTION_MODULE_BM_UART1 \ + | SLEEP_RETENTION_MODULE_BM_UART2 \ + | SLEEP_RETENTION_MODULE_BM_UART3 \ + | SLEEP_RETENTION_MODULE_BM_UART4 \ + ) #ifdef __cplusplus } diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 55f3b8565ae..2465dd497a0 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -606,6 +606,7 @@ #define SOC_UART_SUPPORT_XTAL_CLK (1) /*!< Support XTAL clock as the clock source */ #define SOC_UART_SUPPORT_WAKEUP_INT (1) /*!< Support UART wakeup interrupt */ #define SOC_UART_HAS_LP_UART (1) /*!< Support LP UART */ +#define SOC_UART_SUPPORT_SLEEP_RETENTION (1) /*!< Support back up registers before sleep */ // UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled #define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1) diff --git a/components/soc/esp32p4/include/soc/system_periph_retention.h b/components/soc/esp32p4/include/soc/system_periph_retention.h index 136832f3349..d7fd022775f 100644 --- a/components/soc/esp32p4/include/soc/system_periph_retention.h +++ b/components/soc/esp32p4/include/soc/system_periph_retention.h @@ -45,16 +45,6 @@ extern const regdma_entries_config_t l2_cache_regs_retention[L2_CACHE_RETENTION_ #define HP_SYSTEM_RETENTION_LINK_LEN 1 extern const regdma_entries_config_t hp_system_regs_retention[HP_SYSTEM_RETENTION_LINK_LEN]; -/** - * @brief Provide access to uart configuration registers retention - * context definition. - * - * This is an internal function of the sleep retention driver, and is not - * useful for external use. - */ -#define UART_RETENTION_LINK_LEN 3 -extern const regdma_entries_config_t uart_regs_retention[UART_RETENTION_LINK_LEN]; - /** * @brief Provide access to timer group configuration registers retention * context definition. diff --git a/components/soc/esp32p4/system_retention_periph.c b/components/soc/esp32p4/system_retention_periph.c index 381b20641a7..1cc4a49da4a 100644 --- a/components/soc/esp32p4/system_retention_periph.c +++ b/components/soc/esp32p4/system_retention_periph.c @@ -42,16 +42,6 @@ const regdma_entries_config_t hp_system_regs_retention[] = { }; _Static_assert(ARRAY_SIZE(hp_system_regs_retention) == HP_SYSTEM_RETENTION_LINK_LEN, "Inconsistent HP_SYSTEM retention link length definitions"); -/* UART0 Registers Context */ -#define N_REGS_UART() (((UART_CLK_CONF_REG(0) - REG_UART_BASE(0)) / 4) + 1) -const regdma_entries_config_t uart_regs_retention[] = { - [0] = { .config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_UART_LINK(0x00), REG_UART_BASE(0), REG_UART_BASE(0), N_REGS_UART(), 0, 0), .owner = ENTRY(0) }, /* uart */ - /* Note: uart register should set update reg to make the configuration take effect */ - [1] = { .config = REGDMA_LINK_WRITE_INIT (REGDMA_UART_LINK(0x01), UART_REG_UPDATE_REG(0), UART_REG_UPDATE, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) }, - [2] = { .config = REGDMA_LINK_WAIT_INIT (REGDMA_UART_LINK(0x02), UART_REG_UPDATE_REG(0), 0x0, UART_REG_UPDATE_M, 1, 0), .owner = ENTRY(0) } -}; -_Static_assert(ARRAY_SIZE(uart_regs_retention) == UART_RETENTION_LINK_LEN, "Inconsistent UART retention link length definitions"); - /* IO MUX Registers Context */ #define N_REGS_IOMUX_0() (((IO_MUX_GPIO54_REG - REG_IO_MUX_BASE) / 4) + 1) #define N_REGS_IOMUX_1() (((GPIO_ZERO_DET1_FILTER_CNT_REG - DR_REG_GPIO_BASE) / 4) + 1) diff --git a/components/soc/esp32p4/uart_periph.c b/components/soc/esp32p4/uart_periph.c index 76e12d5c9c0..98d00fd4a22 100644 --- a/components/soc/esp32p4/uart_periph.c +++ b/components/soc/esp32p4/uart_periph.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "soc/uart_periph.h" #include "soc/lp_gpio_sig_map.h" +#include "soc/uart_reg.h" /* Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc @@ -42,7 +43,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { // HP UART1 @@ -76,7 +76,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { // HP UART2 @@ -110,7 +109,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART2_INTR_SOURCE, - .module = PERIPH_UART2_MODULE, }, { // HP UART3 @@ -144,7 +142,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART3_INTR_SOURCE, - .module = PERIPH_UART3_MODULE, }, { // HP UART4 @@ -178,7 +175,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART4_INTR_SOURCE, - .module = PERIPH_UART4_MODULE, }, { // LP UART0 .pins = { @@ -211,6 +207,69 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_LP_UART_INTR_SOURCE, - .module = PERIPH_LP_UART0_MODULE, + }, +}; + +/** + * UART registers to be saved during sleep retention + * + * Reset TXFIFO and RXFIFO + * UART registers require set the reg_update bit to make the configuration take effect + * + * UART_INT_ENA_REG, UART_CLKDIV_SYNC_REG, UART_RX_FILT_REG, UART_CONF0_SYNC_REG, UART_CONF1_REG, + * UART_HWFC_CONF_SYNC_REG, UART_SLEEP_CONF0_REG, UART_SLEEP_CONF1_REG, UART_SLEEP_CONF2_REG, + * UART_SWFC_CONF0_SYNC_REG, UART_SWFC_CONF1_REG, UART_TXBRK_CONF_SYNC_REG, UART_IDLE_CONF_SYNC_REG, + * UART_RS485_CONF_SYNC_REG, UART_AT_CMD_PRECNT_SYNC_REG, UART_AT_CMD_POSTCNT_SYNC_REG, UART_AT_CMD_GAPTOUT_SYNC_REG, + * UART_AT_CMD_CHAR_SYNC_REG, UART_MEM_CONF_REG, UART_TOUT_CONF_SYNC_REG, UART_ID_REG + */ +#define UART_RETENTION_ADDR_MAP_REGS_CNT 21 +#define UART_RETENTION_REGS_BASE(i) UART_INT_ENA_REG(i) +static const uint32_t uart_regs_map[4] = {0x7fff6d, 0x10, 0x0, 0x0}; +#define UART_SLEEP_RETENTION_ENTRIES(uart_num) { \ + [0] = {.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_UART_LINK(0x00), \ + UART_RETENTION_REGS_BASE(uart_num), UART_RETENTION_REGS_BASE(uart_num), \ + UART_RETENTION_ADDR_MAP_REGS_CNT, 0, 0, \ + uart_regs_map[0], uart_regs_map[1], \ + uart_regs_map[2], uart_regs_map[3] \ + ), \ + .owner = ENTRY(0) }, \ + [1] = {.config = REGDMA_LINK_WRITE_INIT(REGDMA_UART_LINK(0x01), \ + UART_REG_UPDATE_REG(uart_num), UART_REG_UPDATE, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) }, \ + [2] = {.config = REGDMA_LINK_WAIT_INIT(REGDMA_UART_LINK(0x02), \ + UART_REG_UPDATE_REG(uart_num), 0x0, \ + UART_REG_UPDATE_M, 1, 0 \ + ), \ + .owner = ENTRY(0) }, \ +} + +static const regdma_entries_config_t uart0_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(0); +static const regdma_entries_config_t uart1_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(1); +static const regdma_entries_config_t uart2_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(2); +static const regdma_entries_config_t uart3_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(3); +static const regdma_entries_config_t uart4_regdma_entries[] = UART_SLEEP_RETENTION_ENTRIES(4); + +const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM] = { + [0] = { + .regdma_entry_array = uart0_regdma_entries, + .array_size = ARRAY_SIZE(uart0_regdma_entries), + }, + [1] = { + .regdma_entry_array = uart1_regdma_entries, + .array_size = ARRAY_SIZE(uart1_regdma_entries), + }, + [2] = { + .regdma_entry_array = uart2_regdma_entries, + .array_size = ARRAY_SIZE(uart2_regdma_entries), + }, + [3] = { + .regdma_entry_array = uart3_regdma_entries, + .array_size = ARRAY_SIZE(uart3_regdma_entries), + }, + [4] = { + .regdma_entry_array = uart4_regdma_entries, + .array_size = ARRAY_SIZE(uart4_regdma_entries), }, }; diff --git a/components/soc/esp32s2/uart_periph.c b/components/soc/esp32s2/uart_periph.c index 8360cae0829..3d3da8ad7a4 100644 --- a/components/soc/esp32s2/uart_periph.c +++ b/components/soc/esp32s2/uart_periph.c @@ -1,16 +1,8 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/uart_periph.h" @@ -49,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -83,6 +74,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, }; diff --git a/components/soc/esp32s3/uart_periph.c b/components/soc/esp32s3/uart_periph.c index 450787854f6..c9f0a2f4b4e 100644 --- a/components/soc/esp32s3/uart_periph.c +++ b/components/soc/esp32s3/uart_periph.c @@ -1,16 +1,8 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "soc/uart_periph.h" @@ -49,7 +41,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART0_INTR_SOURCE, - .module = PERIPH_UART0_MODULE, }, { @@ -83,7 +74,6 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { }, }, .irq = ETS_UART1_INTR_SOURCE, - .module = PERIPH_UART1_MODULE, }, { @@ -117,6 +107,5 @@ const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { } }, .irq = ETS_UART2_INTR_SOURCE, - .module = PERIPH_UART2_MODULE, } }; diff --git a/components/soc/include/soc/gdma_periph.h b/components/soc/include/soc/gdma_periph.h index 3376e4d8817..233c366ebb5 100644 --- a/components/soc/include/soc/gdma_periph.h +++ b/components/soc/include/soc/gdma_periph.h @@ -8,10 +8,7 @@ #include "soc/soc_caps.h" #include "soc/periph_defs.h" - -#if SOC_PM_SUPPORT_TOP_PD #include "soc/regdma.h" -#endif #ifdef __cplusplus extern "C" { diff --git a/components/soc/include/soc/i2c_periph.h b/components/soc/include/soc/i2c_periph.h index 47471d9e22b..c72e7720f16 100644 --- a/components/soc/include/soc/i2c_periph.h +++ b/components/soc/include/soc/i2c_periph.h @@ -10,9 +10,7 @@ #include "soc/soc_caps.h" #if SOC_I2C_SUPPORTED // TODO: [ESP32C5] IDF-8694 #include "soc/periph_defs.h" -#if SOC_PM_SUPPORT_TOP_PD #include "soc/regdma.h" -#endif #endif // SOC_I2C_SUPPORTED #ifdef __cplusplus @@ -32,7 +30,7 @@ typedef struct { extern const i2c_signal_conn_t i2c_periph_signal[SOC_I2C_NUM]; -#if SOC_PM_SUPPORT_TOP_PD +#if SOC_I2C_SUPPORT_SLEEP_RETENTION typedef struct { const regdma_entries_config_t *link_list; uint32_t link_num; diff --git a/components/soc/include/soc/regdma.h b/components/soc/include/soc/regdma.h index b6fd9ff00e8..59897b1ebf3 100644 --- a/components/soc/include/soc/regdma.h +++ b/components/soc/include/soc/regdma.h @@ -66,6 +66,7 @@ extern "C" { #define REGDMA_LINK_PRI_RMT REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_GPTIMER REGDMA_LINK_PRI_GENERAL_PERIPH #define REGDMA_LINK_PRI_I2C REGDMA_LINK_PRI_GENERAL_PERIPH +#define REGDMA_LINK_PRI_UART REGDMA_LINK_PRI_GENERAL_PERIPH typedef enum { REGDMA_LINK_PRI_0 = 0, diff --git a/components/soc/include/soc/uart_periph.h b/components/soc/include/soc/uart_periph.h index 45781b208aa..2c0681e8dad 100644 --- a/components/soc/include/soc/uart_periph.h +++ b/components/soc/include/soc/uart_periph.h @@ -1,17 +1,18 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #pragma once #include "soc/soc_caps.h" -#include "soc/periph_defs.h" +#include "soc/interrupts.h" #include "soc/gpio_sig_map.h" #include "soc/io_mux_reg.h" #include "soc/uart_pins.h" #include "soc/uart_struct.h" #include "soc/uart_reg.h" +#include "soc/regdma.h" #ifdef __cplusplus extern "C" { @@ -45,13 +46,19 @@ typedef struct { typedef struct { const uart_periph_sig_t pins[SOC_UART_PINS_COUNT]; const uint8_t irq; - union { - const periph_module_t module; - }; } uart_signal_conn_t; extern const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM]; +#if SOC_UART_SUPPORT_SLEEP_RETENTION +typedef struct { + const regdma_entries_config_t *regdma_entry_array; + uint32_t array_size; +} uart_reg_retention_info_t; + +extern const uart_reg_retention_info_t uart_reg_retention_info[SOC_UART_HP_NUM]; +#endif + #ifdef __cplusplus } #endif diff --git a/docs/en/api-reference/peripherals/uart.rst b/docs/en/api-reference/peripherals/uart.rst index eba495f20ee..b28bdf929ea 100644 --- a/docs/en/api-reference/peripherals/uart.rst +++ b/docs/en/api-reference/peripherals/uart.rst @@ -68,6 +68,10 @@ Call the function :cpp:func:`uart_param_config` and pass to it a :cpp:type:`uart For more information on how to configure the hardware flow control options, please refer to :example:`peripherals/uart/uart_echo`. +.. only:: SOC_UART_SUPPORT_SLEEP_RETENTION + + Additionally, :cpp:member:`uart_config_t::backup_before_sleep` can be set to enable the backup of the UART configuration registers before entering sleep and restore these registers after exiting sleep. This allows the UART to continue working properly after waking up even when the UART module power domain is entirely off during sleep. This option implies an balance between power consumption and memory usage. If the power consumption is not a concern, you can disable this option to save memory. + Multiple Steps """""""""""""" diff --git a/docs/zh_CN/api-reference/peripherals/uart.rst b/docs/zh_CN/api-reference/peripherals/uart.rst index d93f7e23958..e2cf8b6ca89 100644 --- a/docs/zh_CN/api-reference/peripherals/uart.rst +++ b/docs/zh_CN/api-reference/peripherals/uart.rst @@ -68,6 +68,10 @@ UART 通信参数可以在一个步骤中完成全部配置,也可以在多个 了解配置硬件流控模式的更多信息,请参考 :example:`peripherals/uart/uart_echo`。 +.. only:: SOC_UART_SUPPORT_SLEEP_RETENTION + + 此外,置位 :cpp:member:`uart_config_t::backup_before_sleep` 会使能在进入睡眠模式前备份 UART 配置寄存器并在退出睡眠后恢复这些寄存器。这个功能使 UART 能够在系统唤醒后继续正常工作,即使其电源域在睡眠过程中被完全关闭。此选项需要用户在功耗和内存使用之间取得平衡。如果功耗不是一个问题,可以禁用这个选项来节省内存。 + 分步依次配置每个参数 """"""""""""""""""""""""""""""" diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index 14ef4be6842..db42d9fe3cf 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -587,7 +587,6 @@ components/soc/esp32/include/soc/uhci_struct.h components/soc/esp32/include/soc/wdev_reg.h components/soc/esp32/ledc_periph.c components/soc/esp32/spi_periph.c -components/soc/esp32/uart_periph.c components/soc/esp32c3/i2c_periph.c components/soc/esp32c3/include/soc/apb_saradc_reg.h components/soc/esp32c3/include/soc/assist_debug_reg.h @@ -618,7 +617,6 @@ components/soc/esp32c3/include/soc/usb_serial_jtag_struct.h components/soc/esp32c3/include/soc/wdev_reg.h components/soc/esp32c3/interrupts.c components/soc/esp32c3/ledc_periph.c -components/soc/esp32c3/uart_periph.c components/soc/esp32s2/adc_periph.c components/soc/esp32s2/dedic_gpio_periph.c components/soc/esp32s2/i2c_periph.c @@ -656,7 +654,6 @@ components/soc/esp32s2/include/soc/usb_wrap_reg.h components/soc/esp32s2/include/soc/usb_wrap_struct.h components/soc/esp32s2/include/soc/wdev_reg.h components/soc/esp32s2/ledc_periph.c -components/soc/esp32s2/uart_periph.c components/soc/esp32s3/dedic_gpio_periph.c components/soc/esp32s3/i2c_periph.c components/soc/esp32s3/include/soc/apb_saradc_reg.h @@ -715,7 +712,6 @@ components/soc/esp32s3/include/soc/usb_wrap_reg.h components/soc/esp32s3/include/soc/usb_wrap_struct.h components/soc/esp32s3/include/soc/wdev_reg.h components/soc/esp32s3/ledc_periph.c -components/soc/esp32s3/uart_periph.c components/soc/include/soc/dedic_gpio_periph.h components/soc/include/soc/gpio_periph.h components/soc/include/soc/ledc_periph.h From 753fe53fab634609978a27db3775e5dc05d34ad1 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 5 Jul 2024 22:17:31 +0800 Subject: [PATCH 506/548] fix(uart): fix uart_config_t structure size difference in C and C++ --- components/esp_driver_uart/include/driver/uart.h | 2 -- components/esp_driver_uart/src/uart.c | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_uart/include/driver/uart.h b/components/esp_driver_uart/include/driver/uart.h index 903bd670597..aeb0176bfd1 100644 --- a/components/esp_driver_uart/include/driver/uart.h +++ b/components/esp_driver_uart/include/driver/uart.h @@ -47,11 +47,9 @@ typedef struct { #endif }; struct { -#if SOC_UART_SUPPORT_SLEEP_RETENTION uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the HP UART registers before entering/after exiting sleep mode. By this approach, the system can power off HP UART's power domain. This can save power, but at the expense of more RAM being consumed */ -#endif } flags; /*!< Configuration flags */ } uart_config_t; diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index cfc22442461..6f4ddf48abe 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -842,6 +842,10 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf ESP_RETURN_ON_FALSE((uart_config->flow_ctrl < UART_HW_FLOWCTRL_MAX), ESP_FAIL, UART_TAG, "hw_flowctrl mode error"); ESP_RETURN_ON_FALSE((uart_config->data_bits < UART_DATA_BITS_MAX), ESP_FAIL, UART_TAG, "data bit error"); +#if !SOC_UART_SUPPORT_SLEEP_RETENTION + ESP_RETURN_ON_FALSE(uart_config->flags.backup_before_sleep == 0, ESP_ERR_NOT_SUPPORTED, UART_TAG, "register back up is not supported"); +#endif + uart_module_enable(uart_num); #if SOC_UART_SUPPORT_SLEEP_RETENTION && CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP From 5dac537f6bc20b44f89c169ca1f0b83f43849785 Mon Sep 17 00:00:00 2001 From: Shreyas Sheth Date: Mon, 29 Jul 2024 14:56:58 +0530 Subject: [PATCH 507/548] fix(esp_wifi): Fix crash in wifi deinit due to roaming neighbor list --- .../wifi_apps/roaming_app/src/roaming_app.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c index 271e0d04c04..5f33b2c89bc 100644 --- a/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c +++ b/components/esp_wifi/wifi_apps/roaming_app/src/roaming_app.c @@ -35,9 +35,11 @@ static void *scan_results_lock = NULL; #define ROAM_SCAN_RESULTS_LOCK() os_mutex_lock(scan_results_lock) #define ROAM_SCAN_RESULTS_UNLOCK() os_mutex_unlock(scan_results_lock) +#if PERIODIC_RRM_MONITORING static void *neighbor_list_lock = NULL; #define ROAM_NEIGHBOR_LIST_LOCK() os_mutex_lock(neighbor_list_lock) #define ROAM_NEIGHBOR_LIST_UNLOCK() os_mutex_unlock(neighbor_list_lock) +#endif /*PERIODIC_RRM_MONITORING*/ static int wifi_post_roam_event(struct cand_bss *bss); static void determine_best_ap(int8_t rssi_threshold); @@ -815,8 +817,15 @@ void deinit_roaming_app(void) #if PERIODIC_SCAN_MONITORING g_roaming_app.periodic_scan_active = false; #endif /*PERIODIC_SCAN_MONITORING*/ - os_mutex_delete(neighbor_list_lock); - neighbor_list_lock = NULL; - os_mutex_delete(scan_results_lock); - scan_results_lock = NULL; + +#if PERIODIC_RRM_MONITORING + if (neighbor_list_lock) { + os_mutex_delete(neighbor_list_lock); + neighbor_list_lock = NULL; + } +#endif /*PERIODIC_RRM_MONITORING*/ + if (scan_results_lock) { + os_mutex_delete(scan_results_lock); + scan_results_lock = NULL; + } } From 4cc7eecf4fc6498700f04204f6a374cf3b311c14 Mon Sep 17 00:00:00 2001 From: xuxiao Date: Wed, 31 Jul 2024 10:51:01 +0800 Subject: [PATCH 508/548] fix(wifi): fix some wifi bugs (v5.3) --- components/esp_wifi/include/esp_wifi_he.h | 78 ++++++++++++++++- .../esp_wifi/include/esp_wifi_he_types.h | 87 +++++++++++++++++-- .../esp_wifi/include/esp_wifi_types_generic.h | 2 + components/esp_wifi/lib | 2 +- examples/wifi/itwt/main/itwt_main.c | 2 +- examples/wifi/itwt/main/wifi_itwt_cmd.c | 2 +- .../mock_build_test/main/mock_build_test.c | 2 +- 7 files changed, 160 insertions(+), 15 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi_he.h b/components/esp_wifi/include/esp_wifi_he.h index 5bc361c2f81..57bf819afd9 100644 --- a/components/esp_wifi/include/esp_wifi_he.h +++ b/components/esp_wifi/include/esp_wifi_he.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -35,7 +35,7 @@ extern "C" { * - ESP_ERR_WIFI_TWT_FULL: no available flow id * - ESP_ERR_INVALID_ARG: invalid argument */ -esp_err_t esp_wifi_sta_itwt_setup(wifi_twt_setup_config_t *setup_config); +esp_err_t esp_wifi_sta_itwt_setup(wifi_itwt_setup_config_t *setup_config); /** * @brief Tear down individual TWT agreements @@ -142,6 +142,80 @@ esp_err_t esp_wifi_enable_rx_statistics(bool rx_stats, bool rx_mu_stats); */ esp_err_t esp_wifi_enable_tx_statistics(esp_wifi_aci_t aci, bool tx_stats); +/** + * @brief Set up an broadcast TWT agreement (NegotiationType=3) or change TWT parameters of the existing TWT agreement + * - TWT Wake Interval = TWT Wake Interval Mantissa * (2 ^ TWT Wake Interval Exponent), unit: us + * - e.g. TWT Wake Interval Mantissa = 512, TWT Wake Interval Exponent = 12, then TWT Wake Interval is 2097.152 ms + * Nominal Minimum Wake Duration = 255, then TWT Wake Duration is 65.28 ms + * + * @attention Support at most 32 TWT agreements, otherwise ESP_ERR_WIFI_TWT_FULL will be returned. + * Support sleep time up to (1 << 35) us. + * + * @param[in,out] config pointer to btwt setup config structure. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_NOT_CONNECT: The station is in disconnect status + * - ESP_ERR_WIFI_TWT_FULL: no available flow id + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_sta_btwt_setup(wifi_btwt_setup_config_t *config); + +/** + * @brief Tear down broadcast TWT agreements + * + * @param[in] btwt_id The value range is [0, 31]. + * BTWT_ID_ALL indicates tear down all broadcast TWT agreements. + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_NOT_CONNECT: The station is in disconnect status + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_sta_btwt_teardown(uint8_t btwt_id); + +/** + * @brief Get number of broadcast TWTs supported by the connected AP + * + * @param[out] btwt_number store number of btwts supported by the connected AP + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by esp_wifi_init + * - ESP_ERR_WIFI_NOT_STARTED: WiFi is not started by esp_wifi_start + * - ESP_ERR_INVALID_ARG: invalid argument + */ +esp_err_t esp_wifi_sta_get_btwt_num(uint8_t *btwt_number); + +/** + * @brief Get broadcast TWT information + * + * @param[in] btwt_number As input param, it stores max btwt number AP supported. + * @param[in] btwt_info array to hold the btwt information supported by AP, and the array size must be at least as large as the BTWT number. + * + * @return + * - ESP_OK: succeed + * - ESP_FAIL: fail + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + */ +esp_err_t esp_wifi_sta_btwt_get_info(uint8_t btwt_number, esp_wifi_btwt_info_t *btwt_info); + +/** + * @brief Set WiFi TWT config + * + * @param[in] config pointer to the WiFi TWT configure structure. + * + * @return + * - ESP_OK: succeed + */ +esp_err_t esp_wifi_sta_twt_config(wifi_twt_config_t *config); + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_wifi_he_types.h b/components/esp_wifi/include/esp_wifi_he_types.h index a6ba90d591d..404dc1cf1db 100644 --- a/components/esp_wifi/include/esp_wifi_he_types.h +++ b/components/esp_wifi/include/esp_wifi_he_types.h @@ -15,6 +15,7 @@ extern "C" { #endif #define FLOW_ID_ALL (8) +#define BTWT_ID_ALL (32) #define BSS_MAX_COLOR (63) /** @@ -112,24 +113,37 @@ typedef enum { } wifi_twt_setup_cmds_t; /** - * @brief TWT setup config + * @brief broadcast TWT setup config + */ +typedef struct { + wifi_twt_setup_cmds_t setup_cmd; /**< Indicates the type of TWT command*/ + uint8_t btwt_id; /**< When set up an broadcast TWT agreement, the broadcast twt id will be assigned by AP after a successful agreement setup. + broadcast twt id could be specified to a value in the range of [1, 31], but it might be change by AP in the response. + When change TWT parameters of the existing TWT agreement, broadcast twt id should be an existing one. The value range is [1, 31].*/ + uint16_t timeout_time_ms; /**< Timeout times of receiving setup action frame response, default 5s*/ +} wifi_btwt_setup_config_t; + +/** + * @brief Individual TWT setup config */ typedef struct { wifi_twt_setup_cmds_t setup_cmd; /**< Indicates the type of TWT command */ - uint16_t trigger : 1; /**< 1: a trigger-enabled TWT, 0: a non-trigger-enabled TWT */ - uint16_t flow_type : 1; /**< 0: an announced TWT, 1: an unannounced TWT */ + uint16_t trigger : 1; /**< 1: a trigger-enabled individual TWT, 0: a non-trigger-enabled individual TWT */ + uint16_t flow_type : 1; /**< 0: an announced individual TWT, 1: an unannounced individual TWT */ uint16_t flow_id : 3; /**< When set up an individual TWT agreement, the flow id will be assigned by AP after a successful agreement setup. flow_id could be specified to a value in the range of [0, 7], but it might be changed by AP in the response. When change TWT parameters of the existing TWT agreement, flow_id should be an existing one. The value range is [0, 7]. */ - uint16_t wake_invl_expn : 5; /**< TWT Wake Interval Exponent. The value range is [0, 31]. */ - uint16_t wake_duration_unit : 1; /**< TWT Wake duration unit, 0: 256us 1: TU (TU = 1024us)*/ + uint16_t wake_invl_expn : 5; /**< Individual TWT Wake Interval Exponent. The value range is [0, 31]. */ + uint16_t wake_duration_unit : 1; /**< Individual TWT Wake duration unit, 0: 256us 1: TU (TU = 1024us)*/ uint16_t reserved : 5; /**< bit: 11.15 reserved */ - uint8_t min_wake_dura; /**< Nominal Minimum Wake Duration, indicates the minimum amount of time, in unit of 256 us, that the TWT requesting STA expects that it needs to be awake. The value range is [1, 255]. */ - uint16_t wake_invl_mant; /**< TWT Wake Interval Mantissa. The value range is [1, 65535]. */ - uint16_t twt_id; /**< TWT connection id, the value range is [0, 32767]. */ + uint8_t min_wake_dura; /**< Nominal Minimum Wake Duration, indicates the minimum amount of time, in unit of 256 us, that the individual TWT requesting STA expects that it needs to be awake. The value range is [1, 255]. */ + uint16_t wake_invl_mant; /**< Individual TWT Wake Interval Mantissa. The value range is [1, 65535]. */ + uint16_t twt_id; /**< Individual TWT connection id, the value range is [0, 32767]. */ uint16_t timeout_time_ms; /**< Timeout times of receiving setup action frame response, default 5s*/ } wifi_twt_setup_config_t; +typedef wifi_twt_setup_config_t wifi_itwt_setup_config_t; + /** * @brief HE SU GI and LTF types */ @@ -294,9 +308,21 @@ typedef struct { } __attribute__((packed)) esp_wifi_rxctrl_t; #endif +/** + * @brief bTWT setup status + */ +typedef enum { + BTWT_SETUP_TXFAIL, /**< station sends btwt setup request frame fail */ + BTWT_SETUP_SUCCESS, /**< station receives btwt setup response frame and setup btwt sucessfully */ + BTWT_SETUP_TIMEOUT, /**< timeout of receiving btwt setup response frame */ + BTWT_SETUP_FULL, /**< indicate there is no available btwt id */ + BTWT_SETUP_INVALID_ARG, /**< indicate invalid argument to setup btwt */ + BTWT_SETUP_INTERNAL_ERR, /**< indicate internal error to setup btwt */ +} wifi_btwt_setup_status_t; + /** Argument structure for WIFI_EVENT_TWT_SET_UP event */ typedef struct { - wifi_twt_setup_config_t config; /**< itwt setup config, this value is determined by the AP */ + wifi_itwt_setup_config_t config; /**< itwt setup config, this value is determined by the AP */ esp_err_t status; /**< itwt setup status, 1: indicate setup success, others : indicate setup fail */ uint8_t reason; /**< itwt setup frame tx fail reason */ uint64_t target_wake_time; /**< TWT SP start time */ @@ -316,6 +342,34 @@ typedef struct { wifi_itwt_teardown_status_t status; /**< itwt teardown status */ } wifi_event_sta_itwt_teardown_t; +/** Argument structure for WIFI_EVENT_BTWT_SET_UP event */ +typedef struct { + wifi_btwt_setup_status_t status; /**< indicate btwt setup status */ + wifi_twt_setup_cmds_t setup_cmd; /**< indicate the type of TWT command */ + uint8_t btwt_id; /**< indicate btwt id */ + uint8_t min_wake_dura; /**< Nominal Minimum Wake Duration, indicates the minimum amount of time, in unit of 256 us, that the TWT requesting STA expects that it needs to be awake. The value range is [1, 255]. */ + uint8_t wake_invl_expn; /**< TWT Wake Interval Exponent. The value range is [0, 31]. */ + uint16_t wake_invl_mant; /**< TWT Wake Interval Mantissa. The value range is [1, 65535]. */ + bool trigger; /**< 1: a trigger-enabled TWT, 0: a non-trigger-enabled TWT */ + uint8_t flow_type; /**< 0: an announced TWT, 1: an unannounced TWT */ + uint8_t reason; /**< btwt setup frame tx fail reason */ + uint64_t target_wake_time; /**< TWT SP start time */ +} wifi_event_sta_btwt_setup_t; + +/** + * @brief BTWT teardown status + */ +typedef enum { + BTWT_TEARDOWN_FAIL, /**< station sends teardown frame fail */ + BTWT_TEARDOWN_SUCCESS, /**< 1) station successfully sends teardown frame to AP; 2) station receives teardown frame from AP */ +} wifi_btwt_teardown_status_t; + +/** Argument structure for WIFI_EVENT_TWT_TEARDOWN event */ +typedef struct { + uint8_t btwt_id; /**< btwt id */ + wifi_btwt_teardown_status_t status; /**< btwt teardown status */ +} wifi_event_sta_btwt_teardown_t; + /** * @brief iTWT probe status */ @@ -360,6 +414,21 @@ typedef struct { uint8_t flow_id; /**< flow id */ } wifi_event_sta_twt_wakeup_t; +/** Argument structure for twt information */ +typedef struct { + bool btwt_id_in_use; /**< indicate whether the btwt id is in use or not */ + uint16_t btwt_trigger : 1; /**< 1: a trigger-enabled TWT, 0: a non-trigger-enabled TWT */ + uint16_t btwt_flow_type : 1; /**< 0: an announced TWT, 1: an unannounced TWT */ + uint16_t btwt_recommendation : 3; /**< indicate recommendations on the types of frames. 0: no constraints, [1, 3], [4, 7] reserved */ + uint16_t btwt_wake_interval_exponent : 5; /**< TWT Wake Interval Exponent. The value range is [0, 31]. */ + uint16_t btwt_rsvd : 6; /**< reserved */ + uint8_t btwt_wake_duration; /**< TWT Wake duration unit, 0: 256us 1: TU (TU = 1024us) */ + uint16_t btwt_wake_interval_mantissa; /**< TWT Wake Interval Mantissa. The value range is [1, 65535]. */ + uint16_t btwt_info_id : 5; /**< btwt id */ + uint16_t btwt_info_persistence : 8; /**< indicate the number of TBTTs during which the Broadcast TWT SPs corresponding to this broadcast TWT parameters set are present */ + uint16_t btwt_info_rsvd : 3; /**< reserved */ +} esp_wifi_btwt_info_t; + #ifdef __cplusplus } #endif diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index d1ea00f9a2a..37e6b203cbd 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -817,6 +817,8 @@ typedef enum { WIFI_EVENT_ITWT_PROBE, /**< iTWT probe */ WIFI_EVENT_ITWT_SUSPEND, /**< iTWT suspend */ WIFI_EVENT_TWT_WAKEUP, /**< TWT wakeup */ + WIFI_EVENT_BTWT_SETUP, /**< bTWT setup */ + WIFI_EVENT_BTWT_TEARDOWN, /**< bTWT teardown*/ WIFI_EVENT_NAN_STARTED, /**< NAN Discovery has started */ WIFI_EVENT_NAN_STOPPED, /**< NAN Discovery has stopped */ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index da2c33977ea..7ab37c97e29 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit da2c33977ea14edb9ea4d1dbaea0901a28dea470 +Subproject commit 7ab37c97e2938016495c89a16ab442d4034cf3e9 diff --git a/examples/wifi/itwt/main/itwt_main.c b/examples/wifi/itwt/main/itwt_main.c index cdc87359b09..e2f4ecc7719 100644 --- a/examples/wifi/itwt/main/itwt_main.c +++ b/examples/wifi/itwt/main/itwt_main.c @@ -119,7 +119,7 @@ static void got_ip_handler(void *arg, esp_event_base_t event_base, esp_wifi_sta_get_negotiated_phymode(&phymode); if (phymode == WIFI_PHY_MODE_HE20) { esp_err_t err = ESP_OK; - wifi_twt_setup_config_t setup_config = { + wifi_itwt_setup_config_t setup_config = { .setup_cmd = TWT_REQUEST, .flow_id = 0, .twt_id = CONFIG_EXAMPLE_ITWT_ID, diff --git a/examples/wifi/itwt/main/wifi_itwt_cmd.c b/examples/wifi/itwt/main/wifi_itwt_cmd.c index 157a88ef067..5b2f677ddb5 100644 --- a/examples/wifi/itwt/main/wifi_itwt_cmd.c +++ b/examples/wifi/itwt/main/wifi_itwt_cmd.c @@ -110,7 +110,7 @@ static int wifi_cmd_itwt(int argc, char **argv) return 1; } } - wifi_twt_setup_config_t setup_config = { + wifi_itwt_setup_config_t setup_config = { .setup_cmd = (itwt_args.setup->ival[0] <= TWT_DEMAND) ? itwt_args.setup->ival[0] : TWT_REQUEST, .flow_id = 0, .twt_id = itwt_args.twtid->count ? itwt_args.twtid->ival[0] : 0, diff --git a/tools/test_apps/linux_compatible/mock_build_test/main/mock_build_test.c b/tools/test_apps/linux_compatible/mock_build_test/main/mock_build_test.c index 1a00f1cf688..9f64ecbd62e 100644 --- a/tools/test_apps/linux_compatible/mock_build_test/main/mock_build_test.c +++ b/tools/test_apps/linux_compatible/mock_build_test/main/mock_build_test.c @@ -116,7 +116,7 @@ void app_main(void) esp_wifi_ap_get_sta_list_with_ip(NULL, NULL); esp_wifi_sta_itwt_setup_IgnoreAndReturn(ESP_OK); - esp_wifi_sta_itwt_setup((wifi_twt_setup_config_t*) NULL); + esp_wifi_sta_itwt_setup((wifi_itwt_setup_config_t*) NULL); sc_send_ack_stop_Ignore(); sc_send_ack_stop(); From b124b1d68266bdf63d2fb39e29eaaf4a035898e7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 31 Jul 2024 15:37:11 +0200 Subject: [PATCH 509/548] ci(sdmmc): switch to usb_serial_jtag in the test app for P4 New CI runners use usb_serial_jtag, update configuration to match this. --- .../esp_driver_sdmmc/test_apps/sdmmc/sdkconfig.defaults.esp32p4 | 1 + 1 file changed, 1 insertion(+) diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/sdkconfig.defaults.esp32p4 b/components/esp_driver_sdmmc/test_apps/sdmmc/sdkconfig.defaults.esp32p4 index 7b8ca4566cf..bae8235e8d7 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/sdkconfig.defaults.esp32p4 +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/sdkconfig.defaults.esp32p4 @@ -3,3 +3,4 @@ CONFIG_SDMMC_BOARD_ESP32P4_EV_BOARD=y CONFIG_SPIRAM=y CONFIG_IDF_EXPERIMENTAL_FEATURES=y CONFIG_SPIRAM_SPEED_200M=y +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y From 1dff9575978cae9d756c7f410f96fafd9a81ed16 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 24 May 2024 15:05:11 +0200 Subject: [PATCH 510/548] ci(sdmmc): enable tests for ESP32-P4 --- components/esp_driver_sdmmc/test_apps/.build-test-rules.yml | 4 ---- components/esp_driver_sdmmc/test_apps/sdmmc/pytest_sdmmc.py | 1 - 2 files changed, 5 deletions(-) diff --git a/components/esp_driver_sdmmc/test_apps/.build-test-rules.yml b/components/esp_driver_sdmmc/test_apps/.build-test-rules.yml index cc6c1807730..bb3416b4f33 100644 --- a/components/esp_driver_sdmmc/test_apps/.build-test-rules.yml +++ b/components/esp_driver_sdmmc/test_apps/.build-test-rules.yml @@ -1,10 +1,6 @@ components/esp_driver_sdmmc/test_apps/sdmmc: disable: - if: SOC_SDMMC_HOST_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: lack of runner # TODO: IDF-8970 depends_components: - sdmmc diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/pytest_sdmmc.py b/components/esp_driver_sdmmc/test_apps/sdmmc/pytest_sdmmc.py index 747b8f36ff4..6feedee57e0 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/pytest_sdmmc.py +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/pytest_sdmmc.py @@ -7,7 +7,6 @@ @pytest.mark.esp32 @pytest.mark.esp32s3 @pytest.mark.esp32p4 -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='lack of runners, IDF-8970') @pytest.mark.sdcard def test_sdmmc(dut: IdfDut) -> None: # SDMMC driver can't be reinitialized if the test fails, From 4b665425a28f095bf62c97f9674d852a329d66b7 Mon Sep 17 00:00:00 2001 From: gaoxu Date: Thu, 1 Aug 2024 10:50:58 +0800 Subject: [PATCH 511/548] fix(gpio): correct usb dp gpio pullup disable function v5.3 --- components/hal/esp32c5/include/hal/gpio_ll.h | 19 ++++++------ components/hal/esp32c6/include/hal/gpio_ll.h | 18 ++++++------ components/hal/esp32h2/include/hal/gpio_ll.h | 21 ++++++------- components/hal/esp32p4/include/hal/gpio_ll.h | 31 ++++++++++---------- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/components/hal/esp32c5/include/hal/gpio_ll.h b/components/hal/esp32c5/include/hal/gpio_ll.h index d064b782687..b6908c483bf 100644 --- a/components/hal/esp32c5/include/hal/gpio_ll.h +++ b/components/hal/esp32c5/include/hal/gpio_ll.h @@ -94,6 +94,15 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { + // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value + // USB DP pin is default to PU enabled + // Note that esp32C5 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin + // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. + // TODO: read the specific efuse with efuse_ll.h + if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + USB_SERIAL_JTAG.conf0.pad_pull_override = 1; + USB_SERIAL_JTAG.conf0.dp_pullup = 0; + } IO_MUX.gpio[gpio_num].fun_wpu = 0; } @@ -117,15 +126,7 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) { - // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value - // USB DP pin is default to PU enabled - // Note that esp32C5 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin - // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. - // TODO: read the specific efuse with efuse_ll.h - if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { - USB_SERIAL_JTAG.conf0.pad_pull_override = 1; - USB_SERIAL_JTAG.conf0.dp_pullup = 0; - } + IO_MUX.gpio[gpio_num].fun_wpd = 0; } diff --git a/components/hal/esp32c6/include/hal/gpio_ll.h b/components/hal/esp32c6/include/hal/gpio_ll.h index 67676fbb41f..f227cf6850c 100644 --- a/components/hal/esp32c6/include/hal/gpio_ll.h +++ b/components/hal/esp32c6/include/hal/gpio_ll.h @@ -90,6 +90,15 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { + // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value + // USB DP pin is default to PU enabled + // Note that esp32c6 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin + // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. + // TODO: read the specific efuse with efuse_ll.h + if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); + } REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); } @@ -113,15 +122,6 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) { - // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value - // USB DP pin is default to PU enabled - // Note that esp32c6 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin - // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. - // TODO: read the specific efuse with efuse_ll.h - if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { - SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); - CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); - } REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); } diff --git a/components/hal/esp32h2/include/hal/gpio_ll.h b/components/hal/esp32h2/include/hal/gpio_ll.h index bdd8bcca234..e78dd6bfbb1 100644 --- a/components/hal/esp32h2/include/hal/gpio_ll.h +++ b/components/hal/esp32h2/include/hal/gpio_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -90,6 +90,15 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, gpio_num_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { + // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value + // USB DP pin is default to PU enabled + // Note that esp32h2 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin + // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. + // TODO: read the specific efuse with efuse_ll.h + if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); + } REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PU); } @@ -113,15 +122,7 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, gpio_num_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, gpio_num_t gpio_num) { - // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value - // USB DP pin is default to PU enabled - // Note that esp32h2 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin - // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. - // TODO: read the specific efuse with efuse_ll.h - if (gpio_num == USB_INT_PHY0_DP_GPIO_NUM) { - SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); - CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); - } + REG_CLR_BIT(IO_MUX_GPIO0_REG + (gpio_num * 4), FUN_PD); } diff --git a/components/hal/esp32p4/include/hal/gpio_ll.h b/components/hal/esp32p4/include/hal/gpio_ll.h index 2cfb6467b74..f4111b3f7d5 100644 --- a/components/hal/esp32p4/include/hal/gpio_ll.h +++ b/components/hal/esp32p4/include/hal/gpio_ll.h @@ -95,6 +95,22 @@ static inline void gpio_ll_pullup_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pullup_dis(gpio_dev_t *hw, uint32_t gpio_num) { + // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value + // USB DP pin is default to PU enabled + // Note that esp32p4 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin + // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. + // TODO: read the specific efuse with efuse_ll.h + + // One more noticeable point is P4 has two internal PHYs connecting to USJ and USB_WRAP(OTG1.1) separately. + // We only consider the default connection here: PHY0 -> USJ, PHY1 -> USB_OTG + if (gpio_num == USB_USJ_INT_PHY_DP_GPIO_NUM) { + USB_SERIAL_JTAG.conf0.pad_pull_override = 1; + USB_SERIAL_JTAG.conf0.dp_pullup = 0; + } else if (gpio_num == USB_OTG_INT_PHY_DP_GPIO_NUM) { + USB_WRAP.otg_conf.pad_pull_override = 1; + USB_WRAP.otg_conf.dp_pullup = 0; + } + IO_MUX.gpio[gpio_num].fun_wpu = 0; } @@ -118,21 +134,6 @@ static inline void gpio_ll_pulldown_en(gpio_dev_t *hw, uint32_t gpio_num) __attribute__((always_inline)) static inline void gpio_ll_pulldown_dis(gpio_dev_t *hw, uint32_t gpio_num) { - // The pull-up value of the USB pins are controlled by the pins’ pull-up value together with USB pull-up value - // USB DP pin is default to PU enabled - // Note that esp32p4 has supported USB_EXCHG_PINS feature. If this efuse is burnt, the gpio pin - // which should be checked is USB_INT_PHY0_DM_GPIO_NUM instead. - // TODO: read the specific efuse with efuse_ll.h - - // One more noticeable point is P4 has two internal PHYs connecting to USJ and USB_WRAP(OTG1.1) separately. - // We only consider the default connection here: PHY0 -> USJ, PHY1 -> USB_OTG - if (gpio_num == USB_USJ_INT_PHY_DP_GPIO_NUM) { - USB_SERIAL_JTAG.conf0.pad_pull_override = 1; - USB_SERIAL_JTAG.conf0.dp_pullup = 0; - } else if (gpio_num == USB_OTG_INT_PHY_DP_GPIO_NUM) { - USB_WRAP.otg_conf.pad_pull_override = 1; - USB_WRAP.otg_conf.dp_pullup = 0; - } IO_MUX.gpio[gpio_num].fun_wpd = 0; } From 7be0bf12afcc3f126ddee7cf9b8e5983a2dacb54 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 24 Jul 2024 09:33:08 +0530 Subject: [PATCH 512/548] fix(nimble): Add return value to RPA Timeout API --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index c0363f26cf6..3126e6c5613 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit c0363f26cf6484830779292035fe309c1ec0eb94 +Subproject commit 3126e6c561369589677191a9aa22def441873f69 From 46892c32ec16620da1d9829cf43fe59b8499c118 Mon Sep 17 00:00:00 2001 From: Xiaoyu Liu Date: Tue, 23 Jul 2024 14:45:24 +0800 Subject: [PATCH 513/548] docs(interrupts): fix wrong high-level interrupt level num in doc --- docs/en/api-guides/hlinterrupts.rst | 4 ++-- docs/zh_CN/api-guides/hlinterrupts.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/api-guides/hlinterrupts.rst b/docs/en/api-guides/hlinterrupts.rst index 97d7fff255a..c7ef140dc06 100644 --- a/docs/en/api-guides/hlinterrupts.rst +++ b/docs/en/api-guides/hlinterrupts.rst @@ -77,8 +77,8 @@ Using these symbols is done by creating an assembly file with suffix ``.S`` and .. code-block:: none .section .iram1,"ax" - .global xt_highint5 - .type xt_highint5,@function + .global xt_highint4 + .type xt_highint4,@function .align 4 xt_highint5: ... your code here diff --git a/docs/zh_CN/api-guides/hlinterrupts.rst b/docs/zh_CN/api-guides/hlinterrupts.rst index 8d0c48140f6..7f78e1a3d9c 100644 --- a/docs/zh_CN/api-guides/hlinterrupts.rst +++ b/docs/zh_CN/api-guides/hlinterrupts.rst @@ -77,8 +77,8 @@ Xtensa 架构支持 32 个中断处理程序,这些中断分为从 1 到 7 的 .. code-block:: none .section .iram1,"ax" - .global xt_highint5 - .type xt_highint5,@function + .global xt_highint4 + .type xt_highint4,@function .align 4 xt_highint5: ... your code here From 9e0a13e4d77eb9f3fa01f9b1fcb971da6f70fe02 Mon Sep 17 00:00:00 2001 From: Sachin Billore Date: Sat, 1 Jun 2024 12:33:40 +0530 Subject: [PATCH 514/548] fix(apm): minor fixes for apm api --- components/hal/esp32c6/include/hal/apm_ll.h | 129 +++++++------------- components/hal/esp32h2/include/hal/apm_ll.h | 101 +++++---------- components/hal/include/hal/apm_hal.h | 8 +- 3 files changed, 81 insertions(+), 157 deletions(-) diff --git a/components/hal/esp32c6/include/hal/apm_ll.h b/components/hal/esp32c6/include/hal/apm_ll.h index fc7b3fa4ce5..0288568707c 100644 --- a/components/hal/esp32c6/include/hal/apm_ll.h +++ b/components/hal/esp32c6/include/hal/apm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,6 @@ #include "soc/hp_apm_reg.h" #include "soc/lp_apm_reg.h" #include "soc/interrupts.h" -#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -41,68 +40,68 @@ extern "C" { #define APM_CTRL_REGION_FILTER_EN_REG(apm_ctrl) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION_FILTER_EN_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION_FILTER_EN_REG) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION_FILTER_EN_REG) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION_FILTER_EN_REG) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION_FILTER_EN_REG) : \ + (LP_APM_REGION_FILTER_EN_REG)); \ }) #define TEE_LL_MODE_CTRL_REG(master_id) (TEE_M0_MODE_CTRL_REG + 4 * (master_id)) #define APM_LL_REGION_ADDR_START_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ + (LP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num))); \ }) #define APM_LL_REGION_ADDR_END_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ + (LP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num))); \ }) #define APM_LL_REGION_ADDR_ATTR_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ + (LP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num))); \ }) #define APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path))); \ }) #define APM_CTRL_M_REGION_STATUS_CLR (BIT(0)) #define APM_LL_APM_CTRL_EXCP_CLR_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ + (LP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path))); \ }) #define APM_LL_TEE_EXCP_INFO0_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ + (LP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path))); \ }) #define APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path))); \ }) #define APM_LL_TEE_EXCP_INFO1_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ + (LP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path))); \ }) #define APM_LL_SEC_MODE_REGION_ATTR(sec_mode, regn_pms) ((regn_pms) << (4 * (sec_mode - 1))) @@ -111,24 +110,24 @@ extern "C" { #define APM_LL_APM_CTRL_INT_EN_REG(apm_ctrl) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_INT_EN_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_INT_EN_REG) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_INT_EN_REG) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_INT_EN_REG) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_INT_EN_REG) : \ + (LP_APM_INT_EN_REG)); \ }) #define APM_CTRL_CLK_EN (BIT(0)) #define APM_LL_APM_CTRL_CLOCK_GATE_REG(apm_ctrl) \ ({\ - (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_CLOCK_GATE_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_CLOCK_GATE_REG) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_CLOCK_GATE_REG) : 0)); \ + (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_CLOCK_GATE_REG) : \ + ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_CLOCK_GATE_REG) : \ + (LP_APM_CLOCK_GATE_REG)); \ }) #define APM_LL_APM_CTRL_FUNC_CTRL_REG(apm_ctrl) \ ({\ (LP_APM0_CTRL == apm_ctrl) ? (LP_APM0_FUNC_CTRL_REG) : \ ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_FUNC_CTRL_REG) : \ - ((LP_APM_CTRL == apm_ctrl) ? (LP_APM_FUNC_CTRL_REG) : 0)); \ + (LP_APM_FUNC_CTRL_REG)); \ }) /** @@ -259,11 +258,6 @@ static inline void apm_ll_apm_ctrl_region_filter_enable(apm_ll_apm_ctrl_t apm_ct static inline void apm_ll_apm_ctrl_filter_enable(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path, bool enable) { - HAL_ASSERT(((apm_ctrl == LP_APM0_CTRL) && (apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - if (enable) { REG_SET_BIT(APM_LL_APM_CTRL_FUNC_CTRL_REG(apm_ctrl), BIT(apm_m_path)); } else { @@ -281,10 +275,6 @@ static inline void apm_ll_apm_ctrl_filter_enable(apm_ll_apm_ctrl_t apm_ctrl, static inline void apm_ll_apm_ctrl_set_region_start_address(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, uint32_t addr) { - HAL_ASSERT((((apm_ctrl == LP_APM0_CTRL) || (apm_ctrl == LP_APM_CTRL)) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - REG_WRITE(APM_LL_REGION_ADDR_START_REG(apm_ctrl, regn_num), addr); } @@ -298,10 +288,6 @@ static inline void apm_ll_apm_ctrl_set_region_start_address(apm_ll_apm_ctrl_t ap static inline void apm_ll_apm_ctrl_set_region_end_address(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, uint32_t addr) { - HAL_ASSERT((((apm_ctrl == LP_APM0_CTRL) || (apm_ctrl == LP_APM_CTRL)) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - REG_WRITE(APM_LL_REGION_ADDR_END_REG(apm_ctrl, regn_num), addr); } @@ -316,10 +302,6 @@ static inline void apm_ll_apm_ctrl_set_region_end_address(apm_ll_apm_ctrl_t apm_ static inline void apm_ll_apm_ctrl_sec_mode_region_attr_config(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, apm_ll_secure_mode_t sec_mode, uint32_t regn_pms) { - HAL_ASSERT((((apm_ctrl == LP_APM0_CTRL) || (apm_ctrl == LP_APM_CTRL)) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - uint32_t val = 0; val = REG_READ(APM_LL_REGION_ADDR_ATTR_REG(apm_ctrl, regn_num)); val &= ~APM_LL_SEC_MODE_REGION_ATTR_M(sec_mode); @@ -336,11 +318,6 @@ static inline void apm_ll_apm_ctrl_sec_mode_region_attr_config(apm_ll_apm_ctrl_t static inline uint8_t apm_ll_apm_ctrl_exception_status(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == LP_APM0_CTRL) && (apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - return REG_READ(APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path)); } @@ -353,11 +330,6 @@ static inline uint8_t apm_ll_apm_ctrl_exception_status(apm_ll_apm_ctrl_t apm_ctr static inline void apm_ll_apm_ctrl_exception_clear(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == LP_APM0_CTRL) && (apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - REG_SET_BIT(APM_LL_APM_CTRL_EXCP_CLR_REG(apm_ctrl, apm_m_path), APM_CTRL_M_REGION_STATUS_CLR); } @@ -370,11 +342,6 @@ static inline void apm_ll_apm_ctrl_exception_clear(apm_ll_apm_ctrl_t apm_ctrl, */ static inline void apm_ll_apm_ctrl_get_exception_info(apm_ctrl_exception_info_t *excp_info) { - HAL_ASSERT(((excp_info->apm_path.apm_ctrl == LP_APM0_CTRL) && (excp_info->apm_path.apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((excp_info->apm_path.apm_ctrl == HP_APM_CTRL) && (excp_info->apm_path.apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((excp_info->apm_path.apm_ctrl == LP_APM_CTRL) && (excp_info->apm_path.apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - excp_info->excp_id = REG_GET_FIELD(APM_LL_TEE_EXCP_INFO0_REG(excp_info->apm_path.apm_ctrl, excp_info->apm_path.apm_m_path), APM_LL_CTRL_EXCEPTION_ID); excp_info->excp_mode = REG_GET_FIELD(APM_LL_TEE_EXCP_INFO0_REG(excp_info->apm_path.apm_ctrl, excp_info->apm_path.apm_m_path), @@ -395,11 +362,6 @@ static inline void apm_ll_apm_ctrl_get_exception_info(apm_ctrl_exception_info_t static inline void apm_ll_apm_ctrl_interrupt_enable(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path, bool enable) { - HAL_ASSERT(((apm_ctrl == LP_APM0_CTRL) && (apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - if (enable) { REG_SET_BIT(APM_LL_APM_CTRL_INT_EN_REG(apm_ctrl), BIT(apm_m_path)); } else { @@ -442,25 +404,20 @@ static inline void apm_ll_apm_ctrl_reset_event_enable(bool enable) } /** - * @brief Return APM Ctrl interrupt source number. + * @brief Fetch the APM Ctrl interrupt source number. * * @param apm_ctrl APM Ctrl (LP_APM0/HP_APM/LP_APM) * @param apm_m_path APM Ctrl access patch(M[0:n]) */ -static inline esp_err_t apm_ll_apm_ctrl_get_int_src_num(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) +static inline int apm_ll_apm_ctrl_get_int_src_num(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == LP_APM0_CTRL) && (apm_m_path < LP_APM0_MAX_ACCESS_PATH)) || - ((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - switch (apm_ctrl) { - case LP_APM0_CTRL : - return (ETS_LP_APM0_INTR_SOURCE); - case HP_APM_CTRL : - return (ETS_HP_APM_M0_INTR_SOURCE + apm_m_path); - case LP_APM_CTRL : - return (ETS_LP_APM_M0_INTR_SOURCE + apm_m_path); + case LP_APM0_CTRL : + return (ETS_LP_APM0_INTR_SOURCE); + case HP_APM_CTRL : + return (ETS_HP_APM_M0_INTR_SOURCE + apm_m_path); + case LP_APM_CTRL : + return (ETS_LP_APM_M0_INTR_SOURCE + apm_m_path); } return -1; diff --git a/components/hal/esp32h2/include/hal/apm_ll.h b/components/hal/esp32h2/include/hal/apm_ll.h index b95effad697..cc0046ce274 100644 --- a/components/hal/esp32h2/include/hal/apm_ll.h +++ b/components/hal/esp32h2/include/hal/apm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,7 +14,6 @@ #include "soc/hp_apm_reg.h" #include "soc/lp_apm_reg.h" #include "soc/interrupts.h" -#include "hal/assert.h" #ifdef __cplusplus extern "C" { @@ -39,59 +38,59 @@ extern "C" { #define APM_CTRL_REGION_FILTER_EN_REG(apm_ctrl) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION_FILTER_EN_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION_FILTER_EN_REG) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION_FILTER_EN_REG) : \ + (HP_APM_REGION_FILTER_EN_REG); \ }) #define TEE_LL_MODE_CTRL_REG(master_id) (TEE_M0_MODE_CTRL_REG + 4 * (master_id)) #define APM_LL_REGION_ADDR_START_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)) : \ + (HP_APM_REGION0_ADDR_START_REG + 0xC * (regn_num)); \ }) #define APM_LL_REGION_ADDR_END_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)) : \ + (HP_APM_REGION0_ADDR_END_REG + 0xC * (regn_num)); \ }) #define APM_LL_REGION_ADDR_ATTR_REG(apm_ctrl, regn_num) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)) : \ + (HP_APM_REGION0_PMS_ATTR_REG + 0xC * (regn_num)); \ }) #define APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)); \ }) #define APM_CTRL_M_REGION_STATUS_CLR (BIT(0)) #define APM_LL_APM_CTRL_EXCP_CLR_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)) : \ + (HP_APM_M0_STATUS_CLR_REG + 0x10 * (apm_m_path)); \ }) #define APM_LL_TEE_EXCP_INFO0_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)) : \ + (HP_APM_M0_EXCEPTION_INFO0_REG + 0x10 * (apm_m_path)); \ }) #define APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)) : \ + (HP_APM_M0_STATUS_REG + 0x10 * (apm_m_path)); \ }) #define APM_LL_TEE_EXCP_INFO1_REG(apm_ctrl, apm_m_path) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)) : \ + (HP_APM_M0_EXCEPTION_INFO1_REG + 0x10 * (apm_m_path)); \ }) #define APM_LL_SEC_MODE_REGION_ATTR(sec_mode, regn_pms) ((regn_pms) << (4 * (sec_mode - 1))) @@ -100,21 +99,21 @@ extern "C" { #define APM_LL_APM_CTRL_INT_EN_REG(apm_ctrl) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_INT_EN_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_INT_EN_REG) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_INT_EN_REG) : \ + (HP_APM_INT_EN_REG); \ }) #define APM_CTRL_CLK_EN (BIT(0)) #define APM_LL_APM_CTRL_CLOCK_GATE_REG(apm_ctrl) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_CLOCK_GATE_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_CLOCK_GATE_REG) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_CLOCK_GATE_REG) : \ + (HP_APM_CLOCK_GATE_REG); \ }) #define APM_LL_APM_CTRL_FUNC_CTRL_REG(apm_ctrl) \ ({\ - (LP_APM_CTRL == apm_ctrl) ? (LP_APM_FUNC_CTRL_REG) : \ - ((HP_APM_CTRL == apm_ctrl) ? (HP_APM_FUNC_CTRL_REG) : 0); \ + (LP_APM_CTRL == apm_ctrl) ? (LP_APM_FUNC_CTRL_REG) : \ + (HP_APM_FUNC_CTRL_REG); \ }) /** @@ -242,10 +241,6 @@ static inline void apm_ll_apm_ctrl_region_filter_enable(apm_ll_apm_ctrl_t apm_ct static inline void apm_ll_apm_ctrl_filter_enable(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path, bool enable) { - HAL_ASSERT(((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - if (enable) { REG_SET_BIT(APM_LL_APM_CTRL_FUNC_CTRL_REG(apm_ctrl), BIT(apm_m_path)); } else { @@ -263,10 +258,6 @@ static inline void apm_ll_apm_ctrl_filter_enable(apm_ll_apm_ctrl_t apm_ctrl, static inline void apm_ll_apm_ctrl_set_region_start_address(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, uint32_t addr) { - HAL_ASSERT(((apm_ctrl == LP_APM_CTRL) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - REG_WRITE(APM_LL_REGION_ADDR_START_REG(apm_ctrl, regn_num), addr); } @@ -280,10 +271,6 @@ static inline void apm_ll_apm_ctrl_set_region_start_address(apm_ll_apm_ctrl_t ap static inline void apm_ll_apm_ctrl_set_region_end_address(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, uint32_t addr) { - HAL_ASSERT(((apm_ctrl == LP_APM_CTRL) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - REG_WRITE(APM_LL_REGION_ADDR_END_REG(apm_ctrl, regn_num), addr); } @@ -298,10 +285,6 @@ static inline void apm_ll_apm_ctrl_set_region_end_address(apm_ll_apm_ctrl_t apm_ static inline void apm_ll_apm_ctrl_sec_mode_region_attr_config(apm_ll_apm_ctrl_t apm_ctrl, uint32_t regn_num, apm_ll_secure_mode_t sec_mode, uint32_t regn_pms) { - HAL_ASSERT(((apm_ctrl == LP_APM_CTRL) && (regn_num <= APM_LL_LP_MAX_REGION_NUM)) || - ((apm_ctrl == HP_APM_CTRL) && (regn_num <= APM_LL_HP_MAX_REGION_NUM)) - ); - uint32_t val = 0; val = REG_READ(APM_LL_REGION_ADDR_ATTR_REG(apm_ctrl, regn_num)); val &= ~APM_LL_SEC_MODE_REGION_ATTR_M(sec_mode); @@ -318,10 +301,6 @@ static inline void apm_ll_apm_ctrl_sec_mode_region_attr_config(apm_ll_apm_ctrl_t static inline uint8_t apm_ll_apm_ctrl_exception_status(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - return REG_READ(APM_LL_APM_CTRL_EXCP_STATUS_REG(apm_ctrl, apm_m_path)); } @@ -334,10 +313,6 @@ static inline uint8_t apm_ll_apm_ctrl_exception_status(apm_ll_apm_ctrl_t apm_ctr static inline void apm_ll_apm_ctrl_exception_clear(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - REG_SET_BIT(APM_LL_APM_CTRL_EXCP_CLR_REG(apm_ctrl, apm_m_path), APM_CTRL_M_REGION_STATUS_CLR); } @@ -350,10 +325,6 @@ static inline void apm_ll_apm_ctrl_exception_clear(apm_ll_apm_ctrl_t apm_ctrl, */ static inline void apm_ll_apm_ctrl_get_exception_info(apm_ctrl_exception_info_t *excp_info) { - HAL_ASSERT(((excp_info->apm_path.apm_ctrl == HP_APM_CTRL) && (excp_info->apm_path.apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((excp_info->apm_path.apm_ctrl == LP_APM_CTRL) && (excp_info->apm_path.apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - excp_info->excp_id = REG_GET_FIELD(APM_LL_TEE_EXCP_INFO0_REG(excp_info->apm_path.apm_ctrl, excp_info->apm_path.apm_m_path), APM_LL_CTRL_EXCEPTION_ID); excp_info->excp_mode = REG_GET_FIELD(APM_LL_TEE_EXCP_INFO0_REG(excp_info->apm_path.apm_ctrl, excp_info->apm_path.apm_m_path), @@ -374,10 +345,6 @@ static inline void apm_ll_apm_ctrl_get_exception_info(apm_ctrl_exception_info_t static inline void apm_ll_apm_ctrl_interrupt_enable(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path, bool enable) { - HAL_ASSERT(((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - if (enable) { REG_SET_BIT(APM_LL_APM_CTRL_INT_EN_REG(apm_ctrl), BIT(apm_m_path)); } else { @@ -420,22 +387,18 @@ static inline void apm_ll_apm_ctrl_reset_event_enable(bool enable) } /** - * @brief Return APM Ctrl interrupt source number. + * @brief Fetch the APM Ctrl interrupt source number. * - * @param apm_ctrl APM Ctrl (LP_APM/HP_APM) + * @param apm_ctrl APM Ctrl (LP_APM0/HP_APM/LP_APM) * @param apm_m_path APM Ctrl access patch(M[0:n]) */ -static inline esp_err_t apm_ll_apm_ctrl_get_int_src_num(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) +static inline int apm_ll_apm_ctrl_get_int_src_num(apm_ll_apm_ctrl_t apm_ctrl, apm_ll_ctrl_access_path_t apm_m_path) { - HAL_ASSERT(((apm_ctrl == HP_APM_CTRL) && (apm_m_path < HP_APM_MAX_ACCESS_PATH)) || - ((apm_ctrl == LP_APM_CTRL) && (apm_m_path < LP_APM_MAX_ACCESS_PATH)) - ); - switch (apm_ctrl) { - case HP_APM_CTRL : - return (ETS_HP_APM_M0_INTR_SOURCE + apm_m_path); - case LP_APM_CTRL : - return (ETS_LP_APM_M0_INTR_SOURCE); + case HP_APM_CTRL : + return (ETS_HP_APM_M0_INTR_SOURCE + apm_m_path); + case LP_APM_CTRL : + return (ETS_LP_APM_M0_INTR_SOURCE + apm_m_path); } return -1; diff --git a/components/hal/include/hal/apm_hal.h b/components/hal/include/hal/apm_hal.h index 6f8b6eb5e93..94898df37c9 100644 --- a/components/hal/include/hal/apm_hal.h +++ b/components/hal/include/hal/apm_hal.h @@ -238,11 +238,15 @@ void apm_hal_apm_ctrl_master_sec_mode_config(apm_ctrl_secure_mode_config_t *sec_ void apm_hal_apm_ctrl_reset_event_enable(bool enable); /** - * @brief Returns APM Ctrl access path interrupt source number. + * @brief Fetch the APM Ctrl access path interrupt source number. * * @param apm_path APM controller and access path to be configured + * + * @return + * - valid interrupt source number on success + * - -1: invalid interrupt source */ -esp_err_t apm_hal_apm_ctrl_get_int_src_num(apm_ctrl_path_t *apm_path); +int apm_hal_apm_ctrl_get_int_src_num(apm_ctrl_path_t *apm_path); #endif //CONFIG_IDF_TARGET_ESP32P4 From d61531a8e59d33a660da5afe120d9d067f48a29e Mon Sep 17 00:00:00 2001 From: Jiang Guang Ming Date: Mon, 20 May 2024 16:10:57 +0800 Subject: [PATCH 515/548] fix(esp_rom): add new rom caps ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG --- components/esp_rom/CMakeLists.txt | 2 +- components/esp_rom/esp32c61/Kconfig.soc_caps.in | 4 ++++ components/esp_rom/esp32c61/esp_rom_caps.h | 1 + components/esp_rom/esp32h2/Kconfig.soc_caps.in | 4 ++++ components/esp_rom/esp32h2/esp_rom_caps.h | 1 + components/esp_rom/esp32p4/Kconfig.soc_caps.in | 4 ++++ components/esp_rom/esp32p4/esp_rom_caps.h | 1 + components/newlib/test_apps/newlib/main/test_newlib.c | 2 +- 8 files changed, 17 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 859ebcd58a6..808d0519575 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -204,7 +204,7 @@ else() # Regular app build rom_linker_script("newlib") if(CONFIG_ESP_ROM_HAS_NEWLIB_NANO_FORMAT AND CONFIG_NEWLIB_NANO_FORMAT) - if(NOT CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME) + if(NOT CONFIG_ESP_ROM_HAS_NEWLIB_32BIT_TIME AND NOT CONFIG_ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG) # Newlib-nano functions contains time_t related functions # and cannot be used if they were compiled with 32 bit time_t rom_linker_script("newlib-nano") diff --git a/components/esp_rom/esp32c61/Kconfig.soc_caps.in b/components/esp_rom/esp32c61/Kconfig.soc_caps.in index edb2c52a3d7..f3bea7e1e6b 100644 --- a/components/esp_rom/esp32c61/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32c61/Kconfig.soc_caps.in @@ -67,6 +67,10 @@ config ESP_ROM_HAS_NEWLIB_NANO_FORMAT bool default y +config ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG + bool + default y + config ESP_ROM_HAS_VERSION bool default y diff --git a/components/esp_rom/esp32c61/esp_rom_caps.h b/components/esp_rom/esp32c61/esp_rom_caps.h index a5eea647eff..9bcc14320be 100644 --- a/components/esp_rom/esp32c61/esp_rom_caps.h +++ b/components/esp_rom/esp32c61/esp_rom_caps.h @@ -24,6 +24,7 @@ // #define ESP_ROM_HAS_REGI2C_BUG (1) // ROM has the regi2c bug #define ESP_ROM_HAS_NEWLIB (1) // ROM has newlib (at least parts of it) functions included #define ESP_ROM_HAS_NEWLIB_NANO_FORMAT (1) // ROM has the newlib nano version of formatting functions +#define ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG (1) // ROM has the printf float bug with newlib nano version #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_WDT_INIT_PATCH (1) // ROM version does not configure the clock #define ESP_ROM_RAM_APP_NEEDS_MMU_INIT (1) // ROM doesn't init cache MMU when it's a RAM APP, needs MMU hal to init diff --git a/components/esp_rom/esp32h2/Kconfig.soc_caps.in b/components/esp_rom/esp32h2/Kconfig.soc_caps.in index ade2e7af59a..bc719bac119 100644 --- a/components/esp_rom/esp32h2/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32h2/Kconfig.soc_caps.in @@ -67,6 +67,10 @@ config ESP_ROM_HAS_NEWLIB_NANO_FORMAT bool default y +config ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG + bool + default y + config ESP_ROM_WDT_INIT_PATCH bool default y diff --git a/components/esp_rom/esp32h2/esp_rom_caps.h b/components/esp_rom/esp32h2/esp_rom_caps.h index fbea5f01040..95ae2359362 100644 --- a/components/esp_rom/esp32h2/esp_rom_caps.h +++ b/components/esp_rom/esp32h2/esp_rom_caps.h @@ -22,6 +22,7 @@ #define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs #define ESP_ROM_HAS_NEWLIB (1) // ROM has newlib (at least parts of it) functions included #define ESP_ROM_HAS_NEWLIB_NANO_FORMAT (1) // ROM has the newlib nano versions of formatting functions +#define ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG (1) // ROM has the printf float bug with newlib nano version #define ESP_ROM_WDT_INIT_PATCH (1) // ROM version does not configure the clock #define ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE (1) // ROM needs to set cache MMU size according to instruction and rodata for flash mmap #define ESP_ROM_RAM_APP_NEEDS_MMU_INIT (1) // ROM doesn't init cache MMU when it's a RAM APP, needs MMU hal to init diff --git a/components/esp_rom/esp32p4/Kconfig.soc_caps.in b/components/esp_rom/esp32p4/Kconfig.soc_caps.in index af5b84d7076..a7a0a9c0850 100644 --- a/components/esp_rom/esp32p4/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32p4/Kconfig.soc_caps.in @@ -67,6 +67,10 @@ config ESP_ROM_HAS_NEWLIB_NANO_FORMAT bool default y +config ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG + bool + default y + config ESP_ROM_HAS_VERSION bool default y diff --git a/components/esp_rom/esp32p4/esp_rom_caps.h b/components/esp_rom/esp32p4/esp_rom_caps.h index f0c1d32bb39..8578f4401fa 100644 --- a/components/esp_rom/esp32p4/esp_rom_caps.h +++ b/components/esp_rom/esp32p4/esp_rom_caps.h @@ -22,5 +22,6 @@ #define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs #define ESP_ROM_HAS_NEWLIB (1) // ROM has newlib (at least parts of it) functions included #define ESP_ROM_HAS_NEWLIB_NANO_FORMAT (1) // ROM has the newlib nano version of formatting functions +#define ESP_ROM_HAS_NEWLIB_NANO_PRINTF_FLOAT_BUG (1) // ROM has the printf float bug with newlib nano version #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_CLIC_INT_TYPE_PATCH (1) // ROM api esprv_intc_int_set_type configuring edge type interrupt is invalid diff --git a/components/newlib/test_apps/newlib/main/test_newlib.c b/components/newlib/test_apps/newlib/main/test_newlib.c index 4939fd028e2..729499cb223 100644 --- a/components/newlib/test_apps/newlib/main/test_newlib.c +++ b/components/newlib/test_apps/newlib/main/test_newlib.c @@ -131,7 +131,7 @@ static bool fn_in_rom(void *fn) /* Older chips have newlib nano in rom as well, but this is not linked in due to us now using 64 bit time_t and the ROM code was compiled for 32 bit. */ -#define PRINTF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && (CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4)) +#define PRINTF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2) #define SSCANF_NANO_IN_ROM (CONFIG_NEWLIB_NANO_FORMAT && CONFIG_IDF_TARGET_ESP32C2) TEST_CASE("check if ROM or Flash is used for functions", "[newlib]") From ae8c5f5e1cdbd74a4e04c80acf1d9093bf4bc22c Mon Sep 17 00:00:00 2001 From: Jiang Guang Ming Date: Fri, 24 May 2024 17:44:59 +0800 Subject: [PATCH 516/548] feat(newlib): add test case for printf float --- components/newlib/test_apps/newlib/main/test_newlib.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/newlib/test_apps/newlib/main/test_newlib.c b/components/newlib/test_apps/newlib/main/test_newlib.c index 729499cb223..48cd9d0992e 100644 --- a/components/newlib/test_apps/newlib/main/test_newlib.c +++ b/components/newlib/test_apps/newlib/main/test_newlib.c @@ -230,3 +230,10 @@ TEST_CASE("newlib: rom and toolchain localtime func gives the same result", "[ne printf("%s\n", test_result); TEST_ASSERT_EQUAL_STRING("2020-03-12 15:00:00 EDT (tm_isdst = 1)", test_result); } + +TEST_CASE("newlib: printf float as expected", "[newlib]") +{ + const float val = 1.23; + int len = printf("test printf float val is %1.2f\n", val); + TEST_ASSERT_EQUAL_INT(30, len); +} From c658ae66797dc5cb2a5858bbcfbec210cca8e7da Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Wed, 12 Jun 2024 11:50:52 +0200 Subject: [PATCH 517/548] fix(esp_system): properly exclude XTAL32K WDT from other chips Closes https://github.com/espressif/esp-idf/issues/13955 --- components/esp_system/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index c5f33787eda..ea4290cae81 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -411,7 +411,7 @@ menu "ESP System Settings" default 800 if (SPIRAM && IDF_TARGET_ESP32) range 10 10000 help - The timeout of the watchdog, in miliseconds. Make this higher than the FreeRTOS tick rate. + The timeout of the watchdog, in milliseconds. Make this higher than the FreeRTOS tick rate. config ESP_INT_WDT_CHECK_CPU1 bool "Also watch CPU1 tick interrupt" @@ -485,7 +485,7 @@ menu "ESP System Settings" config ESP_XT_WDT bool "Initialize XTAL32K watchdog timer on startup" - depends on !IDF_TARGET_ESP32 && (ESP_SYSTEM_RTC_EXT_OSC || ESP_SYSTEM_RTC_EXT_XTAL) + depends on SOC_XT_WDT_SUPPORTED && (ESP_SYSTEM_RTC_EXT_OSC || ESP_SYSTEM_RTC_EXT_XTAL) default n help This watchdog timer can detect oscillation failure of the XTAL32K_CLK. When such a failure From e4962dccf37e2d6ab20321e50cbfdb3346a1626b Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 2 Jul 2024 16:00:28 +0200 Subject: [PATCH 518/548] fix(coredump): fix array out of the bounds error Closes https://github.com/espressif/esp-idf/issues/14117 --- components/espcoredump/src/core_dump_elf.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/espcoredump/src/core_dump_elf.c b/components/espcoredump/src/core_dump_elf.c index 183962908e5..2e3da6ee028 100644 --- a/components/espcoredump/src/core_dump_elf.c +++ b/components/espcoredump/src/core_dump_elf.c @@ -207,8 +207,8 @@ static int elf_write_note_header(core_dump_elf_t *self, static char name_buffer[ELF_NOTE_NAME_MAX_SIZE] = { 0 }; elf_note note_hdr = { 0 }; - memcpy((void*)name_buffer, (void*)name, name_len); - note_hdr.n_namesz = name_len; + memcpy(name_buffer, name, name_len); + note_hdr.n_namesz = ALIGN_UP(name_len, 4); note_hdr.n_descsz = data_sz; note_hdr.n_type = type; // write note header @@ -216,7 +216,7 @@ static int elf_write_note_header(core_dump_elf_t *self, ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL, "Write ELF note header failure (%d)", err); // write note name - err = esp_core_dump_write_data(&self->write_data, name_buffer, name_len); + err = esp_core_dump_write_data(&self->write_data, name_buffer, note_hdr.n_namesz); ELF_CHECK_ERR((err == ESP_OK), ELF_PROC_ERR_WRITE_FAIL, "Write ELF note name failure (%d)", err); @@ -671,7 +671,7 @@ static void elf_write_core_dump_note_cb(void *opaque, const char *data) static int elf_add_wdt_panic_details(core_dump_elf_t *self) { - uint32_t name_len = ALIGN_UP(sizeof(ELF_ESP_CORE_DUMP_PANIC_DETAILS_NOTE_NAME), 4); + uint32_t name_len = sizeof(ELF_ESP_CORE_DUMP_PANIC_DETAILS_NOTE_NAME); core_dump_elf_opaque_t param = { .self = self, .total_size = 0, @@ -705,7 +705,7 @@ static int elf_add_wdt_panic_details(core_dump_elf_t *self) } } - return ALIGN_UP(name_len + ALIGN_UP(self->note_data_size, 4) + sizeof(elf_note), 4); + return ALIGN_UP(ALIGN_UP(name_len, 4) + ALIGN_UP(self->note_data_size, 4) + sizeof(elf_note), 4); } #endif //CONFIG_ESP_TASK_WDT_EN From 1df847e2a01d24e70707ad3073e366b7bb9a4557 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Tue, 4 Jun 2024 15:49:33 +0800 Subject: [PATCH 519/548] fix(ble/bluedroid): Fixed issue with resetting BLE security parameters during initialization --- components/bt/host/bluedroid/bta/dm/bta_dm_co.c | 12 ++++++++++++ .../bt/host/bluedroid/bta/dm/include/bta_dm_int.h | 3 +++ components/bt/host/bluedroid/btc/core/btc_main.c | 1 + 3 files changed, 16 insertions(+) diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c index c6b62f3a6f7..5c7ee9bdede 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c @@ -52,6 +52,18 @@ tBTE_APPL_CFG bte_appl_cfg = { BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE, BTM_BLE_OOB_DISABLE, }; + +void bta_dm_co_security_param_init(void) +{ + bte_appl_cfg.ble_auth_req = BTA_LE_AUTH_REQ_SC_MITM_BOND; + bte_appl_cfg.ble_io_cap = BTM_LOCAL_IO_CAPS_BLE; + bte_appl_cfg.ble_init_key = BTM_BLE_INITIATOR_KEY_SIZE; + bte_appl_cfg.ble_resp_key = BTM_BLE_RESPONDER_KEY_SIZE; + bte_appl_cfg.ble_max_key_size = BTM_BLE_MAX_KEY_SIZE; + bte_appl_cfg.ble_min_key_size = BTM_BLE_MIN_KEY_SIZE; + bte_appl_cfg.ble_accept_auth_enable = BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE; + bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE; +}; #endif #if (defined CLASSIC_BT_INCLUDED && CLASSIC_BT_INCLUDED == TRUE) diff --git a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h index 8adc430b185..f8548edea43 100644 --- a/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h +++ b/components/bt/host/bluedroid/bta/dm/include/bta_dm_int.h @@ -1797,6 +1797,9 @@ extern void bta_dm_ble_set_scan_rsp_raw (tBTA_DM_MSG *p_data); extern void bta_dm_ble_broadcast (tBTA_DM_MSG *p_data); extern void bta_dm_ble_set_data_length(tBTA_DM_MSG *p_data); extern void bta_dm_ble_update_duplicate_exceptional_list(tBTA_DM_MSG *p_data); +#if SMP_INCLUDED == TRUE +extern void bta_dm_co_security_param_init(void); +#endif #if BLE_ANDROID_CONTROLLER_SCAN_FILTER == TRUE extern void bta_dm_cfg_filter_cond (tBTA_DM_MSG *p_data); extern void bta_dm_scan_filter_param_setup (tBTA_DM_MSG *p_data); diff --git a/components/bt/host/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c index 28f70b4b6a5..c1c694b8a25 100644 --- a/components/bt/host/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/bluedroid/btc/core/btc_main.c @@ -60,6 +60,7 @@ static void btc_init_bluetooth(void) #if (BLE_INCLUDED == TRUE) //load the ble local key which has been stored in the flash btc_dm_load_ble_local_keys(); + bta_dm_co_security_param_init(); #endif ///BLE_INCLUDED == TRUE #endif /* #if (SMP_INCLUDED) */ #if BTA_DYNAMIC_MEMORY From 86484c14e66757db570ccfe12a8df444bd8e3617 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 31 Jul 2024 15:27:03 +0700 Subject: [PATCH 520/548] fix(newlib): fix include sys/dirent.h breaking change --- components/newlib/CMakeLists.txt | 3 --- .../{clang_include => platform_include}/sys/dirent.h | 7 ++++++- 2 files changed, 6 insertions(+), 4 deletions(-) rename components/newlib/{clang_include => platform_include}/sys/dirent.h (92%) diff --git a/components/newlib/CMakeLists.txt b/components/newlib/CMakeLists.txt index df29489bade..b837b6672a7 100644 --- a/components/newlib/CMakeLists.txt +++ b/components/newlib/CMakeLists.txt @@ -5,9 +5,6 @@ if(${target} STREQUAL "linux") endif() set(include_dirs "platform_include") -if(CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO LLVM-330 - list(APPEND include_dirs "clang_include") -endif() if(BOOTLOADER_BUILD) # Bootloader builds need the platform_include directory (for assert.h), but nothing else diff --git a/components/newlib/clang_include/sys/dirent.h b/components/newlib/platform_include/sys/dirent.h similarity index 92% rename from components/newlib/clang_include/sys/dirent.h rename to components/newlib/platform_include/sys/dirent.h index 444dad2ddf5..2643ddc9544 100644 --- a/components/newlib/clang_include/sys/dirent.h +++ b/components/newlib/platform_include/sys/dirent.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ - +#ifdef __clang__ // TODO LLVM-330 #pragma once #include @@ -63,3 +63,8 @@ int alphasort(const struct dirent **d1, const struct dirent **d2); #ifdef __cplusplus } #endif + +#else // __clang__ TODO: IDF-10675 +#include_next +#include +#endif // __clang__ From f7a3808374f30b6d090fedb75f3eafb08dca4fd7 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 16 Jul 2024 15:35:10 +0800 Subject: [PATCH 521/548] feat(ulp): add option for routing LP-printf to HP console --- .../esp_rom/esp32p4/ld/esp32p4lp.rom.api.ld | 9 ++++ components/ulp/Kconfig | 19 ++++++++ components/ulp/cmake/CMakeLists.txt | 2 + .../lp_core/include/ulp_lp_core_print.h | 7 +++ .../ulp/lp_core/lp_core/lp_core_print.c | 30 +++++++++++-- .../ulp/lp_core/lp_core/lp_core_startup.c | 11 ++++- .../{ => lp_core_basic_tests}/CMakeLists.txt | 2 +- .../{ => lp_core_basic_tests}/README.md | 0 .../main/CMakeLists.txt | 0 .../main/lp_core/test_main.c | 0 .../main/lp_core/test_main_counter.c | 0 .../main/lp_core/test_main_gpio.c | 0 .../main/lp_core/test_main_i2c.c | 0 .../main/lp_core/test_main_isr.c | 0 .../main/lp_core/test_main_set_timer_wakeup.c | 0 .../main/lp_core/test_main_spi_master.c | 0 .../main/lp_core/test_main_spi_slave.c | 0 .../main/lp_core/test_shared.h | 0 .../main/test_app_main.c | 0 .../main/test_lp_core.c | 0 .../main/test_lp_core_etm.c | 0 .../main/test_lp_core_i2c.c | 0 .../main/test_lp_core_spi.c | 0 .../pytest_lp_core_basic.py} | 2 +- .../sdkconfig.ci.default | 0 .../sdkconfig.defaults | 0 .../lp_core/lp_core_hp_uart/CMakeLists.txt | 14 ++++++ .../lp_core/lp_core_hp_uart/README.md | 3 ++ .../lp_core_hp_uart/main/CMakeLists.txt | 11 +++++ .../main/lp_core/test_hello_main.c | 16 +++++++ .../lp_core_hp_uart/main/test_app_main.c | 41 ++++++++++++++++++ .../lp_core_hp_uart/main/test_lp_core.c | 43 +++++++++++++++++++ .../lp_core_hp_uart/pytest_lp_core_hp_uart.py | 13 ++++++ .../lp_core_hp_uart/sdkconfig.ci.default | 0 .../lp_core_hp_uart/sdkconfig.defaults | 7 +++ docs/en/api-reference/system/ulp-lp-core.rst | 40 ++++++++++------- 36 files changed, 248 insertions(+), 22 deletions(-) create mode 100644 components/esp_rom/esp32p4/ld/esp32p4lp.rom.api.ld rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/CMakeLists.txt (94%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/README.md (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/CMakeLists.txt (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_counter.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_gpio.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_i2c.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_isr.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_set_timer_wakeup.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_spi_master.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_main_spi_slave.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/lp_core/test_shared.h (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/test_app_main.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/test_lp_core.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/test_lp_core_etm.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/test_lp_core_i2c.c (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/main/test_lp_core_spi.c (100%) rename components/ulp/test_apps/lp_core/{pytest_lp_core.py => lp_core_basic_tests/pytest_lp_core_basic.py} (91%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/sdkconfig.ci.default (100%) rename components/ulp/test_apps/lp_core/{ => lp_core_basic_tests}/sdkconfig.defaults (100%) create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/CMakeLists.txt create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/README.md create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_hello_main.c create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_app_main.c create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.ci.default create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.defaults diff --git a/components/esp_rom/esp32p4/ld/esp32p4lp.rom.api.ld b/components/esp_rom/esp32p4/ld/esp32p4lp.rom.api.ld new file mode 100644 index 00000000000..4d7fc793e20 --- /dev/null +++ b/components/esp_rom/esp32p4/ld/esp32p4lp.rom.api.ld @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/** ROM APIs + */ + +PROVIDE ( esp_rom_output_putc = uart_tx_one_char ); diff --git a/components/ulp/Kconfig b/components/ulp/Kconfig index 94167bd5dfa..53be58f8292 100644 --- a/components/ulp/Kconfig +++ b/components/ulp/Kconfig @@ -106,6 +106,25 @@ menu "Ultra Low Power (ULP) Co-processor" Disabling this option will reduce the LP core binary size by not linking in panic handler functionality. + config ULP_HP_UART_CONSOLE_PRINT + depends on ULP_COPROC_TYPE_LP_CORE + bool + prompt "Route lp_core_printf to the console HP-UART" + help + Set this option to route lp_core_printf to the console HP-UART. + This allows you to easily view print outputs from the LP core, without + having to connect to the LP-UART. This option comes with the following + limitations: + + 1. There is no mutual exclusion between the HP-Core and the LP-Core accessing + the HP-UART, which means that if both cores are logging heavily the output + strings might get mangled together. + 2. The HP-UART can only work while the HP-Core is running, which means that + if the HP-Core is in deep sleep, the LP-Core will not be able to print to the + console HP-UART. + + Due to these limitations it is only recommended to use this option for easy debugging. + For more serious use-cases you should use the LP-UART. endmenu endmenu # Ultra Low Power (ULP) Co-processor diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index d6117e5a955..9796f1c26b2 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -139,6 +139,8 @@ elseif(CONFIG_ULP_COPROC_TYPE_LP_CORE) PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.newlib.ld) target_link_options(${ULP_APP_NAME} PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.version.ld) + target_link_options(${ULP_APP_NAME} + PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.api.ld) endif() target_sources(${ULP_APP_NAME} PRIVATE ${ULP_S_SOURCES}) diff --git a/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h b/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h index 6544ba72014..27a080581df 100644 --- a/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h +++ b/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h @@ -37,3 +37,10 @@ void lp_core_printf(const char* format, ...); extern void ets_install_uart_printf(void); #define lp_core_install_uart_print ets_install_uart_printf #endif /* CONFIG_ULP_ROM_PRINT_ENABLE */ + +/** + * @brief Print a single character from the LP core + * + * @param c character to be printed + */ +void lp_core_print_char(char c); diff --git a/components/ulp/lp_core/lp_core/lp_core_print.c b/components/ulp/lp_core/lp_core/lp_core_print.c index a14a91bcc64..0a704c28a32 100644 --- a/components/ulp/lp_core/lp_core/lp_core_print.c +++ b/components/ulp/lp_core/lp_core/lp_core_print.c @@ -6,25 +6,47 @@ #include #include "sdkconfig.h" #include "ulp_lp_core_uart.h" - -#if !CONFIG_ULP_ROM_PRINT_ENABLE +#include "hal/uart_hal.h" +#include "esp_rom_uart.h" #define LP_UART_PORT_NUM LP_UART_NUM_0 #define BINARY_SUPPORT 1 #define is_digit(c) ((c >= '0') && (c <= '9')) +#if CONFIG_ULP_HP_UART_CONSOLE_PRINT +void __attribute__((alias("hp_uart_send_char"))) lp_core_print_char(char c); + +static void hp_uart_send_char(char t) +{ + uart_dev_t *uart = (uart_dev_t *)UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM); + + while (uart_ll_get_txfifo_len(uart) < 2) { + ; + } + uart_ll_write_txfifo(uart, &t, 1); +} +#elif !CONFIG_ULP_ROM_PRINT_ENABLE +void __attribute__((alias("lp_uart_send_char"))) lp_core_print_char(char c); static void lp_uart_send_char(char c) { int tx_len = 0; int loop_cnt = 0; - /* Write one byte to LP UART. Break after few iterations if we are stuck for any reason. */ while (tx_len != 1 && loop_cnt < 1000) { tx_len = lp_core_uart_tx_chars(LP_UART_PORT_NUM, (const void *)&c, 1); loop_cnt++; } } +#else +void __attribute__((alias("lp_rom_send_char"))) lp_core_print_char(char c); +static void lp_rom_send_char(char c) +{ + esp_rom_output_putc(c); +} +#endif // CONFIG_ULP_HP_UART_CONSOLE_PRINT + +#if !CONFIG_ULP_ROM_PRINT_ENABLE // Ported over ROM function _cvt() static int lp_core_cvt(unsigned long long val, char *buf, long radix, char *digits) @@ -268,7 +290,7 @@ int lp_core_printf(const char* format, ...) va_start(ap, format); /* Pass the input string and the argument list to ets_vprintf() */ - int ret = lp_core_ets_vprintf(lp_uart_send_char, format, ap); + int ret = lp_core_ets_vprintf(lp_core_print_char, format, ap); va_end(ap); diff --git a/components/ulp/lp_core/lp_core/lp_core_startup.c b/components/ulp/lp_core/lp_core/lp_core_startup.c index 4d87b07fd1a..81cd5c91bc8 100644 --- a/components/ulp/lp_core/lp_core/lp_core_startup.c +++ b/components/ulp/lp_core/lp_core/lp_core_startup.c @@ -1,18 +1,27 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "sdkconfig.h" #include "soc/soc_caps.h" +#include "esp_rom_caps.h" +#include "rom/ets_sys.h" #include "ulp_lp_core_utils.h" #include "ulp_lp_core_lp_timer_shared.h" #include "ulp_lp_core_memory_shared.h" +#include "ulp_lp_core_print.h" extern void main(); /* Initialize lp core related system functions before calling user's main*/ void lp_core_startup() { + +#if CONFIG_ULP_HP_UART_CONSOLE_PRINT && ESP_ROM_HAS_LP_ROM + ets_install_putc1(lp_core_print_char); +#endif + ulp_lp_core_update_wakeup_cause(); main(); diff --git a/components/ulp/test_apps/lp_core/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_basic_tests/CMakeLists.txt similarity index 94% rename from components/ulp/test_apps/lp_core/CMakeLists.txt rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/CMakeLists.txt index 5a16c97e491..2881fcd2f42 100644 --- a/components/ulp/test_apps/lp_core/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/CMakeLists.txt @@ -11,4 +11,4 @@ set(EXTRA_COMPONENT_DIRS set(COMPONENTS main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(lp_core_test) +project(lp_core_basic_tests) diff --git a/components/ulp/test_apps/lp_core/README.md b/components/ulp/test_apps/lp_core/lp_core_basic_tests/README.md similarity index 100% rename from components/ulp/test_apps/lp_core/README.md rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/README.md diff --git a/components/ulp/test_apps/lp_core/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt similarity index 100% rename from components/ulp/test_apps/lp_core/main/CMakeLists.txt rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_counter.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_counter.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_counter.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_counter.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_gpio.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_gpio.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_gpio.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_i2c.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_i2c.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_i2c.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_i2c.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_isr.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_isr.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_isr.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_set_timer_wakeup.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_set_timer_wakeup.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_set_timer_wakeup.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_set_timer_wakeup.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_spi_master.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_master.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_spi_master.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_spi_slave.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_main_spi_slave.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_spi_slave.c diff --git a/components/ulp/test_apps/lp_core/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h similarity index 100% rename from components/ulp/test_apps/lp_core/main/lp_core/test_shared.h rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h diff --git a/components/ulp/test_apps/lp_core/main/test_app_main.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_app_main.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/test_app_main.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_app_main.c diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/test_lp_core.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core_etm.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_etm.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/test_lp_core_etm.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_etm.c diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core_i2c.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_i2c.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/test_lp_core_i2c.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_i2c.c diff --git a/components/ulp/test_apps/lp_core/main/test_lp_core_spi.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_spi.c similarity index 100% rename from components/ulp/test_apps/lp_core/main/test_lp_core_spi.c rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core_spi.c diff --git a/components/ulp/test_apps/lp_core/pytest_lp_core.py b/components/ulp/test_apps/lp_core/lp_core_basic_tests/pytest_lp_core_basic.py similarity index 91% rename from components/ulp/test_apps/lp_core/pytest_lp_core.py rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/pytest_lp_core_basic.py index 24fdcd3bdfe..dc2233f8134 100644 --- a/components/ulp/test_apps/lp_core/pytest_lp_core.py +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/pytest_lp_core_basic.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import pytest from pytest_embedded import Dut diff --git a/components/ulp/test_apps/lp_core/sdkconfig.ci.default b/components/ulp/test_apps/lp_core/lp_core_basic_tests/sdkconfig.ci.default similarity index 100% rename from components/ulp/test_apps/lp_core/sdkconfig.ci.default rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/sdkconfig.ci.default diff --git a/components/ulp/test_apps/lp_core/sdkconfig.defaults b/components/ulp/test_apps/lp_core/lp_core_basic_tests/sdkconfig.defaults similarity index 100% rename from components/ulp/test_apps/lp_core/sdkconfig.defaults rename to components/ulp/test_apps/lp_core/lp_core_basic_tests/sdkconfig.defaults diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_hp_uart/CMakeLists.txt new file mode 100644 index 00000000000..2c8bfb98612 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/CMakeLists.txt @@ -0,0 +1,14 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +list(PREPEND SDKCONFIG_DEFAULTS "$ENV{IDF_PATH}/tools/test_apps/configs/sdkconfig.debug_helpers" "sdkconfig.defaults") + +set(EXTRA_COMPONENT_DIRS + "$ENV{IDF_PATH}/tools/unit-test-app/components" +) + +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lp_core_hp_uart_test) diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/README.md b/components/ulp/test_apps/lp_core/lp_core_hp_uart/README.md new file mode 100644 index 00000000000..b3864443558 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/README.md @@ -0,0 +1,3 @@ +| Supported Targets | ESP32-C6 | ESP32-P4 | +| ----------------- | -------- | -------- | + diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt new file mode 100644 index 00000000000..6fce89dfdde --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt @@ -0,0 +1,11 @@ +set(app_sources "test_app_main.c" "test_lp_core.c") +set(lp_core_sources "lp_core/test_hello_main.c") + +idf_component_register(SRCS ${app_sources} + INCLUDE_DIRS "lp_core" + REQUIRES ulp unity esp_timer test_utils + WHOLE_ARCHIVE) + +set(lp_core_exp_dep_srcs ${app_sources}) + +ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}") diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_hello_main.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_hello_main.c new file mode 100644 index 00000000000..3c844cec7df --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_hello_main.c @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "ulp_lp_core_print.h" + +int main(void) +{ + lp_core_printf("Hello, World!\n"); + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_app_main.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_app_main.c new file mode 100644 index 00000000000..d8a9a98ccc0 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_app_main.c @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in the sleep code, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-500) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + unity_run_menu(); +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c new file mode 100644 index 00000000000..0d3949cd59a --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "sdkconfig.h" +#include "unity.h" +#include "soc/soc_caps.h" +#include "esp_rom_caps.h" +#include "lp_core_test_app.h" +#include "ulp_lp_core.h" + +extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start"); +extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end"); + +static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) +{ + TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, + (firmware_end - firmware_start)) == ESP_OK); + + TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK); + +} + +TEST_CASE("lp-print can output to hp-uart", "[lp_core]") +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_bin_start, lp_core_main_bin_end); + + // Actual test output on UART is checked by pytest, not unity test-case + // We simply wait to allow the lp-core to run once + vTaskDelay(1000 / portTICK_PERIOD_MS); +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py new file mode 100644 index 00000000000..e7a4f5b2a43 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32c6 +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_lp_core_hp_uart_print(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"lp-print can output to hp-uart"') + dut.expect_exact('Hello, World!') diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.ci.default b/components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.ci.default new file mode 100644 index 00000000000..e69de29bb2d diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.defaults b/components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.defaults new file mode 100644 index 00000000000..e3c08c60fa9 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_ESP_TASK_WDT_INIT=n + +CONFIG_ULP_COPROC_ENABLED=y +CONFIG_ULP_COPROC_TYPE_LP_CORE=y +CONFIG_ULP_COPROC_RESERVE_MEM=12000 +CONFIG_ULP_PANIC_OUTPUT_ENABLE=y +CONFIG_ULP_HP_UART_CONSOLE_PRINT=y diff --git a/docs/en/api-reference/system/ulp-lp-core.rst b/docs/en/api-reference/system/ulp-lp-core.rst index 430fe5fa787..dd3cb7cd0c7 100644 --- a/docs/en/api-reference/system/ulp-lp-core.rst +++ b/docs/en/api-reference/system/ulp-lp-core.rst @@ -7,7 +7,7 @@ The ULP LP-Core (Low-power core) coprocessor is a variant of the ULP present in The ULP LP-Core coprocessor has the following features: -* Utilizes a 32-bit processor based on the RISC-V ISA, encompassing the standard extensions integer (I), multiplication/division (M), atomic (A), and compressed (C). +* A RV32I (32-bit RISC-V ISA) processor, with the multiplication/division (M), atomic (A), and compressed (C) extensions. * Interrupt controller. * Includes a debug module that supports external debugging via JTAG. * Can access all of the High-power (HP) SRAM and peripherals when the entire system is active. @@ -22,6 +22,8 @@ The ULP LP-Core code is compiled together with your ESP-IDF project as a separat 2. After registering the component in the CMakeLists.txt file, call the ``ulp_embed_binary`` function. Here is an example: +.. code-block:: cmake + idf_component_register() set(ulp_app_name ulp_${COMPONENT_NAME}) @@ -32,7 +34,7 @@ The ULP LP-Core code is compiled together with your ESP-IDF project as a separat The first argument to ``ulp_embed_binary`` specifies the ULP binary name. The name specified here is also used by other generated artifacts such as the ELF file, map file, header file, and linker export file. The second argument specifies the ULP source files. Finally, the third argument specifies the list of component source files which include the header file to be generated. This list is needed to build the dependencies correctly and ensure that the generated header file is created before any of these files are compiled. See the section below for the concept of generated header files for ULP applications. -1. Enable both :ref:`CONFIG_ULP_COPROC_ENABLED` and :ref:`CONFIG_ULP_COPROC_TYPE` in menucofig, and set :ref:`CONFIG_ULP_COPROC_TYPE` to ``CONFIG_ULP_COPROC_TYPE_LP_CORE``. The :ref:`CONFIG_ULP_COPROC_RESERVE_MEM` option reserves RTC memory for the ULP, and must be set to a value big enough to store both the ULP LP-Core code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one. +1. Enable both :ref:`CONFIG_ULP_COPROC_ENABLED` and :ref:`CONFIG_ULP_COPROC_TYPE` in menuconfig, and set :ref:`CONFIG_ULP_COPROC_TYPE` to ``CONFIG_ULP_COPROC_TYPE_LP_CORE``. The :ref:`CONFIG_ULP_COPROC_RESERVE_MEM` option reserves RTC memory for the ULP, and must be set to a value big enough to store both the ULP LP-Core code and data. If the application components contain multiple ULP programs, then the size of the RTC memory must be sufficient to hold the largest one. 2. Build the application as usual (e.g., ``idf.py app``). @@ -59,7 +61,7 @@ Accessing the ULP LP-Core Program Variables Global symbols defined in the ULP LP-Core program may be used inside the main program. -For example, the ULP LP-Core program may define a variable ``measurement_count`` which defines the number of GPIO measurements the program needs to make before waking up the chip from deep sleep. +For example, the ULP LP-Core program may define a variable ``measurement_count`` which defines the number of GPIO measurements the program needs to make before waking up the chip from Deep-sleep. .. code-block:: c @@ -83,7 +85,9 @@ The header file contains the declaration of the symbol: Note that all symbols (variables, arrays, functions) are declared as ``uint32_t``. For functions and arrays, take the address of the symbol and cast it to the appropriate type. -The generated linker script file defines the locations of symbols in LP_MEM:: +The generated linker script file defines the locations of symbols in LP_MEM: + +.. code-block:: none PROVIDE ( ulp_measurement_count = 0x50000060 ); @@ -97,6 +101,10 @@ To access the ULP LP-Core program variables from the main program, the generated ulp_measurement_count = 64; } +.. note:: + + Variables declared in the global scope of the LP-Core program reside in either the ``.bss`` or ``.data`` section of the binary. These sections are initialized when the LP-Core binary is loaded and executed. Accessing these variables from the main program on the HP-Core before the first LP-Core run may result in undefined behavior. + Starting the ULP LP-Core Program -------------------------------- @@ -129,7 +137,7 @@ Once the program is loaded into LP memory, the application can be configured and ULP LP-Core Program Flow ------------------------ -How the ULP LP-Core coprocessor is started depends on the wakeup source selected in :cpp:type:`ulp_lp_core_cfg_t`. The most common use-case is for the ULP to periodically wake-up, do some measurements before either waking up the main CPU or going back to sleep again. +How the ULP LP-Core coprocessor is started depends on the wake-up source selected in :cpp:type:`ulp_lp_core_cfg_t`. The most common use-case is for the ULP to periodically wake up, do some measurements before either waking up the main CPU or going back to sleep again. The ULP has the following wake-up sources: * :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU` - LP Core can be woken up by the HP CPU. @@ -153,7 +161,7 @@ When the ULP is woken up, it will go through the following steps: ULP LP-Core Peripheral Support ------------------------------ -To enhance the capabilities of the ULP LP-Core coprocessor, it has access to peripherals which operate in the low-power domain. The ULP LP-Core coprocessor can interact with these peripherals when the main CPU is in sleep mode, and can wake up the main CPU once a wakeup condition is reached. The following peripherals are supported: +To enhance the capabilities of the ULP LP-Core coprocessor, it has access to peripherals that operate in the low-power domain. The ULP LP-Core coprocessor can interact with these peripherals when the main CPU is in sleep mode, and can wake up the main CPU once a wake-up condition is reached. The following peripherals are supported: .. list:: @@ -167,7 +175,7 @@ To enhance the capabilities of the ULP LP-Core coprocessor, it has access to per ULP LP-Core ROM --------------- - The ULP LP-Core ROM is a small pre-built piece of code located in LP-ROM, which is not modifiable by users. Similar to the bootloader ROM code ran by the main CPU, this code is executed when the ULP LP-Core coprocessor is started. The ROM code initializes the ULP LP-Core coprocessor and then jumps to the user program. The ROM code also prints boot messages if the LP UART has been initialized. + The ULP LP-Core ROM is a small pre-built piece of code located in LP-ROM, which can't be modified. Similar to the bootloader ROM code ran by the main CPU, this code is executed when the ULP LP-Core coprocessor is started. The ROM code initializes the ULP LP-Core coprocessor and then jumps to the user program. The ROM code also prints boot messages if the LP UART has been initialized. The ROM code is not executed if :cpp:member:`ulp_lp_core_cfg_t::skip_lp_rom_boot` is set to true. This is useful when you need the ULP to wake-up as quickly as possible and the extra overhead of initializing and printing is unwanted. @@ -182,7 +190,7 @@ To enhance the capabilities of the ULP LP-Core coprocessor, it has access to per ULP LP-Core Interrupts ---------------------- -The LP-Core coprocessor can be configured to handle interrupts from various sources. Examples of such interrupts could be LP IO low/high or LP timer interrupts. To register a handler for an interrupt simply override any of the weak handlers provided by IDF. A complete list of handlers can be found in :component_file:`ulp_lp_core_interrupts.h `. For details on which interrupts are available on a specific target, please consult the Low Power CPU chapter in the Technical Reference Manual.` +The LP-Core coprocessor can be configured to handle interrupts from various sources. Examples of such interrupts could be LP IO low/high or LP timer interrupts. To register a handler for an interrupt, simply override any of the weak handlers provided by IDF. A complete list of handlers can be found in :component_file:`ulp_lp_core_interrupts.h `. For details on which interrupts are available on a specific target, please consult **{IDF_TARGET_NAME} Technical Reference Manual** [`PDF <{IDF_TARGET_TRM_EN_URL}#ulp>`__]. For example, to override the handler for the LP IO interrupt, you can define the following function in your ULP LP-Core code: @@ -202,26 +210,28 @@ Debugging ULP LP-Core Applications When programming the LP-Core, it can sometimes be challenging to figure out why the program is not behaving as expected. Here are some strategies to help you debug your LP-Core program: - * Use the LP-UART to print: the LP-Core has access to the LP-UART peripheral, which can be used for printing information independently of the main CPU sleep state. See :example:`system/ulp/lp_core/lp_uart/lp_uart_print` for an example of how to use this driver. +* Use the LP-UART to print: the LP-Core has access to the LP-UART peripheral, which can be used for printing information independently of the main CPU sleep state. See :example:`system/ulp/lp_core/lp_uart/lp_uart_print` for an example of how to use this driver. + +* Routing :cpp:func:`lp_core_printf` to the HP-Core console UART with :ref:`CONFIG_ULP_HP_UART_CONSOLE_PRINT`. This allows you to easily print LP-Core information to the already connected HP-Core console UART. The drawback of this approach is that it requires the main CPU to be awake and since there is no synchronization between the LP and HP cores, the output may be interleaved. - * Share program state through shared variables: as described in :ref:`ulp-lp-core-access-variables`, both the main CPU and the ULP core can easily access global variables in RTC memory. Writing state information to such a variable from the ULP and reading it from the main CPU can help you discern what is happening on the ULP core. The downside of this approach is that it requires the main CPU to be awake, which will not always be the case. Keeping the main CPU awake might even, in some cases, mask problems, as some issues may only occur when certain power domains are powered down. +* Share program state through shared variables: as described in :ref:`ulp-lp-core-access-variables`, both the main CPU and the ULP core can easily access global variables in RTC memory. Writing state information to such a variable from the ULP and reading it from the main CPU can help you discern what is happening on the ULP core. The downside of this approach is that it requires the main CPU to be awake, which will not always be the case. Keeping the main CPU awake might even, in some cases, mask problems, as some issues may only occur when certain power domains are powered down. - * Panic handler: the LP-Core has a panic handler that can dump the state of the LP-Core registers to the LP-UART when an exception is detected. To enable the panic handler, set the :ref:`CONFIG_ULP_PANIC_OUTPUT_ENABLE` option to ``y``. This option can be kept disabled to reduce LP-RAM usage by the LP-Core application. To recover a backtrace from the panic dump it is possible to use esp-idf-monitor_., e.g.: +* Panic handler: the LP-Core has a panic handler that can dump the state of the LP-Core registers by the LP-UART when an exception is detected. To enable the panic handler, set the :ref:`CONFIG_ULP_PANIC_OUTPUT_ENABLE` option to ``y``. This option can be kept disabled to reduce LP-RAM usage by the LP-Core application. To recover a backtrace from the panic dump, it is possible to use esp-idf-monitor_., e.g.: -.. code-block:: bash + .. code-block:: bash - python -m esp_idf_monitor --toolchain-prefix riscv32-esp-elf- --target {IDF_TARGET_NAME} --decode-panic backtrace PATH_TO_ULP_ELF_FILE + python -m esp_idf_monitor --toolchain-prefix riscv32-esp-elf- --target {IDF_TARGET_NAME} --decode-panic backtrace PATH_TO_ULP_ELF_FILE Application Examples -------------------- -* :example:`system/ulp/lp_core/gpio` polls GPIO while main CPU is in deep sleep. +* :example:`system/ulp/lp_core/gpio` polls GPIO while main CPU is in Deep-sleep. * :example:`system/ulp/lp_core/lp_i2c` reads external I2C ambient light sensor (BH1750) while the main CPU is in Deep-sleep and wakes up the main CPU once a threshold is met. * :example:`system/ulp/lp_core/lp_uart/lp_uart_echo` reads data written to a serial console and echoes it back. This example demonstrates the usage of the LP UART driver running on the LP core. * :example:`system/ulp/lp_core/lp_uart/lp_uart_print` shows how to print various statements from a program running on the LP core. * :example:`system/ulp/lp_core/interrupt` shows how to register an interrupt handler on the LP core to receive an interrupt triggered by the main CPU. -* :example:`system/ulp/lp_core/gpio_intr_pulse_counter` shows how to use GPIO interrupts to count pulses while the main CPU is in deep sleep. +* :example:`system/ulp/lp_core/gpio_intr_pulse_counter` shows how to use GPIO interrupts to count pulses while the main CPU is in Deep-sleep mode. API Reference ------------- From f7ac13a56615427d9c6c1eee8a7dfaa8b893203a Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 31 Jul 2024 19:11:55 +0800 Subject: [PATCH 522/548] change(dsi): don't send eot packet in lp mode because some LCD doesn't respond to that --- components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c index 8583a27682f..7fa3e1dc943 100644 --- a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c +++ b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c @@ -105,8 +105,8 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc // enable CRC reception and ECC reception, error correction, and reporting mipi_dsi_host_ll_enable_rx_crc(hal->host, true); mipi_dsi_host_ll_enable_rx_ecc(hal->host, true); - // enable sending the EoTp packet at the end of each transmission - mipi_dsi_host_ll_enable_tx_eotp(hal->host, true, true); + // enable sending the EoTp packet at the end of each transmission for HS mode + mipi_dsi_host_ll_enable_tx_eotp(hal->host, true, false); // Set the divider to get the Time Out clock, clock source is the high-speed byte clock mipi_dsi_host_ll_set_timeout_clock_division(hal->host, bus_config->lane_bit_rate_mbps / 8 / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ); From 948c178a96e5959c612220e8698c679a7e7a1c7a Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Thu, 1 Aug 2024 17:50:18 +0530 Subject: [PATCH 523/548] fix(wifi_prov): Use calloc instead of malloc to zero initialize variable --- components/protocomm/src/simple_ble/simple_ble.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c index 709024d3025..ac33cf2409f 100644 --- a/components/protocomm/src/simple_ble/simple_ble.c +++ b/components/protocomm/src/simple_ble/simple_ble.c @@ -199,7 +199,7 @@ static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_ simple_ble_cfg_t *simple_ble_init(void) { - simple_ble_cfg_t *ble_cfg_p = (simple_ble_cfg_t *) malloc(sizeof(simple_ble_cfg_t)); + simple_ble_cfg_t *ble_cfg_p = (simple_ble_cfg_t *) calloc(1, sizeof(simple_ble_cfg_t)); if (ble_cfg_p == NULL) { ESP_LOGE(TAG, "No memory for simple_ble_cfg_t"); return NULL; From de1050b8105defdadc66538ed8255d22c22c07c4 Mon Sep 17 00:00:00 2001 From: Nachiket Kukade Date: Fri, 2 Aug 2024 10:41:49 +0530 Subject: [PATCH 524/548] fix(wifi): Avoid internal retries for offchannel FTM Requests --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 7ab37c97e29..d1df171e4c9 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 7ab37c97e2938016495c89a16ab442d4034cf3e9 +Subproject commit d1df171e4c9756dac17aa586201c7f94b99dc8aa From cab1a2ab4af4207e53c49c9f8d32e94a0b0d1eed Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 19 Jul 2024 13:49:38 +0800 Subject: [PATCH 525/548] fix(lp-core): fixed ULP shared mem address being wrong on P4 --- components/ulp/ld/lp_core_riscv.ld | 15 +++++++- .../shared/ulp_lp_core_memory_shared.c | 26 +++++++++++--- .../lp_core_hp_uart/main/CMakeLists.txt | 4 ++- .../main/lp_core/test_shared.h | 9 +++++ .../main/lp_core/test_shared_mem_main.c | 34 ++++++++++++++++++ .../lp_core_hp_uart/main/test_lp_core.c | 35 +++++++++++++++++++ .../lp_core_hp_uart/pytest_lp_core_hp_uart.py | 19 ++++++++++ 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h create mode 100644 components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c diff --git a/components/ulp/ld/lp_core_riscv.ld b/components/ulp/ld/lp_core_riscv.ld index 4ecab5b34a1..0f2da81c3ec 100644 --- a/components/ulp/ld/lp_core_riscv.ld +++ b/components/ulp/ld/lp_core_riscv.ld @@ -14,13 +14,20 @@ #define ULP_MEM_START_ADDRESS (SOC_RTC_DRAM_LOW) #endif +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) +/* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_memory_shared.c + */ +#define ALIGNED_COPROC_MEM ALIGN_DOWN(CONFIG_ULP_COPROC_RESERVE_MEM, 0x8) + ENTRY(reset_vector) MEMORY { /*first 128byte for exception/interrupt vectors*/ vector_table(RX) : ORIGIN = ULP_MEM_START_ADDRESS , LENGTH = 0x80 - ram(RWX) : ORIGIN = ULP_MEM_START_ADDRESS + 0x80, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80 - CONFIG_ULP_SHARED_MEM + ram(RWX) : ORIGIN = ULP_MEM_START_ADDRESS + 0x80, LENGTH = ALIGNED_COPROC_MEM - 0x80 - CONFIG_ULP_SHARED_MEM + shared_mem_ram(RW) : ORIGIN = ULP_MEM_START_ADDRESS + ALIGNED_COPROC_MEM - CONFIG_ULP_SHARED_MEM, LENGTH = CONFIG_ULP_SHARED_MEM } SECTIONS @@ -65,4 +72,10 @@ SECTIONS } >ram __stack_top = ORIGIN(ram) + LENGTH(ram); + + . = ORIGIN(shared_mem_ram); + .shared_mem (ALIGN(4)) : + { + KEEP(*(.shared_mem)) + } > shared_mem_ram } diff --git a/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c b/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c index e36c4b56dd1..c3779b50208 100644 --- a/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c +++ b/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,21 +7,37 @@ #include "sdkconfig.h" #include "soc/soc.h" +#include "esp_rom_caps.h" #include "esp_assert.h" +#define ALIGN_DOWN(SIZE, AL) (SIZE & ~(AL - 1)) + /* The last CONFIG_ULP_SHARED_MEM bytes of the reserved memory are reserved for a shared cfg struct The main cpu app and the ulp binary can share variables automatically through the linkerscript generated from esp32ulp_mapgen.py, but this is not available when compiling the ULP library. For those special cases, e.g. config settings. We can use this shared area. */ -#define LP_CORE_SHARED_MEM_ADDR (SOC_RTC_DRAM_LOW + CONFIG_ULP_COPROC_RESERVE_MEM - CONFIG_ULP_SHARED_MEM) - -static ulp_lp_core_memory_shared_cfg_t *const s_shared_mem = (ulp_lp_core_memory_shared_cfg_t *)LP_CORE_SHARED_MEM_ADDR; +#if IS_ULP_COCPU +static ulp_lp_core_memory_shared_cfg_t __attribute__((section(".shared_mem"))) s_shared_mem = {}; ESP_STATIC_ASSERT(CONFIG_ULP_SHARED_MEM == sizeof(ulp_lp_core_memory_shared_cfg_t)); +#endif ulp_lp_core_memory_shared_cfg_t* ulp_lp_core_memory_shared_cfg_get(void) { - return s_shared_mem; +#if IS_ULP_COCPU + return &s_shared_mem; +#else +#if ESP_ROM_HAS_LP_ROM + extern uint32_t _rtc_ulp_memory_start; + uint32_t ulp_base_addr = (uint32_t)&_rtc_ulp_memory_start; +#else + uint32_t ulp_base_addr = SOC_RTC_DRAM_LOW; +#endif + /* Ensure the end where the shared memory starts is aligned to 8 bytes + if updating this also update the same in ulp_lp_core_riscv.ld + */ + return (ulp_lp_core_memory_shared_cfg_t *)(ulp_base_addr + ALIGN_DOWN(CONFIG_ULP_COPROC_RESERVE_MEM, 0x8) - CONFIG_ULP_SHARED_MEM); +#endif } diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt index 6fce89dfdde..d70b7ede3a1 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/CMakeLists.txt @@ -1,5 +1,6 @@ set(app_sources "test_app_main.c" "test_lp_core.c") -set(lp_core_sources "lp_core/test_hello_main.c") +set(lp_core_sources "lp_core/test_hello_main.c") +set(lp_core_sources_shared_mem "lp_core/test_shared_mem_main.c") idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "lp_core" @@ -9,3 +10,4 @@ idf_component_register(SRCS ${app_sources} set(lp_core_exp_dep_srcs ${app_sources}) ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}") +ulp_embed_binary(lp_core_test_app_shared_mem "${lp_core_sources_shared_mem}" "${lp_core_exp_dep_srcs}") diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h new file mode 100644 index 00000000000..17571e195c2 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared.h @@ -0,0 +1,9 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#pragma once + +#define SHARED_MEM_INIT_VALUE 0xEE +#define SHARED_MEM_END_VALUE 0xAA diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c new file mode 100644 index 00000000000..c37c83962c3 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/lp_core/test_shared_mem_main.c @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "ulp_lp_core_print.h" +#include "ulp_lp_core_memory_shared.h" +#include "test_shared.h" + +int main(void) +{ + ulp_lp_core_memory_shared_cfg_t *shared_cfg = ulp_lp_core_memory_shared_cfg_get(); + lp_core_printf("ULP shared memory address: %p\n", shared_cfg); + + volatile uint8_t* shared_mem = (uint8_t*)shared_cfg; + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + if (shared_mem[i] != SHARED_MEM_INIT_VALUE) { + lp_core_printf("Test failed: expected %X, got %X at %d\n", SHARED_MEM_INIT_VALUE, shared_mem[i], i); + return 0; + } + } + + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + shared_mem[i] = SHARED_MEM_END_VALUE; + } + + lp_core_printf("ULP shared memory test passed\n"); + + return 0; +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c index 0d3949cd59a..04644bc78df 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/main/test_lp_core.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "sdkconfig.h" @@ -15,10 +16,15 @@ #include "esp_rom_caps.h" #include "lp_core_test_app.h" #include "ulp_lp_core.h" +#include "ulp_lp_core_memory_shared.h" +#include "test_shared.h" extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start"); extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end"); +extern const uint8_t lp_core_shared_mem_bin_start[] asm("_binary_lp_core_test_app_shared_mem_bin_start"); +extern const uint8_t lp_core_shared_mem_bin_end[] asm("_binary_lp_core_test_app_shared_mem_bin_end"); + static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) { TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, @@ -41,3 +47,32 @@ TEST_CASE("lp-print can output to hp-uart", "[lp_core]") // We simply wait to allow the lp-core to run once vTaskDelay(1000 / portTICK_PERIOD_MS); } + +TEST_CASE("LP-Core Shared-mem", "[lp_core]") +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU, + }; + + TEST_ASSERT(ulp_lp_core_load_binary(lp_core_shared_mem_bin_start, (lp_core_shared_mem_bin_end - lp_core_shared_mem_bin_start)) == ESP_OK); + + printf("HP shared memory address: %p\n", ulp_lp_core_memory_shared_cfg_get()); + + volatile uint8_t* shared_mem = (uint8_t*)ulp_lp_core_memory_shared_cfg_get(); + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + shared_mem[i] = SHARED_MEM_INIT_VALUE; + } + + TEST_ASSERT(ulp_lp_core_run(&cfg) == ESP_OK); + // Actual test output on UART is checked by pytest, not unity test-case + // We simply wait to allow the lp-core to run once + vTaskDelay(1000 / portTICK_PERIOD_MS); + + // Check that ULP set the shared memory to 0xAA, and it did not get overwritten by anything + for (int i = 0; i < sizeof(ulp_lp_core_memory_shared_cfg_t); i++) { + TEST_ASSERT_EQUAL(SHARED_MEM_END_VALUE, shared_mem[i]); + } + + printf("HP shared memory test passed\n"); +} diff --git a/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py index e7a4f5b2a43..28fbb57f694 100644 --- a/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py +++ b/components/ulp/test_apps/lp_core/lp_core_hp_uart/pytest_lp_core_hp_uart.py @@ -11,3 +11,22 @@ def test_lp_core_hp_uart_print(dut: Dut) -> None: dut.expect_exact('Press ENTER to see the list of tests') dut.write('"lp-print can output to hp-uart"') dut.expect_exact('Hello, World!') + + +@pytest.mark.esp32c6 +@pytest.mark.esp32p4 +@pytest.mark.generic +def test_lp_core_shared_mem(dut: Dut) -> None: + dut.expect_exact('Press ENTER to see the list of tests') + dut.write('"LP-Core Shared-mem"') + + result = dut.expect(r'HP shared memory address: (0x[0-9a-fA-F]+)') + hp_addr = result[1] + + result = dut.expect(r'ULP shared memory address: (0x[0-9a-fA-F]+)') + ulp_addr = result[1] + + assert ulp_addr == hp_addr + + dut.expect_exact('ULP shared memory test passed') + dut.expect_exact('HP shared memory test passed') From 4c90790cd261684ebfadfaeb926a2540f8aa4d29 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Wed, 31 Jul 2024 16:15:11 +0200 Subject: [PATCH 526/548] fix: ensure the constraint file is followed also for setuptools Currently, when the venv is installed or updated, we attempt to automatically update pip and setuptools within the venv. Unfortunately, the setuptools package is installed or updated without adhering to the constraints file, which restricts the setuptools version due to https://github.com/pypa/setuptools/issues/4480. Resolve this issue by applying the constraints file to the installation and update of both pip and setuptools. Signed-off-by: Frantisek Hrbata --- tools/idf_tools.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tools/idf_tools.py b/tools/idf_tools.py index 1b9dc6d7d64..50afe3a7f37 100755 --- a/tools/idf_tools.py +++ b/tools/idf_tools.py @@ -2599,18 +2599,12 @@ def action_install_python_env(args): # type: ignore warn(f'Removing the existing Python environment in {idf_python_env_path}') shutil.rmtree(idf_python_env_path) - venv_can_upgrade = False - if os.path.exists(virtualenv_python): check_python_venv_compatibility(idf_python_env_path, idf_version) else: if subprocess.run([sys.executable, '-m', 'venv', '-h'], check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0: # venv available virtualenv_options = ['--clear'] # delete environment if already exists - if sys.version_info[:2] >= (3, 9): - # upgrade pip & setuptools - virtualenv_options += ['--upgrade-deps'] - venv_can_upgrade = True info(f'Creating a new Python environment in {idf_python_env_path}') @@ -2651,17 +2645,19 @@ def action_install_python_env(args): # type: ignore warn('Found PIP_USER="yes" in the environment. Disabling PIP_USER in this shell to install packages into a virtual environment.') env_copy['PIP_USER'] = 'no' - if not venv_can_upgrade: - info('Upgrading pip and setuptools...') - subprocess.check_call([virtualenv_python, '-m', 'pip', 'install', '--upgrade', 'pip', 'setuptools'], - stdout=sys.stdout, stderr=sys.stderr, env=env_copy) + constraint_file = get_constraints(idf_version) if use_constraints else None + + info('Upgrading pip and setuptools...') + run_args = [virtualenv_python, '-m', 'pip', 'install', '--upgrade', 'pip', 'setuptools'] + if constraint_file: + run_args += ['--constraint', constraint_file] + subprocess.check_call(run_args, stdout=sys.stdout, stderr=sys.stderr, env=env_copy) run_args = [virtualenv_python, '-m', 'pip', 'install', '--no-warn-script-location'] requirements_file_list = get_requirements(args.features) for requirement_file in requirements_file_list: run_args += ['-r', requirement_file] - if use_constraints: - constraint_file = get_constraints(idf_version) + if constraint_file: run_args += ['--upgrade', '--constraint', constraint_file] if args.extra_wheels_dir: run_args += ['--find-links', args.extra_wheels_dir] @@ -2675,7 +2671,7 @@ def action_install_python_env(args): # type: ignore run_args += ['--find-links', wheels_dir] info('Installing Python packages') - if use_constraints: + if constraint_file: info(f' Constraint file: {constraint_file}') info(' Requirement files:') info(os.linesep.join(f' - {path}' for path in requirements_file_list)) From 01f0fd4158d07709a5f616261eb76c11744568c3 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 31 Jul 2024 17:28:07 +0530 Subject: [PATCH 527/548] fix(nimble): Modify Advertising Tx power levels --- components/bt/host/nimble/nimble | 2 +- components/bt/host/nimble/port/include/esp_nimble_cfg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 3126e6c5613..2cf7edde638 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 3126e6c561369589677191a9aa22def441873f69 +Subproject commit 2cf7edde63866f5663bbcdfb8776cf29c0809456 diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index fc77f592f98..9370be89b81 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -234,7 +234,7 @@ #endif #ifndef MYNEWT_VAL_BLE_VERSION -#define MYNEWT_VAL_BLE_VERSION (50) +#define MYNEWT_VAL_BLE_VERSION (54) #endif #ifndef MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS From f81cece9d420aa6c32c2ee7b71dcb0fa6a82e34b Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Thu, 30 May 2024 18:54:35 +0800 Subject: [PATCH 528/548] fix(startup): move rtc initialization before MSPI timing tuning to improve stability --- .../include/esp_private/rtc_clk.h | 6 ---- .../esp_hw_support/port/esp32c2/rtc_clk.c | 18 ----------- .../esp_hw_support/port/esp32c6/rtc_clk.c | 19 ----------- .../esp_hw_support/port/esp32c61/rtc_clk.c | 19 ----------- .../esp_hw_support/port/esp32h2/rtc_clk.c | 20 +----------- .../esp_hw_support/port/esp32s3/rtc_clk.c | 21 +----------- components/esp_system/fpga_overrides_clk.c | 8 +++-- components/esp_system/port/cpu_start.c | 13 ++++---- .../port/include/esp_clk_internal.h | 9 ++++++ components/esp_system/port/soc/esp32/clk.c | 5 ++- components/esp_system/port/soc/esp32c2/clk.c | 32 ++++++++++++++++++- components/esp_system/port/soc/esp32c3/clk.c | 5 ++- components/esp_system/port/soc/esp32c5/clk.c | 20 ++++-------- components/esp_system/port/soc/esp32c6/clk.c | 32 ++++++++++++++++++- components/esp_system/port/soc/esp32c61/clk.c | 7 +++- components/esp_system/port/soc/esp32h2/clk.c | 32 ++++++++++++++++++- components/esp_system/port/soc/esp32p4/clk.c | 5 ++- components/esp_system/port/soc/esp32s2/clk.c | 5 ++- components/esp_system/port/soc/esp32s3/clk.c | 30 ++++++++++++++++- 19 files changed, 174 insertions(+), 132 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/rtc_clk.h b/components/esp_hw_support/include/esp_private/rtc_clk.h index 5c143b83967..52610fa0d1c 100644 --- a/components/esp_hw_support/include/esp_private/rtc_clk.h +++ b/components/esp_hw_support/include/esp_private/rtc_clk.h @@ -74,12 +74,6 @@ uint32_t rtc_clk_mpll_get_freq(void); #endif //#if SOC_CLK_MPLL_SUPPORTED -/** - * @brief Workaround for C2, S3, C6, H2. Trigger the calibration of PLL. Should be called when the bootloader doesn't provide a good enough PLL accuracy. -*/ -void rtc_clk_recalib_bbpll(void); - - #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/port/esp32c2/rtc_clk.c b/components/esp_hw_support/port/esp32c2/rtc_clk.c index 20ef6d1d562..425b72b17f5 100644 --- a/components/esp_hw_support/port/esp32c2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c2/rtc_clk.c @@ -356,24 +356,6 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } -// Workaround for bootloader not calibrated well issue. -// Placed in IRAM because disabling BBPLL may influence the cache -void rtc_clk_recalib_bbpll(void) -{ - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - - // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. - // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. - // Turn off the BBPLL and do calibration again to fix the issue. - // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's - // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. - if (old_config.source == SOC_CPU_CLK_SRC_PLL) { - rtc_clk_cpu_freq_set_xtal(); - rtc_clk_cpu_freq_set_config(&old_config); - } -} - /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32c6/rtc_clk.c b/components/esp_hw_support/port/esp32c6/rtc_clk.c index 015a002562c..228a713ad9e 100644 --- a/components/esp_hw_support/port/esp32c6/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c6/rtc_clk.c @@ -423,25 +423,6 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } -// Workaround for bootloader not calibrated well issue. -// Placed in IRAM because disabling BBPLL may influence the cache -void rtc_clk_recalib_bbpll(void) -{ - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - - // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. - // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. - // Turn off the BBPLL and do calibration again to fix the issue. - // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's - // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. - if (old_config.source == SOC_CPU_CLK_SRC_PLL) { - rtc_clk_cpu_freq_set_xtal(); - rtc_clk_cpu_freq_set_config(&old_config); - } -} - - /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32c61/rtc_clk.c b/components/esp_hw_support/port/esp32c61/rtc_clk.c index 4644e1df393..3a20ede1b94 100644 --- a/components/esp_hw_support/port/esp32c61/rtc_clk.c +++ b/components/esp_hw_support/port/esp32c61/rtc_clk.c @@ -427,25 +427,6 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } -// Workaround for bootloader not calibrated well issue. -// Placed in IRAM because disabling BBPLL may influence the cache -void rtc_clk_recalib_bbpll(void) -{ - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - - // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. - // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. - // Turn off the BBPLL and do calibration again to fix the issue. - // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's - // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. - if (old_config.source == SOC_CPU_CLK_SRC_PLL) { - rtc_clk_cpu_freq_set_xtal(); - rtc_clk_cpu_freq_set_config(&old_config); - } -} - - /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_hw_support/port/esp32h2/rtc_clk.c b/components/esp_hw_support/port/esp32h2/rtc_clk.c index f2ca1ca3ff5..27898a95b41 100644 --- a/components/esp_hw_support/port/esp32h2/rtc_clk.c +++ b/components/esp_hw_support/port/esp32h2/rtc_clk.c @@ -238,7 +238,7 @@ static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) /** * Switch to FLASH_PLL as cpu clock source. * On ESP32H2, FLASH_PLL frequency is 64MHz. - * PLL must alreay be enabled. + * PLL must already be enabled. */ static void rtc_clk_cpu_freq_to_flash_pll(uint32_t cpu_freq_mhz, uint32_t cpu_divider) { @@ -474,21 +474,3 @@ bool rtc_dig_8m_enabled(void) { return clk_ll_rc_fast_digi_is_enabled(); } - -// Workaround for bootloader not calibrated well issue. -// Placed in IRAM because disabling BBPLL may influence the cache -void rtc_clk_recalib_bbpll(void) -{ - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - - // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. - // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. - // Turn off the BBPLL and do calibration again to fix the issue. Flash_PLL comes from the same source as PLL. - // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's - // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. - if (old_config.source == SOC_CPU_CLK_SRC_PLL || old_config.source == SOC_CPU_CLK_SRC_FLASH_PLL) { - rtc_clk_cpu_freq_set_xtal(); - rtc_clk_cpu_freq_set_config(&old_config); - } -} diff --git a/components/esp_hw_support/port/esp32s3/rtc_clk.c b/components/esp_hw_support/port/esp32s3/rtc_clk.c index a795619b99e..1416b2862c6 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_clk.c +++ b/components/esp_hw_support/port/esp32s3/rtc_clk.c @@ -187,7 +187,7 @@ static void rtc_clk_bbpll_configure(soc_xtal_freq_t xtal_freq, int pll_freq) static void rtc_clk_cpu_freq_to_pll_mhz(int cpu_freq_mhz) { - /* There are totally 6 LDO slaves(all on by default). At the moment of swithing LDO slave, LDO voltage will also change instantaneously. + /* There are totally 6 LDO slaves(all on by default). At the moment of switching LDO slave, LDO voltage will also change instantaneously. * LDO slave can reduce the voltage change caused by switching frequency. * CPU frequency <= 40M : just open 3 LDO slaves; CPU frequency = 80M : open 4 LDO slaves; CPU frequency = 160M : open 5 LDO slaves; CPU frequency = 240M : open 6 LDO slaves; * @@ -460,25 +460,6 @@ bool rtc_dig_8m_enabled(void) return clk_ll_rc_fast_digi_is_enabled(); } -// Workaround for bootloader not calibrated well issue. -// Placed in IRAM because disabling BBPLL may influence the cache -void rtc_clk_recalib_bbpll(void) -{ - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - - // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. - // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. - // Turn off the BBPLL and do calibration again to fix the issue. - // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's - // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. - if (old_config.source == SOC_CPU_CLK_SRC_PLL) { - rtc_clk_cpu_freq_set_xtal(); - rtc_clk_cpu_freq_set_config(&old_config); - } -} - - /* Name used in libphy.a:phy_chip_v7.o * TODO: update the library to use rtc_clk_xtal_freq_get */ diff --git a/components/esp_system/fpga_overrides_clk.c b/components/esp_system/fpga_overrides_clk.c index a3b4b43de59..1b1f9efad2f 100644 --- a/components/esp_system/fpga_overrides_clk.c +++ b/components/esp_system/fpga_overrides_clk.c @@ -62,14 +62,18 @@ void bootloader_clock_configure(void) REG_WRITE(RTC_XTAL_FREQ_REG, (xtal_freq_mhz) | ((xtal_freq_mhz) << 16)); } -void esp_clk_init(void) +void esp_rtc_init(void) { - s_warn(); #if SOC_PMU_SUPPORTED pmu_init(); #endif } +void esp_clk_init(void) +{ + s_warn(); +} + void esp_perip_clk_init(void) { } diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 61d5238adf8..649007cdfaa 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -536,6 +536,10 @@ void IRAM_ATTR call_start_cpu0(void) // For Octal flash, it's hard to implement a read_id function in OPI mode for all vendors. // So we have to read it here in SPI mode, before entering the OPI mode. bootloader_flash_update_id(); + + // Configure the power related stuff. After this the MSPI timing tuning can be done. + esp_rtc_init(); + /** * This function initialise the Flash chip to the user-defined settings. * @@ -544,14 +548,9 @@ void IRAM_ATTR call_start_cpu0(void) * In this stage, we re-configure the Flash (and MSPI) to required configuration */ spi_flash_init_chip_state(); - - // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. - // Do calibration again here so that we can use better clock for the timing tuning. -#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB - rtc_clk_recalib_bbpll(); -#endif #if SOC_MEMSPI_SRC_FREQ_120M - // This function needs to be called when PLL is enabled + // This function needs to be called when PLL is enabled. Needs to be called after spi_flash_init_chip_state in case + // some state of flash is modified. mspi_timing_flash_tuning(); #endif diff --git a/components/esp_system/port/include/esp_clk_internal.h b/components/esp_system/port/include/esp_clk_internal.h index 358002e2a19..a3829368b32 100644 --- a/components/esp_system/port/include/esp_clk_internal.h +++ b/components/esp_system/port/include/esp_clk_internal.h @@ -18,6 +18,15 @@ extern "C" { * Private clock-related functions */ +/** + * @brief Initialize rtc-related settings + * + * Called from cpu_start.c, not intended to be called from other places. + * This function configures the power related stuff. + * After this the MSPI timing tuning can be done. + */ +void esp_rtc_init(void); + /** * @brief Initialize clock-related settings * diff --git a/components/esp_system/port/soc/esp32/clk.c b/components/esp_system/port/soc/esp32/clk.c index 0de819e687e..88f72ff9473 100644 --- a/components/esp_system/port/soc/esp32/clk.c +++ b/components/esp_system/port/soc/esp32/clk.c @@ -106,11 +106,14 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) esp_clk_slowclk_cal_set(cal_val); } -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { rtc_config_t cfg = RTC_CONFIG_DEFAULT(); rtc_init(cfg); +} +__attribute__((weak)) void esp_clk_init(void) +{ #if (CONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_APP_INIT_CLK) /* Check the bootloader set the XTAL frequency. diff --git a/components/esp_system/port/soc/esp32c2/clk.c b/components/esp_system/port/soc/esp32c2/clk.c index ef75764dacb..6cc267ea6c8 100644 --- a/components/esp_system/port/soc/esp32c2/clk.c +++ b/components/esp_system/port/soc/esp32c2/clk.c @@ -51,11 +51,18 @@ typedef enum { } slow_clk_sel_t; static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); +static __attribute__((unused)) void recalib_bbpll(void); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { +#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB + // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. + // Do calibration again here so that we can use better clock for the timing tuning. + recalib_bbpll(); +#endif + #if !CONFIG_IDF_ENV_FPGA rtc_config_t cfg = RTC_CONFIG_DEFAULT(); soc_reset_reason_t rst_reas; @@ -64,7 +71,12 @@ __attribute__((weak)) void esp_clk_init(void) cfg.cali_ocode = 1; } rtc_init(cfg); +#endif +} +__attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA #ifndef CONFIG_XTAL_FREQ_AUTO assert(rtc_clk_xtal_freq_get() == CONFIG_XTAL_FREQ); #endif @@ -265,3 +277,21 @@ __attribute__((weak)) void esp_perip_clk_init(void) /* Enable RNG clock. */ periph_module_enable(PERIPH_RNG_MODULE); } + +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +static void IRAM_ATTR NOINLINE_ATTR recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} diff --git a/components/esp_system/port/soc/esp32c3/clk.c b/components/esp_system/port/soc/esp32c3/clk.c index 972dc75d1ba..ece3d4c732f 100644 --- a/components/esp_system/port/soc/esp32c3/clk.c +++ b/components/esp_system/port/soc/esp32c3/clk.c @@ -56,7 +56,7 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { #if !CONFIG_IDF_ENV_FPGA rtc_config_t cfg = RTC_CONFIG_DEFAULT(); @@ -70,7 +70,10 @@ __attribute__((weak)) void esp_clk_init(void) cfg.cali_ocode = 1; } rtc_init(cfg); +} +__attribute__((weak)) void esp_clk_init(void) +{ assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); bool rc_fast_d256_is_enabled = rtc_clk_8md256_enabled(); diff --git a/components/esp_system/port/soc/esp32c5/clk.c b/components/esp_system/port/soc/esp32c5/clk.c index 38aa5f9a6cd..b8828072ce4 100644 --- a/components/esp_system/port/soc/esp32c5/clk.c +++ b/components/esp_system/port/soc/esp32c5/clk.c @@ -47,31 +47,25 @@ static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); static const char *TAG = "clk"; // TODO: [ESP32C5] IDF-8642 -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { #if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION #if SOC_PMU_SUPPORTED pmu_init(); #endif +#endif +} +// TODO: [ESP32C5] IDF-8642 +__attribute__((weak)) void esp_clk_init(void) +{ +#if CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION assert((rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M) || (rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_48M)); #if SOC_MODEM_CLOCK_SUPPORTED modem_lpcon_ll_set_pwr_tick_target(&MODEM_LPCON, rtc_clk_xtal_freq_get() - 1); #endif rtc_clk_8m_enable(true); rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); -#elif CONFIG_IDF_TARGET_ESP32C5_BETA3_VERSION -#if !CONFIG_IDF_ENV_FPGA - pmu_init(); - if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON) { - esp_ocode_calib_init(); - } - - assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); - - rtc_clk_8m_enable(true); - rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); -#endif #endif #ifdef CONFIG_BOOTLOADER_WDT_ENABLE diff --git a/components/esp_system/port/soc/esp32c6/clk.c b/components/esp_system/port/soc/esp32c6/clk.c index e2b1e8d20e8..42a2f8f00a3 100644 --- a/components/esp_system/port/soc/esp32c6/clk.c +++ b/components/esp_system/port/soc/esp32c6/clk.c @@ -58,17 +58,29 @@ #define MHZ (1000000) static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); +static __attribute__((unused)) void recalib_bbpll(void); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { +#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB + // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. + // Do calibration again here so that we can use better clock for the timing tuning. + recalib_bbpll(); +#endif + #if !CONFIG_IDF_ENV_FPGA pmu_init(); if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON) { esp_ocode_calib_init(); } +#endif +} +__attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); rtc_clk_8m_enable(true); @@ -302,3 +314,21 @@ __attribute__((weak)) void esp_perip_clk_init(void) WRITE_PERI_REG(LP_CLKRST_LP_CLK_PO_EN_REG, 0); } } + +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +static void IRAM_ATTR NOINLINE_ATTR recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} diff --git a/components/esp_system/port/soc/esp32c61/clk.c b/components/esp_system/port/soc/esp32c61/clk.c index 9eabae25939..9a82793f6f7 100644 --- a/components/esp_system/port/soc/esp32c61/clk.c +++ b/components/esp_system/port/soc/esp32c61/clk.c @@ -41,14 +41,19 @@ static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { #if !CONFIG_IDF_ENV_FPGA pmu_init(); if (esp_rom_get_reset_reason(0) == RESET_REASON_CHIP_POWER_ON) { esp_ocode_calib_init(); } +#endif +} +__attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); rtc_clk_8m_enable(true); diff --git a/components/esp_system/port/soc/esp32h2/clk.c b/components/esp_system/port/soc/esp32h2/clk.c index 0523bd8c92b..87e2140cf3e 100644 --- a/components/esp_system/port/soc/esp32h2/clk.c +++ b/components/esp_system/port/soc/esp32h2/clk.c @@ -58,14 +58,26 @@ #define MHZ (1000000) static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); +static __attribute__((unused)) void recalib_bbpll(void); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { +#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB + // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. + // Do calibration again here so that we can use better clock for the timing tuning. + recalib_bbpll(); +#endif + #if !CONFIG_IDF_ENV_FPGA pmu_init(); +#endif +} +__attribute__((weak)) void esp_clk_init(void) +{ +#if !CONFIG_IDF_ENV_FPGA assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_32M); rtc_clk_8m_enable(true); @@ -290,3 +302,21 @@ __attribute__((weak)) void esp_perip_clk_init(void) WRITE_PERI_REG(LP_CLKRST_LP_CLK_PO_EN_REG, 0); } } + +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +static void IRAM_ATTR NOINLINE_ATTR recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. Flash_PLL comes from the same source as PLL. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL || old_config.source == SOC_CPU_CLK_SRC_FLASH_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} diff --git a/components/esp_system/port/soc/esp32p4/clk.c b/components/esp_system/port/soc/esp32p4/clk.c index c00287e5a10..85332e67ae9 100644 --- a/components/esp_system/port/soc/esp32p4/clk.c +++ b/components/esp_system/port/soc/esp32p4/clk.c @@ -41,12 +41,15 @@ static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); static const char *TAG = "clk"; -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { #if SOC_PMU_SUPPORTED pmu_init(); #endif //SOC_PMU_SUPPORTED +} +__attribute__((weak)) void esp_clk_init(void) +{ assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); rtc_clk_8m_enable(true); diff --git a/components/esp_system/port/soc/esp32s2/clk.c b/components/esp_system/port/soc/esp32s2/clk.c index 7da508fde77..45d932ba520 100644 --- a/components/esp_system/port/soc/esp32s2/clk.c +++ b/components/esp_system/port/soc/esp32s2/clk.c @@ -59,7 +59,7 @@ typedef enum { static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { rtc_config_t cfg = RTC_CONFIG_DEFAULT(); soc_reset_reason_t rst_reas = esp_rom_get_reset_reason(0); @@ -73,7 +73,10 @@ __attribute__((weak)) void esp_clk_init(void) } } rtc_init(cfg); +} +__attribute__((weak)) void esp_clk_init(void) +{ bool rc_fast_d256_is_enabled = rtc_clk_8md256_enabled(); rtc_clk_8m_enable(true, rc_fast_d256_is_enabled); rtc_clk_fast_src_set(SOC_RTC_FAST_CLK_SRC_RC_FAST); diff --git a/components/esp_system/port/soc/esp32s3/clk.c b/components/esp_system/port/soc/esp32s3/clk.c index 4589d5e4f94..fac148fb41a 100644 --- a/components/esp_system/port/soc/esp32s3/clk.c +++ b/components/esp_system/port/soc/esp32s3/clk.c @@ -54,9 +54,16 @@ typedef enum { } slow_clk_sel_t; static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); +static __attribute__((unused)) void recalib_bbpll(void); -__attribute__((weak)) void esp_clk_init(void) +void esp_rtc_init(void) { +#if CONFIG_ESP_SYSTEM_BBPLL_RECALIB + // In earlier version of ESP-IDF, the PLL provided by bootloader is not stable enough. + // Do calibration again here so that we can use better clock for the timing tuning. + recalib_bbpll(); +#endif + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); soc_reset_reason_t rst_reas; rst_reas = esp_rom_get_reset_reason(0); @@ -65,7 +72,10 @@ __attribute__((weak)) void esp_clk_init(void) cfg.cali_ocode = 1; } rtc_init(cfg); +} +__attribute__((weak)) void esp_clk_init(void) +{ assert(rtc_clk_xtal_freq_get() == SOC_XTAL_FREQ_40M); bool rc_fast_d256_is_enabled = rtc_clk_8md256_enabled(); @@ -325,3 +335,21 @@ __attribute__((weak)) void esp_perip_clk_init(void) /* Enable RNG clock. */ periph_module_enable(PERIPH_RNG_MODULE); } + +// Workaround for bootloader not calibrated well issue. +// Placed in IRAM because disabling BBPLL may influence the cache +static void IRAM_ATTR NOINLINE_ATTR recalib_bbpll(void) +{ + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + + // There are two paths we arrive here: 1. CPU reset. 2. Other reset reasons. + // - For other reasons, the bootloader will set CPU source to BBPLL and enable it. But there are calibration issues. + // Turn off the BBPLL and do calibration again to fix the issue. + // - For CPU reset, the CPU source will be set to XTAL, while the BBPLL is kept to meet USB Serial JTAG's + // requirements. In this case, we don't touch BBPLL to avoid USJ disconnection. + if (old_config.source == SOC_CPU_CLK_SRC_PLL) { + rtc_clk_cpu_freq_set_xtal(); + rtc_clk_cpu_freq_set_config(&old_config); + } +} From 0cca45334efd43df0f580a4f52918212f5e71ec8 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Fri, 2 Aug 2024 15:48:37 +0800 Subject: [PATCH 529/548] fix(mmu_map): make a static function force inline in order not be put in flash --- components/esp_mm/esp_mmu_map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c index 8b00d3402ae..cc3260f7c66 100644 --- a/components/esp_mm/esp_mmu_map.c +++ b/components/esp_mm/esp_mmu_map.c @@ -186,7 +186,7 @@ static void s_reserve_drom_region(mem_region_t *hw_mem_regions, int region_nums) #endif //#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if SOC_MMU_PER_EXT_MEM_TARGET -static inline uint32_t s_get_mmu_id_from_target(mmu_target_t target) +FORCE_INLINE_ATTR uint32_t s_get_mmu_id_from_target(mmu_target_t target) { return (target == MMU_TARGET_FLASH0) ? MMU_LL_FLASH_MMU_ID : MMU_LL_PSRAM_MMU_ID; } From 70bc919e80ab9246f1cb8038f67bd93a668e6c99 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 2 Aug 2024 16:34:21 +0800 Subject: [PATCH 530/548] change(examples): set the ili9881c version to 0.2.x --- .../esp_lcd/test_apps/mipi_dsi_lcd/main/idf_component.yml | 2 +- .../camera/camera_dsi/components/dsi_init/idf_component.yml | 2 +- examples/peripherals/camera/camera_dsi/main/idf_component.yml | 2 +- examples/peripherals/isp/auto_focus/main/idf_component.yml | 2 +- examples/peripherals/lcd/mipi_dsi/main/idf_component.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/idf_component.yml b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/idf_component.yml index bcad3c93db3..27d4953b96c 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/idf_component.yml +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/idf_component.yml @@ -1,2 +1,2 @@ dependencies: - esp_lcd_ili9881c: ">=0.1.0" + esp_lcd_ili9881c: "~0.2.0" diff --git a/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml index d43fae96574..3d1a63b5507 100644 --- a/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/components/dsi_init/idf_component.yml @@ -1,4 +1,4 @@ dependencies: - esp_lcd_ili9881c: ">=0.1.0" + esp_lcd_ili9881c: "~0.2.0" idf: version: ">=5.3.0" diff --git a/examples/peripherals/camera/camera_dsi/main/idf_component.yml b/examples/peripherals/camera/camera_dsi/main/idf_component.yml index 47d0275f00d..ebecc56255c 100644 --- a/examples/peripherals/camera/camera_dsi/main/idf_component.yml +++ b/examples/peripherals/camera/camera_dsi/main/idf_component.yml @@ -1,6 +1,6 @@ dependencies: espressif/esp_cam_sensor: "^0.2.2" - espressif/esp_lcd_ili9881c: "*" + espressif/esp_lcd_ili9881c: "~0.2.0" idf: version: ">=5.3.0" dsi_init: diff --git a/examples/peripherals/isp/auto_focus/main/idf_component.yml b/examples/peripherals/isp/auto_focus/main/idf_component.yml index 118d17a8428..0e139a9d081 100644 --- a/examples/peripherals/isp/auto_focus/main/idf_component.yml +++ b/examples/peripherals/isp/auto_focus/main/idf_component.yml @@ -1,6 +1,6 @@ dependencies: espressif/esp_cam_sensor: "^0.5.*" - espressif/esp_lcd_ili9881c: "*" + espressif/esp_lcd_ili9881c: "~0.2.0" idf: version: ">=5.3.0" isp_af_schemes: diff --git a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml index 4cf2c942b0b..f4d4be77e46 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml +++ b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml @@ -1,3 +1,3 @@ dependencies: lvgl/lvgl: "^9.0.0" - esp_lcd_ili9881c: "*" + esp_lcd_ili9881c: "~0.2.0" From 5b8da6f327ba36538e9d027ba1247c6f837f5e62 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Tue, 30 Jul 2024 11:10:29 +0800 Subject: [PATCH 531/548] fix(spi_flash): Add external flash support on esp32c6,esp32h2,esp32p4 --- .../hal/esp32c5/include/hal/gpspi_flash_ll.h | 16 +++- .../hal/esp32c6/include/hal/gpspi_flash_ll.h | 16 +++- .../hal/esp32c61/include/hal/gpspi_flash_ll.h | 14 +++ .../hal/esp32h2/include/hal/gpspi_flash_ll.h | 62 ++++++------ .../hal/esp32p4/include/hal/gpspi_flash_ll.h | 96 +++++++++---------- components/hal/spi_flash_hal_common.inc | 4 + components/spi_flash/esp_flash_spi_init.c | 26 +++-- .../esp_flash/main/test_esp_flash_def.h | 16 ++-- 8 files changed, 149 insertions(+), 101 deletions(-) diff --git a/components/hal/esp32c5/include/hal/gpspi_flash_ll.h b/components/hal/esp32c5/include/hal/gpspi_flash_ll.h index 9bf5f63a10d..a126254f33e 100644 --- a/components/hal/esp32c5/include/hal/gpspi_flash_ll.h +++ b/components/hal/esp32c5/include/hal/gpspi_flash_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -406,6 +406,20 @@ static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) abort(); } +/** + * Set D/Q output level during dummy phase + * + * @param dev Beginning address of the peripheral registers. + * @param out_en whether to enable IO output for dummy phase + * @param out_level dummy output level + */ +static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev) +{ + dev->ctrl.dummy_out = out_en; + dev->ctrl.q_pol = out_lev; + dev->ctrl.d_pol = out_lev; +} + /** * Set extra hold time of CS after the clocks. * diff --git a/components/hal/esp32c6/include/hal/gpspi_flash_ll.h b/components/hal/esp32c6/include/hal/gpspi_flash_ll.h index 4206665f6a6..73d64db653b 100644 --- a/components/hal/esp32c6/include/hal/gpspi_flash_ll.h +++ b/components/hal/esp32c6/include/hal/gpspi_flash_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -366,6 +366,20 @@ static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user1, usr_dummy_cyclelen, dummy_n - 1); } +/** + * Set D/Q output level during dummy phase + * + * @param dev Beginning address of the peripheral registers. + * @param out_en whether to enable IO output for dummy phase + * @param out_level dummy output level + */ +static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev) +{ + dev->ctrl.dummy_out = out_en; + dev->ctrl.q_pol = out_lev; + dev->ctrl.d_pol = out_lev; +} + /** * Set extra hold time of CS after the clocks. * diff --git a/components/hal/esp32c61/include/hal/gpspi_flash_ll.h b/components/hal/esp32c61/include/hal/gpspi_flash_ll.h index f0bfd56982f..92620c7f750 100644 --- a/components/hal/esp32c61/include/hal/gpspi_flash_ll.h +++ b/components/hal/esp32c61/include/hal/gpspi_flash_ll.h @@ -368,6 +368,20 @@ static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user1, usr_dummy_cyclelen, dummy_n - 1); } +/** + * Set D/Q output level during dummy phase + * + * @param dev Beginning address of the peripheral registers. + * @param out_en whether to enable IO output for dummy phase + * @param out_level dummy output level + */ +static inline void gpspi_flash_ll_set_dummy_out(spi_dev_t *dev, uint32_t out_en, uint32_t out_lev) +{ + dev->ctrl.dummy_out = out_en; + dev->ctrl.q_pol = out_lev; + dev->ctrl.d_pol = out_lev; +} + /** * Set extra hold time of CS after the clocks. * diff --git a/components/hal/esp32h2/include/hal/gpspi_flash_ll.h b/components/hal/esp32h2/include/hal/gpspi_flash_ll.h index c086401f32c..124863b7d60 100644 --- a/components/hal/esp32h2/include/hal/gpspi_flash_ll.h +++ b/components/hal/esp32h2/include/hal/gpspi_flash_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,9 +53,9 @@ static inline void gpspi_flash_ll_reset(spi_dev_t *dev) dev->clk_gate.mst_clk_sel = 1; dev->dma_conf.val = 0; - // dev->dma_conf.tx_seg_trans_clr_en = 1; - // dev->dma_conf.rx_seg_trans_clr_en = 1; - // dev->dma_conf.dma_seg_trans_en = 0; + dev->dma_conf.slv_tx_seg_trans_clr_en = 1; + dev->dma_conf.slv_rx_seg_trans_clr_en = 1; + dev->dma_conf.dma_slv_seg_trans_en = 0; } /** @@ -79,20 +79,20 @@ static inline bool gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev) */ static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) { - // if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { - // // If everything is word-aligned, do a faster memcpy - // memcpy(buffer, (void *)dev->data_buf, read_len); - // } else { - // // Otherwise, slow(er) path copies word by word - // int copy_len = read_len; - // for (int i = 0; i < (read_len + 3) / 4; i++) { - // int word_len = MIN(sizeof(uint32_t), copy_len); - // uint32_t word = dev->data_buf[i]; - // memcpy(buffer, &word, word_len); - // buffer = (void *)((intptr_t)buffer + word_len); - // copy_len -= word_len; - // } - // } + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i].buf0; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } } /** @@ -103,7 +103,7 @@ static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, */ static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) { - // dev->data_buf[0] = word; + dev->data_buf[0].buf0 = word; } /** @@ -116,15 +116,15 @@ static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length) { // Load data registers, word at a time - // int num_words = (length + 3) / 4; - // for (int i = 0; i < num_words; i++) { - // uint32_t word = 0; - // uint32_t word_len = MIN(length, sizeof(word)); - // memcpy(&word, buffer, word_len); - // dev->data_buf[i] = word; - // length -= word_len; - // buffer = (void *)((intptr_t)buffer + word_len); - // } + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i].buf0 = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } } /** @@ -339,8 +339,8 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen) { // The blank region should be all ones - // uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen); - // dev->addr = (addr << (32 - bitlen)) | padding_ones; + uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen); + dev->addr.val = (addr << (32 - bitlen)) | padding_ones; } /** @@ -351,7 +351,7 @@ static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, */ static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) { - // dev->addr = addr; + dev->addr.val = addr; } /** diff --git a/components/hal/esp32p4/include/hal/gpspi_flash_ll.h b/components/hal/esp32p4/include/hal/gpspi_flash_ll.h index 05c38d87f29..73d64db653b 100644 --- a/components/hal/esp32p4/include/hal/gpspi_flash_ll.h +++ b/components/hal/esp32p4/include/hal/gpspi_flash_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,7 +23,6 @@ #include #include #include "hal/misc.h" -//TODO: IDF-7499 #ifdef __cplusplus extern "C" { @@ -33,7 +32,7 @@ extern "C" { #define gpspi_flash_ll_get_hw(host_id) ( ((host_id)==SPI2_HOST) ? &GPSPI2 : ({abort();(spi_dev_t*)0;}) ) #define gpspi_flash_ll_hw_get_id(dev) ( ((dev) == (void*)&GPSPI2) ? SPI2_HOST : -1 ) -typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t; +typedef typeof(GPSPI2.clock.val) gpspi_flash_ll_clock_reg_t; #define GPSPI_FLASH_LL_PERIPHERAL_FREQUENCY_MHZ (80) /*------------------------------------------------------------------------------ @@ -46,18 +45,17 @@ typedef typeof(GPSPI2.clock) gpspi_flash_ll_clock_reg_t; */ static inline void gpspi_flash_ll_reset(spi_dev_t *dev) { - // dev->user.val = 0; - // dev->ctrl.val = 0; - - // dev->clk_gate.clk_en = 1; - // dev->clk_gate.mst_clk_active = 1; - // dev->clk_gate.mst_clk_sel = 1; - - // dev->dma_conf.val = 0; - // dev->dma_conf.tx_seg_trans_clr_en = 1; - // dev->dma_conf.rx_seg_trans_clr_en = 1; - // dev->dma_conf.dma_seg_trans_en = 0; - abort(); //TODO: IDF-7499 + dev->user.val = 0; + dev->ctrl.val = 0; + + dev->clk_gate.clk_en = 1; + dev->clk_gate.mst_clk_active = 1; + dev->clk_gate.mst_clk_sel = 1; + + dev->dma_conf.val = 0; + dev->dma_conf.slv_tx_seg_trans_clr_en = 1; + dev->dma_conf.slv_rx_seg_trans_clr_en = 1; + dev->dma_conf.dma_slv_seg_trans_en = 0; } /** @@ -81,21 +79,20 @@ static inline bool gpspi_flash_ll_cmd_is_done(const spi_dev_t *dev) */ static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, uint32_t read_len) { - // if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { - // // If everything is word-aligned, do a faster memcpy - // memcpy(buffer, (void *)dev->data_buf, read_len); - // } else { - // // Otherwise, slow(er) path copies word by word - // int copy_len = read_len; - // for (int i = 0; i < (read_len + 3) / 4; i++) { - // int word_len = MIN(sizeof(uint32_t), copy_len); - // uint32_t word = dev->data_buf[i]; - // memcpy(buffer, &word, word_len); - // buffer = (void *)((intptr_t)buffer + word_len); - // copy_len -= word_len; - // } - // } - abort(); //TODO: IDF-7499 + if (((intptr_t)buffer % 4 == 0) && (read_len % 4 == 0)) { + // If everything is word-aligned, do a faster memcpy + memcpy(buffer, (void *)dev->data_buf, read_len); + } else { + // Otherwise, slow(er) path copies word by word + int copy_len = read_len; + for (int i = 0; i < (read_len + 3) / 4; i++) { + int word_len = MIN(sizeof(uint32_t), copy_len); + uint32_t word = dev->data_buf[i].buf; + memcpy(buffer, &word, word_len); + buffer = (void *)((intptr_t)buffer + word_len); + copy_len -= word_len; + } + } } /** @@ -106,8 +103,7 @@ static inline void gpspi_flash_ll_get_buffer_data(spi_dev_t *dev, void *buffer, */ static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) { - // dev->data_buf[0] = word; - abort(); //TODO: IDF-7499 + dev->data_buf[0].buf = word; } /** @@ -119,17 +115,16 @@ static inline void gpspi_flash_ll_write_word(spi_dev_t *dev, uint32_t word) */ static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *buffer, uint32_t length) { - // // Load data registers, word at a time - // int num_words = (length + 3) / 4; - // for (int i = 0; i < num_words; i++) { - // uint32_t word = 0; - // uint32_t word_len = MIN(length, sizeof(word)); - // memcpy(&word, buffer, word_len); - // dev->data_buf[i] = word; - // length -= word_len; - // buffer = (void *)((intptr_t)buffer + word_len); - // } - abort(); //TODO: IDF-7499 + // Load data registers, word at a time + int num_words = (length + 3) / 4; + for (int i = 0; i < num_words; i++) { + uint32_t word = 0; + uint32_t word_len = MIN(length, sizeof(word)); + memcpy(&word, buffer, word_len); + dev->data_buf[i].buf = word; + length -= word_len; + buffer = (void *)((intptr_t)buffer + word_len); + } } /** @@ -141,7 +136,6 @@ static inline void gpspi_flash_ll_set_buffer_data(spi_dev_t *dev, const void *bu */ static inline void gpspi_flash_ll_user_start(spi_dev_t *dev, bool pe_ops) { - dev->ctrl.hold_pol = 1; dev->cmd.update = 1; while (dev->cmd.update); dev->cmd.usr = 1; @@ -264,7 +258,7 @@ static inline void gpspi_flash_ll_set_read_mode(spi_dev_t *dev, esp_flash_io_mod */ static inline void gpspi_flash_ll_set_clock(spi_dev_t *dev, gpspi_flash_ll_clock_reg_t *clock_val) { - dev->clock.val = (*clock_val).val; + dev->clock.val = *clock_val; } /** @@ -344,10 +338,9 @@ static inline void gpspi_flash_ll_set_addr_bitlen(spi_dev_t *dev, uint32_t bitle */ static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, uint32_t bitlen) { - // // The blank region should be all ones - // uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen); - // dev->addr = (addr << (32 - bitlen)) | padding_ones; - abort(); //TODO: IDF-7499 + // The blank region should be all ones + uint32_t padding_ones = (bitlen == 32? 0 : UINT32_MAX >> bitlen); + dev->addr.val = (addr << (32 - bitlen)) | padding_ones; } /** @@ -358,8 +351,7 @@ static inline void gpspi_flash_ll_set_usr_address(spi_dev_t *dev, uint32_t addr, */ static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) { - // dev->addr = addr; - abort(); //TODO: IDF-7499 + dev->addr.val = addr; } /** @@ -371,7 +363,7 @@ static inline void gpspi_flash_ll_set_address(spi_dev_t *dev, uint32_t addr) static inline void gpspi_flash_ll_set_dummy(spi_dev_t *dev, uint32_t dummy_n) { dev->user.usr_dummy = dummy_n ? 1 : 0; - dev->user1.usr_dummy_cyclelen = dummy_n - 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->user1, usr_dummy_cyclelen, dummy_n - 1); } /** diff --git a/components/hal/spi_flash_hal_common.inc b/components/hal/spi_flash_hal_common.inc index 942edf96f69..65f5af0e7ba 100644 --- a/components/hal/spi_flash_hal_common.inc +++ b/components/hal/spi_flash_hal_common.inc @@ -101,6 +101,7 @@ esp_err_t spi_flash_hal_configure_host_io_mode( return ESP_ERR_NOT_SUPPORTED; } +#ifndef GPSPI_BUILD #if SOC_SPI_PERIPH_SUPPORT_CONTROL_DUMMY_OUT // The CONTROL_DUMMY_OUTPUT feature is used to control M7-M0 bits. spi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1); @@ -129,6 +130,9 @@ esp_err_t spi_flash_hal_configure_host_io_mode( spi_flash_ll_set_extra_address(dev, 0); } #endif +#else + gpspi_flash_ll_set_dummy_out(dev, (conf_required? 1: 0), 1); +#endif if (command >= 0x100) { spi_flash_ll_set_command(dev, command, 16); diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 8ba9a8d9f19..fdff3c944ce 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -122,7 +122,7 @@ esp_flash_t *esp_flash_default_chip = NULL; #endif //!CONFIG_SPI_FLASH_AUTO_SUSPEND #endif // Other target -static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool use_iomux, int cs_id) +static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_flash_spi_device_config_t *config, bool cs_use_iomux, int cs_id) { //Not using spicommon_cs_initialize since we don't want to put the whole //spi_periph_signal into the DRAM. Copy these data from flash before the @@ -139,9 +139,9 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f //To avoid the panic caused by flash data line conflicts during cs line //initialization, disable the cache temporarily chip->os_func->start(chip->os_func_data); - PIN_INPUT_ENABLE(iomux_reg); - if (use_iomux) { - gpio_hal_iomux_func_sel(iomux_reg, spics_func); + gpio_hal_input_enable(&gpio_hal, cs_io_num); + if (cs_use_iomux) { + gpio_hal_func_sel(&gpio_hal, cs_io_num, spics_func); } else { gpio_hal_output_enable(&gpio_hal, cs_io_num); gpio_hal_od_disable(&gpio_hal, cs_io_num); @@ -175,6 +175,16 @@ static bool bus_using_iomux(spi_host_device_t host) return true; } +static bool cs_using_iomux(const esp_flash_spi_device_config_t *config) +{ + bool use_iomux = true; + CHECK_IOMUX_PIN(config->host_id, spics); + if (config->cs_io_num != spi_periph_signal[config->host_id].spics0_iomux_pin) { + use_iomux = false; + } + return use_iomux; +} + static esp_err_t acquire_spi_device(const esp_flash_spi_device_config_t *config, int* out_dev_id, spi_bus_lock_dev_handle_t* out_dev_handle) { esp_err_t ret = ESP_OK; @@ -274,7 +284,7 @@ esp_err_t spi_bus_add_flash_device(esp_flash_t **out_chip, const esp_flash_spi_d } // The cs_id inside `config` is deprecated, use the `dev_id` provided by the bus lock instead. - cs_initialize(chip, config, use_iomux, dev_id); + cs_initialize(chip, config, cs_using_iomux(config), dev_id); *out_chip = chip; return ret; fail: @@ -317,14 +327,14 @@ static void s_esp_flash_choose_correct_mode(memspi_host_config_t *cfg) static const char *mode = FLASH_MODE_STRING; if (bootloader_flash_is_octal_mode_enabled()) { #if !CONFIG_ESPTOOLPY_FLASHMODE_OPI - ESP_EARLY_LOGW(TAG, "Octal flash chip is using but %s mode is selected, will automatically swich to Octal mode", mode); + ESP_EARLY_LOGW(TAG, "Octal flash chip is using but %s mode is selected, will automatically switch to Octal mode", mode); cfg->octal_mode_en = 1; cfg->default_io_mode = SPI_FLASH_OPI_STR; default_chip.read_mode = SPI_FLASH_OPI_STR; #endif } else { #if CONFIG_ESPTOOLPY_FLASHMODE_OPI - ESP_EARLY_LOGW(TAG, "Quad flash chip is using but %s flash mode is selected, will automatically swich to DIO mode", mode); + ESP_EARLY_LOGW(TAG, "Quad flash chip is using but %s flash mode is selected, will automatically switch to DIO mode", mode); cfg->octal_mode_en = 0; cfg->default_io_mode = SPI_FLASH_DIO; default_chip.read_mode = SPI_FLASH_DIO; @@ -357,7 +367,7 @@ esp_err_t esp_flash_init_default_chip(void) #endif - // For chips need time tuning, get value directely from system here. + // For chips need time tuning, get value directly from system here. #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING if (spi_flash_timing_is_tuned()) { cfg.using_timing_tuning = 1; diff --git a/components/spi_flash/test_apps/esp_flash/main/test_esp_flash_def.h b/components/spi_flash/test_apps/esp_flash/main/test_esp_flash_def.h index 766ea621d08..ecbb64df507 100644 --- a/components/spi_flash/test_apps/esp_flash/main/test_esp_flash_def.h +++ b/components/spi_flash/test_apps/esp_flash/main/test_esp_flash_def.h @@ -68,7 +68,7 @@ #define HSPI_PIN_NUM_WP FSPI_PIN_NUM_WP #define HSPI_PIN_NUM_CS FSPI_PIN_NUM_CS -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C6 #define SPI1_CS_IO 26 //the pin which is usually used by the PSRAM cs #define SPI1_HD_IO 27 //the pin which is usually used by the PSRAM hd #define SPI1_WP_IO 28 //the pin which is usually used by the PSRAM wp @@ -88,14 +88,14 @@ #define HSPI_PIN_NUM_WP FSPI_PIN_NUM_WP #define HSPI_PIN_NUM_CS FSPI_PIN_NUM_CS -#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 +#elif CONFIG_IDF_TARGET_ESP32H2 -#define FSPI_PIN_NUM_MOSI 7 -#define FSPI_PIN_NUM_MISO 2 -#define FSPI_PIN_NUM_CLK 6 -#define FSPI_PIN_NUM_HD 4 -#define FSPI_PIN_NUM_WP 5 -#define FSPI_PIN_NUM_CS 17 +#define FSPI_PIN_NUM_MOSI 5 +#define FSPI_PIN_NUM_MISO 0 +#define FSPI_PIN_NUM_CLK 4 +#define FSPI_PIN_NUM_HD 3 +#define FSPI_PIN_NUM_WP 2 +#define FSPI_PIN_NUM_CS 1 // Just use the same pins for HSPI #define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI From 73cdd201680aa3eff35442fb65caff7105e88016 Mon Sep 17 00:00:00 2001 From: zwx Date: Tue, 9 Jul 2024 11:12:31 +0800 Subject: [PATCH 532/548] fix(openthread): make ot task queue sending non-permanent blocking --- components/openthread/lib | 2 +- .../openthread/src/esp_openthread_cli.c | 7 +- .../src/esp_openthread_lwip_netif.c | 6 ++ .../src/esp_openthread_task_queue.c | 4 +- examples/openthread/ot_br/main/esp_ot_br.c | 84 ++++++++++--------- examples/openthread/ot_br/sdkconfig.defaults | 2 +- 6 files changed, 60 insertions(+), 45 deletions(-) diff --git a/components/openthread/lib b/components/openthread/lib index 34d698a2749..203c78501e9 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit 34d698a274940730901b934caa023a3281aca53e +Subproject commit 203c78501e9a6ea9ca3a929e6f9b6b9691ef16ee diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index 6ce998a4305..b2a76a4df0c 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -99,8 +99,11 @@ static void ot_cli_loop(void *context) printf("Internal error: %s\n", esp_err_to_name(err)); } } else { - esp_openthread_cli_input(line); - xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + if (esp_openthread_cli_input(line) == ESP_OK) { + xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + } else { + printf("Openthread task is busy, failed to run command: %s\n", line); + } } linenoiseHistoryAdd(line); } diff --git a/components/openthread/src/esp_openthread_lwip_netif.c b/components/openthread/src/esp_openthread_lwip_netif.c index 29be440ae09..94c8e16861e 100644 --- a/components/openthread/src/esp_openthread_lwip_netif.c +++ b/components/openthread/src/esp_openthread_lwip_netif.c @@ -23,6 +23,12 @@ #define OPENTHREAD_IP6_MTU 1280 +#if CONFIG_OPENTHREAD_BORDER_ROUTER +#if CONFIG_LWIP_IPV6_NUM_ADDRESSES != 12 +#error CONFIG_LWIP_IPV6_NUM_ADDRESSES should be set to 12, please configure it using `idf.py menuconfig` +#endif +#endif + static err_t openthread_netif_init(struct netif *netif); static void openthread_netif_input(void *h, void *buffer, size_t len, void *eb); diff --git a/components/openthread/src/esp_openthread_task_queue.c b/components/openthread/src/esp_openthread_task_queue.c index 32bb4f20020..9d9bf87e6f3 100644 --- a/components/openthread/src/esp_openthread_task_queue.c +++ b/components/openthread/src/esp_openthread_task_queue.c @@ -21,6 +21,8 @@ static QueueHandle_t s_task_queue = NULL; static int s_task_queue_event_fd = -1; static const char *task_queue_workflow = "task_queue"; +#define OT_TASK_QUEUE_SENDING_WAIT_TIME pdMS_TO_TICKS(100) + typedef struct { esp_openthread_task_t task; void *arg; @@ -60,7 +62,7 @@ esp_err_t IRAM_ATTR esp_openthread_task_queue_post(esp_openthread_task_t task, v ESP_RETURN_ON_FALSE_ISR(xQueueSendFromISR(s_task_queue, &task_storage, &task_woken), ESP_FAIL, OT_PLAT_LOG_TAG, "Failed to post task to OpenThread task queue"); } else { - ESP_RETURN_ON_FALSE(xQueueSend(s_task_queue, &task_storage, portMAX_DELAY), ESP_FAIL, OT_PLAT_LOG_TAG, + ESP_RETURN_ON_FALSE(xQueueSend(s_task_queue, &task_storage, OT_TASK_QUEUE_SENDING_WAIT_TIME), ESP_FAIL, OT_PLAT_LOG_TAG, "Failed to post task to OpenThread task queue"); } ret = write(s_task_queue_event_fd, &val, sizeof(val)); diff --git a/examples/openthread/ot_br/main/esp_ot_br.c b/examples/openthread/ot_br/main/esp_ot_br.c index d29718c4aeb..bf887803a93 100644 --- a/examples/openthread/ot_br/main/esp_ot_br.c +++ b/examples/openthread/ot_br/main/esp_ot_br.c @@ -73,29 +73,15 @@ static void ot_task_worker(void *aContext) // Initialize the OpenThread stack ESP_ERROR_CHECK(esp_openthread_init(&config)); - - // Initialize border routing features - esp_openthread_lock_acquire(portMAX_DELAY); -#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE - ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance())); -#endif ESP_ERROR_CHECK(esp_netif_attach(openthread_netif, esp_openthread_netif_glue_init(&config))); - + esp_openthread_lock_acquire(portMAX_DELAY); (void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL); esp_openthread_cli_init(); - -#if CONFIG_OPENTHREAD_BR_AUTO_START - ESP_ERROR_CHECK(esp_openthread_border_router_init()); - otOperationalDatasetTlvs dataset; - otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); - ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); -#endif // CONFIG_OPENTHREAD_BR_AUTO_START - esp_cli_custom_command_init(); + esp_openthread_cli_create_task(); esp_openthread_lock_release(); // Run the main loop - esp_openthread_cli_create_task(); esp_openthread_launch_mainloop(); // Clean up @@ -105,36 +91,15 @@ static void ot_task_worker(void *aContext) vTaskDelete(NULL); } -void app_main(void) +void ot_br_init(void *ctx) { - // Used eventfds: - // * netif - // * task queue - // * border router - esp_vfs_eventfd_config_t eventfd_config = { -#if CONFIG_OPENTHREAD_RADIO_NATIVE || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI - // * radio driver (A native radio device needs a eventfd for radio driver.) - // * SpiSpinelInterface (The Spi Spinel Interface needs a eventfd.) - // The above will not exist at the same time. - .max_fds = 4, -#else - .max_fds = 3, -#endif - }; - ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); - - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - #if CONFIG_EXAMPLE_CONNECT_WIFI #if CONFIG_OPENTHREAD_BR_AUTO_START ESP_ERROR_CHECK(example_connect()); + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MAX_MODEM)); #if CONFIG_ESP_COEX_SW_COEXIST_ENABLE && CONFIG_OPENTHREAD_RADIO_NATIVE - ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MIN_MODEM)); ESP_ERROR_CHECK(esp_coex_wifi_i154_enable()); #else - ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); #if CONFIG_EXTERNAL_COEX_ENABLE ot_br_external_coexist_init(); @@ -155,5 +120,44 @@ void app_main(void) ESP_ERROR_CHECK(mdns_init()); ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br")); - xTaskCreate(ot_task_worker, "ot_br_main", 20480, xTaskGetCurrentTaskHandle(), 5, NULL); + + // Initialize border routing features + esp_openthread_lock_acquire(portMAX_DELAY); +#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE + ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance())); +#endif + +#if CONFIG_OPENTHREAD_BR_AUTO_START + ESP_ERROR_CHECK(esp_openthread_border_router_init()); + otOperationalDatasetTlvs dataset; + otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset); + ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL)); +#endif // CONFIG_OPENTHREAD_BR_AUTO_START + + esp_openthread_lock_release(); + vTaskDelete(NULL); +} + +void app_main(void) +{ + // Used eventfds: + // * netif + // * task queue + // * border router + esp_vfs_eventfd_config_t eventfd_config = { +#if CONFIG_OPENTHREAD_RADIO_NATIVE || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI + // * radio driver (A native radio device needs a eventfd for radio driver.) + // * SpiSpinelInterface (The Spi Spinel Interface needs a eventfd.) + // The above will not exist at the same time. + .max_fds = 4, +#else + .max_fds = 3, +#endif + }; + ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config)); + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + xTaskCreate(ot_task_worker, "ot_br_main", 8192, xTaskGetCurrentTaskHandle(), 5, NULL); + xTaskCreate(ot_br_init, "ot_br_init", 6144, NULL, 4, NULL); } diff --git a/examples/openthread/ot_br/sdkconfig.defaults b/examples/openthread/ot_br/sdkconfig.defaults index 6620bfa46b1..619ab0f7e78 100644 --- a/examples/openthread/ot_br/sdkconfig.defaults +++ b/examples/openthread/ot_br/sdkconfig.defaults @@ -31,7 +31,7 @@ CONFIG_OPENTHREAD_RADIO_SPINEL_UART=y # lwIP # CONFIG_LWIP_IPV6_FORWARD=y -CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 +CONFIG_LWIP_IPV6_NUM_ADDRESSES=12 CONFIG_LWIP_MULTICAST_PING=y CONFIG_LWIP_NETIF_STATUS_CALLBACK=y CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y From 12a2e89ac69b815c69ff8e0219bbc71da61c2518 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Thu, 1 Aug 2024 14:10:06 +0530 Subject: [PATCH 533/548] fix(bootloader_support): Fix encrypt image instead of the partition feature not being enabled --- .../bootloader_support/src/flash_encryption/flash_encrypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bootloader_support/src/flash_encryption/flash_encrypt.c b/components/bootloader_support/src/flash_encryption/flash_encrypt.c index a0a48312e0b..850fcb99841 100644 --- a/components/bootloader_support/src/flash_encryption/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encryption/flash_encrypt.c @@ -422,7 +422,7 @@ static esp_err_t encrypt_partition(int index, const esp_partition_info_t *partit &partition->pos, &image_data); should_encrypt = (err == ESP_OK); -#ifdef SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART +#ifdef CONFIG_SECURE_FLASH_ENCRYPT_ONLY_IMAGE_LEN_IN_APP_PART if (should_encrypt) { // Encrypt only the app image instead of encrypting the whole partition size = image_data.image_len; From 1f0676563050140ef207f01575bee8875497aaec Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Thu, 1 Aug 2024 12:24:47 +0200 Subject: [PATCH 534/548] change: exclude CVEs that do not impact ESP-IDF components cJSON: CVE-2024-31755 - Resolved in cJSON v1.7.18 FreeRTOS: CVE-2024-28115 - Affects only ARMv7-M MPU ports, and ARMv8-M ports Signed-off-by: Frantisek Hrbata --- .gitmodules | 1 + components/freertos/FreeRTOS-Kernel/sbom.yml | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.gitmodules b/.gitmodules index f3060884937..ee3fd858e0c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -55,6 +55,7 @@ sbom-url = https://github.com/DaveGamble/cJSON sbom-description = Ultralightweight JSON parser in ANSI C sbom-hash = acc76239bee01d8e9c858ae2cab296704e52d916 + sbom-cve-exclude-list = CVE-2024-31755 Resolved in v1.7.18 [submodule "components/mbedtls/mbedtls"] path = components/mbedtls/mbedtls diff --git a/components/freertos/FreeRTOS-Kernel/sbom.yml b/components/freertos/FreeRTOS-Kernel/sbom.yml index f5f9f31eb33..1fc82481f88 100644 --- a/components/freertos/FreeRTOS-Kernel/sbom.yml +++ b/components/freertos/FreeRTOS-Kernel/sbom.yml @@ -4,3 +4,6 @@ cpe: cpe:2.3:o:amazon:freertos:{}:*:*:*:*:*:*:* supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' originator: 'Organization: Amazon Web Services' description: An open-source, real-time operating system (RTOS) with additional features and patches from Espressif. +cve-exclude-list: + - cve: CVE-2024-28115 + reason: Affects only ARMv7-M MPU ports, and ARMv8-M ports with Memory Protected Unit (MPU) support enabled From 4a7985ab4a06dba49e0afabd74e5b458550e2968 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 26 Jun 2024 16:05:44 +0800 Subject: [PATCH 535/548] fix(rtc): fixed non-iram rtc code in early stage on p4 leading xip_psram stuck --- components/esp_hw_support/linker.lf | 3 +++ components/esp_system/port/soc/esp32p4/clk.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/linker.lf b/components/esp_hw_support/linker.lf index 0ad8003c564..00bcae6634e 100644 --- a/components/esp_hw_support/linker.lf +++ b/components/esp_hw_support/linker.lf @@ -21,6 +21,9 @@ entries: rtc_time (noflash_text) if SOC_PMU_SUPPORTED = y: pmu_sleep (noflash) + if SPIRAM_FLASH_LOAD_TO_PSRAM = y: + pmu_init (noflash) + pmu_param (noflash) if SOC_USB_SERIAL_JTAG_SUPPORTED = y: sleep_console (noflash) if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y: diff --git a/components/esp_system/port/soc/esp32p4/clk.c b/components/esp_system/port/soc/esp32p4/clk.c index 85332e67ae9..49f9737e8ef 100644 --- a/components/esp_system/port/soc/esp32p4/clk.c +++ b/components/esp_system/port/soc/esp32p4/clk.c @@ -41,7 +41,7 @@ static void select_rtc_slow_clk(soc_rtc_slow_clk_src_t rtc_slow_clk_src); static const char *TAG = "clk"; -void esp_rtc_init(void) +void IRAM_ATTR esp_rtc_init(void) { #if SOC_PMU_SUPPORTED pmu_init(); From e94d1f275c2b6c86dd2dae98dfbe42bef56dfa72 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Mon, 5 Aug 2024 17:49:14 +0530 Subject: [PATCH 536/548] fix(mbedtls/aes): Avoid extra C2M sync of memory --- components/mbedtls/port/aes/dma/esp_aes_dma_core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c index 4bc6999eb3b..c5231d5a7a7 100644 --- a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c +++ b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c @@ -325,7 +325,7 @@ static inline void *aes_dma_calloc(size_t num, size_t size, uint32_t caps, size_ return heap_caps_aligned_calloc(DMA_DESC_MEM_ALIGN_SIZE, num, size, caps | MALLOC_CAP_DMA | MALLOC_CAP_8BIT); } -static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_dma_desc_num, size_t cache_line_size) +static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_dma_desc_num) { esp_err_t ret = ESP_OK; for (int i = 0; i < crypto_dma_desc_num; i++) { @@ -334,7 +334,8 @@ static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_ #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE /* Write back both input buffers and output buffers to clear any cache dirty bit if set If we want to remove `ESP_CACHE_MSYNC_FLAG_UNALIGNED` aligned flag then we need to pass - cache msync size = ALIGN_UP(dma_desc.size, cache_line_size), instead of dma_desc.size + cache msync size = ALIGN_UP(dma_desc.size, cache_line_size), where cache_line_size is the + the cache line size coressponding to the buffer that is being synced, instead of dma_desc.size Keeping the `ESP_CACHE_MSYNC_FLAG_UNALIGNED` flag just because it should not look like we are syncing extra bytes due to ALIGN_UP'ed size but just the number of bytes that are needed in the operation. */ @@ -343,7 +344,7 @@ static inline esp_err_t dma_desc_link(crypto_dma_desc_t *dmadesc, size_t crypto_ return ret; } } - ret = esp_cache_msync(dmadesc, ALIGN_UP(crypto_dma_desc_num * sizeof(crypto_dma_desc_t), cache_line_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + ret = esp_cache_msync(dmadesc, crypto_dma_desc_num * sizeof(crypto_dma_desc_t), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); #else } #endif @@ -470,7 +471,7 @@ static esp_err_t generate_descriptor_list(const uint8_t *buffer, const size_t le populated_dma_descs += (unaligned_end_bytes ? 1 : 0); } - if (dma_desc_link(dma_descriptors, dma_descs_needed, cache_line_size) != ESP_OK) { + if (dma_desc_link(dma_descriptors, dma_descs_needed) != ESP_OK) { ESP_LOGE(TAG, "DMA descriptors cache sync C2M failed"); return ESP_FAIL; } From 3eec62f823d40bd58c477f5d35676740cc3dee77 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Mon, 12 Aug 2024 08:26:05 +0530 Subject: [PATCH 537/548] fix(rng): avoid clearing `PMU_PERIF_I2C_RSTB` in random disable API for C6 This configuration bit is required for ADC operation as well and hence should not be cleared in the RNG API sequence. Ideally, the ADC driver should take care of initializing this bit but still the RNG layer change is required because of interleaved API usage scenario described in following linked issue. Closes https://github.com/espressif/esp-idf/issues/14124 Closes https://github.com/espressif/esp-idf/issues/14280 --- components/bootloader_support/src/bootloader_random_esp32c6.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/bootloader_support/src/bootloader_random_esp32c6.c b/components/bootloader_support/src/bootloader_random_esp32c6.c index 0efd9d4c086..fec85a6a404 100644 --- a/components/bootloader_support/src/bootloader_random_esp32c6.c +++ b/components/bootloader_support/src/bootloader_random_esp32c6.c @@ -88,9 +88,6 @@ void bootloader_random_disable(void) REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC1_ENCAL_REF_ADDR, 0); REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SARADC2_ENCAL_REF_ADDR, 0); - // Revert PMU_RF_PWC_REG to it's initial value - CLEAR_PERI_REG_MASK(PMU_RF_PWC_REG, PMU_PERIF_I2C_RSTB); - // disable ADC_CTRL_CLK (SAR ADC function clock) REG_WRITE(PCR_SARADC_CLKM_CONF_REG, 0x00404000); From fe48cfd6e5175d0ea9c00bd06a0101b78daac366 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 14 Aug 2024 14:57:29 +0800 Subject: [PATCH 538/548] fix(xip): added SOC_SPIRAM_XIP_SUPPORTED for programming guide usage --- components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32p4/include/soc/soc_caps.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 237af554680..1201d5df241 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1319,6 +1319,10 @@ config SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED bool default y +config SOC_SPIRAM_XIP_SUPPORTED + bool + default y + config SOC_SYSTIMER_COUNTER_NUM int default 2 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 754f84efae8..452329f0195 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -522,6 +522,9 @@ #define SOC_MEMSPI_SRC_FREQ_40M_SUPPORTED 1 #define SOC_MEMSPI_SRC_FREQ_20M_SUPPORTED 1 +/*-------------------------- SPIRAM CAPS ----------------------------------------*/ +#define SOC_SPIRAM_XIP_SUPPORTED 1 + /*-------------------------- SYSTIMER CAPS ----------------------------------*/ #define SOC_SYSTIMER_COUNTER_NUM 2 // Number of counter units #define SOC_SYSTIMER_ALARM_NUM 3 // Number of alarm units From eca7b3b1f1e6a53fc5e8c071b1012264fc1b7121 Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 14 Aug 2024 11:28:18 +0800 Subject: [PATCH 539/548] fix(xip): move rest xip_psram doc out from non updated list --- docs/docs_not_updated/esp32c5.txt | 1 - docs/docs_not_updated/esp32p4.txt | 2 - docs/en/api-guides/external-ram.rst | 14 ++--- .../spi_flash/spi_flash_concurrency.rst | 4 +- .../peripherals/spi_flash/xip_from_psram.inc | 6 +- docs/zh_CN/api-guides/external-ram.rst | 62 ++++++++++++------- .../spi_flash/spi_flash_concurrency.rst | 4 +- .../peripherals/spi_flash/xip_from_psram.inc | 6 +- 8 files changed, 54 insertions(+), 45 deletions(-) diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 10ed4b965cf..4f10ca5edf2 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -33,7 +33,6 @@ api-guides/deep-sleep-stub.rst api-guides/blufi.rst api-guides/lwip.rst api-guides/coexist.rst -api-guides/flash_psram_config.rst api-guides/usb-serial-jtag-console.rst api-guides/wifi.rst api-guides/usb-otg-console.rst diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 9568af83ef8..eeb73f96028 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -2,7 +2,6 @@ api-guides/partition-tables.rst api-guides/RF_calibration.rst api-guides/deep-sleep-stub.rst api-guides/coexist.rst -api-guides/flash_psram_config.rst api-guides/wifi.rst api-guides/usb-otg-console.rst api-guides/esp-wifi-mesh.rst @@ -19,7 +18,6 @@ api-reference/peripherals/usb_host/usb_host_notes_design.rst api-reference/peripherals/usb_host/usb_host_notes_usbh.rst api-reference/peripherals/usb_device.rst api-reference/peripherals/touch_element.rst -api-reference/peripherals/spi_flash/xip_from_psram.inc api-reference/peripherals/touch_pad.rst api-reference/peripherals/adc_calibration.rst api-reference/peripherals/parlio.rst diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index d9d7e905921..39f2b402b9b 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -26,7 +26,7 @@ Hardware .. only:: esp32 or esp32s2 or esp32s3 - Some PSRAM chips are 1.8 V devices and some are 3.3 V. The working voltage of the PSRAM chip must match the working voltage of the flash component. Consult the datasheet for your PSRAM chip and {IDF_TARGET_NAME} device to find out the working voltages. For a 1.8 V PSRAM chip, make sure to either set the MTDI pin to a high signal level on bootup, or program {IDF_TARGET_NAME} eFuses to always use the VDD_SIO level of 1.8 V. Not doing this can damage the PSRAM and/or flash chip. + Some PSRAM chips are 1.8 V devices and some are 3.3 V. The working voltage of the PSRAM chip must match the working voltage of the flash component. Consult the datasheet for your PSRAM chip and {IDF_TARGET_NAME} device to find out the working voltages. For a 1.8 V PSRAM chip, make sure to either set the MTDI pin to a high signal level on boot-up, or program {IDF_TARGET_NAME} eFuses to always use the VDD_SIO level of 1.8 V. Not doing this can damage the PSRAM and/or flash chip. .. only:: esp32p4 @@ -55,8 +55,7 @@ ESP-IDF fully supports the use of external RAM in applications. Once the externa * :ref:`external_ram_config_malloc` (default) * :ref:`external_ram_config_bss` :esp32: * :ref:`external_ram_config_noinit` - :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_instructions` - :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_rodata` + :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_xip` .. _external_ram_config_memory_map: @@ -139,8 +138,6 @@ Remaining external RAM can also be added to the capability heap allocator using .. only:: esp32s2 or esp32s3 - .. _external_ram_config_instructions: - Move Instructions in Flash to PSRAM ----------------------------------- @@ -152,8 +149,6 @@ Remaining external RAM can also be added to the capability heap allocator using - The corresponding virtual memory range of those instructions will also be re-mapped to PSRAM. - .. _external_ram_config_rodata: - Move Read-Only Data in Flash to PSRAM --------------------------------------- @@ -165,6 +160,7 @@ Remaining external RAM can also be added to the capability heap allocator using - The corresponding virtual memory range of those rodata will also be re-mapped to PSRAM. + .. _external_ram_config_xip: Execute In Place (XiP) from PSRAM ------------------------------------ @@ -179,10 +175,12 @@ Remaining external RAM can also be added to the capability heap allocator using .. only:: esp32p4 + .. _external_ram_config_xip: + Execute In Place (XiP) from PSRAM ------------------------------------ - The :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` option enables the executable in place (XiP) from PSRAM feature. With this option sections that are normally placed in flash ,``.text`` (for instructions) and ``.rodata`` (for read only data), will be loaded in PSRAM. + The :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` option enables the executable in place (XiP) from PSRAM feature. With this option sections that are normally placed in flash, ``.text`` (for instructions) and ``.rodata`` (for read only data), will be loaded in PSRAM. With this option enabled, the cache will not be disabled during an SPI1 flash operation, so code that requires executing during an SPI1 flash operation does not have to be placed in internal RAM. Because P4 flash and PSRAM are using two separate SPI buses, moving flash content to PSRAM will actually increase the load of the PSRAM MSPI bus, so the exact impact on performance will be dependent on your app usage of PSRAM. For example, as the PSRAM bus speed could be much faster than flash bus speed, if the instructions and data that are used to be in flash are not accessed very frequently, you might get better performance with this option enabled. We suggest doing performance profiling to determine if enabling this option. diff --git a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index e8181236c6c..6db75246cf7 100644 --- a/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/en/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -19,7 +19,7 @@ The SPI0/1 bus is shared between the instruction & data cache (for firmware exec .. only:: SOC_SPIRAM_XIP_SUPPORTED - On {IDF_TARGET_NAME}, the config options :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` (disabled by default) and :ref:`CONFIG_SPIRAM_RODATA` (disabled by default) allow the cache to read/write PSRAM concurrently with SPI1 operations. See :ref:`xip_from_psram` for more details. + On {IDF_TARGET_NAME}, the config options :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` (disabled by default) allows the cache to read/write PSRAM concurrently with SPI1 operations. See :ref:`xip_from_psram` for more details. If these options are disabled, the caches must be disabled while reading/writing/erasing operations. There are some constraints using driver on the SPI1 bus, see :ref:`impact_disabled_cache`. These constraints will cause more IRAM/DRAM usages. @@ -40,7 +40,7 @@ Under this condition, all CPUs should always execute code and access data from i .. note:: - When :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` and :ref:`CONFIG_SPIRAM_RODATA` are both enabled, these APIs will not disable the caches. + When :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` is enabled, these APIs will not disable the caches. .. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES diff --git a/docs/en/api-reference/peripherals/spi_flash/xip_from_psram.inc b/docs/en/api-reference/peripherals/spi_flash/xip_from_psram.inc index d0af4a89be4..e4e0a6acb38 100644 --- a/docs/en/api-reference/peripherals/spi_flash/xip_from_psram.inc +++ b/docs/en/api-reference/peripherals/spi_flash/xip_from_psram.inc @@ -3,10 +3,8 @@ XIP from PSRAM Feature ---------------------- -If :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` is enabled, the flash ``.text`` sections (used for instructions) will be placed in PSRAM. +If :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` is enabled, the flash ``.text`` sections (used for instructions) and the flash ``.rodata`` sections (used for read only data) will be placed in PSRAM. -If :ref:`CONFIG_SPIRAM_RODATA` is enabled, the flash ``.rodata`` sections (used for read only data) will be placed in PSRAM. - -The corresponding virtual memory range will be re-mapped to PSRAM. +The corresponding virtual memory range will be mapped to PSRAM. If both of the above options are enabled, the Cache won't be disabled during an SPI1 Flash operation. You don't need to make sure ISRs, ISR callbacks and involved data are placed in internal RAM. diff --git a/docs/zh_CN/api-guides/external-ram.rst b/docs/zh_CN/api-guides/external-ram.rst index cfd851fdd40..864623b3116 100644 --- a/docs/zh_CN/api-guides/external-ram.rst +++ b/docs/zh_CN/api-guides/external-ram.rst @@ -55,8 +55,7 @@ ESP-IDF 完全支持将片外 RAM 集成到你的应用程序中。在启动并 * :ref:`external_ram_config_malloc` (default) * :ref:`external_ram_config_bss` :esp32: * :ref:`external_ram_config_noinit` - :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_instructions` - :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_rodata` + :SOC_SPIRAM_XIP_SUPPORTED: * :ref:`external_ram_config_xip` .. _external_ram_config_memory_map: @@ -82,7 +81,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到数据虚拟地址空间,该 在 :ref:`CONFIG_SPIRAM_USE` 中选择 ``Make RAM allocatable using heap_caps_malloc(..., MALLOC_CAP_SPIRAM)`` 选项。 -启用上述选项后,片外 RAM 被映射到数据虚拟地址空间,并将这个区域添加到携带 ``MALLOC_CAP_SPIRAM`` 标志的 :doc:`堆内存分配器 ` 。 +启用上述选项后,片外 RAM 被映射到数据虚拟地址空间,并将这个区域添加到携带 ``MALLOC_CAP_SPIRAM`` 标志的 :doc:`堆内存分配器 `。 程序如果想从片外存储器分配存储空间,则需要调用 ``heap_caps_malloc(size, MALLOC_CAP_SPIRAM)``,之后可以调用 ``free()`` 函数释放这部分存储空间。 @@ -114,7 +113,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到数据虚拟地址空间,该 通过勾选 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` 启用该选项。 -启用该选项后,PSRAM 被映射到的数据虚拟地址空间将用于存储来自 lwip、net80211、libpp, wpa_supplicant 和 bluedroid ESP-IDF 库中零初始化的数据(BSS 段)。 +启用该选项后,PSRAM 被映射到的数据虚拟地址空间将用于存储来自 lwip、net80211、libpp、wpa_supplicant 和 bluedroid ESP-IDF 库中零初始化的数据(BSS 段)。 通过将宏 ``EXT_RAM_BSS_ATTR`` 应用于任何静态声明(未初始化为非零值),可以将附加数据从内部 BSS 段移到片外 RAM。 @@ -137,35 +136,54 @@ ESP-IDF 启动过程中,片外 RAM 被映射到数据虚拟地址空间,该 .. only:: SOC_SPIRAM_XIP_SUPPORTED - .. _external_ram_config_instructions: + .. only:: esp32s2 or esp32s3 - 将 flash 中的指令移至 PSRAM - ----------------------------------- + 将 flash 中的指令移至 PSRAM + ----------------------------------- - 启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 选项后,flash 中 ``.text`` 部分的数据(用于指令)将被放入 PSRAM。 + 启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 选项后,flash 中 ``.text`` 部分的数据(用于指令)将被放入 PSRAM。 - 启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 选项后: + 启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 选项后: - - flash ``.text`` 部分中的指令将在系统启动时移至 PSRAM。 + - flash ``.text`` 部分中的指令将在系统启动时移至 PSRAM。 - - 上述指令对应的虚拟内存范围也将重新映射至 PSRAM。 + - 上述指令对应的虚拟内存范围也将重新映射至 PSRAM。 - 如果同时启用 :ref:`CONFIG_SPIRAM_RODATA`,SPI1 flash 操作期间不会禁用 cache。ISR、ISR 回调和相关数据无需放在内部 RAM 中,因此可以优化内部 RAM 的使用。 + 将 flash 中的只读数据移至 PSRAM + --------------------------------------- - .. _external_ram_config_rodata: + 启用 :ref:`CONFIG_SPIRAM_RODATA` 选项后,flash 中 ``.rodata`` 部分的数据(用于只读数据)将被放入 PSRAM。 - 将 flash 中的只读数据移至 PSRAM - --------------------------------------- + 启用 :ref:`CONFIG_SPIRAM_RODATA` 选项后: - 启用 :ref:`CONFIG_SPIRAM_RODATA` 选项后,flash 中 ``.rodata`` 部分的数据(用于只读数据)将被放入 PSRAM。 + - flash ``.rodata`` 部分中的指令将在系统启动时移至 PSRAM。 - 启用 :ref:`CONFIG_SPIRAM_RODATA` 选项后: + - 上述只读数据对应的虚拟内存范围也将重新映射至 PSRAM。 - - flash ``.rodata`` 部分中的指令将在系统启动时移至 PSRAM。 + .. _external_ram_config_xip: - - 上述只读数据对应的虚拟内存范围也将重新映射至 PSRAM。 + 在 PSRAM 中直接执行代码 + ------------------------------------ + + 启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后,可同时指定 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 和 :ref:`CONFIG_SPIRAM_RODATA` 选项。 + + 在 PSRAM 中直接执行代码的好处包括: + + - PSRAM 访问速度快于 flash,因此性能更好。 + + - 在进行 SPI1 flash 操作期间,cache 仍然保持启用状态,这样可以优化代码执行性能。由于无需把中断服务程序 (ISR)、ISR 回调和在此期间可能被访问的数据放置在片上 RAM 中,片上 RAM 可用于其他用途,从而提高了使用效率。这个特性适用于需要处理大量数据的高吞吐量外设应用,能显著提高 SPI1 flash 操作期间的性能。 + + .. only:: esp32p4 + + .. _external_ram_config_xip: + + 在 PSRAM 中直接执行代码 + ------------------------------------ + + 启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后能在 PSRAM 中直接执行代码。通常放置在 flash 中的段,如 ``.text`` 部分的数据(用于指令)和 ``.rodata`` 部分的数据(用于只读数据),将被加载到 PSRAM 中。 + + 启用此选项后,SPI1 flash 操作期间 cache 保持启用状态,因此需要执行的代码在此期间不必放置在内部 RAM 中。由于 ESP32-P4 flash 和 PSRAM 使用两个独立的 SPI 总线,将 flash 内容移动到 PSRAM 实际上增加了 PSRAM MSPI 总线的负载,因此整体性能将取决于应用程序对 PSRAM 的使用。例如,因为 PSRAM 的总线速度可能远大于 flash 总线速度,如果那些之前存放在 flash 中的指令和只读数据(现在存放于 PSRAM 中)不被经常访问,那么整体性能将有可能更好。因此,建议先进行性能分析以确定启用此选项是否会显著影响应用程序性能。 - 如果同时启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS`,SPI1 flash 操作期间不会禁用 cache。ISR、ISR 回调和相关数据无需放在内部 RAM 中,因此可以优化内部 RAM 的使用。 片外 RAM 使用限制 =================== @@ -192,7 +210,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到数据虚拟地址空间,该 初始化失败 -===================== +==================== 默认情况下,片外 RAM 初始化失败将终止 ESP-IDF 启动。如果想禁用此功能,可启用 :ref:`CONFIG_SPIRAM_IGNORE_NOTFOUND` 配置选项。 @@ -206,7 +224,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到数据虚拟地址空间,该 加密 ========== - 可以为存储在外部 RAM 中的数据启用自动加密功能。启用该功能后,通过缓存读写的任何数据将被外部存储器加密硬件自动加密/解密。 + 可以为存储在外部 RAM 中的数据启用自动加密功能。启用该功能后,通过缓存读写的任何数据将被外部存储器加密硬件自动加密、解密。 只要启用了 flash 加密功能,就会启用这个功能。关于如何启用 flash 加密以及其工作原理,请参考 :doc:`/security/flash-encryption`。 diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst index 75662fa9910..eb3b3dab14a 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/spi_flash_concurrency.rst @@ -19,7 +19,7 @@ SPI1 flash 并发约束 .. only:: SOC_SPIRAM_XIP_SUPPORTED - 在 {IDF_TARGET_NAME} 上,启用配置选项 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` (默认禁用)和 :ref:`CONFIG_SPIRAM_RODATA` (默认禁用)后将允许 flash/PSRAM 的 cache 访问和 SPI1 的操作并发执行。请参阅 :ref:`xip_from_psram`,查看详细信息。 + 在 {IDF_TARGET_NAME} 上,启用配置选项 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` (默认禁用)后将允许 flash/PSRAM 的 cache 访问和 SPI1 的操作并发执行。请参阅 :ref:`xip_from_psram`,查看详细信息。 禁用该选项时,在读取/写入/擦除 flash 期间,必须禁用 cache。使用驱动访问 SPI1 的相关约束参见 :ref:`impact_disabled_cache`。这些约束会带来更多的 IRAM/DRAM 消耗。 @@ -40,7 +40,7 @@ SPI1 flash 并发约束 .. note:: - 同时启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 和 :ref:`CONFIG_SPIRAM_RODATA` 选项后,不会禁用 cache。 + 启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后,不会禁用 cache。 .. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES diff --git a/docs/zh_CN/api-reference/peripherals/spi_flash/xip_from_psram.inc b/docs/zh_CN/api-reference/peripherals/spi_flash/xip_from_psram.inc index 0ab88d805b2..ec11ccda61b 100644 --- a/docs/zh_CN/api-reference/peripherals/spi_flash/xip_from_psram.inc +++ b/docs/zh_CN/api-reference/peripherals/spi_flash/xip_from_psram.inc @@ -3,10 +3,8 @@ 在 PSRAM 中执行代码 ---------------------- -启用 :ref:`CONFIG_SPIRAM_FETCH_INSTRUCTIONS` 选项后,flash 中 ``.text`` 部分的数据(用于指令)将被放入 PSRAM。 +启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后,flash 中 ``.text`` 部分的数据(用于指令)和 flash 中 ``.rodata`` 部分的数据(用于只读数据)将被放入 PSRAM。 -启用 :ref:`CONFIG_SPIRAM_RODATA` 选项后,flash 中 ``.rodata`` 部分的数据(用于只读数据)将被放入 PSRAM。 - -相应的虚拟内存地址将被重新映射到 PSRAM。 +相应的虚拟内存地址将被映射到 PSRAM。 如果同时启用以上两个选项,则在 SPI1 flash 操作期间 cache 不会被禁用,无需确保 ISR、ISR 回调及相关数据放置在内部 RAM 中。 From aa2290a0ae63ed53d855030c01cf0a9a094f1868 Mon Sep 17 00:00:00 2001 From: chenqingqing Date: Thu, 1 Aug 2024 11:20:58 +0800 Subject: [PATCH 540/548] fix(bt/bluedroid): Add PCM configuration about pcm frame sync signal shape --- components/bt/controller/lib_esp32 | 2 +- components/bt/include/esp32/include/esp_bt.h | 4 +++- .../bluedroid/classic_bt/hfp_ag/README.md | 15 ++++++++++++- .../classic_bt/hfp_ag/image/Channel_Mode.png | Bin 0 -> 37072 bytes .../bluedroid/classic_bt/hfp_hf/README.md | 21 ++++++++++++++---- 5 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 examples/bluetooth/bluedroid/classic_bt/hfp_ag/image/Channel_Mode.png diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index b814f26bbb3..ad0d5df0b98 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit b814f26bbb3d726418c0f80f9f91153dfd978f85 +Subproject commit ad0d5df0b9890c783c02da126df8a979e5ca1cf9 diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index ed7cfa1df2b..16b2898e7d7 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -55,7 +55,7 @@ extern "C" { * * @note Please do not modify this value. */ -#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20240315 +#define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20240722 /** * @brief Bluetooth Controller mode @@ -202,6 +202,7 @@ the adv packet will be discarded until the memory is restored. */ .ble_sca = CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF, \ .pcm_role = CONFIG_BTDM_CTRL_PCM_ROLE_EFF, \ .pcm_polar = CONFIG_BTDM_CTRL_PCM_POLAR_EFF, \ + .pcm_fsyncshp = 0, \ .hli = BTDM_CTRL_HLI, \ .dup_list_refresh_period = SCAN_DUPL_CACHE_REFRESH_PERIOD, \ .ble_scan_backoff = BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX, \ @@ -253,6 +254,7 @@ typedef struct { uint8_t ble_sca; /*!< BLE low power crystal accuracy index. Configurable in menuconfig */ uint8_t pcm_role; /*!< PCM role (master & slave). Configurable in menuconfig */ uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge). Configurable in menuconfig */ + uint8_t pcm_fsyncshp; /*!< Physical shape of the PCM Frame Synchronization signal (stereo mode & mono mode). Configurable in menuconfig */ bool hli; /*!< True if using high level interrupt; false otherwise. Configurable in menuconfig */ uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period in seconds. Configurable in menuconfig */ bool ble_scan_backoff; /*!< True if BLE scan backoff is enabled; false otherwise. Configurable in menuconfig */ diff --git a/examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md b/examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md index d00c97a9fd8..fc13dc110ad 100644 --- a/examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md +++ b/examples/bluetooth/bluedroid/classic_bt/hfp_ag/README.md @@ -43,6 +43,19 @@ The default configuration is `PCM`, if you want to use `vHCI` you should configu `Component config --> Bluetooth --> Bluedroid Options --> Hands Free/Handset Profile --> audio(SCO) data path --> HCI`. +#### PCM Signal Configurations + +PCM Signal supports two configurations in menuconfig: PCM Role, PCM Polar. + +- PCM Role: PCM role can be configured as PCM master or PCM slave. The default configuration is `Master`, you can change the PCM role in `menuconfig` path: + `Component config --> Bluetooth --> Controller Options --> PCM Signal Config(Role and Polar) --> PCM Role` + +- PCM Polar: PCM polarity can be configured as Falling Edge or Rising Edge. The default configuration is `Falling Edge`, you can change the PCM polar in `menuconfig` path: + `Component config --> Bluetooth --> Controller Options --> PCM Signal Config(Role and Polar) --> PCM Polar` + +The default configuration of PCM frame synchronization signal is `Stereo mode(Dual channel)`. FSYNC and DOUT signals both change simultaneously on the edge of CLK. The FSYNC signal continues until the end of the current channel-data transmission. As is shown in the figure ![Stereo](image/Channel_Mode.png) +The latest version of esp-idf master branch can configure three different forms(Stereo mode, Mono mode 1, Mono mode 2). + ### Codec Choice ESP32 supports two types of codec for HFP audio data: `CVSD` and `mSBC`. @@ -75,7 +88,7 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l ## Example Output -When you flash and monitor this example, the commands help table prints the following log at the very begining: +When you flash and monitor this example, the commands help table prints the following log at the very beginning: ``` Type 'help' to get the list of commands. diff --git a/examples/bluetooth/bluedroid/classic_bt/hfp_ag/image/Channel_Mode.png b/examples/bluetooth/bluedroid/classic_bt/hfp_ag/image/Channel_Mode.png new file mode 100644 index 0000000000000000000000000000000000000000..80b31499e738ad479d3566d21da9941ea3a6946d GIT binary patch literal 37072 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 literal 0 HcmV?d00001 diff --git a/examples/bluetooth/bluedroid/classic_bt/hfp_hf/README.md b/examples/bluetooth/bluedroid/classic_bt/hfp_hf/README.md index 55660bf85d4..00085198395 100644 --- a/examples/bluetooth/bluedroid/classic_bt/hfp_hf/README.md +++ b/examples/bluetooth/bluedroid/classic_bt/hfp_hf/README.md @@ -45,6 +45,19 @@ The default configuration is `PCM`, if you want to use `vHCI` you should configu `Component config --> Bluetooth --> Bluedroid Options --> Hands Free/Handset Profile --> audio(SCO) data path --> HCI`. +#### PCM Signal Configurations + +PCM Signal supports two configurations in menuconfig: PCM Role, PCM Polar. + +- PCM Role: PCM role can be configured as PCM master or PCM slave. The default configuration is `Master`, you can change the PCM role in `menuconfig` path: + `Component config --> Bluetooth --> Controller Options --> PCM Signal Config(Role and Polar) --> PCM Role` + +- PCM Polar: PCM polarity can be configured as Falling Edge or Rising Edge. The default configuration is `Falling Edge`, you can change the PCM polar in `menuconfig` path: + `Component config --> Bluetooth --> Controller Options --> PCM Signal Config(Role and Polar) --> PCM Polar` + +The default configuration of PCM frame synchronization signal is `Stereo mode(Dual channel)`. FSYNC and DOUT signals both change simultaneously on the edge of CLK. The FSYNC signal continues until the end of the current channel-data transmission. As is shown in the figure ![Stereo](../hfp_ag/image/Channel_Mode.png) +The latest version of esp-idf master branch can configure three different forms(Stereo mode, Mono mode 1, Mono mode 2). + ### Codec Choice ESP32 supports two types of codec for HFP audio data: `CVSD` and `mSBC`. @@ -53,7 +66,7 @@ ESP32 supports two types of codec for HFP audio data: `CVSD` and `mSBC`. `Component config --> Bluetooth --> Bluedroid Options --> Wide Band Speech`. -Switching on the `Wide Band Speech` means that the prefered codec is `mSBC`, but which one is actually being used also depends on the `Data Path` configuration. +Switching on the `Wide Band Speech` means that the preferred codec is `mSBC`, but which one is actually being used also depends on the `Data Path` configuration. - If you choose `PCM` for datapath, you can only use `CVSD` and hardware is responsible for the codec job. In the meanwhile, you cannot use `mSBC` by switching `Wide Band Speech` on, because the `mSBC` is implemented in the Bluedroid (Bluetooth Host Stack) by software. @@ -77,7 +90,7 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l ## Example Output -When you run this example, the explain prints the following at the very begining: +When you run this example, the explain prints the following at the very beginning: ``` Type 'help' to get the list of commands. @@ -167,7 +180,7 @@ I (133262) BT_HF: --audio state disconnected - Reject an incoming call - Disable the voice recognition -#### Choise of Codec +#### Choice of Codec ESP32 supports both CVSD and mSBC codec. HF Unit and AG device determine which codec to use by exchanging features during service level connection. The choice of codec also depends on the your configuration in `menuconfig`. @@ -268,7 +281,7 @@ I (293172) BT_HF: APP HFP event: AT_RESPONSE I (293172) BT_HF: --AT response event, code 0, cme 0 E (293702) BT_BTM: btm_sco_connected, handle 181 I (293702) BT_HF: APP HFP event: AUDIO_STATE_EVT -I (293702) BT_HF: --audio state connecte +I (293702) BT_HF: --audio state connected ``` #### Query Current Operator Name From b1c9475b714124d047add2536f52c5a8d0f2b1ce Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Tue, 9 Jul 2024 16:49:11 +0800 Subject: [PATCH 541/548] fix(bt/controller): Fixed disconnection issue - Fixed the issue of disconnection caused by updating the channel map in sniff mode --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index ad0d5df0b98..70337acad44 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit ad0d5df0b9890c783c02da126df8a979e5ca1cf9 +Subproject commit 70337acad449a838ebe8e49b92e201a82bcb9773 From 6c507056f3238fa2850048057ebcdae2ca797366 Mon Sep 17 00:00:00 2001 From: zwl Date: Mon, 19 Aug 2024 21:40:42 +0800 Subject: [PATCH 542/548] fix(ble): fixed blufi issue on ESP32-C2 --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index eefd7794e62..db84a7e4539 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit eefd7794e627dca4fa20f2d8e43385c1360d9a58 +Subproject commit db84a7e4539c5d9e6b8ec882b82a5de0fb8400c7 From 5703d604207d03bb6847c29486376dd38bfd4a38 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Wed, 14 Aug 2024 15:29:11 +0800 Subject: [PATCH 543/548] fix(bt): Update bt lib for ESP32(241c96c) - Fixed BLE vendor HCI get controller status command --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 70337acad44..f21a9ef6a4a 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 70337acad449a838ebe8e49b92e201a82bcb9773 +Subproject commit f21a9ef6a4af418621fab356755151d309aae568 From 13326df918626e61604bbaa57d0c7f7cb0f896a0 Mon Sep 17 00:00:00 2001 From: linruihao Date: Tue, 20 Aug 2024 16:21:38 +0800 Subject: [PATCH 544/548] fix(bt/controller): Fixed bluetooth disconnect issue after modem sleep on ESP32 --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index f21a9ef6a4a..3bb36a79cdf 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit f21a9ef6a4af418621fab356755151d309aae568 +Subproject commit 3bb36a79cdfad65c656b9238e0d46b935775ed72 From 475825c4367b81d43be4dcbbc21e569bf2c86064 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 27 Aug 2024 15:50:08 +0800 Subject: [PATCH 545/548] fix(psram): fixed ap3204 id check --- .../esp_psram/esp32s3/esp_psram_impl_quad.c | 101 +++++++++++------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/components/esp_psram/esp32s3/esp_psram_impl_quad.c b/components/esp_psram/esp32s3/esp_psram_impl_quad.c index 3496a90bc5f..cd76304092b 100644 --- a/components/esp_psram/esp32s3/esp_psram_impl_quad.c +++ b/components/esp_psram/esp32s3/esp_psram_impl_quad.c @@ -24,45 +24,46 @@ static const char* TAG = "quad_psram"; //Commands for PSRAM chip -#define PSRAM_READ 0x03 -#define PSRAM_FAST_READ 0x0B -#define PSRAM_FAST_READ_QUAD 0xEB -#define PSRAM_WRITE 0x02 -#define PSRAM_QUAD_WRITE 0x38 -#define PSRAM_ENTER_QMODE 0x35 -#define PSRAM_EXIT_QMODE 0xF5 -#define PSRAM_RESET_EN 0x66 -#define PSRAM_RESET 0x99 -#define PSRAM_SET_BURST_LEN 0xC0 -#define PSRAM_DEVICE_ID 0x9F - -#define PSRAM_FAST_READ_DUMMY 4 -#define PSRAM_FAST_READ_QUAD_DUMMY 6 +#define PSRAM_READ 0x03 +#define PSRAM_FAST_READ 0x0B +#define PSRAM_FAST_READ_QUAD 0xEB +#define PSRAM_WRITE 0x02 +#define PSRAM_QUAD_WRITE 0x38 +#define PSRAM_ENTER_QMODE 0x35 +#define PSRAM_EXIT_QMODE 0xF5 +#define PSRAM_RESET_EN 0x66 +#define PSRAM_RESET 0x99 +#define PSRAM_SET_BURST_LEN 0xC0 +#define PSRAM_DEVICE_ID 0x9F + +#define PSRAM_FAST_READ_DUMMY 4 +#define PSRAM_FAST_READ_QUAD_DUMMY 6 // ID -#define PSRAM_ID_KGD_M 0xff -#define PSRAM_ID_KGD_S 8 -#define PSRAM_ID_KGD 0x5d -#define PSRAM_ID_EID_M 0xff -#define PSRAM_ID_EID_S 16 - -// Use the [7:5](bit7~bit5) of EID to distinguish the psram size: +#define PSRAM_ID_BITS_NUM 24 +#define PSRAM_EID_BITS_NUM 48 +#define PSRAM_ID_KGD_M 0xff +#define PSRAM_ID_KGD_S 8 +#define PSRAM_ID_KGD 0x5d +#define PSRAM_ID_EID_BIT_47_40_M 0xff +#define PSRAM_ID_EID_BIT_47_40_S 16 + +// Use the [47:45](bit47~bit45) of EID to distinguish the psram size: // -// BIT7 | BIT6 | BIT5 | SIZE(MBIT) +// BIT47 | BIT46 | BIT45 | SIZE(MBIT) // ------------------------------------- -// 0 | 0 | 0 | 16 -// 0 | 0 | 1 | 32 -// 0 | 1 | 0 | 64 -#define PSRAM_EID_SIZE_M 0x07 -#define PSRAM_EID_SIZE_S 5 +// 0 | 0 | 0 | 16 +// 0 | 0 | 1 | 32 +// 0 | 1 | 0 | 64 +#define PSRAM_EID_BIT_47_45_M 0x07 +#define PSRAM_EID_BIT_47_45_S 5 -#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M) -#define PSRAM_EID(id) (((id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M) -#define PSRAM_SIZE_ID(id) ((PSRAM_EID(id) >> PSRAM_EID_SIZE_S) & PSRAM_EID_SIZE_M) -#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD) +#define PSRAM_KGD(id) (((id) >> PSRAM_ID_KGD_S) & PSRAM_ID_KGD_M) +#define PSRAM_EID_BIT_47_40(id) (((id) >> PSRAM_ID_EID_BIT_47_40_S) & PSRAM_ID_EID_BIT_47_40_M) +#define PSRAM_SIZE_ID(id) ((PSRAM_EID_BIT_47_40(id) >> PSRAM_EID_BIT_47_45_S) & PSRAM_EID_BIT_47_45_M) +#define PSRAM_IS_VALID(id) (PSRAM_KGD(id) == PSRAM_ID_KGD) -#define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID(id) == 0x26) -#define PSRAM_IS_2T_APS3204(id) ((((id) >> 21) && 0xfffff) == 1) +#define PSRAM_IS_64MBIT_TRIAL(id) (PSRAM_EID_BIT_47_40(id) == 0x26) // IO-pins for PSRAM. // WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these defines @@ -242,15 +243,15 @@ bool psram_support_wrap_size(uint32_t wrap_size) } //Read ID operation only supports SPI CMD and mode, should issue `psram_disable_qio_mode` before calling this -static void psram_read_id(int spi_num, uint32_t* dev_id) +static void psram_read_id(int spi_num, uint8_t* dev_id, int id_bits) { psram_exec_cmd(spi_num, PSRAM_CMD_SPI, PSRAM_DEVICE_ID, 8, /* command and command bit len*/ 0, 24, /* address and address bit len*/ 0, /* dummy bit len */ NULL, 0, /* tx data and tx bit len*/ - (uint8_t*) dev_id, 24, /* rx data and rx bit len*/ - CS_PSRAM_SEL, /* cs bit mask*/ + dev_id, id_bits, /* rx data and rx bit len*/ + CS_PSRAM_SEL, /* cs bit mask*/ false); /* whether is program/erase operation */ } @@ -303,6 +304,24 @@ static void psram_gpio_config(void) esp_gpio_reserve(BIT64(cs1_io) | BIT64(wp_io)); } +/** + * For certain wafer version and 8MB case, we consider it as 4MB mode as it uses 2T mode + */ +bool s_check_aps3204_2tmode(void) +{ + uint64_t full_eid = 0; + psram_read_id(SPI1_NUM, (uint8_t *)&full_eid, PSRAM_EID_BITS_NUM); + + bool is_2t = false; + uint32_t eid_47_16 = __builtin_bswap32((full_eid >> 16) & UINT32_MAX); + ESP_EARLY_LOGD(TAG, "full_eid: 0x%" PRIx64", eid_47_16: 0x%"PRIx32", (eid_47_16 >> 5) & 0xfffff: 0x%"PRIx32, full_eid, eid_47_16, (eid_47_16 >> 5) & 0xfffff); + if (((eid_47_16 >> 5) & 0xfffff) == 0x8a445) { + is_2t = true; + } + + return is_2t; +} + esp_err_t esp_psram_impl_enable(void) //psram init { psram_gpio_config(); @@ -313,13 +332,13 @@ esp_err_t esp_psram_impl_enable(void) //psram init //We use SPI1 to init PSRAM psram_disable_qio_mode(SPI1_NUM); - psram_read_id(SPI1_NUM, &s_psram_id); + psram_read_id(SPI1_NUM, (uint8_t *)&s_psram_id, PSRAM_ID_BITS_NUM); if (!PSRAM_IS_VALID(s_psram_id)) { /* 16Mbit psram ID read error workaround: * treat the first read id as a dummy one as the pre-condition, * Send Read ID command again */ - psram_read_id(SPI1_NUM, &s_psram_id); + psram_read_id(SPI1_NUM, (uint8_t *)&s_psram_id, PSRAM_ID_BITS_NUM); if (!PSRAM_IS_VALID(s_psram_id)) { ESP_EARLY_LOGE(TAG, "PSRAM ID read error: 0x%08" PRIx32 ", PSRAM chip not found or not supported, or wrong PSRAM line mode", (uint32_t)s_psram_id); return ESP_ERR_NOT_SUPPORTED; @@ -328,8 +347,6 @@ esp_err_t esp_psram_impl_enable(void) //psram init if (PSRAM_IS_64MBIT_TRIAL(s_psram_id)) { s_psram_size = PSRAM_SIZE_8MB; - } else if (PSRAM_IS_2T_APS3204(s_psram_id)) { - s_psram_size = PSRAM_SIZE_4MB; } else { uint8_t density = PSRAM_SIZE_ID(s_psram_id); s_psram_size = density == 0x0 ? PSRAM_SIZE_2MB : @@ -337,6 +354,10 @@ esp_err_t esp_psram_impl_enable(void) //psram init density == 0x2 ? PSRAM_SIZE_8MB : 0; } + if ((s_psram_size == PSRAM_SIZE_8MB) && s_check_aps3204_2tmode()) { + s_psram_size = PSRAM_SIZE_4MB; + } + //SPI1: send psram reset command psram_reset_mode(SPI1_NUM); //SPI1: send QPI enable command From aa754d40b83d3a19d92070ebd13019217787d3d1 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Wed, 28 Aug 2024 11:38:00 +0530 Subject: [PATCH 546/548] fix(security): Fixed flash encryption for esp32p4 The flash encryption on esp32p4 was broken due to code related to key manager not being executed when key manager support was disabled on esp32p4 target. This commit fixes that behaviour Additionally, the atomic env enablement for key_mgr_ll_enable_peripheral_clock was fixed. --- .../src/flash_encryption/flash_encrypt.c | 35 ++++++++++++------- components/esp_system/port/cpu_start.c | 19 +++++++--- components/hal/ecdsa_hal.c | 19 +++++++--- .../hal/esp32p4/include/hal/key_mgr_ll.h | 17 +++++---- components/hal/include/hal/key_mgr_types.h | 7 +--- .../esp32p4/include/soc/Kconfig.soc_caps.in | 8 +++++ components/soc/esp32p4/include/soc/soc_caps.h | 4 ++- 7 files changed, 71 insertions(+), 38 deletions(-) diff --git a/components/bootloader_support/src/flash_encryption/flash_encrypt.c b/components/bootloader_support/src/flash_encryption/flash_encrypt.c index 850fcb99841..85697dbeb3b 100644 --- a/components/bootloader_support/src/flash_encryption/flash_encrypt.c +++ b/components/bootloader_support/src/flash_encryption/flash_encrypt.c @@ -16,11 +16,15 @@ #include "esp_log.h" #include "hal/wdt_hal.h" -#if SOC_KEY_MANAGER_SUPPORTED -#include "hal/key_mgr_hal.h" -#include "hal/mspi_timing_tuning_ll.h" +#if SOC_KEY_MANAGER_FE_KEY_DEPLOY || CONFIG_IDF_TARGET_ESP32C5 +#if CONFIG_IDF_TARGET_ESP32C5 #include "soc/keymng_reg.h" -#endif +#include "soc/pcr_reg.h" +#else /* CONFIG_IDF_TARGET_ESP32C5 */ +#include "hal/key_mgr_ll.h" +#include "hal/mspi_timing_tuning_ll.h" +#endif /* !CONFIG_IDF_TARGET_ESP32C5 */ +#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */ #ifdef CONFIG_SOC_EFUSE_CONSISTS_OF_ONE_KEY_BLOCK #include "soc/sensitive_reg.h" @@ -217,18 +221,25 @@ static esp_err_t check_and_generate_encryption_keys(void) ESP_LOGI(TAG, "Using pre-loaded flash encryption key in efuse"); } -#if SOC_KEY_MANAGER_SUPPORTED -#if CONFIG_IDF_TARGET_ESP32C5 && SOC_KEY_MANAGER_SUPPORTED - // TODO: [ESP32C5] IDF-8622 find a more proper place for these codes - REG_SET_BIT(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY_FLASH); +#if SOC_KEY_MANAGER_FE_KEY_DEPLOY || CONFIG_IDF_TARGET_ESP32C5 +#if CONFIG_IDF_TARGET_ESP32C5 + REG_SET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY, 2); REG_SET_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); REG_CLR_BIT(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); -#endif +#else /* CONFIG_IDF_TARGET_ESP32C5 */ + // Enable and reset key manager + // To suppress build errors about spinlock's __DECLARE_RCC_ATOMIC_ENV + int __DECLARE_RCC_ATOMIC_ENV __attribute__ ((unused)); + key_mgr_ll_enable_bus_clock(true); + key_mgr_ll_enable_peripheral_clock(true); + key_mgr_ll_reset_register(); + while (key_mgr_ll_get_state() != ESP_KEY_MGR_STATE_IDLE) { + }; // Force Key Manager to use eFuse key for XTS-AES operation - key_mgr_hal_set_key_usage(ESP_KEY_MGR_XTS_AES_128_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); + key_mgr_ll_set_key_usage(ESP_KEY_MGR_XTS_AES_128_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); _mspi_timing_ll_reset_mspi(); -#endif - +#endif /* !CONFIG_IDF_TARGET_ESP32C5 */ +#endif /* SOC_KEY_MANAGER_FE_KEY_DEPLOY */ return ESP_OK; } diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 649007cdfaa..6fbe2ff95d3 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -71,8 +71,8 @@ #include "soc/hp_sys_clkrst_reg.h" #endif -#if SOC_KEY_MANAGER_SUPPORTED -#include "hal/key_mgr_hal.h" +#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY || SOC_KEY_MANAGER_FE_KEY_DEPLOY +#include "hal/key_mgr_ll.h" #endif #include "esp_private/rtc_clk.h" @@ -309,13 +309,22 @@ static void start_other_core(void) } #endif -#if SOC_KEY_MANAGER_SUPPORTED // The following operation makes the Key Manager to use eFuse key for ECDSA and XTS-AES operation by default // This is to keep the default behavior same as the other chips // If the Key Manager configuration is already locked then following operation does not have any effect - key_mgr_hal_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); - key_mgr_hal_set_key_usage(ESP_KEY_MGR_XTS_AES_128_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); +#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY || SOC_KEY_MANAGER_FE_KEY_DEPLOY + // Enable key manager clock + // Using ll APIs which do not require critical section + _key_mgr_ll_enable_bus_clock(true); + _key_mgr_ll_enable_peripheral_clock(true); +#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY + key_mgr_ll_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); #endif +#if SOC_KEY_MANAGER_FE_KEY_DEPLOY + key_mgr_ll_set_key_usage(ESP_KEY_MGR_XTS_AES_128_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); +#endif +#endif /* SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY || SOC_KEY_MANAGER_FE_KEY_DEPLOY */ + ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); bool cpus_up = false; diff --git a/components/hal/ecdsa_hal.c b/components/hal/ecdsa_hal.c index 552fb423af0..73302b1f43f 100644 --- a/components/hal/ecdsa_hal.c +++ b/components/hal/ecdsa_hal.c @@ -9,7 +9,11 @@ #include "hal/ecdsa_hal.h" #include "hal/efuse_hal.h" -#ifdef SOC_KEY_MANAGER_SUPPORTED +#if CONFIG_IDF_TARGET_ESP32C5 +#include "soc/keymng_reg.h" +#endif + +#ifdef SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY #include "hal/key_mgr_hal.h" #endif @@ -19,16 +23,21 @@ static void configure_ecdsa_periph(ecdsa_hal_config_t *conf) { - if (conf->use_km_key == 0) { efuse_hal_set_ecdsa_key(conf->efuse_key_blk); -#if SOC_KEY_MANAGER_SUPPORTED - key_mgr_hal_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); + +#if CONFIG_IDF_TARGET_ESP32C5 + REG_SET_FIELD(KEYMNG_STATIC_REG, KEYMNG_USE_EFUSE_KEY, 1); +#endif + +#if SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY + // Force Key Manager to use eFuse key for XTS-AES operation + key_mgr_ll_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_EFUSE_KEY); #endif } #if SOC_KEY_MANAGER_SUPPORTED else { - key_mgr_hal_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_OWN_KEY); + key_mgr_ll_set_key_usage(ESP_KEY_MGR_ECDSA_KEY, ESP_KEY_MGR_USE_OWN_KEY); } #endif diff --git a/components/hal/esp32p4/include/hal/key_mgr_ll.h b/components/hal/esp32p4/include/hal/key_mgr_ll.h index 1d6d05eba57..15923a67ffa 100644 --- a/components/hal/esp32p4/include/hal/key_mgr_ll.h +++ b/components/hal/esp32p4/include/hal/key_mgr_ll.h @@ -10,9 +10,7 @@ ******************************************************************************/ #pragma once -#include "soc/soc_caps.h" -#if SOC_KEY_MANAGER_SUPPORTED #include #include #include @@ -21,7 +19,6 @@ #include "hal/key_mgr_types.h" #include "soc/keymng_reg.h" #include "soc/hp_sys_clkrst_struct.h" -#include "soc/soc_caps.h" #ifdef __cplusplus extern "C" { @@ -29,29 +26,32 @@ extern "C" { /** * @brief Enable the bus clock for Key Manager peripheral - * + * Note: Please use key_mgr_ll_enable_bus_clock which requires the critical section + * and do not use _key_mgr_ll_enable_bus_clock * @param true to enable, false to disable */ -static inline void key_mgr_ll_enable_bus_clock(bool enable) +static inline void _key_mgr_ll_enable_bus_clock(bool enable) { HP_SYS_CLKRST.soc_clk_ctrl1.reg_key_manager_sys_clk_en = enable; } /// use a macro to wrap the function, force the caller to use it in a critical section /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance -#define key_mgr_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; key_mgr_ll_enable_bus_clock(__VA_ARGS__) +#define key_mgr_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _key_mgr_ll_enable_bus_clock(__VA_ARGS__) /** * @brief Enable the peripheral clock for Key Manager * + * Note: Please use key_mgr_ll_enable_peripheral_clock which requires the critical section + * and do not use _key_mgr_ll_enable_peripheral_clock * @param true to enable, false to disable */ -static inline void key_mgr_ll_enable_peripheral_clock(bool enable) +static inline void _key_mgr_ll_enable_peripheral_clock(bool enable) { HP_SYS_CLKRST.peri_clk_ctrl25.reg_crypto_km_clk_en = enable; } -#define key_mgr_ll_enable_peripheral_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; key_mgr_ll_enable_bus_clock(__VA_ARGS__) +#define key_mgr_ll_enable_peripheral_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _key_mgr_ll_enable_peripheral_clock(__VA_ARGS__) /** * @brief Reset the Key Manager peripheral */ @@ -345,4 +345,3 @@ static inline uint32_t key_mgr_ll_get_date_info(void) #ifdef __cplusplus } #endif -#endif diff --git a/components/hal/include/hal/key_mgr_types.h b/components/hal/include/hal/key_mgr_types.h index 82064e58d4a..31ea39aeb4d 100644 --- a/components/hal/include/hal/key_mgr_types.h +++ b/components/hal/include/hal/key_mgr_types.h @@ -5,9 +5,6 @@ */ #pragma once -#include "soc/soc_caps.h" - -#if SOC_KEY_MANAGER_SUPPORTED #include #include #include @@ -24,7 +21,7 @@ extern "C" { */ typedef enum { ESP_KEY_MGR_STATE_IDLE = 0, /* Key Manager is idle */ - ESP_KEY_MGR_STATE_LOAD = 1, /* Key Manager is ready to recieve input */ + ESP_KEY_MGR_STATE_LOAD = 1, /* Key Manager is ready to receive input */ ESP_KEY_MGR_STATE_GAIN = 2, /* Key Manager is ready to provide output */ ESP_KEY_MGR_STATE_BUSY = 3, /* Key Manager is busy */ } esp_key_mgr_state_t; @@ -114,5 +111,3 @@ typedef struct WORD_ALIGNED_ATTR PACKED_ATTR { #ifdef __cplusplus } #endif - -#endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 1201d5df241..e55ced27f02 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1483,6 +1483,14 @@ config SOC_EFUSE_ECDSA_KEY bool default y +config SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY + bool + default y + +config SOC_KEY_MANAGER_FE_KEY_DEPLOY + bool + default y + config SOC_SECURE_BOOT_V2_RSA bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 452329f0195..71d88b890a2 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -582,6 +582,9 @@ #define SOC_EFUSE_DIS_DOWNLOAD_MSPI 1 #define SOC_EFUSE_ECDSA_KEY 1 +/*-------------------------- Key Manager CAPS----------------------------*/ +#define SOC_KEY_MANAGER_ECDSA_KEY_DEPLOY 1 /*!< Key manager responsible to deploy ECDSA key */ +#define SOC_KEY_MANAGER_FE_KEY_DEPLOY 1 /*!< Key manager responsible to deploy Flash Encryption key */ /*-------------------------- Secure Boot CAPS----------------------------*/ #define SOC_SECURE_BOOT_V2_RSA 1 #define SOC_SECURE_BOOT_V2_ECC 1 @@ -595,7 +598,6 @@ #define SOC_FLASH_ENCRYPTION_XTS_AES_OPTIONS 1 #define SOC_FLASH_ENCRYPTION_XTS_AES_128 1 #define SOC_FLASH_ENCRYPTION_XTS_AES_256 1 - /*-------------------------- MEMPROT CAPS ------------------------------------*/ /*-------------------------- UART CAPS ---------------------------------------*/ From c8fc5f643b7a7b0d3b182d3df610844e3dc9bd74 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Tue, 3 Sep 2024 09:37:24 +0800 Subject: [PATCH 547/548] change(version): Update version to 5.3.1 --- .gitlab/ci/common.yml | 2 +- components/esp_common/include/esp_idf_version.h | 2 +- tools/cmake/version.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/common.yml b/.gitlab/ci/common.yml index 4381cea9703..912f706da41 100644 --- a/.gitlab/ci/common.yml +++ b/.gitlab/ci/common.yml @@ -39,7 +39,7 @@ variables: GIT_FETCH_EXTRA_FLAGS: "--no-recurse-submodules --prune --prune-tags" # we're using .cache folder for caches GIT_CLEAN_FLAGS: -ffdx -e .cache/ - LATEST_GIT_TAG: v5.3 + LATEST_GIT_TAG: v5.3.1 SUBMODULE_FETCH_TOOL: "tools/ci/ci_fetch_submodule.py" # by default we will fetch all submodules diff --git a/components/esp_common/include/esp_idf_version.h b/components/esp_common/include/esp_idf_version.h index 4cb488257a4..d3e010a20ea 100644 --- a/components/esp_common/include/esp_idf_version.h +++ b/components/esp_common/include/esp_idf_version.h @@ -15,7 +15,7 @@ extern "C" { /** Minor version number (x.X.x) */ #define ESP_IDF_VERSION_MINOR 3 /** Patch version number (x.x.X) */ -#define ESP_IDF_VERSION_PATCH 0 +#define ESP_IDF_VERSION_PATCH 1 /** * Macro to convert IDF version number into an integer diff --git a/tools/cmake/version.cmake b/tools/cmake/version.cmake index 4db536bdaa5..e01881ca4db 100644 --- a/tools/cmake/version.cmake +++ b/tools/cmake/version.cmake @@ -1,5 +1,5 @@ set(IDF_VERSION_MAJOR 5) set(IDF_VERSION_MINOR 3) -set(IDF_VERSION_PATCH 0) +set(IDF_VERSION_PATCH 1) set(ENV{IDF_VERSION} "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}.${IDF_VERSION_PATCH}") From 52031f249c9dbf17b6f2c651a6e2f24a9db48991 Mon Sep 17 00:00:00 2001 From: IhorNehrutsa Date: Thu, 14 Nov 2024 00:49:53 +0200 Subject: [PATCH 548/548] examples/ledc_check.c: Check freq and duty. --- .../ledc/ledc_check/CMakeLists.txt | 6 + .../ledc/ledc_check/main/CMakeLists.txt | 2 + .../ledc/ledc_check/main/ledc_check.c | 130 ++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 examples/peripherals/ledc/ledc_check/CMakeLists.txt create mode 100644 examples/peripherals/ledc/ledc_check/main/CMakeLists.txt create mode 100755 examples/peripherals/ledc/ledc_check/main/ledc_check.c diff --git a/examples/peripherals/ledc/ledc_check/CMakeLists.txt b/examples/peripherals/ledc/ledc_check/CMakeLists.txt new file mode 100644 index 00000000000..6fd196565b1 --- /dev/null +++ b/examples/peripherals/ledc/ledc_check/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ledc) diff --git a/examples/peripherals/ledc/ledc_check/main/CMakeLists.txt b/examples/peripherals/ledc/ledc_check/main/CMakeLists.txt new file mode 100644 index 00000000000..89e84133bb2 --- /dev/null +++ b/examples/peripherals/ledc/ledc_check/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "ledc_check.c" + INCLUDE_DIRS ".") diff --git a/examples/peripherals/ledc/ledc_check/main/ledc_check.c b/examples/peripherals/ledc/ledc_check/main/ledc_check.c new file mode 100755 index 00000000000..3243a0ebcdf --- /dev/null +++ b/examples/peripherals/ledc/ledc_check/main/ledc_check.c @@ -0,0 +1,130 @@ +/* LEDC (LED Controller) basic example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include "driver/ledc.h" +#include "esp_err.h" + +#include "freertos/FreeRTOS.h" +#include "esp_clk_tree.h" + +#define CHECK_SET 0 // 1 +#if CHECK_SET != 0 +Add to the esp-idf/components/esp_driver_ledc/include/driver/ledc.h +uint32_t ledc_calculate_divisor(uint32_t src_clk_freq, int freq_hz, uint32_t precision); +#endif + +#define CHECK_ALL 0 // 1 +#define FDIV 1 // 2 // 5 +#define DELAY_ms 500 // 3000 + +#undef ESP_ERROR_CHECK +#define ESP_ERROR_CHECK(err) do {if (err != ESP_OK) {printf("freq=%lu, err=%d, LINE=%d\n", freq, err, __LINE__);} } while (0); + +#define LEDC_OUTPUT_IO (26) // Define the output GPIO +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_HIGH_SPEED_MODE // LEDC_LOW_SPEED_MODE // +#define LEDC_CHANNEL LEDC_CHANNEL_0 + +#define LEDC_DUTY ((1UL << timer.duty_resolution) / 2) // 50% +/* Warning: + * For ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, ESP32P4 targets, + * when LEDC_DUTY_RES selects the maximum duty resolution (i.e. value equal to SOC_LEDC_TIMER_BIT_WIDTH), + * 100% duty cycle is not reachable (duty cannot be set to (2 ** SOC_LEDC_TIMER_BIT_WIDTH)). + */ + +#define FREQ_PERCENT (10) +#define DUTY_PERCENT (10) + +ledc_timer_config_t timer; +ledc_channel_config_t channel; + +static void check(uint32_t freq) +{ + printf("freq=%lu \t", freq); + + // Set the LEDC peripheral configuration + uint32_t src_clk_freq; + ESP_ERROR_CHECK(esp_clk_tree_src_get_freq_hz(LEDC_USE_APB_CLK, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &src_clk_freq)); + // Prepare and then apply the LEDC PWM timer configuration + timer = (ledc_timer_config_t){ + .speed_mode = LEDC_MODE, + .timer_num = LEDC_TIMER, + .duty_resolution = ledc_find_suitable_duty_resolution(src_clk_freq, freq), + .freq_hz = freq, + .clk_cfg = LEDC_USE_APB_CLK + }; + ESP_ERROR_CHECK(ledc_timer_config(&timer)); + + // Prepare and then apply the LEDC PWM channel configuration + channel = (ledc_channel_config_t){ + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = LEDC_OUTPUT_IO, + .duty = LEDC_DUTY, + .hpoint = 0 + }; + ESP_ERROR_CHECK(ledc_channel_config(&channel)); + + #if CHECK_SET + uint32_t divider = ledc_calculate_divisor(src_clk_freq, timer.freq_hz, 0x1 << timer.duty_resolution); + ESP_ERROR_CHECK(ledc_timer_set(timer.speed_mode, timer.timer_num, divider, timer.duty_resolution, timer.clk_cfg)); + + // Set duty + ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY)); + // Update duty to apply the new value + ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); + #endif + + vTaskDelay((2000 / freq) / portTICK_PERIOD_MS); + + uint32_t get_freq = ledc_get_freq(LEDC_MODE, LEDC_CHANNEL); + float freq_percent = 100.0 * fabs((float)timer.freq_hz - get_freq) / timer.freq_hz; + uint32_t get_duty = ledc_get_duty(LEDC_MODE, LEDC_CHANNEL); + float duty_percent = 100.0 * fabs((float)channel.duty - get_duty) / channel.duty; + + //if ((timer.freq_hz != get_freq) || (channel.duty != get_duty)) { + if ((freq_percent >= FREQ_PERCENT) || (duty_percent >= DUTY_PERCENT)) { + printf("%6.2f%% timer.freq_hz=%lu, get_freq=%lu, \t\t %6.2f%% channel.duty=%lu, get_duty=%lu \t\t timer.duty_resolution=%u\n", + freq_percent, timer.freq_hz, get_freq, + duty_percent, channel.duty, get_duty, + timer.duty_resolution); + } else { + printf("\n"); + } +} + +void app_main(void) { + uint32_t freq; + for(freq=1; freq<=40000000; freq+=1) { + #if CHECK_ALL != 1 + if (freq > 10000000) + freq += 10000000 / FDIV - 1; + else if (freq > 1000000) + freq += 1000000 / FDIV - 1; + else if (freq > 100000) + freq += 100000 / FDIV - 1; + else if (freq > 10000) + freq += 10000 / FDIV - 1; + else if (freq > 1000) + freq += 1000 / FDIV - 1; + else if (freq > 100) + freq += 100 / FDIV - 1; + else if (freq > 10) + freq += 10 / FDIV - 1; + #endif + + check(freq); + + vTaskDelay(DELAY_ms / portTICK_PERIOD_MS); + } + printf("END.\n"); +}

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 X`rkLe{;0`@4G=eF6mMin>3aVkDoTAW literal 0 HcmV?d00001 diff --git a/docs/_static/itwt_setup.png b/docs/_static/itwt_setup.png new file mode 100644 index 0000000000000000000000000000000000000000..0aa68878e1b282d2a5cdd05536a854c9989d8a16 GIT binary patch literal 48712 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 literal 0 HcmV?d00001 diff --git a/docs/_static/itwt_suspend.png b/docs/_static/itwt_suspend.png new file mode 100644 index 0000000000000000000000000000000000000000..c49403313e32765cb7a2ca48149b2b5abd8cae06 GIT binary patch literal 43566 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 PcQc+iZ9>$zg}?t_PRQIk literal 0 HcmV?d00001 diff --git a/docs/_static/itwt_teardown.png b/docs/_static/itwt_teardown.png new file mode 100644 index 0000000000000000000000000000000000000000..c3c6805e32baaf51fddad77a432c872a018747e1 GIT binary patch literal 38537 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 literal 0 HcmV?d00001 diff --git a/docs/zh_CN/api-guides/low-power-mode.rst b/docs/zh_CN/api-guides/low-power-mode.rst index c18605473a7..a1fd881f0fe 100644 --- a/docs/zh_CN/api-guides/low-power-mode.rst +++ b/docs/zh_CN/api-guides/low-power-mode.rst @@ -743,3 +743,293 @@ Deep-sleep 有如下可配置选项: .. only:: esp32c2 平均电流约 4.9 μA + +.. only:: esp32c6 + + 目标唤醒时间 (TWT) + ---------------------------------- + + 目标唤醒时间 (Target Wake Time, TWT) 是 Wi-Fi 6 中引入的一项特性,旨在降低设备功耗和提高网络效率。 + + 在以往的 Wi-Fi 节能机制中,设备可能需要在每个 DTIM 周期醒来与 AP 交换数据,而在 TWT 机制中支持 AP 和设备协商得到特定的唤醒时间,设备会在这些时间点醒来与 AP 进行数据交换,而其余时间则处于休眠状态。TWT 协商的唤醒和休眠时间取决于设备具体的应用需求。例如,有些传感器设备需要定时上传数据,在该场景下设备可以与 AP 建立 TWT 协商,相隔多个小时交换一次数据。实际应用中可根据具体需求定制唤醒时间,在不影响设备正常工作的情况下降低功耗。 + + AP 可以与多个设备建立 TWT 协商。利用 Wi-Fi 6 的多用户特性,AP 可以对上行和下行数据传输做出合理协调,从而减少信道竞争,提高传输效率。 + + TWT 类型 + ++++++++++ + + 根据协商类型和工作模式,可以把 TWT 分为: + + - **Individual TWT (iTWT)** + + iTWT 模式下,AP 与终端设备建立的是一对一的 TWT 协商。 + + - **Broadcast TWT (bTWT)** + + 在 bTWT 模式下,AP 通过 Beacon 帧广播 TWT 信息,以组的形式来管理多个终端设备的 TWT 过程。终端设备可以根据 Beacon 中的 TWT 信息选择执行加组操作。 + + .. note:: + 在建立 TWT 协商前,需要确认 AP 是否支持并开启了 TWT 功能。{IDF_TARGET_NAME} 当前只支持 iTWT 模式。 + + TWT 工作流程 + ++++++++++++ + TWT 工作流程一般分为 TWT 协商建立、TWT 协商暂停/恢复、TWT 协商终止。TWT 协商建立后,Station 就可以按照协商的参数进入休眠状态,直到约定好的下一个 TWT 时间点到来时苏醒。 + 对已经建立的 TWT,用户可以根据需求协商暂停/恢复 TWT 或者终止 TWT。 + + - TWT 协商建立 + + - Individual TWT 协商建立 + + 在 iTWT 协商建立过程中,通常由 Station 充当请求发起方发送 TWT 请求,而后 AP 作为接收方对该请求做出回应。AP 也可以主动向 Station 发起 TWT 协商建立过程。 + 在成功建立起 iTWT 协商后,Station 可以进入休眠状态,直到约定好的下一个 TWT 时间点到来时苏醒,该时间点通过和 AP 间的协商得到。Station 醒来后和 AP 进行数据交换,这段时间被称为 TWT 服务时间 (Service Period, SP)。 + TWT SP 的持续时间被称为 TWT Wake Duration,其最小值为 256 微秒。当一次 TWT SP 结束后,Station 进入休眠状态直到下次 TWT SP 醒来进行数据传输。本次 TWT SP 的起始到下次 TWT SP 的起始的时间间隔被称为 TWT Wake Interval。下图为基本的 iTWT 示例: + + .. figure:: ../../_static/itwt_setup.png + :align: center + + Individual TWT 协商建立过程示例 + + Station 在 iTWT 协商建立时可以发送不同类型的请求,AP 会根据请求类型及参数做出对应的回复。用户需要根据 AP 回复中的类型和具体参数决定后续的操作逻辑。Station 所发送的请求类型有 ``Request``、``Suggest`` 和 ``Demand``。 + AP 的回复类型可分为 ``Accept``、``Alternate`` 和 ``Dictate``。下表描述了发送不同请求时 AP 可能的回复以及不同情况下对应的含义: + + .. list-table:: + :header-rows: 1 + :widths: 20 10 40 + + * - 请求类型 + - AP 回复 + - 含义 + * - Request, Suggest or Demand + - No response + - 在该情况下 AP 不会与 Station 建立 iTWT 协商。 + * - Suggest or Request + - Accept + - AP 同意建立 iTWT 协商,其使用的参数以回复中 TWT 参数为准。回复中的 TWT 参数有可能与请求中不一致。 + * - Demand + - Accept + - AP 同意建立 iTWT 协商,且回复中的 TWT 参数与请求中的一致。 + * - Demand or Suggest + - Alternate + - AP 使用该回复类型代表给 Station提供一组备选 TWT 参数,此时不会建立 iTWT 协商。后续 Station 可以发送新的请求,但 AP 仍有可能使用该组参数。 + * - Demand or Suggest + - Dictate + - AP 使用该回复类型代表给 Station 提供一组备选 TWT 参数,此时不会建立 iTWT 协商,同时也表明 AP 不接受除该组参数以外的其他参数。后续 Station 可以发送新的请求,但只有参数与所提供的备选参数一致才会收到 Accept 回复。 + * - Request, Suggest or Demand + - Reject + - 在该情况下 AP 不会与 station 建立 iTWT 协商。后续 Station 可以更改 TWT 参数发送新的请求。 + + 在 TWT SP 中依照数据交互时的操作可以将 TWT 进一步地细分为多种类型,下表描述了这些类型间的差异: + + .. list-table:: + :header-rows: 1 + :widths: 10 20 + + * - Types + - 含义 + * - Trigger-enabled + - AP 会在 SP 中使用 Trigger 帧来协调 Station 的数据传输。 + * - Non trigger-enabled + - 在 SP 中不需要使用 Trigger 帧。 + * - Announced + - Station 会发送 QoS Null 帧告知 AP 其唤醒状态。 + * - Unannounced + - 不需要发送 QoS Null 帧。 + + - Broadcast TWT 协商建立 + + 与 iTWT 不同的是,在 bTWT 模式下 AP 将 TWT 信息放在 Beacon 帧中进行广播宣告。Station 接收到 Beacon 后,可以向 AP 发送请求申请选择加入某个 TWT。 + 当建立起 bTWT 协商后, Station 和 AP 会在协商好的 TWT SP 中进行数据传输。 + + 与 iTWT 类似,可以把 bTWT 进一步分成 Trigger-enabled 和 Non trigger-enabled 类型,以及 Announced 和 Unannounced 类型,具体的行为差异可以参考 iTWT 中的描述。 + + - TWT 协商暂停/恢复 + + 建立起 TWT 协商后, Station 可以通过向 AP 发送 TWT Information 帧暂停或者恢复指定的 TWT 协商。由 flow_id 来标识需要暂停或者恢复的 TWT 协商,具体可以参考 TWT 参数配置。 + + .. figure:: ../../_static/itwt_suspend.png + :align: center + + Individual TWT 协商暂停/恢复过程示例 + + - TWT 协商终止 + + 建立起 TWT 协商后, Station 可以通过向 AP 发送 TWT Teardown 帧终止指定的 TWT 协商。由 flow_id 来标识需要终止的 TWT 协商,具体可以参考 TWT 参数配置。 + + .. figure:: ../../_static/itwt_teardown.png + :align: center + + Individual TWT 协商终止过程示例 + + TWT 参数配置 + ++++++++++++ + + 在使用过程中,需要配置 TWT 和低功耗模式的相关参数,其中低功耗模式相关参数决定了设备在休眠状态下的行为模式。本小节将主要阐述如何配置 TWT,有关低功耗模式下的参数配置,请参考 `如何配置 Wi-Fi 场景下低功耗模式`_。 + + - Individual TWT 参数配置 + + 在建立 Station 和 AP 间的 iTWT 时,使用 :component_file:`esp_wifi/include/esp_wifi_he_types.h` 中定义的结构体 :cpp:type:`wifi_twt_setup_config_t` 来配置 TWT 的相关参数,其定义如下: + + .. code-block:: C + + typedef struct + { + wifi_twt_setup_cmds_t setup_cmd; + uint16_t trigger :1; + uint16_t flow_type :1; + uint16_t flow_id :3; + uint16_t wake_invl_expn :5; + uint16_t wake_duration_unit :1; + uint16_t reserved :5; + uint8_t min_wake_dura; + uint16_t wake_invl_mant; + uint16_t twt_id; + uint16_t timeout_time_ms; + } wifi_twt_setup_config_t; + + :cpp:type:`wifi_twt_setup_config_t` 中各个字段的含义如下: + + .. list-table:: + :header-rows: 1 + :widths: 15 45 + :align: center + + * - 字段 + - 描述 + * - setup_cmd + - 指示了 TWT 建立时请求和回复使用的命令类型,具体类型请参阅 :cpp:type:`wifi_twt_setup_cmds_t` 。 + * - trigger + - 值为 1 时配置 TWT 类型为 Trigger-enabled,值为 0 时配置为 Non trigger-enabled。 + * - flow_type + - 值为 1 时配置 TWT 类型为 Unannounced,值为 0 时配置为 Announced。 + * - flow_id + - 当建立起一个 iTWT 协商后,AP 会为其分配 flow_id。Station 在协商建立请求中可以指定 flow_id,但在 AP 的回复中该字段可能会被改变。 + * - wake_invl_expn + - TWT Wake Interval 指数部分。 + * - wake_duration_unit + - TWT Wake Duration 计数单元。为 0 代表 256 微秒,为 1 代表以 TU (1024 微秒) 为单位。 + * - reserved + - 保留字段。 + * - min_wake_dura + - 该字段代表 Station 期望处于唤醒状态的时间,以 ``wake_duration_unit`` 作为基本单位。 + * - wake_invl_mant + - TWT Wake Interval 尾数部分。 + * - twt_id + - TWT 配置标识。在发起多个 TWT 请求时,该字段用于在 handler 中区分不同的 TWT 参数配置。 + * - timeout_time_ms + - TWT 请求超时时间,单位为毫秒。 + + 需要指出的是,Station 在协商中所期望的 TWT Wake Interval 为 wake_invl_mant * 2\ :sup:`wake_invl_expn`\,单位是微秒。 + 而所期望的 TWT Wake Duration 为 min_wake_dura * wake_duration_unit。 + + .. note:: + 注意, TWT Wake Interval 和 TWT Wake Duration 的差值需要大于 10 毫秒。 + + 配置示例如下: + + .. code-block:: C + + wifi_twt_setup_config_t setup_config = { + .setup_cmd = TWT_REQUEST, + .flow_id = 0, + .twt_id = 0, + .flow_type = 0, + .min_wake_dura = 255, + .wake_duration_unit = 0, + .wake_invl_expn = 10, + .wake_invl_mant = 512, + .trigger = 1, + .timeout_time_ms = 5000, + }; + + 以上配置指定建立 TWT 请求时使用的类型为 Trigger-enabled,Announced,期望的 TWT Wake Interval 为 524288 微秒, TWT Wake Duration 为 65280 微秒。配置好 :cpp:type:`wifi_twt_setup_config_t` 后,调用 API :cpp:func:`esp_wifi_sta_itwt_setup` 向 AP 发起 iTWT 建立请求。 + + .. note:: + {IDF_TARGET_NAME} 支持用户调用 API :cpp:func:`esp_wifi_sta_itwt_set_target_wake_time_offset` 配置相对于目标唤醒时间的偏移时间。 + + TWT 事件 + ++++++++++ + + - WIFI_EVENT_ITWT_SETUP + + 发送请求后,用户可以在 :cpp:enumerator:`WIFI_EVENT_ITWT_SETUP` 事件的对应处理程序中获取请求结果并自定义处理逻辑。事件结果保存在 :cpp:type:`wifi_event_sta_itwt_setup_t` 结构体中,其成员变量 status 指示了此次事件的状态。 + 当 status 为 :c:macro:`ITWT_SETUP_SUCCESS` 时代表请求成功收到了对应回复,为其他值代表请求失败。在得到请求成功的状态后,用户可以从该结构体中的 config 成员变量中得到 AP 回复中的具体参数,并根据具体参数决定后续的处理逻辑。 + 例如,Station 发送了类型为 Demand 的 TWT 请求,收到 AP 的回复类型为 Dictate,用户此时可以考察回复中的 TWT 参数是否可行,若可行便可以发送一个新的 TWT 请求与 AP 继续建立 TWT 协商,并且该请求中的 TWT 参数需要与 AP 回复中一致。 + + 在 Station 未主动发送请求时也有可能触发 :cpp:enumerator:`WIFI_EVENT_ITWT_SETUP` 事件,这种情况下对应的是 AP 主动向 Station 发起 iTWT 协商建立过程,此时 AP 向 Station 发送的帧中会带有 TWT 参数。同样地,用户可以在 :cpp:enumerator:`WIFI_EVENT_ITWT_SETUP` 事件的对应处理程序中获取结果并自定义处理逻辑。 + 用户需要检查 config 成员变量中 AP 发送的 TWT 参数类型,一般有两种情况: + 1. AP 发送的 TWT 参数为 Accept 类型,此时 Station 会与 AP 建立起使用该 TWT 参数的 iTWT 协商。若用户不希望建立此 iTWT 协商,可以向 AP 发送 Teardown 帧。 + 2. AP 发送的 TWT 参数为 Alternate 或 Dictate 类型,此时 Station 不会与 AP 建立起 iTWT 协商,但可以在接下来使用该参数向 AP 发起 iTWT 协商建立请求。 + + - WIFI_EVENT_ITWT_SUSPEND + + 在调用 API :cpp:func:`esp_wifi_sta_itwt_suspend` 请求暂停已经建立的 iTWT 协商时, 用户可以在 :cpp:enumerator:`WIFI_EVENT_ITWT_SUSPEND` 事件的对应处理程序中获取请求结果并自定义处理逻辑。事件结果保存在 :cpp:type:`wifi_event_sta_itwt_suspend_t` 结构体中,其成员变量 status 指示了此次事件的状态。 + 当 status 为 :c:macro:`ESP_OK` 时代表成功暂停了指定的 iTWT 协商,为其他值代表请求暂停失败。 + + .. note:: + 注意,调用 API :cpp:func:`esp_wifi_sta_itwt_suspend` 请求暂停 iTWT 时,用户需要指定对应 iTWT 的 flow_id 以及暂停时间。需要注意的是,当暂停时间大于 0 时,对应 iTWT 会在暂停指定时间后恢复,而当暂停时间为 0 时,对应的 iTWT 会暂停,直到被用户调用 API 手动恢复为止。 + + - WIFI_EVENT_ITWT_TEARDOWN + + 在调用 API :cpp:func:`esp_wifi_sta_itwt_teardown` 请求终止 iTWT 时,用户可以在 :cpp:enumerator:`WIFI_EVENT_ITWT_TEARDOWN` 事件的对应处理程序中获取请求结果并自定义处理逻辑。事件结果保存在 :cpp:type:`wifi_event_sta_itwt_teardown_t` 结构体中,其成员变量 status 指示了此次事件的状态。 + 当 status 为 :cpp:enumerator:`ITWT_TEARDOWN_SUCCESS` 时代表成功终止了指定的 iTWT 协商,为其他值代表终止 iTWT 失败。调用 API 时用户需要指定需要终止的 iTWT 的 flow_id。 + + - WIFI_EVENT_TWT_WAKEUP + + 当 Station 在休眠中醒来时,Wi-Fi 驱动程序将会上报 :cpp:enumerator:`WIFI_EVENT_TWT_WAKEUP` 事件,用户可以在该事件的对应处理程序中自定义处理逻辑。事件结果保存在 :cpp:type:`wifi_event_sta_twt_wakeup_t` 结构体中,成员变量 twt_type 指示了此次事件 TWT 的类型,成员变量 flow_id 指示了此次醒来的具体的 TWT。 + + - WIFI_EVENT_ITWT_PROBE + + 调用 API :cpp:func:`esp_wifi_sta_itwt_send_probe_req` 在 iTWT 期间发送 probe request 时,用户可以在 :cpp:enumerator:`WIFI_EVENT_ITWT_PROBE` 事件的对应处理程序中获取请求结果并自定义处理逻辑。事件结果保存在 :cpp:type:`wifi_event_sta_itwt_probe_t` 结构体中,其成员变量 status 指示了此次事件的状态。 + 当 status 为 :cpp:enumerator:`ITWT_PROBE_SUCCESS` 时代表成功发送 probe request 并且接收到 AP 回复的 probe response,为其他值代表发送或者接收 probe 失败。 + + + 有关 iTWT 使用的更多信息,可以参考示例 :example:`wifi/itwt` 。 + + TWT 功耗分析 + +++++++++++++ + + 为了展现 TWT 在节省设备功耗方面的优势,我们使用功率分析仪追踪了 {IDF_TARGET_NAME} 在不同模式下的电流情况。如下图所示,{IDF_TARGET_NAME} 首先处于 DTIM 模式,接着与 AP 建立起 iTWT 协商,TWT Wake Interval 为 10 s,在 TWT SP 结束后,{IDF_TARGET_NAME} 会进入 Light-sleep 状态直到下个 SP 到来时唤醒。 + 其中 :cpp:type:`wifi_twt_setup_config_t` 配置示例如下: + + .. code-block:: C + + wifi_twt_setup_config_t setup_config = { + .setup_cmd = TWT_REQUEST, + .flow_id = 0, + .twt_id = 0, + .flow_type = 0, + .min_wake_dura = 255, + .wake_duration_unit = 0, + .wake_invl_expn = 10, + .wake_invl_mant = 10000, + .trigger = 1, + .timeout_time_ms = 5000, + }; + + .. figure:: ../../_static/itwt_10s_current.png + :align: center + + DTIM 与 iTWT 模式下的电流图 + + 进一步,将 TWT 协商中的 TWT Wake Interval 参数更改为 30 s,下图展现了参数变化对于电流的影响。 + 其中 :cpp:type:`wifi_twt_setup_config_t` 配置示例如下: + + .. code-block:: C + + wifi_twt_setup_config_t setup_config = { + .setup_cmd = TWT_REQUEST, + .flow_id = 0, + .twt_id = 0, + .flow_type = 0, + .min_wake_dura = 255, + .wake_duration_unit = 0, + .wake_invl_expn = 10, + .wake_invl_mant = 30000, + .trigger = 1, + .timeout_time_ms = 5000, + }; + + .. figure:: ../../_static/itwt_30s_current.png + :align: center + + 更改参数后的 DTIM 与 iTWT 模式下的电流图 From d9e4ec6c0a470c484ed98d657e5a09036384e749 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 26 Sep 2023 07:20:51 +0200 Subject: [PATCH 339/548] fix(examples): Add wifi_remote option to common connect example * Add MQTT test configuration with WiFi on ESP32-P4 * Document esp_wifi_remote workflow in the example's README --- .../Kconfig.projbuild | 8 +- examples/protocols/mqtt/tcp/README.md | 171 ++++++++++++++++++ .../protocols/mqtt/tcp/main/idf_component.yml | 4 + .../protocols/mqtt/tcp/sdkconfig.ci.p4_wifi | 4 + 4 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 examples/protocols/mqtt/tcp/sdkconfig.ci.p4_wifi diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index a5b654d50ed..1b450b92362 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -4,8 +4,8 @@ menu "Example Connection Configuration" config EXAMPLE_CONNECT_WIFI bool "connect using WiFi interface" - depends on !IDF_TARGET_LINUX && SOC_WIFI_SUPPORTED - default y + depends on !IDF_TARGET_LINUX && (SOC_WIFI_SUPPORTED || ESP_WIFI_REMOTE_ENABLED) + default y if SOC_WIFI_SUPPORTED help Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. Choose this option to connect with WiFi @@ -119,7 +119,7 @@ menu "Example Connection Configuration" config EXAMPLE_CONNECT_ETHERNET bool "connect using Ethernet interface" depends on !IDF_TARGET_LINUX - default y if !SOC_WIFI_SUPPORTED + default y if !EXAMPLE_CONNECT_WIFI help Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. Choose this option to connect with Ethernet @@ -218,7 +218,7 @@ menu "Example Connection Configuration" bool "KSZ80xx" help With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX - Ethernet Physical Layer Tranceivers (PHY). + Ethernet Physical Layer Transceivers (PHY). The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041, KSZ8051, KSZ8061, KSZ8081, KSZ8091 Goto https://www.microchip.com for more information about them. diff --git a/examples/protocols/mqtt/tcp/README.md b/examples/protocols/mqtt/tcp/README.md index 52888e39dff..07e4333e522 100644 --- a/examples/protocols/mqtt/tcp/README.md +++ b/examples/protocols/mqtt/tcp/README.md @@ -59,3 +59,174 @@ I (5194) MQTT_EXAMPLE: MQTT_EVENT_DATA TOPIC=/topic/qos0 DATA=data ``` + +## Using Wi-Fi connection with ESP32P4 + +It is possible to use Wi-Fi connection on targets that do not support native Wi-Fi peripheral. This example demonstrates using `esp_wifi_remote` on ESP32P4 in the test configuration defined as `sdkconfig.ci.p4_wifi`. This configuration requires another ESP target with native Wi-Fi support physically connected to the ESP32-P4. + +### Configure master-slave verification + +In order to secure the physical connection between the ESP32-P4 (master) and the slave device, it is necessary to set certificates and keys for each side. +To bootstrap this step, you can use one-time generated self-signed RSA keys and certificates running: +``` +./managed_components/espressif__esp_wifi_remote/examples/test_certs/generate_test_certs.sh espressif.local +``` + +### Configure the slave project + +It is recommended to create a new project from `esp_wifi_remote` component's example with +``` +idf.py create-project-from-example "espressif/esp_wifi_remote:server" +``` +but you can also build and flash the slave project directly from the `managed_components` directory using: +``` +idf.py -C managed_components/espressif__esp_wifi_remote/examples/server/ -B build_slave +``` + +Please follow these steps to setup the slave application: +* `idf.py set-target` -- choose the slave target (must support Wi-Fi) +* `idf.py menuconfig` -- configure the physical connection and verification details: + - `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CA` -- CA for verifying ESP32-P4 application + - `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CRT` -- slave's certificate + - `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_KEY` -- slave's private key +* `idf.py build flash monitor` + +### Configure the master project (ESP32-P4) + +similarly to the slave project, we have to configure +* the physical connection +* the verification + - `CONFIG_ESP_WIFI_REMOTE_EPPP_SERVER_CA` -- CA for verifying the slave application + - `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_CRT` -- our own certificate + - `CONFIG_ESP_WIFI_REMOTE_EPPP_CLIENT_KEY` -- our own private key + +After project configuration, you build and flash the board with +``` +idf.py build flash monitor +``` + +### Example Output of the slave device + +``` +I (7982) main_task: Returned from app_main() +I (8242) rpc_server: Received header id 2 +I (8242) pp: pp rom version: 5b8dcfa +I (8242) net80211: net80211 rom version: 5b8dcfa +I (8252) wifi:wifi driver task: 4082be8c, prio:23, stack:6656, core=0 +I (8252) wifi:wifi firmware version: feaf82d +I (8252) wifi:wifi certification version: v7.0 +I (8252) wifi:config NVS flash: enabled +I (8262) wifi:config nano formatting: disabled +I (8262) wifi:mac_version:HAL_MAC_ESP32AX_761,ut_version:N, band:0x1 +I (8272) wifi:Init data frame dynamic rx buffer num: 32 +I (8272) wifi:Init static rx mgmt buffer num: 5 +I (8282) wifi:Init management short buffer num: 32 +I (8282) wifi:Init dynamic tx buffer num: 32 +I (8292) wifi:Init static tx FG buffer num: 2 +I (8292) wifi:Init static rx buffer size: 1700 (rxctrl:92, csi:512) +I (8302) wifi:Init static rx buffer num: 10 +I (8302) wifi:Init dynamic rx buffer num: 32 +I (8302) wifi_init: rx ba win: 6 +I (8312) wifi_init: accept mbox: 6 +I (8312) wifi_init: tcpip mbox: 32 +I (8322) wifi_init: udp mbox: 6 +I (8322) wifi_init: tcp mbox: 6 +I (8322) wifi_init: tcp tx win: 5760 +I (8332) wifi_init: tcp rx win: 5760 +I (8332) wifi_init: tcp mss: 1440 +I (8342) wifi_init: WiFi IRAM OP enabled +I (8342) wifi_init: WiFi RX IRAM OP enabled +I (8352) wifi_init: WiFi SLP IRAM OP enabled +I (8362) rpc_server: Received header id 11 +I (8362) rpc_server: Received header id 4 +I (8372) rpc_server: Received header id 6 +I (8372) phy_init: phy_version 270,339aa07,Apr 3 2024,16:36:11 +I (8492) wifi:enable tsf +I (8492) rpc_server: Received WIFI event 41 +I (8502) rpc_server: Received WIFI event 2 +I (8732) rpc_server: Received header id 10 +I (8742) rpc_server: Received header id 5 +I (8752) rpc_server: Received header id 8 +I (11452) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1, snd_ch_cfg:0x0 +I (11452) wifi:(connect)dot11_authmode:0x3, pairwise_cipher:0x3, group_cipher:0x1 +I (11452) wifi:state: init -> auth (0xb0) +I (11462) rpc_server: Received WIFI event 41 +I (11462) wifi:state: auth -> assoc (0x0) +I (11472) wifi:(assoc)RESP, Extended Capabilities length:8, operating_mode_notification:0 +I (11472) wifi:(assoc)RESP, Extended Capabilities, MBSSID:0, TWT Responder:0, OBSS Narrow Bandwidth RU In OFDMA Tolerance:0 +I (11482) wifi:Extended Capabilities length:8, operating_mode_notification:1 +I (11492) wifi:state: assoc -> run (0x10) +I (11492) wifi:(trc)phytype:CBW20-SGI, snr:50, maxRate:144, highestRateIdx:0 +W (11502) wifi:(trc)band:2G, phymode:3, highestRateIdx:0, lowestRateIdx:11, dataSchedTableSize:14 +I (11512) wifi:(trc)band:2G, rate(S-MCS7, rateIdx:0), ampdu(rate:S-MCS7, schedIdx(0, stop:8)), snr:50, ampduState:wait operational +I (11522) wifi:ifidx:0, rssi:-45, nf:-95, phytype(0x3, CBW20-SGI), phymode(0x3, 11bgn), max_rate:144, he:0, vht:0, ht:1 +I (11532) wifi:(ht)max.RxAMPDULenExponent:3(65535 bytes), MMSS:6(8 us) +W (11542) wifi:idx:0, ifx:0, tid:0, TAHI:0x1002cb4, TALO:0x1b942980, (ssn:0, win:64, cur_ssn:0), CONF:0xc0000005 +I (11572) wifi:connected with Cermakowifi, aid = 2, channel 6, BW20, bssid = 80:29:94:1b:b4:2c +I (11572) wifi:cipher(pairwise:0x3, group:0x1), pmf:0, security:WPA2-PSK, phy:11bgn, rssi:-45 +I (11582) wifi:pm start, type: 1, twt_start:0 + +I (11582) wifi:pm start, type:1, aid:0x2, trans-BSSID:80:29:94:1b:b4:2c, BSSID[5]:0x2c, mbssid(max-indicator:0, index:0), he:0 +I (11592) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us +I (11602) wifi:set rx beacon pti, rx_bcn_pti: 10, bcn_timeout: 25000, mt_pti: 10, mt_time: 10000 +I (11612) wifi:[ADDBA]TX addba request, tid:0, dialogtoken:1, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x0) +I (11622) wifi:[ADDBA]TX addba request, tid:7, dialogtoken:2, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x20) +I (11632) wifi:[ADDBA]TX addba request, tid:5, dialogtoken:3, bufsize:64, A-MSDU:0(not supported), policy:1(IMR), ssn:0(0x0) +I (11642) wifi:[ADDBA]RX addba response, status:0, tid:7/tb:0(0x1), bufsize:64, batimeout:0, txa_wnd:64 +I (11652) wifi:[ADDBA]RX addba response, status:0, tid:5/tb:0(0x1), bufsize:64, batimeout:0, txa_wnd:64 +I (11662) wifi:[ADDBA]RX addba response, status:0, tid:0/tb:1(0x1), bufsize:64, batimeout:0, txa_wnd:64 +I (11672) wifi:AP's beacon interval = 102400 us, DTIM period = 1 +I (11682) rpc_server: Received WIFI event 4 +I (15682) esp_netif_handlers: sta ip: 192.168.0.33, mask: 255.255.255.0, gw: 192.168.0.1 +I (15682) rpc_server: Received IP event 0 +I (15682) rpc_server: Main DNS:185.162.24.55 +I (15682) rpc_server: IP address:192.168.0.33 +``` + +### Example Output of the master device (ESP32-P4) + +``` +I (445) example_connect: Start example_connect. +I (455) uart: queue free spaces: 16 +I (455) eppp_link: Waiting for IP address 0 +I (3195) esp-netif_lwip-ppp: Connected +I (3195) eppp_link: Got IPv4 event: Interface "pppos_client(EPPP0)" address: 192.168.11.2 +I (3195) esp-netif_lwip-ppp: Connected +I (3195) eppp_link: Connected! 0 +I (5475) example_connect: Waiting for IP(s) +I (8405) esp_wifi_remote: esp_wifi_internal_reg_rxcb: sta: 0x4001c68a +I (9445) example_connect: Got IPv6 event: Interface "pppos_client" address: fe80:0000:0000:0000:5632:04ff:fe08:5054, type: ESP_IP6_ADDR_IS_LINK_LOCAL +I (12415) rpc_client: Main DNS:185.162.24.55 +I (12415) esp_netif_handlers: pppos_client ip: 192.168.11.2, mask: 255.255.255.255, gw: 192.168.11.1 +I (12415) rpc_client: EPPP IP:192.168.11.1 +I (12415) example_connect: Got IPv4 event: Interface "pppos_client" address: 192.168.11.2 +I (12425) rpc_client: WIFI IP:192.168.0.33 +I (12435) example_common: Connected to pppos_client +I (12445) rpc_client: WIFI GW:192.168.0.1 +I (12455) example_common: - IPv6 address: fe80:0000:0000:0000:5632:04ff:fe08:5054, type: ESP_IP6_ADDR_IS_LINK_LOCAL +I (12455) rpc_client: WIFI mask:255.255.255.0 +I (12465) example_common: Connected to pppos_client +I (12475) example_common: - IPv4 address: 192.168.11.2, +I (12475) example_common: - IPv6 address: fe80:0000:0000:0000:5c3b:1291:05ca:6dc8, type: ESP_IP6_ADDR_IS_LINK_LOCAL +I (12495) mqtt_example: Other event id:7 +I (12495) main_task: Returned from app_main() +I (12905) mqtt_example: MQTT_EVENT_CONNECTED +I (12905) mqtt_example: sent publish successful, msg_id=36013 +I (12905) mqtt_example: sent subscribe successful, msg_id=44233 +I (12905) mqtt_example: sent subscribe successful, msg_id=36633 +I (12915) mqtt_example: sent unsubscribe successful, msg_id=15480 +I (13115) mqtt_example: MQTT_EVENT_PUBLISHED, msg_id=36013 +I (13415) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=44233 +I (13415) mqtt_example: sent publish successful, msg_id=0 +I (13415) mqtt_example: MQTT_EVENT_SUBSCRIBED, msg_id=36633 +I (13415) mqtt_example: sent publish successful, msg_id=0 +I (13425) mqtt_example: MQTT_EVENT_DATA +TOPIC=/topic/qos1 +DATA=data_3 +I (13435) mqtt_example: MQTT_EVENT_UNSUBSCRIBED, msg_id=15480 +I (13615) mqtt_example: MQTT_EVENT_DATA +TOPIC=/topic/qos0 +DATA=data +I (13925) mqtt_example: MQTT_EVENT_DATA +TOPIC=/topic/qos0 +``` diff --git a/examples/protocols/mqtt/tcp/main/idf_component.yml b/examples/protocols/mqtt/tcp/main/idf_component.yml index 718194867b7..1b1f6dbd59a 100644 --- a/examples/protocols/mqtt/tcp/main/idf_component.yml +++ b/examples/protocols/mqtt/tcp/main/idf_component.yml @@ -1,3 +1,7 @@ dependencies: protocol_examples_common: path: ${IDF_PATH}/examples/common_components/protocol_examples_common + espressif/esp_wifi_remote: + version: ">=0.1.12" + rules: + - if: "target in [esp32p4, esp32h2]" diff --git a/examples/protocols/mqtt/tcp/sdkconfig.ci.p4_wifi b/examples/protocols/mqtt/tcp/sdkconfig.ci.p4_wifi new file mode 100644 index 00000000000..7a5574c7f3a --- /dev/null +++ b/examples/protocols/mqtt/tcp/sdkconfig.ci.p4_wifi @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32p4" +CONFIG_EXAMPLE_CONNECT_WIFI=y +CONFIG_ESP_WIFI_REMOTE_EPPP_UART_TX_PIN=17 +CONFIG_ESP_WIFI_REMOTE_EPPP_UART_RX_PIN=16 From 083db8a169b7005190378216953ab4b1d32d933b Mon Sep 17 00:00:00 2001 From: Jakob Hasse Date: Mon, 24 Jun 2024 11:37:38 +0200 Subject: [PATCH 340/548] fix(bootloader_support): Fixed pattern in RNG enable function on C6 to avoid output on IO0 --- components/bootloader_support/src/bootloader_random_esp32c6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bootloader_support/src/bootloader_random_esp32c6.c b/components/bootloader_support/src/bootloader_random_esp32c6.c index 682e48544c8..0efd9d4c086 100644 --- a/components/bootloader_support/src/bootloader_random_esp32c6.c +++ b/components/bootloader_support/src/bootloader_random_esp32c6.c @@ -53,7 +53,7 @@ void bootloader_random_enable(void) // create patterns and set them in pattern table uint32_t pattern_one = (SAR2_CHANNEL << 2) | SAR2_ATTEN; // we want channel 9 with max attenuation - uint32_t pattern_two = SAR1_ATTEN; // we want channel 0 with max attenuation, channel doesn't really matter here + uint32_t pattern_two = (SAR2_CHANNEL << 2) | SAR1_ATTEN; // we want channel 9 with max attenuation uint32_t pattern_table = 0 | (pattern_two << 3 * PATTERN_BIT_WIDTH) | pattern_one << 2 * PATTERN_BIT_WIDTH; REG_WRITE(APB_SARADC_SAR_PATT_TAB1_REG, pattern_table); From 4e0d5c923d70d16833b291b4add2e2fb6c22d3e9 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Sat, 29 Jun 2024 02:26:14 +0800 Subject: [PATCH 341/548] fix(sdmmc_io): fixed fixed_addr mode will still increase addr when splitting --- components/sdmmc/sdmmc_io.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index 376cebc9e5e..74ab6dd7355 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -336,11 +336,15 @@ esp_err_t sdmmc_io_rw_extended(sdmmc_card_t* card, int func, esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, uint32_t addr, void* dst, size_t size) { - uint32_t arg = SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT; - //Extract and unset the bit used to indicate the OP Code (inverted logic) + uint32_t arg = SD_ARG_CMD53_READ; + bool incr_addr = true; + //Extract and unset the bit used to indicate the OP Code if (addr & SDMMC_IO_FIXED_ADDR) { - arg &= ~SD_ARG_CMD53_INCREMENT; addr &= ~SDMMC_IO_FIXED_ADDR; + incr_addr = false; + } + if (incr_addr) { + arg |= SD_ARG_CMD53_INCREMENT; } /* host quirk: SDIO transfer with length not divisible by 4 bytes @@ -360,7 +364,9 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, } pc_dst += will_transfer; size -= will_transfer; - addr += will_transfer; + if (incr_addr) { + addr += will_transfer; + } } return ESP_OK; } @@ -368,11 +374,15 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, uint32_t addr, const void* src, size_t size) { - uint32_t arg = SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT; - //Extract and unset the bit used to indicate the OP Code (inverted logic) + uint32_t arg = SD_ARG_CMD53_WRITE; + bool incr_addr = true; + //Extract and unset the bit used to indicate the OP Code if (addr & SDMMC_IO_FIXED_ADDR) { - arg &= ~SD_ARG_CMD53_INCREMENT; addr &= ~SDMMC_IO_FIXED_ADDR; + incr_addr = false; + } + if (incr_addr) { + arg |= SD_ARG_CMD53_INCREMENT; } /* same host quirk as in sdmmc_io_read_bytes */ @@ -389,7 +399,9 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, } pc_src += will_transfer; size -= will_transfer; - addr += will_transfer; + if (incr_addr) { + addr += will_transfer; + } } return ESP_OK; } From 1506144d3acce3b7434ae7eb362fed680154b01e Mon Sep 17 00:00:00 2001 From: fbp2m Date: Mon, 10 Jun 2024 21:52:53 +0200 Subject: [PATCH 342/548] fix: fixed allocating if_name in client context multiple times Do not allocate client->if_name twice in esp_http_client_init(). Signed-off-by: Harshit Malpani Closes https://github.com/espressif/esp-idf/pull/13945 --- components/esp_http_client/esp_http_client.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/esp_http_client/esp_http_client.c b/components/esp_http_client/esp_http_client.c index 36ed29f2e1f..8ac63e8f8bd 100644 --- a/components/esp_http_client/esp_http_client.c +++ b/components/esp_http_client/esp_http_client.c @@ -657,9 +657,11 @@ static bool init_common_tcp_transport(esp_http_client_handle_t client, const esp } if (config->if_name) { - client->if_name = calloc(1, sizeof(struct ifreq)); - ESP_RETURN_ON_FALSE(client->if_name, false, TAG, "Memory exhausted"); - memcpy(client->if_name, config->if_name, sizeof(struct ifreq)); + if (client->if_name == NULL) { + client->if_name = calloc(1, sizeof(struct ifreq)); + ESP_RETURN_ON_FALSE(client->if_name, false, TAG, "Memory exhausted"); + memcpy(client->if_name, config->if_name, sizeof(struct ifreq)); + } esp_transport_tcp_set_interface_name(transport, client->if_name); } return true; From 1c5bcc4a5d273c1b52bc44c5a233ce578a93d111 Mon Sep 17 00:00:00 2001 From: liqigan Date: Tue, 2 Jul 2024 14:40:33 +0800 Subject: [PATCH 343/548] fix(bt/controller): Fixed not report HCI_Disconnection_Complete event --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 405cac4cba9..1c6a65923f1 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 405cac4cba9c010ed2f378d7f202f62a3bee8f7a +Subproject commit 1c6a65923f19601c0aa44690664dd0b5152ce2af From 418ddda7ef41010ea4e6eb9b7c01d0f8d0678fed Mon Sep 17 00:00:00 2001 From: linruihao Date: Tue, 2 Jul 2024 15:50:54 +0800 Subject: [PATCH 344/548] fix(bt/controller): Fixed some controller bugs - Fixed fail to establish eSCO when connected to two devices - Changed some error log level to Debug if the error have a workaround Closes https://github.com/espressif/esp-idf/issues/12340 --- components/bt/controller/lib_esp32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32 b/components/bt/controller/lib_esp32 index 1c6a65923f1..1d3d9bfd298 160000 --- a/components/bt/controller/lib_esp32 +++ b/components/bt/controller/lib_esp32 @@ -1 +1 @@ -Subproject commit 1c6a65923f19601c0aa44690664dd0b5152ce2af +Subproject commit 1d3d9bfd298ed3b6916d561dc54317041841ec9e From d6162c4a7830dbaf6c345d0f46b6b49f615c54b1 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 8 Jul 2024 15:10:59 +0800 Subject: [PATCH 345/548] fix(i2c): Fix i2c not release semaphore in command send loop, Closes https://github.com/espressif/esp-idf/issues/13962 --- components/esp_driver_i2c/i2c_master.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index 4ee7c2b409e..34a7106ef9f 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -425,6 +425,8 @@ static void s_i2c_send_commands(i2c_master_bus_handle_t i2c_master, TickType_t t i2c_master->cmd_idx = 0; i2c_master->trans_idx = 0; atomic_store(&i2c_master->status, I2C_STATUS_TIMEOUT); + ESP_LOGE(TAG, "I2C software timeout"); + xSemaphoreGive(i2c_master->cmd_semphr); return; } From 095a0dd85f898f20c5b2d2aa9688814827e16ad3 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Sat, 6 Jul 2024 18:31:08 +0800 Subject: [PATCH 346/548] feat(ble/bluedroid): Support BLE50 instance in related event --- .../api/include/api/esp_gap_ble_api.h | 18 +++++ .../btc/profile/std/gap/btc_gap_ble.c | 20 +++++- .../host/bluedroid/stack/btm/btm_ble_5_gap.c | 45 +++++++++---- .../stack/include/stack/btm_ble_api.h | 12 ++++ .../peroidic_adv/main/periodic_adv_demo.c | 20 +++--- .../Periodic_adv_Example_Walkthrough.md | 66 +++++++++---------- 6 files changed, 125 insertions(+), 56 deletions(-) diff --git a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h index ea52baf00e5..d4c01c734ba 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_gap_ble_api.h @@ -846,6 +846,10 @@ typedef uint8_t esp_ble_gap_adv_type_t; /// Extend advertising tx power, range: [-127, +126] dBm #define EXT_ADV_TX_PWR_NO_PREFERENCE (127) /*!< host has no preference for tx power */ + +/// max number of advertising sets to enable or disable +#define EXT_ADV_NUM_SETS_MAX (10) /*!< max evt instance num */ + /** * @brief ext adv parameters */ @@ -1256,72 +1260,86 @@ typedef union { */ struct ble_ext_adv_set_rand_addr_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate extend advertising random address set status */ + uint8_t instance; /*!< extend advertising handle */ } ext_adv_set_rand_addr; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT */ struct ble_ext_adv_set_params_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate extend advertising parameters set status */ + uint8_t instance; /*!< extend advertising handle */ } ext_adv_set_params; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT */ struct ble_ext_adv_data_set_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate extend advertising data set status */ + uint8_t instance; /*!< extend advertising handle */ } ext_adv_data_set; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT */ struct ble_ext_adv_scan_rsp_set_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate extend advertising scan response data set status */ + uint8_t instance; /*!< extend advertising handle */ } scan_rsp_set; /*!< Event parameter of ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT */ struct ble_ext_adv_start_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate advertising start operation success status */ + uint8_t instance_num; /*!< extend advertising handle numble*/ + uint8_t instance[EXT_ADV_NUM_SETS_MAX]; /*!< extend advertising handle list*/ } ext_adv_start; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT */ struct ble_ext_adv_stop_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate advertising stop operation success status */ + uint8_t instance_num; /*!< extend advertising handle numble*/ + uint8_t instance[EXT_ADV_NUM_SETS_MAX]; /*!< extend advertising handle list*/ } ext_adv_stop; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_SET_REMOVE_COMPLETE_EVT */ struct ble_ext_adv_set_remove_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate advertising stop operation success status */ + uint8_t instance; /*!< extend advertising handle */ } ext_adv_remove; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_SET_REMOVE_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_EXT_ADV_SET_CLEAR_COMPLETE_EVT */ struct ble_ext_adv_set_clear_cmpl_evt_param { esp_bt_status_t status; /*!< Indicate advertising stop operation success status */ + uint8_t instance; /*!< extend advertising handle */ } ext_adv_clear; /*!< Event parameter of ESP_GAP_BLE_EXT_ADV_SET_CLEAR_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT */ struct ble_periodic_adv_set_params_cmpl_param { esp_bt_status_t status; /*!< Indicate periodic advertisingparameters set status */ + uint8_t instance; /*!< extend advertising handle */ } peroid_adv_set_params; /*!< Event parameter of ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT */ struct ble_periodic_adv_data_set_cmpl_param { esp_bt_status_t status; /*!< Indicate periodic advertising data set status */ + uint8_t instance; /*!< extend advertising handle */ } period_adv_data_set; /*!< Event parameter of ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT */ struct ble_periodic_adv_start_cmpl_param { esp_bt_status_t status; /*!< Indicate periodic advertising start status */ + uint8_t instance; /*!< extend advertising handle */ } period_adv_start; /*!< Event parameter of ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_STOP_COMPLETE_EVT */ struct ble_periodic_adv_stop_cmpl_param { esp_bt_status_t status; /*!< Indicate periodic advertising stop status */ + uint8_t instance; /*!< extend advertising handle */ } period_adv_stop; /*!< Event parameter of ESP_GAP_BLE_PERIODIC_ADV_STOP_COMPLETE_EVT */ /** * @brief ESP_GAP_BLE_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 53d0b835d32..464f032417c 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -989,34 +989,48 @@ static void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, case BTA_DM_BLE_5_GAP_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT: msg.act = ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT; param.ext_adv_set_rand_addr.status = btc_btm_status_to_esp_status(params->set_ext_rand_addr.status); + param.ext_adv_set_rand_addr.instance = params->set_ext_rand_addr.instance; break; case BTA_DM_BLE_5_GAP_EXT_ADV_SET_PARAMS_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT; - param.ext_adv_set_rand_addr.status = btc_btm_status_to_esp_status(params->set_params.status); + param.ext_adv_set_params.status = btc_btm_status_to_esp_status(params->set_params.status); + param.ext_adv_set_params.instance = params->set_params.instance; break; } case BTA_DM_BLE_5_GAP_EXT_ADV_DATA_SET_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT; param.ext_adv_data_set.status = btc_btm_status_to_esp_status(params->adv_data_set.status); + param.ext_adv_data_set.instance = params->adv_data_set.instance; break; } case BTA_DM_BLE_5_GAP_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT; param.scan_rsp_set.status = btc_btm_status_to_esp_status(params->scan_rsp_data_set.status); + param.scan_rsp_set.instance = params->scan_rsp_data_set.instance; break; } case BTA_DM_BLE_5_GAP_EXT_ADV_START_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT; param.ext_adv_start.status = btc_btm_status_to_esp_status(params->adv_start.status); + for (UINT8 i = 0; i < params->adv_start.instance_num; i++) { + param.ext_adv_start.instance[i] = params->adv_start.instance[i]; + } + + param.ext_adv_start.instance_num = params->adv_start.instance_num; break; } case BTA_DM_BLE_5_GAP_EXT_ADV_STOP_COMPLETE_EVT: msg.act = ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT; param.ext_adv_stop.status = btc_btm_status_to_esp_status(params->adv_start.status); + for (UINT8 i = 0; i < params->adv_start.instance_num; i++) { + param.ext_adv_stop.instance[i] = params->adv_start.instance[i]; + } + param.ext_adv_stop.instance_num = params->adv_start.instance_num; break; case BTA_DM_BLE_5_GAP_EXT_ADV_SET_REMOVE_COMPLETE_EVT: msg.act = ESP_GAP_BLE_EXT_ADV_SET_REMOVE_COMPLETE_EVT; param.ext_adv_remove.status = btc_btm_status_to_esp_status(params->adv_start.status); + param.ext_adv_remove.instance = params->adv_start.instance[0]; break; case BTA_DM_BLE_5_GAP_EXT_ADV_SET_CLEAR_COMPLETE_EVT: msg.act = ESP_GAP_BLE_EXT_ADV_SET_CLEAR_COMPLETE_EVT; @@ -1025,21 +1039,25 @@ static void btc_ble_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, case BTA_DM_BLE_5_GAP_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT; param.peroid_adv_set_params.status = btc_btm_status_to_esp_status(params->per_adv_set_params.status); + param.peroid_adv_set_params.instance = params->per_adv_set_params.instance; break; } case BTA_DM_BLE_5_GAP_PERIODIC_ADV_DATA_SET_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT; param.period_adv_data_set.status = btc_btm_status_to_esp_status(params->per_adv_data_set.status); + param.period_adv_data_set.instance = params->per_adv_data_set.instance; break; } case BTA_DM_BLE_5_GAP_PERIODIC_ADV_START_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT; param.period_adv_start.status = btc_btm_status_to_esp_status(params->per_adv_start.status); + param.period_adv_start.instance = params->per_adv_start.instance; break; } case BTA_DM_BLE_5_GAP_PERIODIC_ADV_STOP_COMPLETE_EVT: { msg.act = ESP_GAP_BLE_PERIODIC_ADV_STOP_COMPLETE_EVT; param.period_adv_stop.status = btc_btm_status_to_esp_status(params->per_adv_stop.status); + param.period_adv_stop.instance = params->per_adv_stop.instance; break; } case BTA_DM_BLE_5_GAP_PERIODIC_ADV_CREATE_SYNC_COMPLETE_EVT: { diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index 04ad4804bdb..f595e3e6efb 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -340,8 +340,8 @@ tBTM_STATUS BTM_BleSetExtendedAdvRandaddr(UINT8 instance, BD_ADDR rand_addr) } end: - cb_params.status = status; - + cb_params.set_ext_rand_addr.status = status; + cb_params.set_ext_rand_addr.instance = instance; BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, &cb_params); return status; @@ -420,7 +420,8 @@ tBTM_STATUS BTM_BleSetExtendedAdvParams(UINT8 instance, tBTM_BLE_GAP_EXT_ADV_PAR BTM_UpdateAddrInfor(BLE_ADDR_RANDOM, rand_addr); } } - cb_params.status = status; + cb_params.set_params.status = status; + cb_params.set_params.instance = instance; BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_PARAMS_COMPLETE_EVT, &cb_params); return status; @@ -471,7 +472,14 @@ tBTM_STATUS BTM_BleConfigExtendedAdvDataRaw(BOOLEAN is_scan_rsp, UINT8 instance, } while (rem_len); end: - cb_params.status = status; + if (is_scan_rsp) { + cb_params.scan_rsp_data_set.status = status; + cb_params.scan_rsp_data_set.instance = instance; + } else { + cb_params.adv_data_set.status = status; + cb_params.adv_data_set.instance = instance; + } + BTM_ExtBleCallbackTrigger(is_scan_rsp ? BTM_BLE_5_GAP_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT : BTM_BLE_5_GAP_EXT_ADV_DATA_SET_COMPLETE_EVT, &cb_params); return status; @@ -574,7 +582,12 @@ tBTM_STATUS BTM_BleStartExtAdv(BOOLEAN enable, UINT8 num, tBTM_BLE_EXT_ADV *ext_ } } - cb_params.status = status; + cb_params.adv_start.status = status; + cb_params.adv_start.instance_num = num; + for (uint8_t i = 0; i < num; i++) { + cb_params.adv_start.instance[i] = ext_adv[i].instance; + } + BTM_ExtBleCallbackTrigger(enable ? BTM_BLE_5_GAP_EXT_ADV_START_COMPLETE_EVT : BTM_BLE_5_GAP_EXT_ADV_STOP_COMPLETE_EVT, &cb_params); return status; @@ -629,7 +642,9 @@ tBTM_STATUS BTM_BleExtAdvSetRemove(UINT8 instance) end: - cb_params.status = status; + cb_params.adv_start.status = status; + cb_params.adv_start.instance_num = 1; + cb_params.adv_start.instance[0] = instance; BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_REMOVE_COMPLETE_EVT, &cb_params); @@ -655,7 +670,7 @@ tBTM_STATUS BTM_BleExtAdvSetClear(void) } } - cb_params.status = status; + cb_params.adv_start.status = status; BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_EXT_ADV_SET_CLEAR_COMPLETE_EVT, &cb_params); @@ -693,7 +708,8 @@ tBTM_STATUS BTM_BlePeriodicAdvSetParams(UINT8 instance, tBTM_BLE_Periodic_Adv_Pa end: - cb_params.status = status; + cb_params.per_adv_set_params.status = status; + cb_params.per_adv_set_params.instance = instance; BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, &cb_params); @@ -747,7 +763,9 @@ tBTM_STATUS BTM_BlePeriodicAdvCfgDataRaw(UINT8 instance, UINT16 len, UINT8 *data } while(rem_len); end: - cb_params.status = status; + cb_params.per_adv_data_set.status = status; + cb_params.per_adv_data_set.instance = instance; + BTM_ExtBleCallbackTrigger(BTM_BLE_5_GAP_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, &cb_params); return status; @@ -771,8 +789,13 @@ tBTM_STATUS BTM_BlePeriodicAdvEnable(UINT8 instance, UINT8 enable) } end: - - cb_params.status = status; + if (enable) { + cb_params.per_adv_start.status = status; + cb_params.per_adv_start.instance = instance; + } else { + cb_params.per_adv_stop.status = status; + cb_params.per_adv_stop.instance = instance; + } BTM_ExtBleCallbackTrigger(enable ? BTM_BLE_5_GAP_PERIODIC_ADV_START_COMPLETE_EVT : BTM_BLE_5_GAP_PERIODIC_ADV_STOP_COMPLETE_EVT, &cb_params); diff --git a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h index 1bea990878e..1b309642849 100644 --- a/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/btm_ble_api.h @@ -1100,46 +1100,58 @@ typedef struct { typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_SET_PERF_PHY_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_EXT_ADV_SET_RAND_ADDR_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_EXT_ADV_SET_PARAMS_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_EXT_ADV_DATA_SET_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_EXT_ADV_SCAN_RSP_DATA_SET_CMPL; typedef struct { UINT8 status; + UINT8 instance_num; + UINT8 instance[10]; } tBTM_BLE_EXT_ADV_START_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_EXT_ADV_STOP_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_PERIOD_ADV_SET_PARAMS_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_PERIOD_ADV_DATA_SET_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_PERIOD_ADV_START_CMPL; typedef struct { UINT8 status; + UINT8 instance; } tBTM_BLE_PERIOD_ADV_STOP_CMPL; typedef struct { diff --git a/examples/bluetooth/bluedroid/ble_50/peroidic_adv/main/periodic_adv_demo.c b/examples/bluetooth/bluedroid/ble_50/peroidic_adv/main/periodic_adv_demo.c index 240c7c2fcf4..af0bcd8f62a 100644 --- a/examples/bluetooth/bluedroid/ble_50/peroidic_adv/main/periodic_adv_demo.c +++ b/examples/bluetooth/bluedroid/ble_50/peroidic_adv/main/periodic_adv_demo.c @@ -35,7 +35,7 @@ #include "freertos/semphr.h" -#define LOG_TAG "MULTI_ADV_DEMO" +#define LOG_TAG "PERIODIC_ADV_DEMO" #define FUNC_SEND_WAIT_SEM(func, sem) do {\ esp_err_t __err_rc = (func);\ @@ -99,39 +99,39 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param switch (event) { case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext_adv_set_rand_addr.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d, instance %d", param->ext_adv_set_rand_addr.status, param->ext_adv_set_rand_addr.instance); break; case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_adv_set_params.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d, instance %d", param->ext_adv_set_params.status, param->ext_adv_set_params.instance); break; case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_data_set.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->ext_adv_data_set.status, param->ext_adv_data_set.instance); break; case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->scan_rsp_set.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->scan_rsp_set.status, param->scan_rsp_set.instance); break; case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_start.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d, instance numble %d", param->ext_adv_start.status, param->ext_adv_start.instance_num); break; case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d, instance numble %d", param->ext_adv_stop.status, param->ext_adv_stop.instance_num); break; case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->peroid_adv_set_params.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d, instance %d", param->peroid_adv_set_params.status, param->peroid_adv_set_params.instance); break; case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d", param->period_adv_data_set.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->period_adv_data_set.status, param->period_adv_data_set.instance); break; case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d", param->period_adv_start.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d, instance %d", param->period_adv_start.status, param->period_adv_start.instance); break; default: break; diff --git a/examples/bluetooth/bluedroid/ble_50/peroidic_adv/tutorial/Periodic_adv_Example_Walkthrough.md b/examples/bluetooth/bluedroid/ble_50/peroidic_adv/tutorial/Periodic_adv_Example_Walkthrough.md index 6cba5344822..4cab5258ac1 100644 --- a/examples/bluetooth/bluedroid/ble_50/peroidic_adv/tutorial/Periodic_adv_Example_Walkthrough.md +++ b/examples/bluetooth/bluedroid/ble_50/peroidic_adv/tutorial/Periodic_adv_Example_Walkthrough.md @@ -257,46 +257,44 @@ Once the Extended advertising data have been set, the GAP event `ESP_GAP_BLE_EXT ```c -static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){ - switch (event) { - case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d", param->ext _adv_set_rand_addr.status); - break; - case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->ext_adv_set_params.status); - break; - case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d", param->ext_adv_data_set.status); - break; - case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d", param->scan_rsp_set.status); - break; - case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d", param->ext_adv_start.status); - break; - case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d", param->ext_adv_stop.status); - break; - case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT: - xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d", param->p -eroid_adv_set_params.status); +static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + switch (event) { + case ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_RAND_ADDR_COMPLETE_EVT, status %d, instance %d", param->ext_adv_set_rand_addr.status, param->ext_adv_set_rand_addr.instance); + break; + case ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_SET_PARAMS_COMPLETE_EVT, status %d, instance %d", param->ext_adv_set_params.status, param->ext_adv_set_params.instance); + break; + case ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->ext_adv_data_set.status, param->ext_adv_data_set.instance); + break; + case ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_SCAN_RSP_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->scan_rsp_set.status, param->scan_rsp_set.instance); + break; + case ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_START_COMPLETE_EVT, status %d, instance numble %d", param->ext_adv_start.status, param->ext_adv_start.instance_num); + break; + case ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_EXT_ADV_STOP_COMPLETE_EVT, status %d, instance numble %d", param->ext_adv_stop.status, param->ext_adv_stop.instance_num); + break; + case ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT: + xSemaphoreGive(test_sem); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_SET_PARAMS_COMPLETE_EVT, status %d, instance %d", param->peroid_adv_set_params.status, param->peroid_adv_set_params.instance); break; case ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d", param->per -iod_adv_data_set.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_DATA_SET_COMPLETE_EVT, status %d, instance %d", param->period_adv_data_set.status, param->period_adv_data_set.instance); break; case ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT: xSemaphoreGive(test_sem); - ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d", param->period -_adv_start.status); + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PERIODIC_ADV_START_COMPLETE_EVT, status %d, instance %d", param->period_adv_start.status, param->period_adv_start.instance); break; default: break; From c3af6db044e093106380cabea60ab34587dedf1a Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Thu, 9 May 2024 17:37:23 +0800 Subject: [PATCH 347/548] fix(ble/bluedroid): Fixed BLE set adv param check --- components/bt/host/bluedroid/stack/btm/btm_ble_gap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index df24fa08977..c9539341060 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -388,6 +388,12 @@ void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy) &p_cb->adv_addr_type); } + uint8_t null_addr[BD_ADDR_LEN] = {0}; + if ((p_cb->evt_type == 0x01 || p_cb->evt_type == 0x04) && memcmp(p_addr_ptr, null_addr, BD_ADDR_LEN) == 0) { + /* directed advertising */ + return; + } + btsnd_hcic_ble_write_adv_params ((UINT16)(p_cb->adv_interval_min ? p_cb->adv_interval_min : BTM_BLE_GAP_ADV_SLOW_INT), (UINT16)(p_cb->adv_interval_max ? p_cb->adv_interval_max : From 108123d50ca1111c2a370dc006e9718455693684 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 3 Jul 2024 18:03:06 +0800 Subject: [PATCH 348/548] fix(esp_system): fix stuck in bootloader_random_enable after lightsleep --- components/esp_system/port/soc/esp32p4/system_internal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/esp_system/port/soc/esp32p4/system_internal.c b/components/esp_system/port/soc/esp32p4/system_internal.c index 2bd22c2be2f..547f2918101 100644 --- a/components/esp_system/port/soc/esp32p4/system_internal.c +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -49,6 +49,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE); SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE); SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA); + SET_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_ADC); // Clear Peripheral clk rst CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_TIMERGRP0); @@ -62,6 +63,7 @@ void IRAM_ATTR esp_system_reset_modules_on_exit(void) CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART3_CORE); CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN1_REG, HP_SYS_CLKRST_REG_RST_EN_UART4_CORE); CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN0_REG, HP_SYS_CLKRST_REG_RST_EN_GDMA); + CLEAR_PERI_REG_MASK(HP_SYS_CLKRST_HP_RST_EN2_REG, HP_SYS_CLKRST_REG_RST_EN_ADC); #if CONFIG_ESP32P4_REV_MIN_FULL <= 100 // enable soc clk and reset parent crypto From f66ff91e4f58599f596b3cd3624af152b744c9a4 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 26 Jun 2024 10:56:27 +0800 Subject: [PATCH 349/548] feat(dvp): DVP cam supports more color format and don't initialize xclock pin --- .../dvp/include/esp_cam_ctlr_dvp.h | 11 ++--- .../dvp/src/esp_cam_ctlr_dvp_cam.c | 40 +++++++++---------- components/hal/include/hal/cam_ctlr_types.h | 2 + 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h index b235f3e8f74..01cd362a90d 100644 --- a/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h +++ b/components/esp_driver_cam/dvp/include/esp_cam_ctlr_dvp.h @@ -9,6 +9,7 @@ #include #include #include "esp_err.h" +#include "soc/gpio_num.h" #include "hal/cam_types.h" #include "esp_cam_ctlr.h" @@ -21,11 +22,11 @@ extern "C" { */ typedef struct esp_cam_ctlr_dvp_pin_config { cam_ctlr_data_width_t data_width; /*!< Number of data lines */ - int data_io[CAM_DVP_DATA_SIG_NUM]; /*!< DVP data pin number */ - int vsync_io; /*!< DVP V-Sync pin number */ - int de_io; /*!< DVP DE pin number */ - int pclk_io; /*!< DVP PCLK input pin number, clock is from camera sensor */ - int xclk_io; /*!< DVP output clock pin number */ + gpio_num_t data_io[CAM_DVP_DATA_SIG_NUM]; /*!< DVP data pin number */ + gpio_num_t vsync_io; /*!< DVP V-Sync pin number */ + gpio_num_t de_io; /*!< DVP DE pin number */ + gpio_num_t pclk_io; /*!< DVP PCLK input pin number, clock is from camera sensor */ + gpio_num_t xclk_io; /*!< DVP output clock pin number, if using external XTAL, set xclk_io = GPIO_NUM_NC */ } esp_cam_ctlr_dvp_pin_config_t; /** diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index 04334bf7e68..992ea773cc8 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -7,6 +7,7 @@ #include #include "hal/gpio_ll.h" #include "hal/cam_ll.h" +#include "hal/color_hal.h" #include "driver/gpio.h" #include "esp_cache.h" #include "esp_private/periph_ctrl.h" @@ -238,23 +239,15 @@ static esp_err_t esp_cam_ctlr_dvp_cam_get_frame_size(const esp_cam_ctlr_dvp_conf if (config->pic_format_jpeg) { *p_size = config->h_res * config->v_res; } else { - switch (config->input_data_color_type) { - case CAM_CTLR_COLOR_RGB565: - *p_size = config->h_res * config->v_res * 2; - break; - case CAM_CTLR_COLOR_YUV422: - *p_size = config->h_res * config->v_res * 2; - break; - case CAM_CTLR_COLOR_YUV420: - *p_size = (config->h_res * config->v_res / 2) * 3; - break; - case CAM_CTLR_COLOR_RGB888: - *p_size = config->h_res * config->v_res * 3; - break; - default: - ret = ESP_ERR_INVALID_ARG; - break; + color_space_pixel_format_t pixel_format = { + .color_type_id = config->input_data_color_type + }; + uint32_t depth = color_hal_pixel_format_get_bit_depth(pixel_format); + if (!depth) { + return ESP_ERR_INVALID_ARG; } + + *p_size = config->h_res * config->v_res * depth / 8; } return ret; @@ -317,12 +310,17 @@ esp_err_t esp_cam_ctlr_dvp_init(int ctlr_id, cam_clock_source_t clk_src, const e DVP_CAM_CONFIG_INPUT_PIN(pin->data_io[i], cam_periph_signals.buses[ctlr_id].data_sigs[i], false); } - ret = gpio_set_direction(pin->xclk_io, GPIO_MODE_OUTPUT); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "failed to configure pin=%d", pin->xclk_io); - return ret; + /* If using external XTAL, don't initialize xclock pin */ + + if (pin->xclk_io != GPIO_NUM_NC) { + gpio_func_sel(pin->xclk_io, PIN_FUNC_GPIO); + ret = gpio_set_direction(pin->xclk_io, GPIO_MODE_OUTPUT); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "failed to configure pin=%d", pin->xclk_io); + return ret; + } + esp_rom_gpio_connect_out_signal(pin->xclk_io, cam_periph_signals.buses[ctlr_id].clk_sig, false, false); } - esp_rom_gpio_connect_out_signal(pin->xclk_io, cam_periph_signals.buses[ctlr_id].clk_sig, false, false); PERIPH_RCC_ACQUIRE_ATOMIC(cam_periph_signals.buses[ctlr_id].module, ref_count) { if (ref_count == 0) { diff --git a/components/hal/include/hal/cam_ctlr_types.h b/components/hal/include/hal/cam_ctlr_types.h index 58307238213..65ba68c29d6 100644 --- a/components/hal/include/hal/cam_ctlr_types.h +++ b/components/hal/include/hal/cam_ctlr_types.h @@ -25,6 +25,8 @@ typedef enum { CAM_CTLR_COLOR_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), ///< RGB888 CAM_CTLR_COLOR_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), ///< YUV420 CAM_CTLR_COLOR_YUV422 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV422), ///< YUV422 + CAM_CTLR_COLOR_GRAY4 = COLOR_TYPE_ID(COLOR_SPACE_GRAY, COLOR_PIXEL_GRAY4), ///< GRAY4 + CAM_CTLR_COLOR_GRAY8 = COLOR_TYPE_ID(COLOR_SPACE_GRAY, COLOR_PIXEL_GRAY8), ///< GRAY8 } cam_ctlr_color_t; /** From 432aa793c43de16c29ce1e9440296a3558e1fee8 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Mon, 8 Jul 2024 10:39:02 +0200 Subject: [PATCH 350/548] fix(kconfig): Removed duplicate entry for IDF_TARGET_LINUX in Kconfig This commit removes a duplicate entry for the IDF_TARGET_LINUX Kconfig option in the project Kconfig file. Closes https://github.com/espressif/esp-idf/issues/14145 --- Kconfig | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Kconfig b/Kconfig index eff82a46915..743953656ae 100644 --- a/Kconfig +++ b/Kconfig @@ -75,10 +75,6 @@ mainmenu "Espressif IoT Development Framework Configuration" string default "$IDF_INIT_VERSION" - config IDF_TARGET_LINUX - bool - default "y" if IDF_TARGET="linux" - config IDF_TARGET_ESP32 bool default "y" if IDF_TARGET="esp32" From f6974ab18361cc6d3f288164216da8cb34bbae00 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Wed, 10 Jul 2024 13:48:00 +0530 Subject: [PATCH 351/548] fix(nimble): Update menuconfig option to consider 5.0 support --- .../bluetooth/nimble/ble_cts/cts_cent/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/ble_cts/cts_prph/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/ble_htp/htp_cent/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/ble_htp/htp_prph/main/Kconfig.projbuild | 2 +- .../nimble/ble_l2cap_coc/coc_blecent/main/Kconfig.projbuild | 2 +- .../nimble/ble_l2cap_coc/coc_bleprph/main/Kconfig.projbuild | 2 +- .../ble_multi_conn/ble_multi_conn_prph/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/ble_periodic_adv/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/ble_periodic_sync/main/Kconfig.projbuild | 2 +- .../proximity_sensor_cent/main/Kconfig.projbuild | 2 +- .../proximity_sensor_prph/main/Kconfig.projbuild | 2 +- examples/bluetooth/nimble/blecent/main/Kconfig.projbuild | 2 +- examples/bluetooth/nimble/bleprph/main/Kconfig.projbuild | 2 +- .../bluetooth/nimble/bleprph_host_only/main/Kconfig.projbuild | 2 +- examples/bluetooth/nimble/power_save/main/Kconfig.projbuild | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/bluetooth/nimble/ble_cts/cts_cent/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_cts/cts_cent/main/Kconfig.projbuild index 8cad8f99527..12750f2701d 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_cent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_cts/cts_cent/main/Kconfig.projbuild @@ -15,7 +15,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_cts/cts_prph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_cts/cts_prph/main/Kconfig.projbuild index a5240035348..8e5ab9f250a 100644 --- a/examples/bluetooth/nimble/ble_cts/cts_prph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_cts/cts_prph/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_htp/htp_cent/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_htp/htp_cent/main/Kconfig.projbuild index 8cad8f99527..12750f2701d 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_cent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_htp/htp_cent/main/Kconfig.projbuild @@ -15,7 +15,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_htp/htp_prph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_htp/htp_prph/main/Kconfig.projbuild index 92f93deb845..3705112d5e2 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_prph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_htp/htp_prph/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/Kconfig.projbuild index 58d5dc4ef8a..b259360eb0e 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_blecent/main/Kconfig.projbuild @@ -8,7 +8,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/Kconfig.projbuild index ede9e666abd..5d41352b16d 100644 --- a/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_l2cap_coc/coc_bleprph/main/Kconfig.projbuild @@ -50,7 +50,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/Kconfig.projbuild index 0662463dcb0..e57e163cccd 100644 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_periodic_adv/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_periodic_adv/main/Kconfig.projbuild index c7b32ae16d8..fd4037d16a6 100644 --- a/examples/bluetooth/nimble/ble_periodic_adv/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_periodic_adv/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_periodic_sync/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_periodic_sync/main/Kconfig.projbuild index 0763e71d72c..f5315592b1c 100644 --- a/examples/bluetooth/nimble/ble_periodic_sync/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_periodic_sync/main/Kconfig.projbuild @@ -1,7 +1,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/Kconfig.projbuild index c084eb3e35b..eefb5c98154 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_cent/main/Kconfig.projbuild @@ -15,7 +15,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/Kconfig.projbuild b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/Kconfig.projbuild index 92f93deb845..3705112d5e2 100644 --- a/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/ble_proximity_sensor/proximity_sensor_prph/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild b/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild index 23e88bae48c..13d5cd0ddf0 100644 --- a/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild @@ -8,7 +8,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/bleprph/main/Kconfig.projbuild b/examples/bluetooth/nimble/bleprph/main/Kconfig.projbuild index e4520eefa29..2529f3bab9a 100644 --- a/examples/bluetooth/nimble/bleprph/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/bleprph/main/Kconfig.projbuild @@ -50,7 +50,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/bleprph_host_only/main/Kconfig.projbuild b/examples/bluetooth/nimble/bleprph_host_only/main/Kconfig.projbuild index 197519e9038..1162b1216cc 100644 --- a/examples/bluetooth/nimble/bleprph_host_only/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/bleprph_host_only/main/Kconfig.projbuild @@ -110,7 +110,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" diff --git a/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild index 9fb8e732318..ca160813feb 100644 --- a/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild @@ -129,7 +129,7 @@ menu "Example Configuration" config EXAMPLE_EXTENDED_ADV bool - depends on SOC_BLE_50_SUPPORTED + depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT default y if SOC_ESP_NIMBLE_CONTROLLER select BT_NIMBLE_EXT_ADV prompt "Enable Extended Adv" From edf14a1de1f5379ed188a9f5f855e913111258bb Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 19 Jun 2024 11:43:42 +0800 Subject: [PATCH 352/548] fix(esp_hw_support): disable mpll clock after L1 dcache writeback --- .../esp_hw_support/port/esp32p4/pmu_sleep.c | 16 ++++++++++++++++ components/esp_hw_support/port/esp32p4/rtc_clk.c | 8 ++++---- components/esp_hw_support/sleep_modes.c | 14 -------------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index 1f86803d493..a9634f86840 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -11,6 +11,7 @@ #include "sdkconfig.h" #include "esp_err.h" #include "esp_attr.h" +#include "esp_private/rtc_clk.h" #include "esp_private/regi2c_ctrl.h" #include "esp32p4/rom/cache.h" #include "soc/chip_revision.h" @@ -22,6 +23,7 @@ #include "soc/pau_reg.h" #include "soc/pmu_reg.h" #include "soc/pmu_struct.h" +#include "hal/clk_tree_hal.h" #include "hal/lp_aon_hal.h" #include "soc/lp_system_reg.h" #include "hal/pmu_hal.h" @@ -290,6 +292,8 @@ FORCE_INLINE_ATTR void sleep_writeback_l1_dcache(void) { while (!REG_GET_BIT(CACHE_SYNC_CTRL_REG, CACHE_SYNC_DONE)); } +static TCM_DRAM_ATTR uint32_t s_mpll_freq_mhz_before_sleep = 0; + TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp) { lp_aon_hal_inform_wakeup_type(dslp); @@ -302,8 +306,15 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, pmu_ll_hp_clear_reject_intr_status(PMU_instance()->hal->dev); pmu_ll_hp_clear_reject_cause(PMU_instance()->hal->dev); + // !!! Need to manually check that data in L2 memory will not be modified from now on. !!! sleep_writeback_l1_dcache(); + // !!! Need to manually check that data in PSRAM will not be accessed from now on. !!! + s_mpll_freq_mhz_before_sleep = rtc_clk_mpll_get_freq(); + if (s_mpll_freq_mhz_before_sleep) { + rtc_clk_mpll_disable(); + } + /* Start entry into sleep mode */ pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev); @@ -333,6 +344,11 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp) pmu_sleep_shutdown_ldo(); } + if (s_mpll_freq_mhz_before_sleep) { + rtc_clk_mpll_enable(); + rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep); + } + // Wait eFuse memory update done. while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE); diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index a5e45222cc9..343aaf1955a 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -28,7 +28,7 @@ static const char *TAG = "rtc_clk"; static int s_cur_cpll_freq = 0; // MPLL frequency option, 400MHz. Zero if MPLL is not enabled. -static DRAM_ATTR uint32_t s_cur_mpll_freq = 0; +static TCM_DRAM_ATTR uint32_t s_cur_mpll_freq = 0; void rtc_clk_32k_enable(bool enable) { @@ -484,13 +484,13 @@ bool rtc_dig_8m_enabled(void) } //------------------------------------MPLL-------------------------------------// -void rtc_clk_mpll_disable(void) +TCM_IRAM_ATTR void rtc_clk_mpll_disable(void) { clk_ll_mpll_disable(); s_cur_mpll_freq = 0; } -void rtc_clk_mpll_enable(void) +TCM_IRAM_ATTR void rtc_clk_mpll_enable(void) { clk_ll_mpll_enable(); } @@ -508,7 +508,7 @@ void rtc_clk_mpll_configure(uint32_t xtal_freq, uint32_t mpll_freq) s_cur_mpll_freq = mpll_freq; } -uint32_t rtc_clk_mpll_get_freq(void) +TCM_IRAM_ATTR uint32_t rtc_clk_mpll_get_freq(void) { return s_cur_mpll_freq; } diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index faab42aaf3f..c05ba88355c 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -989,13 +989,6 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif #endif -#if SOC_CLK_MPLL_SUPPORTED - uint32_t mpll_freq_mhz = rtc_clk_mpll_get_freq(); - if (mpll_freq_mhz) { - rtc_clk_mpll_disable(); - } -#endif - #if SOC_DCDC_SUPPORTED #if CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON if (!deep_sleep) { @@ -1030,13 +1023,6 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep); #endif -#if SOC_CLK_MPLL_SUPPORTED - if (mpll_freq_mhz) { - rtc_clk_mpll_enable(); - rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), mpll_freq_mhz); - } -#endif - /* Unhold the SPI CS pin */ #if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) #if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359: related rtcio ll func not supported yet From 64ace5b6d8a27d79bcfafcc2d78849de99b3a018 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 11 Jul 2024 22:01:49 +0800 Subject: [PATCH 353/548] fix(esp_hw_support): fix cpu_retention cache invalidate mask --- .../port/esp32p4/sleep_cpu_asm.S | 3 +- .../esp_rom/include/esp32p4/rom/cache.h | 30 +++++++++++-------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S index 046ef617776..ef6aa2d19b0 100644 --- a/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S +++ b/components/esp_hw_support/lowpower/cpu_retention/port/esp32p4/sleep_cpu_asm.S @@ -9,6 +9,7 @@ #include "freertos/FreeRTOSConfig.h" #include "sdkconfig.h" +#include "esp32p4/rom/cache.h" #include "soc/cache_reg.h" #define MTVT (0x307) @@ -154,7 +155,7 @@ rv_core_critical_regs_restore: /* Core 0 is wakeup core, Invalidate L1 Cache here */ /* Invalidate L1 cache is required here!!! */ la t0, CACHE_SYNC_MAP_REG - li t1, 0x7 /* map l1 i/dcache */ + li t1, CACHE_MAP_L1_CACHE_MASK /* map l1 i/dcache */ sw t1, 0x0(t0) /* set EXTMEM_CACHE_SYNC_MAP_REG bit 4 */ la t2, CACHE_SYNC_ADDR_REG sw zero, 0x0(t2) /* clear EXTMEM_CACHE_SYNC_ADDR_REG */ diff --git a/components/esp_rom/include/esp32p4/rom/cache.h b/components/esp_rom/include/esp32p4/rom/cache.h index 95f4a4db05e..f505f6f46b5 100644 --- a/components/esp_rom/include/esp32p4/rom/cache.h +++ b/components/esp_rom/include/esp32p4/rom/cache.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,8 +7,10 @@ #ifndef _ROM_CACHE_H_ #define _ROM_CACHE_H_ +#if (!defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__)) #include #include "esp_bit_defs.h" +#endif #ifdef __cplusplus extern "C" { @@ -86,6 +88,16 @@ extern "C" { // should NOT = #define SMMU_GID_TBIT_INDEX_HIGH (SMMU_GID_TBIT_INDEX_LOW + SMMU_GID_TBIT_NUM) +#define CACHE_MAP_L1_ICACHE_0 BIT(0) +#define CACHE_MAP_L1_ICACHE_1 BIT(1) +#define CACHE_MAP_L1_DCACHE BIT(4) +#define CACHE_MAP_L2_CACHE BIT(5) + +#define CACHE_MAP_L1_ICACHE_MASK (CACHE_MAP_L1_ICACHE_0 | CACHE_MAP_L1_ICACHE_1) +#define CACHE_MAP_L1_CACHE_MASK (CACHE_MAP_L1_ICACHE_MASK | CACHE_MAP_L1_DCACHE) +#define CACHE_MAP_MASK (CACHE_MAP_L1_ICACHE_MASK | CACHE_MAP_L1_DCACHE | CACHE_MAP_L2_CACHE) + +#if (!defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__)) typedef enum { CACHE_L1_ICACHE0 = 0, CACHE_L1_ICACHE1 = 1, @@ -225,14 +237,6 @@ typedef enum { CACHE_SYNC_WRITEBACK_INVALIDATE = BIT(3), } cache_sync_t; -#define CACHE_MAP_L1_ICACHE_0 BIT(0) -#define CACHE_MAP_L1_ICACHE_1 BIT(1) -#define CACHE_MAP_L1_DCACHE BIT(4) -#define CACHE_MAP_L2_CACHE BIT(5) - -#define CACHE_MAP_L1_ICACHE_MASK (CACHE_MAP_L1_ICACHE_0 | CACHE_MAP_L1_ICACHE_1) -#define CACHE_MAP_MASK (CACHE_MAP_L1_ICACHE_MASK | CACHE_MAP_L1_DCACHE | CACHE_MAP_L2_CACHE) - struct cache_internal_stub_table { uint32_t (*l1_icache_line_size)(void); uint32_t (*l1_dcache_line_size)(void); @@ -507,7 +511,7 @@ void ROM_Direct_Boot_Cache_Init(void); * * @param None * - * @return 0 if mmu map is sucessfully, others if not. + * @return 0 if mmu map is successfully, others if not. */ int ROM_Direct_Boot_MMU_Init(void); @@ -1517,7 +1521,7 @@ void Cache_Freeze_L2_Cache_Disable(void); void Cache_Travel_Tag_Memory(struct cache_mode *mode, uint32_t filter_addr, void (*process)(struct tag_group_info *, int res[]), int res[]); /** - * @brief Travel tag memory to run a call back function using 2rd tag api. + * @brief Travel tag memory to run a call back function using 2nd tag api. * ICache and DCache are suspend when doing this. * The callback will get the parameter tag_group_info, which will include a group of tag memory addresses and cache memory addresses. * Please do not call this function in your SDK application. @@ -1539,7 +1543,7 @@ void Cache_Travel_Tag_Memory2(struct cache_mode *mode, uint32_t filter_addr, voi * * @param struct cache_mode * mode : the cache to calculate the virtual address and the cache mode. * - * @param uint32_t tag : the tag part fo a tag item, 12-14 bits. + * @param uint32_t tag : the tag part for a tag item, 12-14 bits. * * @param uint32_t addr_offset : the virtual address offset of the cache ways. * @@ -1602,6 +1606,8 @@ int flash2spiram_rodata_offset(void); uint32_t flash_instr_rodata_start_page(uint32_t bus); uint32_t flash_instr_rodata_end_page(uint32_t bus); +#endif // #if (!defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__)) + #ifdef __cplusplus } #endif From 5deaedfab1c4ce627fe7bcf0847df955f48c5aed Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Thu, 23 May 2024 14:49:35 +0530 Subject: [PATCH 354/548] fix(wifi): Fix issue of supplicant using wrong parameters to configure bss - Ensure that wpa_supplicant's state machine registers the requirement for rsnxe before deciding to add rsnxe to a assoc request. Co-authored-by: jgujarathi --- components/esp_wifi/lib | 2 +- .../wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h | 1 - components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c | 1 - components/wpa_supplicant/src/rsn_supp/wpa.c | 5 +++++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index eacd07f165f..73ed5e75a6b 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit eacd07f165fee254b37ee5819208e1185549ec59 +Subproject commit 73ed5e75a6b8d456583c84428d3f3e3713c99944 diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h index 44f8ca2cc33..248c18a62ca 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wifi_driver.h @@ -142,7 +142,6 @@ struct wpa_funcs { void (*wpa_config_done)(void); uint8_t *(*owe_build_dhie)(uint16_t group); int (*owe_process_assoc_resp)(const u8 *rsn_ie, size_t rsn_len, const uint8_t *dh_ie, size_t dh_len); - int (*wpa_sta_set_ap_rsnxe)(const u8 *rsnxe, size_t rsnxe_ie_len); }; struct wpa2_funcs { diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 5d1281f6d8d..8dd2596ed76 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -469,7 +469,6 @@ int esp_supplicant_init(void) wpa_cb->wpa_config_bss = NULL;//wpa_config_bss; wpa_cb->wpa_michael_mic_failure = wpa_michael_mic_failure; wpa_cb->wpa_config_done = wpa_config_done; - wpa_cb->wpa_sta_set_ap_rsnxe = wpa_sm_set_ap_rsnxe; esp_wifi_register_wpa3_ap_cb(wpa_cb); esp_wifi_register_wpa3_cb(wpa_cb); diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index df5448077d3..4e4e1893638 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -2434,6 +2434,11 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, if (res < 0) return -1; sm->assoc_wpa_ie_len = res; + + const u8 *rsnxe; + rsnxe = esp_wifi_sta_get_rsnxe((u8*)bssid); + wpa_sm_set_ap_rsnxe(rsnxe, rsnxe ? (rsnxe[1] + 2) : 0); + res = wpa_gen_rsnxe(sm, assoc_rsnxe, assoc_rsnxe_len); if (res < 0) return -1; From 8cac15e95bbe086b4a8006ee6a59b095830609d7 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Mon, 1 Jul 2024 15:41:13 +0800 Subject: [PATCH 355/548] ci(spi_lcd): re-enable spi_lcd test on p4 --- .../esp_lcd/test_apps/.build-test-rules.yml | 4 ---- .../test_apps/spi_lcd/main/test_spi_board.h | 16 +++++++++++++++- .../esp_lcd/test_apps/spi_lcd/pytest_spi_lcd.py | 2 -- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/components/esp_lcd/test_apps/.build-test-rules.yml b/components/esp_lcd/test_apps/.build-test-rules.yml index 998917f0ab9..d6308cf692b 100644 --- a/components/esp_lcd/test_apps/.build-test-rules.yml +++ b/components/esp_lcd/test_apps/.build-test-rules.yml @@ -52,7 +52,3 @@ components/esp_lcd/test_apps/spi_lcd: - esp_driver_spi disable: - if: SOC_GPSPI_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: test not pass, should be re-enable # TODO: IDF-8975 diff --git a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_board.h b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_board.h index ec4600376d8..9ce7d5224e8 100644 --- a/components/esp_lcd/test_apps/spi_lcd/main/test_spi_board.h +++ b/components/esp_lcd/test_apps/spi_lcd/main/test_spi_board.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +28,20 @@ extern "C" { #define TEST_LCD_DC_GPIO 1 #define TEST_LCD_PCLK_GPIO 2 #define TEST_LCD_DATA0_GPIO 4 +#elif CONFIG_IDF_TARGET_ESP32P4 +#define TEST_LCD_BK_LIGHT_GPIO 23 +#define TEST_LCD_RST_GPIO 6 +#define TEST_LCD_CS_GPIO 4 +#define TEST_LCD_DC_GPIO 3 +#define TEST_LCD_PCLK_GPIO 2 +#define TEST_LCD_DATA0_GPIO 32 +#define TEST_LCD_DATA1_GPIO 33 +#define TEST_LCD_DATA2_GPIO 22 +#define TEST_LCD_DATA3_GPIO 8 +#define TEST_LCD_DATA4_GPIO 21 +#define TEST_LCD_DATA5_GPIO 53 +#define TEST_LCD_DATA6_GPIO 20 +#define TEST_LCD_DATA7_GPIO 5 #else #define TEST_LCD_BK_LIGHT_GPIO 18 #define TEST_LCD_RST_GPIO 5 diff --git a/components/esp_lcd/test_apps/spi_lcd/pytest_spi_lcd.py b/components/esp_lcd/test_apps/spi_lcd/pytest_spi_lcd.py index f2ad352216e..2cdeaf11e8a 100644 --- a/components/esp_lcd/test_apps/spi_lcd/pytest_spi_lcd.py +++ b/components/esp_lcd/test_apps/spi_lcd/pytest_spi_lcd.py @@ -1,11 +1,9 @@ # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 support TBD') # TODO: IDF-8975 @pytest.mark.supported_targets @pytest.mark.generic @pytest.mark.parametrize( From 8a0a093cd137c729dc42c45b965f9308f7ee2cdd Mon Sep 17 00:00:00 2001 From: muhaidong Date: Wed, 3 Jul 2024 19:59:32 +0800 Subject: [PATCH 356/548] fix(wifi): fix esp32 host lack of lmac api issue --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 73ed5e75a6b..17509c30aec 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 73ed5e75a6b8d456583c84428d3f3e3713c99944 +Subproject commit 17509c30aecde2c38bf4d3cc3e860b9297cf23e8 From 821f4a181f26e9f3dbe5f0a40195cc5b3aa2abe2 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Mon, 29 Apr 2024 12:59:21 +0530 Subject: [PATCH 357/548] fix(wpa_supplicant): Handle case when WPS registrar misses WSC_DONE sent by station When registrar somehow misses the WSC_DONE sent by station and station goes for next connection after sending deauth, make sure that softAP disables the registrar. --- .../wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c | 2 +- components/wpa_supplicant/src/eap_server/eap_server_wsc.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c b/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c index 8ee66789229..044ca46223b 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_hostpad_wps.c @@ -220,7 +220,7 @@ int esp_wifi_ap_wps_enable(const esp_wps_config_t *config) return ret; } -static int wifi_ap_wps_disable_internal(void) +int wifi_ap_wps_disable_internal(void) { struct wps_sm *sm = gWpsSm; diff --git a/components/wpa_supplicant/src/eap_server/eap_server_wsc.c b/components/wpa_supplicant/src/eap_server/eap_server_wsc.c index f3c4756257f..653480efcc1 100644 --- a/components/wpa_supplicant/src/eap_server/eap_server_wsc.c +++ b/components/wpa_supplicant/src/eap_server/eap_server_wsc.c @@ -103,6 +103,13 @@ static void eap_wsc_reset(struct eap_sm *sm, void *priv) wpabuf_free(data->out_buf); //wps_deinit(data->wps); os_free(data); +#ifdef ESP_SUPPLICANT + /* TODO: When wps-registrar is shifted in a separate task other than wifi task, + * call esp_wifi_ap_wps_disable() here instead of wifi_ap_wps_disable_internal() + * */ + extern int wifi_ap_wps_disable_internal(void); + wifi_ap_wps_disable_internal(); +#endif } From 2475e6cd5d9567992f029fa0d80e9d261a05fbab Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Thu, 11 Jul 2024 12:55:42 +0530 Subject: [PATCH 358/548] fix(wpa_supplicant): Avoid delaying removal of wps enrollee by 10ms This is no longer needed as eloop timers are now executed in wifi task context. --- components/wpa_supplicant/src/ap/wpa_auth.c | 28 --------------------- 1 file changed, 28 deletions(-) diff --git a/components/wpa_supplicant/src/ap/wpa_auth.c b/components/wpa_supplicant/src/ap/wpa_auth.c index 24def335844..513ec9fa822 100644 --- a/components/wpa_supplicant/src/ap/wpa_auth.c +++ b/components/wpa_supplicant/src/ap/wpa_auth.c @@ -2620,21 +2620,6 @@ bool wpa_ap_join(struct sta_info *sta, uint8_t *bssid, uint8_t *wpa_ie, return true; } -#ifdef CONFIG_WPS_REGISTRAR -static void ap_free_sta_timeout(void *ctx, void *data) -{ - struct hostapd_data *hapd = (struct hostapd_data *) ctx; - u8 *addr = (u8 *) data; - struct sta_info *sta = ap_get_sta(hapd, addr); - - if (sta) { - ap_free_sta(hapd, sta); - } - - os_free(addr); -} -#endif - bool wpa_ap_remove(u8* bssid) { struct hostapd_data *hapd = hostapd_get_hapd_data(); @@ -2657,19 +2642,6 @@ bool wpa_ap_remove(u8* bssid) return true; } #endif /* CONFIG_SAE */ - -#ifdef CONFIG_WPS_REGISTRAR - wpa_printf(MSG_DEBUG, "wps_status=%d", wps_get_status()); - if (wps_get_status() == WPS_STATUS_PENDING) { - u8 *addr = os_malloc(ETH_ALEN); - - if (!addr) { - return false; - } - os_memcpy(addr, sta->addr, ETH_ALEN); - eloop_register_timeout(0, 10000, ap_free_sta_timeout, hapd, addr); - } else -#endif ap_free_sta(hapd, sta); return true; From f8bbf3f32d2b84b871e2e823057052c354a377d3 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Wed, 10 Jul 2024 12:05:28 +0200 Subject: [PATCH 359/548] fix(usb_dwc_hal): Enabled precise detection of VBUS --- .../hal/esp32p4/include/hal/usb_wrap_ll.h | 9 +++++++ .../usb/test_apps/hcd/main/test_hcd_port.c | 25 ++++++++++++++++++- components/usb/usb_phy_p4.c | 16 ++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/components/hal/esp32p4/include/hal/usb_wrap_ll.h b/components/hal/esp32p4/include/hal/usb_wrap_ll.h index 5e6b9423668..113a56fe771 100644 --- a/components/hal/esp32p4/include/hal/usb_wrap_ll.h +++ b/components/hal/esp32p4/include/hal/usb_wrap_ll.h @@ -12,6 +12,7 @@ #include "soc/lp_system_struct.h" #include "soc/lp_clkrst_struct.h" #include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_struct.h" // For HP_SYSTEM domain #include "soc/usb_wrap_struct.h" #include "hal/usb_wrap_types.h" @@ -262,6 +263,14 @@ FORCE_INLINE_ATTR void usb_wrap_ll_reset_register(void) // P_AON_CLKRST.hp_usb_clkrst_ctrlx are shared registers, so this function must be used in an atomic way #define usb_wrap_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; usb_wrap_ll_reset_register(__VA_ARGS__) +/* ------------------------------- HP System ------------------------------- */ + +FORCE_INLINE_ATTR void usb_wrap_ll_enable_precise_detection(void) +{ + // Enable VBUS precise detection + HP_SYSTEM.sys_usbotg20_ctrl.sys_otg_suspendm = 1; +} + #ifdef __cplusplus } #endif diff --git a/components/usb/test_apps/hcd/main/test_hcd_port.c b/components/usb/test_apps/hcd/main/test_hcd_port.c index 67f502335b0..7ddb4a2cb2b 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_port.c +++ b/components/usb/test_apps/hcd/main/test_hcd_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,29 @@ #define URB_DATA_BUFF_SIZE (sizeof(usb_setup_packet_t) + TRANSFER_MAX_BYTES) // 256 is worst case size for configuration descriptors #define POST_ENQUEUE_DELAY_US 10 +/* +Test a port for a disconnect event, when port is in ENABLED state + +Purpose: This test is essential on HS HCD ports, when device is detaching during the action. + When the HS port is ENABLED, the port operates in HS mode and device disconnection is detected by HS logic. + When the HS port is DISABLED (without issuing a reset), the port operates in FS mode and device disconnection differs for HS mode disconnection logic. + +Procedure: + - Setup the HCD and a port + - Trigger the port connection event + - Trigger the port disconnection event + - Teardown port and HCD +*/ +TEST_CASE("Test HCD port disconnect event, port enabled", "[port][low_speed][full_speed]") +{ + usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); // Trigger a connection + printf("Connected %s speed device \n", (char*[]) { + "Low", "Full", "High" + }[port_speed]); + vTaskDelay(pdMS_TO_TICKS(100)); // Short delay send of SOF (for FS) or EOPs (for LS) + test_hcd_wait_for_disconn(port_hdl, true); +} + /* Test a port sudden disconnect and port recovery diff --git a/components/usb/usb_phy_p4.c b/components/usb/usb_phy_p4.c index cff6420e082..a541fafe4c4 100644 --- a/components/usb/usb_phy_p4.c +++ b/components/usb/usb_phy_p4.c @@ -6,11 +6,27 @@ // This is only a dummy USB PHY file for successful linking of ESP32-P4 target // The internal HS PHY is enabled by default, therefore it needs no configuration + +// TODO: Refactor during the IDF-9198 +#include "sdkconfig.h" +#include "soc/usb_dwc_cfg.h" +#include "hal/usb_wrap_hal.h" // TODO: Remove this file when proper support of P4 PHYs is implemented IDF-7323 #include "esp_private/usb_phy.h" esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_ret) { +#if (OTG_HSPHY_INTERFACE != 0) +#if CONFIG_IDF_TARGET_ESP32P4 + /* + Additional setting to solve missing DCONN event on ESP32P4 (IDF-9953). + + Note: On ESP32P4, the HP_SYSTEM_OTG_SUSPENDM is not connected to 1 by hardware. + For correct detection of the device detaching, internal signal should be set to 1 by the software. + */ + usb_wrap_ll_enable_precise_detection(); +#endif // CONFIG_IDF_TARGET_ESP32P4 +#endif // (OTG_HSPHY_INTERFACE != 0) return ESP_OK; } From 5f6ddad456a2d43be93731da9717a420c4d9692a Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 11 Jul 2024 11:18:28 +0200 Subject: [PATCH 360/548] fix(lp-i2c): Fixed the generation of spurious I2C start with lp-i2c This commit fixes an issue with LP I2C and RTC I2C where in the peripherals generated a spurious I2C start condition when initialized. This caused some sensors to not respond properly to the following read or write request. Closes https://github.com/espressif/esp-idf/issues/14043 Closes https://github.com/espressif/esp-idf/issues/11608 --- components/ulp/lp_core/lp_core_i2c.c | 16 ++++++++++---- components/ulp/ulp_riscv/ulp_riscv_i2c.c | 27 ++++++++++++++++-------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/components/ulp/lp_core/lp_core_i2c.c b/components/ulp/lp_core/lp_core_i2c.c index 0d41f7fba1d..0b5db5add8b 100644 --- a/components/ulp/lp_core/lp_core_i2c.c +++ b/components/ulp/lp_core/lp_core_i2c.c @@ -53,9 +53,10 @@ static esp_err_t lp_i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_ static esp_err_t lp_i2c_configure_io(gpio_num_t io_num, bool pullup_en) { + /* Set the IO pin to high to avoid them from toggling from Low to High state during initialization. This can register a spurious I2C start condition. */ + ESP_RETURN_ON_ERROR(rtc_gpio_set_level(io_num, 1), LPI2C_TAG, "LP GPIO failed to set level to high for %d", io_num); /* Initialize IO Pin */ ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), LPI2C_TAG, "LP GPIO Init failed for GPIO %d", io_num); - /* Set direction to input+output open-drain mode */ ESP_RETURN_ON_ERROR(rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_INPUT_OUTPUT_OD), LPI2C_TAG, "LP GPIO Set direction failed for %d", io_num); /* Disable pulldown on the io pin */ @@ -82,12 +83,16 @@ static esp_err_t lp_i2c_set_pin(const lp_core_i2c_cfg_t *cfg) /* Verify that the LP I2C GPIOs are valid */ ESP_RETURN_ON_ERROR(lp_i2c_gpio_is_cfg_valid(sda_io_num, scl_io_num), LPI2C_TAG, "LP I2C GPIO config invalid"); - /* Initialize SDA Pin */ - ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA pin config failed"); + // NOTE: We always initialize the SCL pin first, then the SDA pin. + // This order of initialization is important to avoid any spurious + // I2C start conditions on the bus. /* Initialize SCL Pin */ ESP_RETURN_ON_ERROR(lp_i2c_configure_io(scl_io_num, scl_pullup_en), LPI2C_TAG, "LP I2C SCL pin config failed"); + /* Initialize SDA Pin */ + ESP_RETURN_ON_ERROR(lp_i2c_configure_io(sda_io_num, sda_pullup_en), LPI2C_TAG, "LP I2C SDA pin config failed"); + #if !SOC_LP_GPIO_MATRIX_SUPPORTED /* Select LP I2C function for the SDA Pin */ lp_io_dev->gpio[sda_io_num].mcu_sel = 1; @@ -123,7 +128,7 @@ static esp_err_t lp_i2c_config_clk(const lp_core_i2c_cfg_t *cfg) } } - /* Fetch the clock source fequency */ + /* Fetch the clock source frequency */ ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(source_clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX, &source_freq), LPI2C_TAG, "Invalid LP I2C source clock selected"); /* Verify that the I2C_SCLK operates at a frequency 20 times larger than the requested SCL bus frequency */ @@ -162,6 +167,9 @@ esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t i2c_hal_init(&i2c_hal, lp_i2c_num); } + /* Clear any pending interrupts */ + i2c_ll_clear_intr_mask(i2c_hal.dev, UINT32_MAX); + /* Initialize LP I2C Master mode */ i2c_hal_master_init(&i2c_hal); diff --git a/components/ulp/ulp_riscv/ulp_riscv_i2c.c b/components/ulp/ulp_riscv/ulp_riscv_i2c.c index a56be4c1bd2..531f023255b 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_i2c.c +++ b/components/ulp/ulp_riscv/ulp_riscv_i2c.c @@ -69,6 +69,8 @@ static esp_err_t i2c_gpio_is_cfg_valid(gpio_num_t sda_io_num, gpio_num_t scl_io_ static esp_err_t i2c_configure_io(gpio_num_t io_num, bool pullup_en) { + /* Set the IO pin to high to avoid them from toggling from Low to High state during initialization. This can register a spurious I2C start condition. */ + ESP_RETURN_ON_ERROR(rtc_gpio_set_level(io_num, 1), RTCI2C_TAG, "RTC GPIO failed to set level to high for %d", io_num); /* Initialize IO Pin */ ESP_RETURN_ON_ERROR(rtc_gpio_init(io_num), RTCI2C_TAG, "RTC GPIO Init failed for GPIO %d", io_num); /* Set direction to input+output */ @@ -95,12 +97,16 @@ static esp_err_t i2c_set_pin(const ulp_riscv_i2c_cfg_t *cfg) /* Verify that the I2C GPIOs are valid */ ESP_RETURN_ON_ERROR(i2c_gpio_is_cfg_valid(sda_io_num, scl_io_num), RTCI2C_TAG, "RTC I2C GPIO config invalid"); - /* Initialize SDA Pin */ - ESP_RETURN_ON_ERROR(i2c_configure_io(sda_io_num, sda_pullup_en), RTCI2C_TAG, "RTC I2C SDA pin config failed"); + // NOTE: We always initialize the SCL pin first, then the SDA pin. + // This order of initialization is important to avoid any spurious + // I2C start conditions on the bus. /* Initialize SCL Pin */ ESP_RETURN_ON_ERROR(i2c_configure_io(scl_io_num, scl_pullup_en), RTCI2C_TAG, "RTC I2C SCL pin config failed"); + /* Initialize SDA Pin */ + ESP_RETURN_ON_ERROR(i2c_configure_io(sda_io_num, sda_pullup_en), RTCI2C_TAG, "RTC I2C SDA pin config failed"); + /* Route SDA IO signal to the RTC subsystem */ rtc_io_dev->touch_pad[sda_io_num].mux_sel = 1; @@ -460,6 +466,12 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) WRITE_PERI_REG(RTC_I2C_CTRL_REG, 0); WRITE_PERI_REG(SENS_SAR_I2C_CTRL_REG, 0); + /* Verify that the input cfg param is valid */ + ESP_RETURN_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, RTCI2C_TAG, "RTC I2C configuration is NULL"); + + /* Configure RTC I2C GPIOs */ + ESP_RETURN_ON_ERROR(i2c_set_pin(cfg), RTCI2C_TAG, "Failed to configure RTC I2C GPIOs"); + /* Reset RTC I2C */ #if CONFIG_IDF_TARGET_ESP32S2 i2c_dev->ctrl.i2c_reset = 1; @@ -473,12 +485,6 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) CLEAR_PERI_REG_MASK(SENS_SAR_PERI_RESET_CONF_REG, SENS_RTC_I2C_RESET); #endif // CONFIG_IDF_TARGET_ESP32S2 - /* Verify that the input cfg param is valid */ - ESP_RETURN_ON_FALSE(cfg, ESP_ERR_INVALID_ARG, RTCI2C_TAG, "RTC I2C configuration is NULL"); - - /* Configure RTC I2C GPIOs */ - ESP_RETURN_ON_ERROR(i2c_set_pin(cfg), RTCI2C_TAG, "Failed to configure RTC I2C GPIOs"); - /* Enable internal open-drain mode for SDA and SCL lines */ #if CONFIG_IDF_TARGET_ESP32S2 i2c_dev->ctrl.sda_force_out = 0; @@ -505,9 +511,12 @@ esp_err_t ulp_riscv_i2c_master_init(const ulp_riscv_i2c_cfg_t *cfg) i2c_dev->i2c_ctrl.i2c_i2c_ctrl_clk_gate_en = 1; #endif // CONFIG_IDF_TARGET_ESP32S2 - /* Configure RTC I2C timing paramters */ + /* Configure RTC I2C timing parameters */ ESP_RETURN_ON_ERROR(i2c_set_timing(cfg), RTCI2C_TAG, "Failed to configure RTC I2C timing"); + /* Clear any pending interrupts */ + WRITE_PERI_REG(RTC_I2C_INT_CLR_REG, UINT32_MAX); + /* Enable RTC I2C interrupts */ SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA | RTC_I2C_TX_DATA_INT_ENA | From 8a18ae60e0798e12031d554681b52281967abbc9 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 Jun 2024 17:16:29 +0800 Subject: [PATCH 361/548] feat(touch_sens): touch sensor driver-ng on P4 --- components/driver/CMakeLists.txt | 8 +- .../touch_sensor/esp32s2/touch_sensor.c | 1 + .../touch_sensor/esp32s3/touch_sensor.c | 1 + .../touch_sensor/include/driver/touch_pad.h | 2 +- .../esp_driver_touch_sens/CMakeLists.txt | 21 + components/esp_driver_touch_sens/Kconfig | 25 + .../common/touch_sens_common.c | 428 +++++++++++++++ .../common/touch_sens_private.h | 191 +++++++ .../include/driver/touch_version_types.h | 12 + .../include/driver/touch_version_types.h | 12 + .../include/driver/touch_version_types.h | 503 ++++++++++++++++++ .../hw_ver3/touch_version_specific.c | 500 +++++++++++++++++ .../include/driver/touch_common_types.h | 30 ++ .../include/driver/touch_sens.h | 294 ++++++++++ components/esp_driver_touch_sens/linker.lf | 10 + .../include/esp_private/esp_pmu.h | 6 + components/esp_hw_support/sleep_modes.c | 22 +- components/hal/CMakeLists.txt | 15 +- .../hal/esp32/include/hal/touch_sensor_ll.h | 7 +- .../esp32p4/include/hal/touch_sensor_hal.h | 79 +++ .../hal/esp32p4/include/hal/touch_sensor_ll.h | 423 +++++++++------ components/hal/esp32p4/touch_sensor_hal.c | 82 +++ .../esp32s2/include/hal/touch_sensor_hal.h | 12 +- .../hal/esp32s2/include/hal/touch_sensor_ll.h | 36 +- components/hal/esp32s2/touch_sensor_hal.c | 6 +- .../esp32s3/include/hal/touch_sensor_hal.h | 12 +- .../hal/esp32s3/include/hal/touch_sensor_ll.h | 53 +- components/hal/esp32s3/touch_sensor_hal.c | 6 +- components/hal/include/hal/touch_sensor_hal.h | 4 +- .../hal/include/hal/touch_sensor_types.h | 4 +- .../soc/esp32/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32/include/soc/soc_caps.h | 2 +- components/soc/esp32/touch_sensor_periph.c | 2 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 26 +- .../include/soc/lp_analog_peri_struct.h | 12 +- components/soc/esp32p4/include/soc/soc_caps.h | 19 +- .../soc/esp32p4/include/soc/touch_reg.h | 52 +- .../soc/esp32p4/include/soc/touch_struct.h | 4 +- components/soc/esp32p4/touch_sensor_periph.c | 2 +- .../esp32s2/include/soc/Kconfig.soc_caps.in | 14 +- components/soc/esp32s2/include/soc/soc_caps.h | 13 +- components/soc/esp32s2/touch_sensor_periph.c | 2 +- .../esp32s3/include/soc/Kconfig.soc_caps.in | 14 +- components/soc/esp32s3/include/soc/soc_caps.h | 17 +- components/soc/esp32s3/touch_sensor_periph.c | 2 +- .../soc/include/soc/touch_sensor_periph.h | 10 +- .../touch_sensor/touch_periph_version.txt | 1 + 47 files changed, 2700 insertions(+), 299 deletions(-) create mode 100644 components/esp_driver_touch_sens/CMakeLists.txt create mode 100644 components/esp_driver_touch_sens/Kconfig create mode 100644 components/esp_driver_touch_sens/common/touch_sens_common.c create mode 100644 components/esp_driver_touch_sens/common/touch_sens_private.h create mode 100644 components/esp_driver_touch_sens/hw_ver1/include/driver/touch_version_types.h create mode 100644 components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h create mode 100644 components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h create mode 100644 components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c create mode 100644 components/esp_driver_touch_sens/include/driver/touch_common_types.h create mode 100644 components/esp_driver_touch_sens/include/driver/touch_sens.h create mode 100644 components/esp_driver_touch_sens/linker.lf create mode 100644 components/hal/esp32p4/include/hal/touch_sensor_hal.h create mode 100644 components/hal/esp32p4/touch_sensor_hal.c diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 9abd8e64c96..e350e1a72f7 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -73,9 +73,11 @@ endif() # Touch Sensor related source files if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED) - list(APPEND srcs "touch_sensor/touch_sensor_common.c" - "touch_sensor/${target}/touch_sensor.c") - list(APPEND includes "touch_sensor/${target}/include") + if(CONFIG_SOC_TOUCH_SENSOR_VERSION LESS 3) + list(APPEND srcs "touch_sensor/touch_sensor_common.c" + "touch_sensor/${target}/touch_sensor.c") + list(APPEND includes "touch_sensor/${target}/include") + endif() endif() # TWAI related source files diff --git a/components/driver/touch_sensor/esp32s2/touch_sensor.c b/components/driver/touch_sensor/esp32s2/touch_sensor.c index 67fce6d464c..42ed7c6291d 100644 --- a/components/driver/touch_sensor/esp32s2/touch_sensor.c +++ b/components/driver/touch_sensor/esp32s2/touch_sensor.c @@ -10,6 +10,7 @@ #include "esp_log.h" #include "sys/lock.h" #include "soc/soc_pins.h" +#include "soc/rtc_cntl_reg.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/timers.h" diff --git a/components/driver/touch_sensor/esp32s3/touch_sensor.c b/components/driver/touch_sensor/esp32s3/touch_sensor.c index e1b86db319e..d749996017b 100644 --- a/components/driver/touch_sensor/esp32s3/touch_sensor.c +++ b/components/driver/touch_sensor/esp32s3/touch_sensor.c @@ -10,6 +10,7 @@ #include "esp_log.h" #include "sys/lock.h" #include "soc/soc_pins.h" +#include "soc/rtc_cntl_reg.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/timers.h" diff --git a/components/driver/touch_sensor/include/driver/touch_pad.h b/components/driver/touch_sensor/include/driver/touch_pad.h index 3730eb386da..5de1a4121c7 100644 --- a/components/driver/touch_sensor/include/driver/touch_pad.h +++ b/components/driver/touch_sensor/include/driver/touch_pad.h @@ -8,6 +8,6 @@ #include "soc/soc_caps.h" -#if SOC_TOUCH_SENSOR_SUPPORTED +#if SOC_TOUCH_SENSOR_SUPPORTED && SOC_TOUCH_SENSOR_VERSION < 3 #include "driver/touch_sensor.h" #endif diff --git a/components/esp_driver_touch_sens/CMakeLists.txt b/components/esp_driver_touch_sens/CMakeLists.txt new file mode 100644 index 00000000000..e2a0c6040f8 --- /dev/null +++ b/components/esp_driver_touch_sens/CMakeLists.txt @@ -0,0 +1,21 @@ +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + return() # This component is not supported by the POSIX/Linux simulator +endif() + +set(srcs) +set(public_inc) + +if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED) + if(CONFIG_SOC_TOUCH_SENSOR_VERSION EQUAL 3) + list(APPEND srcs "hw_ver3/touch_version_specific.c" + "common/touch_sens_common.c") + list(APPEND public_inc "include" "hw_ver3/include") + endif() +endif() + +idf_component_register(SRCS ${srcs} + PRIV_REQUIRES esp_driver_gpio + INCLUDE_DIRS ${public_inc} + ) diff --git a/components/esp_driver_touch_sens/Kconfig b/components/esp_driver_touch_sens/Kconfig new file mode 100644 index 00000000000..ef9d304d2a8 --- /dev/null +++ b/components/esp_driver_touch_sens/Kconfig @@ -0,0 +1,25 @@ +menu "ESP-Driver:Touch Sensor Configurations" + depends on SOC_TOUCH_SENSOR_SUPPORTED + config TOUCH_CTRL_FUNC_IN_IRAM + bool "Place touch sensor control functions into IRAM" + default n + help + Place touch sensor oneshot scanning and continuous scanning functions into IRAM, + so that these function can be IRAM-safe and able to be called when the flash cache is disabled. + Enabling this option can improve driver performance as well. + + config TOUCH_ISR_IRAM_SAFE + bool "Touch sensor ISR IRAM-Safe" + default n + help + Ensure the touch sensor interrupt is IRAM-Safe by allowing the interrupt handler to be + executable when the cache is disabled (e.g. SPI Flash write). + + config TOUCH_ENABLE_DEBUG_LOG + bool "Enable debug log" + default n + help + Whether to enable the debug log message for touch driver. + Note that, this option only controls the touch driver log, won't affect other drivers. + +endmenu # Touch Sensor Configuration diff --git a/components/esp_driver_touch_sens/common/touch_sens_common.c b/components/esp_driver_touch_sens/common/touch_sens_common.c new file mode 100644 index 00000000000..0d647bf072f --- /dev/null +++ b/components/esp_driver_touch_sens/common/touch_sens_common.c @@ -0,0 +1,428 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/soc_caps.h" +#include "soc/rtc.h" +#include "soc/clk_tree_defs.h" +#include "soc/touch_sensor_periph.h" +#include "driver/rtc_io.h" +#include "driver/touch_sens.h" + +#if SOC_TOUCH_SENSOR_VERSION <= 2 +#include "esp_private/rtc_ctrl.h" +#else +#include "soc/interrupts.h" +#include "esp_intr_alloc.h" +#endif + +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "esp_check.h" +#include "touch_sens_private.h" + +#define TOUCH_CHANNEL_CHECK(num) ESP_RETURN_ON_FALSE(num >= TOUCH_MIN_CHAN_ID && num <= TOUCH_MAX_CHAN_ID, \ + ESP_ERR_INVALID_ARG, TAG, "The channel number is out of supported range"); + +static const char *TAG = "touch"; + +touch_sensor_handle_t g_touch = NULL; + +static void touch_channel_pin_init(int id) +{ + gpio_num_t pin = touch_sensor_channel_io_map[id]; + rtc_gpio_init(pin); + rtc_gpio_set_direction(pin, RTC_GPIO_MODE_DISABLED); + rtc_gpio_pulldown_dis(pin); + rtc_gpio_pullup_dis(pin); +} + +static void s_touch_free_resource(touch_sensor_handle_t sens_handle) +{ + if (!sens_handle) { + return; + } + if (sens_handle->mutex) { + vSemaphoreDeleteWithCaps(sens_handle->mutex); + sens_handle->mutex = NULL; + } + free(g_touch); + g_touch = NULL; +} + +esp_err_t touch_sensor_new_controller(const touch_sensor_config_t *sens_cfg, touch_sensor_handle_t *ret_sens_handle) +{ +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG + esp_log_level_set(TAG, ESP_LOG_DEBUG); +#endif + esp_err_t ret = ESP_OK; + TOUCH_NULL_POINTER_CHECK(sens_cfg); + TOUCH_NULL_POINTER_CHECK(ret_sens_handle); + ESP_RETURN_ON_FALSE(!g_touch, ESP_ERR_INVALID_STATE, TAG, "Touch sensor has been allocated"); + + g_touch = (touch_sensor_handle_t)heap_caps_calloc(1, sizeof(struct touch_sensor_s), TOUCH_MEM_ALLOC_CAPS); + ESP_RETURN_ON_FALSE(g_touch, ESP_ERR_NO_MEM, TAG, "No memory for touch sensor struct"); + + g_touch->mutex = xSemaphoreCreateMutexWithCaps(TOUCH_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(g_touch->mutex, ESP_ERR_NO_MEM, err, TAG, "No memory for mutex semaphore"); + + touch_priv_enable_module(true); + ESP_GOTO_ON_ERROR(touch_priv_config_controller(g_touch, sens_cfg), err, TAG, "Failed to configure the touch controller"); +#if SOC_TOUCH_SENSOR_VERSION <= 2 + ESP_GOTO_ON_ERROR(rtc_isr_register(touch_priv_default_intr_handler, NULL, TOUCH_LL_INTR_MASK_ALL, 0), err, TAG, "Failed to register interrupt handler"); +#else + ESP_GOTO_ON_ERROR(esp_intr_alloc(ETS_LP_TOUCH_INTR_SOURCE, TOUCH_INTR_ALLOC_FLAGS, touch_priv_default_intr_handler, NULL, &(g_touch->intr_handle)), + err, TAG, "Failed to register interrupt handler"); +#endif + *ret_sens_handle = g_touch; + return ret; + +err: + touch_priv_enable_module(false); + s_touch_free_resource(g_touch); + return ret; +} + +esp_err_t touch_sensor_del_controller(touch_sensor_handle_t sens_handle) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + ESP_RETURN_ON_FALSE(g_touch == sens_handle, ESP_ERR_INVALID_ARG, TAG, "The input touch sensor handle is unmatched"); + + esp_err_t ret = ESP_OK; + // Take the semaphore to make sure the touch has stopped + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Touch sensor has not disabled"); + FOR_EACH_TOUCH_CHANNEL(i) { + ESP_GOTO_ON_FALSE(!sens_handle->ch[i], ESP_ERR_INVALID_STATE, err, TAG, "There are still some touch channels not deleted"); + } + + ESP_GOTO_ON_ERROR(touch_priv_deinit_controller(sens_handle), err, TAG, "Failed to deinitialize the controller"); +#if SOC_TOUCH_SENSOR_VERSION <= 2 + ESP_GOTO_ON_ERROR(rtc_isr_deregister(touch_priv_default_intr_handler, NULL), err, TAG, "Failed to deregister the interrupt handler"); +#else + ESP_GOTO_ON_ERROR(esp_intr_free(sens_handle->intr_handle), err, TAG, "Failed to deregister the interrupt handler"); +#endif + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_intr_disable(TOUCH_LL_INTR_MASK_ALL); + touch_ll_clear_active_channel_status(); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + touch_priv_enable_module(false); + s_touch_free_resource(sens_handle); +err: + if (g_touch && g_touch->mutex) { + xSemaphoreGive(g_touch->mutex); + } + return ret; +} + +esp_err_t touch_sensor_new_channel(touch_sensor_handle_t sens_handle, int chan_id, + const touch_channel_config_t *chan_cfg, + touch_channel_handle_t *ret_chan_handle) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + TOUCH_NULL_POINTER_CHECK(chan_cfg); + TOUCH_NULL_POINTER_CHECK(ret_chan_handle); + TOUCH_CHANNEL_CHECK(chan_id); + ESP_RETURN_ON_FALSE(g_touch == sens_handle, ESP_ERR_INVALID_ARG, TAG, "The input touch sensor handle is unmatched"); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err2, TAG, "Please disable the touch sensor first"); + ESP_GOTO_ON_FALSE(!sens_handle->ch[chan_id], ESP_ERR_INVALID_STATE, err2, TAG, "The channel %d has been registered", chan_id); + + sens_handle->ch[chan_id] = (touch_channel_handle_t)heap_caps_calloc(1, sizeof(struct touch_channel_s), TOUCH_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(sens_handle->ch[chan_id], ESP_ERR_NO_MEM, err2, TAG, "No memory for touch channel"); + sens_handle->ch[chan_id]->id = chan_id; + sens_handle->ch[chan_id]->base = sens_handle; + sens_handle->ch[chan_id]->is_prox_chan = false; + + /* Init the channel */ + ESP_GOTO_ON_ERROR(touch_priv_config_channel(sens_handle->ch[chan_id], chan_cfg), + err1, TAG, "Failed to configure the touch channel %d", chan_id); + touch_channel_pin_init(chan_id); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); +#if SOC_TOUCH_SENSOR_VERSION == 2 + touch_ll_reset_chan_benchmark(1 << chan_id); +#endif + sens_handle->chan_mask |= 1 << chan_id; + touch_ll_set_channel_mask(sens_handle->chan_mask); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + *ret_chan_handle = sens_handle->ch[chan_id]; + + xSemaphoreGive(sens_handle->mutex); + return ret; +err1: + free(sens_handle->ch[chan_id]); + sens_handle->ch[chan_id] = NULL; +err2: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_del_channel(touch_channel_handle_t chan_handle) +{ + TOUCH_NULL_POINTER_CHECK(chan_handle); + + esp_err_t ret = ESP_OK; + touch_sensor_handle_t sens_handle = chan_handle->base; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); +#if SOC_TOUCH_SENSOR_VERSION == 2 + if (sens_handle->guard_chan == chan_handle || (BIT(chan_handle->id) & sens_handle->shield_chan_mask)) { + ESP_GOTO_ON_ERROR(touch_sensor_config_waterproof(sens_handle, NULL), err, TAG, "Failed to disable waterproof on this channel"); + } + if (sens_handle->sleep_chan == chan_handle) { + ESP_GOTO_ON_ERROR(touch_sensor_config_sleep_channel(sens_handle, NULL), err, TAG, "Failed to disable sleep function on this channel"); + } +#endif + int id = chan_handle->id; + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->chan_mask &= ~(1UL << id); + touch_ll_set_channel_mask(sens_handle->chan_mask); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + free(g_touch->ch[id]); + g_touch->ch[id] = NULL; +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_reconfig_controller(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + TOUCH_NULL_POINTER_CHECK(sens_cfg); + ESP_RETURN_ON_FALSE(sens_cfg->meas_interval_us >= 0, ESP_ERR_INVALID_ARG, TAG, "interval_us should be a positive value"); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + ESP_GOTO_ON_ERROR(touch_priv_config_controller(sens_handle, sens_cfg), err, TAG, "Configure touch controller failed"); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_enable(touch_sensor_handle_t sens_handle) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTakeRecursive(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Touch sensor has already enabled"); + ESP_GOTO_ON_FALSE(sens_handle->sample_cfg_num, ESP_ERR_INVALID_STATE, err, TAG, "No sample configuration was added to the touch controller"); + + sens_handle->is_enabled = true; + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_intr_clear(TOUCH_LL_INTR_MASK_ALL); + touch_ll_intr_enable(TOUCH_LL_INTR_MASK_ALL); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); +#if SOC_TOUCH_SUPPORT_PROX_SENSING + /* Reset the cached data of proximity channel */ + FOR_EACH_TOUCH_CHANNEL(i) { + if (sens_handle->ch[i] && sens_handle->ch[i]->is_prox_chan) { + sens_handle->ch[i]->prox_cnt = 0; + memset(sens_handle->ch[i]->prox_val, 0, sizeof(sens_handle->ch[i]->prox_val[0]) * TOUCH_SAMPLE_CFG_NUM); + } + } +#endif + +err: + xSemaphoreGiveRecursive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_disable(touch_sensor_handle_t sens_handle) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Touch sensor has not enabled"); + + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_intr_disable(TOUCH_LL_INTR_MASK_ALL); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->is_enabled = false; + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_reconfig_channel(touch_channel_handle_t chan_handle, const touch_channel_config_t *chan_cfg) +{ + TOUCH_NULL_POINTER_CHECK(chan_handle); + TOUCH_NULL_POINTER_CHECK(chan_cfg); + + esp_err_t ret = ESP_OK; + touch_sensor_handle_t sens_handle = chan_handle->base; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + ESP_GOTO_ON_ERROR(touch_priv_config_channel(chan_handle, chan_cfg), err, TAG, "Configure touch channel failed"); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_start_continuous_scanning(touch_sensor_handle_t sens_handle) +{ + TOUCH_NULL_POINTER_CHECK_ISR(sens_handle); + + esp_err_t ret = ESP_OK; + + ESP_GOTO_ON_FALSE_ISR(sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please enable the touch sensor first"); + ESP_GOTO_ON_FALSE_ISR(!sens_handle->is_started, ESP_ERR_INVALID_STATE, err, TAG, "Continuous scanning has started already"); + + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + sens_handle->is_started = true; +#if SOC_TOUCH_SENSOR_VERSION <= 2 + touch_ll_set_fsm_mode(TOUCH_FSM_MODE_TIMER); + touch_ll_start_fsm(); +#else + touch_ll_enable_fsm_timer(true); + touch_ll_start_fsm_repeated_timer(false); +#endif + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + +err: + return ret; +} + +esp_err_t touch_sensor_stop_continuous_scanning(touch_sensor_handle_t sens_handle) +{ + TOUCH_NULL_POINTER_CHECK_ISR(sens_handle); + + esp_err_t ret = ESP_OK; + + ESP_GOTO_ON_FALSE_ISR(sens_handle->is_started, ESP_ERR_INVALID_STATE, err, TAG, "Continuous scanning not started yet"); + + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); +#if SOC_TOUCH_SENSOR_VERSION <= 2 + touch_ll_stop_fsm(); + touch_ll_set_fsm_mode(TOUCH_FSM_MODE_SW); +#else + touch_ll_stop_fsm_repeated_timer(false); + touch_ll_enable_fsm_timer(false); +#endif + sens_handle->is_started = false; + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + +err: + return ret; +} + +esp_err_t touch_sensor_trigger_oneshot_scanning(touch_sensor_handle_t sens_handle, int timeout_ms) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + ESP_GOTO_ON_FALSE(sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please enable the touch sensor first"); + ESP_GOTO_ON_FALSE(!sens_handle->is_started, ESP_ERR_INVALID_STATE, err, TAG, "Failed to trigger oneshot scanning because scanning has started"); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->is_started = true; + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + TickType_t ticks = 0; + if (timeout_ms > 0) { + ticks = pdMS_TO_TICKS(timeout_ms); + if (!ticks) { + ESP_LOGW(TAG, "The timeout is too small, use the minimum tick resolution as default: %"PRIu32" ms", portTICK_PERIOD_MS); + ticks = 1; + } + } + xSemaphoreTake(sens_handle->mutex, ticks); + TickType_t end_tick = xTaskGetTickCount() + ticks; + // TODO: extract the following implementation into version specific source file when supporting other targets + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_enable_fsm_timer(false); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + FOR_EACH_TOUCH_CHANNEL(i) { + if (sens_handle->ch[i]) { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_channel_sw_measure_mask(BIT(i)); + touch_ll_trigger_oneshot_measurement(); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + while (!touch_ll_is_measure_done()) { + if (g_touch->is_meas_timeout) { + g_touch->is_meas_timeout = false; + ESP_LOGW(TAG, "The measurement time on channel %d exceed the limitation", i); + break; + } + if (timeout_ms >= 0) { + ESP_GOTO_ON_FALSE(xTaskGetTickCount() <= end_tick, ESP_ERR_TIMEOUT, err, TAG, "Wait for measurement done timeout"); + } + vTaskDelay(1); + } + } + } + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_channel_sw_measure_mask(0); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + +err: + xSemaphoreGive(sens_handle->mutex); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->is_started = false; + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + return ret; +} + +esp_err_t touch_sensor_register_callbacks(touch_sensor_handle_t sens_handle, const touch_event_callbacks_t *callbacks, void *user_ctx) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + TOUCH_NULL_POINTER_CHECK(callbacks); + +#if CONFIG_TOUCH_ISR_IRAM_SAFE + const uint32_t **ptr = (const uint32_t **)callbacks; + for (int i = 0; i < sizeof(touch_event_callbacks_t) / sizeof(uint32_t *); i++) { + ESP_RETURN_ON_FALSE(TOUCH_IRAM_CHECK(ptr[i]), ESP_ERR_INVALID_ARG, TAG, "callback not in IRAM"); + } + ESP_RETURN_ON_FALSE(!user_ctx || esp_ptr_internal(user_ctx), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); +#endif + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + memcpy(&sens_handle->cbs, callbacks, sizeof(touch_event_callbacks_t)); + sens_handle->user_ctx = user_ctx; + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_channel_read_data(touch_channel_handle_t chan_handle, touch_chan_data_type_t type, uint32_t *data) +{ + TOUCH_NULL_POINTER_CHECK_ISR(chan_handle); + TOUCH_NULL_POINTER_CHECK_ISR(data); + return touch_priv_channel_read_data(chan_handle, type, data); +} + +esp_err_t touch_sensor_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op) +{ + TOUCH_NULL_POINTER_CHECK_ISR(chan_handle); + TOUCH_NULL_POINTER_CHECK_ISR(benchmark_op); + touch_priv_set_benchmark(chan_handle, benchmark_op); + return ESP_OK; +} diff --git a/components/esp_driver_touch_sens/common/touch_sens_private.h b/components/esp_driver_touch_sens/common/touch_sens_private.h new file mode 100644 index 00000000000..3eac7d4a9c4 --- /dev/null +++ b/components/esp_driver_touch_sens/common/touch_sens_private.h @@ -0,0 +1,191 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This header file is private for the internal use of the touch driver + * DO NOT use any APIs or types in this file outside of the touch driver + */ + +#pragma once + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/soc_caps.h" +#include "hal/touch_sensor_hal.h" +#include "driver/touch_common_types.h" +#include "esp_memory_utils.h" +#include "esp_check.h" +#include "sdkconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper macros */ +#define TOUCH_NULL_POINTER_CHECK(p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL") +#define TOUCH_NULL_POINTER_CHECK_ISR(p) ESP_RETURN_ON_FALSE_ISR((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL") +#define FOR_EACH_TOUCH_CHANNEL(i) for (int i = 0; i < SOC_TOUCH_SENSOR_NUM; i++) +#define TOUCH_IRAM_CHECK(cb) (!(cb) || esp_ptr_in_iram(cb)) + +/* IRAM safe caps */ +#if CONFIG_TOUCH_ISR_IRAM_SAFE +#define TOUCH_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define TOUCH_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) +#else +#define TOUCH_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) +#define TOUCH_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT +#endif //CONFIG_TOUCH_ISR_IRAM_SAFE + +/* DMA caps */ +#define TOUCH_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA) + +/* RTC peripheral spin lock */ +extern portMUX_TYPE rtc_spinlock; +#define TOUCH_RTC_LOCK (&rtc_spinlock) + +#if SOC_TOUCH_SENSOR_VERSION <= 2 +#define TOUCH_PERIPH_LOCK (&rtc_spinlock) +#else +extern portMUX_TYPE g_touch_spinlock; +#define TOUCH_PERIPH_LOCK (&g_touch_spinlock) +#endif + +#define TOUCH_ENTER_CRITICAL(spinlock) portENTER_CRITICAL(spinlock) +#define TOUCH_EXIT_CRITICAL(spinlock) portEXIT_CRITICAL(spinlock) +#define TOUCH_ENTER_CRITICAL_SAFE(spinlock) portENTER_CRITICAL_SAFE(spinlock) +#define TOUCH_EXIT_CRITICAL_SAFE(spinlock) portEXIT_CRITICAL_SAFE(spinlock) + +/** + * @brief The touch sensor controller instance structure + * @note A touch sensor controller includes multiple channels and sample configurations + * + */ +struct touch_sensor_s { + touch_channel_handle_t ch[SOC_TOUCH_SENSOR_NUM]; /*!< Touch sensor channel handles, will be NULL if the channel is not registered */ + uint32_t chan_mask; /*!< Enabled channel mask, corresponding bit will be set if the channel is registered */ + uint32_t src_freq_hz; /*!< Source clock frequency */ + intr_handle_t intr_handle; /*!< Interrupt handle */ + touch_event_callbacks_t cbs; /*!< Event callbacks */ + touch_channel_handle_t deep_slp_chan; /*!< The configured channel for depp sleep, will be NULL if not enable the deep sleep */ + touch_channel_handle_t guard_chan; /*!< The configured channel for the guard ring, will be NULL if not set */ + touch_channel_handle_t shield_chan; /*!< The configured channel for the shield pad, will be NULL if not set */ + + SemaphoreHandle_t mutex; /*!< Mutex lock to ensure thread safety */ + + uint8_t sample_cfg_num; /*!< The number of sample configurations that in used */ + void *user_ctx; /*!< User context that will pass to the callback function */ + bool is_enabled; /*!< Flag to indicate whether the scanning is enabled */ + bool is_started; /*!< Flag to indicate whether the scanning has started */ + bool is_meas_timeout; /*!< Flag to indicate whether the measurement timeout, will force to stop the current measurement if the timeout is triggered */ + bool sleep_en; /*!< Flag to indicate whether the sleep wake-up feature is enabled */ + bool waterproof_en; /*!< Flag to indicate whether the water proof feature is enabled */ + bool proximity_en; /*!< Flag to indicate whether the proximity sensing feature is enabled */ + bool timeout_en; /*!< Flag to indicate whether the measurement timeout feature (hardware timeout) is enabled */ +}; + +/** + * @brief The touch sensor channel instance structure + * + */ +struct touch_channel_s { + touch_sensor_handle_t base; /*!< The touch sensor controller handle */ + int id; /*!< Touch channel id, the range is target-specific */ + bool is_prox_chan; /*!< Flag to indicate whether this is a proximity channel */ + uint32_t prox_cnt; /*!< Cache the proximity measurement count, only takes effect when the channel is a proximity channel. + * When this count reaches `touch_proximity_config_t::scan_times`, + * this field will be cleared and call the `on_proximity_meas_done` callback. + */ + uint32_t prox_val[TOUCH_SAMPLE_CFG_NUM]; /*!< The accumulated proximity value of each sample config. + * The value will accumulate for each scanning until it reaches `touch_proximity_config_t::scan_times`. + * This accumulated proximity value can be read via `touch_channel_read_data` when all scanning finished. + */ +}; + +extern touch_sensor_handle_t g_touch; /*!< Global touch sensor controller handle for `esp_driver_touch_sens` use only */ + +/** + * @brief Touch sensor module enable interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] enable Set true to enable touch sensor module clock + */ +void touch_priv_enable_module(bool enable); + +/** + * @brief Touch sensor default interrupt handler + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] arg The input argument + */ +void touch_priv_default_intr_handler(void *arg); + +/** + * @brief Touch sensor controller configuration interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] sens_handle The touch sensor controller handle + * @param[in] sens_cfg The touch sensor controller configuration pointer + * @return + * - ESP_OK On success + * - Others Version-specific failure code + */ +esp_err_t touch_priv_config_controller(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg); + +/** + * @brief Touch sensor channel configuration interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] chan_handle The touch sensor channel handle + * @param[in] chan_cfg The touch sensor channel configuration pointer + * @return + * - ESP_OK On success + * - Others Version-specific failure code + */ +esp_err_t touch_priv_config_channel(touch_channel_handle_t chan_handle, const touch_channel_config_t *chan_cfg); + +/** + * @brief Touch sensor controller de-initialize interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] sens_handle The touch sensor handle + * @return + * - ESP_OK On success + * - Others Version-specific failure code + */ +esp_err_t touch_priv_deinit_controller(touch_sensor_handle_t sens_handle); + +/** + * @brief Touch sensor channel data read interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] chan_handle The touch sensor channel handle + * @param[in] type The read data type + * @param[out] data The output data pointer + * @return + * - ESP_OK On success + * - Others Version-specific failure code + */ +esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch_chan_data_type_t type, uint32_t *data); + +/** + * @brief Touch sensor channel benchmark set interface + * @note This is a private interface of `esp_driver_touch_sens` + * It should be implemented by each hardware version + * + * @param[in] chan_handle The channel handle + * @param[in] benchmark_op The benchmark operation + */ +void touch_priv_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/hw_ver1/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver1/include/driver/touch_version_types.h new file mode 100644 index 00000000000..230a0df55ee --- /dev/null +++ b/components/esp_driver_touch_sens/hw_ver1/include/driver/touch_version_types.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This file is only applicable to the touch hardware version1 + * Version 1 includes ESP32 + */ + +#error "'esp_driver_touch_sens' does not support for ESP32 yet" diff --git a/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h new file mode 100644 index 00000000000..3eb0d2167e9 --- /dev/null +++ b/components/esp_driver_touch_sens/hw_ver2/include/driver/touch_version_types.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This file is only applicable to the touch hardware version2 + * Version 2 includes ESP32-S2 and ESP32-S3 + */ + +#error "'esp_driver_touch_sens' does not support for ESP32-S2 and ESP32-S3 yet" diff --git a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h new file mode 100644 index 00000000000..591bd7d8d0f --- /dev/null +++ b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h @@ -0,0 +1,503 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This file is only applicable to the touch hardware version3 + * Version 3 includes ESP32-P4 + */ + +#pragma once + +#include "soc/soc_caps.h" +#include "driver/touch_common_types.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TOUCH_MIN_CHAN_ID 0 /*!< The minimum available channel id of the touch pad */ +#define TOUCH_MAX_CHAN_ID 13 /*!< The maximum available channel id of the touch pad */ + +/** + * @brief Helper macro to the default configurations of the touch sensor controller + * + */ +#define TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(sample_cfg_number, sample_cfg_array) { \ + .power_on_wait_us = 256, \ + .meas_interval_us = 32.0, \ + .max_meas_time_us = 0, \ + .output_mode = TOUCH_PAD_OUT_AS_CLOCK, \ + .sample_cfg_num = sample_cfg_number, \ + .sample_cfg = sample_cfg_array, \ +} + +/** + * @brief Helper macro to the default sample configurations + * @note This default configuration is based on clock frequency 16MHz + * + */ +#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0() { \ + .freq_hz = 16000000, \ + .charge_times = 500, \ + .rc_filter_res = 2, \ + .rc_filter_cap = 88, \ + .low_drv = 3, \ + .high_drv = 0, \ + .bias_volt = 5, \ + .bypass_shield_output = false, \ +} + +/** + * @brief Helper macro to the default sample configurations + * @note This default configuration is based on clock frequency 8MHz + * + */ +#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1() { \ + .freq_hz = 8000000, \ + .charge_times = 500, \ + .rc_filter_res = 3, \ + .rc_filter_cap = 29, \ + .low_drv = 3, \ + .high_drv = 8, \ + .bias_volt = 5, \ + .bypass_shield_output = false, \ +} + +/** + * @brief Helper macro to the default sample configurations + * @note This default configuration is based on clock frequency 4MHz + * + */ +#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2() { \ + .freq_hz = 4000000, \ + .charge_times = 500, \ + .rc_filter_res = 3, \ + .rc_filter_cap = 10, \ + .low_drv = 7, \ + .high_drv = 31, \ + .bias_volt = 15, \ + .bypass_shield_output = false, \ +} + +#define TOUCH_SENSOR_DEFAULT_FILTER_CONFIG() { \ + .benchmark = { \ + .filter_mode = TOUCH_BM_IIR_FILTER_4, \ + .jitter_step = 4, \ + .update = { \ + .pos_thresh = TOUCH_UPDATE_BM_POS_THRESH_1_4, \ + .neg_thresh = TOUCH_UPDATE_BM_NEG_THRESH_1_4, \ + .neg_limit = 5, \ + }, \ + }, \ + .data = { \ + .smooth_filter = TOUCH_SMOOTH_IIR_FILTER_2, \ + .active_hysteresis = 2, \ + }, \ +} + +/** + * @brief The data type of the touch channel + * + */ +typedef enum { + TOUCH_CHAN_DATA_TYPE_SMOOTH, /*!< The smooth data of the touch channel */ + TOUCH_CHAN_DATA_TYPE_BENCHMARK, /*!< The benchmark of the touch channel */ + TOUCH_CHAN_DATA_TYPE_PROXIMITY, /*!< The proximity data of the proximity channel */ +} touch_chan_data_type_t; + +/** + * @brief The chip sleep level that allows the touch sensor to wake-up + * + */ +typedef enum { + TOUCH_LIGHT_SLEEP_WAKEUP, /*!< Only enable the touch sensor to wake up the chip from light sleep */ + TOUCH_DEEP_SLEEP_WAKEUP, /*!< Enable the touch sensor to wake up the chip from deep sleep or light sleep */ +} touch_sleep_wakeup_level_t; + +/** + * @brief Touch sensor shield channel drive capability level + * + */ +typedef enum { + TOUCH_SHIELD_CAP_40PF, /*!< The max equivalent capacitance in shield channel is 40pf */ + TOUCH_SHIELD_CAP_80PF, /*!< The max equivalent capacitance in shield channel is 80pf */ + TOUCH_SHIELD_CAP_120PF, /*!< The max equivalent capacitance in shield channel is 120pf */ + TOUCH_SHIELD_CAP_160PF, /*!< The max equivalent capacitance in shield channel is 160pf */ + TOUCH_SHIELD_CAP_200PF, /*!< The max equivalent capacitance in shield channel is 200pf */ + TOUCH_SHIELD_CAP_240PF, /*!< The max equivalent capacitance in shield channel is 240pf */ + TOUCH_SHIELD_CAP_280PF, /*!< The max equivalent capacitance in shield channel is 280pf */ + TOUCH_SHIELD_CAP_320PF, /*!< The max equivalent capacitance in shield channel is 320pf */ +} touch_chan_shield_cap_t; + +/** + * @brief Touch channel Infinite Impulse Response (IIR) filter or Jitter filter for benchmark + * @note Recommended filter coefficient selection is `IIR_16`. + */ +typedef enum { + TOUCH_BM_IIR_FILTER_4, /*!< IIR Filter for benchmark, 1/4 raw_value + 3/4 benchmark */ + TOUCH_BM_IIR_FILTER_8, /*!< IIR Filter for benchmark, 1/8 raw_value + 7/8 benchmark */ + TOUCH_BM_IIR_FILTER_16, /*!< IIR Filter for benchmark, 1/16 raw_value + 15/16 benchmark (typical) */ + TOUCH_BM_IIR_FILTER_32, /*!< IIR Filter for benchmark, 1/32 raw_value + 31/32 benchmark */ + TOUCH_BM_IIR_FILTER_64, /*!< IIR Filter for benchmark, 1/64 raw_value + 63/64 benchmark */ + TOUCH_BM_IIR_FILTER_128, /*!< IIR Filter for benchmark, 1/128 raw_value + 127/128 benchmark */ + TOUCH_BM_JITTER_FILTER, /*!< Jitter Filter for benchmark, raw value +/- jitter_step */ +} touch_benchmark_filter_mode_t; + +/** + * @brief Positive noise limitation of benchmark + * benchmark will only update gradually when + * the smooth data within the positive noise limitation + * + */ +typedef enum { + TOUCH_UPDATE_BM_POS_ALWAYS = -1, /*!< Always update benchmark when (smooth_data - benchmark) > 0 */ + TOUCH_UPDATE_BM_POS_THRESH_1_2 = 0, /*!< Only update benchmark when the (smooth_data - benchmark) < 1/2 * activate_threshold */ + TOUCH_UPDATE_BM_POS_THRESH_3_8, /*!< Only update benchmark when the (smooth_data - benchmark) < 3/8 * activate_threshold */ + TOUCH_UPDATE_BM_POS_THRESH_1_4, /*!< Only update benchmark when the (smooth_data - benchmark) < 1/4 * activate_threshold */ + TOUCH_UPDATE_BM_POS_THRESH_1, /*!< Only update benchmark when the (smooth_data - benchmark) < 1 * activate_threshold */ +} touch_benchmark_pos_thresh_t; + +/** + * @brief Negative noise limitation of benchmark + * benchmark will only update gradually when + * the smooth data within the negative noise limitation + * + */ +typedef enum { + TOUCH_UPDATE_BM_NEG_NEVER = -2, /*!< Never update benchmark when (benchmark - smooth_data) > 0 */ + TOUCH_UPDATE_BM_NEG_ALWAYS = -1, /*!< Always update benchmark when (benchmark - smooth_data) > 0 */ + TOUCH_UPDATE_BM_NEG_THRESH_1_2 = 0, /*!< Only update benchmark when the (benchmark - smooth_data) < 1/2 * activate_threshold */ + TOUCH_UPDATE_BM_NEG_THRESH_3_8, /*!< Only update benchmark when the (benchmark - smooth_data) < 3/8 * activate_threshold */ + TOUCH_UPDATE_BM_NEG_THRESH_1_4, /*!< Only update benchmark when the (benchmark - smooth_data) < 1/4 * activate_threshold */ + TOUCH_UPDATE_BM_NEG_THRESH_1, /*!< Only update benchmark when the (benchmark - smooth_data) < 1 * activate_threshold */ +} touch_benchmark_neg_thresh_t; + +/** + * @brief Touch channel Infinite Impulse Response (IIR) filter for smooth data + * + */ +typedef enum { + TOUCH_SMOOTH_NO_FILTER, /*!< No filter adopted for smooth data, smooth data equals raw data */ + TOUCH_SMOOTH_IIR_FILTER_2, /*!< IIR filter adopted for smooth data, smooth data equals 1/2 raw data + 1/2 last smooth data (typical) */ + TOUCH_SMOOTH_IIR_FILTER_4, /*!< IIR filter adopted for smooth data, smooth data equals 1/4 raw data + 3/4 last smooth data */ + TOUCH_SMOOTH_IIR_FILTER_8, /*!< IIR filter adopted for smooth data, smooth data equals 1/8 raw data + 7/8 last smooth data */ +} touch_smooth_filter_mode_t; + +/** + * @brief Interrupt events + * + */ +typedef enum { + TOUCH_INTR_EVENT_ACTIVE, /*!< Touch channel active event */ + TOUCH_INTR_EVENT_INACTIVE, /*!< Touch channel inactive event */ + TOUCH_INTR_EVENT_MEASURE_DONE, /*!< Touch channel measure done event */ + TOUCH_INTR_EVENT_SCAN_DONE, /*!< All touch channels scan done event */ + TOUCH_INTR_EVENT_TIMEOUT, /*!< Touch channel measurement timeout event */ + TOUCH_INTR_EVENT_PROXIMITY_DONE, /*!< Proximity channel measurement done event */ +} touch_intr_event_t; + +/** + * @brief Sample configurations of the touch sensor + * + */ +typedef struct { + uint32_t freq_hz; /*!< The sampling frequency for this configuration in Hz */ + uint32_t charge_times; /*!< The charge and discharge times of this sample configuration, the read data are positive correlation to the charge_times */ + uint8_t rc_filter_res; /*!< The resistance of the RC filter of this sample configuration, range [0, 3], while 0 = 0K, 1 = 1.5K, 2 = 3K, 3 = 4.5K */ + uint8_t rc_filter_cap; /*!< The capacitance of the RC filter of this sample configuration, range [0, 127], while 0 = 0pF, 1 = 20fF, ..., 127 = 2.54pF */ + uint8_t low_drv; /*!< Low speed touch driver, only effective when high speed driver is disabled */ + uint8_t high_drv; /*!< High speed touch driver */ + uint8_t bias_volt; /*!< The Internal LDO voltage, which decide the bias voltage of the sample wave, range [0,15] */ + bool bypass_shield_output; /*!< Whether to bypass the shield output, enable when the charging/discharging rate greater than 10MHz */ +} touch_sensor_sample_config_t; + +/** + * @brief Configurations of the touch sensor controller + * + */ +typedef struct { + uint32_t power_on_wait_us; /*!< The waiting time between the channels power on and able to measure, to ensure the data stability */ + float meas_interval_us; /*!< Measurement interval of each channels */ + uint32_t max_meas_time_us; /*!< The maximum time of measuring one channel, if the time exceeds this value, the timeout interrupt will be triggered. + * Set to '0' to ignore the measurement time limitation, otherwise please set a proper time considering the configurations + * of this sample configurations below. + */ + touch_out_mode_t output_mode; /*!< Touch channel counting mode of the binarized touch output */ + uint32_t sample_cfg_num; /*!< The sample configuration number that used for sampling */ + touch_sensor_sample_config_t *sample_cfg; /*!< The array of this sample configuration configurations, the length should be specified in `touch_sensor_config_t::sample_cfg_num` */ +} touch_sensor_config_t; + +/** + * @brief Configurations of the touch sensor channel + * + */ +typedef struct { + uint32_t active_thresh[TOUCH_SAMPLE_CFG_NUM]; /*!< The active threshold of each sample configuration, + * while the touch channel smooth value minus benchmark value exceed this threshold, + * will be regarded as activated + */ +} touch_channel_config_t; + +/** + * @brief Configurations of the touch sensor filter + * + */ +typedef struct { + /** + * @brief Benchmark configuration + */ + struct { + touch_benchmark_filter_mode_t filter_mode; /*!< Benchmark filter mode. IIR filter and Jitter filter can be selected, + * TOUCH_BM_IIR_FILTER_16 is recommended + */ + uint32_t jitter_step; /*!< Jitter filter step size, only takes effect when the `filter_mode` is TOUCH_BM_JITTER_FILTER. Range: 0 ~ 15 */ + /** + * @brief Benchmark update strategy + */ + struct { + touch_benchmark_pos_thresh_t pos_thresh; /*!< Select the positive noise threshold. Higher = More noise resistance. + * Range: [-1 ~ 3]. The coefficient of the positive threshold are -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; + * Once the data of the channel exceeded the positive threshold (i.e., benchmark + coefficient * touch threshold), + * the benchmark will stop updated to that value. + * -1: ignore the positive threshold and always update the benchmark for positive noise + */ + touch_benchmark_neg_thresh_t neg_thresh; /*!< Select the negative noise threshold. Higher = More noise resistance. + * Range: [-2 ~ 3]. The coefficient of the negative threshold are -2: never; -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; + * Once the data of the channel below the negative threshold (i.e., benchmark - coefficient * touch threshold), + * the benchmark will stop updated to that value, + * unless the data keep below the negative threshold for more than the limitation of `neg_limit` + * -1: ignore the negative threshold and always update the benchmark for negative noise + * -2: never update the benchmark for negative noise + */ + uint32_t neg_limit; /*!< Set the time limitation of the negative threshold. + * The benchmark will be updated to the value that below to the negative threshold after the limited time. + * Normally the negative update is used at the beginning, as the initial benchmark is a very large value. + * (the unit of `neg_limit` is the tick of the slow clock source) + */ + } update; /*!< The benchmark update strategy */ + } benchmark; /*!< Benchmark filter */ + /** + * @brief Data configuration + */ + struct { + touch_smooth_filter_mode_t smooth_filter; /*!< Smooth data IIR filter mode */ + uint32_t active_hysteresis; /*!< The hysteresis threshold to judge whether the touch channel is active + * If the channel data exceed the 'touch_channel_config_t::active_thresh + active_hysteresis' + * The channel will be activated. If the channel data is below to + * 'touch_channel_config_t::active_thresh - active_hysteresis' the channel will be inactivated. + */ + uint32_t debounce_cnt; /*!< The debounce count of the touch channel. + * Only when the channel data exceed the `touch_channel_config_t::active_thresh + active_hysteresis` for `debounce_cnt` times + * The channel will be activated. And only if the channel data is below to the `touch_channel_config_t::active_thresh - active_hysteresis` + * for `debounce_cnt` times, the channel will be inactivated. + * (The unit of `debounce_cnt` is the tick of the slow clock source) + */ + } data; /*!< Channel data filter */ +} touch_sensor_filter_config_t; + +/** + * @brief Touch sensor configuration during the deep sleep + * @note Currently it is the same as the normal controller configuration. + * The deep sleep configuration only takes effect when the chip entered sleep, + * so that to update a more power efficient configuration. + * + */ +typedef touch_sensor_config_t touch_sensor_config_dslp_t; + +/** + * @brief Configure the touch sensor sleep function + * + */ +typedef struct { + touch_sleep_wakeup_level_t slp_wakeup_lvl; /*!< The sleep level that can be woke up by touch sensor. */ + touch_channel_handle_t deep_slp_chan; /*!< The touch channel handle that supposed to work in the deep sleep. It can wake up the chip + * from deep sleep when this channel is activated. + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ + uint32_t deep_slp_thresh[TOUCH_SAMPLE_CFG_NUM]; /*!< The active threshold of the deep sleep channel during deep sleep, + * while the sleep channel exceed this threshold, it will be regarded as activated + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ + touch_sensor_config_dslp_t *deep_slp_sens_cfg; /*!< Specify the touch sensor configuration during the deep sleep. + * Note that these configurations will no take effect immediately, + * they will be set automatically while the chip prepare to enter sleep. + * Set NULL to not change the configurations before entering sleep. + * The sleep configuration mainly aims at lower down the charging and measuring times, + * so that to save power consumption during the sleep. + * Only effective when the `touch_sleep_config_t::slp_wakeup_lvl` is `TOUCH_DEEP_SLEEP_WAKEUP` + */ +} touch_sleep_config_t; + +/** + * @brief Configure the touch sensor waterproof function + * + */ +typedef struct { + touch_channel_handle_t guard_chan; /*!< The guard channel of waterproof. Set NULL if you don't need the guard channel. + * Typically, the guard channel is a ring that surrounds the touch panels, + * it is used to detect the large area that covered by water. + * While large area of water covers the touch panel, the touch sensor will be temporary disable to avoid the fake touch. + */ + touch_channel_handle_t shield_chan; /*!< The touch channel that used as the shield channel, can't be NULL. + * Typically, the shield channel uses grid layout which covers the touch area, + * it is used to shield the influence of water droplets covering both the touch panel and the shield channel. + * The shield channel will be paralleled to the current measuring channel (except the guard channel) to reduce the influence of water droplets. + */ + uint32_t shield_drv; /*!< The shield channel driver, which controls the drive capability of shield channel, range: 0 ~ 7 + * The larger the parasitic capacitance on the shielding channel, the higher the drive capability needs to be set. + */ +} touch_waterproof_config_t; + +/** + * @brief Configure the touch sensor proximity function + * + */ +typedef struct { + touch_channel_handle_t proximity_chan[TOUCH_PROXIMITY_CHAN_NUM]; /*!< The touch channel handles that will be configured as proximity sensing channels */ + uint32_t scan_times; /*!< The total scan times of EACH sample configuration, all sample configurations share a same `scan_times`. + * The measurement result of each scanning will be accumulated together to get the final result. + */ + uint32_t charge_times[TOUCH_SAMPLE_CFG_NUM]; /*!< The charge times of EACH scanning, different sample configurations can set different `charge_times`. + * The measurement result of each scanning is positive correlation to the `charge_times`, + * please set a proper value in case of the final accumulated result overflow. + */ +} touch_proximity_config_t; + +/** + * @brief Base event structure used in touch event queue + */ +typedef struct { + touch_channel_handle_t chan; /*!< the current triggered touch channel handle */ + int chan_id; /*!< the current triggered touch channel number */ + uint32_t status_mask; /*!< the current channel triggered status. + * For the bits in the status mask, + * if the bit is set, the corresponding channel is active + * if the bit is cleared, the corresponding channel is inactive + */ +} touch_base_event_data_t; + +/** + * @brief Measure done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_meas_done_event_data_t; + +/** + * @brief Scan done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_scan_done_event_data_t; + +/** + * @brief Active event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_active_event_data_t; + +/** + * @brief Inactive event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_inactive_event_data_t; + +/** + * @brief Proximity sensing measure done event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_prox_done_event_data_t; + +/** + * @brief Timeout event data + * @note Currently same as base event data + * + */ +typedef touch_base_event_data_t touch_timeout_event_data_t; + +/** + * @brief Touch sensor callbacks + * @note Set NULL for the used callbacks. + * + */ +typedef struct { + /** + * @brief Touch sensor on active event callback. + * Callback when any touch channel is activated. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor active event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_active)(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on inactive event callback. + * Callback when any touch channel is inactivated. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor inactive event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_inactive)(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on measure done event callback. + * Callback when the measurement of all the sample configurations on the current touch channel is done. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor measure done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_measure_done)(touch_sensor_handle_t sens_handle, const touch_meas_done_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on scan done event callback. + * Callback when finished scanning all the registered touch channels. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor scan done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_scan_done)(touch_sensor_handle_t sens_handle, const touch_scan_done_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on measurement timeout event callback. + * Callback when measure the current touch channel timeout. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor timeout event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_timeout)(touch_sensor_handle_t sens_handle, const touch_timeout_event_data_t *event, void *user_ctx); + /** + * @brief Touch sensor on proximity sensing measurement done event callback. + * Callback when proximity sensing measurement of the current channel is done. + * @param[in] sens_handle Touch sensor controller handle, created from `touch_sensor_new_controller()` + * @param[in] event Touch sensor proximity sensing measure done event data + * @param[in] user_ctx User registered context, passed from `touch_sensor_register_callbacks()` + * + * @return Whether a high priority task has been waken up by this callback function + */ + bool (*on_proximity_meas_done)(touch_sensor_handle_t sens_handle, const touch_prox_done_event_data_t *event, void *user_ctx); +} touch_event_callbacks_t; + +/** + * @brief Touch sensor benchmark operation, to set or reset the benchmark of the channel + * + */ +typedef struct { + bool do_reset; /*!< Whether to reset the benchmark to the channel's latest smooth data */ +} touch_chan_benchmark_op_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c new file mode 100644 index 00000000000..29f1267011b --- /dev/null +++ b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c @@ -0,0 +1,500 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief This file is only applicable to the touch hardware version3 + * Version 3 includes ESP32-P4 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/soc_caps.h" +#include "soc/clk_tree_defs.h" +#include "soc/touch_sensor_periph.h" +#include "soc/rtc.h" +#include "hal/hal_utils.h" +#include "driver/touch_sens.h" +#include "esp_private/rtc_ctrl.h" +#include "esp_private/periph_ctrl.h" +#include "esp_clk_tree.h" +#include "esp_sleep.h" +#include "../../common/touch_sens_private.h" +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG +// The local log level must be defined before including esp_log.h +// Set the maximum log level for this source file +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG +#endif +#include "esp_check.h" + +static const char *TAG = "touch"; + +portMUX_TYPE g_touch_spinlock = portMUX_INITIALIZER_UNLOCKED; + +/****************************************************************************** + * Scope: touch driver private * + ******************************************************************************/ + +void touch_priv_enable_module(bool enable) +{ + TOUCH_ENTER_CRITICAL(TOUCH_RTC_LOCK); + touch_ll_enable_module_clock(enable); + touch_ll_enable_out_gate(enable); +#if SOC_TOUCH_SENSOR_VERSION >= 2 + // Reset the benchmark after finished the scanning + touch_ll_reset_chan_benchmark(TOUCH_LL_FULL_CHANNEL_MASK); +#endif + TOUCH_EXIT_CRITICAL(TOUCH_RTC_LOCK); +} + +void IRAM_ATTR touch_priv_default_intr_handler(void *arg) +{ + /* If the touch controller object has not been allocated, return directly */ + if (!g_touch) { + return; + } + bool need_yield = false; + uint32_t status = touch_ll_get_intr_status_mask(); + g_touch->is_meas_timeout = false; + touch_ll_intr_clear(status); + touch_base_event_data_t data; + touch_ll_get_active_channel_mask(&data.status_mask); + data.chan = g_touch->ch[touch_ll_get_current_meas_channel()]; + /* If the channel is not registered, return directly */ + if (!data.chan) { + return; + } + data.chan_id = data.chan->id; + + if (status & TOUCH_LL_INTR_MASK_DONE) { + if (g_touch->cbs.on_measure_done) { + need_yield |= g_touch->cbs.on_measure_done(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_SCAN_DONE) { + if (g_touch->cbs.on_scan_done) { + need_yield |= g_touch->cbs.on_scan_done(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_PROX_DONE) { + data.chan->prox_cnt++; + /* The proximity sensing result only accurate when the scanning times equal to the sample_cfg_num */ + if (data.chan->prox_cnt == g_touch->sample_cfg_num) { + data.chan->prox_cnt = 0; + for (uint32_t i = 0; i < g_touch->sample_cfg_num; i++) { + touch_ll_read_chan_data(data.chan_id, i, TOUCH_LL_READ_BENCHMARK, &data.chan->prox_val[i]); + } + if (g_touch->cbs.on_proximity_meas_done) { + need_yield |= g_touch->cbs.on_proximity_meas_done(g_touch, &data, g_touch->user_ctx); + } + } + } + if (status & TOUCH_LL_INTR_MASK_ACTIVE) { + /* When the guard ring activated, disable the scanning of other channels to avoid fake touch */ + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + touch_ll_enable_scan_mask(~BIT(data.chan->id), false); + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->cbs.on_active) { + need_yield |= g_touch->cbs.on_active(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_INACTIVE) { + /* When the guard ring inactivated, enable the scanning of other channels again */ + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + touch_ll_enable_scan_mask(g_touch->chan_mask & (~BIT(g_touch->shield_chan->id)), true); + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (g_touch->cbs.on_inactive) { + need_yield |= g_touch->cbs.on_inactive(g_touch, &data, g_touch->user_ctx); + } + } + if (status & TOUCH_LL_INTR_MASK_TIMEOUT) { + g_touch->is_meas_timeout = true; + touch_ll_force_done_curr_measurement(); + if (g_touch->cbs.on_timeout) { + need_yield |= g_touch->cbs.on_timeout(g_touch, &data, g_touch->user_ctx); + } + } + + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +static esp_err_t s_touch_convert_to_hal_config(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg, touch_hal_config_t *hal_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_cfg); + TOUCH_NULL_POINTER_CHECK(hal_cfg); + TOUCH_NULL_POINTER_CHECK(hal_cfg->sample_cfg); + ESP_RETURN_ON_FALSE(sens_cfg->sample_cfg_num && sens_cfg->sample_cfg, ESP_ERR_INVALID_ARG, TAG, + "at least one sample configuration required"); + ESP_RETURN_ON_FALSE(sens_cfg->sample_cfg_num <= TOUCH_SAMPLE_CFG_NUM, ESP_ERR_INVALID_ARG, TAG, + "at most %d sample configurations supported", (int)(TOUCH_SAMPLE_CFG_NUM)); + + /* Get the source clock frequency for the first time */ + if (!sens_handle->src_freq_hz) { + /* Touch sensor actually uses dynamic fast clock LP_DYN_FAST_CLK, but it will only switch to the slow clock during sleep, + * This driver only designed for wakeup case (sleep case should use ULP driver), so we only need to consider RTC_FAST here */ + ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_RTC_FAST, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &sens_handle->src_freq_hz), + TAG, "get clock frequency failed"); + ESP_LOGD(TAG, "touch rtc clock source: RTC_FAST, frequency: %"PRIu32" Hz", sens_handle->src_freq_hz); + } + + uint32_t src_freq_hz = sens_handle->src_freq_hz; + uint32_t src_freq_mhz = src_freq_hz / 1000000; + hal_cfg->power_on_wait_ticks = (uint32_t)sens_cfg->power_on_wait_us * src_freq_mhz; + hal_cfg->meas_interval_ticks = (uint32_t)(sens_cfg->meas_interval_us * src_freq_mhz); + hal_cfg->timeout_ticks = (uint32_t)sens_cfg->max_meas_time_us * src_freq_mhz; + ESP_RETURN_ON_FALSE(hal_cfg->timeout_ticks <= TOUCH_LL_TIMEOUT_MAX, ESP_ERR_INVALID_ARG, TAG, + "max_meas_time_ms should within %"PRIu32, TOUCH_LL_TIMEOUT_MAX / src_freq_mhz); + hal_cfg->sample_cfg_num = sens_cfg->sample_cfg_num; + hal_cfg->output_mode = sens_cfg->output_mode; + + hal_utils_clk_info_t clk_info = { + .src_freq_hz = sens_handle->src_freq_hz, + .min_integ = 1, + .max_integ = TOUCH_LL_CLK_DIV_MAX, + .round_opt = HAL_DIV_ROUND, + }; + for (uint32_t div_num, smp_cfg_id = 0; smp_cfg_id < sens_cfg->sample_cfg_num; smp_cfg_id++) { + const touch_sensor_sample_config_t *sample_cfg = &(sens_cfg->sample_cfg[smp_cfg_id]); + uint32_t actual_freq_hz = 0; + /* Allow 10% overflow to increase the robustness when the sample frequency is close to the source clock, + because the source clock is from RTC FAST whose frequency is floating up and down among startups */ + if (sample_cfg->freq_hz > sens_handle->src_freq_hz && sample_cfg->freq_hz < sens_handle->src_freq_hz * 1.1) { + ESP_LOGW(TAG, "[sample_cfg_id %"PRIu32"] sample frequency exceed the src clock but still within 10%%", smp_cfg_id); + div_num = 1; + actual_freq_hz = sens_handle->src_freq_hz; + } else { + clk_info.exp_freq_hz = sample_cfg->freq_hz; + actual_freq_hz = hal_utils_calc_clk_div_integer(&clk_info, &div_num); + } + /* Check the actual frequency and its precision */ + ESP_RETURN_ON_FALSE(actual_freq_hz, ESP_ERR_INVALID_ARG, TAG, + "[sample_cfg_id %"PRIu32"] sample frequency should within range %"PRIu32" ~ %"PRIu32" hz", + smp_cfg_id, sens_handle->src_freq_hz / TOUCH_LL_CLK_DIV_MAX, sens_handle->src_freq_hz); + ESP_LOGD(TAG, "[sample_cfg_id %"PRIu32"] clock divider %"PRIu32, smp_cfg_id, div_num); + if (actual_freq_hz != clk_info.exp_freq_hz) { + ESP_LOGW(TAG, "[sample_cfg_id %"PRIu32"] clock precision loss, expect %"PRIu32" hz, got %"PRIu32" hz", + smp_cfg_id, clk_info.exp_freq_hz, actual_freq_hz); + } + /* Assign the hal configurations */ + hal_cfg->sample_cfg[smp_cfg_id].div_num = div_num; + hal_cfg->sample_cfg[smp_cfg_id].charge_times = sample_cfg->charge_times; + hal_cfg->sample_cfg[smp_cfg_id].rc_filter_res = sample_cfg->rc_filter_res; + hal_cfg->sample_cfg[smp_cfg_id].rc_filter_cap = sample_cfg->rc_filter_cap; + hal_cfg->sample_cfg[smp_cfg_id].low_drv = sample_cfg->low_drv; + hal_cfg->sample_cfg[smp_cfg_id].high_drv = sample_cfg->high_drv; + hal_cfg->sample_cfg[smp_cfg_id].bias_volt = sample_cfg->bias_volt; + } + return ESP_OK; +} + +esp_err_t touch_priv_config_controller(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg) +{ +#if CONFIG_TOUCH_ENABLE_DEBUG_LOG + esp_log_level_set(TAG, ESP_LOG_DEBUG); +#endif + /* Check and convert the configuration to hal configurations */ + touch_hal_sample_config_t sample_cfg[TOUCH_SAMPLE_CFG_NUM] = {}; + touch_hal_config_t hal_cfg = { + .sample_cfg = sample_cfg, + }; + ESP_RETURN_ON_ERROR(s_touch_convert_to_hal_config(sens_handle, sens_cfg, &hal_cfg), + TAG, "parse the configuration failed due to the invalid configuration"); + sens_handle->sample_cfg_num = sens_cfg->sample_cfg_num; + + /* Configure the hardware */ + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_hal_config_controller(&hal_cfg); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + + return ESP_OK; +} + +esp_err_t touch_priv_config_channel(touch_channel_handle_t chan_handle, const touch_channel_config_t *chan_cfg) +{ + uint8_t sample_cfg_num = chan_handle->base->sample_cfg_num; + // Check the validation of the channel active threshold + for (uint8_t smp_cfg_id = 0; smp_cfg_id < sample_cfg_num; smp_cfg_id++) { + ESP_RETURN_ON_FALSE(chan_cfg->active_thresh[smp_cfg_id] <= TOUCH_LL_ACTIVE_THRESH_MAX, ESP_ERR_INVALID_ARG, + TAG, "the active threshold out of range 0~%d", TOUCH_LL_ACTIVE_THRESH_MAX); + } + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + for (uint8_t smp_cfg_id = 0; smp_cfg_id < sample_cfg_num; smp_cfg_id++) { + touch_ll_set_chan_active_threshold(chan_handle->id, smp_cfg_id, chan_cfg->active_thresh[smp_cfg_id]); + } + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + return ESP_OK; +} + +esp_err_t touch_priv_deinit_controller(touch_sensor_handle_t sens_handle) +{ + /* Disable the additional functions */ + if (sens_handle->proximity_en) { + touch_sensor_config_proximity_sensing(sens_handle, NULL); + } + if (sens_handle->sleep_en) { + touch_sensor_config_sleep_wakeup(sens_handle, NULL); + } + if (sens_handle->waterproof_en) { + touch_sensor_config_waterproof(sens_handle, NULL); + } + return ESP_OK; +} + +esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch_chan_data_type_t type, uint32_t *data) +{ + ESP_RETURN_ON_FALSE_ISR(type >= TOUCH_CHAN_DATA_TYPE_SMOOTH && type <= TOUCH_CHAN_DATA_TYPE_PROXIMITY, + ESP_ERR_INVALID_ARG, TAG, "The channel data type is invalid"); +#if CONFIG_TOUCH_CTRL_FUNC_IN_IRAM + ESP_RETURN_ON_FALSE_ISR(esp_ptr_internal(data), ESP_ERR_INVALID_ARG, TAG, "user context not in internal RAM"); +#endif + uint8_t sample_cfg_num = chan_handle->base->sample_cfg_num; + if (type < TOUCH_CHAN_DATA_TYPE_PROXIMITY) { + uint32_t internal_type = 0; + switch (type) { + default: // fall through + case TOUCH_CHAN_DATA_TYPE_SMOOTH: + internal_type = TOUCH_LL_READ_SMOOTH; + break; + case TOUCH_CHAN_DATA_TYPE_BENCHMARK: + internal_type = TOUCH_LL_READ_BENCHMARK; + break; + } + if (type <= TOUCH_CHAN_DATA_TYPE_BENCHMARK) { + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + if (chan_handle != chan_handle->base->deep_slp_chan) { + for (int i = 0; i < sample_cfg_num; i++) { + touch_ll_read_chan_data(chan_handle->id, i, internal_type, &data[i]); + } + } else { + for (int i = 0; i < sample_cfg_num; i++) { + touch_ll_sleep_read_chan_data(internal_type, i, &data[i]); + } + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + } + } else { + if (!chan_handle->is_prox_chan) { + ESP_EARLY_LOGW(TAG, "This is not a proximity sensing channel"); + } + TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + /* Get the proximity value from the stored data. + * The proximity value are updated in the isr when proximity scanning is done */ + for (int i = 0; i < sample_cfg_num; i++) { + data[i] = chan_handle->prox_val[i]; + } + TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); + } + return ESP_OK; +} + +void touch_priv_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op) +{ + if (benchmark_op->do_reset) { + touch_ll_reset_chan_benchmark(BIT(chan_handle->id)); + } +} + +/****************************************************************************** + * Scope: public APIs * + ******************************************************************************/ + +esp_err_t touch_sensor_config_filter(touch_sensor_handle_t sens_handle, const touch_sensor_filter_config_t *filter_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + if (filter_cfg) { + ESP_RETURN_ON_FALSE(filter_cfg->benchmark.update.neg_limit >= filter_cfg->data.debounce_cnt, + ESP_ERR_INVALID_ARG, TAG, "The neg_limit should be greater than debounce_cnt"); + } + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + + if (filter_cfg) { + touch_ll_filter_enable(true); + /* Configure the benchmark filter and update strategy */ + touch_ll_filter_set_filter_mode(filter_cfg->benchmark.filter_mode); + if (filter_cfg->benchmark.filter_mode == TOUCH_BM_JITTER_FILTER) { + touch_ll_filter_set_jitter_step(filter_cfg->benchmark.jitter_step); + } + touch_ll_filter_set_pos_noise_thresh(filter_cfg->benchmark.update.pos_thresh); + touch_ll_filter_set_neg_noise_thresh(filter_cfg->benchmark.update.neg_thresh, filter_cfg->benchmark.update.neg_limit); + /* Configure the touch data filter */ + touch_ll_filter_set_smooth_mode(filter_cfg->data.smooth_filter); + touch_ll_filter_set_active_hysteresis(filter_cfg->data.active_hysteresis); + touch_ll_filter_set_debounce(filter_cfg->data.debounce_cnt); + } else { + touch_ll_filter_enable(false); + } + + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_config_sleep_wakeup(touch_sensor_handle_t sens_handle, const touch_sleep_config_t *sleep_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + int dp_slp_chan_id = -1; + touch_hal_sample_config_t sample_cfg[TOUCH_SAMPLE_CFG_NUM] = {}; + touch_hal_config_t hal_cfg = { + .sample_cfg = sample_cfg, + }; + touch_hal_config_t *hal_cfg_ptr = NULL; + + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + ESP_GOTO_ON_FALSE(sleep_cfg->slp_wakeup_lvl == TOUCH_LIGHT_SLEEP_WAKEUP || sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP, + ESP_ERR_INVALID_ARG, err, TAG, "Invalid sleep level"); + + if (sleep_cfg) { + /* Enabled touch sensor as wake-up source */ + ESP_GOTO_ON_ERROR(esp_sleep_enable_touchpad_wakeup(), err, TAG, "Failed to enable touch sensor wakeup"); +#if SOC_PM_SUPPORT_RC_FAST_PD + ESP_GOTO_ON_ERROR(esp_sleep_pd_config(ESP_PD_DOMAIN_RC_FAST, ESP_PD_OPTION_ON), err, TAG, "Failed to keep touch sensor module clock during the sleep"); +#endif + + /* If set the deep sleep channel (i.e., enable deep sleep wake-up), + configure the deep sleep related settings. */ + if (sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP) { + ESP_GOTO_ON_FALSE(sleep_cfg->deep_slp_chan, ESP_ERR_INVALID_ARG, err, TAG, "deep sleep waken channel can't be NULL"); + dp_slp_chan_id = sleep_cfg->deep_slp_chan->id; + + /* Check and convert the configuration to hal configurations */ + if (sleep_cfg->deep_slp_sens_cfg) { + hal_cfg_ptr = &hal_cfg; + ESP_GOTO_ON_ERROR(s_touch_convert_to_hal_config(sens_handle, (const touch_sensor_config_t *)sleep_cfg->deep_slp_sens_cfg, hal_cfg_ptr), + err, TAG, "parse the configuration failed due to the invalid configuration"); + } + sens_handle->sleep_en = true; + sens_handle->deep_slp_chan = sleep_cfg->deep_slp_chan; + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + /* Set sleep threshold */ + for (uint8_t smp_cfg_id = 0; smp_cfg_id < TOUCH_SAMPLE_CFG_NUM; smp_cfg_id++) { + touch_ll_sleep_set_threshold(smp_cfg_id, sleep_cfg->deep_slp_thresh[smp_cfg_id]); + } + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } + + } else { + /* Disable the touch sensor as wake-up source */ + esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TOUCHPAD); +#if SOC_PM_SUPPORT_RC_FAST_PD + esp_sleep_pd_config(ESP_PD_DOMAIN_RC_FAST, ESP_PD_OPTION_AUTO); +#endif + + sens_handle->sleep_en = false; + } + + /* Save or update the sleep config */ + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_hal_save_sleep_config(dp_slp_chan_id, hal_cfg_ptr); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +// Water proof can be enabled separately +esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, const touch_waterproof_config_t *wp_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + if (wp_cfg) { + // Check the validation of the waterproof configuration + TOUCH_NULL_POINTER_CHECK(wp_cfg->shield_chan); + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + sens_handle->waterproof_en = true; + sens_handle->guard_chan = wp_cfg->guard_chan; + sens_handle->shield_chan = wp_cfg->shield_chan; + touch_ll_waterproof_set_guard_chan(wp_cfg->guard_chan ? wp_cfg->guard_chan->id : TOUCH_LL_NULL_CHANNEL); + touch_ll_waterproof_set_shield_chan_mask(BIT(wp_cfg->shield_chan->id)); + // need to disable the scanning of the shield channel + touch_ll_enable_scan_mask(BIT(wp_cfg->shield_chan->id), false); + touch_ll_waterproof_set_shield_driver(wp_cfg->shield_drv); + touch_ll_waterproof_enable(true); + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } else { + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + touch_ll_waterproof_enable(false); + touch_ll_waterproof_set_guard_chan(TOUCH_LL_NULL_CHANNEL); + touch_ll_waterproof_set_shield_chan_mask(0); + touch_ll_enable_scan_mask(BIT(wp_cfg->shield_chan->id), true); + touch_ll_waterproof_set_shield_driver(0); + sens_handle->guard_chan = NULL; + sens_handle->shield_chan = NULL; + sens_handle->waterproof_en = false; + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + } +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} + +esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handle, const touch_proximity_config_t *prox_cfg) +{ + TOUCH_NULL_POINTER_CHECK(sens_handle); + + esp_err_t ret = ESP_OK; + xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); + + ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); + + TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); + + /* Reset proximity sensing part of all channels */ + FOR_EACH_TOUCH_CHANNEL(i) { + if (sens_handle->ch[i] && sens_handle->ch[i]->is_prox_chan) { + sens_handle->ch[i]->is_prox_chan = false; + sens_handle->ch[i]->prox_cnt = 0; + for (int i = 0; i < TOUCH_SAMPLE_CFG_NUM; i++) { + sens_handle->ch[i]->prox_val[i] = 0; + } + } + } + + if (prox_cfg) { + sens_handle->proximity_en = true; + uint8_t sample_cfg_num = sens_handle->sample_cfg_num; + for (int i = 0; i < TOUCH_PROXIMITY_CHAN_NUM; i++) { + if (prox_cfg->proximity_chan[i]) { + prox_cfg->proximity_chan[i]->is_prox_chan = true; + touch_ll_set_proximity_sensing_channel(i, prox_cfg->proximity_chan[i]->id); + } else { + touch_ll_set_proximity_sensing_channel(i, TOUCH_LL_NULL_CHANNEL); + } + } + touch_ll_proximity_set_total_scan_times(prox_cfg->scan_times * sample_cfg_num); + for (uint8_t smp_cfg_id = 0; smp_cfg_id < sample_cfg_num; smp_cfg_id++) { + touch_ll_proximity_set_charge_times(smp_cfg_id, prox_cfg->charge_times[smp_cfg_id]); + } + } else { + for (int i = 0; i < TOUCH_PROXIMITY_CHAN_NUM; i++) { + touch_ll_set_proximity_sensing_channel(i, TOUCH_LL_NULL_CHANNEL); + } + sens_handle->proximity_en = false; + } + TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + +err: + xSemaphoreGive(sens_handle->mutex); + return ret; +} diff --git a/components/esp_driver_touch_sens/include/driver/touch_common_types.h b/components/esp_driver_touch_sens/include/driver/touch_common_types.h new file mode 100644 index 00000000000..3b802cc6ccd --- /dev/null +++ b/components/esp_driver_touch_sens/include/driver/touch_common_types.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "soc/soc_caps.h" +#include "hal/touch_sensor_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TOUCH_TOTAL_CHAN_NUM SOC_TOUCH_SENSOR_NUM /*!< The total channel number of the touch sensor */ +#define TOUCH_SAMPLE_CFG_NUM SOC_TOUCH_SAMPLE_CFG_NUM /*!< The supported max sample configuration number */ +#if SOC_TOUCH_SUPPORT_PROX_SENSING +#define TOUCH_PROXIMITY_CHAN_NUM SOC_TOUCH_PROXIMITY_CHANNEL_NUM /*!< The supported proximity channel number in proximity sensing mode */ +#endif + +typedef struct touch_sensor_s *touch_sensor_handle_t; /*!< The handle of touch sensor controller */ +typedef struct touch_channel_s *touch_channel_handle_t; /*!< The handle of touch channel */ + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/include/driver/touch_sens.h b/components/esp_driver_touch_sens/include/driver/touch_sens.h new file mode 100644 index 00000000000..ca4b4a9300d --- /dev/null +++ b/components/esp_driver_touch_sens/include/driver/touch_sens.h @@ -0,0 +1,294 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" +#include "driver/touch_common_types.h" +#include "driver/touch_version_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Allocate a new touch sensor controller + * @note The touch sensor driver will be in INIT state after this function is called successfully. + * + * @param[in] sens_cfg Touch sensor controller configurations + * @param[out] ret_sens_handle The return handle of the touch controller instance + * @return + * - ESP_OK On success + * - ESP_ERR_NO_MEM No memory for the touch sensor controller + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller is already allocated + */ +esp_err_t touch_sensor_new_controller(const touch_sensor_config_t *sens_cfg, touch_sensor_handle_t *ret_sens_handle); + +/** + * @brief Delete the touch sensor controller + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * + * @param[in] sens_handle Touch sensor controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE Controller not disabled or still some touch channels not deleted + */ +esp_err_t touch_sensor_del_controller(touch_sensor_handle_t sens_handle); + +/** + * @brief Allocate a new touch channel from the touch sensor controller + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] chan_id Touch channel index + * @param[in] chan_cfg Touch channel configurations + * @param[out] ret_chan_handle The return handle of the touch channel instance + * @return + * - ESP_OK On success + * - ESP_ERR_NO_MEM No memory for the touch sensor channel + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has not disabled or this channel has been allocated + */ +esp_err_t touch_sensor_new_channel(touch_sensor_handle_t sens_handle, int chan_id, + const touch_channel_config_t *chan_cfg, + touch_channel_handle_t *ret_chan_handle); + +/** + * @brief Delete the touch channel + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * + * @param[in] chan_handle Touch channel handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has not disabled + */ +esp_err_t touch_sensor_del_channel(touch_channel_handle_t chan_handle); + +/** + * @brief Re-configure the touch sensor controller + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * @note The re-configuration only applies to the touch controller, + * so it requires the controller handle that allocated from ``touch_sensor_new_controller``, + * meanwhile, it won't affect the touch channels, no matter the channels are allocated or not. + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] sens_cfg Touch sensor controller configurations + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has not disabled + */ +esp_err_t touch_sensor_reconfig_controller(touch_sensor_handle_t sens_handle, const touch_sensor_config_t *sens_cfg); + +/** + * @brief Re-configure the touch channel + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * @note The re-configuration only applies to a particular touch channel, + * so it requires the channel handle that allocated from ``touch_sensor_new_channel`` + * + * @param[in] chan_handle Touch channel handle + * @param[in] chan_cfg Touch channel configurations + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has not disabled + */ +esp_err_t touch_sensor_reconfig_channel(touch_channel_handle_t chan_handle, const touch_channel_config_t *chan_cfg); + +/** + * @brief Configure the touch sensor filter + * @note This function is allowed to be called after the touch sensor is enabled + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] filter_cfg Filter configurations, set NULL to disable the filter + * @return + * - ESP_OK: Configure the filter success + * - ESP_ERR_INVALID_ARG: The sensor handle is NULL + */ +esp_err_t touch_sensor_config_filter(touch_sensor_handle_t sens_handle, const touch_sensor_filter_config_t *filter_cfg); + +/** + * @brief Enable the touch sensor controller + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * And the touch sensor driver will be in ENABLED state after this function is called successfully. + * @note Enable the touch sensor will power on the registered touch channels + * + * @param[in] sens_handle Touch sensor controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has already enabled + */ +esp_err_t touch_sensor_enable(touch_sensor_handle_t sens_handle); + +/** + * @brief Disable the touch sensor controller + * @note This function can only be called after the touch sensor controller is enabled (i.e. ENABLED state). + * And the touch sensor driver will be in INIT state after this function is called successfully. + * @note Disable the touch sensor will power off the registered touch channels + * + * @param[in] sens_handle Touch sensor controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller has already disabled + */ +esp_err_t touch_sensor_disable(touch_sensor_handle_t sens_handle); + +/** + * @brief Start the scanning of the registered touch channels continuously + * @note This function can only be called after the touch sensor controller is enabled (i.e. ENABLED state). + * And the touch sensor driver will be in SCANNING state after this function is called successfully. + * And it can also be called in ISR/callback context. + * @note The hardware FSM (Finite-State Machine) of touch sensor will be driven by + * its hardware timer continuously and repeatedly. + * i.e., the registered channels will be scanned one by one repeatedly. + * + * @param[in] sens_handle Touch sensor controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The touch sensor controller is not enabled or the continuous scanning has started + */ +esp_err_t touch_sensor_start_continuous_scanning(touch_sensor_handle_t sens_handle); + +/** + * @brief Stop the continuous scanning of the registered touch channels immediately + * @note This function can only be called after the continuous scanning started (i.e. SCANNING state). + * And the touch sensor driver will be in ENABLED state after this function is called successfully. + * And it can also be called in ISR/callback context. + * @note Stop the hardware timer and reset the FSM (Finite-State Machine) of the touch sensor controller + * + * @param[in] sens_handle Touch sensor controller handle + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + * - ESP_ERR_INVALID_STATE The continuous scanning has stopped + */ +esp_err_t touch_sensor_stop_continuous_scanning(touch_sensor_handle_t sens_handle); + +/** + * @brief Trigger an oneshot scanning for all the registered channels + * @note This function can only be called after the touch sensor controller is enabled (i.e. ENABLED state). + * And the touch sensor driver will be in SCANNING state after this function is called successfully, + * and then switch back to ENABLED state after the scanning is done or timeout. + * @note The block time of this function depends on various factors, + * In common practice, recommend to set the timeout to a second-level timeout or wait forever, + * because oneshot scanning can't last for so long. + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] timeout_ms Set a positive value or zero means scan timeout in milliseconds + * Set a negative value means wait forever until finished scanning + * @return + * - ESP_OK On success + * - ESP_ERR_TIMEOUT Timeout to finish the oneshot scanning + * - ESP_ERR_INVALID_ARG Invalid argument + * - ESP_ERR_INVALID_STATE The touch sensor controller is not enabled or the continuous scanning has started + */ +esp_err_t touch_sensor_trigger_oneshot_scanning(touch_sensor_handle_t sens_handle, int timeout_ms); + +/** + * @brief Register the touch sensor callbacks + * @note This function can be called when the touch sensor controller is NOT enabled (i.e. INIT state). + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] callbacks Callback functions + * @param[in] user_ctx User context that will be passed to the callback functions + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG NULL pointer + * - ESP_ERR_INVALID_STATE Touch sensor controller has not disabled + */ +esp_err_t touch_sensor_register_callbacks(touch_sensor_handle_t sens_handle, const touch_event_callbacks_t *callbacks, void *user_ctx); + +/** + * @brief Set the touch sensor benchmark for all the registered channels + * @note This function can be called no matter the touch sensor controller is enabled or not (i.e. ENABLED or SCANNING state). + * And it can also be called in ISR/callback context. + * + * @param[in] chan_handle Touch channel handle + * @param[in] benchmark_op The benchmark operations + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG NULL pointer + */ +esp_err_t touch_sensor_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op); + +/** + * @brief Read the touch channel data according to the types + * @note This function can be called no matter the touch sensor controller is enabled or not (i.e. ENABLED or SCANNING state). + * And it can also be called in ISR/callback context. + * @note Specially, `TOUCH_CHAN_DATA_TYPE_PROXIMITY` data type will be read from the cached data in the driver, + * because the proximity data need to be accumulated in several scan times that specified by `touch_proximity_config_t::scan_times`. + * For other data types, the data are read from the hardware registers directly (not cached in the driver). + * The channel data in the register will be updated once the measurement of this channels is done, + * And keep locked until the next measurement is done. + * + * @param[in] chan_handle Touch channel handle + * @param[in] type Specify the data type to read + * @param[out] data The data array pointer. If the target supports multiple sample configurations (SOC_TOUCH_SAMPLE_CFG_NUM), the array length should be equal to + * the frequency hopping number that specified in `touch_sensor_config_t::sample_cfg_num`, otherwise the array length should be 1. + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG Invalid argument or NULL pointer + */ +esp_err_t touch_channel_read_data(touch_channel_handle_t chan_handle, touch_chan_data_type_t type, uint32_t *data); + +#if SOC_TOUCH_SUPPORT_WATERPROOF +/** + * @brief Configure the touch sensor water proof channels + * @note Once waterproof is enabled, the other touch channels won't be updated unless the shield channels is activated. + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] wp_cfg Water proof channel configurations, set NULL to disable the water proof function + * @return + * - ESP_OK: Configure the water proof success + * - ESP_ERR_INVALID_ARG: The sensor handle is NULL + * - ESP_ERR_INVALID_STATE: The touch sensor is enabled + */ +esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, const touch_waterproof_config_t *wp_cfg); +#endif + +#if SOC_TOUCH_SUPPORT_PROX_SENSING +/** + * @brief Configure the touch sensor proximity sensing channels + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] prox_cfg Proximity channels configurations, set NULL to disable the proximity sensing + * @return + * - ESP_OK: Configure the proximity channel success + * - ESP_ERR_INVALID_ARG: The sensor handle is NULL + * - ESP_ERR_INVALID_STATE: The touch sensor is enabled + */ +esp_err_t touch_sensor_config_proximity_sensing(touch_sensor_handle_t sens_handle, const touch_proximity_config_t *prox_cfg); +#endif + +#if SOC_TOUCH_SUPPORT_SLEEP_WAKEUP +/** + * @brief Configure the touch sensor to wake-up the chip from sleep + * @note Call this function to enable/disable the touch sensor wake-up the chip from deep/light sleep + * To only enable the touch sensor wake-up the chip from light sleep, set the `touch_sleep_config_t::deep_slp_chan` to NULL. + * During the light sleep, all enabled touch channels will keep working, and any one of them can wake-up the chip from light sleep. + * To enable the touch sensor wake-up the chip from both light and deep sleep, set the `touch_sleep_config_t::deep_slp_chan` to an enabled channel. + * During the deep sleep, only this specified channels can work and wake-up the chip from the deep sleep, + * and other enabled channels can only wake-up the chip from light sleep. + * + * @param[in] sens_handle Touch sensor controller handle + * @param[in] sleep_cfg Sleep wake-up configurations, set NULL to disable the touch sensor wake-up the chip from sleep + * @return + * - ESP_OK: Configure the sleep channel success + * - ESP_ERR_INVALID_ARG: The sensor handle is NULL + * - ESP_ERR_INVALID_STATE: The touch sensor is enabled + */ +esp_err_t touch_sensor_config_sleep_wakeup(touch_sensor_handle_t sens_handle, const touch_sleep_config_t *sleep_cfg); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_touch_sens/linker.lf b/components/esp_driver_touch_sens/linker.lf new file mode 100644 index 00000000000..9ba19d62f2a --- /dev/null +++ b/components/esp_driver_touch_sens/linker.lf @@ -0,0 +1,10 @@ +[mapping:touch_sens_driver] +archive: libesp_driver_touch_sens.a +entries: + if TOUCH_CTRL_FUNC_IN_IRAM = y: + touch_sens_common: touch_sensor_start_continuous_scanning (noflash) + touch_sens_common: touch_sensor_stop_continuous_scanning (noflash) + touch_sens_common: touch_channel_read_data (noflash) + touch_sens_common: touch_sensor_set_benchmark (noflash) + touch_sens_version_specific: touch_priv_channel_read_data (noflash) + touch_sens_version_specific: touch_priv_set_benchmark (noflash) diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index d985b0823f2..eb37b697f24 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -90,6 +90,12 @@ typedef enum { #define RTC_BT_TRIG_EN 0 #endif +#if SOC_TOUCH_SENSOR_SUPPORTED +#define RTC_TOUCH_TRIG_EN PMU_TOUCH_WAKEUP_EN //!< TOUCH wakeup +#else +#define RTC_TOUCH_TRIG_EN 0 +#endif + #define RTC_USB_TRIG_EN PMU_USB_WAKEUP_EN #if SOC_LP_CORE_SUPPORTED diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 12d12fbef3d..3a779b0b117 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -284,7 +284,7 @@ static void ext0_wakeup_prepare(void); static void ext1_wakeup_prepare(void); #endif static esp_err_t timer_wakeup_prepare(int64_t sleep_duration); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if SOC_TOUCH_SENSOR_SUPPORTED && SOC_TOUCH_SENSOR_VERSION != 1 static void touch_wakeup_prepare(void); #endif #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP @@ -843,7 +843,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m misc_modules_sleep_prepare(deep_sleep); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if SOC_TOUCH_SENSOR_VERSION >= 2 if (deep_sleep) { if (s_config.wakeup_triggers & RTC_TOUCH_TRIG_EN) { touch_wakeup_prepare(); @@ -858,7 +858,12 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m /* In light sleep, the RTC_PERIPH power domain should be in the power-on state (Power on the touch circuit in light sleep), * otherwise the touch sensor FSM will be cleared, causing touch sensor false triggering. */ - if (touch_ll_get_fsm_state()) { // Check if the touch sensor is working properly. +#if SOC_TOUCH_SENSOR_VERSION == 3 + bool keep_rtc_power_on = touch_ll_is_fsm_repeated_timer_enabled(); +#else + bool keep_rtc_power_on = touch_ll_get_fsm_state(); +#endif + if (keep_rtc_power_on) { // Check if the touch sensor is working properly. pd_flags &= ~RTC_SLEEP_PD_RTC_PERIPH; } } @@ -1608,7 +1613,7 @@ static esp_err_t timer_wakeup_prepare(int64_t sleep_duration) return ESP_OK; } -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if SOC_TOUCH_SENSOR_VERSION == 2 /* In deep sleep mode, only the sleep channel is supported, and other touch channels should be turned off. */ static void touch_wakeup_prepare(void) { @@ -1627,6 +1632,11 @@ static void touch_wakeup_prepare(void) touch_ll_start_fsm(); } } +#elif SOC_TOUCH_SENSOR_VERSION == 3 +static void touch_wakeup_prepare(void) +{ + touch_hal_prepare_deep_sleep(); +} #endif #if SOC_TOUCH_SENSOR_SUPPORTED @@ -1654,7 +1664,11 @@ touch_pad_t esp_sleep_get_touchpad_wakeup_status(void) return TOUCH_PAD_MAX; } touch_pad_t pad_num; +#if SOC_TOUCH_SENSOR_VERSION == 3 + touch_ll_sleep_get_channel_num((uint32_t *)(&pad_num)); +#else touch_hal_get_wakeup_status(&pad_num); +#endif return pad_num; } diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 3aad2d604e2..b00cdad58ca 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -280,26 +280,27 @@ if(NOT BOOTLOADER_BUILD) "usb_wrap_hal.c") endif() + if(CONFIG_SOC_TOUCH_SENSOR_SUPPORTED) + list(APPEND srcs "${target}/touch_sensor_hal.c") + if(CONFIG_SOC_TOUCH_SENSOR_VERSION LESS 3) + list(APPEND srcs "touch_sensor_hal.c") + endif() + endif() + if(${target} STREQUAL "esp32") list(APPEND srcs - "touch_sensor_hal.c" - "esp32/touch_sensor_hal.c" "esp32/gpio_hal_workaround.c") endif() if(${target} STREQUAL "esp32s2") list(APPEND srcs - "touch_sensor_hal.c" "xt_wdt_hal.c" - "esp32s2/cp_dma_hal.c" - "esp32s2/touch_sensor_hal.c") + "esp32s2/cp_dma_hal.c") endif() if(${target} STREQUAL "esp32s3") list(APPEND srcs - "touch_sensor_hal.c" "xt_wdt_hal.c" - "esp32s3/touch_sensor_hal.c" "esp32s3/rtc_cntl_hal.c") endif() diff --git a/components/hal/esp32/include/hal/touch_sensor_ll.h b/components/hal/esp32/include/hal/touch_sensor_ll.h index c12200fc523..8d1c945024b 100644 --- a/components/hal/esp32/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32/include/hal/touch_sensor_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -229,6 +229,7 @@ static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_ * * @param mode FSM mode. */ +__attribute__((always_inline)) static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode) { SENS.sar_touch_ctrl2.touch_start_fsm_en = 1; @@ -264,6 +265,7 @@ static inline void touch_ll_start_fsm(void) * * @param mode FSM mode. */ +__attribute__((always_inline)) static inline void touch_ll_stop_fsm(void) { RTCCNTL.state0.touch_slp_timer_en = 0; @@ -497,7 +499,8 @@ static inline uint32_t touch_ll_read_raw_data(touch_pad_t touch_num) * @return * - If touch sensors measure done. */ -static inline bool touch_ll_meas_is_done(void) +__attribute__((always_inline)) +static inline bool touch_ll_is_measure_done(void) { return (bool)SENS.sar_touch_ctrl2.touch_meas_done; } diff --git a/components/hal/esp32p4/include/hal/touch_sensor_hal.h b/components/hal/esp32p4/include/hal/touch_sensor_hal.h new file mode 100644 index 00000000000..bc6d03f503b --- /dev/null +++ b/components/hal/esp32p4/include/hal/touch_sensor_hal.h @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in hal/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for touch sensor (ESP32-P4 specific part) + +#pragma once + +#include "hal/touch_sensor_ll.h" +#include "hal/touch_sensor_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sample configurations of the touch sensor + * + */ +typedef struct { + uint32_t div_num; /*!< The division from the source clock to the sampling frequency */ + uint32_t charge_times; /*!< The charge and discharge times of the sample configuration, the read data are positive correlation to the charge_times */ + uint8_t rc_filter_res; /*!< The resistance of the RC filter of the sample configuration, range [0, 3], while 0 = 0K, 1 = 1.5K, 2 = 3K, 3 = 4.5K */ + uint8_t rc_filter_cap; /*!< The capacitance of the RC filter of the sample configuration, range [0, 127], while 0 = 0pF, 1 = 20fF, ..., 127 = 2.54pF */ + uint8_t low_drv; /*!< Low speed touch driver, only effective when high speed driver is disabled */ + uint8_t high_drv; /*!< High speed touch driver */ + uint8_t bias_volt; /*!< The Internal LDO voltage, which decide the bias voltage of the sample wave, range [0,15] */ + bool bypass_shield_output; /*!< Whether to bypass the shield output */ +} touch_hal_sample_config_t; + +/** + * @brief Configurations of the touch sensor controller + * + */ +typedef struct { + uint32_t power_on_wait_ticks; /*!< The waiting time between the channels power on and able to measure, to ensure the data stability */ + uint32_t meas_interval_ticks; /*!< Measurement interval of each channels */ // TODO: Test the supported range + uint32_t timeout_ticks; /*!< The maximum time of measuring one channel, if the time exceeds this value, the timeout interrupt will be triggered. + * Set to '0' to ignore the measurement time limitation, otherwise please set a proper time considering the configurations + * of the sample configurations below. + */ + touch_out_mode_t output_mode; /*!< Touch channel counting mode of the binarized touch output */ + uint32_t sample_cfg_num; /*!< The sample configuration number that used for sampling */ + touch_hal_sample_config_t *sample_cfg; /*!< The array of the sample configuration configurations, the length should be specified in `touch_hal_sample_config_t::sample_cfg_num` */ +} touch_hal_config_t; + +/** + * @brief Configure the touch sensor hardware with the configuration + * + * @param[in] cfg Touch sensor hardware configuration + */ +void touch_hal_config_controller(const touch_hal_config_t *cfg); + +/** + * @brief Save the touch sensor hardware configuration + * @note The saved configurations will be applied before entering deep sleep + * + * @param[in] deep_slp_chan The touch sensor channel that can wake-up the chip from deep sleep + * @param[in] deep_slp_cfg The hardware configuration that takes effect during the deep sleep + */ +void touch_hal_save_sleep_config(int deep_slp_chan, const touch_hal_config_t *deep_slp_cfg); + +/** + * @brief Prepare for the deep sleep + * @note Including apply the deep sleep configuration, clear interrupts, resetting benchmark + */ +void touch_hal_prepare_deep_sleep(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32p4/include/hal/touch_sensor_ll.h b/components/hal/esp32p4/include/hal/touch_sensor_ll.h index 7f15fad2b57..1bb9286bf3d 100644 --- a/components/hal/esp32p4/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32p4/include/hal/touch_sensor_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,9 @@ #include "hal/assert.h" #include "soc/touch_sensor_periph.h" #include "soc/lp_analog_peri_struct.h" +#include "soc/lp_clkrst_struct.h" +#include "soc/lp_system_struct.h" +#include "soc/lpperi_struct.h" #include "soc/touch_struct.h" #include "soc/pmu_struct.h" #include "soc/soc_caps.h" @@ -27,7 +30,6 @@ extern "C" { #endif -#define TOUCH_LL_READ_RAW 0x0 #define TOUCH_LL_READ_BENCHMARK 0x2 #define TOUCH_LL_READ_SMOOTH 0x3 @@ -35,27 +37,41 @@ extern "C" { #define TOUCH_LL_TIMER_DONE_BY_FSM 0x0 // Interrupt mask -#define TOUCH_LL_INTR_MASK_SCAN_DONE BIT(1) -#define TOUCH_LL_INTR_MASK_DONE BIT(2) -#define TOUCH_LL_INTR_MASK_ACTIVE BIT(3) -#define TOUCH_LL_INTR_MASK_INACTIVE BIT(4) -#define TOUCH_LL_INTR_MASK_TIMEOUT BIT(5) -#define TOUCH_LL_INTR_MASK_APPROACH_DONE BIT(6) +#define TOUCH_LL_INTR_MASK_SCAN_DONE BIT(0) +#define TOUCH_LL_INTR_MASK_DONE BIT(1) +#define TOUCH_LL_INTR_MASK_ACTIVE BIT(2) +#define TOUCH_LL_INTR_MASK_INACTIVE BIT(3) +#define TOUCH_LL_INTR_MASK_TIMEOUT BIT(4) +#define TOUCH_LL_INTR_MASK_PROX_DONE BIT(5) #define TOUCH_LL_INTR_MASK_ALL (0x3F) #define TOUCH_LL_FULL_CHANNEL_MASK ((uint16_t)((1U << SOC_TOUCH_SENSOR_NUM) - 1)) -#define TOUCH_LL_NULL_CHANNEL (15) // Null Channel id. Used for disabling some functions like sleep/approach/waterproof +#define TOUCH_LL_NULL_CHANNEL (15) // Null Channel id. Used for disabling some functions like sleep/proximity/waterproof #define TOUCH_LL_PAD_MEASURE_WAIT_MAX (0x7FFF) // The timer frequency is 8Mhz, the max value is 0xff +#define TOUCH_LL_ACTIVE_THRESH_MAX (0xFFFF) // Max channel active threshold +#define TOUCH_LL_CLK_DIV_MAX (0x08) // Max clock divider value +#define TOUCH_LL_TIMEOUT_MAX (0xFFFF) // Max timeout value /** * Enable/disable clock gate of touch sensor. * * @param enable true/false. */ -static inline void touch_ll_enable_clock(bool enable) +static inline void touch_ll_enable_module_clock(bool enable) { - LP_ANA_PERI.date.clk_en = enable; + LPPERI.clk_en.ck_en_lp_touch = enable; +} + +/** + * Enable/disable clock gate of touch sensor. + * + * @param enable true/false. + */ +static inline void touch_ll_reset_module(void) +{ + LPPERI.reset_en.rst_en_lp_touch = 1; + LPPERI.reset_en.rst_en_lp_touch = 0; } /** @@ -71,14 +87,14 @@ static inline void touch_ll_set_power_on_wait_cycle(uint32_t wait_cycles) /** * Set touch sensor touch sensor charge and discharge times of every measurement on a pad. * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param charge_times The times of charge and discharge in each measure process of touch channels. - * The timer frequency is 8Mhz. Range: 0 ~ 0xffff. + * The timer frequency is RTC_FAST (about 16M). Range: 0 ~ 0xffff. */ -static inline void touch_ll_set_charge_times(uint8_t sampler_id, uint16_t charge_times) +static inline void touch_ll_set_charge_times(uint8_t sample_cfg_id, uint16_t charge_times) { //The times of charge and discharge in each measure process of touch channels. - switch (sampler_id) { + switch (sample_cfg_id) { case 0: LP_ANA_PERI.touch_work_meas_num.touch_meas_num0 = charge_times; break; @@ -98,9 +114,9 @@ static inline void touch_ll_set_charge_times(uint8_t sampler_id, uint16_t charge * * @param meas_times Pointer to accept times count of charge and discharge. */ -static inline void touch_ll_get_charge_times(uint8_t sampler_id, uint16_t *charge_times) +static inline void touch_ll_get_charge_times(uint8_t sample_cfg_id, uint16_t *charge_times) { - switch (sampler_id) { + switch (sample_cfg_id) { case 0: *charge_times = LP_ANA_PERI.touch_work_meas_num.touch_meas_num0; break; @@ -140,21 +156,21 @@ static inline void touch_ll_get_measure_interval_ticks(uint16_t *interval_ticks) } /** - * Set touch sensor FSM mode. - * The measurement action can be triggered by the hardware timer, as well as by the software instruction. + * Enable touch sensor FSM timer trigger (continuous) mode or software trigger (oneshot) mode. * - * @param mode FSM mode. - * TOUCH_FSM_MODE_TIMER: the FSM will trigger scanning repeatedly under the control of the hardware timer - * TOUCH_FSM_MODE_SW: the FSM will trigger scanning once under the control of the software + * @param enable Enable FSM timer mode. + * True: the FSM will trigger scanning repeatedly under the control of the hardware timer (continuous mode) + * False: the FSM will trigger scanning once under the control of the software (continuous mode) */ -static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode) +__attribute__((always_inline)) +static inline void touch_ll_enable_fsm_timer(bool enable) { // FSM controlled by timer or software - LP_ANA_PERI.touch_mux0.touch_fsm_en = mode; - // Start by timer or software - LP_ANA_PERI.touch_mux0.touch_start_force = mode; - // Stop by timer or software - LP_ANA_PERI.touch_mux0.touch_done_force = mode; + LP_ANA_PERI.touch_mux0.touch_fsm_en = enable; + // Set 0 to stop by timer, otherwise by software + LP_ANA_PERI.touch_mux0.touch_done_force = !enable; + // Set 0 to start by timer, otherwise by software + LP_ANA_PERI.touch_mux0.touch_start_force = !enable; } /** @@ -182,18 +198,23 @@ static inline bool touch_ll_is_fsm_using_timer(void) /** * Touch timer trigger measurement and always wait measurement done. * Force done for touch timer ensures that the timer always can get the measurement done signal. + * @note The `force done` signal should last as least one slow clock tick */ +__attribute__((always_inline)) static inline void touch_ll_force_done_curr_measurement(void) { - if (touch_ll_is_fsm_using_timer()) { - LP_ANA_PERI.touch_mux0.touch_done_force = TOUCH_LL_TIMER_FORCE_DONE_BY_SW; - LP_ANA_PERI.touch_mux0.touch_done_en = 1; - LP_ANA_PERI.touch_mux0.touch_done_en = 0; - LP_ANA_PERI.touch_mux0.touch_done_force = TOUCH_LL_TIMER_DONE_BY_FSM; - } else { - LP_ANA_PERI.touch_mux0.touch_done_en = 1; - LP_ANA_PERI.touch_mux0.touch_done_en = 0; - } + // Enable event tick first + LP_AON_CLKRST.lp_clk_en.etm_event_tick_en = 1; + // Set `force done` signal + PMU.touch_pwr_cntl.force_done = 1; + // Force done signal should last at least one slow clock tick, wait until tick interrupt triggers + LP_SYS.int_clr.slow_clk_tick_int_clr = 1; + while(LP_SYS.int_clr.slow_clk_tick_int_clr); + while(!LP_SYS.int_raw.slow_clk_tick_int_raw); + // Clear `force done` signal + PMU.touch_pwr_cntl.force_done = 0; + // Disable event tick + LP_AON_CLKRST.lp_clk_en.etm_event_tick_en = 0; } /** @@ -203,6 +224,7 @@ static inline void touch_ll_force_done_curr_measurement(void) * The timer should be triggered * @param is_sleep Whether in sleep state */ +__attribute__((always_inline)) static inline void touch_ll_start_fsm_repeated_timer(bool is_sleep) { /** @@ -210,11 +232,7 @@ static inline void touch_ll_start_fsm_repeated_timer(bool is_sleep) * Force done for touch timer ensures that the timer always can get the measurement done signal. */ touch_ll_force_done_curr_measurement(); - if (is_sleep) { - PMU.touch_pwr_cntl.sleep_timer_en = 1; - } else { - LP_ANA_PERI.touch_mux0.touch_start_en = 1; - } + PMU.touch_pwr_cntl.sleep_timer_en = 1; } /** @@ -222,21 +240,31 @@ static inline void touch_ll_start_fsm_repeated_timer(bool is_sleep) * The measurement action can be triggered by the hardware timer, as well as by the software instruction. * @param is_sleep Whether in sleep state */ +__attribute__((always_inline)) static inline void touch_ll_stop_fsm_repeated_timer(bool is_sleep) { - if (is_sleep) { - PMU.touch_pwr_cntl.sleep_timer_en = 0; - } else { - LP_ANA_PERI.touch_mux0.touch_start_en = 0; - } + PMU.touch_pwr_cntl.sleep_timer_en = 0; touch_ll_force_done_curr_measurement(); } /** - * Start touch sensor FSM once by software - * @note Every trigger means measuring one channel, not scanning all enabled channels + * Is the FSM repeated timer enabled. + * @note when the timer is enabled, RTC clock should not be power down + * + * @return + * - true: enabled + * - true: disabled */ -static inline void touch_ll_start_fsm_once(void) +static inline bool touch_ll_is_fsm_repeated_timer_enabled(void) +{ + return (bool)(PMU.touch_pwr_cntl.sleep_timer_en); +} + +/** + * Enable the touch sensor FSM start signal from software + */ +__attribute__((always_inline)) +static inline void touch_ll_trigger_oneshot_measurement(void) { /* Trigger once measurement */ LP_ANA_PERI.touch_mux0.touch_start_en = 1; @@ -245,7 +273,8 @@ static inline void touch_ll_start_fsm_once(void) static inline void touch_ll_measure_channel_once(uint16_t chan_mask) { - LP_ANA_PERI.touch_mux1.touch_start = chan_mask; + // Channel shift workaround + LP_ANA_PERI.touch_mux1.touch_start = chan_mask << 1; } /** @@ -255,13 +284,34 @@ static inline void touch_ll_measure_channel_once(uint16_t chan_mask) * * @note If set "TOUCH_PAD_THRESHOLD_MAX", the touch is never be triggered. * @param touch_num The touch pad id - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param thresh The threshold of charge cycles */ -static inline void touch_ll_set_chan_active_threshold(uint32_t touch_num, uint8_t sampler_id, uint32_t thresh) +static inline void touch_ll_set_chan_active_threshold(uint32_t touch_num, uint8_t sample_cfg_id, uint32_t thresh) { - HAL_ASSERT(sampler_id < SOC_TOUCH_SAMPLER_NUM); - HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_padx_thn[touch_num].thn[sampler_id], threshold, thresh); + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + // Channel shift workaround + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_padx_thn[touch_num + 1].thresh[sample_cfg_id], threshold, thresh); // codespell:ignore +} + +/** + * @brief Enable or disable the channel that will be scanned. + * @note The shield channel should not be enabled to scan here + * + * @param chan_mask The channel mask to be enabled or disabled + * @param enable Enable or disable the channel mask + */ +__attribute__((always_inline)) +static inline void touch_ll_enable_scan_mask(uint16_t chan_mask, bool enable) +{ + // Channel shift workaround: the lowest bit takes no effect + uint16_t mask = (chan_mask << 1) & TOUCH_PAD_BIT_MASK_ALL; + uint16_t prev_mask = LP_ANA_PERI.touch_scan_ctrl1.touch_scan_pad_map; + if (enable) { + LP_ANA_PERI.touch_scan_ctrl1.touch_scan_pad_map = prev_mask | mask; + } else { + LP_ANA_PERI.touch_scan_ctrl1.touch_scan_pad_map = prev_mask & (~mask); + } } /** @@ -278,7 +328,8 @@ static inline void touch_ll_set_chan_active_threshold(uint32_t touch_num, uint8_ */ static inline void touch_ll_set_channel_mask(uint16_t enable_mask) { - uint16_t mask = enable_mask & TOUCH_PAD_BIT_MASK_ALL; + // Channel shift workaround: the lowest bit takes no effect + uint16_t mask = (enable_mask << 1) & TOUCH_PAD_BIT_MASK_ALL; LP_ANA_PERI.touch_scan_ctrl1.touch_scan_pad_map = mask; LP_ANA_PERI.touch_filter2.touch_outen = mask; } @@ -288,10 +339,12 @@ static inline void touch_ll_set_channel_mask(uint16_t enable_mask) * * @param chan_mask The channel mask that needs to power on */ -static inline void touch_ll_channel_power_on(uint16_t chan_mask) +__attribute__((always_inline)) +static inline void touch_ll_channel_sw_measure_mask(uint16_t chan_mask) { - uint32_t curr_mask = LP_ANA_PERI.touch_mux1.touch_xpd; - LP_ANA_PERI.touch_mux1.touch_xpd = chan_mask | curr_mask; + // Channel shift workaround + LP_ANA_PERI.touch_mux1.touch_xpd = chan_mask << 1; + LP_ANA_PERI.touch_mux1.touch_start = chan_mask << 1; } /** @@ -302,20 +355,8 @@ static inline void touch_ll_channel_power_on(uint16_t chan_mask) static inline void touch_ll_channel_power_off(uint16_t chan_mask) { uint32_t curr_mask = LP_ANA_PERI.touch_mux1.touch_xpd; - LP_ANA_PERI.touch_mux1.touch_xpd = (~chan_mask) & curr_mask; -} - -/** - * @brief Start channel by mask - * @note Only start the specified channels - * - * @param chan_mask The channel mask that needs to start - */ -static inline void touch_ll_channel_start(uint16_t chan_mask) -{ - uint32_t curr_mask = LP_ANA_PERI.touch_mux1.touch_start; - LP_ANA_PERI.touch_mux1.touch_start = chan_mask | curr_mask; - LP_ANA_PERI.touch_mux1.touch_start = (~chan_mask) & curr_mask; + // Channel shift workaround + LP_ANA_PERI.touch_mux1.touch_xpd = (~(chan_mask << 1)) & curr_mask; } /** @@ -323,9 +364,11 @@ static inline void touch_ll_channel_start(uint16_t chan_mask) * * @param active_mask The touch channel status. e.g. Touch1 trigger status is `status_mask & (BIT1)`. */ +__attribute__((always_inline)) static inline void touch_ll_get_active_channel_mask(uint32_t *active_mask) { - *active_mask = LP_TOUCH.chn_status.pad_active; + // Channel shift workaround + *active_mask = (LP_TOUCH.chn_status.pad_active >> 1); } /** @@ -342,22 +385,23 @@ static inline void touch_ll_clear_active_channel_status(void) * Get the data of the touch channel according to the types * * @param touch_num touch pad index - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param type data type - * 0/1: TOUCH_LL_READ_RAW, the raw data of the touch channel + * 0/1: not work * 2: TOUCH_LL_READ_BENCHMARK, benchmark value of touch channel, * the benchmark value is the maximum during the first measurement period * 3: TOUCH_LL_READ_SMOOTH, the smoothed data that obtained by filtering the raw data. * @param data pointer to the data */ __attribute__((always_inline)) -static inline void touch_ll_read_chan_data(uint32_t touch_num, uint8_t sampler_id, uint8_t type, uint32_t *data) +static inline void touch_ll_read_chan_data(uint32_t touch_num, uint8_t sample_cfg_id, uint8_t type, uint32_t *data) { - HAL_ASSERT(sampler_id < SOC_TOUCH_SAMPLER_NUM); - HAL_ASSERT(type <= TOUCH_LL_READ_SMOOTH); - LP_ANA_PERI.touch_mux0.touch_freq_sel = sampler_id + 1; + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + HAL_ASSERT(type == TOUCH_LL_READ_BENCHMARK || type == TOUCH_LL_READ_SMOOTH); + LP_ANA_PERI.touch_mux0.touch_freq_sel = sample_cfg_id; LP_ANA_PERI.touch_mux0.touch_data_sel = type; - *data = LP_TOUCH.chn_data[touch_num - 1].pad_data; + // Channel shift workaround + *data = LP_TOUCH.chn_data[touch_num + 1].pad_data; } /** @@ -366,12 +410,17 @@ static inline void touch_ll_read_chan_data(uint32_t touch_num, uint8_t sampler_i * @return * - If touch sensors measure done. */ -static inline bool touch_ll_is_measure_done(uint32_t *touch_num) +__attribute__((always_inline)) +static inline bool touch_ll_is_measure_done(void) { - *touch_num = (uint32_t)(LP_TOUCH.chn_status.scan_curr); return (bool)LP_TOUCH.chn_status.meas_done; } +static inline uint32_t touch_ll_get_current_measure_channel(void) +{ + // Channel shift workaround + return (uint32_t)(LP_TOUCH.chn_status.scan_curr - 1); +} /** * Select the counting mode of the binarized touch out wave * @@ -384,26 +433,36 @@ static inline void touch_ll_set_out_mode(touch_out_mode_t mode) LP_ANA_PERI.touch_work.touch_out_sel = mode; } +/** + * @brief Enable/disable the touch sensor output gate + * + * @param enable set true to enable the output gate, false to disable it + */ +static inline void touch_ll_enable_out_gate(bool enable) +{ + LP_ANA_PERI.touch_work.touch_out_gate = enable; +} + /** * @brief Set the clock division of the sampling frequency * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param div_num Division number */ -static inline void touch_ll_set_clock_div(uint8_t sampler_id, uint32_t div_num) +static inline void touch_ll_set_clock_div(uint8_t sample_cfg_id, uint32_t div_num) { - switch (sampler_id) { + switch (sample_cfg_id) { case 0: - LP_ANA_PERI.touch_work.div_num0 = div_num; + LP_ANA_PERI.touch_work.div_num0 = div_num - 1; break; case 1: - LP_ANA_PERI.touch_work.div_num1 = div_num; + LP_ANA_PERI.touch_work.div_num1 = div_num - 1; break; case 2: - LP_ANA_PERI.touch_work.div_num2 = div_num; + LP_ANA_PERI.touch_work.div_num2 = div_num - 1; break; default: - // invalid sampler_id + // invalid sample_cfg_id abort(); } } @@ -434,7 +493,8 @@ static inline void touch_ll_set_idle_channel_connect(touch_pad_conn_type_t type) __attribute__((always_inline)) static inline uint32_t touch_ll_get_current_meas_channel(void) { - return (uint32_t)(LP_TOUCH.chn_status.scan_curr); + // Channel shift workaround + return (uint32_t)(LP_TOUCH.chn_status.scan_curr - 1); } /** @@ -466,9 +526,10 @@ static inline void touch_ll_intr_disable(uint32_t int_mask) * * @param int_mask Pad mask to clear interrupts */ -static inline void touch_ll_intr_clear_all(void) +__attribute__((always_inline)) +static inline void touch_ll_intr_clear(touch_pad_intr_mask_t int_mask) { - LP_TOUCH.int_clr.val = TOUCH_LL_INTR_MASK_ALL; + LP_TOUCH.int_clr.val = int_mask; } /** @@ -476,6 +537,7 @@ static inline void touch_ll_intr_clear_all(void) * * @return type interrupt type */ +__attribute__((always_inline)) static inline uint32_t touch_ll_get_intr_status_mask(void) { uint32_t intr_st = LP_TOUCH.int_st.val; @@ -508,56 +570,68 @@ static inline void touch_ll_timeout_disable(void) } /** - * Set the engaged sampler number + * Set the engaged sample configuration number * - * @param sampler_num The enabled sampler number, range 0~3. - * 0/1 means only one sampler enabled, which can not support frequency hopping + * @param sample_cfg_num The enabled sample configuration number, range 0~3. + * 0/1 means only one sample configuration enabled, which can not support frequency hopping */ -static inline void touch_ll_sampler_set_engaged_num(uint8_t sampler_num) +static inline void touch_ll_sample_cfg_set_engaged_num(uint8_t sample_cfg_num) { - HAL_ASSERT(sampler_num < SOC_TOUCH_SAMPLER_NUM); - LP_ANA_PERI.touch_scan_ctrl2.freq_scan_en = !!sampler_num; - LP_ANA_PERI.touch_scan_ctrl2.freq_scan_cnt_limit = sampler_num ? sampler_num : 1; + HAL_ASSERT(sample_cfg_num <= SOC_TOUCH_SAMPLE_CFG_NUM); + LP_ANA_PERI.touch_scan_ctrl2.freq_scan_en = !!sample_cfg_num; + LP_ANA_PERI.touch_scan_ctrl2.freq_scan_cnt_limit = sample_cfg_num ? sample_cfg_num : 1; } /** * Set capacitance and resistance of the RC filter of the sampling frequency. * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param cap Capacitance of the RC filter. * @param res Resistance of the RC filter. */ -static inline void touch_ll_sampler_set_rc_filter(uint8_t sampler_id, uint32_t cap, uint32_t res) +static inline void touch_ll_sample_cfg_set_rc_filter(uint8_t sample_cfg_id, uint32_t cap, uint32_t res) { - HAL_ASSERT(sampler_id < SOC_TOUCH_SAMPLER_NUM); - LP_ANA_PERI.touch_freq_scan_para[sampler_id].touch_freq_dcap_lpf = cap; - LP_ANA_PERI.touch_freq_scan_para[sampler_id].touch_freq_dres_lpf = res; + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_freq_dcap_lpf = cap; + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_freq_dres_lpf = res; } /** * @brief Set the driver of the sampling frequency * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param ls_drv Low speed touch driver * @param hs_drv High speed touch driver */ -static inline void touch_ll_sampler_set_driver(uint8_t sampler_id, uint32_t ls_drv, uint32_t hs_drv) +static inline void touch_ll_sample_cfg_set_driver(uint8_t sample_cfg_id, uint32_t ls_drv, uint32_t hs_drv) +{ + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_freq_drv_ls = ls_drv; + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_freq_drv_hs = hs_drv; +} + +/** + * Bypass the shield channel output for the specify sample configuration + * + * @param sample_cfg_id The sample configuration index + * @param enable Set true to bypass the shield channel output for the current channel + */ +static inline void touch_ll_sample_cfg_bypass_shield_output(uint8_t sample_cfg_id, bool enable) { - HAL_ASSERT(sampler_id < SOC_TOUCH_SAMPLER_NUM); - LP_ANA_PERI.touch_freq_scan_para[sampler_id].touch_freq_drv_ls = ls_drv; - LP_ANA_PERI.touch_freq_scan_para[sampler_id].touch_freq_drv_hs = hs_drv; + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_bypass_shield = enable; } /** * Set the touch internal LDO bias voltage of the sampling frequency * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param bias_volt LDO bias voltage */ -static inline void touch_ll_sampler_set_bias_voltage(uint8_t sampler_id, uint32_t bias_volt) +static inline void touch_ll_sample_cfg_set_bias_voltage(uint8_t sample_cfg_id, uint32_t bias_volt) { - HAL_ASSERT(sampler_id < SOC_TOUCH_SAMPLER_NUM); - LP_ANA_PERI.touch_freq_scan_para[sampler_id].touch_freq_dbias = bias_volt; + HAL_ASSERT(sample_cfg_id < SOC_TOUCH_SAMPLE_CFG_NUM); + LP_ANA_PERI.touch_freq_scan_para[sample_cfg_id].touch_freq_dbias = bias_volt; } /** @@ -581,6 +655,7 @@ static inline void touch_ll_set_internal_loop_capacitance(int cap) * @note If call this API, make sure enable clock gate(`touch_ll_clkgate`) first. * @param chan_mask touch channel mask */ +__attribute__((always_inline)) static inline void touch_ll_reset_chan_benchmark(uint32_t chan_mask) { LP_ANA_PERI.touch_clr.touch_channel_clr = chan_mask; @@ -711,7 +786,8 @@ static inline void touch_ll_force_update_benchmark(uint32_t benchmark) */ static inline void touch_ll_waterproof_set_guard_chan(uint32_t pad_num) { - LP_ANA_PERI.touch_scan_ctrl2.touch_out_ring = pad_num; + // Channel shift workaround + LP_ANA_PERI.touch_scan_ctrl2.touch_out_ring = pad_num == TOUCH_LL_NULL_CHANNEL ? TOUCH_LL_NULL_CHANNEL : pad_num + 1; } /** @@ -734,7 +810,8 @@ static inline void touch_ll_waterproof_enable(bool enable) */ static inline void touch_ll_waterproof_set_shield_chan_mask(uint32_t mask) { - LP_ANA_PERI.touch_mux0.touch_bufsel = (mask & TOUCH_LL_FULL_CHANNEL_MASK); + // Channel shift workaround + LP_ANA_PERI.touch_mux0.touch_bufsel = mask << 1; } /** @@ -750,63 +827,76 @@ static inline void touch_ll_waterproof_set_shield_driver(touch_pad_shield_driver /************************ Approach register setting ************************/ /** - * Set the approach channel to the specific touch channel - * To disable the approach channel, point this pad to `TOUCH_LL_NULL_CHANNEL` + * Set the proximity sensing channel to the specific touch channel + * To disable the proximity channel, point this pad to `TOUCH_LL_NULL_CHANNEL` * - * @param aprch_chan approach channel. - * @param touch_num The touch channel that supposed to be used as approach channel + * @param prox_chan proximity sensing channel. + * @param touch_num The touch channel that supposed to be used as proximity sensing channel */ -static inline void touch_ll_set_approach_channel(uint8_t aprch_chan, uint32_t touch_num) +static inline void touch_ll_set_proximity_sensing_channel(uint8_t prox_chan, uint32_t touch_num) { - switch (aprch_chan) { + switch (prox_chan) { case 0: - LP_ANA_PERI.touch_approach.touch_approach_pad0 = touch_num; + // Channel shift workaround + LP_ANA_PERI.touch_approach.touch_approach_pad0 = touch_num + 1; break; case 1: - LP_ANA_PERI.touch_approach.touch_approach_pad1 = touch_num; + // Channel shift workaround + LP_ANA_PERI.touch_approach.touch_approach_pad1 = touch_num + 1; break; case 2: - LP_ANA_PERI.touch_approach.touch_approach_pad2 = touch_num; + // Channel shift workaround + LP_ANA_PERI.touch_approach.touch_approach_pad2 = touch_num + 1; break; default: - // invalid approach channel + // invalid proximity channel abort(); } } /** - * Set cumulative measurement times for approach channel. + * Set the total scan times of the proximity sensing channel. * - * @param sampler_id The sampler index - * @param times The cumulative number of measurement cycles. + * @param scan_times The total scan times of the proximity sensing channel */ -static inline void touch_ll_approach_set_measure_times(uint8_t sampler_id, uint32_t times) +static inline void touch_ll_proximity_set_total_scan_times(uint32_t scan_times) { - switch (sampler_id) { + LP_ANA_PERI.touch_filter1.touch_approach_limit = scan_times; +} + +/** + * Set charge times for each sample configuration in proximity sensing mode. + * + * @param sample_cfg_id The sample configuration index + * @param charge_times The charge and discharge times. + */ +static inline void touch_ll_proximity_set_charge_times(uint8_t sample_cfg_id, uint32_t charge_times) +{ + switch (sample_cfg_id) { case 0: - LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num0 = times; + LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num0 = charge_times; break; case 1: - LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num1 = times; + LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num1 = charge_times; break; case 2: - LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num2 = times; + LP_ANA_PERI.touch_approach_work_meas_num.touch_approach_meas_num2 = charge_times; break; default: - // invalid sampler_id + // invalid sample_cfg_id abort(); } } /** - * Read current cumulative measurement times for approach channel. + * Read current cumulative measurement times for proximity sensing channel. * - * @param aprch_chan approach channel. + * @param prox_chan proximity sensing channel. * @param cnt The cumulative number of measurement cycles. */ -static inline void touch_ll_approach_read_measure_cnt(uint8_t aprch_chan, uint32_t *cnt) +static inline void touch_ll_proximity_read_measure_cnt(uint8_t prox_chan, uint32_t *cnt) { - switch (aprch_chan) { + switch (prox_chan) { case 0: *cnt = HAL_FORCE_READ_U32_REG_FIELD(LP_TOUCH.aprch_ch_data, approach_pad0_cnt); break; @@ -823,19 +913,18 @@ static inline void touch_ll_approach_read_measure_cnt(uint8_t aprch_chan, uint32 } /** - * Check if the touch sensor channel is the approach channel. + * Check if the touch sensor channel is the proximity sensing channel. * * @param touch_num The touch sensor channel number. */ -static inline bool touch_ll_is_approach_channel(uint32_t touch_num) +static inline bool touch_ll_is_proximity_sensing_channel(uint32_t touch_num) { if ((LP_ANA_PERI.touch_approach.touch_approach_pad0 != touch_num) && (LP_ANA_PERI.touch_approach.touch_approach_pad1 != touch_num) && (LP_ANA_PERI.touch_approach.touch_approach_pad2 != touch_num)) { return false; - } else { - return true; } + return true; } /************** sleep channel setting ***********************/ @@ -848,7 +937,8 @@ static inline bool touch_ll_is_approach_channel(uint32_t touch_num) */ static inline void touch_ll_sleep_set_channel_num(uint32_t touch_num) { - LP_ANA_PERI.touch_slp0.touch_slp_pad = touch_num; + // Channel shift workaround + LP_ANA_PERI.touch_slp0.touch_slp_pad = touch_num + 1; } /** @@ -869,9 +959,9 @@ static inline void touch_ll_sleep_get_channel_num(uint32_t *touch_num) * * @note In general, the touch threshold during sleep can use the threshold parameter parameters before sleep. */ -static inline void touch_ll_sleep_set_threshold(uint8_t sampler_id, uint32_t touch_thresh) +static inline void touch_ll_sleep_set_threshold(uint8_t sample_cfg_id, uint32_t touch_thresh) { - switch (sampler_id) { + switch (sample_cfg_id) { case 0: HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_slp0, touch_slp_th0, touch_thresh); break; @@ -882,15 +972,15 @@ static inline void touch_ll_sleep_set_threshold(uint8_t sampler_id, uint32_t tou HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_slp1, touch_slp_th2, touch_thresh); break; default: - // invalid sampler_id + // invalid sample_cfg_id abort(); } } /** - * Enable approach function for sleep channel. + * Enable proximity sensing function for sleep channel. */ -static inline void touch_ll_sleep_enable_approach(bool enable) +static inline void touch_ll_sleep_enable_proximity_sensing(bool enable) { LP_ANA_PERI.touch_approach.touch_slp_approach_en = enable; } @@ -898,7 +988,7 @@ static inline void touch_ll_sleep_enable_approach(bool enable) /** * Get the data of the touch channel according to the types * - * @param sampler_id The sampler index + * @param sample_cfg_id The sample configuration index * @param type data type * 0/1: TOUCH_LL_READ_RAW, the raw data of the touch channel * 2: TOUCH_LL_READ_BENCHMARK, benchmark value of touch channel, @@ -907,10 +997,10 @@ static inline void touch_ll_sleep_enable_approach(bool enable) * @param smooth_data pointer to smoothed data */ __attribute__((always_inline)) -static inline void touch_ll_sleep_read_chan_data(uint8_t type, uint8_t sampler_id, uint32_t *data) +static inline void touch_ll_sleep_read_chan_data(uint8_t type, uint8_t sample_cfg_id, uint32_t *data) { HAL_ASSERT(type <= TOUCH_LL_READ_SMOOTH); - LP_ANA_PERI.touch_mux0.touch_freq_sel = sampler_id + 1; + LP_ANA_PERI.touch_mux0.touch_freq_sel = sample_cfg_id + 1; LP_ANA_PERI.touch_mux0.touch_data_sel = type; *data = HAL_FORCE_READ_U32_REG_FIELD(LP_TOUCH.slp_ch_data, slp_data); } @@ -935,12 +1025,33 @@ static inline void touch_ll_sleep_read_debounce(uint32_t *debounce) } /** - * Read approach count of touch sensor for sleep channel. - * @param approach_cnt Pointer to accept touch sensor approach count value. + * Read proximity count of touch sensor for sleep channel. + * @param prox_cnt Pointer to accept touch sensor proximity count value. + */ +static inline void touch_ll_sleep_read_proximity_cnt(uint32_t *prox_cnt) +{ + *prox_cnt = HAL_FORCE_READ_U32_REG_FIELD(LP_TOUCH.aprch_ch_data, slp_approach_cnt); +} + +/** + * @brief Enable or disable the internal capacitor, mainly for debug + * + * @param enable enable or disable the internal capacitor + */ +static inline void touch_ll_enable_internal_capacitor(bool enable) +{ + LP_ANA_PERI.touch_ana_para.touch_touch_en_cal = enable; +} + +/** + * @brief Set the internal capacitor, mainly for debug + * @note Only take effect when the internal capacitor is enabled + * + * @param cap the capacitor value */ -static inline void touch_ll_sleep_read_approach_cnt(uint32_t *approach_cnt) +static inline void touch_ll_set_internal_capacitor(uint32_t cap) { - *approach_cnt = HAL_FORCE_READ_U32_REG_FIELD(LP_TOUCH.aprch_ch_data, slp_approach_cnt); + LP_ANA_PERI.touch_ana_para.touch_touch_dcap_cal = cap; } #ifdef __cplusplus diff --git a/components/hal/esp32p4/touch_sensor_hal.c b/components/hal/esp32p4/touch_sensor_hal.c new file mode 100644 index 00000000000..8f11b230d7e --- /dev/null +++ b/components/hal/esp32p4/touch_sensor_hal.c @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/soc_pins.h" +#include "hal/touch_sensor_ll.h" +#include "hal/touch_sensor_hal.h" +#include "hal/touch_sensor_types.h" +#include "soc/soc_caps.h" + +typedef struct { + int deep_slp_chan; + touch_hal_config_t slp_cfg; + bool apply_slp_cfg; +} touch_hal_deep_sleep_obj_t; + +static touch_hal_deep_sleep_obj_t s_touch_slp_obj = { + .deep_slp_chan = -1, + .apply_slp_cfg = false, +}; + +void touch_hal_config_controller(const touch_hal_config_t *cfg) +{ + HAL_ASSERT(cfg); + touch_ll_set_out_mode(cfg->output_mode); + touch_ll_set_power_on_wait_cycle(cfg->power_on_wait_ticks); + touch_ll_set_measure_interval_ticks(cfg->meas_interval_ticks); + if (cfg->timeout_ticks) { + touch_ll_timeout_enable(cfg->timeout_ticks); + } else { + touch_ll_timeout_disable(); + } + + touch_ll_sample_cfg_set_engaged_num(cfg->sample_cfg_num); + for (int i = 0; i < cfg->sample_cfg_num; i++) { + touch_ll_set_clock_div(i, cfg->sample_cfg[i].div_num); + touch_ll_set_charge_times(i, cfg->sample_cfg[i].charge_times); + touch_ll_sample_cfg_set_rc_filter(i, cfg->sample_cfg[i].rc_filter_cap, cfg->sample_cfg[i].rc_filter_res); + touch_ll_sample_cfg_set_driver(i, cfg->sample_cfg[i].low_drv, cfg->sample_cfg[i].high_drv); + touch_ll_sample_cfg_bypass_shield_output(i, cfg->sample_cfg[i].bypass_shield_output); + touch_ll_sample_cfg_set_bias_voltage(i, cfg->sample_cfg[i].bias_volt); + } +} + +void touch_hal_save_sleep_config(int deep_slp_chan, const touch_hal_config_t *deep_slp_cfg) +{ + s_touch_slp_obj.deep_slp_chan = deep_slp_chan; + /* If particular deep sleep configuration is given, save it and apply it before entering the deep sleep */ + if (deep_slp_chan >= 0 && deep_slp_cfg) { + s_touch_slp_obj.apply_slp_cfg = true; + memcpy(&s_touch_slp_obj.slp_cfg, deep_slp_cfg, sizeof(touch_hal_config_t)); + } else { + s_touch_slp_obj.apply_slp_cfg = false; + } +} + +//This function will only be called when the chip is going to deep sleep. +static void s_touch_hal_apply_sleep_config(void) +{ + /* Apply the particular configuration for deep sleep */ + if (s_touch_slp_obj.apply_slp_cfg) { + touch_hal_config_controller(&s_touch_slp_obj.slp_cfg); + } + /* Whether to enable touch sensor wake-up the chip from deep sleep */ + if (s_touch_slp_obj.deep_slp_chan >= 0) { + touch_ll_sleep_set_channel_num(s_touch_slp_obj.deep_slp_chan); + touch_ll_set_channel_mask(BIT(s_touch_slp_obj.deep_slp_chan)); + } else { + touch_ll_sleep_set_channel_num(TOUCH_LL_NULL_CHANNEL); + } +} + +void touch_hal_prepare_deep_sleep(void) +{ + s_touch_hal_apply_sleep_config(); + // TODO: check if it is necessary to reset the sleep benchmark + touch_ll_sleep_reset_benchmark(); + touch_ll_intr_clear(TOUCH_LL_INTR_MASK_ALL); +} diff --git a/components/hal/esp32s2/include/hal/touch_sensor_hal.h b/components/hal/esp32s2/include/hal/touch_sensor_hal.h index 5f0c266018d..b42532c78f9 100644 --- a/components/hal/esp32s2/include/hal/touch_sensor_hal.h +++ b/components/hal/esp32s2/include/hal/touch_sensor_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,7 +26,7 @@ extern "C" { /** * Reset the whole of touch module. * - * @note Call this funtion after `touch_pad_fsm_stop`, + * @note Call this function after `touch_pad_fsm_stop`, */ #define touch_hal_reset() touch_ll_reset() @@ -385,7 +385,7 @@ void touch_hal_denoise_enable(void); #define touch_hal_waterproof_get_guard_pad(pad_num) touch_ll_waterproof_get_guard_pad(pad_num) /** - * Set max equivalent capacitance for sheild channel. + * Set max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -394,7 +394,7 @@ void touch_hal_denoise_enable(void); #define touch_hal_waterproof_set_sheild_driver(driver_level) touch_ll_waterproof_set_sheild_driver(driver_level) /** - * Get max equivalent capacitance for sheild channel. + * Get max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -551,12 +551,12 @@ void touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable); /** * Enable proximity function for sleep pad. */ -#define touch_hal_sleep_enable_approach() touch_ll_sleep_enable_approach() +#define touch_hal_sleep_enable_approach() touch_ll_sleep_enable_proximity_sensing() /** * Disable proximity function for sleep pad. */ -#define touch_hal_sleep_disable_approach() touch_ll_sleep_disable_approach() +#define touch_hal_sleep_disable_approach() touch_ll_sleep_disable_proximity_sensing() /** * Read benchmark of touch sensor for sleep pad. diff --git a/components/hal/esp32s2/include/hal/touch_sensor_ll.h b/components/hal/esp32s2/include/hal/touch_sensor_ll.h index 656b79099f3..0cc5069d2f2 100644 --- a/components/hal/esp32s2/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32s2/include/hal/touch_sensor_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -214,6 +214,7 @@ static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_ * * @param mode FSM mode. */ +__attribute__((always_inline)) static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode) { RTCCNTL.touch_ctrl2.touch_start_force = mode; @@ -280,6 +281,7 @@ static inline void touch_ll_start_fsm(void) * Stop touch sensor FSM timer. * The measurement action can be triggered by the hardware timer, as well as by the software instruction. */ +__attribute__((always_inline)) static inline void touch_ll_stop_fsm(void) { RTCCNTL.touch_ctrl2.touch_start_en = 0; //stop touch fsm @@ -416,7 +418,8 @@ static inline uint32_t IRAM_ATTR touch_ll_read_raw_data(touch_pad_t touch_num) * @return * - If touch sensors measure done. */ -static inline bool touch_ll_meas_is_done(void) +__attribute__((always_inline)) +static inline bool touch_ll_is_measure_done(void) { return (bool)SENS.sar_touch_chn_st.touch_meas_done; } @@ -555,22 +558,23 @@ static inline void touch_ll_intr_clear(touch_pad_intr_mask_t int_mask) */ static inline uint32_t touch_ll_read_intr_status_mask(void) { - uint32_t intr_st = RTCCNTL.int_st.val; + typeof(RTCCNTL.int_st) intr_st; + intr_st.val = RTCCNTL.int_st.val; uint32_t intr_msk = 0; - if (intr_st & RTC_CNTL_TOUCH_DONE_INT_ST_M) { + if (intr_st.rtc_touch_done) { intr_msk |= TOUCH_PAD_INTR_MASK_DONE; } - if (intr_st & RTC_CNTL_TOUCH_ACTIVE_INT_ST_M) { + if (intr_st.rtc_touch_active) { intr_msk |= TOUCH_PAD_INTR_MASK_ACTIVE; } - if (intr_st & RTC_CNTL_TOUCH_INACTIVE_INT_ST_M) { + if (intr_st.rtc_touch_inactive) { intr_msk |= TOUCH_PAD_INTR_MASK_INACTIVE; } - if (intr_st & RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M) { + if (intr_st.rtc_touch_scan_done) { intr_msk |= TOUCH_PAD_INTR_MASK_SCAN_DONE; } - if (intr_st & RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M) { + if (intr_st.rtc_touch_timeout) { intr_msk |= TOUCH_PAD_INTR_MASK_TIMEOUT; } return (intr_msk & TOUCH_PAD_INTR_MASK_ALL); @@ -909,7 +913,7 @@ static inline void touch_ll_waterproof_get_guard_pad(touch_pad_t *pad_num) } /** - * Set max equivalent capacitance for sheild channel. + * Set max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -921,7 +925,7 @@ static inline void touch_ll_waterproof_set_sheild_driver(touch_pad_shield_driver } /** - * Get max equivalent capacitance for sheild channel. + * Get max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -1084,7 +1088,7 @@ static inline void touch_ll_sleep_get_threshold(uint32_t *touch_thres) /** * Enable proximity function for sleep pad. */ -static inline void touch_ll_sleep_enable_approach(void) +static inline void touch_ll_sleep_enable_proximity_sensing(void) { RTCCNTL.touch_slp_thres.touch_slp_approach_en = 1; } @@ -1092,7 +1096,7 @@ static inline void touch_ll_sleep_enable_approach(void) /** * Disable proximity function for sleep pad. */ -static inline void touch_ll_sleep_disable_approach(void) +static inline void touch_ll_sleep_disable_proximity_sensing(void) { RTCCNTL.touch_slp_thres.touch_slp_approach_en = 0; } @@ -1100,7 +1104,7 @@ static inline void touch_ll_sleep_disable_approach(void) /** * Get proximity function status for sleep pad. */ -static inline bool touch_ll_sleep_get_approach_status(void) +static inline bool touch_ll_sleep_is_proximity_enabled(void) { return (bool)RTCCNTL.touch_slp_thres.touch_slp_approach_en; } @@ -1157,11 +1161,11 @@ static inline void touch_ll_sleep_read_debounce(uint32_t *debounce) /** * Read proximity count of touch sensor for sleep pad. - * @param proximity_cnt Pointer to accept touch sensor proximity count value. + * @param prox_cnt Pointer to accept touch sensor proximity count value. */ -static inline void touch_ll_sleep_read_proximity_cnt(uint32_t *approach_cnt) +static inline void touch_ll_sleep_read_proximity_cnt(uint32_t *prox_cnt) { - *approach_cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_slp_approach_cnt); + *prox_cnt = HAL_FORCE_READ_U32_REG_FIELD(SENS.sar_touch_appr_status, touch_slp_approach_cnt); } /** diff --git a/components/hal/esp32s2/touch_sensor_hal.c b/components/hal/esp32s2/touch_sensor_hal.c index 04deb1c9252..78bc17819e0 100644 --- a/components/hal/esp32s2/touch_sensor_hal.c +++ b/components/hal/esp32s2/touch_sensor_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,7 +53,7 @@ void touch_hal_deinit(void) touch_pad_t prox_pad[SOC_TOUCH_PROXIMITY_CHANNEL_NUM] = {[0 ... (SOC_TOUCH_PROXIMITY_CHANNEL_NUM - 1)] = 0}; touch_ll_proximity_set_channel_num((const touch_pad_t *)prox_pad); touch_ll_sleep_set_channel_num(0); - touch_ll_sleep_disable_approach(); + touch_ll_sleep_disable_proximity_sensing(); touch_ll_reset(); // Reset the touch sensor FSM. } @@ -152,7 +152,7 @@ void touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable) void touch_hal_sleep_channel_get_config(touch_pad_sleep_channel_t *slp_config) { touch_ll_sleep_get_channel_num(&slp_config->touch_num); - slp_config->en_proximity = touch_ll_sleep_get_approach_status(); + slp_config->en_proximity = touch_ll_sleep_is_proximity_enabled(); } void touch_hal_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times) diff --git a/components/hal/esp32s3/include/hal/touch_sensor_hal.h b/components/hal/esp32s3/include/hal/touch_sensor_hal.h index 603c437f166..c80f624fde1 100644 --- a/components/hal/esp32s3/include/hal/touch_sensor_hal.h +++ b/components/hal/esp32s3/include/hal/touch_sensor_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,7 +26,7 @@ extern "C" { /** * Reset the whole of touch module. * - * @note Call this funtion after `touch_pad_fsm_stop`, + * @note Call this function after `touch_pad_fsm_stop`, */ #define touch_hal_reset() touch_ll_reset() @@ -385,7 +385,7 @@ void touch_hal_denoise_enable(void); #define touch_hal_waterproof_get_guard_pad(pad_num) touch_ll_waterproof_get_guard_pad(pad_num) /** - * Set max equivalent capacitance for sheild channel. + * Set max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -394,7 +394,7 @@ void touch_hal_denoise_enable(void); #define touch_hal_waterproof_set_sheild_driver(driver_level) touch_ll_waterproof_set_sheild_driver(driver_level) /** - * Get max equivalent capacitance for sheild channel. + * Get max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -551,12 +551,12 @@ void touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable); /** * Enable proximity function for sleep pad. */ -#define touch_hal_sleep_enable_approach() touch_ll_sleep_enable_approach() +#define touch_hal_sleep_enable_approach() touch_ll_sleep_enable_proximity_sensing() /** * Disable proximity function for sleep pad. */ -#define touch_hal_sleep_disable_approach() touch_ll_sleep_disable_approach() +#define touch_hal_sleep_disable_approach() touch_ll_sleep_disable_proximity_sensing() /** * Read benchmark of touch sensor for sleep pad. diff --git a/components/hal/esp32s3/include/hal/touch_sensor_ll.h b/components/hal/esp32s3/include/hal/touch_sensor_ll.h index 0cb69edc541..d3dde4edd35 100644 --- a/components/hal/esp32s3/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32s3/include/hal/touch_sensor_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -168,11 +168,18 @@ static inline void touch_ll_get_voltage_attenuation(touch_volt_atten_t *atten) */ static inline void touch_ll_set_slope(touch_pad_t touch_num, touch_cnt_slope_t slope) { +#define PAD_SLOP_MASK(val, num) ((val) << (29 - (num) * 3)) + uint32_t curr_slop = 0; if (touch_num < TOUCH_PAD_NUM10) { - SET_PERI_REG_BITS(RTC_CNTL_TOUCH_DAC_REG, RTC_CNTL_TOUCH_PAD0_DAC_V, slope, (RTC_CNTL_TOUCH_PAD0_DAC_S - touch_num * 3)); + curr_slop = RTCCNTL.touch_dac.val; + curr_slop &= ~PAD_SLOP_MASK(0x07, touch_num); // clear the old value + RTCCNTL.touch_dac.val = curr_slop | PAD_SLOP_MASK(slope, touch_num); } else { - SET_PERI_REG_BITS(RTC_CNTL_TOUCH_DAC1_REG, RTC_CNTL_TOUCH_PAD10_DAC_V, slope, (RTC_CNTL_TOUCH_PAD10_DAC_S - (touch_num - TOUCH_PAD_NUM10) * 3)); + curr_slop = RTCCNTL.touch_dac1.val; + curr_slop &= ~PAD_SLOP_MASK(0x07, touch_num - TOUCH_PAD_NUM10); // clear the old value + RTCCNTL.touch_dac1.val = curr_slop | PAD_SLOP_MASK(slope, touch_num - TOUCH_PAD_NUM10); } +#undef PAD_SLOP_MASK } /** @@ -188,9 +195,9 @@ static inline void touch_ll_set_slope(touch_pad_t touch_num, touch_cnt_slope_t s static inline void touch_ll_get_slope(touch_pad_t touch_num, touch_cnt_slope_t *slope) { if (touch_num < TOUCH_PAD_NUM10) { - *slope = (touch_cnt_slope_t)(GET_PERI_REG_BITS2(RTC_CNTL_TOUCH_DAC_REG, RTC_CNTL_TOUCH_PAD0_DAC_V, (RTC_CNTL_TOUCH_PAD0_DAC_S - touch_num * 3))); + *slope = (touch_cnt_slope_t)((RTCCNTL.touch_dac.val >> (29 - touch_num * 3)) & 0x07); } else { - *slope = (touch_cnt_slope_t)(GET_PERI_REG_BITS2(RTC_CNTL_TOUCH_DAC1_REG, RTC_CNTL_TOUCH_PAD10_DAC_V, (RTC_CNTL_TOUCH_PAD10_DAC_S - (touch_num - TOUCH_PAD_NUM10) * 3))); + *slope = (touch_cnt_slope_t)((RTCCNTL.touch_dac1.val >> (29 - (touch_num - TOUCH_PAD_NUM10) * 3)) & 0x07); } } @@ -222,6 +229,7 @@ static inline void touch_ll_get_tie_option(touch_pad_t touch_num, touch_tie_opt_ * * @param mode FSM mode. */ +__attribute__((always_inline)) static inline void touch_ll_set_fsm_mode(touch_fsm_mode_t mode) { RTCCNTL.touch_ctrl2.touch_start_force = mode; @@ -288,6 +296,7 @@ static inline void touch_ll_start_fsm(void) * Stop touch sensor FSM timer. * The measurement action can be triggered by the hardware timer, as well as by the software instruction. */ +__attribute__((always_inline)) static inline void touch_ll_stop_fsm(void) { RTCCNTL.touch_ctrl2.touch_start_en = 0; //stop touch fsm @@ -424,7 +433,8 @@ static inline uint32_t IRAM_ATTR touch_ll_read_raw_data(touch_pad_t touch_num) * @return * - If touch sensors measure done. */ -static inline bool touch_ll_meas_is_done(void) +__attribute__((always_inline)) +static inline bool touch_ll_is_measure_done(void) { return (bool)SENS.sar_touch_chn_st.touch_meas_done; } @@ -572,25 +582,26 @@ static inline void touch_ll_intr_clear(touch_pad_intr_mask_t int_mask) */ static inline uint32_t touch_ll_read_intr_status_mask(void) { - uint32_t intr_st = RTCCNTL.int_st.val; + typeof(RTCCNTL.int_st) intr_st; + intr_st.val = RTCCNTL.int_st.val; uint32_t intr_msk = 0; - if (intr_st & RTC_CNTL_TOUCH_DONE_INT_ST_M) { + if (intr_st.rtc_touch_done) { intr_msk |= TOUCH_PAD_INTR_MASK_DONE; } - if (intr_st & RTC_CNTL_TOUCH_ACTIVE_INT_ST_M) { + if (intr_st.rtc_touch_active) { intr_msk |= TOUCH_PAD_INTR_MASK_ACTIVE; } - if (intr_st & RTC_CNTL_TOUCH_INACTIVE_INT_ST_M) { + if (intr_st.rtc_touch_inactive) { intr_msk |= TOUCH_PAD_INTR_MASK_INACTIVE; } - if (intr_st & RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M) { + if (intr_st.rtc_touch_scan_done) { intr_msk |= TOUCH_PAD_INTR_MASK_SCAN_DONE; } - if (intr_st & RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M) { + if (intr_st.rtc_touch_timeout) { intr_msk |= TOUCH_PAD_INTR_MASK_TIMEOUT; } - if (intr_st & RTC_CNTL_TOUCH_APPROACH_LOOP_DONE_INT_ST_M) { + if (intr_st.rtc_touch_approach_loop_done) { intr_msk |= TOUCH_PAD_INTR_MASK_PROXI_MEAS_DONE; } return (intr_msk & TOUCH_PAD_INTR_MASK_ALL); @@ -929,7 +940,7 @@ static inline void touch_ll_waterproof_get_guard_pad(touch_pad_t *pad_num) } /** - * Set max equivalent capacitance for sheild channel. + * Set max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -941,7 +952,7 @@ static inline void touch_ll_waterproof_set_sheild_driver(touch_pad_shield_driver } /** - * Get max equivalent capacitance for sheild channel. + * Get max equivalent capacitance for shield channel. * The equivalent capacitance of the shielded channel can be calculated * from the reading of denoise channel. * @@ -1104,7 +1115,7 @@ static inline void touch_ll_sleep_get_threshold(uint32_t *touch_thres) /** * Enable proximity function for sleep pad. */ -static inline void touch_ll_sleep_enable_approach(void) +static inline void touch_ll_sleep_enable_proximity_sensing(void) { RTCCNTL.touch_slp_thres.touch_slp_approach_en = 1; } @@ -1112,7 +1123,7 @@ static inline void touch_ll_sleep_enable_approach(void) /** * Disable proximity function for sleep pad. */ -static inline void touch_ll_sleep_disable_approach(void) +static inline void touch_ll_sleep_disable_proximity_sensing(void) { RTCCNTL.touch_slp_thres.touch_slp_approach_en = 0; } @@ -1120,7 +1131,7 @@ static inline void touch_ll_sleep_disable_approach(void) /** * Get proximity function status for sleep pad. */ -static inline bool touch_ll_sleep_get_approach_status(void) +static inline bool touch_ll_sleep_is_proximity_enabled(void) { return (bool)RTCCNTL.touch_slp_thres.touch_slp_approach_en; } @@ -1177,11 +1188,11 @@ static inline void touch_ll_sleep_read_debounce(uint32_t *debounce) /** * Read proximity count of touch sensor for sleep pad. - * @param proximity_cnt Pointer to accept touch sensor proximity count value. + * @param prox_cnt Pointer to accept touch sensor proximity count value. */ -static inline void touch_ll_sleep_read_proximity_cnt(uint32_t *approach_cnt) +static inline void touch_ll_sleep_read_proximity_cnt(uint32_t *prox_cnt) { - *approach_cnt = SENS.sar_touch_appr_status.touch_slp_approach_cnt; + *prox_cnt = SENS.sar_touch_appr_status.touch_slp_approach_cnt; } /** diff --git a/components/hal/esp32s3/touch_sensor_hal.c b/components/hal/esp32s3/touch_sensor_hal.c index 9b92bd2bc36..83dcc05cd56 100644 --- a/components/hal/esp32s3/touch_sensor_hal.c +++ b/components/hal/esp32s3/touch_sensor_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,7 +53,7 @@ void touch_hal_deinit(void) touch_pad_t prox_pad[SOC_TOUCH_PROXIMITY_CHANNEL_NUM] = {[0 ... (SOC_TOUCH_PROXIMITY_CHANNEL_NUM - 1)] = 0}; touch_ll_proximity_set_channel_num((const touch_pad_t *)prox_pad); touch_ll_sleep_set_channel_num(0); - touch_ll_sleep_disable_approach(); + touch_ll_sleep_disable_proximity_sensing(); touch_ll_reset(); // Reset the touch sensor FSM. } @@ -152,7 +152,7 @@ void touch_hal_sleep_channel_enable(touch_pad_t pad_num, bool enable) void touch_hal_sleep_channel_get_config(touch_pad_sleep_channel_t *slp_config) { touch_ll_sleep_get_channel_num(&slp_config->touch_num); - slp_config->en_proximity = touch_ll_sleep_get_approach_status(); + slp_config->en_proximity = touch_ll_sleep_is_proximity_enabled(); } void touch_hal_sleep_channel_set_work_time(uint16_t sleep_cycle, uint16_t meas_times) diff --git a/components/hal/include/hal/touch_sensor_hal.h b/components/hal/include/hal/touch_sensor_hal.h index 08da29daae2..be45ca89ab6 100644 --- a/components/hal/include/hal/touch_sensor_hal.h +++ b/components/hal/include/hal/touch_sensor_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -194,7 +194,7 @@ void touch_hal_get_meas_mode(touch_pad_t touch_num, touch_hal_meas_mode_t *meas) * @return * - If touch sensors measure done. */ -#define touch_hal_meas_is_done() touch_ll_meas_is_done() +#define touch_hal_meas_is_done() touch_ll_is_measure_done() /** * Initialize touch module. diff --git a/components/hal/include/hal/touch_sensor_types.h b/components/hal/include/hal/touch_sensor_types.h index 55291090cb6..dac11762f3e 100644 --- a/components/hal/include/hal/touch_sensor_types.h +++ b/components/hal/include/hal/touch_sensor_types.h @@ -275,7 +275,7 @@ typedef enum { TOUCH_PAD_SMOOTH_MAX, } touch_smooth_mode_t; -#if CONFIG_IDF_TARGET_ESP32P4 +#if SOC_TOUCH_SENSOR_VERSION == 3 /** * @brief Touch channel counting mode of the binarized touch output * @@ -283,9 +283,11 @@ typedef enum { typedef enum { TOUCH_PAD_OUT_AS_DATA, /*!< Counting the output of touch channel as data. * The value will be smaller than actual value but more sensitive when the frequency of touch_out is close to the source clock + * Normally we treat the output as data when it is lower than the sample clock */ TOUCH_PAD_OUT_AS_CLOCK, /*!< Counting the output of touch channel as clock. * The value is accurate but less sensitive when the frequency of touch_out is close to the source clock + * Normally we treat the output as clock when it is higher than the sample clock */ } touch_out_mode_t; #endif diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index a4c8168e8aa..ebe9974fb03 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -703,7 +703,7 @@ config SOC_TOUCH_SENSOR_NUM int default 10 -config SOC_TOUCH_SAMPLER_NUM +config SOC_TOUCH_SAMPLE_CFG_NUM int default 1 diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 97b1c6e9301..0519bc04c88 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -326,7 +326,7 @@ #define SOC_TOUCH_SENSOR_VERSION (1U) /*! Date: Fri, 7 Jun 2024 17:22:12 +0800 Subject: [PATCH 362/548] ci(touch): add test cases for cap touch sens driver --- .../test_apps/.build-test-rules.yml | 10 + .../test_apps/touch_sens/CMakeLists.txt | 22 ++ .../test_apps/touch_sens/README.md | 3 + .../test_apps/touch_sens/main/CMakeLists.txt | 6 + .../test_apps/touch_sens/main/test_app_main.c | 53 +++++ .../touch_sens/main/test_touch_sens_common.c | 198 ++++++++++++++++++ .../test_apps/touch_sens/pytest_touch_sens.py | 19 ++ .../touch_sens/sdkconfig.ci.iram_safe | 7 + .../test_apps/touch_sens/sdkconfig.ci.release | 5 + .../test_apps/touch_sens/sdkconfig.defaults | 2 + 10 files changed, 325 insertions(+) create mode 100644 components/esp_driver_touch_sens/test_apps/.build-test-rules.yml create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/README.md create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release create mode 100644 components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults diff --git a/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml new file mode 100644 index 00000000000..ff1dc3e64ca --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml @@ -0,0 +1,10 @@ +components/esp_driver_touch_sens/test_apps/touch_sens: + disable: + - if: SOC_TOUCH_SENSOR_VERSION != 3 + temporary: currently driver ng only support version 3 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: the runners do not support the pins for touch sensor + depends_components: + - esp_driver_touch_sens diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt b/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt new file mode 100644 index 00000000000..e774828c4d6 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt @@ -0,0 +1,22 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(COMPONENTS main) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(touch_sens) + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target(check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_driver_touch_sens/,${CMAKE_BINARY_DIR}/esp-idf/hal/ + --elf-file ${CMAKE_BINARY_DIR}/touch_sens.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/README.md b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md new file mode 100644 index 00000000000..f8ea707124d --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md @@ -0,0 +1,3 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt new file mode 100644 index 00000000000..97285a11223 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(srcs "test_app_main.c" "test_touch_sens_common.c") + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES unity esp_driver_touch_sens + WHOLE_ARCHIVE) diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c new file mode 100644 index 00000000000..a7498bd1eb3 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in Touch Sensor driver, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-300) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + // _____ _ ____ _____ _ + // |_ _|__ _ _ ___| |__ / ___| ___ _ __ ___ ___ _ __ |_ _|__ ___| |_ + // | |/ _ \| | | |/ __| '_ \ \___ \ / _ \ '_ \/ __|/ _ \| '__| | |/ _ \/ __| __| + // | | (_) | |_| | (__| | | | ___) | __/ | | \__ \ (_) | | | | __/\__ \ |_ + // |_|\___/ \__,_|\___|_| |_| |____/ \___|_| |_|___/\___/|_| |_|\___||___/\__| + + printf(" _____ _ ____ _____ _ \n"); + printf(" |_ _|__ _ _ ___| |__ / ___| ___ _ __ ___ ___ _ __ |_ _|__ ___| |_ \n"); + printf(" | |/ _ \\| | | |/ __| '_ \\ \\___ \\ / _ \\ '_ \\/ __|/ _ \\| '__| | |/ _ \\/ __| __|\n"); + printf(" | | (_) | |_| | (__| | | | ___) | __/ | | \\__ \\ (_) | | | | __/\\__ \\ |_ \n"); + printf(" |_|\\___/ \\__,_|\\___|_| |_| |____/ \\___|_| |_|___/\\___/|_| |_|\\___||___/\\__|\n"); + + unity_run_menu(); +} diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c new file mode 100644 index 00000000000..8dda1d8d6a7 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "driver/touch_sens.h" +#include "hal/touch_sensor_ll.h" +#include "esp_log.h" +#include "esp_attr.h" + +static touch_sensor_sample_config_t s_sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), +#if TOUCH_SAMPLE_CFG_NUM > 1 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1(), +#endif +#if TOUCH_SAMPLE_CFG_NUM > 2 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2(), +#endif +}; + +static touch_channel_config_t s_chan_cfg = { + .active_thresh = { + 5000, +#if TOUCH_SAMPLE_CFG_NUM > 1 + 2500, +#endif +#if TOUCH_SAMPLE_CFG_NUM > 2 + 1000, +#endif + }, +}; + +TEST_CASE("touch_sens_install_uninstall_test", "[touch]") +{ + touch_sensor_handle_t touch = NULL; + touch_channel_handle_t touch_chan[TOUCH_TOTAL_CHAN_NUM] = {NULL}; + + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(TOUCH_SAMPLE_CFG_NUM, s_sample_cfg); + /* Allocate new controller */ + TEST_ESP_OK(touch_sensor_new_controller(&sens_cfg, &touch)); + TEST_ASSERT(touch_sensor_new_controller(&sens_cfg, &touch) == ESP_ERR_INVALID_STATE); + /* Configuring the filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + TEST_ESP_OK(touch_sensor_config_filter(touch, &filter_cfg)); + + for (int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + TEST_ESP_OK(touch_sensor_new_channel(touch, i, &s_chan_cfg, &touch_chan[i])); + } + touch_channel_handle_t fault_chan = NULL; + TEST_ASSERT(touch_sensor_new_channel(touch, TOUCH_TOTAL_CHAN_NUM, &s_chan_cfg, &fault_chan) == ESP_ERR_INVALID_ARG); + TEST_ASSERT(touch_sensor_new_channel(touch, 0, &s_chan_cfg, &fault_chan) == ESP_ERR_INVALID_STATE); + + TEST_ESP_OK(touch_sensor_enable(touch)); + TEST_ASSERT(touch_sensor_del_channel(touch_chan[0]) == ESP_ERR_INVALID_STATE); + TEST_ESP_OK(touch_sensor_disable(touch)); + + TEST_ASSERT(touch_sensor_del_controller(touch) == ESP_ERR_INVALID_STATE); + + for (int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + TEST_ESP_OK(touch_sensor_del_channel(touch_chan[i])); + } + TEST_ESP_OK(touch_sensor_del_controller(touch)); +} + +typedef struct { + int active_count; + int inactive_count; +} test_touch_cb_data_t; + +static touch_channel_config_t s_test_get_chan_cfg_by_benchmark(uint32_t benchmark[], uint32_t num, float coeff) +{ + touch_channel_config_t chan_cfg = {}; + for (int i = 0; i < num; i++) { + chan_cfg.active_thresh[i] = benchmark[i] * coeff; + printf("[Sampler %d] benchmark %5"PRIu32" thresh %4"PRIu32"\n", + i, benchmark[i], chan_cfg.active_thresh[i]); + } + return chan_cfg; +} + +static void s_test_touch_do_initial_scanning(touch_sensor_handle_t touch, int scan_times) +{ + /* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */ + TEST_ESP_OK(touch_sensor_enable(touch)); + /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */ + for (int i = 0; i < scan_times; i++) { + TEST_ESP_OK(touch_sensor_trigger_oneshot_scanning(touch, 2000)); + } + /* Disable the touch channel to rollback the state */ + TEST_ESP_OK(touch_sensor_disable(touch)); +} + +#if CONFIG_TOUCH_ISR_IRAM_SAFE +#define TEST_TCH_IRAM_ATTR IRAM_ATTR +#else +#define TEST_TCH_IRAM_ATTR +#endif + +static bool TEST_TCH_IRAM_ATTR s_test_touch_on_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] active", (int)event->chan_id); + test_touch_cb_data_t *cb_data = (test_touch_cb_data_t *)user_ctx; + cb_data->active_count++; + return false; +} + +static bool TEST_TCH_IRAM_ATTR s_test_touch_on_inactive_callback(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] inactive", (int)event->chan_id); + test_touch_cb_data_t *cb_data = (test_touch_cb_data_t *)user_ctx; + cb_data->inactive_count++; + return false; +} + +static void s_test_touch_simulate_touch(touch_sensor_handle_t touch, touch_channel_handle_t touch_chan, bool active) +{ + touch_ll_set_internal_capacitor(active ? 0x7f : 0); +} + +static void s_test_touch_log_data(touch_channel_handle_t touch_chan, uint32_t sample_cfg_num, const char *tag) +{ + uint32_t data[sample_cfg_num]; + TEST_ESP_OK(touch_channel_read_data(touch_chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, data)); + printf("%s:", tag); + for (int i = 0; i < sample_cfg_num; i++) { + printf(" %"PRIu32, data[i]); + } + printf("\n"); +} + +#define TEST_ACTIVE_THRESH_RATIO (0.01f) + +TEST_CASE("touch_sens_active_inactive_test", "[touch]") +{ + touch_sensor_handle_t touch = NULL; + touch_channel_handle_t touch_chan = NULL; + + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(TOUCH_SAMPLE_CFG_NUM, s_sample_cfg); + TEST_ESP_OK(touch_sensor_new_controller(&sens_cfg, &touch)); + + /* Configuring the filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + TEST_ESP_OK(touch_sensor_config_filter(touch, &filter_cfg)); + TEST_ESP_OK(touch_sensor_new_channel(touch, 0, &s_chan_cfg, &touch_chan)); + /* Connect the touch channels to the internal capacitor */ + touch_ll_enable_internal_capacitor(true); + + s_test_touch_do_initial_scanning(touch, 3); + + /* Read benchmark */ + uint32_t benchmark[TOUCH_SAMPLE_CFG_NUM] = {0}; + TEST_ESP_OK(touch_channel_read_data(touch_chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + /* Re-configure the threshold according to the benchmark */ + touch_channel_config_t chan_cfg = s_test_get_chan_cfg_by_benchmark(benchmark, TOUCH_SAMPLE_CFG_NUM, TEST_ACTIVE_THRESH_RATIO); + TEST_ESP_OK(touch_sensor_reconfig_channel(touch_chan, &chan_cfg)); + + touch_event_callbacks_t callbacks = { + .on_active = s_test_touch_on_active_callback, + .on_inactive = s_test_touch_on_inactive_callback, + }; + test_touch_cb_data_t cb_data = {}; + TEST_ESP_OK(touch_sensor_register_callbacks(touch, &callbacks, &cb_data)); + + TEST_ESP_OK(touch_sensor_enable(touch)); + TEST_ESP_OK(touch_sensor_start_continuous_scanning(touch)); + vTaskDelay(pdMS_TO_TICKS(20)); + + int touch_cnt = 3; + for (int i = 0; i < touch_cnt; i++) { + printf("\nSimulate Touch [%d] ->\n--------------------------\n", i + 1); + // Read data before touched + s_test_touch_log_data(touch_chan, TOUCH_SAMPLE_CFG_NUM, "Data Before"); + // Simulate touch + s_test_touch_simulate_touch(touch, touch_chan, true); + vTaskDelay(pdMS_TO_TICKS(50)); + + // Read data after touched + s_test_touch_log_data(touch_chan, TOUCH_SAMPLE_CFG_NUM, "Data After "); + // Simulate release + s_test_touch_simulate_touch(touch, touch_chan, false); + vTaskDelay(pdMS_TO_TICKS(50)); + } + printf("\n"); + + TEST_ESP_OK(touch_sensor_stop_continuous_scanning(touch)); + TEST_ESP_OK(touch_sensor_disable(touch)); + TEST_ESP_OK(touch_sensor_del_channel(touch_chan)); + TEST_ESP_OK(touch_sensor_del_controller(touch)); + + /* Check the callback count */ + TEST_ASSERT_EQUAL_INT32(touch_cnt, cb_data.active_count); + TEST_ASSERT_EQUAL_INT32(touch_cnt, cb_data.inactive_count); +} diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py new file mode 100644 index 00000000000..871cdb6baf0 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 runners do not support touch pins') +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'release', + 'iram_safe', + ], + indirect=True, +) +def test_touch_sens(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe new file mode 100644 index 00000000000..e8074e7fa86 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe @@ -0,0 +1,7 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_TOUCH_CTRL_FUNC_IN_IRAM=y +CONFIG_TOUCH_ISR_IRAM_SAFE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +# silent the error check, as the error string are stored in rodata, causing RTL check failure +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release new file mode 100644 index 00000000000..91d93f163e6 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults new file mode 100644 index 00000000000..b308cb2ddda --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n From 82cba6e3fffd18e055930dde495597ad45ef2ffc Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 Jun 2024 17:25:35 +0800 Subject: [PATCH 363/548] feat(touch_sens): add example for the touch sensor v3 --- examples/peripherals/.build-test-rules.yml | 10 ++ .../touch_sensor_v3/CMakeLists.txt | 6 + .../touch_sensor/touch_sensor_v3/README.md | 125 +++++++++++++ .../touch_sensor_v3/main/CMakeLists.txt | 3 + .../main/touch_sens_v3_example_main.c | 169 ++++++++++++++++++ .../touch_sensor_v3/pytest_touch_sens_v3.py | 14 ++ .../system/deep_sleep/main/touch_wakeup.c | 4 +- .../system/light_sleep/main/CMakeLists.txt | 4 + .../light_sleep/main/light_sleep_example.h | 9 +- .../main/light_sleep_example_main.c | 4 +- .../light_sleep/main/touch_sens_wakeup.c | 107 +++++++++++ 11 files changed, 450 insertions(+), 5 deletions(-) create mode 100644 examples/peripherals/touch_sensor/touch_sensor_v3/CMakeLists.txt create mode 100644 examples/peripherals/touch_sensor/touch_sensor_v3/README.md create mode 100644 examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt create mode 100644 examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c create mode 100644 examples/peripherals/touch_sensor/touch_sensor_v3/pytest_touch_sens_v3.py create mode 100644 examples/system/light_sleep/main/touch_sens_wakeup.c diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index b6d05fd2151..e99615502ae 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -433,6 +433,16 @@ examples/peripherals/touch_sensor/touch_sensor_v2: disable: - if: SOC_TOUCH_SENSOR_VERSION != 2 +examples/peripherals/touch_sensor/touch_sensor_v3: + disable: + - if: SOC_TOUCH_SENSOR_VERSION != 3 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: the runners do not support the pins for touch sensor + depends_components: + - esp_driver_touch_sens + examples/peripherals/twai/twai_alert_and_recovery: disable: - if: SOC_TWAI_SUPPORTED != 1 diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/CMakeLists.txt b/examples/peripherals/touch_sensor/touch_sensor_v3/CMakeLists.txt new file mode 100644 index 00000000000..dc484f27e81 --- /dev/null +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(touch_sens_example) diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/README.md b/examples/peripherals/touch_sensor/touch_sensor_v3/README.md new file mode 100644 index 00000000000..650d3a24a66 --- /dev/null +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/README.md @@ -0,0 +1,125 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + +# Capacity Touch Sensor Example (for hardware version 3) + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example is going to demonstrate how to register the touch channels and read the data. + +## How to Use Example + +### Hardware Required + +* A development board with any supported Espressif SOC chip (see `Supported Targets` table above) +* A USB cable for power supply and programming +* (Optional) Touch board with touch buttons on it. + - If you don't have a touch board, you can connect the touch pins with male jump wires and touch it directly for testing. + +### Configure the Project + +You can determine the touch channel number by ``EXAMPLE_TOUCH_CHANNEL_NUM`` in the example. And adjust the active threshold by ``s_thresh2bm_ratio``. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT build flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +You can see the following output in the monitor if the example runs successfully: + +``` +W (461) touch: [sample_cfg_id 0] clock precision loss, expect 4000000 hz, got 4006725 hz +W (461) touch: [sample_cfg_id 1] clock precision loss, expect 8000000 hz, got 8013450 hz +W (461) touch: [sample_cfg_id 2] clock precision loss, expect 16000000 hz, got 16026900 hz +Initial benchmark and new threshold are: +[CH 0] 0: 4114, 411 1: 2057, 205 2: 1028, 102 +[CH 1] 0: 4643, 464 1: 2322, 232 2: 1160, 116 +[CH 2] 0: 4848, 484 1: 2424, 242 2: 1211, 121 +[CH 3] 0: 4340, 434 1: 2170, 217 2: 1085, 108 +================================= +benchmark [CH 0]: 4115 2056 1028 +chan_data [CH 0]: 4115 2056 1028 + +benchmark [CH 1]: 4644 2322 1160 +chan_data [CH 1]: 4644 2322 1160 + +benchmark [CH 2]: 4848 2423 1211 +chan_data [CH 2]: 4848 2423 1211 + +benchmark [CH 3]: 4337 2168 1084 +chan_data [CH 3]: 4337 2168 1084 + +================================= +benchmark [CH 0]: 4109 2054 1027 +chan_data [CH 0]: 4109 2054 1027 + +benchmark [CH 1]: 4638 2318 1158 +chan_data [CH 1]: 4638 2318 1158 + +benchmark [CH 2]: 4843 2421 1210 +chan_data [CH 2]: 4845 2421 1210 + +benchmark [CH 3]: 4334 2167 1084 +chan_data [CH 3]: 4334 2167 1083 +... +``` + +And if you touch and release a button, you will see the following output: + +``` +... +I (1321) touch_callback: [CH 1] active +================================= +benchmark [CH 0]: 4111 2055 1027 +chan_data [CH 0]: 4111 2055 1027 + +benchmark [CH 1]: 4676 2339 1168 +chan_data [CH 1]: 17701 8798 4399 + +benchmark [CH 2]: 4870 2434 1217 +chan_data [CH 2]: 4867 2433 1217 + +benchmark [CH 3]: 4333 2165 1082 +chan_data [CH 3]: 4333 2165 1082 + +================================= +benchmark [CH 0]: 4109 2053 1027 +chan_data [CH 0]: 4108 2053 1027 + +benchmark [CH 1]: 4676 2339 1168 +chan_data [CH 1]: 11256 8817 4363 + +benchmark [CH 2]: 4868 2434 1217 +chan_data [CH 2]: 4862 2429 1214 + +benchmark [CH 3]: 4332 2165 1082 +chan_data [CH 3]: 4330 2164 1081 + +I (1931) touch_callback: [CH 1] inactive +================================= +benchmark [CH 0]: 4106 2052 1026 +chan_data [CH 0]: 4106 2052 1026 + +benchmark [CH 1]: 4649 2323 1161 +chan_data [CH 1]: 4650 2323 1161 + +benchmark [CH 2]: 4847 2422 1211 +chan_data [CH 2]: 4846 2422 1211 + +benchmark [CH 3]: 4329 2163 1082 +chan_data [CH 3]: 4329 2164 1082 +... +``` + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt b/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt new file mode 100644 index 00000000000..b88a846c5aa --- /dev/null +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "touch_sens_v3_example_main.c" + PRIV_REQUIRES esp_driver_touch_sens + INCLUDE_DIRS ".") diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c b/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c new file mode 100644 index 00000000000..4eeb1c91bc8 --- /dev/null +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/touch_sens.h" +#include "soc/lp_analog_peri_struct.h" +#include "esp_check.h" + +// Touch version 3 supports multiple sample configurations +#define EXAMPLE_TOUCH_SAMPLE_CFG_NUM TOUCH_SAMPLE_CFG_NUM +#define EXAMPLE_TOUCH_CHANNEL_NUM 4 +#define EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES 3 + +static touch_sensor_handle_t s_sens_handle = NULL; +static touch_channel_handle_t s_chan_handle[EXAMPLE_TOUCH_CHANNEL_NUM] = {}; +// Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio)) +static float s_thresh2bm_ratio[EXAMPLE_TOUCH_CHANNEL_NUM] = { + [0 ... EXAMPLE_TOUCH_CHANNEL_NUM - 1] = 0.02f, // 2% +}; + +bool example_touch_on_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] active", (int)event->chan_id); + return false; +} + +bool example_touch_on_inactive_callback(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] inactive", (int)event->chan_id); + return false; +} + +static void example_touch_do_initial_scanning(void) +{ + /* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */ + ESP_ERROR_CHECK(touch_sensor_enable(s_sens_handle)); + + /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */ + for (int i = 0; i < EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES; i++) { + ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(s_sens_handle, 2000)); + } + + /* Disable the touch channel to rollback the state */ + ESP_ERROR_CHECK(touch_sensor_disable(s_sens_handle)); + + /* (Optional) Read the initial channel benchmark and reconfig the channel active threshold accordingly */ + printf("Initial benchmark and new threshold are:\n"); + for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) { + /* Read the initial benchmark of the touch channel */ + uint32_t benchmark[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {}; + ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + /* Calculate the proper active thresholds regarding the initial benchmark */ + printf("[CH %d]", i); + touch_channel_config_t chan_cfg = {}; + for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) { + chan_cfg.active_thresh[j] = (uint32_t)(benchmark[j] * s_thresh2bm_ratio[j]); + printf(" %d: %"PRIu32", %"PRIu32"\t", j, benchmark[j], chan_cfg.active_thresh[j]); + } + printf("\n"); + /* Update the channel configuration */ + ESP_ERROR_CHECK(touch_sensor_reconfig_channel(s_chan_handle[i], &chan_cfg)); + } +} + +void app_main(void) +{ + /* Use the default sample configurations */ + touch_sensor_sample_config_t sample_cfg[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = { + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), +#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1(), +#endif +#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2(), +#endif + }; + /* Allocate new touch controller handle */ + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(EXAMPLE_TOUCH_SAMPLE_CFG_NUM, sample_cfg); + ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &s_sens_handle)); + + /* Configure the touch sensor filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + ESP_ERROR_CHECK(touch_sensor_config_filter(s_sens_handle, &filter_cfg)); + + /* Allocate new touch channel on the touch controller */ + touch_channel_config_t chan_cfg = { + /** Set the touch channel active threshold of each sample configuration. + * + * @How to Determine: + * As the actual threshold is affected by various factors in real application, + * we need to run the touch app first to get the `benchmark` and the `smooth_data` that being touched. + * + * @Formula: + * threshold = benchmark * coeff, (coeff for example, 0.1%~20%) + * Please adjust the coeff to guarantee the threshold < smooth_data - benchmark + * + * @Typical Practice: + * Normally, we can't determine a fixed threshold at the beginning, + * but we can give them estimated values first and update them after an initial scanning (like this example), + * Step1: set an estimated value for each sample configuration first. (i.e., here) + * Step2: then reconfig the threshold after the initial scanning.(see `example_touch_do_initial_scanning`) + * Step3: adjust the `s_thresh2bm_ratio` to a proper value to trigger the active callback + */ + .active_thresh = { + 5000, // estimated active threshold of sample configuration 0 +#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1 + 2500, // estimated active threshold of sample configuration 1 +#endif +#if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2 + 1000, // estimated active threshold of sample configuration 2 +#endif + }, + }; + for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) { + ESP_ERROR_CHECK(touch_sensor_new_channel(s_sens_handle, i, &chan_cfg, &s_chan_handle[i])); + } + + /* Do the initial scanning to initialize the touch channel data + * Without this step, the channel data in the first read will be invalid + */ + example_touch_do_initial_scanning(); + + /* Register the touch sensor callbacks, here only take `active` and `deactivate` event for example */ + touch_event_callbacks_t callbacks = { + .on_active = example_touch_on_active_callback, + .on_inactive = example_touch_on_inactive_callback, + .on_measure_done = NULL, + .on_scan_done = NULL, + .on_timeout = NULL, + .on_proximity_meas_done = NULL, + }; + ESP_ERROR_CHECK(touch_sensor_register_callbacks(s_sens_handle, &callbacks, NULL)); + + /* Enable the touch sensor */ + ESP_ERROR_CHECK(touch_sensor_enable(s_sens_handle)); + + /* Start continuous scanning, you can also trigger oneshot scanning manually */ + ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(s_sens_handle)); + + uint32_t benchmark[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {}; + uint32_t chan_data[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {}; + while (1) { + printf("=================================\n"); + for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) { + /* Read and print the benchmark of each sample configuration */ + ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + printf("benchmark [CH %d]:", i); + for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) { + printf(" %"PRIu32, benchmark[j]); + } + printf("\n"); + /* Read and print the channel data of each sample configuration */ + ESP_ERROR_CHECK(touch_channel_read_data(s_chan_handle[i], TOUCH_CHAN_DATA_TYPE_SMOOTH, chan_data)); + printf("chan_data [CH %d]:", i); + for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) { + printf(" %"PRIu32, chan_data[j]); + } + printf("\n\n"); + } + /* Read and display the data every 300 ms */ + vTaskDelay(pdMS_TO_TICKS(300)); + } +} diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/pytest_touch_sens_v3.py b/examples/peripherals/touch_sensor/touch_sensor_v3/pytest_touch_sens_v3.py new file mode 100644 index 00000000000..f03c56c2ffd --- /dev/null +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/pytest_touch_sens_v3.py @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 runners do not support touch pins') +@pytest.mark.generic +def test_touch_sens_v3(dut: Dut) -> None: + dut.expect_exact('Initial benchmark and new threshold are:') + dut.expect(r'\[CH [0-9]+\] 0: [0-9]+, [0-9]+') + dut.expect(r'benchmark \[CH [0-9]+\]: [0-9]+') + dut.expect(r'chan_data \[CH [0-9]+\]: [0-9]+') diff --git a/examples/system/deep_sleep/main/touch_wakeup.c b/examples/system/deep_sleep/main/touch_wakeup.c index c2dd41daf88..13d4ff64d4d 100644 --- a/examples/system/deep_sleep/main/touch_wakeup.c +++ b/examples/system/deep_sleep/main/touch_wakeup.c @@ -50,7 +50,7 @@ void example_deep_sleep_register_touch_wakeup(void) // If use touch pad wake up, should set touch sensor FSM mode at 'TOUCH_FSM_MODE_TIMER'. touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); // Set reference voltage for charging/discharging - // In this case, the high reference valtage will be 2.4V - 1V = 1.4V + // In this case, the high reference voltage will be 2.4V - 1V = 1.4V // The low reference voltage will be 0.5 // The larger the range, the larger the pulse count value. touch_pad_set_voltage(TOUCH_HVOLT_2V4, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V); @@ -104,6 +104,8 @@ void example_deep_sleep_register_touch_wakeup(void) #endif printf("Enabling touch pad wakeup\n"); ESP_ERROR_CHECK(esp_sleep_enable_touchpad_wakeup()); +#if SOC_PM_SUPPORT_RTC_PERIPH_PD ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON)); +#endif } #endif // CONFIG_EXAMPLE_TOUCH_WAKEUP diff --git a/examples/system/light_sleep/main/CMakeLists.txt b/examples/system/light_sleep/main/CMakeLists.txt index 25d2112b95f..f36ab83fd89 100644 --- a/examples/system/light_sleep/main/CMakeLists.txt +++ b/examples/system/light_sleep/main/CMakeLists.txt @@ -9,5 +9,9 @@ if(IDF_TARGET IN_LIST TOUCH_ELEMENT_COMPATIBLE_TARGETS) list(APPEND srcs "touch_wakeup.c") endif() +if(IDF_TARGET STREQUAL "esp32p4") + list(APPEND srcs "touch_sens_wakeup.c") +endif() + idf_component_register(SRCS ${srcs} INCLUDE_DIRS ".") diff --git a/examples/system/light_sleep/main/light_sleep_example.h b/examples/system/light_sleep/main/light_sleep_example.h index c3401c4aed8..cb62682502c 100644 --- a/examples/system/light_sleep/main/light_sleep_example.h +++ b/examples/system/light_sleep/main/light_sleep_example.h @@ -1,15 +1,20 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #pragma once +#include "sdkconfig.h" + #ifdef __cplusplus extern "C" { #endif +// TODO: [ESP32P4] add P4 when runner is ready +#define EXAMPLE_TOUCH_LSLEEP_WAKEUP_SUPPORT (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) + void example_wait_gpio_inactive(void); esp_err_t example_register_gpio_wakeup(void); @@ -18,7 +23,7 @@ esp_err_t example_register_timer_wakeup(void); esp_err_t example_register_uart_wakeup(void); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if EXAMPLE_TOUCH_LSLEEP_WAKEUP_SUPPORT void example_register_touch_wakeup(void); #endif diff --git a/examples/system/light_sleep/main/light_sleep_example_main.c b/examples/system/light_sleep/main/light_sleep_example_main.c index 8791d4de6eb..989cfea24bd 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -50,7 +50,7 @@ static void light_sleep_task(void *args) * Otherwise the chip may fall sleep again before running uart task */ vTaskDelay(1); break; -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if EXAMPLE_TOUCH_LSLEEP_WAKEUP_SUPPORT case ESP_SLEEP_WAKEUP_TOUCHPAD: wakeup_reason = "touch"; break; @@ -83,7 +83,7 @@ void app_main(void) example_register_timer_wakeup(); /* Enable wakeup from light sleep by uart */ example_register_uart_wakeup(); -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +#if EXAMPLE_TOUCH_LSLEEP_WAKEUP_SUPPORT /* Enable wakeup from light sleep by touch element */ example_register_touch_wakeup(); #endif diff --git a/examples/system/light_sleep/main/touch_sens_wakeup.c b/examples/system/light_sleep/main/touch_sens_wakeup.c new file mode 100644 index 00000000000..fbf6c6fcc54 --- /dev/null +++ b/examples/system/light_sleep/main/touch_sens_wakeup.c @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "freertos/FreeRTOS.h" +#include "esp_log.h" +#include "driver/touch_sens.h" + +static const char *TAG = "touch_wakeup"; + +#define EXAMPLE_TOUCH_SAMPLE_CFG_NUM 1 +#define EXAMPLE_TOUCH_CHANNEL_NUM 5 +#define EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES 3 + +// Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio)) +static float s_thresh2bm_ratio[EXAMPLE_TOUCH_CHANNEL_NUM] = { + [0 ... EXAMPLE_TOUCH_CHANNEL_NUM - 1] = 0.02f, // 2% +}; + +static bool example_touch_on_active_cb(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGW("isr", "ch %d active", (int)event->chan_id); + return false; +} + +static bool example_touch_on_inactive_cb(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGW("isr", "ch %d inactive", (int)event->chan_id); + return false; +} + +static void example_touch_do_initial_scanning(touch_sensor_handle_t sens_handle, touch_channel_handle_t chan_handle[]) +{ + /* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */ + ESP_ERROR_CHECK(touch_sensor_enable(sens_handle)); + + /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */ + for (int i = 0; i < EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES; i++) { + ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 2000)); + } + + /* Disable the touch channel to rollback the state */ + ESP_ERROR_CHECK(touch_sensor_disable(sens_handle)); + + /* (Optional) Read the initial channel benchmark and reconfig the channel active threshold accordingly */ + printf("Initial benchmark and new threshold are:\n"); + for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) { + /* Read the initial benchmark of the touch channel */ + uint32_t benchmark[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = {}; + ESP_ERROR_CHECK(touch_channel_read_data(chan_handle[i], TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + /* Calculate the proper active thresholds regarding the initial benchmark */ + printf("[CH %d]", i); + touch_channel_config_t chan_cfg = {}; + for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) { + chan_cfg.active_thresh[j] = (uint32_t)(benchmark[j] * s_thresh2bm_ratio[j]); + printf(" %d: %"PRIu32", %"PRIu32"\t", j, benchmark[j], chan_cfg.active_thresh[j]); + } + printf("\n"); + /* Update the channel configuration */ + ESP_ERROR_CHECK(touch_sensor_reconfig_channel(chan_handle[i], &chan_cfg)); + } +} + +esp_err_t example_register_touch_wakeup(void) +{ + touch_sensor_handle_t sens_handle = NULL; + touch_sensor_sample_config_t sample_cfg[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = { + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), + }; + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(EXAMPLE_TOUCH_SAMPLE_CFG_NUM, sample_cfg); + ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &sens_handle)); + + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, &filter_cfg)); + + touch_channel_handle_t chan_handle[EXAMPLE_TOUCH_CHANNEL_NUM]; + touch_channel_config_t chan_cfg = { + .active_thresh = {5000}, // Initial threshold + + }; + for (int i = 0; i < EXAMPLE_TOUCH_CHANNEL_NUM; i++) { + ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, i, &chan_cfg, &chan_handle[i])); + } + + /* (Optional) Do the initial scanning to initialize the touch channel data + * Without this step, the channel data in the first read will be invalid + */ + example_touch_do_initial_scanning(sens_handle, chan_handle); + + touch_event_callbacks_t callbacks = { + .on_active = example_touch_on_active_cb, + .on_inactive = example_touch_on_inactive_cb, + }; + ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens_handle, &callbacks, NULL)); + + touch_sleep_config_t light_slp_cfg = { + .slp_wakeup_lvl = TOUCH_LIGHT_SLEEP_WAKEUP, + }; + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, &light_slp_cfg)); + + ESP_ERROR_CHECK(touch_sensor_enable(sens_handle)); + ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens_handle)); + + ESP_LOGI(TAG, "touch wakeup source is ready"); + return ESP_OK; +} From e6103c521a74f2647a807269bce0a17713c544dc Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 Jun 2024 17:26:31 +0800 Subject: [PATCH 364/548] docs(touch): add doc for cap touch sens driver --- .../common/touch_sens_common.c | 6 +- .../common/touch_sens_private.h | 9 +- .../include/driver/touch_version_types.h | 70 +-- .../hw_ver3/touch_version_specific.c | 52 +-- .../include/driver/touch_sens.h | 10 +- ...ouch_common_types.h => touch_sens_types.h} | 0 components/esp_driver_touch_sens/linker.lf | 4 +- .../touch_sens/main/test_touch_sens_common.c | 6 +- .../include/esp_private/esp_pmu.h | 1 + components/hal/esp32p4/touch_sensor_hal.c | 2 +- .../cap_touch_sens/touch_file_structure.svg | 4 + .../cap_touch_sens/touch_state_machine.svg | 4 + docs/conf_common.py | 7 +- docs/doxygen/Doxyfile_esp32p4 | 3 + .../peripherals/cap_touch_sens.rst | 416 ++++++++++++++++++ docs/en/api-reference/peripherals/index.rst | 3 +- .../peripherals/cap_touch_sens.rst | 415 +++++++++++++++++ .../zh_CN/api-reference/peripherals/index.rst | 3 +- .../{touch_periph_version.txt => README.md} | 0 .../touch_sensor_v3/main/CMakeLists.txt | 2 +- .../main/touch_sens_v3_example_main.c | 17 +- .../light_sleep/main/touch_sens_wakeup.c | 2 +- 22 files changed, 914 insertions(+), 122 deletions(-) rename components/esp_driver_touch_sens/include/driver/{touch_common_types.h => touch_sens_types.h} (100%) create mode 100644 docs/_static/diagrams/cap_touch_sens/touch_file_structure.svg create mode 100644 docs/_static/diagrams/cap_touch_sens/touch_state_machine.svg create mode 100644 docs/en/api-reference/peripherals/cap_touch_sens.rst create mode 100644 docs/zh_CN/api-reference/peripherals/cap_touch_sens.rst rename examples/peripherals/touch_sensor/{touch_periph_version.txt => README.md} (100%) diff --git a/components/esp_driver_touch_sens/common/touch_sens_common.c b/components/esp_driver_touch_sens/common/touch_sens_common.c index 0d647bf072f..f5119c72372 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_common.c +++ b/components/esp_driver_touch_sens/common/touch_sens_common.c @@ -419,10 +419,10 @@ esp_err_t touch_channel_read_data(touch_channel_handle_t chan_handle, touch_chan return touch_priv_channel_read_data(chan_handle, type, data); } -esp_err_t touch_sensor_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op) +esp_err_t touch_channel_config_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_config_t *benchmark_cfg) { TOUCH_NULL_POINTER_CHECK_ISR(chan_handle); - TOUCH_NULL_POINTER_CHECK_ISR(benchmark_op); - touch_priv_set_benchmark(chan_handle, benchmark_op); + TOUCH_NULL_POINTER_CHECK_ISR(benchmark_cfg); + touch_priv_config_benchmark(chan_handle, benchmark_cfg); return ESP_OK; } diff --git a/components/esp_driver_touch_sens/common/touch_sens_private.h b/components/esp_driver_touch_sens/common/touch_sens_private.h index 3eac7d4a9c4..325acb775e5 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_private.h +++ b/components/esp_driver_touch_sens/common/touch_sens_private.h @@ -15,7 +15,7 @@ #include "freertos/semphr.h" #include "soc/soc_caps.h" #include "hal/touch_sensor_hal.h" -#include "driver/touch_common_types.h" +#include "driver/touch_sens_types.h" #include "esp_memory_utils.h" #include "esp_check.h" #include "sdkconfig.h" @@ -31,7 +31,7 @@ extern "C" { #define TOUCH_IRAM_CHECK(cb) (!(cb) || esp_ptr_in_iram(cb)) /* IRAM safe caps */ -#if CONFIG_TOUCH_ISR_IRAM_SAFE +#if CONFIG_TOUCH_ISR_IRAM_SAFE || CONFIG_TOUCH_CTRL_FUNC_IN_IRAM #define TOUCH_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED) #define TOUCH_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else @@ -82,6 +82,7 @@ struct touch_sensor_s { bool is_meas_timeout; /*!< Flag to indicate whether the measurement timeout, will force to stop the current measurement if the timeout is triggered */ bool sleep_en; /*!< Flag to indicate whether the sleep wake-up feature is enabled */ bool waterproof_en; /*!< Flag to indicate whether the water proof feature is enabled */ + bool immersion_proof; /*!< Flag to indicate whether to disable scanning when the guard ring is triggered */ bool proximity_en; /*!< Flag to indicate whether the proximity sensing feature is enabled */ bool timeout_en; /*!< Flag to indicate whether the measurement timeout feature (hardware timeout) is enabled */ }; @@ -182,9 +183,9 @@ esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch * It should be implemented by each hardware version * * @param[in] chan_handle The channel handle - * @param[in] benchmark_op The benchmark operation + * @param[in] benchmark_cfg The benchmark operation */ -void touch_priv_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op); +void touch_priv_config_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_config_t *benchmark_cfg); #ifdef __cplusplus } diff --git a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h index 591bd7d8d0f..a9ec0dea796 100644 --- a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h +++ b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h @@ -12,15 +12,15 @@ #pragma once #include "soc/soc_caps.h" -#include "driver/touch_common_types.h" +#include "driver/touch_sens_types.h" #include "esp_err.h" #ifdef __cplusplus extern "C" { #endif -#define TOUCH_MIN_CHAN_ID 0 /*!< The minimum available channel id of the touch pad */ -#define TOUCH_MAX_CHAN_ID 13 /*!< The maximum available channel id of the touch pad */ +#define TOUCH_MIN_CHAN_ID 0 /*!< The minimum available channel id of the touch pad */ +#define TOUCH_MAX_CHAN_ID 13 /*!< The maximum available channel id of the touch pad */ /** * @brief Helper macro to the default configurations of the touch sensor controller @@ -37,52 +37,20 @@ extern "C" { /** * @brief Helper macro to the default sample configurations - * @note This default configuration is based on clock frequency 16MHz + * @note This default configuration uses `sample frequency = clock frequency / 1` * */ -#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0() { \ - .freq_hz = 16000000, \ +#define TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(_div_num, coarse_freq_tune, fine_freq_tune) { \ + .div_num = _div_num, \ .charge_times = 500, \ - .rc_filter_res = 2, \ - .rc_filter_cap = 88, \ - .low_drv = 3, \ - .high_drv = 0, \ + .rc_filter_res = 1, \ + .rc_filter_cap = 1, \ + .low_drv = fine_freq_tune, \ + .high_drv = coarse_freq_tune, \ .bias_volt = 5, \ .bypass_shield_output = false, \ } -/** - * @brief Helper macro to the default sample configurations - * @note This default configuration is based on clock frequency 8MHz - * - */ -#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1() { \ - .freq_hz = 8000000, \ - .charge_times = 500, \ - .rc_filter_res = 3, \ - .rc_filter_cap = 29, \ - .low_drv = 3, \ - .high_drv = 8, \ - .bias_volt = 5, \ - .bypass_shield_output = false, \ -} - -/** - * @brief Helper macro to the default sample configurations - * @note This default configuration is based on clock frequency 4MHz - * - */ -#define TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2() { \ - .freq_hz = 4000000, \ - .charge_times = 500, \ - .rc_filter_res = 3, \ - .rc_filter_cap = 10, \ - .low_drv = 7, \ - .high_drv = 31, \ - .bias_volt = 15, \ - .bypass_shield_output = false, \ -} - #define TOUCH_SENSOR_DEFAULT_FILTER_CONFIG() { \ .benchmark = { \ .filter_mode = TOUCH_BM_IIR_FILTER_4, \ @@ -205,7 +173,7 @@ typedef enum { * */ typedef struct { - uint32_t freq_hz; /*!< The sampling frequency for this configuration in Hz */ + uint32_t div_num; /*!< Division of the touch output pulse, `touch_out_pulse / div_num = charge_times` */ uint32_t charge_times; /*!< The charge and discharge times of this sample configuration, the read data are positive correlation to the charge_times */ uint8_t rc_filter_res; /*!< The resistance of the RC filter of this sample configuration, range [0, 3], while 0 = 0K, 1 = 1.5K, 2 = 3K, 3 = 4.5K */ uint8_t rc_filter_cap; /*!< The capacitance of the RC filter of this sample configuration, range [0, 127], while 0 = 0pF, 1 = 20fF, ..., 127 = 2.54pF */ @@ -337,12 +305,12 @@ typedef struct { * */ typedef struct { - touch_channel_handle_t guard_chan; /*!< The guard channel of waterproof. Set NULL if you don't need the guard channel. + touch_channel_handle_t guard_chan; /*!< The guard channel of that used for immersion detect. Set NULL if you don't need the guard channel. * Typically, the guard channel is a ring that surrounds the touch panels, * it is used to detect the large area that covered by water. - * While large area of water covers the touch panel, the touch sensor will be temporary disable to avoid the fake touch. + * While large area of water covers the touch panel, the guard channel will be activated. */ - touch_channel_handle_t shield_chan; /*!< The touch channel that used as the shield channel, can't be NULL. + touch_channel_handle_t shield_chan; /*!< The shield channel that used for water droplets shield, can't be NULL. * Typically, the shield channel uses grid layout which covers the touch area, * it is used to shield the influence of water droplets covering both the touch panel and the shield channel. * The shield channel will be paralleled to the current measuring channel (except the guard channel) to reduce the influence of water droplets. @@ -350,6 +318,12 @@ typedef struct { uint32_t shield_drv; /*!< The shield channel driver, which controls the drive capability of shield channel, range: 0 ~ 7 * The larger the parasitic capacitance on the shielding channel, the higher the drive capability needs to be set. */ + struct { + uint32_t immersion_proof: 1; /*!< Enable to protect the touch sensor pad when immersion detected. + * It will temporary disable the touch scanning if the guard channel triggered, and enable again if guard channel released. + * So that to avoid the fake touch when the touch panel is immersed in water. + */ + } flags; /*!< Flags of the water proof function */ } touch_waterproof_config_t; /** @@ -491,12 +465,12 @@ typedef struct { } touch_event_callbacks_t; /** - * @brief Touch sensor benchmark operation, to set or reset the benchmark of the channel + * @brief Touch sensor benchmark configurations, to set or reset the benchmark of the channel * */ typedef struct { bool do_reset; /*!< Whether to reset the benchmark to the channel's latest smooth data */ -} touch_chan_benchmark_op_t; +} touch_chan_benchmark_config_t; #ifdef __cplusplus } diff --git a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c index 29f1267011b..bd990ba47d8 100644 --- a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c +++ b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c @@ -96,7 +96,7 @@ void IRAM_ATTR touch_priv_default_intr_handler(void *arg) if (status & TOUCH_LL_INTR_MASK_ACTIVE) { /* When the guard ring activated, disable the scanning of other channels to avoid fake touch */ TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); - if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + if (g_touch->immersion_proof && data.chan == g_touch->guard_chan) { touch_ll_enable_scan_mask(~BIT(data.chan->id), false); } TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); @@ -107,7 +107,7 @@ void IRAM_ATTR touch_priv_default_intr_handler(void *arg) if (status & TOUCH_LL_INTR_MASK_INACTIVE) { /* When the guard ring inactivated, enable the scanning of other channels again */ TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); - if (g_touch->waterproof_en && data.chan == g_touch->guard_chan) { + if (g_touch->immersion_proof && data.chan == g_touch->guard_chan) { touch_ll_enable_scan_mask(g_touch->chan_mask & (~BIT(g_touch->shield_chan->id)), true); } TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); @@ -157,36 +157,12 @@ static esp_err_t s_touch_convert_to_hal_config(touch_sensor_handle_t sens_handle hal_cfg->sample_cfg_num = sens_cfg->sample_cfg_num; hal_cfg->output_mode = sens_cfg->output_mode; - hal_utils_clk_info_t clk_info = { - .src_freq_hz = sens_handle->src_freq_hz, - .min_integ = 1, - .max_integ = TOUCH_LL_CLK_DIV_MAX, - .round_opt = HAL_DIV_ROUND, - }; - for (uint32_t div_num, smp_cfg_id = 0; smp_cfg_id < sens_cfg->sample_cfg_num; smp_cfg_id++) { + for (uint32_t smp_cfg_id = 0; smp_cfg_id < sens_cfg->sample_cfg_num; smp_cfg_id++) { const touch_sensor_sample_config_t *sample_cfg = &(sens_cfg->sample_cfg[smp_cfg_id]); - uint32_t actual_freq_hz = 0; - /* Allow 10% overflow to increase the robustness when the sample frequency is close to the source clock, - because the source clock is from RTC FAST whose frequency is floating up and down among startups */ - if (sample_cfg->freq_hz > sens_handle->src_freq_hz && sample_cfg->freq_hz < sens_handle->src_freq_hz * 1.1) { - ESP_LOGW(TAG, "[sample_cfg_id %"PRIu32"] sample frequency exceed the src clock but still within 10%%", smp_cfg_id); - div_num = 1; - actual_freq_hz = sens_handle->src_freq_hz; - } else { - clk_info.exp_freq_hz = sample_cfg->freq_hz; - actual_freq_hz = hal_utils_calc_clk_div_integer(&clk_info, &div_num); - } - /* Check the actual frequency and its precision */ - ESP_RETURN_ON_FALSE(actual_freq_hz, ESP_ERR_INVALID_ARG, TAG, - "[sample_cfg_id %"PRIu32"] sample frequency should within range %"PRIu32" ~ %"PRIu32" hz", - smp_cfg_id, sens_handle->src_freq_hz / TOUCH_LL_CLK_DIV_MAX, sens_handle->src_freq_hz); - ESP_LOGD(TAG, "[sample_cfg_id %"PRIu32"] clock divider %"PRIu32, smp_cfg_id, div_num); - if (actual_freq_hz != clk_info.exp_freq_hz) { - ESP_LOGW(TAG, "[sample_cfg_id %"PRIu32"] clock precision loss, expect %"PRIu32" hz, got %"PRIu32" hz", - smp_cfg_id, clk_info.exp_freq_hz, actual_freq_hz); - } + ESP_RETURN_ON_FALSE(sample_cfg->div_num > 0, ESP_ERR_INVALID_ARG, TAG, + "div_num can't be 0"); /* Assign the hal configurations */ - hal_cfg->sample_cfg[smp_cfg_id].div_num = div_num; + hal_cfg->sample_cfg[smp_cfg_id].div_num = sample_cfg->div_num; hal_cfg->sample_cfg[smp_cfg_id].charge_times = sample_cfg->charge_times; hal_cfg->sample_cfg[smp_cfg_id].rc_filter_res = sample_cfg->rc_filter_res; hal_cfg->sample_cfg[smp_cfg_id].rc_filter_cap = sample_cfg->rc_filter_cap; @@ -271,14 +247,8 @@ esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch } if (type <= TOUCH_CHAN_DATA_TYPE_BENCHMARK) { TOUCH_ENTER_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); - if (chan_handle != chan_handle->base->deep_slp_chan) { - for (int i = 0; i < sample_cfg_num; i++) { - touch_ll_read_chan_data(chan_handle->id, i, internal_type, &data[i]); - } - } else { - for (int i = 0; i < sample_cfg_num; i++) { - touch_ll_sleep_read_chan_data(internal_type, i, &data[i]); - } + for (int i = 0; i < sample_cfg_num; i++) { + touch_ll_read_chan_data(chan_handle->id, i, internal_type, &data[i]); } TOUCH_EXIT_CRITICAL_SAFE(TOUCH_PERIPH_LOCK); } @@ -297,9 +267,9 @@ esp_err_t touch_priv_channel_read_data(touch_channel_handle_t chan_handle, touch return ESP_OK; } -void touch_priv_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op) +void touch_priv_config_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_config_t *benchmark_cfg) { - if (benchmark_op->do_reset) { + if (benchmark_cfg->do_reset) { touch_ll_reset_chan_benchmark(BIT(chan_handle->id)); } } @@ -423,6 +393,7 @@ esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, cons TOUCH_NULL_POINTER_CHECK(wp_cfg->shield_chan); TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); sens_handle->waterproof_en = true; + sens_handle->immersion_proof = wp_cfg->flags.immersion_proof; sens_handle->guard_chan = wp_cfg->guard_chan; sens_handle->shield_chan = wp_cfg->shield_chan; touch_ll_waterproof_set_guard_chan(wp_cfg->guard_chan ? wp_cfg->guard_chan->id : TOUCH_LL_NULL_CHANNEL); @@ -441,6 +412,7 @@ esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, cons touch_ll_waterproof_set_shield_driver(0); sens_handle->guard_chan = NULL; sens_handle->shield_chan = NULL; + sens_handle->immersion_proof = false; sens_handle->waterproof_en = false; TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); } diff --git a/components/esp_driver_touch_sens/include/driver/touch_sens.h b/components/esp_driver_touch_sens/include/driver/touch_sens.h index ca4b4a9300d..cba510baef9 100644 --- a/components/esp_driver_touch_sens/include/driver/touch_sens.h +++ b/components/esp_driver_touch_sens/include/driver/touch_sens.h @@ -7,7 +7,7 @@ #pragma once #include "esp_err.h" -#include "driver/touch_common_types.h" +#include "driver/touch_sens_types.h" #include "driver/touch_version_types.h" #ifdef __cplusplus @@ -179,7 +179,7 @@ esp_err_t touch_sensor_stop_continuous_scanning(touch_sensor_handle_t sens_handl * And the touch sensor driver will be in SCANNING state after this function is called successfully, * and then switch back to ENABLED state after the scanning is done or timeout. * @note The block time of this function depends on various factors, - * In common practice, recommend to set the timeout to a second-level timeout or wait forever, + * In common practice, recommend to set the timeout to several seconds or wait forever, * because oneshot scanning can't last for so long. * * @param[in] sens_handle Touch sensor controller handle @@ -208,17 +208,17 @@ esp_err_t touch_sensor_trigger_oneshot_scanning(touch_sensor_handle_t sens_handl esp_err_t touch_sensor_register_callbacks(touch_sensor_handle_t sens_handle, const touch_event_callbacks_t *callbacks, void *user_ctx); /** - * @brief Set the touch sensor benchmark for all the registered channels + * @brief Confiture the touch sensor benchmark for all the registered channels * @note This function can be called no matter the touch sensor controller is enabled or not (i.e. ENABLED or SCANNING state). * And it can also be called in ISR/callback context. * * @param[in] chan_handle Touch channel handle - * @param[in] benchmark_op The benchmark operations + * @param[in] benchmark_cfg The benchmark configurations * @return * - ESP_OK On success * - ESP_ERR_INVALID_ARG NULL pointer */ -esp_err_t touch_sensor_set_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_op_t *benchmark_op); +esp_err_t touch_channel_config_benchmark(touch_channel_handle_t chan_handle, const touch_chan_benchmark_config_t *benchmark_cfg); /** * @brief Read the touch channel data according to the types diff --git a/components/esp_driver_touch_sens/include/driver/touch_common_types.h b/components/esp_driver_touch_sens/include/driver/touch_sens_types.h similarity index 100% rename from components/esp_driver_touch_sens/include/driver/touch_common_types.h rename to components/esp_driver_touch_sens/include/driver/touch_sens_types.h diff --git a/components/esp_driver_touch_sens/linker.lf b/components/esp_driver_touch_sens/linker.lf index 9ba19d62f2a..9dbc60f1753 100644 --- a/components/esp_driver_touch_sens/linker.lf +++ b/components/esp_driver_touch_sens/linker.lf @@ -5,6 +5,6 @@ entries: touch_sens_common: touch_sensor_start_continuous_scanning (noflash) touch_sens_common: touch_sensor_stop_continuous_scanning (noflash) touch_sens_common: touch_channel_read_data (noflash) - touch_sens_common: touch_sensor_set_benchmark (noflash) + touch_sens_common: touch_channel_config_benchmark (noflash) touch_sens_version_specific: touch_priv_channel_read_data (noflash) - touch_sens_version_specific: touch_priv_set_benchmark (noflash) + touch_sens_version_specific: touch_priv_config_benchmark (noflash) diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c index 8dda1d8d6a7..226b8549fa2 100644 --- a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c @@ -14,12 +14,12 @@ #include "esp_attr.h" static touch_sensor_sample_config_t s_sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1), #if TOUCH_SAMPLE_CFG_NUM > 1 - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(2, 1, 1), #endif #if TOUCH_SAMPLE_CFG_NUM > 2 - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(4, 1, 1), #endif }; diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index eb37b697f24..02a2c5762f8 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -119,6 +119,7 @@ typedef enum { RTC_UART1_TRIG_EN | \ RTC_BT_TRIG_EN | \ RTC_LP_CORE_TRIG_EN | \ + RTC_TOUCH_TRIG_EN | \ RTC_XTAL32K_DEAD_TRIG_EN | \ RTC_USB_TRIG_EN | \ RTC_BROWNOUT_DET_TRIG_EN) diff --git a/components/hal/esp32p4/touch_sensor_hal.c b/components/hal/esp32p4/touch_sensor_hal.c index 8f11b230d7e..450e3ab89ba 100644 --- a/components/hal/esp32p4/touch_sensor_hal.c +++ b/components/hal/esp32p4/touch_sensor_hal.c @@ -25,6 +25,7 @@ static touch_hal_deep_sleep_obj_t s_touch_slp_obj = { void touch_hal_config_controller(const touch_hal_config_t *cfg) { HAL_ASSERT(cfg); + touch_ll_sleep_set_channel_num(TOUCH_LL_NULL_CHANNEL); touch_ll_set_out_mode(cfg->output_mode); touch_ll_set_power_on_wait_cycle(cfg->power_on_wait_ticks); touch_ll_set_measure_interval_ticks(cfg->meas_interval_ticks); @@ -76,7 +77,6 @@ static void s_touch_hal_apply_sleep_config(void) void touch_hal_prepare_deep_sleep(void) { s_touch_hal_apply_sleep_config(); - // TODO: check if it is necessary to reset the sleep benchmark touch_ll_sleep_reset_benchmark(); touch_ll_intr_clear(TOUCH_LL_INTR_MASK_ALL); } diff --git a/docs/_static/diagrams/cap_touch_sens/touch_file_structure.svg b/docs/_static/diagrams/cap_touch_sens/touch_file_structure.svg new file mode 100644 index 00000000000..8d1abf0dd2f --- /dev/null +++ b/docs/_static/diagrams/cap_touch_sens/touch_file_structure.svg @@ -0,0 +1,4 @@ + + + +
touch_sens.h
touch_sens.h
touch_sens_types.h
touch_sens_types.h
touch_version_types.h
touch_version_types.h
touch_sensor_ll.h
touch_sensor_ll.h
touch_sensor_hal.h
touch_sensor_hal.h
touch_sensor_hal.c
touch_sensor_hal.c
touch_sensor_types.h
touch_sensor_types.h
touch_sens_common.c
touch_sens_common.c
touch_sens_private.h
touch_sens_private.h
touch_sens_v1.c
touch_sens_v1.c
Capacitive Touch Sensor Application
Capacitive Touch Sensor Application
components / esp_driver_touch_sens
components / esp_driver_touch_sens
components / hal
components / hal
public header
public header
private header
private header
source file
source file
includes
includes
Legend
Legend
touch_sens_v2.c
touch_sens_v2.c
touch_sens_v3.c
touch_sens_v3.c
touch_version_types.h
touch_version_types.h
touch_version_types.h
touch_version_types.h
Text is not SVG - cannot display
diff --git a/docs/_static/diagrams/cap_touch_sens/touch_state_machine.svg b/docs/_static/diagrams/cap_touch_sens/touch_state_machine.svg new file mode 100644 index 00000000000..2f4eecf8d93 --- /dev/null +++ b/docs/_static/diagrams/cap_touch_sens/touch_state_machine.svg @@ -0,0 +1,4 @@ + + + +
BEGIN
BEGIN
touch_sensor_new_controller
touch_sensor_new_controller
touch_sensor_new_channel
touch_sensor_new_channel
INIT
INIT
READY
READY
SCAN
SCAN
<other_configurations>
<other_configurations>
touch_sensor_enable
touch_sensor_enable
touch_sensor_disable
touch_sensor_disable
touch_sensor_start_continuous_scanning
touch_sensor_start_continuous_scanning
touch_sensor_stop_continuous_scanning
touch_sensor_stop_continuous_scanning
touch_sensor_trigger_oneshot_sacnning
touch_sensor_trigger_oneshot_sacnning
All channels scanned?
All channels scanned?
touch_sensor_del_channel
touch_sensor_del_channel
touch_sensor_del_controller
touch_sensor_del_controller
END
END
Y
Y
N
N
Text is not SVG - cannot display
diff --git a/docs/conf_common.py b/docs/conf_common.py index a0b4ace54c4..528201789f4 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -108,8 +108,6 @@ TEMP_SENSOR_DOCS = ['api-reference/peripherals/temp_sensor.rst'] -TOUCH_SENSOR_DOCS = ['api-reference/peripherals/touch_pad.rst'] - SPIRAM_DOCS = ['api-guides/external-ram.rst'] USB_DOCS = ['api-reference/peripherals/usb_device.rst', @@ -185,6 +183,7 @@ 'security/secure-boot-v1.rst', 'api-reference/peripherals/dac.rst', 'api-reference/peripherals/sd_pullup_requirements.rst', + 'api-reference/peripherals/touch_pad.rst', 'hw-reference/esp32/**', 'api-guides/RF_calibration.rst', 'api-guides/phy.rst'] + FTDI_JTAG_DOCS + QEMU_DOCS @@ -194,6 +193,7 @@ 'api-reference/peripherals/ds.rst', 'api-reference/peripherals/temp_sensor.rst', 'api-reference/system/async_memcpy.rst', + 'api-reference/peripherals/touch_pad.rst', 'api-reference/peripherals/touch_element.rst', 'api-guides/RF_calibration.rst', 'api-guides/phy.rst'] + FTDI_JTAG_DOCS + USB_OTG_DFU_DOCS + USB_OTG_CONSOLE_DOCS @@ -201,6 +201,7 @@ ESP32S3_DOCS = ['hw-reference/esp32s3/**', 'api-reference/system/ipc.rst', 'api-guides/flash_psram_config.rst', + 'api-reference/peripherals/touch_pad.rst', 'api-reference/peripherals/sd_pullup_requirements.rst', 'api-guides/RF_calibration.rst', 'api-guides/phy.rst'] + USB_OTG_DFU_DOCS + USB_OTG_CONSOLE_DOCS @@ -223,6 +224,7 @@ 'api-guides/phy.rst'] ESP32P4_DOCS = ['api-reference/system/ipc.rst', + 'api-reference/peripherals/cap_touch_sens.rst', 'api-reference/peripherals/sd_pullup_requirements.rst'] # format: {tag needed to include: documents to included}, tags are parsed from sdkconfig and peripheral_caps.h headers @@ -253,7 +255,6 @@ 'SOC_RMT_SUPPORTED':RMT_DOCS, 'SOC_DAC_SUPPORTED':DAC_DOCS, 'SOC_ETM_SUPPORTED':ETM_DOCS, - 'SOC_TOUCH_SENSOR_SUPPORTED':TOUCH_SENSOR_DOCS, 'SOC_ULP_FSM_SUPPORTED':ULP_FSM_DOCS, 'SOC_RISCV_COPROC_SUPPORTED':RISCV_COPROC_DOCS, 'SOC_LP_CORE_SUPPORTED':LP_CORE_DOCS, diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index 32f0c5817b7..0fdf35bc6b1 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -18,6 +18,9 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_cam/csi/include/esp_cam_ctlr_csi.h \ $(PROJECT_PATH)/components/hal/include/hal/jpeg_types.h \ $(PROJECT_PATH)/components/hal/include/hal/ppa_types.h \ + $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens.h \ + $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens_types.h \ + $(PROJECT_PATH)/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_types.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_types.h \ diff --git a/docs/en/api-reference/peripherals/cap_touch_sens.rst b/docs/en/api-reference/peripherals/cap_touch_sens.rst new file mode 100644 index 00000000000..2583952c3ac --- /dev/null +++ b/docs/en/api-reference/peripherals/cap_touch_sens.rst @@ -0,0 +1,416 @@ +Capacitive Touch Sensor +========================= + +:link_to_translation:`zh_CN:[中文]` + +{IDF_TARGET_TOUCH_SENSOR_VERSION:default="NOT_UPDATED", esp32p4="v3"} + +Introduction +--------------- + +A touch sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When the surface is touched, the capacitance variation is used to evaluate if the touch was valid. + +The sensing pads can be arranged in different combinations (e.g., matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer. + +For design, operation, and control registers of a touch sensor, see **{IDF_TARGET_NAME} Technical Reference Manual** > **On-Chip Sensors and Analog Signal Processing** [`PDF <{IDF_TARGET_TRM_EN_URL}#sensor>`__]. + +In-depth design details of touch sensors and firmware development guidelines for {IDF_TARGET_NAME} are available in `Touch Sensor Application Note `_. + +Overview of Capacitive Touch Sensor Versions +----------------------------------------------- + ++------------------+--------------+------------------------------------------------------------------------+ +| Hardware Version | Chip | Main Features | ++==================+==============+========================================================================+ +| V1 | ESP32 | Version 1, the channel value decreases when it is touched | ++------------------+--------------+------------------------------------------------------------------------+ +| V2 | ESP32-S2 | Version 2, the channel value increases when it is touched | +| | | Supports waterproof, proximity sensing and sleep wake-up | +| +--------------+------------------------------------------------------------------------+ +| | ESP32-S3 | Version 2, support proximity measurement done interrupt | ++------------------+--------------+------------------------------------------------------------------------+ +| V3 | ESP32-P4 | Version 3, support frequency hopping | ++------------------+--------------+------------------------------------------------------------------------+ + +Overview of Touch Sensor Channels +------------------------------------ + +.. only:: esp32p4 + + ========= ===== ===== ===== ===== ===== ===== ===== ===== ====== ====== ====== ====== ====== ====== ========== + Channel CH0 CH1 CH2 CH3 CH4 CH5 CH6 CH7 CH8 CH9 CH10 CH11 CH12 CH13 CH14 + --------- ----- ----- ----- ----- ----- ----- ----- ----- ------ ------ ------ ------ ------ ------ ---------- + GPIO IO2 IO3 IO4 IO5 IO6 IO7 IO8 IO9 IO10 IO11 IO12 IO13 IO14 IO15 Internal + ========= ===== ===== ===== ===== ===== ===== ===== ===== ====== ====== ====== ====== ====== ====== ========== + +Terminology in the Driver +---------------------------- + +- **Touch Sensor Controller**: The controller of the touch sensor, responsible for configuring and managing the touch sensor. +- **Touch Sensor Channel**: A specific touch sensor sampling channel. A touch sensor module has multiple touch channels, which are usually connected to the touch pad for measuring the capacitance change. In the driver, sampling of **one** channel is called one ``measurement`` and the scanning of **all** registered channels is called one ``scan``. + +.. only:: SOC_TOUCH_SUPPORT_FREQ_HOP + + - **Touch Sensor Sampling Configuration**: Touch sensor sampling configuration refers to all the hardware configurations that related to the sampling. It can determine how the touch channels sample by setting the number of charging times, charging frequency, measurement interval, etc. {IDF_TARGET_NAME} supports multiple sets of sample configuration, which means it can support frequency hopping. + +.. only:: not SOC_TOUCH_SUPPORT_FREQ_HOP + + - **Touch Sensor Sampling Configuration**: Touch sensor sampling configuration refers to all the hardware configurations that related to the sampling. It can determine how the touch channels sample by setting the number of charging times, charging frequency, measurement interval, etc. {IDF_TARGET_NAME} only support one set of sample configuration, so it doesn't support frequency hopping. + +File Structure +----------------- + +.. figure:: ../../../_static/diagrams/cap_touch_sens/touch_file_structure.svg + :align: center + :alt: File Structure of Touch Sensor Driver + + File Structure of Touch Sensor Driver + +Finite-state Machine +--------------------- + +The following diagram shows the state machine of the touch sensor driver, which describes the driver state after calling a function, and the constraint of the state transition. + +.. figure:: ../../../_static/diagrams/cap_touch_sens/touch_state_machine.svg + :align: center + :alt: Finite-state Machine of Touch Sensor Driver + + Finite-state Machine of Touch Sensor Driver + +The diagram above is the finite-state machine of the touch sensor driver, which describes how the state transferred by invoking different APIs. ```` in the diagram stands for the other optional configurations, like reconfigurations to the touch sensor controller or channels, callback registration, filter, and so on. + +.. note:: + + :cpp:func:`touch_channel_read_data` can be called at any time after the channel is registered (i.e., since ``INIT`` state), but please take care of the validation of the data. + +Functionality Introduction +------------------------------ + +Categorized by functionality, the APIs of Capacitive Touch Sensor mainly include: + +.. list:: + + - `Touch Sensor Controller Management <#touch-ctrl>`__ + - `Touch Sensor Channel Management <#touch-chan>`__ + - `Filter Configuration <#touch-filter>`__ + - `Callback <#touch-callback>`__ + - `Enable and Disable <#touch-enable>`__ + - `Continuous Scan <#touch-conti-scan>`__ + - `Oneshot Scan <#touch-oneshot-scan>`__ + - `Benchmark Configuration <#touch-benchmark>`__ + - `Read Measurement Data <#touch-read>`__ + :SOC_TOUCH_SUPPORT_WATERPROOF: - `Waterproof Configuration <#touch-waterproof>`__ + :SOC_TOUCH_SUPPORT_PROX_SENSING: - `Proximity Sensing Configuration <#touch-prox-sensing>`__ + :SOC_TOUCH_SUPPORT_SLEEP_WAKEUP: - `Sleep Wake-up Configuration <#touch-sleep-wakeup>`__ + +.. _touch-ctrl: + +Touch Sensor Controller Management +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Touch Sensor is controlled by controller handle :cpp:type:`touch_sensor_handle_t`, it can be initialized and allocated by :cpp:func:`touch_sensor_new_controller`. + +.. code-block:: c + + // Some target has multiple sets of sample configuration can be set, here take one for example + #define SAMPLE_NUM 1 + touch_sensor_handle_t sens_handle = NULL; + // sample configuration + touch_sensor_sample_config_t sample_cfg[SAMPLE_NUM] = { + // Specify sample configuration or apply the default sample configuration via `TOUCH_SENSOR_Vn_DEFAULT_SAMPLE_CONFIG` + // ... + }; + // Use the default touch controller configuration + touch_sensor_config_t touch_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(SAMPLE_NUM, sample_cfg); + // Allocate a new touch sensor controller handle + ESP_ERROR_CHECK(touch_sensor_new_controller(&touch_cfg, &sens_handle)); + +To delete the controller handle and free the software and hardware resources, please call :cpp:func:`touch_sensor_del_controller`. But note that you need to delete the other resources that based on the controller first, like the registered touch channels, otherwise it can't be deleted directly. + +.. code-block:: c + + ESP_ERROR_CHECK(touch_sensor_del_controller(sens_handle)); + +You can also update the configurations via :cpp:func:`touch_sensor_reconfig_controller` before the controller is enabled. + +.. code-block:: c + + touch_sensor_config_t touch_cfg = { + // New controller configurations + // ... + }; + ESP_ERROR_CHECK(touch_sensor_reconfig_controller(sens_handle, &touch_cfg)); + +.. _touch-chan: + +Touch Sensor Channel Management +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are multiple touch channels in the touch sensor module, the touch sensor channel is controlled by the channel handle :cpp:type:`touch_channel_handle_t`. It can be initialized and allocated by :cpp:func:`touch_sensor_new_channel`. + +.. code-block:: c + + // ... + touch_channel_config_t chan_cfg = { + // Touch channel configurations + // ... + }; + touch_channel_handle_t chan_handle = NULL; + int chan_id = 0; + // Allocate a new touch sensor controller handle + ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, chan_id, &chan_cfg, &chan_handle)); + +To delete the touch channel handle and free the software and hardware resources, please call :cpp:func:`touch_sensor_del_channel`. + +.. code-block:: c + + ESP_ERROR_CHECK(touch_sensor_del_channel(chan_handle)); + +You can also update the configurations via :cpp:func:`touch_sensor_reconfig_channel` before the controller is enabled. + +.. code-block:: c + + touch_channel_config_t chan_cfg = { + // New touch channel configurations + // ... + }; + ESP_ERROR_CHECK(touch_sensor_reconfig_channel(chan_handle, &chan_cfg)); + +.. _touch-filter: + +Filter Configuration +^^^^^^^^^^^^^^^^^^^^^^ + +The filter can help to increase the stability in different use cases. The filter can be registered by calling :cpp:func:`touch_sensor_config_filter` and specify the configurations :cpp:type:`touch_sensor_filter_config_t`. These configurations mainly determine how to filter and update the benchmark and read data. Please note that all touch channels will share this filter. + +To deregister the filter, you can call :cpp:func:`touch_sensor_config_filter` again, and set the second parameter (i.e. :cpp:type:`touch_sensor_filter_config_t` pointer) to ``NULL``. + +.. code-block:: c + + // ... + touch_sensor_filter_config_t filter_config = { + // Filter configurations + // ... + }; + // Register the filter + ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, &filter_config)); + // ... + // Deregister the filter + ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, NULL)); + +.. _touch-callback: + +Callback +^^^^^^^^^^^^^ + +Calling :cpp:func:`touch_sensor_register_callbacks` to register the touch sensor event callbacks. Once the touch sensor events (like ``on_active``, ``on_inactive``) trigger, the corresponding callbacks will be invoked, so that to deal with the event in the upper application. + +For the general example, when the measured data of the current touch channel exceed the ``benchmark`` + ``active_threshold``, this channel is activated, and the driver will call ``on_active`` callback to inform the application layer. Similar, when the active channel measured a lower data than ``benchmark`` + ``active_threshold``, then this channel will be inactivated, and ``on_inactive`` will be called to inform this channel is released. + +.. note:: + + To ensure the stability of the triggering and releasing, ``active_hysteresis`` and ``debounce_cnt`` can be configured to avoid the frequent triggering that caused by jitter and noise. + +Please refer to :cpp:type:`touch_event_callbacks_t` for the details about the supported callbacks. + +.. code-block:: c + + touch_event_callbacks_t callbacks = { + .on_active = example_touch_on_active_cb, + // Other callbacks + // ... + }; + // Register callbacks + ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens_handle, &callbacks, NULL)); + + // To deregister callbacks, set the corresponding callback to NULL + callbacks.on_active = NULL; + // Other callbacks to deregister + // ... + ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens_handle, &callbacks, NULL)); + +.. _touch-enable: + +Enable and Disable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +After finished the configuration of the touch controller and touch channels, :cpp:func:`touch_sensor_enable` can be called to enable the touch sensor controller. It will enter ``READY`` status and power on the registered channels, then you can start scanning and sampling the touch data. Note that you can only do scanning and reading operation once the controller is enabled. If you want to update the controller or channel configurations, you need to call :cpp:func:`touch_sensor_disable` first. + +.. code-block:: c + + // Enable touch sensor + ESP_ERROR_CHECK(touch_sensor_enable(sens_handle)); + // ... + // Disable touch sensor + ESP_ERROR_CHECK(touch_sensor_disable(sens_handle)); + +.. _touch-conti-scan: + +Continuous Scan +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With the touch controller enabled, :cpp:func:`touch_sensor_start_continuous_scanning` can be called to start the continuous scanning to all the registered touch channels. The read data of these touch channels will be updated automatically in each scan. Calling :cpp:func:`touch_sensor_stop_continuous_scanning` can stop the continuous scan. + +.. code-block:: c + + // Start continuous scan + ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens_handle)); + // ... + // Stop continuous scan + ESP_ERROR_CHECK(touch_sensor_stop_continuous_scanning(sens_handle)); + +.. _touch-oneshot-scan: + +Oneshot Scan +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +With the touch controller enabled, :cpp:func:`touch_sensor_trigger_oneshot_scanning` can be called to trigger an one-time scan to all the registered touch channels. Note that oneshot scan is a blocking function, it will keep blocking and only return when the scan is finished. Moreover, you can't trigger an oneshot scan after the continuous scan has started. + +.. code-block:: c + + // Trigger an oneshot scan with timeout 1000ms + ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 1000)); + +.. _touch-benchmark: + +Benchmark Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Normally, you don't have to set the benchmark manually, but you can force reset the benchmark to the current smooth value by calling :cpp:func:`touch_channel_config_benchmark` when necessary + +.. code-block:: c + + touch_chan_benchmark_config_t benchmark_cfg = { + // Benchmark operations + // ... + }; + ESP_ERROR_CHECK(touch_channel_config_benchmark(chan_handle, &benchmark_cfg)); + +.. _touch-read: + +Read Measurement Data +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Call :cpp:func:`touch_channel_read_data` to read the data with different types. Like, benchmark, smooth data, etc. You can refer to :cpp:type:`touch_chan_data_type_t` for the supported data types. + +.. only:: SOC_TOUCH_SUPPORT_FREQ_HOP + + {IDF_TARGET_NAME} supports frequency hopping by configuring multiple set of sample configurations, :cpp:func:`touch_channel_read_data` can read out the data of each sample configuration in a single call, you can determine the sample configuration number by :cpp:member:`touch_sensor_config_t::sample_cfg_num`, and pass an array (which length is not smaller than the configuration number) to the third parameter ``*data``, so that all the measured data of this channel will be stored in the array. + +.. code-block:: c + + #define SAMPLE_NUM 1 // Take one sample configuration set for example + uint32_t smooth_data[SAMPLE_NUM] = {}; + // Read the smooth data + ESP_ERROR_CHECK(touch_channel_read_data(chan_handle, TOUCH_CHAN_DATA_TYPE_SMOOTH, smooth_data)); + +.. _touch-waterproof: + +.. only:: SOC_TOUCH_SUPPORT_WATERPROOF + + Waterproof Configuration + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} supports waterproof. Waterproof can be registered by calling :cpp:func:`touch_sensor_config_waterproof` and specify the configurations :cpp:type:`touch_waterproof_config_t`. There are two parts of the waterproof function: + + - Immersion (in-water) proof: :cpp:member:`touch_waterproof_config_t::guard_chan` can be specified for detecting immersion. It is usually designed as a ring on the PCB, which surrounds all the other touch pads. When this guard ring channel is triggered, that means the touch panel is immersed by water, all the touch channels will stop measuring to avoid falsely triggering. + - Moisture (water-drop) proof: :cpp:member:`touch_waterproof_config_t::shield_chan` can be specified for detecting moisture. It usually uses the grid layout on the PCB, which covers the whole touch panel. The shield channel will charge and discharge synchronously with the current touch channel, when there is a water droplet covers both shield channel and normal touch channel, :cpp:member:`touch_waterproof_config_t::shield_drv` can strengthen the electrical coupling caused by the water droplets, and then reconfigure the active threshold based on the disturbance to eliminate the influence that introduced by the water droplet. + + To deregister the waterproof function, you can call :cpp:func:`touch_sensor_config_waterproof` again, and set the second parameter (i.e. :cpp:type:`touch_waterproof_config_t` pointer) to ``NULL``. + + .. code-block:: c + + touch_waterproof_config_t waterproof_cfg = { + // Waterproof configurations + // ... + }; + // Register waterproof function + ESP_ERROR_CHECK(touch_sensor_config_waterproof(sens_handle, &waterproof_cfg)); + // ... + // Deregister waterproof function + ESP_ERROR_CHECK(touch_sensor_config_waterproof(sens_handle, NULL)); + +.. _touch-prox-sensing: + +.. only:: SOC_TOUCH_SUPPORT_PROX_SENSING + + Proximity Sensing Configuration + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} supports proximity sensing. Proximity sensing can be registered by calling :cpp:func:`touch_sensor_config_proximity_sensing` and specify the configurations :cpp:type:`touch_proximity_config_t`. + + Since the capacitance change caused by proximity sensing is far less than that caused by physical touch, large area of copper foil is often used on PCB to increase the sensing area. In addition, multiple rounds of scans are needed and the result of each scan will be accumulated in the driver to improve the measurement sensitivity. The scan times (rounds) can be determined by :cpp:member:`touch_proximity_config_t::scan_times` and the charging times of the proximity channel in one scan can be determined by :cpp:member:`touch_proximity_config_t::charge_times`. Generally, the larger the scan times and charging times is, the higher the sensitivity will be, however, the read data will be unstable if the sensitivity is too high. Proper parameters should be determined regarding the application. + + The accumulated proximity data can be read by :cpp:func:`touch_channel_read_data` with the data type :cpp:enumerator:`TOUCH_CHAN_DATA_TYPE_PROXIMITY` + + To deregister the proximity sensing, you can call :cpp:func:`touch_sensor_config_proximity_sensing` again, and set the second parameter (i.e. :cpp:type:`touch_proximity_config_t` pointer) to ``NULL``. + + .. code-block:: c + + touch_proximity_config_t prox_cfg = { + // Proximity sensing configuration + // ... + }; + // Register the proximity sensing + ESP_ERROR_CHECK(touch_sensor_config_proximity_sensing(sens_handle, &prox_cfg)); + // ... + // Deregister the proximity sensing + ESP_ERROR_CHECK(touch_sensor_config_proximity_sensing(sens_handle, NULL)); + +.. _touch-sleep-wakeup: + +.. only:: SOC_TOUCH_SUPPORT_SLEEP_WAKEUP + + Sleep Wake-up Configuration + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} supports waking-up the chip from light sleep or deep sleep with the touch sensor as a wake-up source. The wake-up functionality can be registered by calling :cpp:func:`touch_sensor_config_sleep_wakeup` and specifying the configurations :cpp:type:`touch_sleep_config_t`. + + After registering the touch sensor sleep wake-up, the chip will continue to sample the touch channels after sleep, which will increase the power consumption during the sleep. To reduce the sleep power consumption, you can reduce the number of charging and discharging times, increase the sampling interval, etc. + + Moreover, please note that the operations like sampling, wake-up are all done by hardware when the main core is sleeping. Since this driver runs on the main core, it cannot provide functions such as reading or configuring during the sleep. + + .. only:: SOC_RISCV_COPROC_SUPPORTED + + If you want to read or configure the touch sensor during the sleep, you can turn to the driver ``components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_touch_ulp_core.h`` which based on the :doc:`Ultra Low Power (ULP) Coprocessor <../system/ulp>`. + + - Light sleep wake-up: you need to set :cpp:member:`slp_wakeup_lvl` to :cpp:enumerator:`TOUCH_LIGHT_SLEEP_WAKEUP` to enable the light sleep wake-up by touch sensor. Note that any registered touch channel can wake-up the chip from light sleep. + - Deep sleep wake-up: beside setting :cpp:member:`slp_wakeup_lvl` to :cpp:enumerator:`TOUCH_DEEP_SLEEP_WAKEUP`, you need to specify :cpp:member:`deep_slp_chan` additionally. Only the specified channel can wake-up the chip from the deep sleep, in order to reduce the power consumption. And also, the driver supports to store another set of configurations for the deep sleep via :cpp:member:`deep_slp_sens_cfg`, this set of configurations only takes effect during the deep sleep, you can customize the configurations to save more power. The configurations will be reset to the previous set after waking-up from the deep sleep. Please be aware that, not only deep sleep wake-up, but also light sleep wake-up will be enabled when the :cpp:member:`slp_wakeup_lvl` is :cpp:enumerator:`TOUCH_DEEP_SLEEP_WAKEUP`. + + To deregister the sleep wake-up function, you can call :cpp:func:`touch_sensor_config_sleep_wakeup` again, and set the second parameter (i.e. :cpp:type:`touch_sleep_config_t` pointer) to ``NULL``. + + .. code-block:: c + + touch_sleep_config_t light_slp_cfg = { + .slp_wakeup_lvl = TOUCH_LIGHT_SLEEP_WAKEUP, + }; + // Register the light sleep wake-up + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, &light_slp_cfg)); + // ... + // Deregister the light sleep wake-up + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, NULL)); + touch_sleep_config_t deep_slp_cfg = { + .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP, + .deep_slp_chan = dslp_chan_handle, + // Other deep sleep configurations + // ... + }; + // Register the deep sleep wake-up + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, &deep_slp_cfg)); + +Application Examples +------------------------ + +.. only:: esp32p4 + + - Touch sensor basic example: :example:`peripherals/touch_sensor/touch_sensor_{IDF_TARGET_TOUCH_SENSOR_VERSION}`. + +API 参考 +------------- + +.. only:: esp32p4 + + .. include-build-file:: inc/touch_sens.inc + .. include-build-file:: inc/touch_sens_types.inc + .. include-build-file:: inc/touch_version_types.inc + diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index fa847069b12..3a959b72490 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -42,7 +42,8 @@ Peripherals API :SOC_GPSPI_SUPPORTED: spi_slave :SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd :SOC_TEMP_SENSOR_SUPPORTED: temp_sensor - :SOC_TOUCH_SENSOR_SUPPORTED: touch_pad + :SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad + :esp32p4: cap_touch_sens :esp32s2: touch_element :SOC_TWAI_SUPPORTED: twai uart diff --git a/docs/zh_CN/api-reference/peripherals/cap_touch_sens.rst b/docs/zh_CN/api-reference/peripherals/cap_touch_sens.rst new file mode 100644 index 00000000000..de4928883de --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/cap_touch_sens.rst @@ -0,0 +1,415 @@ +电容式触摸传感器 +=================== + +:link_to_translation:`en:[English]` + +{IDF_TARGET_TOUCH_SENSOR_VERSION:default="NOT_UPDATED", esp32p4="v3"} + +概述 +------------ + +触摸传感器系统由保护覆盖层、触摸电极、绝缘基板和走线组成,保护覆盖层位于最上层,绝缘基板上设有电极及走线。触摸覆盖层将引起电容变化,根据电容变化,可以判断此次触摸是否为有效触摸行为。 + +触摸传感器可以以矩阵或滑条等方式组合使用,从而覆盖更大触感区域及更多触感点。触摸传感由软件或专用硬件计时器发起,由有限状态机 (FSM) 硬件控制。 + +如需了解触摸传感器设计、操作及其控制寄存器等相关信息,请参考《`{IDF_TARGET_NAME} 技术参考手册 <{IDF_TARGET_TRM_CN_URL}>`_》(PDF) 中“片上传感器与模拟信号处理”章节。 + +请参考 `触摸传感器应用方案简介 `_,查看触摸传感器设计详情和固件开发指南。 + +电容式触摸传感器版本概览 +------------------------- + ++-----------+--------------+------------------------------------------------------------------------+ +| 硬件版本 | 芯片 | 主要特征 | ++===========+==============+========================================================================+ +| V1 | ESP32 | 第一代触摸传感器,触摸时读数变小 | ++-----------+--------------+------------------------------------------------------------------------+ +| V2 | ESP32-S2 | 第二代触摸传感器,触摸时读数变大 | +| | | 新增防水防潮、接近感应、睡眠唤醒功能 | +| +--------------+------------------------------------------------------------------------+ +| | ESP32-S3 | 第二代触摸传感器,新增接近感应测量完成中断 | ++-----------+--------------+------------------------------------------------------------------------+ +| V3 | ESP32-P4 | 第三代触摸传感器,新增跳频扫描 | ++-----------+--------------+------------------------------------------------------------------------+ + +触摸通道概览 +---------------------- + +.. only:: esp32p4 + + ====== ===== ===== ===== ===== ===== ===== ===== ===== ====== ====== ====== ====== ====== ====== ========== + 通道 CH0 CH1 CH2 CH3 CH4 CH5 CH6 CH7 CH8 CH9 CH10 CH11 CH12 CH13 CH14 + ------ ----- ----- ----- ----- ----- ----- ----- ----- ------ ------ ------ ------ ------ ------ ---------- + GPIO IO2 IO3 IO4 IO5 IO6 IO7 IO8 IO9 IO10 IO11 IO12 IO13 IO14 IO15 未引出 + ====== ===== ===== ===== ===== ===== ===== ===== ===== ====== ====== ====== ====== ====== ====== ========== + +驱动中的术语介绍 +------------------------- + +- **触摸传感器控制器**:触摸传感器驱动的控制器,负责触摸传感器的配置和管理。 +- **触摸传感器通道**:具体的一路触摸传感器采样通道。一个触摸传感器模块具有多个通道,一般连接到触摸板上,用于测量该触摸板电容的变化。驱动中把对 **一个** 通道的采样称为 ``测量``,而对 **所有** 注册通道的 ``测量`` 称为一次 ``扫描``。 + +.. only:: IDF_TARGET_TOUCH_SAMPLE_CFG_DESC + + - **触摸传感器采样配置**:触摸传感器采样配置是驱动中对采样有关的硬件配置的统称。采样配置负责触摸传感器通道的采样,其配置决定了触摸通道的充放电次数、充放电频率、测量间隔等。{IDF_TARGET_NAME} 支持多套采样配置,支持跳频采样。 + +.. only:: not IDF_TARGET_TOUCH_SAMPLE_CFG_DESC + + - **触摸传感器采样配置**:触摸传感器采样配置是驱动中对采样有关的硬件配置的统称。采样配置负责触摸传感器通道的采样,其配置决定了触摸通道的充放电次数、充放电频率、测量间隔等。{IDF_TARGET_NAME} 仅支持一套采样配置,不支持跳频采样。 + +文件结构 +-------------------- + +.. figure:: ../../../_static/diagrams/cap_touch_sens/touch_file_structure.svg + :align: center + :alt: 触摸传感器驱动文件结构图 + + 触摸传感器驱动文件结构图 + +驱动状态机 +--------------------- + +下图为触摸传感器驱动的状态机,描述了调用不同函数后驱动的运行状态,以及状态变迁的约束。 + +.. figure:: ../../../_static/diagrams/cap_touch_sens/touch_state_machine.svg + :align: center + :alt: 触摸传感器驱动状态机示意图 + + 触摸传感器驱动状态机示意图 + +上图为触摸传感器驱动的状态机,描述了调用不同函数后状态的变换关系。其中 ```` 部分为可选的配置项,包括对触摸驱动控制器和触摸通道的重新配置、回调函数注册等。 + +.. note:: + + :cpp:func:`touch_channel_read_data` 可在获取触摸通道句柄后(即 ``INIT`` 后)任意状态调用,但请注意读数值的有效性。 + +功能介绍 +------------------ + +{IDF_TARGET_NAME} 的电容式触摸传感器驱动提供的 API 按功能主要可分为: + +.. list:: + + - `触摸传感器控制器管理 <#touch-ctrl>`__ + - `触摸传感器通道管理 <#touch-chan>`__ + - `滤波器配置 <#touch-filter>`__ + - `回调函数 <#touch-callback>`__ + - `启用和禁用 <#touch-enable>`__ + - `连续扫描 <#touch-conti-scan>`__ + - `单次扫描 <#touch-oneshot-scan>`__ + - `基线值配置 <#touch-benchmark>`__ + - `测量值读数 <#touch-read>`__ + :SOC_TOUCH_SUPPORT_WATERPROOF: - `防水防潮配置 <#touch-waterproof>`__ + :SOC_TOUCH_SUPPORT_PROX_SENSING: - `接近感应配置 <#touch-prox-sensing>`__ + :SOC_TOUCH_SUPPORT_SLEEP_WAKEUP: - `睡眠唤醒配置 <#touch-sleep-wakeup>`__ + +.. _touch-ctrl: + +触摸传感器控制器管理 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +触摸传感器驱动通过触摸传感器控制器句柄 :cpp:type:`touch_sensor_handle_t` 控制。调用 :cpp:func:`touch_sensor_new_controller` 函数即可初始化触摸传感器控制器并得到控制器句柄。 + +.. code-block:: c + + // 有些芯片支持多套采样配置,这里以一套为例 + #define SAMPLE_NUM 1 + touch_sensor_handle_t sens_handle = NULL; + // 采样配置 + touch_sensor_sample_config_t sample_cfg[SAMPLE_NUM] = { + // 指定采样配置或通过 `TOUCH_SENSOR_Vn_DEFAULT_SAMPLE_CONFIG` 使用默认采样配置 + // ... + }; + // 默认控制器配置 + touch_sensor_config_t touch_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(SAMPLE_NUM, sample_cfg); + // 申请一个新的触摸传感器控制器句柄 + ESP_ERROR_CHECK(touch_sensor_new_controller(&touch_cfg, &sens_handle)); + +删除触摸传感器驱动控制器时需调用 :cpp:func:`touch_sensor_del_controller` 函数,从而释放该控制器所占用的软硬件资源。注意,需要将基于该控制器申请的其他资源销毁或释放后才能删除该控制器。如该控制器下仍有触摸通道未被删除,则无法直接删除。 + +.. code-block:: c + + ESP_ERROR_CHECK(touch_sensor_del_controller(sens_handle)); + +在触摸传感器驱动控制器初始化后,且未启用触摸传感器时,可调用 :cpp:func:`touch_sensor_reconfig_controller` 函数对该控制器进行重新配置。 + +.. code-block:: c + + touch_sensor_config_t touch_cfg = { + // 控制器的新配置 + // ... + }; + ESP_ERROR_CHECK(touch_sensor_reconfig_controller(sens_handle, &touch_cfg)); + +.. _touch-chan: + +触摸传感器通道管理 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +一个触摸传感器具有多个测量通道,每个触摸传感器通道由句柄 :cpp:type:`touch_channel_handle_t` 控制。调用 :cpp:func:`touch_sensor_new_channel` 函数即可初始化触摸传感器通道并得到通道句柄。 + +.. code-block:: c + + // ... + touch_channel_config_t chan_cfg = { + // 触摸通道配置 + // ... + }; + touch_channel_handle_t chan_handle = NULL; + int chan_id = 0; + // 申请一个新的触摸通道句柄 + ESP_ERROR_CHECK(touch_sensor_new_channel(sens_handle, chan_id, &chan_cfg, &chan_handle)); + +删除触摸传感器通道时需调用 :cpp:func:`touch_sensor_del_channel` 函数,从而释放该通道所占用的软硬件资源。 + +.. code-block:: c + + ESP_ERROR_CHECK(touch_sensor_del_channel(chan_handle)); + +在触摸传感器驱动通道初始化后,且未启用触摸传感器时,可调用 :cpp:func:`touch_sensor_reconfig_channel` 函数对该通道进行重新配置。 + +.. code-block:: c + + touch_channel_config_t chan_cfg = { + // 触摸通道新配置 + // ... + }; + ESP_ERROR_CHECK(touch_sensor_reconfig_channel(chan_handle, &chan_cfg)); + +.. _touch-filter: + +滤波器配置 +^^^^^^^^^^^^^^ + +触摸传感器可以通过配置滤波器来提升不同场景下的数据稳定性。调用 :cpp:func:`touch_sensor_config_filter` 并指定 :cpp:type:`touch_sensor_filter_config_t` 来配置基线值和读数值的滤波策略和更新方式,配置后对所有启用的触摸通道都生效。 + +若需要注销滤波器,可再次调用 :cpp:func:`touch_sensor_config_filter` 并将第二个参数(即 :cpp:type:`touch_sensor_filter_config_t` 的配置结构体指针)设为 ``NULL`` 来注销滤波器功能。 + +.. code-block:: c + + // ... + touch_sensor_filter_config_t filter_config = { + // 滤波器配置 + // ... + }; + // 注册滤波器 + ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, &filter_config)); + // ... + // 注销滤波器 + ESP_ERROR_CHECK(touch_sensor_config_filter(sens_handle, NULL)); + +.. _touch-callback: + +回调函数 +^^^^^^^^^^^^^ + +通过调用 :cpp:func:`touch_sensor_register_callbacks` 注册各类触摸传感器事件回调函数,当触摸传感器通道触发如触摸 ``on_active``、释放 ``on_inactive`` 等事件时,就会调用对应的回调函数通知上层应用,以便对触摸事件进行处理。 + +例如,测量值超出当前的测量通道的 ``基线值`` + ``触发阈值``,则该通道将被触发,并调用 ``on_active`` 事件的回调函数,通知应用层该触摸通道被 ``触发``。同理,若处于 ``触发`` 状态的通道测量值小于 ``基线值`` + ``触发阈值``,则该通道将回到未触发状态,并调用 ``on_inactive`` 事件的回调函数,通知应用层该触摸通道被 ``释放``。 + +.. note:: + + 为保证触发和释放事件的稳定性,触摸传感器可配置 ``触发阈值`` 的迟滞比较裕量和 ``去抖动计数`` 来避免短时间内由噪声和读数抖动引起的反复触发和释放 + +具体可注册的回调时间请参考 :cpp:type:`touch_event_callbacks_t`。 + +.. code-block:: c + + touch_event_callbacks_t callbacks = { + .on_active = example_touch_on_active_cb, + // 其他回调函数 + // ... + }; + // 注册回调函数 + ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens_handle, &callbacks, NULL)); + + // 通过把相应回调设为 NULL 以注销回调函数 + callbacks.on_active = NULL; + // 其他需要注销的回调函数 + // ... + ESP_ERROR_CHECK(touch_sensor_register_callbacks(sens_handle, &callbacks, NULL)); + +.. _touch-enable: + +启用和禁用 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +配置完成触摸传感器控制器以及通道后,可调用 :cpp:func:`touch_sensor_enable` 函数启用该控制器,启用后控制器处于 ``就绪`` 状态,会对注册的通道上电,可以开始扫描并采集触摸数据。注意,控制器启用后无法更新配置,只能进行扫描采样和读数操作。若要更新配置,需先调用 :cpp:func:`touch_sensor_disable` 函数禁用控制器,方可重新配置控制器、通道等。 + +.. code-block:: c + + // 启用触摸传感器 + ESP_ERROR_CHECK(touch_sensor_enable(sens_handle)); + // ... + // 禁用触摸传感器 + ESP_ERROR_CHECK(touch_sensor_disable(sens_handle)); + +.. _touch-conti-scan: + +连续扫描 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +在控制器启用后,调用 :cpp:func:`touch_sensor_start_continuous_scanning` 函数可开始对所有已注册的触摸通道进行连续扫描,每次扫描都会更新对应通道的测量值。调用 :cpp:func:`touch_sensor_stop_continuous_scanning` 函数后则停止扫描。 + +.. code-block:: c + + // 开始连续扫描 + ESP_ERROR_CHECK(touch_sensor_start_continuous_scanning(sens_handle)); + // ... + // 停止连续扫描 + ESP_ERROR_CHECK(touch_sensor_stop_continuous_scanning(sens_handle)); + +.. _touch-oneshot-scan: + +单次扫描 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +在控制器启用后,调用 :cpp:func:`touch_sensor_trigger_oneshot_scanning` 函数可触发一次对所有已注册的触摸通道的扫描。注意,单次扫描为阻塞函数,调用后会保持阻塞直到扫描结束后返回。此外在开始连续扫描后,无法再触发单次扫描。 + +.. code-block:: c + + // 触发单次扫描,并设置超时时间为 1000ms + ESP_ERROR_CHECK(touch_sensor_trigger_oneshot_scanning(sens_handle, 1000)); + +.. _touch-benchmark: + +基线值配置 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +一般情况下,不需要额外设置触摸传感器的基线值,若有必要强制复位基线值到当前平滑值,可调用 :cpp:func:`touch_channel_config_benchmark`。 + +.. code-block:: c + + touch_chan_benchmark_config_t benchmark_cfg = { + // 基线操作 + // ... + }; + ESP_ERROR_CHECK(touch_channel_config_benchmark(chan_handle, &benchmark_cfg)); + +.. _touch-read: + +测量值读数 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +调用 :cpp:func:`touch_channel_read_data` 可读取每个通道不同种类的数据,例如基线值、经过滤波后的平滑值等。支持的数据类型请参考 :cpp:type:`touch_chan_data_type_t`。 + +.. only:: SOC_TOUCH_SUPPORT_FREQ_HOP + + {IDF_TARGET_NAME} 支持通过配置多套采样配置来实现跳频采样,:cpp:func:`touch_channel_read_data` 可一次性读出一个通道所有采样配置的测量值。根据配置的 :cpp:member:`touch_sensor_config_t::sample_cfg_num` 采样配置数量,第三个参数 (``*data``) 数据指针传入数组长度大于等于采样配置数量的数组指针即可,该函数会将所指定通道的所有采样配置的测量值存入该数组中。 + +.. code-block:: c + + #define SAMPLE_NUM 1 // 以一套采样配置为例 + uint32_t smooth_data[SAMPLE_NUM] = {}; + // 读取滤波后的平滑数据 + ESP_ERROR_CHECK(touch_channel_read_data(chan_handle, TOUCH_CHAN_DATA_TYPE_SMOOTH, smooth_data)); + +.. _touch-waterproof: + +.. only:: SOC_TOUCH_SUPPORT_WATERPROOF + + 防水防潮配置 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} 支持防水防潮功能。可通过调用 :cpp:func:`touch_sensor_config_waterproof` 并配置 :cpp:type:`touch_waterproof_config_t` 来注册防水防潮功能。防水防潮功能主要包含两部分: + + - 遇水(浸没)保护功能: :cpp:member:`touch_waterproof_config_t::guard_chan` 用于指定用于遇水保护功能的触摸通道,该通道在 PCB 上一般设计成环形,其他普通触摸通道布局在该环形保护圈内,当电路板大面积浸水时,该环形保护通道会被触发,并停止其他触摸通道的扫描,由此防止其他普通通道的误触发; + - 防潮(水滴)屏蔽功能: :cpp:member:`touch_waterproof_config_t::shield_chan` 用于指定防潮屏蔽功能的触摸通道,该通道在 PCB 上一般设计成网格状铺铜。防潮屏蔽通道将与当前测量通道进行同步充放电,当有小水珠覆盖时,通过配置适当的 :cpp:member:`touch_waterproof_config_t::shield_drv` 来提高因水滴造成的电耦合强度,从而识别水滴造成的误触。在实际应用中识别到水滴造成的误触后可适当增加触摸通道触发的阈值来实现通道在水滴覆盖下的正常触发,从而实现防潮功能。 + + 若需要注销防水防潮功能,可再次调用 :cpp:func:`touch_sensor_config_waterproof` 并将第二个参数(即 :cpp:type:`touch_waterproof_config_t` 的配置结构体指针)设为 ``NULL`` 来注销防水防潮功能。 + + .. code-block:: c + + touch_waterproof_config_t waterproof_cfg = { + // 防水防潮配置 + // ... + }; + // 注册防水防潮功能 + ESP_ERROR_CHECK(touch_sensor_config_waterproof(sens_handle, &waterproof_cfg)); + // ... + // 注销防水防潮功能 + ESP_ERROR_CHECK(touch_sensor_config_waterproof(sens_handle, NULL)); + +.. _touch-prox-sensing: + +.. only:: SOC_TOUCH_SUPPORT_PROX_SENSING + + 接近感应配置 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} 支持接近感应功能。可通过调用 :cpp:func:`touch_sensor_config_proximity_sensing` 并配置 :cpp:type:`touch_proximity_config_t` 来注册接近感应功能。 + + 由于接近感应引起的电容变化远小于物理触摸,PCB 上常用较大面积的铺铜来增大触摸通道的感应面积,另外需要在硬件上对接近感应通道进行多轮扫描并在驱动中进行累加来提高测量灵敏度。接近感应的灵敏度由测量轮数 :cpp:member:`touch_proximity_config_t::scan_times` 以及单次测量的充放电次数 :cpp:member:`touch_proximity_config_t::charge_times` 决定。测量轮数以及充放电次数越高,灵敏度越高,但是过高的灵敏度容易导致误触发,请选择适当的灵敏度来保证触发的稳定性。 + + 接近感应通道多次测量的累加值也可通过 :cpp:func:`touch_channel_read_data` 获取,数据类型 :cpp:type:`touch_chan_data_type_t` 为 :cpp:enumerator:`TOUCH_CHAN_DATA_TYPE_PROXIMITY`。 + + 若需要注销接近感应功能,可再次调用 :cpp:func:`touch_sensor_config_proximity_sensing` 并将第二个参数(即 :cpp:type:`touch_proximity_config_t` 的配置结构体指针)设为 ``NULL`` 来注销接近感应功能。 + + .. code-block:: c + + touch_proximity_config_t prox_cfg = { + // 接近感应配置 + // ... + }; + // 注册接近感应功能 + ESP_ERROR_CHECK(touch_sensor_config_proximity_sensing(sens_handle, &prox_cfg)); + // ... + // 注销接近感应功能 + ESP_ERROR_CHECK(touch_sensor_config_proximity_sensing(sens_handle, NULL)); + +.. _touch-sleep-wakeup: + +.. only:: SOC_TOUCH_SUPPORT_SLEEP_WAKEUP + + 睡眠唤醒配置 + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + {IDF_TARGET_NAME} 支持触摸传感器将芯片从浅睡眠或深睡眠状态中唤醒。可通过调用 :cpp:func:`touch_sensor_config_sleep_wakeup` 并配置 :cpp:type:`touch_sleep_config_t` 来注册接近感应功能。 + + 注册触摸传感器的睡眠唤醒功能后,处于睡眠状态下的芯片仍将继续保持对触摸传感器的采样,这将会导致芯片睡眠后的功耗增加,可通过减少充放电次数、增加采样间隔等方式来降低功耗。 + + 另外,请注意在主核睡眠期间的采样、唤醒等操作均由硬件完成,本驱动由于运行在主核上,无法提供读数、配置等功能。 + + .. only:: SOC_RISCV_COPROC_SUPPORTED + + 若需要在睡眠过程中进行读数、配置等操作,可通过运行在 :doc:`超低功耗协处理器 ULP <../system/ulp>` 上的触摸传感器驱动 ``components/ulp/ulp_riscv/ulp_core/include/ulp_riscv_touch_ulp_core.h`` 实现。 + + - 浅睡眠状态唤醒:通过指定 :cpp:member:`slp_wakeup_lvl` 为 :cpp:enumerator:`TOUCH_LIGHT_SLEEP_WAKEUP` 即可启用触摸传感器浅睡眠唤醒功能。注意任何已注册的触摸传感器通道都会在浅睡眠状态下保持采样并支持唤醒浅睡眠。 + - 深睡眠状态唤醒:启用触摸传感器深睡眠唤醒功能除了指定 :cpp:member:`slp_wakeup_lvl` 为 :cpp:enumerator:`TOUCH_DEEP_SLEEP_WAKEUP` 外,还需要指定深睡眠唤醒通道 :cpp:member:`deep_slp_chan`,注意只有该指定的通道才会在深睡眠状态下保持采样以及唤醒,以此降低在深睡眠状态下的功耗。此外,若需要在深度睡眠下使用另一套低功耗的配置来进一步降低功耗,可以通过 :cpp:member:`deep_slp_sens_cfg` 额外指定一套低功耗配置,在进入深睡眠前,驱动会应用这套配置,从深睡眠状态唤醒后,则会重新配置到之前的配置。请注意当 :cpp:member:`slp_wakeup_lvl` 配置为 :cpp:enumerator:`TOUCH_DEEP_SLEEP_WAKEUP` 后,触摸传感器不仅能唤醒深睡眠状态,还能唤醒浅睡眠状态。 + + 若需要注销睡眠唤醒功能,可再次调用 :cpp:func:`touch_sensor_config_sleep_wakeup` 并将第二个参数(即 :cpp:type:`touch_sleep_config_t` 的配置结构体指针)设为 ``NULL`` 来注销睡眠唤醒功能。 + + .. code-block:: c + + touch_sleep_config_t light_slp_cfg = { + .slp_wakeup_lvl = TOUCH_LIGHT_SLEEP_WAKEUP, + }; + // 注册浅睡眠唤醒功能 + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, &light_slp_cfg)); + // ... + // 注销睡眠唤醒功能 + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, NULL)); + touch_sleep_config_t deep_slp_cfg = { + .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP, + .deep_slp_chan = dslp_chan_handle, + // 其他深睡眠唤醒配置 + // ... + }; + // 注册深睡眠唤醒功能 + ESP_ERROR_CHECK(touch_sensor_config_sleep_wakeup(sens_handle, &deep_slp_cfg)); + +应用示例 +-------------------- + +.. only:: esp32p4 + + - 触摸传感器基础例程: :example:`peripherals/touch_sensor/touch_sensor_{IDF_TARGET_TOUCH_SENSOR_VERSION}`. + +API 参考 +------------- + +.. only:: esp32p4 + + .. include-build-file:: inc/touch_sens.inc + .. include-build-file:: inc/touch_sens_types.inc + .. include-build-file:: inc/touch_version_types.inc diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 0171c6a5d7d..ea2198b57a3 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -42,7 +42,8 @@ :SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd :SOC_JPEG_CODEC_SUPPORTED: jpeg :SOC_TEMP_SENSOR_SUPPORTED: temp_sensor - :SOC_TOUCH_SENSOR_SUPPORTED: touch_pad + :SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad + :esp32p4: cap_touch_sens :esp32s2: touch_element :SOC_TWAI_SUPPORTED: twai uart diff --git a/examples/peripherals/touch_sensor/touch_periph_version.txt b/examples/peripherals/touch_sensor/README.md similarity index 100% rename from examples/peripherals/touch_sensor/touch_periph_version.txt rename to examples/peripherals/touch_sensor/README.md diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt b/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt index b88a846c5aa..8c6b0002d3b 100644 --- a/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "touch_sens_v3_example_main.c" - PRIV_REQUIRES esp_driver_touch_sens + REQUIRES esp_driver_touch_sens INCLUDE_DIRS ".") diff --git a/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c b/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c index 4eeb1c91bc8..77d37045f08 100644 --- a/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c +++ b/examples/peripherals/touch_sensor/touch_sensor_v3/main/touch_sens_v3_example_main.c @@ -9,11 +9,10 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/touch_sens.h" -#include "soc/lp_analog_peri_struct.h" #include "esp_check.h" // Touch version 3 supports multiple sample configurations -#define EXAMPLE_TOUCH_SAMPLE_CFG_NUM TOUCH_SAMPLE_CFG_NUM +#define EXAMPLE_TOUCH_SAMPLE_CFG_NUM 1 // Up to 'TOUCH_SAMPLE_CFG_NUM' #define EXAMPLE_TOUCH_CHANNEL_NUM 4 #define EXAMPLE_TOUCH_CHAN_INIT_SCAN_TIMES 3 @@ -21,7 +20,7 @@ static touch_sensor_handle_t s_sens_handle = NULL; static touch_channel_handle_t s_chan_handle[EXAMPLE_TOUCH_CHANNEL_NUM] = {}; // Active threshold to benchmark ratio. (i.e., touch will be activated when data >= benchmark * (1 + ratio)) static float s_thresh2bm_ratio[EXAMPLE_TOUCH_CHANNEL_NUM] = { - [0 ... EXAMPLE_TOUCH_CHANNEL_NUM - 1] = 0.02f, // 2% + [0 ... EXAMPLE_TOUCH_CHANNEL_NUM - 1] = 0.015f, // 1.5% }; bool example_touch_on_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) @@ -59,7 +58,7 @@ static void example_touch_do_initial_scanning(void) printf("[CH %d]", i); touch_channel_config_t chan_cfg = {}; for (int j = 0; j < EXAMPLE_TOUCH_SAMPLE_CFG_NUM; j++) { - chan_cfg.active_thresh[j] = (uint32_t)(benchmark[j] * s_thresh2bm_ratio[j]); + chan_cfg.active_thresh[j] = (uint32_t)(benchmark[j] * s_thresh2bm_ratio[i]); printf(" %d: %"PRIu32", %"PRIu32"\t", j, benchmark[j], chan_cfg.active_thresh[j]); } printf("\n"); @@ -72,12 +71,12 @@ void app_main(void) { /* Use the default sample configurations */ touch_sensor_sample_config_t sample_cfg[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = { - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1), #if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1 - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(2, 1, 1), #endif #if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2 - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(4, 1, 1), #endif }; /* Allocate new touch controller handle */ @@ -108,12 +107,12 @@ void app_main(void) * Step3: adjust the `s_thresh2bm_ratio` to a proper value to trigger the active callback */ .active_thresh = { - 5000, // estimated active threshold of sample configuration 0 + 1000, // estimated active threshold of sample configuration 0 #if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 1 2500, // estimated active threshold of sample configuration 1 #endif #if EXAMPLE_TOUCH_SAMPLE_CFG_NUM > 2 - 1000, // estimated active threshold of sample configuration 2 + 5000, // estimated active threshold of sample configuration 2 #endif }, }; diff --git a/examples/system/light_sleep/main/touch_sens_wakeup.c b/examples/system/light_sleep/main/touch_sens_wakeup.c index fbf6c6fcc54..22354c05762 100644 --- a/examples/system/light_sleep/main/touch_sens_wakeup.c +++ b/examples/system/light_sleep/main/touch_sens_wakeup.c @@ -66,7 +66,7 @@ esp_err_t example_register_touch_wakeup(void) { touch_sensor_handle_t sens_handle = NULL; touch_sensor_sample_config_t sample_cfg[EXAMPLE_TOUCH_SAMPLE_CFG_NUM] = { - TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), + TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG(1, 1, 1), }; touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(EXAMPLE_TOUCH_SAMPLE_CFG_NUM, sample_cfg); ESP_ERROR_CHECK(touch_sensor_new_controller(&sens_cfg, &sens_handle)); From 96e370f9bb6048f2b05cddde9263f4015c1dda40 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 13 Jun 2024 11:28:35 +0800 Subject: [PATCH 365/548] fix(touch): fix driver coverity issue --- .../hw_ver3/touch_version_specific.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c index bd990ba47d8..acc88c09c55 100644 --- a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c +++ b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c @@ -326,10 +326,10 @@ esp_err_t touch_sensor_config_sleep_wakeup(touch_sensor_handle_t sens_handle, co xSemaphoreTake(sens_handle->mutex, portMAX_DELAY); ESP_GOTO_ON_FALSE(!sens_handle->is_enabled, ESP_ERR_INVALID_STATE, err, TAG, "Please disable the touch sensor first"); - ESP_GOTO_ON_FALSE(sleep_cfg->slp_wakeup_lvl == TOUCH_LIGHT_SLEEP_WAKEUP || sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP, - ESP_ERR_INVALID_ARG, err, TAG, "Invalid sleep level"); if (sleep_cfg) { + ESP_GOTO_ON_FALSE(sleep_cfg->slp_wakeup_lvl == TOUCH_LIGHT_SLEEP_WAKEUP || sleep_cfg->slp_wakeup_lvl == TOUCH_DEEP_SLEEP_WAKEUP, + ESP_ERR_INVALID_ARG, err, TAG, "Invalid sleep level"); /* Enabled touch sensor as wake-up source */ ESP_GOTO_ON_ERROR(esp_sleep_enable_touchpad_wakeup(), err, TAG, "Failed to enable touch sensor wakeup"); #if SOC_PM_SUPPORT_RC_FAST_PD @@ -408,7 +408,9 @@ esp_err_t touch_sensor_config_waterproof(touch_sensor_handle_t sens_handle, cons touch_ll_waterproof_enable(false); touch_ll_waterproof_set_guard_chan(TOUCH_LL_NULL_CHANNEL); touch_ll_waterproof_set_shield_chan_mask(0); - touch_ll_enable_scan_mask(BIT(wp_cfg->shield_chan->id), true); + if (sens_handle->shield_chan) { + touch_ll_enable_scan_mask(BIT(sens_handle->shield_chan->id), true); + } touch_ll_waterproof_set_shield_driver(0); sens_handle->guard_chan = NULL; sens_handle->shield_chan = NULL; From a77531709177d2d94216e6dee846604e38d837a7 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 17 Jun 2024 15:39:26 +0800 Subject: [PATCH 366/548] refactor(lp_ana_periph): sync the reg names to TRM --- .../hal/esp32p4/include/hal/touch_sensor_ll.h | 8 ++-- .../esp32p4/include/soc/lp_analog_peri_reg.h | 42 +++++++++---------- .../include/soc/lp_analog_peri_struct.h | 16 +++---- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/components/hal/esp32p4/include/hal/touch_sensor_ll.h b/components/hal/esp32p4/include/hal/touch_sensor_ll.h index 1bb9286bf3d..b8f1d625fc4 100644 --- a/components/hal/esp32p4/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32p4/include/hal/touch_sensor_ll.h @@ -724,10 +724,10 @@ static inline void touch_ll_filter_set_neg_noise_thresh(int neg_noise_thresh, ui { bool always_update = neg_noise_thresh == -1; bool stop_update = neg_noise_thresh == -2; - LP_ANA_PERI.touch_filter2.touch_bypass_neg_noise_thres = always_update; - LP_ANA_PERI.touch_filter1.touch_neg_noise_disupdate_baseline_en = stop_update; - LP_ANA_PERI.touch_filter1.touch_neg_noise_thres = always_update || stop_update ? 0 : neg_noise_thresh; - LP_ANA_PERI.touch_filter1.touch_neg_noise_limit = always_update || stop_update ? 5 : neg_noise_limit; // 5 is the default value + LP_ANA_PERI.touch_filter2.touch_bypass_nn_thres = always_update; + LP_ANA_PERI.touch_filter1.touch_nn_disupdate_baseline_en = stop_update; + LP_ANA_PERI.touch_filter1.touch_nn_thres = always_update || stop_update ? 0 : neg_noise_thresh; + LP_ANA_PERI.touch_filter1.touch_nn_limit = always_update || stop_update ? 5 : neg_noise_limit; // 5 is the default value } /** diff --git a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h index 68fcde9d0d3..cfd26fd0164 100644 --- a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h +++ b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -619,13 +619,13 @@ extern "C" { * need_des */ #define LP_ANALOG_PERI_TOUCH_FILTER1_REG (DR_REG_LP_ANALOG_PERI_BASE + 0x110) -/** LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN : R/W; bitpos: [0]; default: 0; +/** LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN : R/W; bitpos: [0]; default: 0; * Reserved */ -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN (BIT(0)) -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN_M (LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN_V << LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN_S) -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN_V 0x00000001U -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_DISUPDATE_BASELINE_EN_S 0 +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN (BIT(0)) +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_M (LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_V << LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_S) +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_V 0x00000001U +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_S 0 /** LP_ANALOG_PERI_TOUCH_HYSTERESIS : R/W; bitpos: [2:1]; default: 0; * need_des */ @@ -633,13 +633,13 @@ extern "C" { #define LP_ANALOG_PERI_TOUCH_HYSTERESIS_M (LP_ANALOG_PERI_TOUCH_HYSTERESIS_V << LP_ANALOG_PERI_TOUCH_HYSTERESIS_S) #define LP_ANALOG_PERI_TOUCH_HYSTERESIS_V 0x00000003U #define LP_ANALOG_PERI_TOUCH_HYSTERESIS_S 1 -/** LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES : R/W; bitpos: [4:3]; default: 0; +/** LP_ANALOG_PERI_TOUCH_NN_THRES : R/W; bitpos: [4:3]; default: 0; * need_des */ -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES 0x00000003U -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES_M (LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES_V << LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES_S) -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES_V 0x00000003U -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_THRES_S 3 +#define LP_ANALOG_PERI_TOUCH_NN_THRES 0x00000003U +#define LP_ANALOG_PERI_TOUCH_NN_THRES_M (LP_ANALOG_PERI_TOUCH_NN_THRES_V << LP_ANALOG_PERI_TOUCH_NN_THRES_S) +#define LP_ANALOG_PERI_TOUCH_NN_THRES_V 0x00000003U +#define LP_ANALOG_PERI_TOUCH_NN_THRES_S 3 /** LP_ANALOG_PERI_TOUCH_NOISE_THRES : R/W; bitpos: [6:5]; default: 0; * need_des */ @@ -675,13 +675,13 @@ extern "C" { #define LP_ANALOG_PERI_TOUCH_FILTER_EN_M (LP_ANALOG_PERI_TOUCH_FILTER_EN_V << LP_ANALOG_PERI_TOUCH_FILTER_EN_S) #define LP_ANALOG_PERI_TOUCH_FILTER_EN_V 0x00000001U #define LP_ANALOG_PERI_TOUCH_FILTER_EN_S 16 -/** LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT : R/W; bitpos: [20:17]; default: 5; +/** LP_ANALOG_PERI_TOUCH_NN_LIMIT : R/W; bitpos: [20:17]; default: 5; * need_des */ -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT 0x0000000FU -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT_M (LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT_V << LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT_S) -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT_V 0x0000000FU -#define LP_ANALOG_PERI_TOUCH_NEG_NOISE_LIMIT_S 17 +#define LP_ANALOG_PERI_TOUCH_NN_LIMIT 0x0000000FU +#define LP_ANALOG_PERI_TOUCH_NN_LIMIT_M (LP_ANALOG_PERI_TOUCH_NN_LIMIT_V << LP_ANALOG_PERI_TOUCH_NN_LIMIT_S) +#define LP_ANALOG_PERI_TOUCH_NN_LIMIT_V 0x0000000FU +#define LP_ANALOG_PERI_TOUCH_NN_LIMIT_S 17 /** LP_ANALOG_PERI_TOUCH_APPROACH_LIMIT : R/W; bitpos: [28:21]; default: 80; * need_des */ @@ -715,13 +715,13 @@ extern "C" { #define LP_ANALOG_PERI_TOUCH_BYPASS_NOISE_THRES_M (LP_ANALOG_PERI_TOUCH_BYPASS_NOISE_THRES_V << LP_ANALOG_PERI_TOUCH_BYPASS_NOISE_THRES_S) #define LP_ANALOG_PERI_TOUCH_BYPASS_NOISE_THRES_V 0x00000001U #define LP_ANALOG_PERI_TOUCH_BYPASS_NOISE_THRES_S 30 -/** LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES : R/W; bitpos: [31]; default: 0; +/** LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES : R/W; bitpos: [31]; default: 0; * need_des */ -#define LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES (BIT(31)) -#define LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES_M (LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES_V << LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES_S) -#define LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES_V 0x00000001U -#define LP_ANALOG_PERI_TOUCH_BYPASS_NEG_NOISE_THRES_S 31 +#define LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES (BIT(31)) +#define LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES_M (LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES_V << LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES_S) +#define LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES_V 0x00000001U +#define LP_ANALOG_PERI_TOUCH_BYPASS_NN_THRES_S 31 /** LP_ANALOG_PERI_TOUCH_FILTER3_REG register * need_des diff --git a/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h b/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h index e50534067c7..2819658d26e 100644 --- a/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h +++ b/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h @@ -510,18 +510,18 @@ typedef union { */ typedef union { struct { - /** touch_neg_noise_disupdate_baseline_en : R/W; bitpos: [0]; default: 0; + /** touch_nn_disupdate_baseline_en : R/W; bitpos: [0]; default: 0; * Reserved */ - uint32_t touch_neg_noise_disupdate_baseline_en:1; + uint32_t touch_nn_disupdate_baseline_en:1; /** touch_hysteresis : R/W; bitpos: [2:1]; default: 0; * need_des */ uint32_t touch_hysteresis:2; - /** touch_neg_noise_thres : R/W; bitpos: [4:3]; default: 0; + /** touch_nn_thres : R/W; bitpos: [4:3]; default: 0; * need_des */ - uint32_t touch_neg_noise_thres:2; + uint32_t touch_nn_thres:2; /** touch_noise_thres : R/W; bitpos: [6:5]; default: 0; * need_des */ @@ -542,10 +542,10 @@ typedef union { * need_des */ uint32_t touch_filter_en:1; - /** touch_neg_noise_limit : R/W; bitpos: [20:17]; default: 5; + /** touch_nn_limit : R/W; bitpos: [20:17]; default: 5; * need_des */ - uint32_t touch_neg_noise_limit:4; + uint32_t touch_nn_limit:4; /** touch_approach_limit : R/W; bitpos: [28:21]; default: 80; * need_des */ @@ -572,10 +572,10 @@ typedef union { * need_des */ uint32_t touch_bypass_noise_thres:1; - /** touch_bypass_neg_noise_thres : R/W; bitpos: [31]; default: 0; + /** touch_bypass_nn_thres : R/W; bitpos: [31]; default: 0; * need_des */ - uint32_t touch_bypass_neg_noise_thres:1; + uint32_t touch_bypass_nn_thres:1; }; uint32_t val; } lp_analog_peri_touch_filter2_reg_t; From 2ee7f0e133e37e33f64dcc47a09289f4c22ef065 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 17 Jun 2024 20:46:41 +0800 Subject: [PATCH 367/548] refactor(touch): refactor the filter configuration --- .../include/driver/touch_version_types.h | 63 ++----------------- .../hw_ver3/touch_version_specific.c | 7 +-- .../hal/esp32p4/include/hal/touch_sensor_ll.h | 38 ++++------- 3 files changed, 19 insertions(+), 89 deletions(-) diff --git a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h index a9ec0dea796..cf15c14be8a 100644 --- a/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h +++ b/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h @@ -55,11 +55,7 @@ extern "C" { .benchmark = { \ .filter_mode = TOUCH_BM_IIR_FILTER_4, \ .jitter_step = 4, \ - .update = { \ - .pos_thresh = TOUCH_UPDATE_BM_POS_THRESH_1_4, \ - .neg_thresh = TOUCH_UPDATE_BM_NEG_THRESH_1_4, \ - .neg_limit = 5, \ - }, \ + .denoise_lvl = 1, \ }, \ .data = { \ .smooth_filter = TOUCH_SMOOTH_IIR_FILTER_2, \ @@ -115,35 +111,6 @@ typedef enum { TOUCH_BM_JITTER_FILTER, /*!< Jitter Filter for benchmark, raw value +/- jitter_step */ } touch_benchmark_filter_mode_t; -/** - * @brief Positive noise limitation of benchmark - * benchmark will only update gradually when - * the smooth data within the positive noise limitation - * - */ -typedef enum { - TOUCH_UPDATE_BM_POS_ALWAYS = -1, /*!< Always update benchmark when (smooth_data - benchmark) > 0 */ - TOUCH_UPDATE_BM_POS_THRESH_1_2 = 0, /*!< Only update benchmark when the (smooth_data - benchmark) < 1/2 * activate_threshold */ - TOUCH_UPDATE_BM_POS_THRESH_3_8, /*!< Only update benchmark when the (smooth_data - benchmark) < 3/8 * activate_threshold */ - TOUCH_UPDATE_BM_POS_THRESH_1_4, /*!< Only update benchmark when the (smooth_data - benchmark) < 1/4 * activate_threshold */ - TOUCH_UPDATE_BM_POS_THRESH_1, /*!< Only update benchmark when the (smooth_data - benchmark) < 1 * activate_threshold */ -} touch_benchmark_pos_thresh_t; - -/** - * @brief Negative noise limitation of benchmark - * benchmark will only update gradually when - * the smooth data within the negative noise limitation - * - */ -typedef enum { - TOUCH_UPDATE_BM_NEG_NEVER = -2, /*!< Never update benchmark when (benchmark - smooth_data) > 0 */ - TOUCH_UPDATE_BM_NEG_ALWAYS = -1, /*!< Always update benchmark when (benchmark - smooth_data) > 0 */ - TOUCH_UPDATE_BM_NEG_THRESH_1_2 = 0, /*!< Only update benchmark when the (benchmark - smooth_data) < 1/2 * activate_threshold */ - TOUCH_UPDATE_BM_NEG_THRESH_3_8, /*!< Only update benchmark when the (benchmark - smooth_data) < 3/8 * activate_threshold */ - TOUCH_UPDATE_BM_NEG_THRESH_1_4, /*!< Only update benchmark when the (benchmark - smooth_data) < 1/4 * activate_threshold */ - TOUCH_UPDATE_BM_NEG_THRESH_1, /*!< Only update benchmark when the (benchmark - smooth_data) < 1 * activate_threshold */ -} touch_benchmark_neg_thresh_t; - /** * @brief Touch channel Infinite Impulse Response (IIR) filter for smooth data * @@ -222,31 +189,11 @@ typedef struct { touch_benchmark_filter_mode_t filter_mode; /*!< Benchmark filter mode. IIR filter and Jitter filter can be selected, * TOUCH_BM_IIR_FILTER_16 is recommended */ - uint32_t jitter_step; /*!< Jitter filter step size, only takes effect when the `filter_mode` is TOUCH_BM_JITTER_FILTER. Range: 0 ~ 15 */ - /** - * @brief Benchmark update strategy - */ - struct { - touch_benchmark_pos_thresh_t pos_thresh; /*!< Select the positive noise threshold. Higher = More noise resistance. - * Range: [-1 ~ 3]. The coefficient of the positive threshold are -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; - * Once the data of the channel exceeded the positive threshold (i.e., benchmark + coefficient * touch threshold), - * the benchmark will stop updated to that value. - * -1: ignore the positive threshold and always update the benchmark for positive noise - */ - touch_benchmark_neg_thresh_t neg_thresh; /*!< Select the negative noise threshold. Higher = More noise resistance. - * Range: [-2 ~ 3]. The coefficient of the negative threshold are -2: never; -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; - * Once the data of the channel below the negative threshold (i.e., benchmark - coefficient * touch threshold), - * the benchmark will stop updated to that value, - * unless the data keep below the negative threshold for more than the limitation of `neg_limit` - * -1: ignore the negative threshold and always update the benchmark for negative noise - * -2: never update the benchmark for negative noise - */ - uint32_t neg_limit; /*!< Set the time limitation of the negative threshold. - * The benchmark will be updated to the value that below to the negative threshold after the limited time. - * Normally the negative update is used at the beginning, as the initial benchmark is a very large value. - * (the unit of `neg_limit` is the tick of the slow clock source) + uint32_t jitter_step; /*!< Jitter filter step size, only takes effect when the `filter_mode` is TOUCH_BM_JITTER_FILTER. Range: [0 ~ 15] */ + int denoise_lvl; /*!< The denoise level, which determines the noise bouncing range that won't trigger benchmark update. + * Range: [0 ~ 4]. The greater the denoise_lvl is, more noise resistance will be. Specially, `0` stands for no denoise + * Typically, recommend to set this field to 1. */ - } update; /*!< The benchmark update strategy */ } benchmark; /*!< Benchmark filter */ /** * @brief Data configuration diff --git a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c index acc88c09c55..ebf9acecdd6 100644 --- a/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c +++ b/components/esp_driver_touch_sens/hw_ver3/touch_version_specific.c @@ -282,8 +282,8 @@ esp_err_t touch_sensor_config_filter(touch_sensor_handle_t sens_handle, const to { TOUCH_NULL_POINTER_CHECK(sens_handle); if (filter_cfg) { - ESP_RETURN_ON_FALSE(filter_cfg->benchmark.update.neg_limit >= filter_cfg->data.debounce_cnt, - ESP_ERR_INVALID_ARG, TAG, "The neg_limit should be greater than debounce_cnt"); + ESP_RETURN_ON_FALSE(filter_cfg->benchmark.denoise_lvl >= 0 && filter_cfg->benchmark.denoise_lvl <= 4, + ESP_ERR_INVALID_ARG, TAG, "denoise_lvl is out of range"); } esp_err_t ret = ESP_OK; @@ -297,8 +297,7 @@ esp_err_t touch_sensor_config_filter(touch_sensor_handle_t sens_handle, const to if (filter_cfg->benchmark.filter_mode == TOUCH_BM_JITTER_FILTER) { touch_ll_filter_set_jitter_step(filter_cfg->benchmark.jitter_step); } - touch_ll_filter_set_pos_noise_thresh(filter_cfg->benchmark.update.pos_thresh); - touch_ll_filter_set_neg_noise_thresh(filter_cfg->benchmark.update.neg_thresh, filter_cfg->benchmark.update.neg_limit); + touch_ll_filter_set_denoise_level(filter_cfg->benchmark.denoise_lvl); /* Configure the touch data filter */ touch_ll_filter_set_smooth_mode(filter_cfg->data.smooth_filter); touch_ll_filter_set_active_hysteresis(filter_cfg->data.active_hysteresis); diff --git a/components/hal/esp32p4/include/hal/touch_sensor_ll.h b/components/hal/esp32p4/include/hal/touch_sensor_ll.h index b8f1d625fc4..e63fb9d465f 100644 --- a/components/hal/esp32p4/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32p4/include/hal/touch_sensor_ll.h @@ -695,39 +695,23 @@ static inline void touch_ll_filter_set_debounce(uint32_t dbc_cnt) } /** - * Set the positive noise threshold coefficient. Higher = More noise resistance. - * The benchmark will update to the new value if the touch data is within (benchmark + active_threshold * pos_coeff) + * Set the denoise coefficient regarding the denoise level. * - * - * @param pos_noise_thresh Range [-1 ~ 3]. The coefficient is -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; - * -1: the benchmark will always update to the new touch data without considering the positive noise threshold + * @param denoise_lvl Range [0 ~ 4]. 0 = no noise resistance, otherwise higher denoise_lvl means more noise resistance. */ -static inline void touch_ll_filter_set_pos_noise_thresh(int pos_noise_thresh) +static inline void touch_ll_filter_set_denoise_level(int denoise_lvl) { - bool always_update = pos_noise_thresh < 0; + HAL_ASSERT(denoise_lvl >= 0 && denoise_lvl <= 4); + bool always_update = denoise_lvl == 0; + // Map denoise level to actual noise threshold coefficients + uint32_t noise_thresh = denoise_lvl == 4 ? 3 : 3 - denoise_lvl; + LP_ANA_PERI.touch_filter2.touch_bypass_noise_thres = always_update; - LP_ANA_PERI.touch_filter1.touch_noise_thres = always_update ? 0 : pos_noise_thresh; -} + LP_ANA_PERI.touch_filter1.touch_noise_thres = always_update ? 0 : noise_thresh; -/** - * Set the negative noise threshold coefficient. Higher = More noise resistance. - * The benchmark will update to the new value if the touch data is greater than (benchmark - active_threshold * neg_coeff) - * - * @param neg_noise_thresh Range [-2 ~ 3]. The coefficient is -2: never; -1: always; 0: 4/8; 1: 3/8; 2: 2/8; 3: 1; - * -1: the benchmark will always update to the new touch data without considering the negative noise threshold - * -2: the benchmark will never update to the new touch data with negative growth - * @param neg_noise_limit Only when neg_noise_thresh >= 0, if the touch data keep blow the negative threshold for mare than neg_noise_limit ticks, - * the benchmark will still update to the new value. - * It is normally used for updating the benchmark at the first scanning - */ -static inline void touch_ll_filter_set_neg_noise_thresh(int neg_noise_thresh, uint8_t neg_noise_limit) -{ - bool always_update = neg_noise_thresh == -1; - bool stop_update = neg_noise_thresh == -2; LP_ANA_PERI.touch_filter2.touch_bypass_nn_thres = always_update; - LP_ANA_PERI.touch_filter1.touch_nn_disupdate_baseline_en = stop_update; - LP_ANA_PERI.touch_filter1.touch_nn_thres = always_update || stop_update ? 0 : neg_noise_thresh; - LP_ANA_PERI.touch_filter1.touch_nn_limit = always_update || stop_update ? 5 : neg_noise_limit; // 5 is the default value + LP_ANA_PERI.touch_filter1.touch_nn_thres = always_update ? 0 : noise_thresh; + LP_ANA_PERI.touch_filter1.touch_nn_limit = 5; // 5 is the default value } /** From 2c7958735d73a79999b4dcf62d9d34cc7a839176 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 24 Jun 2024 15:29:52 +0800 Subject: [PATCH 368/548] refactor(lp_ana_periph): sync the reg names to TRM (part2) --- .../hal/esp32p4/include/hal/touch_sensor_ll.h | 6 ++-- .../esp32p4/include/soc/lp_analog_peri_reg.h | 30 +++++++++---------- .../include/soc/lp_analog_peri_struct.h | 14 ++++----- components/soc/esp32s3/include/soc/sens_reg.h | 24 +++++---------- .../soc/esp32s3/include/soc/sens_struct.h | 2 +- .../peripherals/touch_element.rst | 2 +- tools/ci/check_copyright_ignore.txt | 1 - 7 files changed, 35 insertions(+), 44 deletions(-) diff --git a/components/hal/esp32p4/include/hal/touch_sensor_ll.h b/components/hal/esp32p4/include/hal/touch_sensor_ll.h index e63fb9d465f..37280c3b5d2 100644 --- a/components/hal/esp32p4/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32p4/include/hal/touch_sensor_ll.h @@ -755,10 +755,10 @@ static inline void touch_ll_filter_enable(bool enable) */ static inline void touch_ll_force_update_benchmark(uint32_t benchmark) { - HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_filter3, touch_baseline_sw, benchmark); - LP_ANA_PERI.touch_filter3.touch_update_baseline_sw = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(LP_ANA_PERI.touch_filter3, touch_benchmark_sw, benchmark); + LP_ANA_PERI.touch_filter3.touch_update_benchmark_sw = 1; // waiting for update - while (LP_ANA_PERI.touch_filter3.touch_update_baseline_sw); + while (LP_ANA_PERI.touch_filter3.touch_update_benchmark_sw); } /************************ Waterproof register setting ************************/ diff --git a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h index cfd26fd0164..b9064e20c2b 100644 --- a/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h +++ b/components/soc/esp32p4/include/soc/lp_analog_peri_reg.h @@ -619,13 +619,13 @@ extern "C" { * need_des */ #define LP_ANALOG_PERI_TOUCH_FILTER1_REG (DR_REG_LP_ANALOG_PERI_BASE + 0x110) -/** LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN : R/W; bitpos: [0]; default: 0; +/** LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN : R/W; bitpos: [0]; default: 0; * Reserved */ -#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN (BIT(0)) -#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_M (LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_V << LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_S) -#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_V 0x00000001U -#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BASELINE_EN_S 0 +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN (BIT(0)) +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN_M (LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN_V << LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN_S) +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN_V 0x00000001U +#define LP_ANALOG_PERI_TOUCH_NN_DISUPDATE_BENCHMARK_EN_S 0 /** LP_ANALOG_PERI_TOUCH_HYSTERESIS : R/W; bitpos: [2:1]; default: 0; * need_des */ @@ -727,20 +727,20 @@ extern "C" { * need_des */ #define LP_ANALOG_PERI_TOUCH_FILTER3_REG (DR_REG_LP_ANALOG_PERI_BASE + 0x118) -/** LP_ANALOG_PERI_TOUCH_BASELINE_SW : R/W; bitpos: [15:0]; default: 0; +/** LP_ANALOG_PERI_TOUCH_BENCHMARK_SW : R/W; bitpos: [15:0]; default: 0; * need_des */ -#define LP_ANALOG_PERI_TOUCH_BASELINE_SW 0x0000FFFFU -#define LP_ANALOG_PERI_TOUCH_BASELINE_SW_M (LP_ANALOG_PERI_TOUCH_BASELINE_SW_V << LP_ANALOG_PERI_TOUCH_BASELINE_SW_S) -#define LP_ANALOG_PERI_TOUCH_BASELINE_SW_V 0x0000FFFFU -#define LP_ANALOG_PERI_TOUCH_BASELINE_SW_S 0 -/** LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW : WT; bitpos: [16]; default: 0; +#define LP_ANALOG_PERI_TOUCH_BENCHMARK_SW 0x0000FFFFU +#define LP_ANALOG_PERI_TOUCH_BENCHMARK_SW_M (LP_ANALOG_PERI_TOUCH_BENCHMARK_SW_V << LP_ANALOG_PERI_TOUCH_BENCHMARK_SW_S) +#define LP_ANALOG_PERI_TOUCH_BENCHMARK_SW_V 0x0000FFFFU +#define LP_ANALOG_PERI_TOUCH_BENCHMARK_SW_S 0 +/** LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW : WT; bitpos: [16]; default: 0; * need_des */ -#define LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW (BIT(16)) -#define LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW_M (LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW_V << LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW_S) -#define LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW_V 0x00000001U -#define LP_ANALOG_PERI_TOUCH_UPDATE_BASELINE_SW_S 16 +#define LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW (BIT(16)) +#define LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW_M (LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW_V << LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW_S) +#define LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW_V 0x00000001U +#define LP_ANALOG_PERI_TOUCH_UPDATE_BENCHMARK_SW_S 16 /** LP_ANALOG_PERI_TOUCH_SLP0_REG register * need_des diff --git a/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h b/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h index 2819658d26e..54b0eb9f81b 100644 --- a/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h +++ b/components/soc/esp32p4/include/soc/lp_analog_peri_struct.h @@ -510,10 +510,10 @@ typedef union { */ typedef union { struct { - /** touch_nn_disupdate_baseline_en : R/W; bitpos: [0]; default: 0; + /** touch_nn_disupdate_benchmark_en : R/W; bitpos: [0]; default: 0; * Reserved */ - uint32_t touch_nn_disupdate_baseline_en:1; + uint32_t touch_nn_disupdate_benchmark_en:1; /** touch_hysteresis : R/W; bitpos: [2:1]; default: 0; * need_des */ @@ -585,14 +585,14 @@ typedef union { */ typedef union { struct { - /** touch_baseline_sw : R/W; bitpos: [15:0]; default: 0; + /** touch_benchmark_sw : R/W; bitpos: [15:0]; default: 0; * need_des */ - uint32_t touch_baseline_sw:16; - /** touch_update_baseline_sw : WT; bitpos: [16]; default: 0; + uint32_t touch_benchmark_sw:16; + /** touch_update_benchmark_sw : WT; bitpos: [16]; default: 0; * need_des */ - uint32_t touch_update_baseline_sw:1; + uint32_t touch_update_benchmark_sw:1; uint32_t reserved_17:15; }; uint32_t val; @@ -750,7 +750,7 @@ typedef union { /** touch_data_sel : R/W; bitpos: [9:8]; default: 0; * The type of the output data for debugging * 0/1: raw data - * 2: baseline + * 2: benchmark * 3: smooth data */ uint32_t touch_data_sel:2; diff --git a/components/soc/esp32s3/include/soc/sens_reg.h b/components/soc/esp32s3/include/soc/sens_reg.h index 666f3a9c128..ca14d862dc9 100644 --- a/components/soc/esp32s3/include/soc/sens_reg.h +++ b/components/soc/esp32s3/include/soc/sens_reg.h @@ -1,16 +1,8 @@ -// Copyright 2017-2021 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef _SOC_SENS_REG_H_ #define _SOC_SENS_REG_H_ @@ -602,7 +594,7 @@ extern "C" { #define SENS_TOUCH_DENOISE_END_V 0x1 #define SENS_TOUCH_DENOISE_END_S 18 /* SENS_TOUCH_DATA_SEL : R/W ;bitpos:[17:16] ;default: 2'd0 ; */ -/*description: 3: smooth data 2: baseline 1,0: raw_data.*/ +/*description: 3: smooth data 2: benchmark 1,0: raw_data.*/ #define SENS_TOUCH_DATA_SEL 0x00000003 #define SENS_TOUCH_DATA_SEL_M ((SENS_TOUCH_DATA_SEL_V)<<(SENS_TOUCH_DATA_SEL_S)) #define SENS_TOUCH_DATA_SEL_V 0x3 @@ -1378,8 +1370,8 @@ extern "C" { #define SENS_SAR_HALL_CTRL_REG (DR_REG_SENS_BASE + 0xFC) /* SENS_HALL_PHASE_FORCE : R/W ;bitpos:[31] ;default: 1'b1 ; */ -/*description: 1: HALL PHASE is controlled by SW 0: HALL PHASE is controlled by FSM in ULP-cop -rocessor.*/ +/*description: 1: HALL PHASE is controlled by SW 0: HALL PHASE is controlled by FSM in +ULP-coprocessor.*/ #define SENS_HALL_PHASE_FORCE (BIT(31)) #define SENS_HALL_PHASE_FORCE_M (BIT(31)) #define SENS_HALL_PHASE_FORCE_V 0x1 diff --git a/components/soc/esp32s3/include/soc/sens_struct.h b/components/soc/esp32s3/include/soc/sens_struct.h index c2a104d4ccf..3fb730f3c95 100644 --- a/components/soc/esp32s3/include/soc/sens_struct.h +++ b/components/soc/esp32s3/include/soc/sens_struct.h @@ -217,7 +217,7 @@ typedef volatile struct sens_dev_s { struct { uint32_t touch_outen : 15; /*touch controller output enable*/ uint32_t touch_status_clr : 1; /*clear all touch active status*/ - uint32_t touch_data_sel : 2; /*3: smooth data 2: baseline 1,0: raw_data*/ + uint32_t touch_data_sel : 2; /*3: smooth data 2: benchmark 1,0: raw_data*/ uint32_t touch_denoise_end : 1; /*touch_denoise_done*/ uint32_t touch_unit_end : 1; /*touch_unit_done*/ uint32_t touch_approach_pad2 : 4; /*indicate which pad is approach pad2*/ diff --git a/docs/en/api-reference/peripherals/touch_element.rst b/docs/en/api-reference/peripherals/touch_element.rst index 18bc2a377b2..8be2d2ecdcc 100644 --- a/docs/en/api-reference/peripherals/touch_element.rst +++ b/docs/en/api-reference/peripherals/touch_element.rst @@ -443,7 +443,7 @@ The Touch Element Wakeup example is available in `system/light_sleep` directory. // ESP_ERROR_CHECK(touch_element_enable_light_sleep(&sleep_config)); ESP_ERROR_CHECK(touch_element_enable_deep_sleep(button_handle[0], &sleep_config)); - // ESP_ERROR_CHECK(touch_element_sleep_enable_wakeup_calibration(button_handle[0], false)); // (optional) Disable wakeup calibration to prevent updating the baseline to a wrong value + // ESP_ERROR_CHECK(touch_element_sleep_enable_wakeup_calibration(button_handle[0], false)); // (optional) Disable wakeup calibration to prevent updating the benchmark to a wrong value touch_element_start(); diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index e0fcb163efb..f6dd204037f 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -692,7 +692,6 @@ components/soc/esp32s3/include/soc/rtc_io_reg.h components/soc/esp32s3/include/soc/rtc_io_struct.h components/soc/esp32s3/include/soc/sdmmc_pins.h components/soc/esp32s3/include/soc/sdmmc_reg.h -components/soc/esp32s3/include/soc/sens_reg.h components/soc/esp32s3/include/soc/sensitive_reg.h components/soc/esp32s3/include/soc/sensitive_struct.h components/soc/esp32s3/include/soc/soc_ulp.h From 9e34963397382a32cc44d89c0de4fce0db5c4ed4 Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 11 Jul 2024 15:23:29 +0800 Subject: [PATCH 369/548] feat(panic): supported more cache error cactch --- components/esp_system/port/arch/riscv/panic_arch.c | 4 +--- components/riscv/include/esp_private/panic_reason.h | 4 +++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index 718a01116b8..b2278dacb7d 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -39,7 +39,6 @@ */ static inline void print_cache_err_details(const void *frame) { -#if !CONFIG_IDF_TARGET_ESP32P4 const char* cache_err_msg = esp_cache_err_panic_string(); if (cache_err_msg) { panic_print_str(cache_err_msg); @@ -47,7 +46,6 @@ static inline void print_cache_err_details(const void *frame) panic_print_str("Cache error active, but failed to find a corresponding error message"); } panic_print_str("\r\n"); -#endif } #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD @@ -195,7 +193,7 @@ bool panic_soc_check_pseudo_cause(void *f, panic_info_t *info) /* Cache errors when reading instructions will result in an illegal instructions, before any cache error interrupts trigger. We override the exception cause if any cache errors are active to more accurately report the actual reason */ - if (esp_cache_err_has_active_err() && (frame->mcause == MCAUSE_ILLEGAL_INSTRUCTION)) { + if (esp_cache_err_has_active_err() && ((frame->mcause == MCAUSE_ILLEGAL_INSTRUCTION) || (frame->mcause == MCAUSE_ILLIGAL_INSTRUCTION_ACCESS) || (frame->mcause == MCAUSE_LOAD_ACCESS_FAULT))) { pseudo_cause = true; frame->mcause = ETS_CACHEERR_INUM; } diff --git a/components/riscv/include/esp_private/panic_reason.h b/components/riscv/include/esp_private/panic_reason.h index 252f6de9c0b..fdbee96fa30 100644 --- a/components/riscv/include/esp_private/panic_reason.h +++ b/components/riscv/include/esp_private/panic_reason.h @@ -19,4 +19,6 @@ #define PANIC_RSN_CACHEERR 3 -#define MCAUSE_ILLEGAL_INSTRUCTION 2 +#define MCAUSE_ILLIGAL_INSTRUCTION_ACCESS 1 +#define MCAUSE_ILLEGAL_INSTRUCTION 2 +#define MCAUSE_LOAD_ACCESS_FAULT 5 From 22f1d2853386a136f61c81f05d21eec777cb67ae Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 11 Jul 2024 15:25:18 +0800 Subject: [PATCH 370/548] feat(cache): supported cache panic on p4 --- .../port/soc/esp32p4/cache_err_int.c | 32 +++++++---- components/hal/esp32p4/include/hal/cache_ll.h | 54 ++++++++++++++++--- .../soc/esp32p4/include/soc/cache_struct.h | 13 ++--- .../soc/esp32p4/ld/esp32p4.peripherals.ld | 2 + tools/test_apps/system/panic/pytest_panic.py | 4 +- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/components/esp_system/port/soc/esp32p4/cache_err_int.c b/components/esp_system/port/soc/esp32p4/cache_err_int.c index c1a20bbee16..24904c2d5a8 100644 --- a/components/esp_system/port/soc/esp32p4/cache_err_int.c +++ b/components/esp_system/port/soc/esp32p4/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,19 +20,24 @@ static const char *TAG = "CACHE_ERR"; -//TODO: IDF-7515 +const char cache_error_msg[] = "Cache access error"; + const char *esp_cache_err_panic_string(void) { - return NULL; + uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK) | cache_ll_l2_get_access_error_intr_status(0, CACHE_LL_L2_ACCESS_EVENT_MASK); + + /* Return the error string if a cache error is active */ + const char* err_str = access_err_status ? cache_error_msg : NULL; + + return err_str; } -//TODO: IDF-7515 bool esp_cache_err_has_active_err(void) { - return false; + bool has_active_err = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK) | cache_ll_l2_get_access_error_intr_status(0, CACHE_LL_L2_ACCESS_EVENT_MASK); + return has_active_err; } -//TODO: IDF-7515 void esp_cache_err_int_init(void) { const uint32_t core_id = 0; @@ -56,10 +61,13 @@ void esp_cache_err_int_init(void) esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); - /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + /* On the hardware side, start by clearing all the bits responsible for cache access error */ cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + cache_ll_l2_clear_access_error_intr(0, CACHE_LL_L2_ACCESS_EVENT_MASK); + /* Then enable cache access error interrupts. */ cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + cache_ll_l2_enable_access_error_intr(0, CACHE_LL_L2_ACCESS_EVENT_MASK); /* Enable the interrupts for cache error. */ ESP_INTR_ENABLE(ETS_CACHEERR_INUM); @@ -67,7 +75,11 @@ void esp_cache_err_int_init(void) int esp_cache_err_get_cpuid(void) { - //TODO: IDF-7515 - //Should return hart ID according to the cache error - return 0; + if (cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_CORE0_EVENT_MASK)) { + return 0; + } else if (cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_CORE1_EVENT_MASK)) { + return 1; + } else { + return -1; + } } diff --git a/components/hal/esp32p4/include/hal/cache_ll.h b/components/hal/esp32p4/include/hal/cache_ll.h index c2f4bbd2f0a..5e1a07130ee 100644 --- a/components/hal/esp32p4/include/hal/cache_ll.h +++ b/components/hal/esp32p4/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #include #include "soc/cache_reg.h" +#include "soc/cache_struct.h" #include "soc/ext_mem_defs.h" #include "hal/cache_types.h" #include "hal/assert.h" @@ -47,8 +48,10 @@ extern "C" { #define CACHE_LL_DEFAULT_IBUS_MASK (CACHE_BUS_IBUS0 | CACHE_BUS_IBUS1 | CACHE_BUS_IBUS2) #define CACHE_LL_DEFAULT_DBUS_MASK (CACHE_BUS_DBUS0 | CACHE_BUS_DBUS1 | CACHE_BUS_DBUS2) -//TODO: IDF-7515 -#define CACHE_LL_L1_ACCESS_EVENT_MASK (0x3f) +#define CACHE_LL_L1_ACCESS_EVENT_MASK (0x1f) +#define CACHE_LL_L2_ACCESS_EVENT_MASK (1<<6) +#define CACHE_LL_L1_CORE0_EVENT_MASK (1<<0) +#define CACHE_LL_L1_CORE1_EVENT_MASK (1<<1) /*------------------------------------------------------------------------------ * Autoload @@ -1019,27 +1022,29 @@ static inline bool cache_ll_vaddr_to_cache_level_id(uint32_t vaddr_start, uint32 * Interrupt *----------------------------------------------------------------------------*/ /** - * @brief Enable Cache access error interrupt + * @brief Enable L1 Cache access error interrupt * * @param cache_id Cache ID * @param mask Interrupt mask */ static inline void cache_ll_l1_enable_access_error_intr(uint32_t cache_id, uint32_t mask) { + CACHE.l1_cache_acs_fail_int_ena.val |= mask; } /** - * @brief Clear Cache access error interrupt status + * @brief Clear L1 Cache access error interrupt status * * @param cache_id Cache ID * @param mask Interrupt mask */ static inline void cache_ll_l1_clear_access_error_intr(uint32_t cache_id, uint32_t mask) { + CACHE.l1_cache_acs_fail_int_clr.val = mask; } /** - * @brief Get Cache access error interrupt status + * @brief Get L1 Cache access error interrupt status * * @param cache_id Cache ID * @param mask Interrupt mask @@ -1048,7 +1053,42 @@ static inline void cache_ll_l1_clear_access_error_intr(uint32_t cache_id, uint32 */ static inline uint32_t cache_ll_l1_get_access_error_intr_status(uint32_t cache_id, uint32_t mask) { - return 0; + return CACHE.l1_cache_acs_fail_int_st.val & mask; +} + +/** + * @brief Enable L2 Cache access error interrupt + * + * @param cache_id Cache ID + * @param mask Interrupt mask + */ +static inline void cache_ll_l2_enable_access_error_intr(uint32_t cache_id, uint32_t mask) +{ + CACHE.l2_cache_acs_fail_int_ena.val |= mask; +} + +/** + * @brief Clear L2 Cache access error interrupt status + * + * @param cache_id Cache ID + * @param mask Interrupt mask + */ +static inline void cache_ll_l2_clear_access_error_intr(uint32_t cache_id, uint32_t mask) +{ + CACHE.l2_cache_acs_fail_int_clr.val = mask; +} + +/** + * @brief Get L2 Cache access error interrupt status + * + * @param cache_id Cache ID + * @param mask Interrupt mask + * + * @return Status mask + */ +static inline uint32_t cache_ll_l2_get_access_error_intr_status(uint32_t cache_id, uint32_t mask) +{ + return CACHE.l2_cache_acs_fail_int_st.val & mask; } #ifdef __cplusplus diff --git a/components/soc/esp32p4/include/soc/cache_struct.h b/components/soc/esp32p4/include/soc/cache_struct.h index 0c6fb056d52..67e57371b29 100644 --- a/components/soc/esp32p4/include/soc/cache_struct.h +++ b/components/soc/esp32p4/include/soc/cache_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -5269,12 +5269,12 @@ typedef union { struct { /** l1_icache0_unalloc_clr : R/W; bitpos: [0]; default: 0; * The bit is used to clear the unallocate request buffer of l1 icache0 where the - * unallocate request is responsed but not completed. + * unallocate request is responded but not completed. */ uint32_t l1_icache0_unalloc_clr:1; /** l1_icache1_unalloc_clr : R/W; bitpos: [1]; default: 0; * The bit is used to clear the unallocate request buffer of l1 icache1 where the - * unallocate request is responsed but not completed. + * unallocate request is responded but not completed. */ uint32_t l1_icache1_unalloc_clr:1; /** l1_icache2_unalloc_clr : HRO; bitpos: [2]; default: 0; @@ -5287,7 +5287,7 @@ typedef union { uint32_t l1_icache3_unalloc_clr:1; /** l1_dcache_unalloc_clr : R/W; bitpos: [4]; default: 0; * The bit is used to clear the unallocate request buffer of l1 dcache where the - * unallocate request is responsed but not completed. + * unallocate request is responded but not completed. */ uint32_t l1_dcache_unalloc_clr:1; uint32_t reserved_5:27; @@ -5303,7 +5303,7 @@ typedef union { uint32_t reserved_0:5; /** l2_cache_unalloc_clr : R/W; bitpos: [5]; default: 0; * The bit is used to clear the unallocate request buffer of l2 icache where the - * unallocate request is responsed but not completed. + * unallocate request is responded but not completed. */ uint32_t l2_cache_unalloc_clr:1; uint32_t reserved_6:26; @@ -5548,7 +5548,7 @@ typedef union { } cache_date_reg_t; -typedef struct { +typedef struct cache_dev_t { volatile cache_l1_icache_ctrl_reg_t l1_icache_ctrl; volatile cache_l1_dcache_ctrl_reg_t l1_dcache_ctrl; volatile cache_l1_bypass_cache_conf_reg_t l1_bypass_cache_conf; @@ -5799,6 +5799,7 @@ typedef struct { volatile cache_date_reg_t date; } cache_dev_t; +extern cache_dev_t CACHE; #ifndef __cplusplus _Static_assert(sizeof(cache_dev_t) == 0x400, "Invalid size of cache_dev_t structure"); diff --git a/components/soc/esp32p4/ld/esp32p4.peripherals.ld b/components/soc/esp32p4/ld/esp32p4.peripherals.ld index 0b293ba89e7..2b2c9cbc999 100644 --- a/components/soc/esp32p4/ld/esp32p4.peripherals.ld +++ b/components/soc/esp32p4/ld/esp32p4.peripherals.ld @@ -120,3 +120,5 @@ PROVIDE ( USB_UTMI = 0x5009C000 ); PROVIDE ( EMAC_MAC = 0x50098000 ); PROVIDE ( EMAC_DMA = 0x50099000 ); + +PROVIDE ( CACHE = 0x3FF10000); diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index e3193670ad3..5287f5dde3f 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -267,14 +267,12 @@ def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> Non if dut.target in ['esp32c3', 'esp32c2']: dut.expect_gme('Cache error') dut.expect_exact('Cached memory region accessed while ibus or cache is disabled') - elif dut.target in ['esp32c6', 'esp32h2']: + elif dut.target in ['esp32c6', 'esp32h2', 'esp32p4']: dut.expect_gme('Cache error') dut.expect_exact('Cache access error') elif dut.target in ['esp32s2']: # Cache error interrupt is not enabled, IDF-1558 dut.expect_gme('IllegalInstruction') - elif dut.target in ['esp32p4']: # TODO IDF-7515 - dut.expect_gme('Instruction access fault') else: dut.expect_gme('Cache disabled but cached memory region accessed') dut.expect_reg_dump(0) From aacfe19a4e70dbbe194f10428a47ce0481209f04 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 10 Jul 2024 15:51:01 +0530 Subject: [PATCH 371/548] fix(esp_mm): for existing mmap region, consider new offset for virtual addr While returning virtual address for existing memory mapped region, newly supplied offset from the physical address was not getting considered. This was a regression present from ESP-IDF 5.1 release. Added test case in spi_flash component that fails without this fix. Closes https://github.com/espressif/esp-idf/issues/13929 --- components/esp_mm/esp_mmu_map.c | 10 ++++++- components/esp_mm/include/esp_mmu_map.h | 2 +- .../flash_mmap/main/test_flash_mmap.c | 27 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c index 226ec38e0c9..8b00d3402ae 100644 --- a/components/esp_mm/esp_mmu_map.c +++ b/components/esp_mm/esp_mmu_map.c @@ -509,7 +509,15 @@ esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_target_t target, if (is_enclosed) { ESP_LOGW(TAG, "paddr block is mapped already, vaddr_start: %p, size: 0x%x", (void *)mem_block->vaddr_start, mem_block->size); - *out_ptr = (void *)mem_block->vaddr_start; + /* + * This condition is triggered when `s_is_enclosed` is true and hence + * we are sure that `paddr_start` >= `mem_block->paddr_start`. + * + * Add the offset of new physical address while returning the virtual + * address. + */ + const uint32_t new_paddr_offset = paddr_start - mem_block->paddr_start; + *out_ptr = (void *)mem_block->vaddr_start + new_paddr_offset; return ESP_ERR_INVALID_STATE; } diff --git a/components/esp_mm/include/esp_mmu_map.h b/components/esp_mm/include/esp_mmu_map.h index e4a42e483d0..2e64a0d8425 100644 --- a/components/esp_mm/include/esp_mmu_map.h +++ b/components/esp_mm/include/esp_mmu_map.h @@ -75,7 +75,7 @@ typedef uint32_t esp_paddr_t; * - ESP_ERR_NOT_SUPPORTED: Only on ESP32, PSRAM is not a supported physical memory target * - ESP_ERR_NOT_FOUND: No enough size free block to use * - ESP_ERR_NO_MEM: Out of memory, this API will allocate some heap memory for internal usage - * - ESP_ERR_INVALID_STATE: Paddr is mapped already, this API will return corresponding vaddr_start of the previously mapped block. + * - ESP_ERR_INVALID_STATE: Paddr is mapped already, this API will return corresponding `vaddr_start + new_block_offset` as per the previously mapped block. * Only to-be-mapped paddr block is totally enclosed by a previously mapped block will lead to this error. (Identical scenario will behave similarly) * new_block_start new_block_end * |-------- New Block --------| diff --git a/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c index 83b0453bcbd..3f36d6bf34a 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c +++ b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c @@ -101,6 +101,33 @@ static void setup_mmap_tests(void) } } +TEST_CASE("Can get correct data in existing mapped region", "[spi_flash][mmap]") +{ + setup_mmap_tests(); + + printf("Mapping %"PRIx32" (+%"PRIx32")\n", start, end - start); + const void *ptr1; + TEST_ESP_OK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle1, ptr1); + + /* Remap in the previously mapped region itself */ + uint32_t new_start = start + CONFIG_MMU_PAGE_SIZE; + printf("Mapping %"PRIx32" (+%"PRIx32")\n", new_start, end - new_start); + const void *ptr2; + TEST_ESP_OK( spi_flash_mmap(new_start, end - new_start, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); + printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle2, ptr2); + + const void *src1 = (void *) ((uint32_t) ptr1 + CONFIG_MMU_PAGE_SIZE); + const void *src2 = ptr2; + /* Memory contents should be identical - as the region is same */ + TEST_ASSERT_EQUAL(0, memcmp(src1, src2, end - new_start)); + + spi_flash_munmap(handle1); + handle1 = 0; + spi_flash_munmap(handle2); + handle2 = 0; + TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); +} TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") { From 0b5db82e5e3d802d47e69f2fa45c13f7e2aa475d Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 10 Jul 2024 10:01:22 +0800 Subject: [PATCH 372/548] feat(psram): support bss on psram on p4 --- components/esp_psram/esp_psram.c | 9 ++++++++ .../include/esp_private/esp_psram_extram.h | 7 +++++- components/esp_system/ld/esp32p4/memory.ld.in | 9 ++++++++ .../esp_system/ld/esp32p4/sections.ld.in | 22 +++++++++++++++++++ components/esp_system/port/cpu_start.c | 7 +----- 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/components/esp_psram/esp_psram.c b/components/esp_psram/esp_psram.c index 23cd5f1b59f..debbf9de31b 100644 --- a/components/esp_psram/esp_psram.c +++ b/components/esp_psram/esp_psram.c @@ -11,6 +11,7 @@ * When we add more types of external RAM memory, this can be made into a more intelligent dispatcher. *----------------------------------------------------------------------------------------------------*/ #include +#include #include "sdkconfig.h" #include "esp_attr.h" #include "esp_err.h" @@ -521,3 +522,11 @@ bool esp_psram_extram_test(void) return true; } + +void esp_psram_bss_init(void) +{ +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + size_t size = (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start); + memset(&_ext_ram_bss_start, 0, size); +#endif +} diff --git a/components/esp_psram/include/esp_private/esp_psram_extram.h b/components/esp_psram/include/esp_private/esp_psram_extram.h index 5cd7e52a153..0b44e1bfd87 100644 --- a/components/esp_psram/include/esp_private/esp_psram_extram.h +++ b/components/esp_psram/include/esp_private/esp_psram_extram.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,6 +55,11 @@ esp_err_t esp_psram_extram_reserve_dma_pool(size_t size); */ bool esp_psram_extram_test(void); +/** + * @brief Init .bss on psram + */ +void esp_psram_bss_init(void); + #if CONFIG_IDF_TARGET_ESP32 /** * @brief Force a writeback of the data in the PSRAM cache. This is to be called whenever diff --git a/components/esp_system/ld/esp32p4/memory.ld.in b/components/esp_system/ld/esp32p4/memory.ld.in index 8c76daee195..226803c2933 100644 --- a/components/esp_system/ld/esp32p4/memory.ld.in +++ b/components/esp_system/ld/esp32p4/memory.ld.in @@ -103,6 +103,9 @@ MEMORY This segment is placed at the beginning of LP RAM, as the end of LP RAM is occupied by LP ROM stack/data */ lp_reserved_seg(RW) : org = 0x50108000, len = RESERVE_RTC_MEM + + /* PSRAM seg */ + extern_ram_seg(RWX) : org = 0x48000000, len = IDROM_SEG_SIZE } /* Heap ends at top of dram0_0_seg */ @@ -135,6 +138,12 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg ); REGION_ALIAS("rodata_seg_high", sram_high); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS +#if CONFIG_SPIRAM_XIP_FROM_PSRAM + REGION_ALIAS("ext_ram_seg", drom_seg); +#else + REGION_ALIAS("ext_ram_seg", extern_ram_seg); +#endif //#if CONFIG_SPIRAM_XIP_FROM_PSRAM + /** * If rodata default segment is placed in `drom_seg`, then flash's first rodata section must * also be first in the segment. diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index 38d844c4bd1..ef288b49a95 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -475,6 +475,28 @@ SECTIONS mapping[rodata_noload] } > rodata_seg_low +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY +#if CONFIG_SPIRAM_XIP_FROM_PSRAM + /** + * This section is required to skip flash sections, because `extern_ram_seg` + * and `drom_seg` / `irom_seg` are on the same bus when xip on psram + */ + .ext_ram.dummy (NOLOAD): + { + . = ORIGIN(ext_ram_seg) + (_rodata_reserved_end - _flash_rodata_dummy_start); + . = ALIGN (0x10000); + } > ext_ram_seg +#endif //CONFIG_SPIRAM_XIP_FROM_PSRAM + + /* This section holds .ext_ram.bss data, and will be put in PSRAM */ + .ext_ram.bss (NOLOAD) : + { + _ext_ram_bss_start = ABSOLUTE(.); + mapping[extern_ram] + ALIGNED_SYMBOL(4, _ext_ram_bss_end) + } > ext_ram_seg +#endif //CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + .dram0.bss (NOLOAD) : { ALIGNED_SYMBOL(4, _bss_start_low) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 2469b315068..cdfd523063e 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -148,11 +148,6 @@ extern int _mtvt_table; static const char *TAG = "cpu_start"; -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY -extern int _ext_ram_bss_start; -extern int _ext_ram_bss_end; -#endif - #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY extern int _iram_bss_start; extern int _iram_bss_end; @@ -684,7 +679,7 @@ void IRAM_ATTR call_start_cpu0(void) #endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); + esp_psram_bss_init(); #endif //Enable trace memory and immediately start trace. From c85dc30b45676b12c1272015093892ee9cab14ab Mon Sep 17 00:00:00 2001 From: Armando Date: Wed, 10 Jul 2024 10:02:47 +0800 Subject: [PATCH 373/548] test(psram): enable bss psram test --- .../esp_common/test_apps/.build-test-rules.yml | 3 --- .../test_apps/esp_common/pytest_esp_common.py | 18 ++++++++++++++++-- .../esp_common/sdkconfig.xip_psram_esp32p4 | 6 ++++++ 3 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 components/esp_common/test_apps/esp_common/sdkconfig.xip_psram_esp32p4 diff --git a/components/esp_common/test_apps/.build-test-rules.yml b/components/esp_common/test_apps/.build-test-rules.yml index 7b18cd897db..04fd48936f0 100644 --- a/components/esp_common/test_apps/.build-test-rules.yml +++ b/components/esp_common/test_apps/.build-test-rules.yml @@ -3,6 +3,3 @@ components/esp_common/test_apps/esp_common: disable: - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 - - if: CONFIG_NAME == "psram" and IDF_TARGET in ["esp32p4"] - temporary: true - reason: esp32p4 is not supported yet # TODO: IDF-7557 diff --git a/components/esp_common/test_apps/esp_common/pytest_esp_common.py b/components/esp_common/test_apps/esp_common/pytest_esp_common.py index 983220995f6..1a31480cc2f 100644 --- a/components/esp_common/test_apps/esp_common/pytest_esp_common.py +++ b/components/esp_common/test_apps/esp_common/pytest_esp_common.py @@ -1,6 +1,5 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 - import pytest from pytest_embedded import Dut @@ -51,6 +50,7 @@ def run_multiple_stages(dut: Dut, test_case_num: int, stages: int) -> None: @pytest.mark.esp32 @pytest.mark.esp32s2 @pytest.mark.esp32s3 +@pytest.mark.esp32p4 @pytest.mark.generic @pytest.mark.parametrize( 'config', @@ -89,3 +89,17 @@ def test_esp_attr_xip_psram_esp32s2(dut: Dut) -> None: ) def test_esp_attr_xip_psram_esp32s3(dut: Dut) -> None: dut.run_all_single_board_cases() + + +# psram attr tests with xip_psram +@pytest.mark.esp32p4 +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'xip_psram_esp32p4' + ], + indirect=True, +) +def test_esp_attr_xip_psram_esp32p4(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_common/test_apps/esp_common/sdkconfig.xip_psram_esp32p4 b/components/esp_common/test_apps/esp_common/sdkconfig.xip_psram_esp32p4 new file mode 100644 index 00000000000..706f080ca94 --- /dev/null +++ b/components/esp_common/test_apps/esp_common/sdkconfig.xip_psram_esp32p4 @@ -0,0 +1,6 @@ +# For XiP PSRAM EXT_RAM_BSS_ATTR + +CONFIG_IDF_TARGET="esp32p4" +CONFIG_SPIRAM=y +CONFIG_SPIRAM_XIP_FROM_PSRAM=y +CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y From 2a24cc206efb4c92b5a2e40fb71db7650d9cf112 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Mon, 17 Jun 2024 10:46:34 +0200 Subject: [PATCH 374/548] fix(console): USB Serial JTAG freezes when input received before init When data was sent through USB Serial JTAG before the driver was installed, the bus was malfunctioning. This was because the interrupt bit for data reception was cleared regardless of whether data was received or not. Consequently, usb_serial_jtag_isr_handler_default was not triggered and the data was never read causing the bus to malfunction. This commit is modifying usb_serial_jtag_driver_install to prevent clearing USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT and USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY thus allowing the callback usb_serial_jtag_isr_handler_default to trigger for possible data exchanged prior to the call to usb_serial_jtag_driver_install. This commit also modified the while logic in linenoiseProbe to discard any data that doesn't match the expected chaaracter sequences to prevent random input from interfering with evaluating whether the terminal supports escape sequences or not. See https://github.com/espressif/esp-idf/issues/13940 --- components/console/linenoise/linenoise.c | 6 +++--- .../esp_driver_usb_serial_jtag/src/usb_serial_jtag.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/components/console/linenoise/linenoise.c b/components/console/linenoise/linenoise.c index b4e8409af90..e585ab7e89c 100644 --- a/components/console/linenoise/linenoise.c +++ b/components/console/linenoise/linenoise.c @@ -1091,9 +1091,9 @@ int linenoiseProbe(void) { if (cb < 0) { continue; } - if (read_bytes == 0 && c != '\x1b') { - /* invalid response */ - break; + if (read_bytes == 0 && c != ESC) { + /* invalid response, try again until the timeout triggers */ + continue; } read_bytes += cb; } diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c index e03b4efc764..790aed174cf 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c @@ -193,10 +193,14 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se usb_serial_jtag_ll_phy_set_defaults(); // External PHY not supported. Set default values. #endif // USB_WRAP_LL_EXT_PHY_SUPPORTED - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | - USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); - usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY | - USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); + // Note: DO NOT clear the interrupt status bits here. The output routine needs + // USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY set because it needs the ISR to trigger + // as soon as data is sent; the input routine needs the status to retrieve any + // data that is still in the FIFOs. + + // We only enable the RX interrupt; we'll enable the TX one when we actually + // have anything to send. + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); err = esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, usb_serial_jtag_isr_handler_default, NULL, &p_usb_serial_jtag_obj->intr_handle); if (err != ESP_OK) { From 4c2b86f5fe099ac5926b343a14eac6231d9e2e69 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 11 Jul 2024 17:34:32 +0800 Subject: [PATCH 375/548] fix(esp_hw_support): stall another core during cpu/mem/apb freq switching --- .../esp_hw_support/port/esp32p4/rtc_clk.c | 23 ++++++++++++++++++- .../hal/esp32p4/include/hal/cpu_utility_ll.h | 13 +++++++---- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk.c b/components/esp_hw_support/port/esp32p4/rtc_clk.c index 343aaf1955a..4bcccf422e1 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk.c @@ -14,6 +14,7 @@ #include "soc/rtc.h" #include "esp_private/rtc_clk.h" #include "esp_attr.h" +#include "esp_cpu.h" #include "esp_hw_log.h" #include "esp_rom_sys.h" #include "hal/clk_tree_ll.h" @@ -182,7 +183,13 @@ static void rtc_clk_cpu_freq_to_xtal(int cpu_freq, int div, bool to_default) clk_ll_mem_set_divider(mem_divider); clk_ll_sys_set_divider(sys_divider); clk_ll_apb_set_divider(apb_divider); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + esp_cpu_stall(1 - esp_cpu_get_core_id()); +#endif clk_ll_bus_update(); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + esp_cpu_unstall(1 - esp_cpu_get_core_id()); +#endif esp_rom_set_cpu_ticks_per_us(cpu_freq); } @@ -194,7 +201,13 @@ static void rtc_clk_cpu_freq_to_8m(void) clk_ll_sys_set_divider(1); clk_ll_apb_set_divider(1); clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_RC_FAST); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + esp_cpu_stall(1 - esp_cpu_get_core_id()); +#endif clk_ll_bus_update(); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + esp_cpu_unstall(1 - esp_cpu_get_core_id()); +#endif esp_rom_set_cpu_ticks_per_us(20); } @@ -240,14 +253,22 @@ static void rtc_clk_cpu_freq_to_cpll_mhz(int cpu_freq_mhz, hal_utils_clk_div_t * // Update bit does not control CPU clock sel mux. Therefore, there may be a middle state during the switch (CPU rises) // Since this is upscaling, we need to configure the frequency division coefficient before switching the clock source. // Otherwise, an intermediate state will occur, in the intermediate state, the frequency of APB/MEM does not meet the - // timing requirements. If there are periperals/CPU access that depend on these two clocks at this moment, some exception + // timing requirements. If there are periperals access that depend on these two clocks at this moment, some exception // might occur. clk_ll_cpu_set_divider(div->integer, div->numerator, div->denominator); clk_ll_mem_set_divider(mem_divider); clk_ll_sys_set_divider(sys_divider); clk_ll_apb_set_divider(apb_divider); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + // During frequency switching, non-frequency switching cores may have ongoing memory accesses, which may cause access + // failures, stalling non-frequency switching cores here can avoid such failures. + esp_cpu_stall(1 - esp_cpu_get_core_id()); +#endif clk_ll_bus_update(); clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); +#if (!defined(BOOTLOADER_BUILD) && (CONFIG_FREERTOS_NUMBER_OF_CORES == 2)) + esp_cpu_unstall(1 - esp_cpu_get_core_id()); +#endif esp_rom_set_cpu_ticks_per_us(cpu_freq_mhz); } diff --git a/components/hal/esp32p4/include/hal/cpu_utility_ll.h b/components/hal/esp32p4/include/hal/cpu_utility_ll.h index 5c6b606488b..f9686b8ceae 100644 --- a/components/hal/esp32p4/include/hal/cpu_utility_ll.h +++ b/components/hal/esp32p4/include/hal/cpu_utility_ll.h @@ -11,6 +11,7 @@ #include "soc/pmu_struct.h" #include "soc/hp_system_reg.h" #include "esp_attr.h" +#include "hal/misc.h" #ifdef __cplusplus extern "C" { @@ -29,18 +30,22 @@ FORCE_INLINE_ATTR void cpu_utility_ll_reset_cpu(uint32_t cpu_no) FORCE_INLINE_ATTR void cpu_utility_ll_stall_cpu(uint32_t cpu_no) { if (cpu_no == 0) { - PMU.cpu_sw_stall.hpcore0_stall_code = 0x86; + HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.cpu_sw_stall, hpcore0_stall_code, 0x86); + while(!REG_GET_BIT(HP_SYSTEM_CPU_CORESTALLED_ST_REG, HP_SYSTEM_REG_CORE0_CORESTALLED_ST)); } else { - PMU.cpu_sw_stall.hpcore1_stall_code = 0x86; + HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.cpu_sw_stall, hpcore1_stall_code, 0x86); + while(!REG_GET_BIT(HP_SYSTEM_CPU_CORESTALLED_ST_REG, HP_SYSTEM_REG_CORE1_CORESTALLED_ST)); } } FORCE_INLINE_ATTR void cpu_utility_ll_unstall_cpu(uint32_t cpu_no) { if (cpu_no == 0) { - PMU.cpu_sw_stall.hpcore0_stall_code = 0xFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.cpu_sw_stall, hpcore0_stall_code, 0xFF); + while(REG_GET_BIT(HP_SYSTEM_CPU_CORESTALLED_ST_REG, HP_SYSTEM_REG_CORE0_CORESTALLED_ST)); } else { - PMU.cpu_sw_stall.hpcore1_stall_code = 0xFF; + HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.cpu_sw_stall, hpcore1_stall_code, 0xFF); + while(REG_GET_BIT(HP_SYSTEM_CPU_CORESTALLED_ST_REG, HP_SYSTEM_REG_CORE1_CORESTALLED_ST)); } } #endif // SOC_CPU_CORES_NUM > 1 From 074035aac58bc5e128305c43cc5d0dcde666a9a4 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 18 Jun 2024 20:39:34 +0800 Subject: [PATCH 376/548] feat(esp_hw_support): support esp32p4 gpio wakeup deepsleep --- components/esp_hw_support/include/esp_private/esp_pmu.h | 6 +++++- components/esp_hw_support/sleep_modes.c | 4 ++-- components/soc/esp32c2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c2/include/soc/soc_caps.h | 1 + components/soc/esp32c3/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c3/include/soc/soc_caps.h | 1 + components/soc/esp32c6/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c6/include/soc/soc_caps.h | 1 + components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 8 ++++++++ components/soc/esp32p4/include/soc/soc_caps.h | 2 ++ 10 files changed, 32 insertions(+), 3 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index d985b0823f2..4b9a7043227 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -62,7 +62,11 @@ typedef enum { #define RTC_EXT1_TRIG_EN 0 #endif -#define RTC_GPIO_TRIG_EN PMU_GPIO_WAKEUP_EN //!< GPIO wakeup +#if SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE +#define RTC_GPIO_TRIG_EN (PMU_GPIO_WAKEUP_EN | PMU_LP_GPIO_WAKEUP_EN) //!< GPIO & LP_GPIO wakeup +#else +#define RTC_GPIO_TRIG_EN (PMU_GPIO_WAKEUP_EN) +#endif #if SOC_LP_TIMER_SUPPORTED #define RTC_TIMER_TRIG_EN PMU_LP_TIMER_WAKEUP_EN //!< Timer wakeup diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index c05ba88355c..5c34c89607b 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -217,8 +217,8 @@ typedef struct { uint32_t ext0_rtc_gpio_num : 5; #endif #if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP - uint32_t gpio_wakeup_mask : 8; // 8 is the maximum RTCIO number in all chips that support GPIO wakeup - uint32_t gpio_trigger_mode : 8; + uint32_t gpio_wakeup_mask : SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT; // Only RTC_GPIO supports wakeup deepsleep + uint32_t gpio_trigger_mode : SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT; #endif uint32_t sleep_time_adjustment; uint32_t ccount_ticks_record; diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index c8fd88516dd..2e711551174 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -311,6 +311,10 @@ config SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK int default 0 +config SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT + int + default 6 + config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x00000000001FFFC0 diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index 545f4e5cdbc..9ee2f14fed6 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -135,6 +135,7 @@ #define SOC_GPIO_OUT_RANGE_MAX 20 #define SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK (0ULL | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5) +#define SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT (6) // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_6~GPIO_NUM_20) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00000000001FFFC0ULL diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index d16372d9724..95dff02b456 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -403,6 +403,10 @@ config SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK int default 0 +config SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT + int + default 6 + config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x00000000003FFFC0 diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 1b18dda18a8..e51177a0518 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -173,6 +173,7 @@ #define SOC_GPIO_OUT_RANGE_MAX 21 #define SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK (0ULL | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5) +#define SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT (6) // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_6~GPIO_NUM_21) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x00000000003FFFC0ULL diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index f3f3df1034b..ab310ecb290 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -499,6 +499,10 @@ config SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK int default 0 +config SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT + int + default 8 + config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x000000007FFFFF00 diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index c16ebceee48..d0c430129ac 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -203,6 +203,7 @@ #define SOC_GPIO_OUT_RANGE_MAX 30 #define SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK (0ULL | BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7) +#define SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT (8) // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_8~GPIO_NUM_30) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x000000007FFFFF00ULL diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b40de47a8b9..cfd681cf291 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -587,6 +587,10 @@ config SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP bool default y +config SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE + bool + default y + config SOC_GPIO_VALID_GPIO_MASK hex default 0x007FFFFFFFFFFFFF @@ -603,6 +607,10 @@ config SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK int default 0 +config SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT + int + default 16 + config SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK hex default 0x007FFFFFFFFF0000 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index a085b517628..f25fa6948f7 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -232,6 +232,7 @@ #define SOC_GPIO_SUPPORT_RTC_INDEPENDENT (1) // GPIO0~15 on ESP32P4 can support chip deep sleep wakeup #define SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP (1) +#define SOC_LP_IO_HAS_INDEPENDENT_WAKEUP_SOURCE (1) #define SOC_GPIO_VALID_GPIO_MASK (0x007FFFFFFFFFFFFF) #define SOC_GPIO_VALID_OUTPUT_GPIO_MASK SOC_GPIO_VALID_GPIO_MASK @@ -240,6 +241,7 @@ #define SOC_GPIO_OUT_RANGE_MAX 54 #define SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK (0ULL | 0xFFFF) +#define SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT (16) // digital I/O pad powered by VDD3P3_CPU or VDD_SPI(GPIO_NUM_16~GPIO_NUM_54) #define SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK 0x007FFFFFFFFF0000ULL From 603ad059a39c944f8875940e85989bf7754f1e56 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 19 Jun 2024 20:37:36 +0800 Subject: [PATCH 377/548] fix(esp_hw_support): hold LP_IO mode if LP_PERI domain powerdown in sleep --- components/esp_hw_support/port/esp32p4/pmu_sleep.c | 9 ++++++--- .../port/esp32p4/private_include/pmu_param.h | 11 ++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index a9634f86840..0ac1107cc65 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -154,6 +154,10 @@ const pmu_sleep_config_t* pmu_sleep_config_default( if (dslp) { config->param.lp_sys.analog_wait_target_cycle = rtc_time_us_to_slowclk(PMU_LP_ANALOG_WAIT_TARGET_TIME_DSLP_US, slowclk_period); + + pmu_sleep_digital_config_t digital_default = PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(pd_flags); + config->digital = digital_default; + pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_DSLP_CONFIG_DEFAULT(pd_flags); config->analog = analog_default; } else { @@ -200,6 +204,7 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig) { pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel); + pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, HP(SLEEP), dig->syscntl.lp_pad_hold_all); } static void pmu_sleep_analog_init(pmu_context_t *ctx, const pmu_sleep_analog_config_t *analog, bool dslp) @@ -255,9 +260,7 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp) { assert(PMU_instance()); pmu_sleep_power_init(PMU_instance(), &config->power, dslp); - if(!dslp){ - pmu_sleep_digital_init(PMU_instance(), &config->digital); - } + pmu_sleep_digital_init(PMU_instance(), &config->digital); pmu_sleep_analog_init(PMU_instance(), &config->analog, dslp); pmu_sleep_param_init(PMU_instance(), &config->param, dslp); } diff --git a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h index a3c48c04202..0d2bb42bf65 100644 --- a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h @@ -314,9 +314,18 @@ typedef struct { pmu_hp_sys_cntl_reg_t syscntl; } pmu_sleep_digital_config_t; + +#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(pd_flags) { \ + .syscntl = { \ + .dig_pad_slp_sel = 0, \ + .lp_pad_hold_all = (pd_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ + } \ +} + #define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(pd_flags) { \ .syscntl = { \ - .dig_pad_slp_sel = ((pd_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \ + .dig_pad_slp_sel = (pd_flags & PMU_SLEEP_PD_TOP) ? 0 : 1, \ + .lp_pad_hold_all = (pd_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \ } \ } From 51a102a4679c27d1699f02e71516c950191fba50 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Thu, 27 Jun 2024 16:19:15 +0800 Subject: [PATCH 378/548] feat(example): update gpio/ext1 wakeup avaliable IO num in example Kconfig --- examples/system/deep_sleep/main/Kconfig.projbuild | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/system/deep_sleep/main/Kconfig.projbuild b/examples/system/deep_sleep/main/Kconfig.projbuild index 51dffc1f8ca..7c34046cda6 100644 --- a/examples/system/deep_sleep/main/Kconfig.projbuild +++ b/examples/system/deep_sleep/main/Kconfig.projbuild @@ -44,6 +44,7 @@ menu "Example Configuration" range 7 14 if IDF_TARGET_ESP32H2 range 0 21 if IDF_TARGET_ESP32S2 range 0 21 if IDF_TARGET_ESP32S3 + range 0 15 if IDF_TARGET_ESP32P4 choice EXAMPLE_EXT1_WAKEUP_PIN_1_SEL prompt "Enable wakeup from PIN_1" @@ -118,6 +119,7 @@ menu "Example Configuration" range 7 14 if IDF_TARGET_ESP32H2 range 0 21 if IDF_TARGET_ESP32S2 range 0 21 if IDF_TARGET_ESP32S3 + range 0 15 if IDF_TARGET_ESP32P4 choice EXAMPLE_EXT1_WAKEUP_PIN_2_SEL prompt "Enable wakeup from PIN_2" @@ -247,7 +249,7 @@ menu "Example Configuration" if we turn off the RTC_PERIPH domain or if certain chips lack the RTC_PERIPH domain, we will use the HOLD feature to maintain the pull-up and pull-down on the pins during sleep. but if we turn on the RTC_PERIPH domain, we don not need to use HOLD feature and this will - increase some power comsumption. + increase some power consumption. EXT0 wakeup source resides in the same power domain as RTCIO (RTC Periph), so internal pull-up/downs are always available. There's no need to explicitly force it on for EXT0. @@ -259,7 +261,7 @@ menu "Example Configuration" depends on SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP help This option enables wake up from GPIO. Be aware that if you use low level to trigger wakeup, we strongly - recommand you to connect external pull-up resistance. + recommend you to connect external pull-up resistance. menu "GPIO wakeup configuration" visible if EXAMPLE_GPIO_WAKEUP @@ -268,6 +270,7 @@ menu "Example Configuration" int "Enable wakeup from GPIO" default 0 range 0 7 if IDF_TARGET_ESP32C6 + range 0 15 if IDF_TARGET_ESP32P4 range 0 5 if !IDF_TARGET_ESP32C6 config EXAMPLE_GPIO_WAKEUP_HIGH_LEVEL From de7b7bc880cdf46780ce1996aaeb137df08297ac Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 24 Jun 2024 18:17:28 +0800 Subject: [PATCH 379/548] fix(rmt): fix gcc static analyzer warnings --- components/esp_driver_rmt/src/rmt_private.h | 2 +- components/esp_driver_rmt/src/rmt_tx.c | 41 +++++++++++---------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_rmt/src/rmt_private.h b/components/esp_driver_rmt/src/rmt_private.h index cf56d52c6b2..ec6edc72173 100644 --- a/components/esp_driver_rmt/src/rmt_private.h +++ b/components/esp_driver_rmt/src/rmt_private.h @@ -64,7 +64,7 @@ extern "C" { typedef dma_descriptor_align4_t rmt_dma_descriptor_t; #ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR -#define RMT_GET_NON_CACHE_ADDR(addr) ((addr) ? CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) : 0) +#define RMT_GET_NON_CACHE_ADDR(addr) (CACHE_LL_L2MEM_NON_CACHE_ADDR(addr)) #else #define RMT_GET_NON_CACHE_ADDR(addr) (addr) #endif diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index 1d9e1a06e33..aafa4613b24 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -1098,27 +1098,30 @@ static void IRAM_ATTR rmt_tx_default_isr(void *args) static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { rmt_tx_channel_t *tx_chan = (rmt_tx_channel_t *)user_data; + // tx_eof_desc_addr must be non-zero, guaranteed by the hardware rmt_dma_descriptor_t *eof_desc_nc = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(event_data->tx_eof_desc_addr); - rmt_dma_descriptor_t *n = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(eof_desc_nc->next); // next points to a cache address, needs to convert it to a non-cached one - if (n) { - rmt_dma_descriptor_t *nn = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(n->next); - // if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event - if (nn) { - // continue ping-pong transmission - rmt_tx_trans_desc_t *t = tx_chan->cur_trans; - size_t encoded_symbols = t->transmitted_symbol_num; - if (t->flags.encoding_done) { - rmt_tx_mark_eof(tx_chan); - encoded_symbols += 1; - } else { - encoded_symbols += rmt_encode_check_result(tx_chan, t); - } - t->transmitted_symbol_num = encoded_symbols; - tx_chan->mem_end = tx_chan->ping_pong_symbols * 3 - tx_chan->mem_end; // mem_end equals to either ping_pong_symbols or ping_pong_symbols*2 - // tell DMA that we have a new descriptor attached - gdma_append(dma_chan); - } + if (!eof_desc_nc->next) { + return false; + } + // next points to a cache address, convert it to a non-cached one + rmt_dma_descriptor_t *n = (rmt_dma_descriptor_t *)RMT_GET_NON_CACHE_ADDR(eof_desc_nc->next); + if (!n->next) { + return false; } + // if the DMA descriptor link is still a ring (i.e. hasn't broken down by `rmt_tx_mark_eof()`), then we treat it as a valid ping-pong event + // continue ping-pong transmission + rmt_tx_trans_desc_t *t = tx_chan->cur_trans; + size_t encoded_symbols = t->transmitted_symbol_num; + if (t->flags.encoding_done) { + rmt_tx_mark_eof(tx_chan); + encoded_symbols += 1; + } else { + encoded_symbols += rmt_encode_check_result(tx_chan, t); + } + t->transmitted_symbol_num = encoded_symbols; + tx_chan->mem_end = tx_chan->ping_pong_symbols * 3 - tx_chan->mem_end; // mem_end equals to either ping_pong_symbols or ping_pong_symbols*2 + // tell DMA that we have a new descriptor attached + gdma_append(dma_chan); return false; } #endif // SOC_RMT_SUPPORT_DMA From 5a6b9fc1b2b9afbd07bf50048895b1667c3bcdef Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 26 Jun 2024 12:23:42 +0800 Subject: [PATCH 380/548] fix(ble): fixed some ble controller issues on ESP32-C2 --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index 8ddd8acac49..e597ae52976 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit 8ddd8acac498fcbb76b5a39c5c7d4025238298ab +Subproject commit e597ae529761d270f10d0616c375faa0e4b7ca13 diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 6d813e541d8..10634491c23 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -973,7 +973,6 @@ r_ble_lll_adv_coex_dpc_update_on_event_scheduled = 0x40001418; r_ble_lll_adv_done = 0x4000141c; r_ble_lll_adv_event_done = 0x40001424; r_ble_lll_adv_event_rmvd_from_sched = 0x40001428; -r_ble_lll_adv_ext_estimate_data_itvl = 0x4000142c; r_ble_lll_adv_get_sec_pdu_len = 0x40001430; r_ble_lll_adv_make_done = 0x40001438; r_ble_lll_adv_periodic_done = 0x4000143c; From 04e543949eb0e26a0963b7ac0b98046c9856b04d Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 2 Jul 2024 15:09:51 +0800 Subject: [PATCH 381/548] fix(ble): fixed some ble controller issues on ESP32C6 and ESP32H2 --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index ed6c0b4e0ab..4a63b2963a8 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit ed6c0b4e0ab3b8ddce5d8bc65e417b1adcbca5b4 +Subproject commit 4a63b2963a8a75958db680df4ace64bbd3d6c618 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 2d69367e13a..96b48749e24 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 2d69367e13a928afb73d1a8c579c0dad98eb9393 +Subproject commit 96b48749e249d0752f196007b008212cb8b28e07 From 580b6fbd3cf4a119a0321dae6d8d38a98b60b748 Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 2 Jul 2024 16:11:18 +0800 Subject: [PATCH 382/548] fix(ble): fixed some ble issues on ESP32C5 --- components/bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index 5f428f91411..2e05c001042 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit 5f428f914114c88470bf0a785f08840c2b35abca +Subproject commit 2e05c001042650bca426b672febd23c9ff45754e From 6089f8465399cda37fb57ee940ab9a9bfb248634 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:11:23 +0800 Subject: [PATCH 383/548] feat(bluetooth/controller): optimize bt hci layer code --- components/bt/CMakeLists.txt | 59 +- components/bt/host/bluedroid/hci/hci_hal_h4.c | 39 - .../transport/driver/common/hci_driver_h4.c | 356 ++++++++++ .../transport/driver/common/hci_driver_mem.c | 55 ++ .../transport/driver/common/hci_driver_util.c | 225 ++++++ .../transport/driver/uart/hci_driver_uart.c | 222 ++++++ .../transport/driver/uart/hci_driver_uart.h | 97 +++ .../driver/uart/hci_driver_uart_config.c | 40 ++ .../driver/uart/hci_driver_uart_dma.c | 670 ++++++++++++++++++ .../transport/driver/vhci/hci_driver_nimble.c | 61 ++ .../driver/vhci/hci_driver_standard.c | 149 ++++ .../driver/vhci/hci_driver_tamplete.c | 133 ++++ .../transport/include/common/hci_driver_h4.h | 75 ++ .../transport/include/common/hci_driver_mem.h | 25 + .../include/common/hci_driver_util.h | 18 + .../transport/include/esp_hci_driver.h | 52 ++ .../transport/include/esp_hci_internal.h | 121 ++++ .../transport/include/esp_hci_transport.h | 83 +++ .../bt/porting/transport/include/hci_uart.h | 100 --- .../bt/porting/transport/src/hci_transport.c | 175 +++++ .../bt/porting/transport/uart/hci_uart.c | 207 ------ 21 files changed, 2599 insertions(+), 363 deletions(-) create mode 100644 components/bt/porting/transport/driver/common/hci_driver_h4.c create mode 100644 components/bt/porting/transport/driver/common/hci_driver_mem.c create mode 100644 components/bt/porting/transport/driver/common/hci_driver_util.c create mode 100644 components/bt/porting/transport/driver/uart/hci_driver_uart.c create mode 100644 components/bt/porting/transport/driver/uart/hci_driver_uart.h create mode 100644 components/bt/porting/transport/driver/uart/hci_driver_uart_config.c create mode 100644 components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c create mode 100644 components/bt/porting/transport/driver/vhci/hci_driver_nimble.c create mode 100644 components/bt/porting/transport/driver/vhci/hci_driver_standard.c create mode 100644 components/bt/porting/transport/driver/vhci/hci_driver_tamplete.c create mode 100644 components/bt/porting/transport/include/common/hci_driver_h4.h create mode 100644 components/bt/porting/transport/include/common/hci_driver_mem.h create mode 100644 components/bt/porting/transport/include/common/hci_driver_util.h create mode 100644 components/bt/porting/transport/include/esp_hci_driver.h create mode 100644 components/bt/porting/transport/include/esp_hci_internal.h create mode 100644 components/bt/porting/transport/include/esp_hci_transport.h delete mode 100644 components/bt/porting/transport/include/hci_uart.h create mode 100644 components/bt/porting/transport/src/hci_transport.c delete mode 100644 components/bt/porting/transport/uart/hci_uart.c diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 6dd5ef9b378..24e1517aa3e 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -117,6 +117,7 @@ if(CONFIG_BT_ENABLED) common/btc/include common/include porting/mem/ + porting/include ) list(APPEND include_dirs ${common_include_dirs}) @@ -573,29 +574,51 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) + list(APPEND srcs + "porting/npl/freertos/src/npl_os_freertos.c" + "porting/mem/os_msys_init.c" + "porting/transport/src/hci_transport.c" + ) + + if(CONFIG_BT_CONTROLLER_DISABLED) list(APPEND srcs - "porting/npl/freertos/src/npl_os_freertos.c" - "porting/mem/os_msys_init.c" + "host/nimble/nimble/porting/nimble/src/hal_uart.c" ) - - if(CONFIG_BT_CONTROLLER_DISABLED) + elseif(CONFIG_BT_LE_HCI_INTERFACE_USE_RAM) + if(CONFIG_BT_NIMBLE_ENABLED) list(APPEND srcs - "host/nimble/nimble/porting/nimble/src/hal_uart.c" - ) + "porting/transport/driver/vhci/hci_driver_nimble.c" + "host/nimble/nimble/nimble/transport/esp_ipc/src/hci_esp_ipc.c" + ) + else() + list(APPEND srcs + "porting/transport/driver/vhci/hci_driver_standard.c" + ) endif() - list(APPEND include_dirs - porting/include - porting/npl/freertos/include - porting/transport/include - ) - - if(CONFIG_BT_LE_HCI_INTERFACE_USE_UART) + elseif(CONFIG_BT_LE_HCI_INTERFACE_USE_UART) list(APPEND srcs - "porting/transport/uart/hci_uart.c" - ) + "porting/transport/driver/common/hci_driver_util.c" + "porting/transport/driver/common/hci_driver_h4.c" + "porting/transport/driver/common/hci_driver_mem.c" + "porting/transport/driver/uart/hci_driver_uart_config.c" + ) + if(CONFIG_BT_LE_UART_HCI_DMA_MODE) + list(APPEND srcs + "porting/transport/driver/uart/hci_driver_uart_dma.c" + ) + else() + list(APPEND srcs + "porting/transport/driver/uart/hci_driver_uart.c" + ) endif() - endif() + endif() + list(APPEND include_dirs + porting/include + porting/npl/freertos/include + porting/transport/include + ) + endif() if(NOT (CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS OR CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS)) list(APPEND include_dirs @@ -621,7 +644,6 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_NIMBLE_ENABLED) list(APPEND include_dirs - host/nimble/nimble/nimble/host/include host/nimble/nimble/nimble/include host/nimble/nimble/nimble/host/services/ans/include @@ -725,10 +747,12 @@ if(CONFIG_BT_ENABLED) "host/nimble/nimble/porting/npl/freertos/src/nimble_port_freertos.c" "host/nimble/port/src/nvs_port.c" ) + list(APPEND include_dirs host/nimble/nimble/porting/nimble/include host/nimble/port/include host/nimble/nimble/nimble/transport/include + host/nimble/nimble/nimble/include ) if(CONFIG_BT_CONTROLLER_DISABLED) @@ -762,6 +786,7 @@ if(CONFIG_BT_ENABLED) if(CONFIG_BT_NIMBLE_LEGACY_VHCI_ENABLE AND CONFIG_BT_CONTROLLER_ENABLED) list(APPEND srcs "host/nimble/esp-hci/src/esp_nimble_hci.c" + "host/nimble/nimble/nimble/transport/esp_ipc_legacy/src/hci_esp_ipc_legacy.c" ) list(APPEND include_dirs ${nimble_hci_include_dirs}) endif() diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index 9663126ad62..47717803aea 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -35,10 +35,6 @@ #include "esp_bluedroid_hci.h" #include "stack/hcimsgs.h" -#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER) -#include "ble_hci_trans.h" -#endif - #if (C2H_FLOW_CONTROL_INCLUDED == TRUE) #include "l2c_int.h" #endif ///C2H_FLOW_CONTROL_INCLUDED == TRUE @@ -622,42 +618,7 @@ static int host_recv_pkt_cb(uint8_t *data, uint16_t len) return 0; } -#if ((BT_CONTROLLER_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER) - -int -ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg) -{ - if(esp_bluedroid_get_status() == ESP_BLUEDROID_STATUS_UNINITIALIZED) { - ble_hci_trans_buf_free(hci_ev); - return 0; - } - uint16_t len = hci_ev[1] + 3; - uint8_t *data = (uint8_t *)malloc(len); - assert(data != NULL); - data[0] = 0x04; - memcpy(&data[1], hci_ev, len - 1); - ble_hci_trans_buf_free(hci_ev); - host_recv_pkt_cb(data, len); - free(data); - return 0; -} - - -int -ble_hs_rx_data(struct os_mbuf *om, void *arg) -{ - uint16_t len = OS_MBUF_PKTHDR(om)->omp_len + 1; - uint8_t *data = (uint8_t *)malloc(len); - assert(data != NULL); - data[0] = 0x02; - os_mbuf_copydata(om, 0, len - 1, &data[1]); - host_recv_pkt_cb(data, len); - free(data); - os_mbuf_free_chain(om); - return 0; -} -#endif static const esp_bluedroid_hci_driver_callbacks_t hci_host_cb = { .notify_host_send_available = host_send_pkt_available_cb, .notify_host_recv = host_recv_pkt_cb, diff --git a/components/bt/porting/transport/driver/common/hci_driver_h4.c b/components/bt/porting/transport/driver/common/hci_driver_h4.c new file mode 100644 index 00000000000..c31b71164e6 --- /dev/null +++ b/components/bt/porting/transport/driver/common/hci_driver_h4.c @@ -0,0 +1,356 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include "common/hci_driver_h4.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define HCI_H4_SM_W4_PKT_TYPE 0 +#define HCI_H4_SM_W4_HEADER 1 +#define HCI_H4_SM_W4_PAYLOAD 2 +#define HCI_H4_SM_COMPLETED 3 + +struct hci_h4_input_buffer { + const uint8_t *buf; + uint16_t len; +}; + +static int +hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type) +{ + rxs->pkt_type = pkt_type; + rxs->len = 0; + rxs->exp_len = 0; + + switch (rxs->pkt_type) { + case HCI_H4_CMD: + rxs->min_len = 3; + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + rxs->min_len = 4; + break; + case HCI_H4_EVT: + rxs->min_len = 2; + break; + default: + /* !TODO: Sync loss. Need to wait for reset. */ + return -1; + } + + return 0; +} + +static int +hci_h4_ib_consume(struct hci_h4_input_buffer *ib, uint16_t len) +{ + assert(ib->len >= len); + + ib->buf += len; + ib->len -= len; + + return len; +} + +static int +hci_h4_ib_pull_min_len(struct hci_h4_sm *rxs, + struct hci_h4_input_buffer *ib) +{ + uint16_t len; + + len = min(ib->len, rxs->min_len - rxs->len); + memcpy(&rxs->hdr[rxs->len], ib->buf, len); + + rxs->len += len; + hci_h4_ib_consume(ib, len); + + + return rxs->len != rxs->min_len; +} + +static int +hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib) +{ + int rc; + + rc = hci_h4_ib_pull_min_len(h4sm, ib); + if (rc) { + /* need more data */ + return 1; + } + + switch (h4sm->pkt_type) { + case HCI_H4_CMD: + assert(h4sm->allocs && h4sm->allocs->cmd); + h4sm->buf = h4sm->allocs->cmd(); + if (!h4sm->buf) { + return -1; + } + + memcpy(h4sm->buf, h4sm->hdr, h4sm->len); + h4sm->exp_len = h4sm->hdr[2] + 3; + + break; + case HCI_H4_ACL: + assert(h4sm->allocs && h4sm->allocs->acl); + h4sm->om = h4sm->allocs->acl(); + if (!h4sm->om) { + return -1; + } + + os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len); + h4sm->exp_len = get_le16(&h4sm->hdr[2]) + 4; + break; +#if !CONFIG_BT_CONTROLLER_ENABLED + case HCI_H4_EVT: + if (h4sm->hdr[0] == BLE_HCI_EVCODE_LE_META) { + /* For LE Meta event we need 3 bytes to parse header */ + h4sm->min_len = 3; + rc = hci_h4_ib_pull_min_len(h4sm, ib); + if (rc) { + /* need more data */ + return 1; + } + } + + assert(h4sm->allocs && h4sm->allocs->evt); + + /* We can drop legacy advertising events if there's no free buffer in + * discardable pool. + */ + if (h4sm->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) { + h4sm->buf = h4sm->allocs->evt(1); + } else { + h4sm->buf = h4sm->allocs->evt(0); + if (!h4sm->buf) { + return -1; + } + } + + if (h4sm->buf) { + memcpy(h4sm->buf, h4sm->hdr, h4sm->len); + } + + h4sm->exp_len = h4sm->hdr[1] + 2; + break; +#endif // !CONFIG_BT_CONTROLLER_ENABLED + case HCI_H4_ISO: + assert(h4sm->allocs && h4sm->allocs->iso); + h4sm->om = h4sm->allocs->iso(); + if (!h4sm->om) { + return -1; + } + + os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len); + h4sm->exp_len = (get_le16(&h4sm->hdr[2]) & 0x7fff) + 4; + break; + default: + assert(0); + break; + } + + return 0; +} + +static int +hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm, + struct hci_h4_input_buffer *ib) +{ + uint16_t mbuf_len; + uint16_t len; + int rc; + + len = min(ib->len, h4sm->exp_len - h4sm->len); + + + switch (h4sm->pkt_type) { + case HCI_H4_CMD: + case HCI_H4_EVT: + if (h4sm->buf) { + memcpy(&h4sm->buf[h4sm->len], ib->buf, len); + } + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + assert(h4sm->om); + + mbuf_len = OS_MBUF_PKTLEN(h4sm->om); + rc = os_mbuf_append(h4sm->om, ib->buf, len); + if (rc) { + /* Some data may already be appended so need to adjust h4sm only by + * the size of appended data. + */ + len = OS_MBUF_PKTLEN(h4sm->om) - mbuf_len; + h4sm->len += len; + hci_h4_ib_consume(ib, len); + + return -1; + } + break; + default: + assert(0); + break; + } + + h4sm->len += len; + hci_h4_ib_consume(ib, len); + + /* return 1 if need more data */ + return h4sm->len != h4sm->exp_len; +} + +static void +hci_h4_sm_completed(struct hci_h4_sm *h4sm) +{ + int rc; + + switch (h4sm->pkt_type) { +#if CONFIG_BT_CONTROLLER_ENABLED + case HCI_H4_CMD: + if (h4sm->buf) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf); + assert(rc == 0); + h4sm->buf = NULL; + } + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + if (h4sm->om) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om); + assert(rc == 0); + h4sm->om = NULL; + } + break; +#else + case HCI_H4_CMD: + case HCI_H4_EVT: + if (h4sm->buf) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf); + if (rc != 0) { + ble_transport_free(h4sm->buf); + } + h4sm->buf = NULL; + } + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + if (h4sm->om) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om); + if (rc != 0) { + os_mbuf_free_chain(h4sm->om); + } + h4sm->om = NULL; + } + break; +#endif // CONFIG_BT_CONTROLLER_ENABLED + default: + assert(0); + break; + } +} + +int +hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len) +{ + struct hci_h4_input_buffer ib = { + .buf = buf, + .len = len, + }; + + int rc = 0; + while (ib.len && (rc >= 0)) { + rc = 0; + switch (h4sm->state) { + case HCI_H4_SM_W4_PKT_TYPE: + if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) { + return -1; + } + + hci_h4_ib_consume(&ib, 1); + h4sm->state = HCI_H4_SM_W4_HEADER; + /* no break */ + case HCI_H4_SM_W4_HEADER: + rc = hci_h4_sm_w4_header(h4sm, &ib); + assert(rc >= 0); + if (rc) { + break; + } + h4sm->state = HCI_H4_SM_W4_PAYLOAD; + /* no break */ + case HCI_H4_SM_W4_PAYLOAD: + rc = hci_h4_sm_w4_payload(h4sm, &ib); + assert(rc >= 0); + if (rc) { + break; + } + h4sm->state = HCI_H4_SM_COMPLETED; + /* no break */ + case HCI_H4_SM_COMPLETED: + hci_h4_sm_completed(h4sm); + h4sm->state = HCI_H4_SM_W4_PKT_TYPE; + break; + default: + return -1; + } + } + + /* Calculate consumed bytes + * + * Note: we should always consume some bytes unless there is an oom error. + * It's also possible that we have an oom error but already consumed some + * data, in such case just return success and error will be returned on next + * pass. + */ + len = len - ib.len; + if (len == 0) { + assert(rc < 0); + return -1; + } + + return len; +} + +void +hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs, + hci_h4_frame_cb *frame_cb) +{ + memset(h4sm, 0, sizeof(*h4sm)); + h4sm->allocs = allocs; + h4sm->frame_cb = frame_cb; +} diff --git a/components/bt/porting/transport/driver/common/hci_driver_mem.c b/components/bt/porting/transport/driver/common/hci_driver_mem.c new file mode 100644 index 00000000000..acfdf793f67 --- /dev/null +++ b/components/bt/porting/transport/driver/common/hci_driver_mem.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "common/hci_driver_mem.h" +#include "common/hci_driver_h4.h" +#include "esp_hci_internal.h" + +void * +hci_driver_mem_cmd_alloc(void) +{ + return r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD); +} + +void * +hci_driver_mem_evt_alloc(int discardable) +{ + /* The controller shouldn't invoke this. */ + assert(0); + return NULL; +} + +struct os_mbuf * +hci_driver_mem_acl_alloc(void) +{ + return os_msys_get_pkthdr(0, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); +} + +struct os_mbuf * +hci_driver_mem_acl_len_alloc(uint32_t len) +{ + return os_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); +} + +struct os_mbuf * +hci_driver_mem_iso_alloc(void) +{ + return os_msys_get_pkthdr(0, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); +} + +struct os_mbuf * +hci_driver_mem_iso_len_alloc(uint32_t len) +{ + return os_msys_get_pkthdr(len, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); +} + +const struct hci_h4_allocators s_hci_driver_mem_alloc = { + .cmd = hci_driver_mem_cmd_alloc, + .evt = hci_driver_mem_evt_alloc, + .acl = hci_driver_mem_acl_alloc, + .iso = hci_driver_mem_iso_alloc, +}; diff --git a/components/bt/porting/transport/driver/common/hci_driver_util.c b/components/bt/porting/transport/driver/common/hci_driver_util.c new file mode 100644 index 00000000000..30fe8d13c46 --- /dev/null +++ b/components/bt/porting/transport/driver/common/hci_driver_util.c @@ -0,0 +1,225 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_log.h" +#include "os/os.h" +#include "os/os_mempool.h" +#include "esp_hci_driver.h" +#include "esp_hci_internal.h" +#include "common/hci_driver_util.h" + +#define TAG "HCI_UTIL" +#define HCI_DRIVER_UTIL_TX_POOL_NUM \ + (CONFIG_BT_LE_ACL_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_HI_BUF_COUNT + CONFIG_BT_LE_HCI_EVT_LO_BUF_COUNT) + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/** + * @brief Structure representing HCI TX data. + */ +typedef struct hci_driver_util_tx_entry { + hci_driver_data_type_t data_type; ///< Type of the HCI TX data. + uint8_t *data; ///< Pointer to the TX data. + uint32_t length; ///< Length of the TX data. + STAILQ_ENTRY(hci_driver_util_tx_entry) next; ///< Next element in the linked list. +} hci_driver_util_tx_entry_t; + +/* The list for hci_driver_util_tx_entry */ +STAILQ_HEAD(hci_driver_util_tx_list, hci_driver_util_tx_entry); + +typedef struct { + struct hci_driver_util_tx_list tx_head; + struct hci_driver_util_tx_entry *cur_tx_entry; + uint32_t cur_tx_off; + struct os_mempool *tx_entry_pool; + uint8_t *tx_entry_mem; +} hci_driver_util_env_t; + +static hci_driver_util_env_t s_hci_driver_util_env; + +static void +hci_driver_util_memory_deinit(void) +{ + if (s_hci_driver_util_env.tx_entry_pool) { + free(s_hci_driver_util_env.tx_entry_pool); + s_hci_driver_util_env.tx_entry_pool = NULL; + } + if (s_hci_driver_util_env.tx_entry_mem) { + free(s_hci_driver_util_env.tx_entry_mem); + s_hci_driver_util_env.tx_entry_mem = NULL; + } +} + +static int +hci_driver_util_memory_init(void) +{ + int rc; + + s_hci_driver_util_env.tx_entry_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool)); + if (!s_hci_driver_util_env.tx_entry_pool) { + ESP_LOGE(TAG, "No memory for tx pool"); + goto init_err; + } + + s_hci_driver_util_env.tx_entry_mem = malloc(OS_MEMPOOL_SIZE(HCI_DRIVER_UTIL_TX_POOL_NUM, + sizeof(hci_driver_util_tx_entry_t)) * sizeof(os_membuf_t)); + if (!s_hci_driver_util_env.tx_entry_mem) { + ESP_LOGE(TAG, "No memory for tx pool buffer"); + goto init_err; + } + + rc = os_mempool_init(s_hci_driver_util_env.tx_entry_pool, HCI_DRIVER_UTIL_TX_POOL_NUM, + sizeof(hci_driver_util_tx_entry_t), s_hci_driver_util_env.tx_entry_mem, + "hci_tx_entry_pool"); + if (rc) { + ESP_LOGE(TAG, "Failed to initialize tx pool"); + goto init_err; + } + + return 0; + +init_err: + hci_driver_util_memory_deinit(); + return -1; +} + +void +hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len) +{ + os_sr_t sr; + hci_driver_util_tx_entry_t *tx_entry; + + tx_entry = os_memblock_get(s_hci_driver_util_env.tx_entry_pool); + assert(tx_entry != NULL); + tx_entry->data_type = type; + tx_entry->data = data; + tx_entry->length = len; + /* If the txbuf is command status event or command complete event, we should send firstly. + * The tx list maybe used in the controller task and hci task. Therefore, enter critical area. + */ + if ((type == HCI_DRIVER_TYPE_EVT) && ((data[0] == 0x0E) || (data[0] == 0x0F))) { + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_HEAD(&s_hci_driver_util_env.tx_head, tx_entry, next); + OS_EXIT_CRITICAL(sr); + } else { + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&s_hci_driver_util_env.tx_head, tx_entry, next); + OS_EXIT_CRITICAL(sr); + } +} + +uint32_t +hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame) +{ + os_sr_t sr; + uint32_t tx_len; + uint32_t data_len; + uint16_t out_off; + struct os_mbuf *om; + hci_driver_util_tx_entry_t *tx_entry; + + /* Check if there is any remaining data that hasn't been sent completely. If it has been completed, + * free the corresponding memory. Therefore, the HCI TX entry needs to be sent one by one; multiple + * entries cannot be sent together. + */ + tx_len = 0; + tx_entry = s_hci_driver_util_env.cur_tx_entry; + if (tx_entry) { + data_len = tx_entry->length; + if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) { + om = (struct os_mbuf *)tx_entry->data; + if (s_hci_driver_util_env.cur_tx_off >= data_len) { + os_mbuf_free_chain(om); + } else { + om = os_mbuf_off(om, s_hci_driver_util_env.cur_tx_off, &out_off); + tx_len = min(max_tx_len, om->om_len - out_off); + *tx_data = (void *)&om->om_data[out_off]; + } + } else if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) { + if (s_hci_driver_util_env.cur_tx_off >= data_len) { + r_ble_hci_trans_buf_free(tx_entry->data); + } else { + tx_len = min(max_tx_len, data_len - s_hci_driver_util_env.cur_tx_off); + *tx_data = &tx_entry->data[s_hci_driver_util_env.cur_tx_off]; + } + } else { + assert(0); + } + /* If this is the last frame, inform the invoker not to call this API until the current data + * has been completely sent. + */ + if (tx_len) { + s_hci_driver_util_env.cur_tx_off += tx_len; + + if (s_hci_driver_util_env.cur_tx_off >= data_len) { + *last_frame = true; + } else { + *last_frame = false; + } + } else { + os_memblock_put(s_hci_driver_util_env.tx_entry_pool, (void *)tx_entry); + s_hci_driver_util_env.cur_tx_entry = NULL; + } + } + + /* Find a new entry. */ + if (!tx_len && !STAILQ_EMPTY(&s_hci_driver_util_env.tx_head)) { + OS_ENTER_CRITICAL(sr); + tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head); + STAILQ_REMOVE_HEAD(&s_hci_driver_util_env.tx_head, next); + OS_EXIT_CRITICAL(sr); + + *tx_data = &tx_entry->data_type; + s_hci_driver_util_env.cur_tx_entry = tx_entry; + s_hci_driver_util_env.cur_tx_off = 0; + tx_len = 1; + *last_frame = false; + } + + return tx_len; +} + +int +hci_driver_util_init(void) +{ + memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t)); + + if (hci_driver_util_memory_init()) { + return -1; + } + + STAILQ_INIT(&s_hci_driver_util_env.tx_head); + + return 0; +} + +void +hci_driver_util_deinit(void) +{ + hci_driver_util_tx_entry_t *tx_entry; + hci_driver_util_tx_entry_t *next_entry; + + /* Free all of controller buffers which haven't been sent yet. The whole mempool will be freed. + * Therefore, it's unnecessary to put the tx_entry into mempool. + */ + tx_entry = STAILQ_FIRST(&s_hci_driver_util_env.tx_head); + while (tx_entry) { + next_entry = STAILQ_NEXT(tx_entry, next); + if (tx_entry->data_type == HCI_DRIVER_TYPE_ACL) { + os_mbuf_free_chain((struct os_mbuf *)tx_entry->data); + } else if (tx_entry->data_type == HCI_DRIVER_TYPE_EVT) { + r_ble_hci_trans_buf_free(tx_entry->data); + } + tx_entry = next_entry; + } + + hci_driver_util_memory_deinit(); + + memset(&s_hci_driver_util_env, 0, sizeof(hci_driver_util_env_t)); +} diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart.c b/components/bt/porting/transport/driver/uart/hci_driver_uart.c new file mode 100644 index 00000000000..6ac2a462fa1 --- /dev/null +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart.c @@ -0,0 +1,222 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "driver/uart.h" +#include "esp_hci_transport.h" +#include "esp_hci_internal.h" +#include "common/hci_driver_h4.h" +#include "common/hci_driver_util.h" +#include "common/hci_driver_mem.h" +#include "hci_driver_uart.h" + +static const char *TAG = "hci_uart"; + +#define CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN (256) + +typedef struct { + TaskHandle_t tx_task_handler; + TaskHandle_t rx_task_handler; + hci_driver_uart_params_config_t *hci_uart_params; + SemaphoreHandle_t tx_sem; + QueueHandle_t rx_event_queue; + uint8_t *rx_data; + struct hci_h4_sm *h4_sm; + hci_driver_forward_fn *forward_cb; +} hci_driver_uart_env_t; + +static hci_driver_uart_env_t s_hci_driver_uart_env; +static struct hci_h4_sm s_hci_driver_uart_h4_sm; +static uint8_t s_hci_driver_uart_rx_data[CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN]; +static hci_driver_uart_params_config_t hci_driver_uart_params = BT_HCI_DRIVER_UART_CONFIG_DEFAULT(); + +static int +hci_driver_uart_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + /* By now, this layer is only used by controller. */ + assert(dir == HCI_DRIVER_DIR_C2H); + ESP_LOGD(TAG, "controller tx len:%d\n", length); + + hci_driver_util_tx_list_enqueue(data_type, data, length); + xSemaphoreGive(s_hci_driver_uart_env.tx_sem); + + return 0; +} + +static int +hci_driver_uart_h4_frame_cb(uint8_t pkt_type, void *data) +{ + hci_driver_forward_fn *forward_cb; + + forward_cb = s_hci_driver_uart_env.forward_cb; + if (!forward_cb) { + return -1; + } + ESP_LOGD(TAG, "h4 frame\n"); + return forward_cb(pkt_type, data, 0, HCI_DRIVER_DIR_H2C); +} + +static void +hci_driver_uart_tx_task(void *p) +{ + void *data; + bool last_frame; + uint32_t tx_len; + uart_port_t port; + + port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port; + while (true) { + xSemaphoreTake(s_hci_driver_uart_env.tx_sem, portMAX_DELAY); + while (true) { + tx_len = hci_driver_util_tx_list_dequeue(0xffffff, &data, &last_frame); + if (tx_len == 0) { + break; + } + ESP_LOGD(TAG, "uart tx"); + ESP_LOG_BUFFER_HEXDUMP(TAG, data, tx_len, ESP_LOG_DEBUG); + uart_write_bytes(port, data, tx_len); + } + } +} + +static void +hci_driver_uart_rx_task(void *p) +{ + void *data; + int read_len; + int ret; + uart_port_t port; + uart_event_t uart_event; + + port = s_hci_driver_uart_env.hci_uart_params->hci_uart_port; + while (true) { + xQueueReceive(s_hci_driver_uart_env.rx_event_queue, &uart_event, portMAX_DELAY); + data = s_hci_driver_uart_env.rx_data; + while (true) { + read_len = uart_read_bytes(port, data, CONFIG_BT_LE_HCI_RX_PROC_DATA_LEN, 0); + if (read_len == 0) { + break; + } + ESP_LOGD(TAG, "uart rx"); + ESP_LOG_BUFFER_HEXDUMP(TAG, data, read_len, ESP_LOG_DEBUG); + ret = hci_h4_sm_rx(s_hci_driver_uart_env.h4_sm, data, read_len); + if (ret < 0) { + r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR); + } + } + } +} + +static int +hci_driver_uart_task_create(void) +{ + /* !TODO: Set the core id by menuconfig */ + xTaskCreatePinnedToCore(hci_driver_uart_tx_task, "hci_driver_uart_tx_task", + CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL, + ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.tx_task_handler, + 0); + assert(s_hci_driver_uart_env.tx_task_handler); + + xTaskCreatePinnedToCore(hci_driver_uart_rx_task, "hci_driver_uart_rx_task", + CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL, + ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_env.rx_task_handler, + 0); + assert(s_hci_driver_uart_env.rx_task_handler); + + ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld", + ESP_TASK_BT_CONTROLLER_PRIO, CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE); + + return 0; +} + +static void +hci_driver_uart_deinit(void) +{ + if (s_hci_driver_uart_env.tx_task_handler) { + vTaskDelete(s_hci_driver_uart_env.tx_task_handler); + s_hci_driver_uart_env.tx_task_handler = NULL; + } + + if (s_hci_driver_uart_env.rx_task_handler) { + vTaskDelete(s_hci_driver_uart_env.rx_task_handler); + s_hci_driver_uart_env.rx_task_handler = NULL; + } + + ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_env.hci_uart_params->hci_uart_port)); + + if (!s_hci_driver_uart_env.tx_sem) { + vSemaphoreDelete(s_hci_driver_uart_env.tx_sem); + } + + hci_driver_util_deinit(); + memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t)); +} + +static int +hci_driver_uart_init(hci_driver_forward_fn *cb) +{ + int rc; + memset(&s_hci_driver_uart_env, 0, sizeof(hci_driver_uart_env_t)); + + s_hci_driver_uart_env.h4_sm = &s_hci_driver_uart_h4_sm; + hci_h4_sm_init(s_hci_driver_uart_env.h4_sm, &s_hci_driver_mem_alloc, hci_driver_uart_h4_frame_cb); + + rc = hci_driver_util_init(); + if (rc) { + goto error; + } + + s_hci_driver_uart_env.tx_sem = xSemaphoreCreateBinary(); + if (!s_hci_driver_uart_env.tx_sem) { + goto error; + } + + s_hci_driver_uart_env.rx_data = s_hci_driver_uart_rx_data; + s_hci_driver_uart_env.forward_cb = cb; + s_hci_driver_uart_env.hci_uart_params = &hci_driver_uart_params; + hci_driver_uart_config(&hci_driver_uart_params); + /* Currently, the queue size is set to 1. It will be considered as semaphore. */ + ESP_ERROR_CHECK(uart_driver_install(s_hci_driver_uart_env.hci_uart_params->hci_uart_port, + CONFIG_BT_LE_HCI_UART_RX_BUFFER_SIZE, + CONFIG_BT_LE_HCI_UART_TX_BUFFER_SIZE, + 1, &s_hci_driver_uart_env.rx_event_queue, + 0)); + + rc = hci_driver_uart_task_create(); + if (rc) { + goto error; + } + + return 0; + +error: + hci_driver_uart_deinit(); + return rc; +} + +int +hci_driver_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin) +{ + hci_driver_uart_params_config_t *uart_param = s_hci_driver_uart_env.hci_uart_params; + uart_param->hci_uart_tx_pin = tx_pin; + uart_param->hci_uart_rx_pin = rx_pin; + uart_param->hci_uart_rts_pin = rts_pin; + uart_param->hci_uart_cts_pin = cts_pin; + return hci_driver_uart_config(uart_param); +} + +hci_driver_ops_t hci_driver_uart_ops = { + .hci_driver_tx = hci_driver_uart_tx, + .hci_driver_init = hci_driver_uart_init, + .hci_driver_deinit = hci_driver_uart_deinit, +}; diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart.h b/components/bt/porting/transport/driver/uart/hci_driver_uart.h new file mode 100644 index 00000000000..8b5f5eb8560 --- /dev/null +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart.h @@ -0,0 +1,97 @@ +/* + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "driver/uart.h" +#include "os/os_mbuf.h" +#include "esp_bt.h" +#include "esp_hci_transport.h" + +/** + * @brief UART configuration parameters for the HCI driver + */ +typedef struct hci_driver_uart_params_config +{ + uint8_t hci_uart_port; /*!< Port of UART for HCI */ + uint8_t hci_uart_data_bits; /*!< Data bits of UART for HCI */ + uint8_t hci_uart_stop_bits; /*!< Stop bits of UART for HCI */ + uint8_t hci_uart_flow_ctrl; /*!< Flow control of UART for HCI */ + uint8_t hci_uart_parity; /*!< UART parity */ + uint8_t hci_uart_driver_mode; /*!< UART driver mode */ + uint32_t hci_uart_baud; /*!< Baudrate of UART for HCI */ + int hci_uart_tx_pin; /*!< Tx Pin number of UART for HCI */ + int hci_uart_rx_pin; /*!< Rx Pin number of UART for HCI */ + int hci_uart_rts_pin; /*!< RTS Pin number of UART for HCI */ + int hci_uart_cts_pin; /*!< CTS Pin number of UART for HCI */ +} hci_driver_uart_params_config_t; + +#define BT_HCI_DRIVER_UART_CONFIG_DEFAULT() { \ + .hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \ + .hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \ + .hci_uart_tx_pin = DEFAULT_BT_LE_HCI_UART_TX_PIN , \ + .hci_uart_rx_pin = DEFAULT_BT_LE_HCI_UART_RX_PIN, \ + .hci_uart_cts_pin = DEFAULT_BT_LE_HCI_UART_CTS_PIN, \ + .hci_uart_rts_pin = DEFAULT_BT_LE_HCI_UART_RTS_PIN, \ + .hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \ + .hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \ + .hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \ + .hci_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \ +} + +/** + * @brief Configures the HCI driver UART parameters. + * This function sets up the UART interface according to the specified configuration parameters. + * + * @param uart_config A pointer to a structure containing the UART configuration parameters. + * The structure should include details such as baud rate, parity, stop bits, and flow control. + * Ensure that the uart_config structure is correctly initialized before calling this function. + * + * @return int Returns 0 on success, or a non-zero error code on failure. + * + * @note This function should be called before any UART communication is initiated. + */ +int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config); + +#if CONFIG_BT_LE_UART_HCI_DMA_MODE +/** + * @brief Reconfigure the UART pins for the HCI driver. + * + * This function changes the UART pin configuration for the HCI driver. + * + * @param tx_pin The pin number for the UART TX (transmit) line. + * @param rx_pin The pin number for the UART RX (receive) line. + * @param cts_pin The pin number for the UART CTS (clear to send) line. + * @param rts_pin The pin number for the UART RTS (request to send) line. + * + * @return int Returns 0 on success, or a negative error code on failure. + */ +int hci_driver_uart_dma_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin); +#define hci_uart_reconfig_pin hci_driver_uart_dma_reconfig_pin +#else +/** + * @brief Reconfigure the UART pins for the HCI driver. + * + * This function changes the UART pin configuration for the HCI driver. + * + * @param tx_pin The pin number for the UART TX (transmit) line. + * @param rx_pin The pin number for the UART RX (receive) line. + * @param cts_pin The pin number for the UART CTS (clear to send) line. + * @param rts_pin The pin number for the UART RTS (request to send) line. + * + * @return int Returns 0 on success, or a negative error code on failure. + */ +int hci_driver_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin); +#define hci_uart_reconfig_pin hci_driver_uart_reconfig_pin +#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE + +#ifdef __cplusplus +} +#endif diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_config.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_config.c new file mode 100644 index 00000000000..aae33634647 --- /dev/null +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_config.c @@ -0,0 +1,40 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_log.h" +#include "driver/uart.h" +#include "hci_driver_uart.h" + + +static const char *TAG = "hci_uart_config"; +static uart_config_t s_uart_cfg; + +int hci_driver_uart_config(hci_driver_uart_params_config_t *uart_config) +{ + uart_config_t *uart_cfg; + uart_cfg = &s_uart_cfg; + uart_cfg->baud_rate = uart_config->hci_uart_baud; + uart_cfg->data_bits = uart_config->hci_uart_data_bits; + uart_cfg->stop_bits = uart_config->hci_uart_stop_bits; + uart_cfg->parity = uart_config->hci_uart_parity; + uart_cfg->flow_ctrl = uart_config->hci_uart_flow_ctrl; + uart_cfg->source_clk= UART_SCLK_DEFAULT; + uart_cfg->rx_flow_ctrl_thresh = UART_HW_FIFO_LEN(uart_config->hci_uart_port) - 1; + + + ESP_LOGI(TAG,"set uart pin tx:%d, rx:%d.\n", uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin); + ESP_LOGI(TAG,"set rts:%d, cts:%d.\n", uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin); + ESP_LOGI(TAG,"set baud_rate:%d.\n", uart_config->hci_uart_baud); + ESP_LOGI(TAG,"set flow_ctrl:%d.\n", uart_config->hci_uart_flow_ctrl); + + ESP_ERROR_CHECK(uart_driver_delete(uart_config->hci_uart_port)); + ESP_ERROR_CHECK(uart_param_config(uart_config->hci_uart_port, uart_cfg)); + ESP_ERROR_CHECK(uart_set_pin(uart_config->hci_uart_port, uart_config->hci_uart_tx_pin, uart_config->hci_uart_rx_pin, + uart_config->hci_uart_rts_pin, uart_config->hci_uart_cts_pin)); + return 0; +} diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c new file mode 100644 index 00000000000..a90fb749a11 --- /dev/null +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -0,0 +1,670 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "driver/uart.h" +#include "esp_hci_transport.h" +#include "esp_hci_internal.h" +#include "common/hci_driver_h4.h" +#include "common/hci_driver_util.h" +#include "common/hci_driver_mem.h" +#include "hci_driver_uart.h" + +#include "ble_hci_trans.h" +#include "esp_private/periph_ctrl.h" +#include "esp_private/gdma.h" +#include "hal/uhci_ll.h" + +/* + * UART DMA Desc struct + * + * -------------------------------------------------------------- + * | own | EoF | sub_sof | 5'b0 | length [11:0] | size [11:0] | + * -------------------------------------------------------------- + * | buf_ptr [31:0] | + * -------------------------------------------------------------- + * | next_desc_ptr [31:0] | + * -------------------------------------------------------------- + */ + +/* this bitfield is start from the LSB!!! */ +typedef struct uhci_lldesc_s { + volatile uint32_t size : 12, + length: 12, + offset: 5, /* h/w reserved 5bit, s/w use it as offset in buffer */ + sosf : 1, /* start of sub-frame */ + eof : 1, /* end of frame */ + owner : 1; /* hw or sw */ + volatile const uint8_t *buf; /* point to buffer data */ + union { + volatile uint32_t empty; + STAILQ_ENTRY(uhci_lldesc_s) qe; /* pointing to the next desc */ + }; +} uhci_lldesc_t; + +/** + * @brief Enumeration of HCI transport transmission states. + */ +typedef enum { + HCI_TRANS_TX_IDLE, ///< HCI Transport TX is in idle state. + HCI_TRANS_TX_START, ///< HCI Transport TX is starting transmission. + HCI_TRANS_TX_END, ///< HCI Transport TX has completed transmission. +} hci_trans_tx_state_t; + +typedef struct { + TaskHandle_t task_handler; + hci_driver_uart_params_config_t *hci_uart_params; + SemaphoreHandle_t process_sem; + struct hci_h4_sm *h4_sm; + hci_driver_forward_fn *forward_cb; + struct os_mempool *hci_rx_data_pool; /*!< Init a memory pool for rx_data cache */ + uint8_t *hci_rx_data_buffer; + struct os_mempool *hci_rxinfo_pool; /*!< Init a memory pool for rxinfo cache */ + os_membuf_t *hci_rxinfo_buffer; + volatile bool rxinfo_mem_exhausted; /*!< Indicate rxinfo memory does not exist */ + volatile bool is_continue_rx; /*!< Continue to rx */ + volatile hci_trans_tx_state_t hci_tx_state; /*!< HCI Tx State */ + struct os_mempool lldesc_mem_pool;/*!< Init a memory pool for uhci_lldesc_t */ + uhci_lldesc_t *lldesc_mem; +} hci_driver_uart_dma_env_t; + +#define ESP_BT_HCI_TL_STATUS_OK (0) /*!< HCI_TL Tx/Rx operation status OK */ +/* The number of lldescs pool */ +#define HCI_LLDESCS_POOL_NUM (CONFIG_BT_LE_HCI_LLDESCS_POOL_NUM) +/* Default block size for HCI RX data */ +#define HCI_RX_DATA_BLOCK_SIZE (DEFAULT_BT_LE_ACL_BUF_SIZE + BLE_HCI_TRANS_CMD_SZ) +#define HCI_RX_DATA_POOL_NUM (CONFIG_BT_LE_HCI_TRANS_RX_MEM_NUM) +#define HCI_RX_INFO_POOL_NUM (CONFIG_BT_LE_HCI_TRANS_RX_MEM_NUM + 1) + +/** + * @brief callback function for HCI Transport Layer send/receive operations + */ +typedef void (* esp_bt_hci_tl_callback_t) (void *arg, uint8_t status); + +struct uart_txrxchannel { + esp_bt_hci_tl_callback_t callback; + void *arg; + uhci_lldesc_t *link_head; +}; + +struct uart_env_tag { + struct uart_txrxchannel tx; + struct uart_txrxchannel rx; +}; + +typedef struct hci_message { + void *ptr; ///< Pointer to the message data. + uint32_t length; ///< Length of the message data. + STAILQ_ENTRY(hci_message) next; ///< Next element in the linked list. +} hci_message_t; + +static void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg); +int hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length); +int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg); + +static const char *TAG = "uart_dma"; +static hci_driver_uart_dma_env_t s_hci_driver_uart_dma_env; +static struct hci_h4_sm s_hci_driver_uart_h4_sm; +static hci_driver_uart_params_config_t hci_driver_uart_dma_params = BT_HCI_DRIVER_UART_CONFIG_DEFAULT(); + +/* The list for hci_rx_data */ +STAILQ_HEAD(g_hci_rxinfo_list, hci_message); + +DRAM_ATTR struct g_hci_rxinfo_list g_hci_rxinfo_head; +static DRAM_ATTR struct uart_env_tag uart_env; +static volatile uhci_dev_t *s_uhci_hw = &UHCI0; +static DRAM_ATTR gdma_channel_handle_t s_rx_channel; +static DRAM_ATTR gdma_channel_handle_t s_tx_channel; + +static int hci_driver_uart_dma_memory_deinit(void) +{ + + if (s_hci_driver_uart_dma_env.hci_rxinfo_buffer) { + free(s_hci_driver_uart_dma_env.hci_rxinfo_buffer); + s_hci_driver_uart_dma_env.hci_rxinfo_buffer = NULL; + } + + if (s_hci_driver_uart_dma_env.hci_rxinfo_pool) { + free(s_hci_driver_uart_dma_env.hci_rxinfo_pool); + s_hci_driver_uart_dma_env.hci_rxinfo_pool = NULL; + } + + if (s_hci_driver_uart_dma_env.hci_rx_data_buffer) { + free(s_hci_driver_uart_dma_env.hci_rx_data_buffer); + s_hci_driver_uart_dma_env.hci_rx_data_buffer = NULL; + } + + if (s_hci_driver_uart_dma_env.hci_rx_data_pool) { + free(s_hci_driver_uart_dma_env.hci_rx_data_pool); + s_hci_driver_uart_dma_env.hci_rx_data_pool = NULL; + } + + if (s_hci_driver_uart_dma_env.lldesc_mem) { + free(s_hci_driver_uart_dma_env.lldesc_mem); + s_hci_driver_uart_dma_env.lldesc_mem = NULL; + } + + return 0; +} + +static int hci_driver_uart_dma_memory_init(void) +{ + int rc = 0; + + s_hci_driver_uart_dma_env.lldesc_mem = malloc(OS_MEMPOOL_SIZE(HCI_LLDESCS_POOL_NUM, + sizeof (uhci_lldesc_t)) * sizeof(os_membuf_t)); + if (!s_hci_driver_uart_dma_env.lldesc_mem) { + return -1; + } + + rc = os_mempool_init(&s_hci_driver_uart_dma_env.lldesc_mem_pool, HCI_LLDESCS_POOL_NUM, + sizeof (uhci_lldesc_t), s_hci_driver_uart_dma_env.lldesc_mem, "hci_lldesc_pool"); + if (rc) { + goto init_err; + } + + s_hci_driver_uart_dma_env.hci_rx_data_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool)); + if (!s_hci_driver_uart_dma_env.hci_rx_data_pool) { + goto init_err; + } + + memset(s_hci_driver_uart_dma_env.hci_rx_data_pool, 0, sizeof(struct os_mempool)); + s_hci_driver_uart_dma_env.hci_rx_data_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM, + HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t)); + if (!s_hci_driver_uart_dma_env.hci_rx_data_buffer) { + goto init_err; + } + + memset(s_hci_driver_uart_dma_env.hci_rx_data_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_DATA_POOL_NUM, + HCI_RX_DATA_BLOCK_SIZE) * sizeof(os_membuf_t)); + rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rx_data_pool, HCI_RX_DATA_POOL_NUM, + HCI_RX_DATA_BLOCK_SIZE, s_hci_driver_uart_dma_env.hci_rx_data_buffer, + "hci_rx_data_pool"); + if (rc) { + goto init_err; + } + + + /* Malloc hci rxinfo pool */ + s_hci_driver_uart_dma_env.hci_rxinfo_pool = (struct os_mempool *)malloc(sizeof(struct os_mempool)); + if (!s_hci_driver_uart_dma_env.hci_rxinfo_pool) { + goto init_err; + } + + memset(s_hci_driver_uart_dma_env.hci_rxinfo_pool, 0, sizeof(struct os_mempool)); + s_hci_driver_uart_dma_env.hci_rxinfo_buffer = malloc(OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM, + sizeof(hci_message_t)) * sizeof(os_membuf_t)); + if (!s_hci_driver_uart_dma_env.hci_rxinfo_buffer) { + goto init_err; + } + + memset(s_hci_driver_uart_dma_env.hci_rxinfo_buffer, 0, OS_MEMPOOL_SIZE(HCI_RX_INFO_POOL_NUM, + sizeof(hci_message_t)) * sizeof(os_membuf_t)); + rc = os_mempool_init(s_hci_driver_uart_dma_env.hci_rxinfo_pool, HCI_RX_INFO_POOL_NUM, + sizeof(hci_message_t), s_hci_driver_uart_dma_env.hci_rxinfo_buffer, + "hci_rxinfo_pool"); + if (rc) { + goto init_err; + } + + return rc; +init_err: + hci_driver_uart_dma_memory_deinit(); + return rc; +} + +static IRAM_ATTR bool hci_uart_tl_rx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + esp_bt_hci_tl_callback_t callback = uart_env.rx.callback; + void *arg = uart_env.rx.arg; + assert(dma_chan == s_rx_channel); + assert(uart_env.rx.callback != NULL); + // clear callback pointer + uart_env.rx.callback = NULL; + uart_env.rx.arg = NULL; + // call handler + callback(arg, ESP_BT_HCI_TL_STATUS_OK); + return true; +} + +static IRAM_ATTR bool hci_uart_tl_tx_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) +{ + esp_bt_hci_tl_callback_t callback = uart_env.tx.callback; + assert(dma_chan == s_tx_channel); + assert(uart_env.tx.callback != NULL); + // clear callback pointer + uart_env.tx.callback = NULL; + // call handler + callback(uart_env.tx.arg, ESP_BT_HCI_TL_STATUS_OK); + uart_env.tx.arg = NULL; + return true; +} + +uint8_t * IRAM_ATTR hci_driver_uart_dma_rxdata_memory_get(void) +{ + uint8_t *rx_data; + rx_data = os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool); + return rx_data; +} + +hci_message_t * IRAM_ATTR hci_driver_uart_dma_rxinfo_memory_get(void) +{ + hci_message_t *rx_info; + rx_info = os_memblock_get(s_hci_driver_uart_dma_env.hci_rxinfo_pool); + return rx_info; +} + +void IRAM_ATTR hci_driver_uart_dma_cache_rxinfo(hci_message_t *hci_rxinfo) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&g_hci_rxinfo_head, hci_rxinfo, next); + OS_EXIT_CRITICAL(sr); +} + +void IRAM_ATTR hci_driver_uart_dma_continue_rx_enable(bool enable) +{ + os_sr_t sr; + OS_ENTER_CRITICAL(sr); + s_hci_driver_uart_dma_env.is_continue_rx = enable; + OS_EXIT_CRITICAL(sr); +} + +void IRAM_ATTR hci_driver_uart_dma_rxinfo_mem_exhausted_set(bool is_exhausted) +{ + os_sr_t sr; + OS_ENTER_CRITICAL(sr); + s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = is_exhausted; + OS_EXIT_CRITICAL(sr); +} + +void IRAM_ATTR hci_driver_uart_dma_recv_callback(void *arg, uint8_t status) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + hci_message_t *hci_rxinfo; + uint8_t *rx_data; + + if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) { + ESP_LOGE(TAG, "Will lost rx data, need adjust rxinfo memory count\n"); + assert(0); + } + + hci_rxinfo = hci_driver_uart_dma_rxinfo_memory_get(); + if (!hci_rxinfo) { + ESP_LOGW(TAG, "set rxinfo mem exhausted flag\n"); + hci_driver_uart_dma_rxinfo_mem_exhausted_set(true); + xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken); + return; + } + + hci_rxinfo->ptr = (void *)uart_env.rx.link_head->buf; + hci_rxinfo->length = uart_env.rx.link_head->length; + hci_driver_uart_dma_cache_rxinfo(hci_rxinfo); + xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken); + rx_data = hci_driver_uart_dma_rxdata_memory_get(); + if (!rx_data) { + hci_driver_uart_dma_continue_rx_enable(true); + }else { + hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE); + } +} + +void IRAM_ATTR hci_driver_uart_dma_txstate_set(hci_trans_tx_state_t tx_state) +{ + os_sr_t sr; + OS_ENTER_CRITICAL(sr); + s_hci_driver_uart_dma_env.hci_tx_state = tx_state; + OS_EXIT_CRITICAL(sr); +} + +void IRAM_ATTR hci_driver_uart_dma_send_callback(void *arg, uint8_t status) +{ + uhci_lldesc_t *lldesc_head; + uhci_lldesc_t *lldesc_nxt; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + lldesc_head = uart_env.tx.link_head; + while (lldesc_head) { + lldesc_nxt = lldesc_head->qe.stqe_next; + os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head); + lldesc_head = lldesc_nxt; + } + + uart_env.tx.link_head = NULL; + hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_IDLE); + xSemaphoreGiveFromISR(s_hci_driver_uart_dma_env.process_sem, &xHigherPriorityTaskWoken); +} + +static IRAM_ATTR void hci_driver_uart_dma_recv_async(uint8_t *buf, uint32_t size, esp_bt_hci_tl_callback_t callback, void *arg) +{ + uhci_lldesc_t *lldesc_head; + assert(buf != NULL); + assert(size != 0); + assert(callback != NULL); + uart_env.rx.callback = callback; + uart_env.rx.arg = arg; + lldesc_head = uart_env.rx.link_head; + + while (lldesc_head) { + os_memblock_put(&s_hci_driver_uart_dma_env.lldesc_mem_pool, lldesc_head), + lldesc_head = lldesc_head->qe.stqe_next; + } + + uart_env.rx.link_head = NULL; + lldesc_head = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool); + assert(lldesc_head); + memset(lldesc_head, 0, sizeof(uhci_lldesc_t)); + lldesc_head->buf = buf; + lldesc_head->size = size; + lldesc_head->eof = 0; + s_uhci_hw->pkt_thres.pkt_thrs = size; + uart_env.rx.link_head = lldesc_head; + gdma_start(s_rx_channel, (intptr_t)(uart_env.rx.link_head)); +} + +int IRAM_ATTR hci_driver_uart_dma_rx_start(uint8_t *rx_data, uint32_t length) +{ + hci_driver_uart_dma_recv_async(rx_data, length, hci_driver_uart_dma_recv_callback, NULL); + return 0; +} + +int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg) +{ + void *data; + bool last_frame; + bool head_is_setted; + uint32_t tx_len; + uhci_lldesc_t *lldesc_data; + uhci_lldesc_t *lldesc_head; + uhci_lldesc_t *lldesc_tail; + + lldesc_head = NULL; + lldesc_tail = NULL; + head_is_setted = false; + last_frame = false; + while (true) { + tx_len = hci_driver_util_tx_list_dequeue(0xffffff, &data, &last_frame); + if (!tx_len) { + break; + } + + lldesc_data = os_memblock_get(&s_hci_driver_uart_dma_env.lldesc_mem_pool); + /* According to the current processing logic, It should not be empty */ + assert(lldesc_data); + memset(lldesc_data, 0, sizeof(uhci_lldesc_t)); + lldesc_data->length = tx_len; + lldesc_data->buf = data; + lldesc_data->eof = 0; + if (!head_is_setted) { + lldesc_head = lldesc_data; + head_is_setted = true; + } else { + lldesc_tail->qe.stqe_next = lldesc_data; + } + + lldesc_tail = lldesc_data; + if (last_frame) { + break; + } + } + + if (lldesc_head) { + lldesc_tail->eof = 1; + uart_env.tx.link_head = lldesc_head; + uart_env.tx.callback = callback; + uart_env.tx.arg = arg; + gdma_start(s_tx_channel, (intptr_t)(uart_env.tx.link_head)); + return 0; + } else { + return -1; + } +} + +static void hci_driver_uart_dma_install(void) +{ + periph_module_enable(PERIPH_UHCI0_MODULE); + periph_module_reset(PERIPH_UHCI0_MODULE); + // install DMA driver + gdma_channel_alloc_config_t tx_channel_config = { + .flags.reserve_sibling = 1, + .direction = GDMA_CHANNEL_DIRECTION_TX, + }; + + ESP_ERROR_CHECK(gdma_new_channel(&tx_channel_config, &s_tx_channel)); + gdma_channel_alloc_config_t rx_channel_config = { + .direction = GDMA_CHANNEL_DIRECTION_RX, + .sibling_chan = s_tx_channel, + }; + + ESP_ERROR_CHECK(gdma_new_channel(&rx_channel_config, &s_rx_channel)); + gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); + gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); + gdma_strategy_config_t strategy_config = { + .auto_update_desc = false, + .owner_check = false + }; + + gdma_apply_strategy(s_tx_channel, &strategy_config); + gdma_apply_strategy(s_rx_channel, &strategy_config); + gdma_rx_event_callbacks_t rx_cbs = { + .on_recv_eof = hci_uart_tl_rx_eof_callback + }; + + gdma_register_rx_event_callbacks(s_rx_channel, &rx_cbs, NULL); + gdma_tx_event_callbacks_t tx_cbs = { + .on_trans_eof = hci_uart_tl_tx_eof_callback + }; + + gdma_register_tx_event_callbacks(s_tx_channel, &tx_cbs, NULL); + // configure UHCI + uhci_ll_init((uhci_dev_t *)s_uhci_hw); + // uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_LEN_EOF); + uhci_ll_set_eof_mode((uhci_dev_t *)s_uhci_hw, UHCI_RX_IDLE_EOF); + // disable software flow control + s_uhci_hw->escape_conf.val = 0; + uhci_ll_attach_uart_port((uhci_dev_t *)s_uhci_hw, s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port); +} + +static int +hci_driver_uart_dma_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + /* By now, this layer is only used by controller. */ + assert(dir == HCI_DRIVER_DIR_C2H); + ESP_LOGD(TAG, "dma tx:"); + ESP_LOG_BUFFER_HEXDUMP(TAG, data, length, ESP_LOG_DEBUG); + + hci_driver_util_tx_list_enqueue(data_type, data, length); + xSemaphoreGive(s_hci_driver_uart_dma_env.process_sem); + return 0; +} + +static int +hci_driver_uart_dma_h4_frame_cb(uint8_t pkt_type, void *data) +{ + hci_driver_forward_fn *forward_cb; + forward_cb = s_hci_driver_uart_dma_env.forward_cb; + if (!forward_cb) { + return -1; + } + ESP_LOGD(TAG, "h4 frame\n"); + return forward_cb(pkt_type, data, 0, HCI_DRIVER_DIR_H2C); +} + +static void +hci_driver_uart_dma_process_task(void *p) +{ + hci_message_t *rxinfo_container; + os_sr_t sr; + int ret; + uint8_t* rx_data; + uint32_t rx_len; + + while (true) { + xSemaphoreTake(s_hci_driver_uart_dma_env.process_sem, portMAX_DELAY); + ESP_LOGD(TAG, "task run:%d\n",s_hci_driver_uart_dma_env.hci_tx_state); + if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) { + rx_data = (void *)uart_env.rx.link_head->buf; + rx_len = uart_env.rx.link_head->length; + ESP_LOGD(TAG, "rxinfo exhausted:"); + ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG); + ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len); + hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE); + hci_driver_uart_dma_rxinfo_mem_exhausted_set(false); + if (ret < 0) { + ESP_LOGW(TAG, "parse rx data error!\n"); + r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR); + } + } + + while (!STAILQ_EMPTY(&g_hci_rxinfo_head)) { + OS_ENTER_CRITICAL(sr); + rxinfo_container = STAILQ_FIRST(&g_hci_rxinfo_head); + STAILQ_REMOVE_HEAD(&g_hci_rxinfo_head, next); + OS_EXIT_CRITICAL(sr); + + rx_data = rxinfo_container->ptr; + rx_len = rxinfo_container->length; + ESP_LOGD(TAG, "uart rx"); + ESP_LOG_BUFFER_HEXDUMP(TAG, rx_data, rx_len, ESP_LOG_DEBUG); + ret = hci_h4_sm_rx(s_hci_driver_uart_dma_env.h4_sm, rx_data, rx_len); + if (ret < 0) { + ESP_LOGW(TAG, "parse rx data error!\n"); + r_ble_ll_hci_ev_hw_err(ESP_HCI_SYNC_LOSS_ERR); + } + + os_memblock_put(s_hci_driver_uart_dma_env.hci_rxinfo_pool, rxinfo_container); + /* No need to enter CRITICAL */ + if (s_hci_driver_uart_dma_env.is_continue_rx) { + /* We should set continux rx flag first, RX interrupted may happened when rx start soon */ + hci_driver_uart_dma_continue_rx_enable(false); + hci_driver_uart_dma_rx_start(rx_data, HCI_RX_DATA_BLOCK_SIZE); + } else { + os_memblock_put(s_hci_driver_uart_dma_env.hci_rx_data_pool, rx_data); + } + } + + /* Process Tx data */ + if (s_hci_driver_uart_dma_env.hci_tx_state == HCI_TRANS_TX_IDLE) { + ret = hci_driver_uart_dma_tx_start(hci_driver_uart_dma_send_callback, (void*)&uart_env); + if (!ret) { + s_hci_driver_uart_dma_env.hci_tx_state = HCI_TRANS_TX_START; + } + } + } +} + +static int +hci_driver_uart_dma_task_create(void) +{ + /* !TODO: Set the core id by menuconfig */ + xTaskCreatePinnedToCore(hci_driver_uart_dma_process_task, "hci_driver_uart_dma_process_task", + CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE, NULL, + ESP_TASK_BT_CONTROLLER_PRIO, &s_hci_driver_uart_dma_env.task_handler, + 0); + assert(s_hci_driver_uart_dma_env.task_handler); + + ESP_LOGI(TAG, "hci transport task create successfully, prio:%d, stack size: %ld", + ESP_TASK_BT_CONTROLLER_PRIO, CONFIG_BT_LE_HCI_TRANS_TASK_STACK_SIZE); + + return 0; +} + + +static void +hci_driver_uart_dma_deinit(void) +{ + if (s_hci_driver_uart_dma_env.task_handler) { + vTaskDelete(s_hci_driver_uart_dma_env.task_handler); + s_hci_driver_uart_dma_env.task_handler = NULL; + } + + ESP_ERROR_CHECK(uart_driver_delete(s_hci_driver_uart_dma_env.hci_uart_params->hci_uart_port)); + hci_driver_uart_dma_memory_deinit(); + if (!s_hci_driver_uart_dma_env.process_sem) { + vSemaphoreDelete(s_hci_driver_uart_dma_env.process_sem); + } + + hci_driver_util_deinit(); + memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t)); +} + + +static int +hci_driver_uart_dma_init(hci_driver_forward_fn *cb) +{ + int rc; + + memset(&s_hci_driver_uart_dma_env, 0, sizeof(hci_driver_uart_dma_env_t)); + + s_hci_driver_uart_dma_env.h4_sm = &s_hci_driver_uart_h4_sm; + hci_h4_sm_init(s_hci_driver_uart_dma_env.h4_sm, &s_hci_driver_mem_alloc, hci_driver_uart_dma_h4_frame_cb); + + rc = hci_driver_util_init(); + if (rc) { + goto error; + } + + s_hci_driver_uart_dma_env.process_sem = xSemaphoreCreateBinary(); + if (!s_hci_driver_uart_dma_env.process_sem) { + goto error; + } + + rc = hci_driver_uart_dma_memory_init(); + if (rc) { + goto error; + } + + s_hci_driver_uart_dma_env.forward_cb = cb; + s_hci_driver_uart_dma_env.hci_uart_params = &hci_driver_uart_dma_params; + hci_driver_uart_config(&hci_driver_uart_dma_params); + + ESP_LOGI(TAG, "uart attach uhci!"); + hci_driver_uart_dma_install(); + + STAILQ_INIT(&g_hci_rxinfo_head); + + rc = hci_driver_uart_dma_task_create(); + if (rc) { + goto error; + } + + s_hci_driver_uart_dma_env.hci_tx_state = HCI_TRANS_TX_IDLE; + s_hci_driver_uart_dma_env.rxinfo_mem_exhausted = false; + s_hci_driver_uart_dma_env.is_continue_rx = false; + hci_driver_uart_dma_rx_start(os_memblock_get(s_hci_driver_uart_dma_env.hci_rx_data_pool), + HCI_RX_DATA_BLOCK_SIZE); + return 0; + +error: + hci_driver_uart_dma_deinit(); + return rc; +} + +int +hci_driver_uart_dma_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin) +{ + hci_driver_uart_params_config_t *uart_param = s_hci_driver_uart_dma_env.hci_uart_params; + uart_param->hci_uart_tx_pin = tx_pin; + uart_param->hci_uart_rx_pin = rx_pin; + uart_param->hci_uart_rts_pin = rts_pin; + uart_param->hci_uart_cts_pin = cts_pin; + return hci_driver_uart_config(uart_param); +} + + +hci_driver_ops_t hci_driver_uart_dma_ops = { + .hci_driver_tx = hci_driver_uart_dma_tx, + .hci_driver_init = hci_driver_uart_dma_init, + .hci_driver_deinit = hci_driver_uart_dma_deinit, +}; diff --git a/components/bt/porting/transport/driver/vhci/hci_driver_nimble.c b/components/bt/porting/transport/driver/vhci/hci_driver_nimble.c new file mode 100644 index 00000000000..9a117eb88a5 --- /dev/null +++ b/components/bt/porting/transport/driver/vhci/hci_driver_nimble.c @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_hci_internal.h" +#include "esp_hci_driver.h" + +typedef struct { + hci_driver_forward_fn *forward_cb; +} hci_driver_vhci_env_t; + +static hci_driver_vhci_env_t s_hci_driver_vhci_env; + +static int +hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data) +{ + /* The length is contained in the data. */ + return s_hci_driver_vhci_env.forward_cb(data_type, data, 0, HCI_DRIVER_DIR_C2H); +} + +static int +hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + return s_hci_driver_vhci_env.forward_cb(data_type, data, length, HCI_DRIVER_DIR_H2C); +} + +static int +hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + int rc; + + if (dir == HCI_DRIVER_DIR_C2H) { + rc = hci_driver_vhci_controller_tx(data_type, data); + } else { + rc = hci_driver_vhci_host_tx(data_type, data, length); + } + return rc; +} + +static int +hci_driver_vhci_init(hci_driver_forward_fn *cb) +{ + s_hci_driver_vhci_env.forward_cb = cb; + return 0; +} + +static void +hci_driver_vhci_deinit(void) +{ + memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t)); +} + +hci_driver_ops_t hci_driver_vhci_ops = { + .hci_driver_tx = hci_driver_vhci_tx, + .hci_driver_init = hci_driver_vhci_init, + .hci_driver_deinit = hci_driver_vhci_deinit, +}; diff --git a/components/bt/porting/transport/driver/vhci/hci_driver_standard.c b/components/bt/porting/transport/driver/vhci/hci_driver_standard.c new file mode 100644 index 00000000000..2cdab4359e5 --- /dev/null +++ b/components/bt/porting/transport/driver/vhci/hci_driver_standard.c @@ -0,0 +1,149 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "os/os_mbuf.h" +#include "esp_hci_transport.h" +#include "esp_hci_internal.h" +#include "esp_hci_driver.h" +#include "esp_bt.h" + +typedef struct { + hci_driver_forward_fn *forward_cb; + const esp_vhci_host_callback_t *host_recv_cb; +} hci_driver_vhci_env_t; + +static hci_driver_vhci_env_t s_hci_driver_vhci_env; + +static int +hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + int rc; + uint16_t buf_len = 0; + uint8_t *buf = NULL; + struct os_mbuf *om; + + if (data_type == HCI_DRIVER_TYPE_ACL) { + om = (struct os_mbuf *)data; + buf_len = length + 1; + buf = malloc(buf_len); + /* TODO: If there is no memory, should handle it in the controller. */ + assert(buf); + buf[0] = HCI_DRIVER_TYPE_ACL; + os_mbuf_copydata(om, 0, length, &buf[1]); + os_mbuf_free_chain(om); + } else if (data_type == HCI_DRIVER_TYPE_EVT) { + buf_len = length + 1; + buf = malloc(buf_len); + /* TODO: If there is no memory, should handle it in the controller. */ + assert(buf != NULL); + buf[0] = HCI_DRIVER_TYPE_EVT; + memcpy(&buf[1], data, length); + r_ble_hci_trans_buf_free(data); + } + + rc = s_hci_driver_vhci_env.forward_cb(data_type, buf, buf_len, HCI_DRIVER_DIR_C2H); + free(buf); + + return rc; +} + +static int +hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + uint8_t *cmd; + struct os_mbuf *om; + + if (data_type == HCI_DRIVER_TYPE_ACL) { + om = os_msys_get_pkthdr(length, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); + assert(om); + assert(os_mbuf_append(om, &data[1], length - 1) == 0); + data = (uint8_t *)om; + } else if (data_type == HCI_DRIVER_TYPE_CMD) { + cmd = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD); + assert(cmd); + memcpy(cmd, data + 1, length - 1); + data = cmd; + } + + return s_hci_driver_vhci_env.forward_cb(data_type, data, length, HCI_DRIVER_DIR_H2C); +} + +static int +hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + int rc; + + if (dir == HCI_DRIVER_DIR_C2H) { + rc = hci_driver_vhci_controller_tx(data_type, data, length); + } else { + rc = hci_driver_vhci_host_tx(data_type, data, length); + } + return rc; +} + +static int +hci_driver_vhci_init(hci_driver_forward_fn *cb) +{ + memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t)); + s_hci_driver_vhci_env.forward_cb = cb; + return 0; +} + +static void +hci_driver_vhci_deinit(void) +{ + memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t)); +} + +hci_driver_ops_t hci_driver_vhci_ops = { + .hci_driver_tx = hci_driver_vhci_tx, + .hci_driver_init = hci_driver_vhci_init, + .hci_driver_deinit = hci_driver_vhci_deinit, +}; + +/* Special APIs declared in the `esp_bt.h'. */ +static int +hci_driver_vhci_host_recv_cb(hci_trans_pkt_ind_t type, uint8_t *data, uint16_t len) +{ + static const esp_vhci_host_callback_t *host_recv_cb; + + host_recv_cb = s_hci_driver_vhci_env.host_recv_cb; + if (host_recv_cb) { + return host_recv_cb->notify_host_recv(data, len); + } + + return -1; +} + +esp_err_t +esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) +{ + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return ESP_FAIL; + } + + s_hci_driver_vhci_env.host_recv_cb = callback; + if(hci_transport_host_callback_register(hci_driver_vhci_host_recv_cb)) { + s_hci_driver_vhci_env.host_recv_cb = NULL; + return ESP_FAIL; + } + + return ESP_OK; +} + +void +esp_vhci_host_send_packet(uint8_t *data, uint16_t len) +{ + hci_driver_vhci_tx(data[0], data, len, HCI_DRIVER_DIR_H2C); +} + +bool +esp_vhci_host_check_send_available(void) +{ + return true; +} diff --git a/components/bt/porting/transport/driver/vhci/hci_driver_tamplete.c b/components/bt/porting/transport/driver/vhci/hci_driver_tamplete.c new file mode 100644 index 00000000000..63feb934dad --- /dev/null +++ b/components/bt/porting/transport/driver/vhci/hci_driver_tamplete.c @@ -0,0 +1,133 @@ +/* + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "os/os_mbuf.h" +#include "esp_hci_transport.h" +#include "esp_hci_internal.h" +#include "esp_hci_driver.h" + +typedef struct { + hci_driver_forward_fn *forward_cb; +} hci_driver_vhci_env_t; + +static hci_driver_vhci_env_t s_hci_driver_vhci_env; + +static int +hci_driver_vhci_controller_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + int rc; + uint16_t len = 0; + uint8_t *buf = NULL; + struct os_mbuf *om; + + if (data_type == HCI_DRIVER_TYPE_ACL) { + /* The ACL data will be packaged as structure of `os_mbuf`. + * 1. Allocate a buffer suitable for the host. Use the following method to copy the data + * from the os_mbuf to the newly allocated memory. + * ```c + * buf = malloc(length); + * os_mbuf_copydata(om, 0, length, buf); + * ``` + * 2. Free the controller's os_mbuf + * ```c + * os_mbuf_free_chain(om); + * ``` + */ + } else if (data_type == HCI_DRIVER_TYPE_EVT) { + /* The event data will be packaged as an array. + * 1. Allocate a buffer suitable for the host. Use the following method to copy the data + * from the controller buffer to the newly allocated memory. + * ```c + * buf = malloc(length); + * memcpy(buf, data, length); + * ``` + * 2. Free the controller's buffer. + * ```c + * r_ble_hci_trans_buf_free(data); + * ``` + */ + } else { + assert(0); + } + + rc = s_hci_driver_vhci_env.forward_cb(data_type, buf, len, HCI_DRIVER_DIR_C2H); + free(buf); + + return rc; +} + +static int +hci_driver_vhci_host_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + uint8_t *hci_data; + struct os_mbuf *om; + + if (data_type == HCI_DRIVER_TYPE_ACL) { + /* The ACL data needs to be packaged as structure of `os_mbuf`. + * 1. Get an os_mbuf in the following way. + * ```c + * om = os_msys_get_pkthdr(length, ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE); + * ``` + * 2. Copy the host's data into this os_mbuf using the following method. + * ```c + * assert(os_mbuf_append(om, data, length) == 0); + * hci_data = (uint8_t *)om; + * ``` + * 3. Free the host's buffer if needed. + */ + } else if (data_type == HCI_DRIVER_TYPE_CMD) { + /* The COMMAND data needs to be packaged as an array. + * 1. Get a command buffer from the controller. + * ```c + * hci_data = r_ble_hci_trans_buf_alloc(ESP_HCI_INTERNAL_BUF_CMD); + * ``` + * 2. Copy the host's data into this buffer. + * ```c + * memcpy(hci_data, data, length); + * ``` + * 3. Free the host's buffer if needed. + */ + } else { + assert(0); + } + + return s_hci_driver_vhci_env.forward_cb(data_type, hci_data, length, HCI_DRIVER_DIR_H2C); +} + +static int +hci_driver_vhci_tx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + int rc; + + if (dir == HCI_DRIVER_DIR_C2H) { + rc = hci_driver_vhci_controller_tx(data_type, data, length); + } else { + rc = hci_driver_vhci_host_tx(data_type, data, length); + } + return rc; +} + +static int +hci_driver_vhci_init(hci_driver_forward_fn *cb) +{ + memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t)); + s_hci_driver_vhci_env.forward_cb = cb; + return 0; +} + +static void +hci_driver_vhci_deinit(void) +{ + memset(&s_hci_driver_vhci_env, 0, sizeof(hci_driver_vhci_env_t)); +} + +hci_driver_ops_t hci_driver_vhci_ops = { + .hci_driver_tx = hci_driver_vhci_tx, + .hci_driver_init = hci_driver_vhci_init, + .hci_driver_deinit = hci_driver_vhci_deinit, +}; diff --git a/components/bt/porting/transport/include/common/hci_driver_h4.h b/components/bt/porting/transport/include/common/hci_driver_h4.h new file mode 100644 index 00000000000..32d2dd8ba6c --- /dev/null +++ b/components/bt/porting/transport/include/common/hci_driver_h4.h @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _HCI_H4_H_ +#define _HCI_H4_H_ + +#include + +#define HCI_H4_NONE 0x00 +#define HCI_H4_CMD 0x01 +#define HCI_H4_ACL 0x02 +#define HCI_H4_EVT 0x04 +#define HCI_H4_ISO 0x05 + +typedef void *(hci_h4_alloc_cmd)(void); +typedef void *(hci_h4_alloc_evt)(int); +typedef struct os_mbuf *(hci_h4_alloc_acl)(void); +typedef struct os_mbuf *(hci_h4_alloc_iso)(void); + +struct hci_h4_allocators { + hci_h4_alloc_cmd *cmd; + hci_h4_alloc_acl *acl; + hci_h4_alloc_evt *evt; + hci_h4_alloc_iso *iso; +}; + +extern const struct hci_h4_allocators hci_h4_allocs_from_ll; +extern const struct hci_h4_allocators hci_h4_allocs_from_hs; + +typedef int (hci_h4_frame_cb)(uint8_t pkt_type, void *data); + +struct hci_h4_sm { + uint8_t state; + uint8_t pkt_type; + uint8_t min_len; + uint16_t len; + uint16_t exp_len; + uint8_t hdr[4]; + union { + uint8_t *buf; + struct os_mbuf *om; + }; + + const struct hci_h4_allocators *allocs; + hci_h4_frame_cb *frame_cb; +}; + +void hci_h4_sm_init(struct hci_h4_sm *h4sm, + const struct hci_h4_allocators *allocs, + hci_h4_frame_cb *frame_cb); + +int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len); + +#endif /* _HCI_H4_H_ */ diff --git a/components/bt/porting/transport/include/common/hci_driver_mem.h b/components/bt/porting/transport/include/common/hci_driver_mem.h new file mode 100644 index 00000000000..769b18369eb --- /dev/null +++ b/components/bt/porting/transport/include/common/hci_driver_mem.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _H_HCI_DRIVER_MEM_ +#define _H_HCI_DRIVER_MEM_ +#include +#include "os/os_mbuf.h" + +void *hci_driver_mem_cmd_alloc(void); + +void *hci_driver_mem_evt_alloc(int discardable); + +struct os_mbuf *hci_driver_mem_acl_alloc(void); + +struct os_mbuf *hci_driver_mem_acl_len_alloc(uint32_t len); + +struct os_mbuf *hci_driver_mem_iso_alloc(void); + +struct os_mbuf *hci_driver_mem_iso_len_alloc(uint32_t len); + +extern const struct hci_h4_allocators s_hci_driver_mem_alloc; + +#endif // _H_HCI_DRIVER_MEM_ diff --git a/components/bt/porting/transport/include/common/hci_driver_util.h b/components/bt/porting/transport/include/common/hci_driver_util.h new file mode 100644 index 00000000000..05b7abd5023 --- /dev/null +++ b/components/bt/porting/transport/include/common/hci_driver_util.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef _H_HCI_DRIVER_UTIL_ +#define _H_HCI_DRIVER_UTIL_ +#include + +int hci_driver_util_init(void); + +void hci_driver_util_deinit(void); + +void hci_driver_util_tx_list_enqueue(hci_driver_data_type_t type, uint8_t *data, uint32_t len); + +uint32_t hci_driver_util_tx_list_dequeue(uint32_t max_tx_len, void **tx_data, bool *last_frame); + +#endif // _H_HCI_DRIVER_UTIL_ diff --git a/components/bt/porting/transport/include/esp_hci_driver.h b/components/bt/porting/transport/include/esp_hci_driver.h new file mode 100644 index 00000000000..09102edff83 --- /dev/null +++ b/components/bt/porting/transport/include/esp_hci_driver.h @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef H_ESP_HCI_DRIVER_ +#define H_ESP_HCI_DRIVER_ +#include + +/** + * @brief Enumeration of HCI transport direction. + */ +typedef enum { + HCI_DRIVER_DIR_C2H = 0x00, ///< From controller to host. + HCI_DRIVER_DIR_H2C, ///< From host to controller. +} hci_driver_direction_t; + +typedef enum { + HCI_DRIVER_TYPE_CMD = 0x01, ///< HCI Command Indicator. + HCI_DRIVER_TYPE_ACL, ///< HCI ACL Data Indicator. + HCI_DRIVER_TYPE_SYNC, ///< HCI Synchronous Data Indicator. + HCI_DRIVER_TYPE_EVT, ///< HCI Event Indicator. + HCI_DRIVER_TYPE_ISO, ///< HCI Isochronous Data Indicator. + HCI_DRIVER_TYPE_VENDOR, ///< HCI Vendor data Indicator. +} hci_driver_data_type_t; + +typedef int hci_driver_forward_fn(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir); + +/** + * @brief Structure of HCI driver operations. + */ +typedef struct hci_driver_ops { + int (*hci_driver_tx)(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir); + int (*hci_driver_init)(hci_driver_forward_fn *cb); + void (*hci_driver_deinit)(void); +} hci_driver_ops_t; + + +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM +extern hci_driver_ops_t hci_driver_vhci_ops; +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +extern hci_driver_ops_t hci_driver_uart_ops; +#if CONFIG_BT_LE_UART_HCI_DMA_MODE +extern hci_driver_ops_t hci_driver_uart_dma_ops; +#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART + +#endif // H_ESP_HCI_DRIVER_ diff --git a/components/bt/porting/transport/include/esp_hci_internal.h b/components/bt/porting/transport/include/esp_hci_internal.h new file mode 100644 index 00000000000..2b1c3353082 --- /dev/null +++ b/components/bt/porting/transport/include/esp_hci_internal.h @@ -0,0 +1,121 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_ESP_HCI_INTERNAL_ +#define H_ESP_HCI_INTERNAL_ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "os/os_mbuf.h" + + +/* The leadingspace in user info header for ACL data */ +#define ESP_HCI_INTERNAL_ACL_MBUF_LEADINGSPCAE (4) + +#define ESP_HCI_INTERNAL_BUF_CMD (3) + +/** + * @brief Define the HCI hardware error code for synchronization loss. + * This error code is used to indicate a loss of synchronization between the controller and the host. + */ +#define ESP_HCI_SYNC_LOSS_ERR (0x1) +/** Callback function types; executed when HCI packets are received. */ +typedef int esp_hci_internal_rx_cmd_fn(uint8_t *cmd, void *arg); +typedef int esp_hci_internal_rx_acl_fn(struct os_mbuf *om, void *arg); + +/** + * Configures the HCI transport to operate with a host. The transport will + * execute specified callbacks upon receiving HCI packets from the controller. + * + * @param evt_cb The callback to execute upon receiving an HCI + * event. + * @param evt_arg Optional argument to pass to the event + * callback. + * @param acl_cb The callback to execute upon receiving ACL + * data. + * @param acl_arg Optional argument to pass to the ACL + * callback. + */ +void r_ble_hci_trans_cfg_hs(esp_hci_internal_rx_cmd_fn *evt_cb, void *evt_arg, + esp_hci_internal_rx_acl_fn *acl_cb, void *acl_arg); +/** + * Sends ACL data from host to controller. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int r_ble_hci_trans_hs_acl_tx(struct os_mbuf *om); + +/** + * Sends an HCI command from the host to the controller. + * + * @param cmd The HCI command to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int r_ble_hci_trans_hs_cmd_tx(uint8_t *cmd); + +/** + * Allocates a flat buffer of the specified type. + * + * @param type The type of buffer to allocate; one of the + * BLE_HCI_TRANS_BUF_[...] constants. + * + * @return The allocated buffer on success; + * NULL on buffer exhaustion. + */ +uint8_t * r_ble_hci_trans_buf_alloc(int type); + +/** + * Frees the specified flat buffer. The buffer must have been allocated via + * ble_hci_trans_buf_alloc(). + * + * @param buf The buffer to free. + */ +void r_ble_hci_trans_buf_free(uint8_t *buf); + +/** + * Configures a callback to get executed whenever an ACL data packet is freed. + * The function is called immediately before the free occurs. + * + * @param cb The callback to configure. + * @param arg An optional argument to pass to the callback. + * + * @return 0 on success; + * BLE_ERR_UNSUPPORTED if the transport does not + * support this operation. + */ +int r_ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg); + +/** + * @brief Handle an HCI hardware error event. + * This function processes a hardware error code and generates the appropriate HCI hardware error event. + * + * @param hw_err The hardware error code that needs to be processed. The specific meaning of the error code + * depends on the implementation and the hardware. + * + * @return int Returns 0 on success, or a non-zero error code on failure. + * + * @note This function should be called whenever a hardware error is detected in the HCI Layer. + */ +int r_ble_ll_hci_ev_hw_err(uint8_t hw_err); + +//!TODO: Check what this API is used for +int r_ble_hci_trans_reset(void); + +//!TODO: Should we initialize the hci layer in IDF ? +void esp_ble_hci_trans_init(uint8_t); + +#ifdef __cplusplus +} +#endif +#endif /* H_ESP_HCI_INTERNAL_ */ diff --git a/components/bt/porting/transport/include/esp_hci_transport.h b/components/bt/porting/transport/include/esp_hci_transport.h new file mode 100644 index 00000000000..044ebfdfb80 --- /dev/null +++ b/components/bt/porting/transport/include/esp_hci_transport.h @@ -0,0 +1,83 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_ESP_HCI_TRANSPORT_ +#define H_ESP_HCI_TRANSPORT_ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "os/os_mbuf.h" +#include "esp_hci_driver.h" + +/** + * @brief Enumeration of HCI packet indicators + */ +typedef enum { + HCI_CMD_IND = 0x01, /*!< HCI Command Indicator */ + HCI_ACL_IND, /*!< HCI ACL Data Indicator */ + HCI_SYNC_IND, /*!< HCI Synchronous Data Indicator */ + HCI_EVT_IND, /*!< HCI Event Indicator */ + HCI_ISO_IND, /*!< HCI Isochronous Data Indicator */ + HCI_VENDOR_IND, /*!< HCI Vendor data Indicator */ +} hci_trans_pkt_ind_t; + +/** + * @brief Enumeration of HCI Transport Mode + */ +typedef enum { + HCI_TRANSPORT_VHCI, /*!< VHCI Transport Mode */ + HCI_TRANSPORT_UART_NO_DMA, /*!< UART_NO_DMA Transport Mode */ + HCI_TRANSPORT_UART_UHCI, /*!< UART_UHCI Transport Mode */ + HCI_TRANSPORT_SDIO, /*!< SDIO Transport Mode */ + HCI_TRANSPORT_USB, /*!< USB Transport Mode */ +} hci_trans_mode_t; + +typedef int hci_transport_host_recv_fn(hci_trans_pkt_ind_t type, uint8_t *data, uint16_t len); + +/** + * @brief Initialize the HCI transport layer. + * It should be called before using any other functions in the transport layer. + * + * @param hci_transport_mode The mode in which the HCI transport should operate. + * + * @return int Returns 0 on success, or a non-zero error code on failure. + */ +int hci_transport_init(uint8_t hci_transport_mode); + +/** + * @brief Deinitialize the HCI transport layer for releasing any allocated resources. + */ +void hci_transport_deinit(void); + +/** + * @brief Set the host's HCI callback which will be invoked when receiving ACL/Events from controller. + * @param callback hci_transport_host_recv_fn type variable + * @return int 0 on success, non-zero error code on failure. + */ +int hci_transport_host_callback_register(hci_transport_host_recv_fn *callback); + +/** + * @brief Called to send HCI commands form host to controller. + * @param data Point to the commands data + * @param length Length of data + * @return int 0 on success, non-zero error code on failure. + */ +int hci_transport_host_cmd_tx(uint8_t *data, uint32_t length); + +/** + * @brief Called to send HCI ACL form host to controller. + * @param data Point to the ACL data + * @param length Length of data + * @return int 0 on success, non-zero error code on failure. + */ +int hci_transport_host_acl_tx(uint8_t *data, uint32_t length); + +#ifdef __cplusplus +} +#endif +#endif /* H_ESP_HCI_TRANSPORT_ */ diff --git a/components/bt/porting/transport/include/hci_uart.h b/components/bt/porting/transport/include/hci_uart.h deleted file mode 100644 index 02bc91b4033..00000000000 --- a/components/bt/porting/transport/include/hci_uart.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include "driver/uart.h" - -/** - * Function prototype for UART driver to ask for more data to send. - * Returns -1 if no more data is available for TX. - * Driver must call this with interrupts disabled. - */ -typedef int (*hci_uart_tx_char)(void *arg); - -/** - * Function prototype for UART driver to report that transmission is - * complete. This should be called when transmission of last byte is - * finished. - * Driver must call this with interrupts disabled. - */ -typedef void (*hci_uart_tx_done)(void *arg); - -/** - * Function prototype for UART driver to report incoming byte of data. - * Returns -1 if data was dropped. - * Driver must call this with interrupts disabled. - */ -typedef int (*hci_uart_rx_char)(void *arg, uint8_t byte); - - -/** - * Initializes given uart. Mapping of logical UART number to physical - * UART/GPIO pins is in BSP. - */ -int hci_uart_init_cbs(int uart, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); - - -/** - * Applies given configuration to UART. - * - * @param port_num The UART number to configure - * @param speed The baudrate in bps to configure - * @param databits The number of databits to send per byte - * @param stopbits The number of stop bits to send - * @param parity The UART parity - * @param flow_ctl Flow control settings on the UART - * - * @return 0 on success, non-zero error code on failure - */ -int hci_uart_config(int port_num, int32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); - -/** - * Close UART port. Can call hal_uart_config() with different settings after - * calling this. - * - * @param port_num The UART number to close - */ -int hci_uart_close(int port_num); - -/** - * More data queued for transmission. UART driver will start asking for that - * data. - * - * @param port_num The UART number to start TX on - */ -void hci_uart_start_tx(int port_num); - -/** - * Upper layers have consumed some data, and are now ready to receive more. - * This is meaningful after uart_rx_char callback has returned -1 telling - * that no more data can be accepted. - * - * @param port_num The UART number to begin RX on - */ -void hci_uart_start_rx(int port_num); - -/** - * @brief reconfig hci uart pin - * - * @param tx_pin The Tx pin - * @param rx_pin The Rx pin - * @param cts_pin The CTS pin - * @param rts_pin The RTS pin - * @return int 0 on success, non-zero error code on failure - */ -int hci_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin); - -#ifdef __cplusplus -} -#endif diff --git a/components/bt/porting/transport/src/hci_transport.c b/components/bt/porting/transport/src/hci_transport.c new file mode 100644 index 00000000000..df8b5db009c --- /dev/null +++ b/components/bt/porting/transport/src/hci_transport.c @@ -0,0 +1,175 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "esp_log.h" +#include "esp_hci_transport.h" +#include "esp_hci_internal.h" +#include "esp_bt.h" + +typedef struct hci_transport_env +{ + hci_transport_host_recv_fn *host_recv_cb; + hci_driver_ops_t *driver_ops; +} hci_transport_env_t; + +static hci_transport_env_t s_hci_transport_env; + +/* Functions for packets Rx. */ +static int +hci_transport_controller_packet_rx(hci_driver_data_type_t data_type, uint8_t *data) +{ + if (data_type == HCI_DRIVER_TYPE_CMD) { + r_ble_hci_trans_hs_cmd_tx(data); + } + + if (data_type == HCI_DRIVER_TYPE_ACL) { + r_ble_hci_trans_hs_acl_tx((struct os_mbuf *) data); + } + return 0; +} + +static int +hci_transport_host_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) +{ + if (!s_hci_transport_env.host_recv_cb) { + return -1; + } + return s_hci_transport_env.host_recv_cb((hci_trans_pkt_ind_t)data_type, data, length); +} + +static int +hci_transport_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, + hci_driver_direction_t dir) +{ + int rc; + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return -1; + } + + if (dir == HCI_DRIVER_DIR_C2H) { + rc = hci_transport_host_packet_rx(data_type, data, length); + } else { + rc = hci_transport_controller_packet_rx(data_type, data); + } + + return rc; +} + +/* Functions for controller Tx. */ +static int +hci_transport_controller_tx_dummy(void *data, void *arg) +{ + return -1; +} + +static int +hci_transport_controller_evt_tx(uint8_t *hci_ev, void *arg) +{ + uint32_t len; + + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return -1; + } + + len = hci_ev[1] + 2; + return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_EVT, hci_ev, len, + HCI_DRIVER_DIR_C2H); +} + +static int +hci_transport_controller_acl_tx(struct os_mbuf *om, void *arg) +{ + uint16_t len; + if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { + return -1; + } + + len = OS_MBUF_PKTHDR(om)->omp_len; + return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, (uint8_t *)om, len, + HCI_DRIVER_DIR_C2H); +} + +/* Functions for host Tx. */ +int +hci_transport_host_cmd_tx(uint8_t *data, uint32_t length) +{ + return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_CMD, data, length, + HCI_DRIVER_DIR_H2C); +} + +int +hci_transport_host_acl_tx(uint8_t *data, uint32_t length) +{ + return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, data, length, + HCI_DRIVER_DIR_H2C); +} + +int +hci_transport_host_callback_register(hci_transport_host_recv_fn *callback) +{ + s_hci_transport_env.host_recv_cb = callback; + return 0; +} + +int +hci_transport_init(uint8_t hci_transport_mode) +{ + int rc; + hci_driver_ops_t *ops; + + memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t)); + + switch(hci_transport_mode) { +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + case HCI_TRANSPORT_VHCI: + ops = &hci_driver_vhci_ops; + break; +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM +#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART +#if CONFIG_BT_LE_UART_HCI_DMA_MODE + case HCI_TRANSPORT_UART_UHCI: + ops = &hci_driver_uart_dma_ops; + break; +#else + case HCI_TRANSPORT_UART_NO_DMA: + ops = &hci_driver_uart_ops; + break; +#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART + default: + assert(0); + } + + rc = ops->hci_driver_init(hci_transport_packet_rx); + if (rc) { + goto error; + } + + s_hci_transport_env.driver_ops = ops; + r_ble_hci_trans_cfg_hs(hci_transport_controller_evt_tx, NULL, hci_transport_controller_acl_tx, NULL); + + return 0; + +error: + hci_transport_deinit(); + return rc; +} + +void +hci_transport_deinit(void) +{ + hci_driver_ops_t *ops; + + r_ble_hci_trans_cfg_hs((esp_hci_internal_rx_cmd_fn *)hci_transport_controller_tx_dummy, NULL, + (esp_hci_internal_rx_acl_fn *)hci_transport_controller_tx_dummy, NULL); + + ops = s_hci_transport_env.driver_ops; + if (ops) { + ops->hci_driver_deinit(); + } + memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t)); +} diff --git a/components/bt/porting/transport/uart/hci_uart.c b/components/bt/porting/transport/uart/hci_uart.c deleted file mode 100644 index c202e0a5041..00000000000 --- a/components/bt/porting/transport/uart/hci_uart.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "driver/uart.h" -#include "hci_uart.h" -#include "esp_log.h" -#include "esp_attr.h" - -#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART - -static const char *TAG = "hci_uart"; - -#define BUF_SIZE (1024) -#define RD_BUF_SIZE (BUF_SIZE) - -#define HCI_UART_TX_PIN CONFIG_BT_LE_HCI_UART_TX_PIN -#define HCI_UART_RX_PIN CONFIG_BT_LE_HCI_UART_RX_PIN - - -#ifdef CONFIG_BT_LE_HCI_UART_FLOWCTRL -#define HCI_UART_FLOWCTRL UART_HW_FLOWCTRL_CTS_RTS -#define HCI_UART_RTS_PIN CONFIG_BT_LE_HCI_UART_RTS_PIN -#define HCI_UART_CTS_PIN CONFIG_BT_LE_HCI_UART_CTS_PIN -#else -#define HCI_UART_FLOWCTRL UART_HW_FLOWCTRL_DISABLE -#define HCI_UART_RTS_PIN (-1) -#define HCI_UART_CTS_PIN (-1) -#endif - - -typedef struct { - bool uart_opened; - uart_port_t port; - uart_config_t cfg; - QueueHandle_t evt_queue; - TaskHandle_t rx_task_handler; - hci_uart_tx_char tx_char; - hci_uart_tx_done tx_done; - hci_uart_rx_char rx_char; - void *u_func_arg; - -} hci_uart_t; - -static hci_uart_t hci_uart; - -static void IRAM_ATTR hci_uart_rx_task(void *pvParameters) -{ - uart_event_t event; - uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE); - while (hci_uart.uart_opened) { - //Waiting for UART event. - if (xQueueReceive(hci_uart.evt_queue, (void * )&event, (TickType_t)portMAX_DELAY)) { - bzero(dtmp, RD_BUF_SIZE); - ESP_LOGD(TAG, "uart[%d] event:", hci_uart.port); - switch (event.type) { - //Event of UART receving data - /*We'd better handler data event fast, there would be much more data events than - other types of events. If we take too much time on data event, the queue might - be full.*/ - case UART_DATA: - // ESP_LOGI(TAG, "[UART DATA]: %d", event.size); - uart_read_bytes(hci_uart.port, dtmp, event.size, portMAX_DELAY); - for (int i = 0 ; i < event.size; i++) { - hci_uart.rx_char(hci_uart.u_func_arg, dtmp[i]); - } - break; - //Event of HW FIFO overflow detected - case UART_FIFO_OVF: - ESP_LOGI(TAG, "hw fifo overflow"); - // If fifo overflow happened, you should consider adding flow control for your application. - // The ISR has already reset the rx FIFO, - uart_flush_input(hci_uart.port); - xQueueReset(hci_uart.evt_queue); - break; - //Event of UART ring buffer full - case UART_BUFFER_FULL: - ESP_LOGI(TAG, "ring buffer full"); - // If buffer full happened, you should consider encreasing your buffer size - uart_flush_input(hci_uart.port); - xQueueReset(hci_uart.evt_queue); - break; - //Event of UART RX break detected - case UART_BREAK: - ESP_LOGI(TAG, "uart rx break"); - break; - //Event of UART parity check error - case UART_PARITY_ERR: - ESP_LOGI(TAG, "uart parity error"); - break; - //Event of UART frame error - case UART_FRAME_ERR: - ESP_LOGI(TAG, "uart frame error"); - break; - //Others - default: - ESP_LOGI(TAG, "uart event type: %d", event.type); - break; - } - } - } - free(dtmp); - dtmp = NULL; - hci_uart.rx_task_handler = NULL; - vTaskDelete(NULL); -} - -int hci_uart_config(int port_num, int32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl) -{ - uart_config_t uart_cfg = { - .baud_rate = baud_rate, - .data_bits = data_bits, - .parity = parity, - .stop_bits = stop_bits, - .flow_ctrl = HCI_UART_FLOWCTRL, - .source_clk = UART_SCLK_DEFAULT, - .rx_flow_ctrl_thresh = UART_HW_FIFO_LEN(port_num) - 1, - }; - hci_uart.port = port_num; - hci_uart.cfg = uart_cfg; - - int intr_alloc_flags = 0; - intr_alloc_flags = ESP_INTR_FLAG_IRAM; - - printf("set uart pin tx:%d, rx:%d.\n", HCI_UART_TX_PIN, HCI_UART_RX_PIN); - printf("set rts:%d, cts:%d.\n", HCI_UART_RTS_PIN, HCI_UART_CTS_PIN); - printf("set baud_rate:%d.\n", baud_rate); - - ESP_ERROR_CHECK(uart_driver_delete(port_num)); - ESP_ERROR_CHECK(uart_driver_install(port_num, BUF_SIZE * 2, BUF_SIZE * 2, 20, &hci_uart.evt_queue, intr_alloc_flags)); - ESP_ERROR_CHECK(uart_param_config(port_num, &hci_uart.cfg)); - ESP_ERROR_CHECK(uart_set_pin(port_num, HCI_UART_TX_PIN, HCI_UART_RX_PIN, HCI_UART_RTS_PIN, HCI_UART_CTS_PIN)); - - hci_uart.uart_opened = true; - - //Create a task to handler UART event from ISR - xTaskCreate(hci_uart_rx_task, "hci_uart_rx_task", 2048, NULL, 12, &hci_uart.rx_task_handler); - return 0; -} - -void IRAM_ATTR hci_uart_start_tx(int port_num) -{ - int data; - uint8_t u8_data = 0; - while (1) { - data = hci_uart.tx_char(hci_uart.u_func_arg); - if (data >= 0) { - u8_data = data; - uart_write_bytes(port_num, (char *)&u8_data, 1); - } else { - break; - } - } - if (hci_uart.tx_done) { - hci_uart.tx_done(hci_uart.u_func_arg); - } -} - -int hci_uart_init_cbs(int port_num, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) -{ - hci_uart.tx_char = tx_func; - hci_uart.rx_char = rx_func; - hci_uart.tx_done = tx_done; - hci_uart.u_func_arg = arg; - return 0; -} - -int hci_uart_close(int port_num) -{ - uart_event_t uart_event; - uart_event.type = UART_BREAK; - hci_uart.uart_opened = false; - // Stop uart rx task - if (hci_uart.rx_task_handler != NULL) { - xQueueSend(hci_uart.evt_queue, (void *)&uart_event, 1000); - ESP_LOGW(TAG, "Waiting for uart task finish..."); - } - while (hci_uart.rx_task_handler != NULL); - - uart_driver_delete(port_num); - ESP_LOGI(TAG, "hci uart close success."); - return 0; -} - -int hci_uart_reconfig_pin(int tx_pin, int rx_pin, int cts_pin, int rts_pin) -{ - int port_num = hci_uart.port; - int32_t baud_rate = hci_uart.cfg.baud_rate; - uint8_t data_bits = hci_uart.cfg.data_bits; - uint8_t stop_bits = hci_uart.cfg.stop_bits; - uart_parity_t parity = hci_uart.cfg.parity; - uart_hw_flowcontrol_t flow_ctl = hci_uart.cfg.flow_ctrl; - hci_uart_close(port_num); - hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); - ESP_ERROR_CHECK(uart_set_pin(port_num, tx_pin, rx_pin, rts_pin, cts_pin)); - return 0; -} -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART From 1390711c27e0a1711ba6e85f02bd038520840f04 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:12:38 +0800 Subject: [PATCH 384/548] feat(bluetooth/controller): adopting new HCI layer code on ESP32-C2 --- components/bt/controller/esp32c2/Kconfig.in | 30 ++- components/bt/controller/esp32c2/bt.c | 188 ++---------------- components/bt/controller/esp32c2/esp_bt_cfg.h | 19 +- .../bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- .../bt/include/esp32c2/include/esp_bt.h | 9 +- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 1 - 6 files changed, 59 insertions(+), 190 deletions(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index 9a04ae6394c..8699b6b56c5 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -2,15 +2,15 @@ menu "HCI Config" choice BT_LE_HCI_INTERFACE - prompt "Select HCI interface" + prompt "HCI mode" default BT_LE_HCI_INTERFACE_USE_RAM config BT_LE_HCI_INTERFACE_USE_RAM - bool "ram" + bool "VHCI" help Use RAM as HCI interface config BT_LE_HCI_INTERFACE_USE_UART - bool "uart" + bool "UART(H4)" help Use UART as HCI interface endchoice @@ -73,12 +73,26 @@ menu "HCI Config" UART_PARITY_ODD endchoice - config BT_LE_HCI_UART_TASK_STACK_SIZE - int "HCI uart task stack size" - depends on BT_LE_HCI_INTERFACE_USE_UART - default 1000 + config BT_LE_HCI_UART_RX_BUFFER_SIZE + int "The size of rx ring buffer memory" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 512 + help + The size of rx ring buffer memory + + config BT_LE_HCI_UART_TX_BUFFER_SIZE + int "The size of tx ring buffer memory" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 256 + help + The size of tx ring buffer memory + + config BT_LE_HCI_TRANS_TASK_STACK_SIZE + int "HCI transport task stack size" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 1024 help - Set the size of uart task stack + This configures stack size of hci transport task endmenu config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT diff --git a/components/bt/controller/esp32c2/bt.c b/components/bt/controller/esp32c2/bt.c index 29c3332604b..8333a8a2b11 100644 --- a/components/bt/controller/esp32c2/bt.c +++ b/components/bt/controller/esp32c2/bt.c @@ -31,7 +31,7 @@ #endif #include "nimble/nimble_npl_os.h" -#include "ble_hci_trans.h" +#include "esp_hci_transport.h" #include "os/endian.h" #include "esp_bt.h" @@ -44,13 +44,8 @@ #include "soc/syscon_reg.h" #include "soc/modem_clkrst_reg.h" #include "esp_private/periph_ctrl.h" -#include "hci_uart.h" #include "bt_osi_mem.h" -#ifdef CONFIG_BT_BLUEDROID_ENABLED -#include "hci/hci_hal.h" -#endif - #if CONFIG_FREERTOS_USE_TICKLESS_IDLE #include "esp_private/sleep_modem.h" #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE @@ -67,6 +62,7 @@ #include "hal/efuse_ll.h" #include "soc/rtc.h" + /* Macro definition ************************************************************************ */ @@ -79,12 +75,6 @@ #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 #define BT_ASSERT_PRINT ets_printf - -#ifdef CONFIG_BT_BLUEDROID_ENABLED -/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ -#define ACL_DATA_MBUF_LEADINGSPCAE 4 -#endif // CONFIG_BT_BLUEDROID_ENABLED - typedef enum ble_rtc_slow_clk_src { BT_SLOW_CLK_SRC_MAIN_XTAL, BT_SLOW_CLK_SRC_32K_XTAL_ON_PIN0, @@ -108,12 +98,12 @@ struct ext_funcs_t { int (*_esp_intr_free)(void **ret_handle); void *(* _malloc)(size_t size); void (*_free)(void *p); - void (*_hal_uart_start_tx)(int); - int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); - int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); - int (*_hal_uart_close)(int); - void (*_hal_uart_blocking_tx)(int, uint8_t); - int (*_hal_uart_init)(int, void *); + void (*_rsv1)(int); + int (*_rsv2)(int, int (*)(void *arg), int (*)(void *arg, uint8_t byte), int (*)(void *arg, uint8_t byte), void *); + int (*_rsv3)(int, int32_t, uint8_t, uint8_t, int, int); + int (*_rsv4)(int); + void (*_rsv5)(int, uint8_t); + int (*_rsv6)(int, void *); int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); void (* _task_delete)(void *task_handle); void (*_osi_assert)(const uint32_t ln, const char *fn, uint32_t param1, uint32_t param2); @@ -191,16 +181,6 @@ static void coex_schm_status_bit_set_wrapper(uint32_t type, uint32_t status); static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); static void task_delete_wrapper(void *task_handle); -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no); -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); -static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); -static int hci_uart_close_wrapper(int uart_no); -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); -static int hci_uart_init_wrapper(int uart_no, void *cfg); -#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in); static int esp_intr_free_wrapper(void **ret_handle); @@ -218,7 +198,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b */ /* Static variable declare */ static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; - #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -232,7 +211,6 @@ static DRAM_ATTR esp_pm_lock_handle_t s_pm_lock = NULL; #define BLE_RTC_DELAY_US (1800) - static const struct osi_coex_funcs_t s_osi_coex_funcs_ro = { ._magic = OSI_COEX_MAGIC_VALUE, ._version = OSI_COEX_VERSION, @@ -248,14 +226,6 @@ struct ext_funcs_t ext_funcs_ro = { ._esp_intr_free = esp_intr_free_wrapper, ._malloc = bt_osi_mem_malloc_internal, ._free = bt_osi_mem_free, -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART - ._hal_uart_start_tx = hci_uart_start_tx_wrapper, - ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, - ._hal_uart_config = hci_uart_config_wrapper, - ._hal_uart_close = hci_uart_close_wrapper, - ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, - ._hal_uart_init = hci_uart_init_wrapper, -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART ._task_create = task_create_wrapper, ._task_delete = task_delete_wrapper, ._osi_assert = osi_assert_wrapper, @@ -302,83 +272,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) #endif // CONFIG_SW_COEXIST_ENABLE } -#ifdef CONFIG_BT_BLUEDROID_ENABLED -bool esp_vhci_host_check_send_available(void) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return false; - } - return true; -} - -/** - * Allocates an mbuf for use by the nimble host. - */ -static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) -{ - struct os_mbuf *om; - int rc; - - om = os_msys_get_pkthdr(0, 0); - if (om == NULL) { - return NULL; - } - - if (om->om_omp->omp_databuf_len < leading_space) { - rc = os_mbuf_free_chain(om); - assert(rc == 0); - return NULL; - } - - om->om_data += leading_space; - - return om; -} - -/** - * Allocates an mbuf suitable for an HCI ACL data packet. - * - * @return An empty mbuf on success; null on memory - * exhaustion. - */ -struct os_mbuf *ble_hs_mbuf_acl_pkt(void) -{ - return ble_hs_mbuf_gen_pkt(4 + 1); -} - -void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return; - } - - if (*(data) == DATA_TYPE_COMMAND) { - struct ble_hci_cmd *cmd = NULL; - cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - assert(cmd); - memcpy((uint8_t *)cmd, data + 1, len - 1); - ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); - } - - if (*(data) == DATA_TYPE_ACL) { - struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); - assert(om); - assert(os_mbuf_append(om, &data[1], len - 1) == 0); - ble_hci_trans_hs_acl_tx(om); - } -} - -esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return ESP_FAIL; - } - - ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); - - return ESP_OK; -} -#endif // CONFIG_BT_BLUEDROID_ENABLED static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < CONFIG_FREERTOS_NUMBER_OF_CORES ? core_id : tskNO_AFFINITY)); @@ -408,56 +301,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer return rc; } -#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no) -{ - hci_uart_start_tx(uart_no); -} - -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) -{ - int rc = -1; - rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); - return rc; -} - - -static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, - uint8_t stop_bits,uart_parity_t parity, - uart_hw_flowcontrol_t flow_ctl) -{ - int rc = -1; - rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); - return rc; -} - -static int hci_uart_close_wrapper(int uart_no) -{ - int rc = -1; - rc = hci_uart_close(uart_no); - return rc; -} - -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) -{ - //This function is nowhere to use. -} - -static int hci_uart_init_wrapper(int uart_no, void *cfg) -{ - //This function is nowhere to use. - return 0; -} - -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART - -static int ble_hci_unregistered_hook(void*, void*) -{ - ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); - return 0; -} - static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in) { int rc = esp_intr_alloc(source, flags | ESP_INTR_FLAG_IRAM, handler, arg, (intr_handle_t *)ret_handle_in); @@ -635,6 +478,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t ret = ESP_OK; ble_npl_count_info_t npl_info; ble_rtc_slow_clk_src_t rtc_clk_src; + uint8_t hci_transport_mode; memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { @@ -757,10 +601,19 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; - ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, - (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + hci_transport_mode = HCI_TRANSPORT_VHCI; +#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART + hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA; +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + ret = hci_transport_init(hci_transport_mode); + if (ret) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret); + goto free_controller; + } return ESP_OK; free_controller: + hci_transport_deinit(); controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED controller_init_err: @@ -789,6 +642,7 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_FAIL; } + hci_transport_deinit(); controller_sleep_deinit(); #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED diff --git a/components/bt/controller/esp32c2/esp_bt_cfg.h b/components/bt/controller/esp32c2/esp_bt_cfg.h index 0cb4168e030..ff0db7c8919 100644 --- a/components/bt/controller/esp32c2/esp_bt_cfg.h +++ b/components/bt/controller/esp32c2/esp_bt_cfg.h @@ -28,7 +28,6 @@ extern "C" { #else #define BLE_LL_SCAN_PHY_NUMBER_N (1) #endif - #define DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST MYNEWT_VAL(BLE_MAX_PERIODIC_ADVERTISER_LIST) #define DEFAULT_BT_LE_MAX_PERIODIC_SYNCS MYNEWT_VAL(BLE_MAX_PERIODIC_SYNCS) #define DEFAULT_BT_LE_MAX_CONNECTIONS MYNEWT_VAL(BLE_MAX_CONNECTIONS) @@ -152,6 +151,20 @@ extern "C" { #else #define DEFAULT_BT_LE_ROLE_OBSERVER (0) #endif + #if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN) + #else + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif + #else + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF @@ -192,8 +205,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #else #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) @@ -202,8 +213,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #endif /* Unchanged configuration */ diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index e597ae52976..fc65dbee209 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit e597ae529761d270f10d0616c375faa0e4b7ca13 +Subproject commit fc65dbee2093051bdf8dd45fd4346811a39a4ff8 diff --git a/components/bt/include/esp32c2/include/esp_bt.h b/components/bt/include/esp32c2/include/esp_bt.h index ee1bede7e4d..c73d4cb9243 100644 --- a/components/bt/include/esp32c2/include/esp_bt.h +++ b/components/bt/include/esp32c2/include/esp_bt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -262,13 +262,6 @@ typedef struct { .controller_run_cpu = 0, \ .enable_qa_test = RUN_QA_TEST, \ .enable_bqb_test = RUN_BQB_TEST, \ - .enable_uart_hci = HCI_UART_EN, \ - .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \ - .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \ - .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \ - .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \ - .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \ - .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \ .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \ .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \ .sleep_en = NIMBLE_SLEEP_ENABLE, \ diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 10634491c23..a5ebd9f8805 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -753,7 +753,6 @@ r_ble_ll_hci_ev_send_adv_set_terminated = 0x40000ff4; r_ble_ll_hci_ev_send_scan_req_recv = 0x40000ff8; r_ble_ll_hci_ev_send_scan_timeout = 0x40000ffc; r_ble_ll_hci_ev_send_vendor_err = 0x40001000; -r_ble_ll_hci_event_send = 0x40001004; r_ble_ll_hci_ext_scan_set_enable = 0x40001008; r_ble_ll_hci_get_num_cmd_pkts = 0x4000100c; r_ble_ll_hci_info_params_cmd_proc = 0x40001010; From e761c1de8f9c0777829d597b4d5a33bb070a30a8 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:14:14 +0800 Subject: [PATCH 385/548] feat(bluetooth/controller): adopting new HCI layer code and support UHCI function on ESP32-C6 and ESP32-H2 --- components/bt/controller/esp32c6/Kconfig.in | 62 +++++- components/bt/controller/esp32c6/bt.c | 178 ++---------------- components/bt/controller/esp32c6/esp_bt_cfg.h | 21 ++- components/bt/controller/esp32h2/Kconfig.in | 62 +++++- components/bt/controller/esp32h2/bt.c | 178 ++---------------- components/bt/controller/esp32h2/esp_bt_cfg.h | 22 ++- .../bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- .../bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- .../bt/include/esp32c6/include/esp_bt.h | 18 +- .../bt/include/esp32h2/include/esp_bt.h | 18 +- components/hal/esp32c6/include/hal/uhci_ll.h | 133 +++++++++++++ components/hal/esp32h2/include/hal/uhci_ll.h | 133 +++++++++++++ 12 files changed, 450 insertions(+), 379 deletions(-) create mode 100644 components/hal/esp32c6/include/hal/uhci_ll.h create mode 100644 components/hal/esp32h2/include/hal/uhci_ll.h diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 0dcc8996bf6..665e34366a1 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -2,19 +2,37 @@ menu "HCI Config" choice BT_LE_HCI_INTERFACE - prompt "Select HCI interface" + prompt "HCI mode" default BT_LE_HCI_INTERFACE_USE_RAM config BT_LE_HCI_INTERFACE_USE_RAM - bool "ram" + bool "VHCI" help Use RAM as HCI interface config BT_LE_HCI_INTERFACE_USE_UART - bool "uart" + bool "UART(H4)" help Use UART as HCI interface endchoice + choice BT_LE_UART_HCI_MODE_CHOICE + prompt "UART HCI mode" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_UART_HCI_NO_DMA_MODE + help + Specify UART HCI mode: DMA or No DMA + + config BT_LE_UART_HCI_DMA_MODE + bool "UHCI(UART with DMA)(EXPERIMENTAL)" + help + UART HCI Mode with DMA functionality. + + config BT_LE_UART_HCI_NO_DMA_MODE + bool "UART(NO DMA)" + help + UART HCI Mode without DMA functionality. + endchoice + config BT_LE_HCI_UART_PORT int "HCI UART port" depends on BT_LE_HCI_INTERFACE_USE_UART @@ -73,12 +91,40 @@ menu "HCI Config" UART_PARITY_ODD endchoice - config BT_LE_HCI_UART_TASK_STACK_SIZE - int "HCI uart task stack size" - depends on BT_LE_HCI_INTERFACE_USE_UART - default 1000 + config BT_LE_HCI_UART_RX_BUFFER_SIZE + int "The size of rx ring buffer memory" + depends on BT_LE_UART_HCI_NO_DMA_MODE + default 512 + help + The size of rx ring buffer memory + + config BT_LE_HCI_UART_TX_BUFFER_SIZE + int "The size of tx ring buffer memory" + depends on BT_LE_UART_HCI_NO_DMA_MODE + default 256 + help + The size of tx ring buffer memory + + config BT_LE_HCI_TRANS_TASK_STACK_SIZE + int "HCI transport task stack size" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 1024 + help + This configures stack size of hci transport task + + config BT_LE_HCI_TRANS_RX_MEM_NUM + int "The amount of rx memory received at the same time" + depends on BT_LE_UART_HCI_DMA_MODE + default 3 + help + The amount of rx memory received at the same time + + config BT_LE_HCI_LLDESCS_POOL_NUM + int "The amount of lldecs memory for driver dma mode" + depends on BT_LE_UART_HCI_DMA_MODE + default 20 help - Set the size of uart task stack + The amount of lldecs memory for driver dma mode endmenu config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 489327f0281..10d15761568 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -30,7 +30,7 @@ #endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "ble_hci_trans.h" +#include "esp_hci_transport.h" #include "os/endian.h" #include "esp_bt.h" @@ -41,7 +41,6 @@ #include "esp_phy_init.h" #endif #include "esp_private/periph_ctrl.h" -#include "hci_uart.h" #include "bt_osi_mem.h" #if SOC_PM_RETENTION_HAS_CLOCK_BUG @@ -52,10 +51,6 @@ #include "esp_private/sleep_modem.h" #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE -#ifdef CONFIG_BT_BLUEDROID_ENABLED -#include "hci/hci_hal.h" -#endif // CONFIG_BT_BLUEDROID_ENABLED - #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -71,16 +66,11 @@ #define OSI_COEX_VERSION 0x00010006 #define OSI_COEX_MAGIC_VALUE 0xFADEBEAD -#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_VERSION 0x20240422 #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 #define BT_ASSERT_PRINT ets_printf -#ifdef CONFIG_BT_BLUEDROID_ENABLED -/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ -#define ACL_DATA_MBUF_LEADINGSPCAE 4 -#endif // CONFIG_BT_BLUEDROID_ENABLED - /* Types definition ************************************************************************ */ @@ -99,12 +89,6 @@ struct ext_funcs_t { int (*_esp_intr_free)(void **ret_handle); void *(* _malloc)(size_t size); void (*_free)(void *p); - void (*_hal_uart_start_tx)(int); - int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); - int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); - int (*_hal_uart_close)(int); - void (*_hal_uart_blocking_tx)(int, uint8_t); - int (*_hal_uart_init)(int, void *); int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); void (* _task_delete)(void *task_handle); @@ -181,16 +165,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); static void task_delete_wrapper(void *task_handle); -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no); -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); -static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); -static int hci_uart_close_wrapper(int uart_no); -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); -static int hci_uart_init_wrapper(int uart_no, void *cfg); -#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in); static int esp_intr_free_wrapper(void **ret_handle); @@ -208,7 +182,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b */ /* Static variable declare */ static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; - #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -238,14 +211,6 @@ struct ext_funcs_t ext_funcs_ro = { ._esp_intr_free = esp_intr_free_wrapper, ._malloc = bt_osi_mem_malloc_internal, ._free = bt_osi_mem_free, -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART - ._hal_uart_start_tx = hci_uart_start_tx_wrapper, - ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, - ._hal_uart_config = hci_uart_config_wrapper, - ._hal_uart_close = hci_uart_close_wrapper, - ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, - ._hal_uart_init = hci_uart_init_wrapper, -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART ._task_create = task_create_wrapper, ._task_delete = task_delete_wrapper, ._osi_assert = osi_assert_wrapper, @@ -290,75 +255,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) #endif // CONFIG_SW_COEXIST_ENABLE } -#ifdef CONFIG_BT_BLUEDROID_ENABLED -bool esp_vhci_host_check_send_available(void) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return false; - } - return true; -} - -static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) -{ - struct os_mbuf *om; - int rc; - - om = os_msys_get_pkthdr(0, 0); - if (om == NULL) { - return NULL; - } - - if (om->om_omp->omp_databuf_len < leading_space) { - rc = os_mbuf_free_chain(om); - assert(rc == 0); - return NULL; - } - - om->om_data += leading_space; - - return om; -} - -struct os_mbuf *ble_hs_mbuf_acl_pkt(void) -{ - return ble_hs_mbuf_gen_pkt(4 + 1); -} - -void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return; - } - - if (*(data) == DATA_TYPE_COMMAND) { - struct ble_hci_cmd *cmd = NULL; - cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - assert(cmd); - memcpy((uint8_t *)cmd, data + 1, len - 1); - ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); - } - - if (*(data) == DATA_TYPE_ACL) { - struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); - assert(om); - assert(os_mbuf_append(om, &data[1], len - 1) == 0); - ble_hci_trans_hs_acl_tx(om); - } -} - -esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return ESP_FAIL; - } - - ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); - - return ESP_OK; -} -#endif // CONFIG_BT_BLUEDROID_ENABLED - static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { @@ -390,56 +286,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer return rc; } -#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no) -{ - hci_uart_start_tx(uart_no); -} - -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) -{ - int rc = -1; - rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); - return rc; -} - - -static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, - uint8_t stop_bits, uart_parity_t parity, - uart_hw_flowcontrol_t flow_ctl) -{ - int rc = -1; - rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); - return rc; -} - -static int hci_uart_close_wrapper(int uart_no) -{ - int rc = -1; - rc = hci_uart_close(uart_no); - return rc; -} - -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) -{ - //This function is nowhere to use. -} - -static int hci_uart_init_wrapper(int uart_no, void *cfg) -{ - //This function is nowhere to use. - return 0; -} - -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART - -static int ble_hci_unregistered_hook(void*, void*) -{ - ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); - return 0; -} - static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in) { @@ -718,6 +564,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t ret = ESP_OK; ble_npl_count_info_t npl_info; uint32_t slow_clk_freq = 0; + uint8_t hci_transport_mode; memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); @@ -862,11 +709,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; - ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, - (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); - return ESP_OK; +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + hci_transport_mode = HCI_TRANSPORT_VHCI; +#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART + hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA; +#if CONFIG_BT_LE_UART_HCI_DMA_MODE + hci_transport_mode = HCI_TRANSPORT_UART_UHCI; +#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + ret = hci_transport_init(hci_transport_mode); + if (ret) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret); + goto free_controller; + } + return ESP_OK; free_controller: + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); r_ble_controller_deinit(); @@ -897,6 +756,7 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_FAIL; } + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); diff --git a/components/bt/controller/esp32c6/esp_bt_cfg.h b/components/bt/controller/esp32c6/esp_bt_cfg.h index 9e341e32290..b8bbfd3d4b7 100644 --- a/components/bt/controller/esp32c6/esp_bt_cfg.h +++ b/components/bt/controller/esp32c6/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -129,6 +129,21 @@ extern "C" { #else #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) #endif + + #if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN) + #else + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif + #else + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF @@ -169,8 +184,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #else #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) @@ -179,8 +192,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #endif /* Unchanged configuration */ diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index e0c4936156e..e45aa2030ae 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -2,19 +2,37 @@ menu "HCI Config" choice BT_LE_HCI_INTERFACE - prompt "Select HCI interface" + prompt "HCI mode" default BT_LE_HCI_INTERFACE_USE_RAM config BT_LE_HCI_INTERFACE_USE_RAM - bool "ram" + bool "VHCI" help Use RAM as HCI interface config BT_LE_HCI_INTERFACE_USE_UART - bool "uart" + bool "UART(H4)" help Use UART as HCI interface endchoice + choice BT_LE_UART_HCI_MODE_CHOICE + prompt "UART HCI mode" + depends on BT_LE_HCI_INTERFACE_USE_UART + default BT_LE_UART_HCI_NO_DMA_MODE + help + Specify UART HCI mode: DMA or No DMA + + config BT_LE_UART_HCI_DMA_MODE + bool "UHCI(UART with DMA)(EXPERIMENTAL)" + help + UART HCI Mode with DMA functionality. + + config BT_LE_UART_HCI_NO_DMA_MODE + bool "UART(NO DMA)" + help + UART HCI Mode without DMA functionality. + endchoice + config BT_LE_HCI_UART_PORT int "HCI UART port" depends on BT_LE_HCI_INTERFACE_USE_UART @@ -73,12 +91,40 @@ menu "HCI Config" UART_PARITY_ODD endchoice - config BT_LE_HCI_UART_TASK_STACK_SIZE - int "HCI uart task stack size" - depends on BT_LE_HCI_INTERFACE_USE_UART - default 1000 + config BT_LE_HCI_UART_RX_BUFFER_SIZE + int "The size of rx ring buffer memory" + depends on BT_LE_UART_HCI_NO_DMA_MODE + default 512 + help + The size of rx ring buffer memory + + config BT_LE_HCI_UART_TX_BUFFER_SIZE + int "The size of tx ring buffer memory" + depends on BT_LE_UART_HCI_NO_DMA_MODE + default 256 + help + The size of tx ring buffer memory + + config BT_LE_HCI_TRANS_TASK_STACK_SIZE + int "HCI transport task stack size" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 1024 + help + This configures stack size of hci transport task + + config BT_LE_HCI_TRANS_RX_MEM_NUM + int "The amount of rx memory received at the same time" + depends on BT_LE_UART_HCI_DMA_MODE + default 3 + help + The amount of rx memory received at the same time + + config BT_LE_HCI_LLDESCS_POOL_NUM + int "The amount of lldecs memory for driver dma mode" + depends on BT_LE_UART_HCI_DMA_MODE + default 20 help - Set the size of uart task stack + The amount of lldecs memory for driver dma mode endmenu config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index adb10d4981f..5e2b1fb66b7 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -30,7 +30,7 @@ #endif // CONFIG_ESP_COEX_ENABLED #include "nimble/nimble_npl_os.h" -#include "ble_hci_trans.h" +#include "esp_hci_transport.h" #include "os/endian.h" #include "esp_bt.h" @@ -39,7 +39,6 @@ #include "esp_pm.h" #include "esp_phy_init.h" #include "esp_private/periph_ctrl.h" -#include "hci_uart.h" #include "bt_osi_mem.h" #if CONFIG_FREERTOS_USE_TICKLESS_IDLE @@ -47,10 +46,6 @@ #include "esp_private/sleep_retention.h" #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE -#ifdef CONFIG_BT_BLUEDROID_ENABLED -#include "hci/hci_hal.h" -#endif // CONFIG_BT_BLUEDROID_ENABLED - #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -64,16 +59,11 @@ #define OSI_COEX_VERSION 0x00010006 #define OSI_COEX_MAGIC_VALUE 0xFADEBEAD -#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_VERSION 0x20240422 #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 #define BT_ASSERT_PRINT ets_printf -#ifdef CONFIG_BT_BLUEDROID_ENABLED -/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ -#define ACL_DATA_MBUF_LEADINGSPCAE 4 -#endif // CONFIG_BT_BLUEDROID_ENABLED - /* Types definition ************************************************************************ */ @@ -92,12 +82,6 @@ struct ext_funcs_t { int (*_esp_intr_free)(void **ret_handle); void *(* _malloc)(size_t size); void (*_free)(void *p); - void (*_hal_uart_start_tx)(int); - int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); - int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); - int (*_hal_uart_close)(int); - void (*_hal_uart_blocking_tx)(int, uint8_t); - int (*_hal_uart_init)(int, void *); int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); void (* _task_delete)(void *task_handle); @@ -173,16 +157,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); static void task_delete_wrapper(void *task_handle); -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no); -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); -static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); -static int hci_uart_close_wrapper(int uart_no); -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); -static int hci_uart_init_wrapper(int uart_no, void *cfg); -#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in); static int esp_intr_free_wrapper(void **ret_handle); @@ -200,7 +174,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b */ /* Static variable declare */ static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; - #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -230,14 +203,6 @@ struct ext_funcs_t ext_funcs_ro = { ._esp_intr_free = esp_intr_free_wrapper, ._malloc = bt_osi_mem_malloc_internal, ._free = bt_osi_mem_free, -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART - ._hal_uart_start_tx = hci_uart_start_tx_wrapper, - ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, - ._hal_uart_config = hci_uart_config_wrapper, - ._hal_uart_close = hci_uart_close_wrapper, - ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, - ._hal_uart_init = hci_uart_init_wrapper, -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART ._task_create = task_create_wrapper, ._task_delete = task_delete_wrapper, ._osi_assert = osi_assert_wrapper, @@ -282,75 +247,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) #endif // CONFIG_SW_COEXIST_ENABLE } -#ifdef CONFIG_BT_BLUEDROID_ENABLED -bool esp_vhci_host_check_send_available(void) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return false; - } - return true; -} - -static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) -{ - struct os_mbuf *om; - int rc; - - om = os_msys_get_pkthdr(0, 0); - if (om == NULL) { - return NULL; - } - - if (om->om_omp->omp_databuf_len < leading_space) { - rc = os_mbuf_free_chain(om); - assert(rc == 0); - return NULL; - } - - om->om_data += leading_space; - - return om; -} - -struct os_mbuf *ble_hs_mbuf_acl_pkt(void) -{ - return ble_hs_mbuf_gen_pkt(4 + 1); -} - -void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return; - } - - if (*(data) == DATA_TYPE_COMMAND) { - struct ble_hci_cmd *cmd = NULL; - cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - assert(cmd); - memcpy((uint8_t *)cmd, data + 1, len - 1); - ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); - } - - if (*(data) == DATA_TYPE_ACL) { - struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); - assert(om); - assert(os_mbuf_append(om, &data[1], len - 1) == 0); - ble_hci_trans_hs_acl_tx(om); - } -} - -esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return ESP_FAIL; - } - - ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); - - return ESP_OK; -} -#endif // CONFIG_BT_BLUEDROID_ENABLED - static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { @@ -382,56 +278,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer return rc; } -#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no) -{ - hci_uart_start_tx(uart_no); -} - -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) -{ - int rc = -1; - rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); - return rc; -} - - -static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, - uint8_t stop_bits, uart_parity_t parity, - uart_hw_flowcontrol_t flow_ctl) -{ - int rc = -1; - rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); - return rc; -} - -static int hci_uart_close_wrapper(int uart_no) -{ - int rc = -1; - rc = hci_uart_close(uart_no); - return rc; -} - -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) -{ - //This function is nowhere to use. -} - -static int hci_uart_init_wrapper(int uart_no, void *cfg) -{ - //This function is nowhere to use. - return 0; -} - -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART - -static int ble_hci_unregistered_hook(void*, void*) -{ - ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); - return 0; -} - static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in) { @@ -689,6 +535,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t ret = ESP_OK; ble_npl_count_info_t npl_info; uint32_t slow_clk_freq = 0; + uint8_t hci_transport_mode; memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_IDLE) { @@ -831,11 +678,23 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; - ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, - (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); - return ESP_OK; +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + hci_transport_mode = HCI_TRANSPORT_VHCI; +#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART + hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA; +#if CONFIG_BT_LE_UART_HCI_DMA_MODE + hci_transport_mode = HCI_TRANSPORT_UART_UHCI; +#endif // CONFIG_BT_LE_UART_HCI_DMA_MODE +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + ret = hci_transport_init(hci_transport_mode); + if (ret) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret); + goto free_controller; + } + return ESP_OK; free_controller: + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); r_ble_controller_deinit(); @@ -865,6 +724,7 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_FAIL; } + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); diff --git a/components/bt/controller/esp32h2/esp_bt_cfg.h b/components/bt/controller/esp32h2/esp_bt_cfg.h index c0c5801af14..b8bbfd3d4b7 100644 --- a/components/bt/controller/esp32h2/esp_bt_cfg.h +++ b/components/bt/controller/esp32h2/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -124,12 +124,26 @@ extern "C" { #else #define DEFAULT_BT_LE_POWER_CONTROL_ENABLED (0) #endif - #if defined(CONFIG_BT_LE_50_FEATURE_SUPPORT) #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (1) #else #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) #endif + + #if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN) + #else + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif + #else + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF @@ -170,8 +184,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #else #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) @@ -180,8 +192,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #endif /* Unchanged configuration */ diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index 4a63b2963a8..2085541b6e9 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit 4a63b2963a8a75958db680df4ace64bbd3d6c618 +Subproject commit 2085541b6e9963640e4090401faaf2061758d847 diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index 96b48749e24..9e29a8b39fe 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit 96b48749e249d0752f196007b008212cb8b28e07 +Subproject commit 9e29a8b39fe81ac82064dc4525e56e0faa9e1b8a diff --git a/components/bt/include/esp32c6/include/esp_bt.h b/components/bt/include/esp32c6/include/esp_bt.h index 210ead42da9..ea272287228 100644 --- a/components/bt/include/esp32c6/include/esp_bt.h +++ b/components/bt/include/esp32c6/include/esp_bt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -155,7 +155,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20231124 +#define CONFIG_VERSION 0x20240422 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -196,13 +196,6 @@ typedef struct { uint8_t controller_run_cpu; /*!< CPU core on which the controller runs */ uint8_t enable_qa_test; /*!< Enable quality assurance (QA) testing */ uint8_t enable_bqb_test; /*!< Enable Bluetooth Qualification Test (BQB) testing */ - uint8_t enable_uart_hci; /*!< Enable UART HCI (Host Controller Interface) */ - uint8_t ble_hci_uart_port; /*!< UART port number for Bluetooth HCI */ - uint32_t ble_hci_uart_baud; /*!< Baud rate for Bluetooth HCI UART */ - uint8_t ble_hci_uart_data_bits; /*!< Number of data bits for Bluetooth HCI UART */ - uint8_t ble_hci_uart_stop_bits; /*!< Number of stop bits for Bluetooth HCI UART */ - uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control settings for Bluetooth HCI UART */ - uint8_t ble_hci_uart_uart_parity; /*!< Parity settings for Bluetooth HCI UART */ uint8_t enable_tx_cca; /*!< Enable Transmit Clear Channel Assessment (TX CCA) */ uint8_t cca_rssi_thresh; /*!< RSSI threshold for Transmit Clear Channel Assessment (CCA) */ uint8_t sleep_en; /*!< Enable sleep mode */ @@ -253,13 +246,6 @@ typedef struct { .controller_run_cpu = 0, \ .enable_qa_test = RUN_QA_TEST, \ .enable_bqb_test = RUN_BQB_TEST, \ - .enable_uart_hci = HCI_UART_EN, \ - .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \ - .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \ - .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \ - .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \ - .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \ - .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \ .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \ .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \ .sleep_en = NIMBLE_SLEEP_ENABLE, \ diff --git a/components/bt/include/esp32h2/include/esp_bt.h b/components/bt/include/esp32h2/include/esp_bt.h index a1c7aed8ee2..bbecb64072f 100644 --- a/components/bt/include/esp32h2/include/esp_bt.h +++ b/components/bt/include/esp32h2/include/esp_bt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -160,7 +160,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20231124 +#define CONFIG_VERSION 0x20240422 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -201,13 +201,6 @@ typedef struct { uint8_t controller_run_cpu; /*!< CPU number on which the Bluetooth controller task runs */ uint8_t enable_qa_test; /*!< Enable for QA test */ uint8_t enable_bqb_test; /*!< Enable for BQB test */ - uint8_t enable_uart_hci; /*!< Enable UART for HCI (Host Controller Interface) */ - uint8_t ble_hci_uart_port; /*!< Port of UART for HCI */ - uint32_t ble_hci_uart_baud; /*!< Baudrate of UART for HCI */ - uint8_t ble_hci_uart_data_bits; /*!< Data bits of UART for HCI */ - uint8_t ble_hci_uart_stop_bits; /*!< Stop bits of UART for HCI */ - uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control of UART for HCI */ - uint8_t ble_hci_uart_uart_parity; /*!< UART parity */ uint8_t enable_tx_cca; /*!< Enable Clear Channel Assessment (CCA) when transmitting */ uint8_t cca_rssi_thresh; /*!< RSSI threshold for CCA */ uint8_t sleep_en; /*!< Enable sleep functionality */ @@ -258,13 +251,6 @@ typedef struct { .controller_run_cpu = 0, \ .enable_qa_test = RUN_QA_TEST, \ .enable_bqb_test = RUN_BQB_TEST, \ - .enable_uart_hci = HCI_UART_EN, \ - .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \ - .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \ - .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \ - .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \ - .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \ - .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \ .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \ .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \ .sleep_en = NIMBLE_SLEEP_ENABLE, \ diff --git a/components/hal/esp32c6/include/hal/uhci_ll.h b/components/hal/esp32c6/include/hal/uhci_ll.h new file mode 100644 index 00000000000..07d4a40a683 --- /dev/null +++ b/components/hal/esp32c6/include/hal/uhci_ll.h @@ -0,0 +1,133 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include +#include "hal/uhci_types.h" +#include "soc/uhci_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL)) + +typedef enum { + UHCI_RX_BREAK_CHR_EOF = 0x1, + UHCI_RX_IDLE_EOF = 0x2, + UHCI_RX_LEN_EOF = 0x4, + UHCI_RX_EOF_MAX = 0x7, +} uhci_rxeof_cfg_t; + +static inline void uhci_ll_init(uhci_dev_t *hw) +{ + typeof(hw->conf0) conf0_reg; + hw->conf0.clk_en = 1; + conf0_reg.val = 0; + conf0_reg.clk_en = 1; + hw->conf0.val = conf0_reg.val; + hw->conf1.val = 0; +} + +static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num) +{ + hw->conf0.uart0_ce = (uart_num == 0)? 1: 0; + hw->conf0.uart1_ce = (uart_num == 1)? 1: 0; +} + +static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char) +{ + if (seper_char->sub_chr_en) { + typeof(hw->esc_conf0) esc_conf0_reg; + esc_conf0_reg.val = hw->esc_conf0.val; + + esc_conf0_reg.seper_char = seper_char->seper_chr; + esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1; + esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2; + hw->esc_conf0.val = esc_conf0_reg.val; + hw->escape_conf.tx_c0_esc_en = 1; + hw->escape_conf.rx_c0_esc_en = 1; + } else { + hw->escape_conf.tx_c0_esc_en = 0; + hw->escape_conf.rx_c0_esc_en = 0; + } +} + +static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr) +{ + (void)hw; + (void)seper_chr; +} + +static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr) +{ + typeof(hw->escape_conf) escape_conf_reg; + escape_conf_reg.val = hw->escape_conf.val; + + if (sub_ctr->flow_en == 1) { + typeof(hw->esc_conf2) esc_conf2_reg; + esc_conf2_reg.val = hw->esc_conf2.val; + typeof(hw->esc_conf3) esc_conf3_reg; + esc_conf3_reg.val = hw->esc_conf3.val; + + esc_conf2_reg.esc_seq1 = sub_ctr->xon_chr; + esc_conf2_reg.esc_seq1_char0 = sub_ctr->xon_sub1; + esc_conf2_reg.esc_seq1_char1 = sub_ctr->xon_sub2; + esc_conf3_reg.esc_seq2 = sub_ctr->xoff_chr; + esc_conf3_reg.esc_seq2_char0 = sub_ctr->xoff_sub1; + esc_conf3_reg.esc_seq2_char1 = sub_ctr->xoff_sub2; + escape_conf_reg.tx_11_esc_en = 1; + escape_conf_reg.tx_13_esc_en = 1; + escape_conf_reg.rx_11_esc_en = 1; + escape_conf_reg.rx_13_esc_en = 1; + hw->esc_conf2.val = esc_conf2_reg.val; + hw->esc_conf3.val = esc_conf3_reg.val; + } else { + escape_conf_reg.tx_11_esc_en = 0; + escape_conf_reg.tx_13_esc_en = 0; + escape_conf_reg.rx_11_esc_en = 0; + escape_conf_reg.rx_13_esc_en = 0; + } + hw->escape_conf.val = escape_conf_reg.val; +} + +static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_clr.val = intr_mask; +} + +static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw) +{ + return hw->int_st.val; +} + + +static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode) +{ + if (eof_mode & UHCI_RX_BREAK_CHR_EOF) { + hw->conf0.uart_rx_brk_eof_en = 1; + } + if (eof_mode & UHCI_RX_IDLE_EOF) { + hw->conf0.uart_idle_eof_en = 1; + } + if (eof_mode & UHCI_RX_LEN_EOF) { + hw->conf0.len_eof_en = 1; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h2/include/hal/uhci_ll.h b/components/hal/esp32h2/include/hal/uhci_ll.h new file mode 100644 index 00000000000..07d4a40a683 --- /dev/null +++ b/components/hal/esp32h2/include/hal/uhci_ll.h @@ -0,0 +1,133 @@ +/* + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once +#include +#include "hal/uhci_types.h" +#include "soc/uhci_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (NULL)) + +typedef enum { + UHCI_RX_BREAK_CHR_EOF = 0x1, + UHCI_RX_IDLE_EOF = 0x2, + UHCI_RX_LEN_EOF = 0x4, + UHCI_RX_EOF_MAX = 0x7, +} uhci_rxeof_cfg_t; + +static inline void uhci_ll_init(uhci_dev_t *hw) +{ + typeof(hw->conf0) conf0_reg; + hw->conf0.clk_en = 1; + conf0_reg.val = 0; + conf0_reg.clk_en = 1; + hw->conf0.val = conf0_reg.val; + hw->conf1.val = 0; +} + +static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num) +{ + hw->conf0.uart0_ce = (uart_num == 0)? 1: 0; + hw->conf0.uart1_ce = (uart_num == 1)? 1: 0; +} + +static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char) +{ + if (seper_char->sub_chr_en) { + typeof(hw->esc_conf0) esc_conf0_reg; + esc_conf0_reg.val = hw->esc_conf0.val; + + esc_conf0_reg.seper_char = seper_char->seper_chr; + esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1; + esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2; + hw->esc_conf0.val = esc_conf0_reg.val; + hw->escape_conf.tx_c0_esc_en = 1; + hw->escape_conf.rx_c0_esc_en = 1; + } else { + hw->escape_conf.tx_c0_esc_en = 0; + hw->escape_conf.rx_c0_esc_en = 0; + } +} + +static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr) +{ + (void)hw; + (void)seper_chr; +} + +static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr) +{ + typeof(hw->escape_conf) escape_conf_reg; + escape_conf_reg.val = hw->escape_conf.val; + + if (sub_ctr->flow_en == 1) { + typeof(hw->esc_conf2) esc_conf2_reg; + esc_conf2_reg.val = hw->esc_conf2.val; + typeof(hw->esc_conf3) esc_conf3_reg; + esc_conf3_reg.val = hw->esc_conf3.val; + + esc_conf2_reg.esc_seq1 = sub_ctr->xon_chr; + esc_conf2_reg.esc_seq1_char0 = sub_ctr->xon_sub1; + esc_conf2_reg.esc_seq1_char1 = sub_ctr->xon_sub2; + esc_conf3_reg.esc_seq2 = sub_ctr->xoff_chr; + esc_conf3_reg.esc_seq2_char0 = sub_ctr->xoff_sub1; + esc_conf3_reg.esc_seq2_char1 = sub_ctr->xoff_sub2; + escape_conf_reg.tx_11_esc_en = 1; + escape_conf_reg.tx_13_esc_en = 1; + escape_conf_reg.rx_11_esc_en = 1; + escape_conf_reg.rx_13_esc_en = 1; + hw->esc_conf2.val = esc_conf2_reg.val; + hw->esc_conf3.val = esc_conf3_reg.val; + } else { + escape_conf_reg.tx_11_esc_en = 0; + escape_conf_reg.tx_13_esc_en = 0; + escape_conf_reg.rx_11_esc_en = 0; + escape_conf_reg.rx_13_esc_en = 0; + } + hw->escape_conf.val = escape_conf_reg.val; +} + +static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_clr.val = intr_mask; +} + +static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw) +{ + return hw->int_st.val; +} + + +static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode) +{ + if (eof_mode & UHCI_RX_BREAK_CHR_EOF) { + hw->conf0.uart_rx_brk_eof_en = 1; + } + if (eof_mode & UHCI_RX_IDLE_EOF) { + hw->conf0.uart_idle_eof_en = 1; + } + if (eof_mode & UHCI_RX_LEN_EOF) { + hw->conf0.len_eof_en = 1; + } +} + +#ifdef __cplusplus +} +#endif From 9117932c6d73bcac9947fef3c8ab5baa29ce28e1 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:15:18 +0800 Subject: [PATCH 386/548] feat(bluetooth/controller): adopting new HCI layer code on ESP32-C5 --- components/bt/controller/esp32c5/Kconfig.in | 30 ++- components/bt/controller/esp32c5/bt.c | 175 ++---------------- components/bt/controller/esp32c5/esp_bt_cfg.h | 19 +- .../bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- .../bt/include/esp32c5/include/esp_bt.h | 16 +- 5 files changed, 55 insertions(+), 187 deletions(-) diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index 02ac4995d27..6ad2a9ce8c0 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -2,15 +2,15 @@ menu "HCI Config" choice BT_LE_HCI_INTERFACE - prompt "Select HCI interface" + prompt "HCI mode" default BT_LE_HCI_INTERFACE_USE_RAM config BT_LE_HCI_INTERFACE_USE_RAM - bool "ram" + bool "VHCI" help Use RAM as HCI interface config BT_LE_HCI_INTERFACE_USE_UART - bool "uart" + bool "UART(H4)" help Use UART as HCI interface endchoice @@ -73,12 +73,26 @@ menu "HCI Config" UART_PARITY_ODD endchoice - config BT_LE_HCI_UART_TASK_STACK_SIZE - int "HCI uart task stack size" - depends on BT_LE_HCI_INTERFACE_USE_UART - default 1000 + config BT_LE_HCI_UART_RX_BUFFER_SIZE + int "The size of rx ring buffer memory" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 512 + help + The size of rx ring buffer memory + + config BT_LE_HCI_UART_TX_BUFFER_SIZE + int "The size of tx ring buffer memory" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 256 + help + The size of tx ring buffer memory + + config BT_LE_HCI_TRANS_TASK_STACK_SIZE + int "HCI transport task stack size" + depends on !BT_LE_HCI_INTERFACE_USE_RAM + default 1024 help - Set the size of uart task stack + This configures stack size of hci transport task endmenu config BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT diff --git a/components/bt/controller/esp32c5/bt.c b/components/bt/controller/esp32c5/bt.c index 17794564355..3d558b357d1 100644 --- a/components/bt/controller/esp32c5/bt.c +++ b/components/bt/controller/esp32c5/bt.c @@ -30,7 +30,7 @@ #endif // CONFIG_SW_COEXIST_ENABLE #include "nimble/nimble_npl_os.h" -#include "ble_hci_trans.h" +#include "esp_hci_transport.h" #include "os/endian.h" #include "esp_bt.h" @@ -39,7 +39,6 @@ #include "esp_pm.h" #include "esp_phy_init.h" #include "esp_private/periph_ctrl.h" -#include "hci_uart.h" #include "bt_osi_mem.h" #if SOC_PM_RETENTION_HAS_CLOCK_BUG @@ -50,10 +49,6 @@ #include "esp_private/sleep_modem.h" #endif // CONFIG_FREERTOS_USE_TICKLESS_IDLE -#ifdef CONFIG_BT_BLUEDROID_ENABLED -#include "hci/hci_hal.h" -#endif // CONFIG_BT_BLUEDROID_ENABLED - #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -69,16 +64,11 @@ #define OSI_COEX_VERSION 0x00010006 #define OSI_COEX_MAGIC_VALUE 0xFADEBEAD -#define EXT_FUNC_VERSION 0x20221122 +#define EXT_FUNC_VERSION 0x20240422 #define EXT_FUNC_MAGIC_VALUE 0xA5A5A5A5 #define BT_ASSERT_PRINT ets_printf -#ifdef CONFIG_BT_BLUEDROID_ENABLED -/* ACL_DATA_MBUF_LEADINGSPCAE: The leadingspace in user info header for ACL data */ -#define ACL_DATA_MBUF_LEADINGSPCAE 4 -#endif // CONFIG_BT_BLUEDROID_ENABLED - /* Types definition ************************************************************************ */ @@ -97,12 +87,6 @@ struct ext_funcs_t { int (*_esp_intr_free)(void **ret_handle); void *(* _malloc)(size_t size); void (*_free)(void *p); - void (*_hal_uart_start_tx)(int); - int (*_hal_uart_init_cbs)(int, hci_uart_tx_char, hci_uart_tx_done, hci_uart_rx_char, void *); - int (*_hal_uart_config)(int, int32_t, uint8_t, uint8_t, uart_parity_t, uart_hw_flowcontrol_t); - int (*_hal_uart_close)(int); - void (*_hal_uart_blocking_tx)(int, uint8_t); - int (*_hal_uart_init)(int, void *); int (* _task_create)(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); void (* _task_delete)(void *task_handle); @@ -179,16 +163,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status); static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id); static void task_delete_wrapper(void *task_handle); -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no); -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg); -static int hci_uart_config_wrapper(int uart_no, int32_t speed, uint8_t databits, uint8_t stopbits, - uart_parity_t parity, uart_hw_flowcontrol_t flow_ctl); -static int hci_uart_close_wrapper(int uart_no); -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data); -static int hci_uart_init_wrapper(int uart_no, void *cfg); -#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in); static int esp_intr_free_wrapper(void **ret_handle); @@ -206,7 +180,6 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b */ /* Static variable declare */ static DRAM_ATTR esp_bt_controller_status_t ble_controller_status = ESP_BT_CONTROLLER_STATUS_IDLE; - #if CONFIG_BT_LE_CONTROLLER_LOG_ENABLED const static uint32_t log_bufs_size[] = {CONFIG_BT_LE_LOG_CTRL_BUF1_SIZE, CONFIG_BT_LE_LOG_HCI_BUF_SIZE, CONFIG_BT_LE_LOG_CTRL_BUF2_SIZE}; #endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED @@ -236,14 +209,6 @@ struct ext_funcs_t ext_funcs_ro = { ._esp_intr_free = esp_intr_free_wrapper, ._malloc = bt_osi_mem_malloc_internal, ._free = bt_osi_mem_free, -#if CONFIG_BT_LE_HCI_INTERFACE_USE_UART - ._hal_uart_start_tx = hci_uart_start_tx_wrapper, - ._hal_uart_init_cbs = hci_uart_init_cbs_wrapper, - ._hal_uart_config = hci_uart_config_wrapper, - ._hal_uart_close = hci_uart_close_wrapper, - ._hal_uart_blocking_tx = hci_uart_blocking_tx_wrapper, - ._hal_uart_init = hci_uart_init_wrapper, -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART ._task_create = task_create_wrapper, ._task_delete = task_delete_wrapper, ._osi_assert = osi_assert_wrapper, @@ -288,75 +253,6 @@ static void coex_schm_status_bit_clear_wrapper(uint32_t type, uint32_t status) #endif // CONFIG_SW_COEXIST_ENABLE } -#ifdef CONFIG_BT_BLUEDROID_ENABLED -bool esp_vhci_host_check_send_available(void) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return false; - } - return true; -} - -static struct os_mbuf *ble_hs_mbuf_gen_pkt(uint16_t leading_space) -{ - struct os_mbuf *om; - int rc; - - om = os_msys_get_pkthdr(0, 0); - if (om == NULL) { - return NULL; - } - - if (om->om_omp->omp_databuf_len < leading_space) { - rc = os_mbuf_free_chain(om); - assert(rc == 0); - return NULL; - } - - om->om_data += leading_space; - - return om; -} - -struct os_mbuf *ble_hs_mbuf_acl_pkt(void) -{ - return ble_hs_mbuf_gen_pkt(4 + 1); -} - -void esp_vhci_host_send_packet(uint8_t *data, uint16_t len) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return; - } - - if (*(data) == DATA_TYPE_COMMAND) { - struct ble_hci_cmd *cmd = NULL; - cmd = (struct ble_hci_cmd *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - assert(cmd); - memcpy((uint8_t *)cmd, data + 1, len - 1); - ble_hci_trans_hs_cmd_tx((uint8_t *)cmd); - } - - if (*(data) == DATA_TYPE_ACL) { - struct os_mbuf *om = os_msys_get_pkthdr(len, ACL_DATA_MBUF_LEADINGSPCAE); - assert(om); - assert(os_mbuf_append(om, &data[1], len - 1) == 0); - ble_hci_trans_hs_acl_tx(om); - } -} - -esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback) -{ - if (ble_controller_status != ESP_BT_CONTROLLER_STATUS_ENABLED) { - return ESP_FAIL; - } - - ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); - - return ESP_OK; -} -#endif // CONFIG_BT_BLUEDROID_ENABLED - static int task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id) { @@ -388,56 +284,6 @@ static int esp_ecc_gen_dh_key(const uint8_t *peer_pub_key_x, const uint8_t *peer return rc; } -#ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART -static void hci_uart_start_tx_wrapper(int uart_no) -{ - hci_uart_start_tx(uart_no); -} - -static int hci_uart_init_cbs_wrapper(int uart_no, hci_uart_tx_char tx_func, - hci_uart_tx_done tx_done, hci_uart_rx_char rx_func, void *arg) -{ - int rc = -1; - rc = hci_uart_init_cbs(uart_no, tx_func, tx_done, rx_func, arg); - return rc; -} - - -static int hci_uart_config_wrapper(int port_num, int32_t baud_rate, uint8_t data_bits, - uint8_t stop_bits, uart_parity_t parity, - uart_hw_flowcontrol_t flow_ctl) -{ - int rc = -1; - rc = hci_uart_config(port_num, baud_rate, data_bits, stop_bits, parity, flow_ctl); - return rc; -} - -static int hci_uart_close_wrapper(int uart_no) -{ - int rc = -1; - rc = hci_uart_close(uart_no); - return rc; -} - -static void hci_uart_blocking_tx_wrapper(int port, uint8_t data) -{ - //This function is nowhere to use. -} - -static int hci_uart_init_wrapper(int uart_no, void *cfg) -{ - //This function is nowhere to use. - return 0; -} - -#endif //CONFIG_BT_LE_HCI_INTERFACE_USE_UART - -static int ble_hci_unregistered_hook(void*, void*) -{ - ESP_LOGD(NIMBLE_PORT_LOG_TAG,"%s ble hci rx_evt is not registered.",__func__); - return 0; -} - static int esp_intr_alloc_wrapper(int source, int flags, intr_handler_t handler, void *arg, void **ret_handle_in) { @@ -694,6 +540,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) esp_err_t ret = ESP_OK; ble_npl_count_info_t npl_info; uint32_t slow_clk_freq = 0; + uint8_t hci_transport_mode; memset(&npl_info, 0, sizeof(ble_npl_count_info_t)); @@ -838,11 +685,20 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg) ble_controller_status = ESP_BT_CONTROLLER_STATUS_INITED; - ble_hci_trans_cfg_hs((ble_hci_trans_rx_cmd_fn *)ble_hci_unregistered_hook,NULL, - (ble_hci_trans_rx_acl_fn *)ble_hci_unregistered_hook,NULL); - return ESP_OK; +#if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + hci_transport_mode = HCI_TRANSPORT_VHCI; +#elif CONFIG_BT_LE_HCI_INTERFACE_USE_UART + hci_transport_mode = HCI_TRANSPORT_UART_NO_DMA; +#endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM + ret = hci_transport_init(hci_transport_mode); + if (ret) { + ESP_LOGW(NIMBLE_PORT_LOG_TAG, "hci transport init failed %d", ret); + goto free_controller; + } + return ESP_OK; free_controller: + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); r_ble_controller_deinit(); @@ -873,6 +729,7 @@ esp_err_t esp_bt_controller_deinit(void) return ESP_FAIL; } + hci_transport_deinit(); controller_sleep_deinit(); os_msys_deinit(); diff --git a/components/bt/controller/esp32c5/esp_bt_cfg.h b/components/bt/controller/esp32c5/esp_bt_cfg.h index b9597034fc6..b8bbfd3d4b7 100644 --- a/components/bt/controller/esp32c5/esp_bt_cfg.h +++ b/components/bt/controller/esp32c5/esp_bt_cfg.h @@ -129,6 +129,21 @@ extern "C" { #else #define DEFAULT_BT_LE_50_FEATURE_SUPPORT (0) #endif + + #if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN) + #else + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif + #else + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF @@ -169,8 +184,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #else #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) @@ -179,8 +192,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #endif /* Unchanged configuration */ diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index 2e05c001042..77c67a4d06c 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit 2e05c001042650bca426b672febd23c9ff45754e +Subproject commit 77c67a4d06c95113a2d1766892cde59f5af744af diff --git a/components/bt/include/esp32c5/include/esp_bt.h b/components/bt/include/esp32c5/include/esp_bt.h index 1a7cd646851..37a70c2a40f 100644 --- a/components/bt/include/esp32c5/include/esp_bt.h +++ b/components/bt/include/esp32c5/include/esp_bt.h @@ -155,7 +155,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20231124 +#define CONFIG_VERSION 0x20240422 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -196,13 +196,6 @@ typedef struct { uint8_t controller_run_cpu; /*!< CPU core on which the controller runs */ uint8_t enable_qa_test; /*!< Enable quality assurance (QA) testing */ uint8_t enable_bqb_test; /*!< Enable Bluetooth Qualification Test (BQB) testing */ - uint8_t enable_uart_hci; /*!< Enable UART HCI (Host Controller Interface) */ - uint8_t ble_hci_uart_port; /*!< UART port number for Bluetooth HCI */ - uint32_t ble_hci_uart_baud; /*!< Baud rate for Bluetooth HCI UART */ - uint8_t ble_hci_uart_data_bits; /*!< Number of data bits for Bluetooth HCI UART */ - uint8_t ble_hci_uart_stop_bits; /*!< Number of stop bits for Bluetooth HCI UART */ - uint8_t ble_hci_uart_flow_ctrl; /*!< Flow control settings for Bluetooth HCI UART */ - uint8_t ble_hci_uart_uart_parity; /*!< Parity settings for Bluetooth HCI UART */ uint8_t enable_tx_cca; /*!< Enable Transmit Clear Channel Assessment (TX CCA) */ uint8_t cca_rssi_thresh; /*!< RSSI threshold for Transmit Clear Channel Assessment (CCA) */ uint8_t sleep_en; /*!< Enable sleep mode */ @@ -252,13 +245,6 @@ typedef struct { .controller_run_cpu = 0, \ .enable_qa_test = RUN_QA_TEST, \ .enable_bqb_test = RUN_BQB_TEST, \ - .enable_uart_hci = HCI_UART_EN, \ - .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT, \ - .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD, \ - .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS, \ - .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS, \ - .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL, \ - .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY, \ .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED, \ .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH, \ .sleep_en = NIMBLE_SLEEP_ENABLE, \ From 09f46446293d7babd2857374644fd6e0fa8d9666 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:18:15 +0800 Subject: [PATCH 387/548] feat(bluetooth/controller): add default cts and rts macro definition --- .../bt/include/esp32h4/include/esp_bt_cfg.h | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/components/bt/include/esp32h4/include/esp_bt_cfg.h b/components/bt/include/esp32h4/include/esp_bt_cfg.h index 768a0c6ccec..1f8caaeca8b 100644 --- a/components/bt/include/esp32h4/include/esp_bt_cfg.h +++ b/components/bt/include/esp32h4/include/esp_bt_cfg.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -116,6 +116,20 @@ extern "C" { #define DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT (8) #endif + #if defined (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (CONFIG_BT_LE_HCI_UART_FLOWCTRL) + #if DEFAULT_BT_LE_HCI_UART_FLOW_CTRL + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (CONFIG_BT_LE_HCI_UART_CTS_PIN) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (CONFIG_BT_LE_HCI_UART_RTS_PIN) + #else + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif + #else + #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) + #define DEFAULT_BT_LE_HCI_UART_CTS_PIN (-1) + #define DEFAULT_BT_LE_HCI_UART_RTS_PIN (-1) + #endif #endif #define DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF CONFIG_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF @@ -156,8 +170,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (UART_DATA_8_BITS) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (UART_STOP_BITS_1) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (CONFIG_BT_LE_HCI_UART_TASK_STACK_SIZE) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #else #define DEFAULT_BT_LE_HCI_UART_TX_PIN (0) #define DEFAULT_BT_LE_HCI_UART_RX_PIN (0) @@ -166,8 +178,6 @@ extern "C" { #define DEFAULT_BT_LE_HCI_UART_DATA_BITS (0) #define DEFAULT_BT_LE_HCI_UART_STOP_BITS (0) #define DEFAULT_BT_LE_HCI_UART_PARITY (0) - #define DEFAULT_BT_LE_HCI_UART_TASK_STACK_SIZE (0) - #define DEFAULT_BT_LE_HCI_UART_FLOW_CTRL (0) #endif /* Unchanged configuration */ From 52c9d724bc592ebd29b2e6b95cdd6d5e4a00c3b9 Mon Sep 17 00:00:00 2001 From: zwl Date: Thu, 4 Jul 2024 21:16:59 +0800 Subject: [PATCH 388/548] feat(bluetooth/controller): update nimble host to adapt hci layer --- components/bt/host/nimble/nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index 73112f9b406..ec9f21253ae 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit 73112f9b4068ef7dc541c88c555ff829bebb9f8f +Subproject commit ec9f21253ae539b44855fed223bee52979a9d251 From 5a545d68857d2d29bbea325c068878a605aedc19 Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 9 Jul 2024 20:42:11 +0800 Subject: [PATCH 389/548] fix(ble): fixed nimble host only build error --- .../bluetooth/nimble/bleprph_host_only/main/uart_driver.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c b/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c index 07e82387f51..cd3916724a6 100644 --- a/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c +++ b/examples/bluetooth/nimble/bleprph_host_only/main/uart_driver.c @@ -170,6 +170,13 @@ void hci_uart_send(uint8_t *buf, uint16_t len) } } + +void +ble_transport_ll_init(void) +{ + +} + int ble_transport_to_ll_acl_impl(struct os_mbuf *om) { From d5df6dd78b6f5d70be0a0f754a563f73ee372ef8 Mon Sep 17 00:00:00 2001 From: zwl Date: Tue, 16 Jul 2024 10:16:15 +0800 Subject: [PATCH 390/548] fix(bluetooth/controller): fixed alloc memory fail when use uhci on ESP32-C6 and ESP32-H2 --- .../transport/driver/uart/hci_driver_uart_dma.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c index a90fb749a11..3111a7cea3c 100644 --- a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -423,6 +423,10 @@ int hci_driver_uart_dma_tx_start(esp_bt_hci_tl_callback_t callback, void *arg) uart_env.tx.link_head = lldesc_head; uart_env.tx.callback = callback; uart_env.tx.arg = arg; + /* The DMA interrupt may have been triggered before setting the tx_state, + * So we set it first. + */ + hci_driver_uart_dma_txstate_set(HCI_TRANS_TX_START); gdma_start(s_tx_channel, (intptr_t)(uart_env.tx.link_head)); return 0; } else { @@ -513,6 +517,11 @@ hci_driver_uart_dma_process_task(void *p) while (true) { xSemaphoreTake(s_hci_driver_uart_dma_env.process_sem, portMAX_DELAY); ESP_LOGD(TAG, "task run:%d\n",s_hci_driver_uart_dma_env.hci_tx_state); + /* Process Tx data */ + if (s_hci_driver_uart_dma_env.hci_tx_state == HCI_TRANS_TX_IDLE) { + hci_driver_uart_dma_tx_start(hci_driver_uart_dma_send_callback, (void*)&uart_env); + } + if (s_hci_driver_uart_dma_env.rxinfo_mem_exhausted) { rx_data = (void *)uart_env.rx.link_head->buf; rx_len = uart_env.rx.link_head->length; @@ -553,14 +562,6 @@ hci_driver_uart_dma_process_task(void *p) os_memblock_put(s_hci_driver_uart_dma_env.hci_rx_data_pool, rx_data); } } - - /* Process Tx data */ - if (s_hci_driver_uart_dma_env.hci_tx_state == HCI_TRANS_TX_IDLE) { - ret = hci_driver_uart_dma_tx_start(hci_driver_uart_dma_send_callback, (void*)&uart_env); - if (!ret) { - s_hci_driver_uart_dma_env.hci_tx_state = HCI_TRANS_TX_START; - } - } } } From a2df884e6451df3ac3444283d1de85bf5be0a53c Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 17 Jul 2024 17:23:28 +0800 Subject: [PATCH 391/548] feat(bluetooth/controller): support default tx power configurable on ESP32C6 and ESP32H2 --- components/bt/controller/esp32c6/Kconfig.in | 50 ++++++++++++++++ components/bt/controller/esp32c6/esp_bt_cfg.h | 2 +- components/bt/controller/esp32h2/Kconfig.in | 59 +++++++++++++++++++ components/bt/controller/esp32h2/esp_bt_cfg.h | 3 +- 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 665e34366a1..9de74d8f05f 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -621,3 +621,53 @@ config BT_LE_CCA_RSSI_THRESH default 20 help Power threshold of CCA in unit of -1 dBm. + +choice BT_LE_DFT_TX_POWER_LEVEL_DBM + prompt "BLE default Tx power level(dBm)" + default BT_LE_DFT_TX_POWER_LEVEL_P9 + help + Specify default Tx power level(dBm). + config BT_LE_DFT_TX_POWER_LEVEL_N15 + bool "-15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N12 + bool "-12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N9 + bool "-9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N6 + bool "-6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N3 + bool "-3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N0 + bool "0dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P3 + bool "+3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P6 + bool "+6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P9 + bool "+9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P12 + bool "+12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P15 + bool "+15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P18 + bool "+18dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P20 + bool "+20dBm" +endchoice + +config BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF + int + default -15 if BT_LE_DFT_TX_POWER_LEVEL_N15 + default -12 if BT_LE_DFT_TX_POWER_LEVEL_N12 + default -9 if BT_LE_DFT_TX_POWER_LEVEL_N9 + default -6 if BT_LE_DFT_TX_POWER_LEVEL_N6 + default -3 if BT_LE_DFT_TX_POWER_LEVEL_N3 + default 0 if BT_LE_DFT_TX_POWER_LEVEL_N0 + default 3 if BT_LE_DFT_TX_POWER_LEVEL_P3 + default 6 if BT_LE_DFT_TX_POWER_LEVEL_P6 + default 9 if BT_LE_DFT_TX_POWER_LEVEL_P9 + default 12 if BT_LE_DFT_TX_POWER_LEVEL_P12 + default 15 if BT_LE_DFT_TX_POWER_LEVEL_P15 + default 18 if BT_LE_DFT_TX_POWER_LEVEL_P18 + default 20 if BT_LE_DFT_TX_POWER_LEVEL_P20 + default 0 diff --git a/components/bt/controller/esp32c6/esp_bt_cfg.h b/components/bt/controller/esp32c6/esp_bt_cfg.h index b8bbfd3d4b7..4e24c186140 100644 --- a/components/bt/controller/esp32c6/esp_bt_cfg.h +++ b/components/bt/controller/esp32c6/esp_bt_cfg.h @@ -216,7 +216,7 @@ extern "C" { #define RTC_FREQ_N (32768) /* in Hz */ -#define BLE_LL_TX_PWR_DBM_N (9) +#define BLE_LL_TX_PWR_DBM_N (CONFIG_BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF) #define RUN_BQB_TEST (0) diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index e45aa2030ae..f68a615b7c2 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -613,3 +613,62 @@ config BT_LE_CCA_RSSI_THRESH default 20 help Power threshold of CCA in unit of -1 dBm. + +choice BT_LE_DFT_TX_POWER_LEVEL_DBM + prompt "BLE default Tx power level(dBm)" + default BT_LE_DFT_TX_POWER_LEVEL_P9 + help + Specify default Tx power level(dBm). + config BT_LE_DFT_TX_POWER_LEVEL_N24 + bool "-24dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N21 + bool "-21dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N18 + bool "-18dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N15 + bool "-15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N12 + bool "-12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N9 + bool "-9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N6 + bool "-6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N3 + bool "-3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N0 + bool "0dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P3 + bool "+3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P6 + bool "+6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P9 + bool "+9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P12 + bool "+12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P15 + bool "+15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P18 + bool "+18dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P20 + bool "+20dBm" +endchoice + +config BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF + int + default -24 if BT_LE_DFT_TX_POWER_LEVEL_N24 + default -21 if BT_LE_DFT_TX_POWER_LEVEL_N21 + default -18 if BT_LE_DFT_TX_POWER_LEVEL_N18 + default -15 if BT_LE_DFT_TX_POWER_LEVEL_N15 + default -12 if BT_LE_DFT_TX_POWER_LEVEL_N12 + default -9 if BT_LE_DFT_TX_POWER_LEVEL_N9 + default -6 if BT_LE_DFT_TX_POWER_LEVEL_N6 + default -3 if BT_LE_DFT_TX_POWER_LEVEL_N3 + default 0 if BT_LE_DFT_TX_POWER_LEVEL_N0 + default 3 if BT_LE_DFT_TX_POWER_LEVEL_P3 + default 6 if BT_LE_DFT_TX_POWER_LEVEL_P6 + default 9 if BT_LE_DFT_TX_POWER_LEVEL_P9 + default 12 if BT_LE_DFT_TX_POWER_LEVEL_P12 + default 15 if BT_LE_DFT_TX_POWER_LEVEL_P15 + default 18 if BT_LE_DFT_TX_POWER_LEVEL_P18 + default 20 if BT_LE_DFT_TX_POWER_LEVEL_P20 + default 0 diff --git a/components/bt/controller/esp32h2/esp_bt_cfg.h b/components/bt/controller/esp32h2/esp_bt_cfg.h index b8bbfd3d4b7..22a09be3adc 100644 --- a/components/bt/controller/esp32h2/esp_bt_cfg.h +++ b/components/bt/controller/esp32h2/esp_bt_cfg.h @@ -216,8 +216,7 @@ extern "C" { #define RTC_FREQ_N (32768) /* in Hz */ -#define BLE_LL_TX_PWR_DBM_N (9) - +#define BLE_LL_TX_PWR_DBM_N (CONFIG_BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF) #define RUN_BQB_TEST (0) #define RUN_QA_TEST (0) From e497c29efee05e741e55c5e7ccf0dff15530bfa0 Mon Sep 17 00:00:00 2001 From: zwl Date: Wed, 17 Jul 2024 17:27:42 +0800 Subject: [PATCH 392/548] feat(bluetooth/controller): support default tx power configurable on ESP32C2 --- components/bt/controller/esp32c2/Kconfig.in | 59 +++++++++++++++++++ components/bt/controller/esp32c2/esp_bt_cfg.h | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c2/Kconfig.in b/components/bt/controller/esp32c2/Kconfig.in index 8699b6b56c5..75355ed098e 100644 --- a/components/bt/controller/esp32c2/Kconfig.in +++ b/components/bt/controller/esp32c2/Kconfig.in @@ -540,3 +540,62 @@ config BT_LE_ROLE_OBSERVER_ENABLE default y help Enable observer role function. + +choice BT_LE_DFT_TX_POWER_LEVEL_DBM + prompt "BLE default Tx power level(dBm)" + default BT_LE_DFT_TX_POWER_LEVEL_P9 + help + Specify default Tx power level(dBm). + config BT_LE_DFT_TX_POWER_LEVEL_N24 + bool "-24dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N21 + bool "-21dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N18 + bool "-18dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N15 + bool "-15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N12 + bool "-12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N9 + bool "-9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N6 + bool "-6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N3 + bool "-3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_N0 + bool "0dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P3 + bool "+3dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P6 + bool "+6dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P9 + bool "+9dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P12 + bool "+12dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P15 + bool "+15dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P18 + bool "+18dBm" + config BT_LE_DFT_TX_POWER_LEVEL_P20 + bool "+20dBm" +endchoice + +config BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF + int + default -24 if BT_LE_DFT_TX_POWER_LEVEL_N24 + default -21 if BT_LE_DFT_TX_POWER_LEVEL_N21 + default -18 if BT_LE_DFT_TX_POWER_LEVEL_N18 + default -15 if BT_LE_DFT_TX_POWER_LEVEL_N15 + default -12 if BT_LE_DFT_TX_POWER_LEVEL_N12 + default -9 if BT_LE_DFT_TX_POWER_LEVEL_N9 + default -6 if BT_LE_DFT_TX_POWER_LEVEL_N6 + default -3 if BT_LE_DFT_TX_POWER_LEVEL_N3 + default 0 if BT_LE_DFT_TX_POWER_LEVEL_N0 + default 3 if BT_LE_DFT_TX_POWER_LEVEL_P3 + default 6 if BT_LE_DFT_TX_POWER_LEVEL_P6 + default 9 if BT_LE_DFT_TX_POWER_LEVEL_P9 + default 12 if BT_LE_DFT_TX_POWER_LEVEL_P12 + default 15 if BT_LE_DFT_TX_POWER_LEVEL_P15 + default 18 if BT_LE_DFT_TX_POWER_LEVEL_P18 + default 20 if BT_LE_DFT_TX_POWER_LEVEL_P20 + default 0 diff --git a/components/bt/controller/esp32c2/esp_bt_cfg.h b/components/bt/controller/esp32c2/esp_bt_cfg.h index ff0db7c8919..456ddcf9a85 100644 --- a/components/bt/controller/esp32c2/esp_bt_cfg.h +++ b/components/bt/controller/esp32c2/esp_bt_cfg.h @@ -241,7 +241,7 @@ extern "C" { #define RTC_FREQ_N (32000) /* in Hz */ #endif // CONFIG_XTAL_FREQ_26 -#define BLE_LL_TX_PWR_DBM_N (9) +#define BLE_LL_TX_PWR_DBM_N (CONFIG_BT_LE_DFT_TX_POWER_LEVEL_DBM_EFF) #define RUN_BQB_TEST (0) From 5c39705bacde6954d5b82d737617b06bb4e523db Mon Sep 17 00:00:00 2001 From: luoxu Date: Thu, 18 Jul 2024 10:30:11 +0800 Subject: [PATCH 393/548] fix(ble_mesh): fixed BLEMESH24-76 --- components/bt/esp_ble_mesh/core/net.c | 35 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 2f9889669be..d5b768c7d22 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1129,23 +1129,34 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, if (((IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) || (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en())) && (bt_mesh_fixed_group_match(tx->ctx->addr) || bt_mesh_elem_find(tx->ctx->addr))) { - if (cb && cb->start) { - cb->start(0, 0, cb_data); - } + /** + * If the target address isn't a unicast address, then the callback function + * will be called by `adv task` in place of here, to avoid the callback function + * being called twice. + * See BLEMESH24-76 for more details. + */ + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { + if (cb && cb->start) { + cb->start(0, 0, cb_data); + } - net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); - if (cb && cb->end) { - cb->end(0, cb_data); - } + if (cb && cb->end) { + cb->end(0, cb_data); + } - bt_mesh_net_local(); + bt_mesh_net_local(); + + err = 0; - err = 0; - /* If it is a group address, it still needs to be relayed */ - if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { goto done; + } else { + net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + bt_mesh_net_local(); } + + err = 0; } if ((bearer & BLE_MESH_ADV_BEARER) && From 3a1cc2be50f346e67efbc0dec31bd9d80a998931 Mon Sep 17 00:00:00 2001 From: Sarvesh Bodakhe Date: Wed, 17 Jul 2024 17:33:58 +0530 Subject: [PATCH 394/548] fix(wifi): Free scan configuration after use when channel bitmap is used --- examples/wifi/scan/main/scan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/wifi/scan/main/scan.c b/examples/wifi/scan/main/scan.c index 2876fb95a50..243b4a7a98f 100644 --- a/examples/wifi/scan/main/scan.c +++ b/examples/wifi/scan/main/scan.c @@ -179,6 +179,7 @@ static void wifi_scan(void) } array_2_channel_bitmap(channel_list, CHANNEL_LIST_SIZE, scan_config); esp_wifi_scan_start(scan_config, true); + free(scan_config); #else esp_wifi_scan_start(NULL, true); From 25f78b3715f639349a55957ca17951c1e1dd312f Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 20 Jun 2024 23:46:21 +0800 Subject: [PATCH 395/548] fix(rmt): power up memory block --- components/driver/deprecated/driver/rmt.h | 8 ++-- components/driver/deprecated/rmt_legacy.c | 10 ++++- components/hal/esp32/include/hal/rmt_ll.h | 33 ++++++++++++---- components/hal/esp32c3/include/hal/rmt_ll.h | 42 ++++++++++++++------ components/hal/esp32c5/include/hal/rmt_ll.h | 44 +++++++++++++++------ components/hal/esp32c6/include/hal/rmt_ll.h | 42 ++++++++++++++------ components/hal/esp32h2/include/hal/rmt_ll.h | 42 ++++++++++++++------ components/hal/esp32p4/include/hal/rmt_ll.h | 44 +++++++++++++++------ components/hal/esp32s2/include/hal/rmt_ll.h | 42 ++++++++++++++------ components/hal/esp32s3/include/hal/rmt_ll.h | 44 +++++++++++++++------ components/hal/rmt_hal.c | 8 ++-- 11 files changed, 255 insertions(+), 104 deletions(-) diff --git a/components/driver/deprecated/driver/rmt.h b/components/driver/deprecated/driver/rmt.h index c99bde31bed..e162b147aa8 100644 --- a/components/driver/deprecated/driver/rmt.h +++ b/components/driver/deprecated/driver/rmt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -152,10 +152,10 @@ esp_err_t rmt_set_tx_carrier(rmt_channel_t channel, bool carrier_en, uint16_t hi esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en); /** -* @brief Get RMT memory low power mode. +* @brief Check if the RMT memory is force powered down * -* @param channel RMT channel -* @param pd_en Pointer to accept RMT memory low power mode. +* @param channel RMT channel (actually this function is configured for all channels) +* @param pd_en Pointer to accept the result * * @return * - ESP_ERR_INVALID_ARG Parameter error diff --git a/components/driver/deprecated/rmt_legacy.c b/components/driver/deprecated/rmt_legacy.c index 16d120725b4..4269c8fa56d 100644 --- a/components/driver/deprecated/rmt_legacy.c +++ b/components/driver/deprecated/rmt_legacy.c @@ -142,6 +142,7 @@ static void rmt_module_enable(void) rmt_ll_enable_bus_clock(0, true); rmt_ll_reset_register(0); } + rmt_ll_mem_power_by_pmu(rmt_contex.hal.regs); rmt_contex.rmt_module_enabled = true; } RMT_EXIT_CRITICAL(); @@ -152,6 +153,7 @@ static void rmt_module_disable(void) { RMT_ENTER_CRITICAL(); if (rmt_contex.rmt_module_enabled == true) { + rmt_ll_mem_force_power_off(rmt_contex.hal.regs); RMT_RCC_ATOMIC() { rmt_ll_enable_bus_clock(0, false); } @@ -251,7 +253,11 @@ esp_err_t rmt_set_mem_pd(rmt_channel_t channel, bool pd_en) { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - rmt_ll_power_down_mem(rmt_contex.hal.regs, pd_en); + if (pd_en) { + rmt_ll_mem_force_power_off(rmt_contex.hal.regs); + } else { + rmt_ll_mem_power_by_pmu(rmt_contex.hal.regs); + } RMT_EXIT_CRITICAL(); return ESP_OK; } @@ -260,7 +266,7 @@ esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool *pd_en) { ESP_RETURN_ON_FALSE(channel < RMT_CHANNEL_MAX, ESP_ERR_INVALID_ARG, TAG, RMT_CHANNEL_ERROR_STR); RMT_ENTER_CRITICAL(); - *pd_en = rmt_ll_is_mem_powered_down(rmt_contex.hal.regs); + *pd_en = rmt_ll_is_mem_force_powered_down(rmt_contex.hal.regs); RMT_EXIT_CRITICAL(); return ESP_OK; } diff --git a/components/hal/esp32/include/hal/rmt_ll.h b/components/hal/esp32/include/hal/rmt_ll.h index 97a9267fcdd..147c6c089db 100644 --- a/components/hal/esp32/include/hal/rmt_ll.h +++ b/components/hal/esp32/include/hal/rmt_ll.h @@ -88,14 +88,33 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->conf_ch[0].conf0.mem_pd = enable; // Only conf0 register of channel0 has `mem_pd` + (void)dev; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->conf_ch[0].conf0.mem_pd = 1; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->conf_ch[0].conf0.mem_pd = 0; } /** @@ -120,7 +139,7 @@ static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) * @param divider_numerator Numerator part of the divider */ static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, - uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { (void)divider_integral; (void)divider_denominator; @@ -485,7 +504,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -631,7 +650,7 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->conf_ch[channel].conf1.idle_out_lv; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { // Only conf0 register of channel0 has `mem_pd` return dev->conf_ch[0].conf0.mem_pd; diff --git a/components/hal/esp32c3/include/hal/rmt_ll.h b/components/hal/esp32c3/include/hal/rmt_ll.h index b1d8acdc75d..c76924fedf2 100644 --- a/components/hal/esp32c3/include/hal/rmt_ll.h +++ b/components/hal/esp32c3/include/hal/rmt_ll.h @@ -87,15 +87,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -427,7 +448,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -658,7 +679,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -812,12 +833,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->tx_conf[channel].idle_out_lv; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32c5/include/hal/rmt_ll.h b/components/hal/esp32c5/include/hal/rmt_ll.h index f62639604ca..990f6e56bc1 100644 --- a/components/hal/esp32c5/include/hal/rmt_ll.h +++ b/components/hal/esp32c5/include/hal/rmt_ll.h @@ -82,15 +82,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -115,7 +136,7 @@ static inline void rmt_ll_enable_mem_access_nonfifo(rmt_dev_t *dev, bool enable) * @param divider_numerator Numerator part of the divider */ static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, - uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) (void)channel; // the source clock is set for all channels @@ -436,7 +457,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -667,7 +688,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -821,12 +842,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->chnconf0[channel].idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32c6/include/hal/rmt_ll.h b/components/hal/esp32c6/include/hal/rmt_ll.h index f2da58d4151..8d1d4afbb7f 100644 --- a/components/hal/esp32c6/include/hal/rmt_ll.h +++ b/components/hal/esp32c6/include/hal/rmt_ll.h @@ -79,15 +79,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -433,7 +454,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -664,7 +685,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -818,12 +839,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->chnconf0[channel].idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32h2/include/hal/rmt_ll.h b/components/hal/esp32h2/include/hal/rmt_ll.h index 707c57ef3ae..c299ed114ef 100644 --- a/components/hal/esp32h2/include/hal/rmt_ll.h +++ b/components/hal/esp32h2/include/hal/rmt_ll.h @@ -79,15 +79,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -430,7 +451,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -661,7 +682,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -812,12 +833,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->chnconf0[channel].idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32p4/include/hal/rmt_ll.h b/components/hal/esp32p4/include/hal/rmt_ll.h index 136dda044ef..105aa426925 100644 --- a/components/hal/esp32p4/include/hal/rmt_ll.h +++ b/components/hal/esp32p4/include/hal/rmt_ll.h @@ -85,7 +85,7 @@ static inline void rmt_ll_reset_register(int group_id) * @param divider_numerator Numerator part of the divider */ static inline void rmt_ll_set_group_clock_src(rmt_dev_t *dev, uint32_t channel, rmt_clock_source_t src, - uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) + uint32_t divider_integral, uint32_t divider_denominator, uint32_t divider_numerator) { (void)dev; // Formula: rmt_sclk = module_clock_src / (1 + div_num + div_a / div_b) @@ -143,15 +143,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -463,7 +484,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -706,7 +727,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -860,12 +881,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->chnconf0[channel].idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32s2/include/hal/rmt_ll.h b/components/hal/esp32s2/include/hal/rmt_ll.h index 00730fec0c2..98eb39dfe05 100644 --- a/components/hal/esp32s2/include/hal/rmt_ll.h +++ b/components/hal/esp32s2/include/hal/rmt_ll.h @@ -90,15 +90,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->apb_conf.mem_force_pu = !enable; - dev->apb_conf.mem_force_pd = enable; + dev->apb_conf.mem_force_pu = 1; + dev->apb_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->apb_conf.mem_force_pd = 1; + dev->apb_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->apb_conf.mem_force_pd = 0; + dev->apb_conf.mem_force_pu = 0; } /** @@ -423,7 +444,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -628,7 +649,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -774,12 +795,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->conf_ch[channel].conf1.idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->apb_conf.mem_force_pd) || !(dev->apb_conf.mem_force_pu); + return dev->apb_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/esp32s3/include/hal/rmt_ll.h b/components/hal/esp32s3/include/hal/rmt_ll.h index 7d5dcf5eecf..e999add0260 100644 --- a/components/hal/esp32s3/include/hal/rmt_ll.h +++ b/components/hal/esp32s3/include/hal/rmt_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,15 +87,36 @@ static inline void rmt_ll_enable_periph_clock(rmt_dev_t *dev, bool enable) } /** - * @brief Power down memory + * @brief Force power on the RMT memory block, regardless of the outside PMU logic * * @param dev Peripheral instance address - * @param enable True to power down, False to power up */ -static inline void rmt_ll_power_down_mem(rmt_dev_t *dev, bool enable) +static inline void rmt_ll_mem_force_power_on(rmt_dev_t *dev) { - dev->sys_conf.mem_force_pu = !enable; - dev->sys_conf.mem_force_pd = enable; + dev->sys_conf.mem_force_pu = 1; + dev->sys_conf.mem_force_pd = 0; +} + +/** + * @brief Force power off the RMT memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_force_power_off(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 1; + dev->sys_conf.mem_force_pu = 0; +} + +/** + * @brief Power control the RMT memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void rmt_ll_mem_power_by_pmu(rmt_dev_t *dev) +{ + dev->sys_conf.mem_force_pd = 0; + dev->sys_conf.mem_force_pu = 0; } /** @@ -453,7 +474,7 @@ static inline void rmt_ll_tx_set_carrier_level(rmt_dev_t *dev, uint32_t channel, * * @param dev Peripheral instance address * @param channel RMT TX channel number - * @param enable True to output carrier signal in all RMT state, False to only ouput carrier signal for effective data + * @param enable True to output carrier signal in all RMT state, False to only output carrier signal for effective data */ static inline void rmt_ll_tx_enable_carrier_always_on(rmt_dev_t *dev, uint32_t channel, bool enable) { @@ -696,7 +717,7 @@ static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool e * @brief Clear RMT interrupt status by mask * * @param dev Peripheral instance address - * @param mask Interupt status mask + * @param mask Interrupt status mask */ __attribute__((always_inline)) static inline void rmt_ll_clear_interrupt_status(rmt_dev_t *dev, uint32_t mask) @@ -850,12 +871,9 @@ static inline uint32_t rmt_ll_tx_get_idle_level(rmt_dev_t *dev, uint32_t channel return dev->chnconf0[channel].idle_out_lv_chn; } -static inline bool rmt_ll_is_mem_powered_down(rmt_dev_t *dev) +static inline bool rmt_ll_is_mem_force_powered_down(rmt_dev_t *dev) { - // the RTC domain can also power down RMT memory - // so it's probably not enough to detect whether it's powered down or not - // mem_force_pd has higher priority than mem_force_pu - return (dev->sys_conf.mem_force_pd) || !(dev->sys_conf.mem_force_pu); + return dev->sys_conf.mem_force_pd; } __attribute__((always_inline)) diff --git a/components/hal/rmt_hal.c b/components/hal/rmt_hal.c index d83e5952dac..7290d36b1f2 100644 --- a/components/hal/rmt_hal.c +++ b/components/hal/rmt_hal.c @@ -10,9 +10,9 @@ void rmt_hal_init(rmt_hal_context_t *hal) { hal->regs = &RMT; - rmt_ll_power_down_mem(hal->regs, false); // turn on RMTMEM power domain + rmt_ll_mem_power_by_pmu(hal->regs); rmt_ll_enable_mem_access_nonfifo(hal->regs, true); // APB access the RMTMEM in nonfifo mode - rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events + rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interrupt events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events #if SOC_RMT_SUPPORT_TX_SYNCHRO rmt_ll_tx_clear_sync_group(hal->regs); @@ -21,9 +21,9 @@ void rmt_hal_init(rmt_hal_context_t *hal) void rmt_hal_deinit(rmt_hal_context_t *hal) { - rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interupt events + rmt_ll_enable_interrupt(hal->regs, UINT32_MAX, false); // disable all interrupt events rmt_ll_clear_interrupt_status(hal->regs, UINT32_MAX); // clear all pending events - rmt_ll_power_down_mem(hal->regs, true); // turn off RMTMEM power domain + rmt_ll_mem_force_power_off(hal->regs); // power off RMTMEM power domain forcefully hal->regs = NULL; } From a23ae5b4bff5a606e3eef6721417446ff690136a Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 16 Jul 2024 11:04:52 +0800 Subject: [PATCH 396/548] fix(dma): fix esp_dma_is_buffer_alignment_satisfied align issue when l2 cache line 128B --- components/esp_hw_support/dma/esp_dma_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_hw_support/dma/esp_dma_utils.c b/components/esp_hw_support/dma/esp_dma_utils.c index a8e7611a741..0c1f0df1af8 100644 --- a/components/esp_hw_support/dma/esp_dma_utils.c +++ b/components/esp_hw_support/dma/esp_dma_utils.c @@ -130,7 +130,7 @@ bool esp_dma_is_buffer_alignment_satisfied(const void *ptr, size_t size, esp_dma int cache_flags = 0; size_t cache_alignment_bytes = 0; if (esp_ptr_external_ram(ptr)) { - cache_flags |= ESP_DMA_MALLOC_FLAG_PSRAM; + cache_flags |= MALLOC_CAP_SPIRAM; } esp_err_t ret = esp_cache_get_alignment(cache_flags, &cache_alignment_bytes); assert(ret == ESP_OK); From c3fc7cffdaa2a20b6715707529a1e4193304d28f Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 16 Jul 2024 11:48:47 +0800 Subject: [PATCH 397/548] fix(aes): fixed aes wrong dma desc alignment --- components/mbedtls/port/aes/dma/esp_aes_dma_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c index 5788b0c2f8e..1fcf979533c 100644 --- a/components/mbedtls/port/aes/dma/esp_aes_dma_core.c +++ b/components/mbedtls/port/aes/dma/esp_aes_dma_core.c @@ -622,7 +622,8 @@ int esp_aes_process_dma(esp_aes_context *ctx, const unsigned char *input, unsign } #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - if (esp_cache_msync(output_desc, ALIGN_UP(output_dma_desc_num * sizeof(crypto_dma_desc_t), output_cache_line_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C) != ESP_OK) { + size_t output_desc_cache_line_size = get_cache_line_size(output_desc); + if (esp_cache_msync(output_desc, ALIGN_UP(output_dma_desc_num * sizeof(crypto_dma_desc_t), output_desc_cache_line_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C) != ESP_OK) { ESP_LOGE(TAG, "Output DMA descriptor cache sync M2C failed"); ret = -1; goto cleanup; @@ -841,7 +842,8 @@ int esp_aes_process_dma_gcm(esp_aes_context *ctx, const unsigned char *input, un } #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - if (esp_cache_msync(output_desc, ALIGN_UP(output_dma_desc_num * sizeof(crypto_dma_desc_t), output_cache_line_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C) != ESP_OK) { + size_t output_desc_cache_line_size = get_cache_line_size(output_desc); + if (esp_cache_msync(output_desc, ALIGN_UP(output_dma_desc_num * sizeof(crypto_dma_desc_t), output_desc_cache_line_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C) != ESP_OK) { ESP_LOGE(TAG, "Output DMA descriptor cache sync M2C failed"); ret = -1; goto cleanup; From 8d15c0417f8e8713ae5be4292769f2c8d0e45dbb Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Mon, 1 Jul 2024 15:44:19 +0800 Subject: [PATCH 398/548] fix(spi_master): change MOSI pin default idle level to low --- components/hal/esp32p4/include/hal/spi_ll.h | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/components/hal/esp32p4/include/hal/spi_ll.h b/components/hal/esp32p4/include/hal/spi_ll.h index 57df0aa8af9..e45f4845497 100644 --- a/components/hal/esp32p4/include/hal/spi_ll.h +++ b/components/hal/esp32p4/include/hal/spi_ll.h @@ -42,6 +42,7 @@ extern "C" { #define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words #define SPI_LL_SUPPORT_CLK_SRC_PRE_DIV 1 //clock source have divider before peripheral #define SPI_LL_CLK_SRC_PRE_DIV_MAX 512//div1(8bit) * div2(8bit but set const 2) +#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized /** * The data structure holding calculated clock configuration. Since the @@ -358,7 +359,7 @@ static inline void spi_ll_slave_reset(spi_dev_t *hw) /** * Reset SPI CPU TX FIFO * - * On P4, this function is not seperated + * On P4, this function is not separated * * @param hw Beginning address of the peripheral registers. */ @@ -371,7 +372,7 @@ static inline void spi_ll_cpu_tx_fifo_reset(spi_dev_t *hw) /** * Reset SPI CPU RX FIFO * - * On P4, this function is not seperated + * On P4, this function is not separated * * @param hw Beginning address of the peripheral registers. */ @@ -760,7 +761,7 @@ static inline void spi_ll_master_set_clock_by_reg(spi_dev_t *hw, const spi_ll_cl * Get the frequency of given dividers. Don't use in app. * * @param fapb APB clock of the system. - * @param pre Pre devider. + * @param pre Pre divider. * @param n Main divider. * * @return Frequency of given dividers. @@ -771,10 +772,10 @@ static inline int spi_ll_freq_for_pre_n(int fapb, int pre, int n) } /** - * Calculate the nearest frequency avaliable for master. + * Calculate the nearest frequency available for master. * * @param fapb APB clock of the system. - * @param hz Frequncy desired. + * @param hz Frequency desired. * @param duty_cycle Duty cycle desired. * @param out_reg Output address to store the calculated clock configurations for the return frequency. * @@ -854,7 +855,7 @@ static inline int spi_ll_master_cal_clock(int fapb, int hz, int duty_cycle, spi_ * * @param hw Beginning address of the peripheral registers. * @param fapb APB clock of the system. - * @param hz Frequncy desired. + * @param hz Frequency desired. * @param duty_cycle Duty cycle desired. * * @return Actual frequency that is used. @@ -880,6 +881,16 @@ static inline void spi_ll_set_mosi_delay(spi_dev_t *hw, int delay_mode, int dela { } +/** + * Determine and unify the default level of mosi line when bus free + * + * @param hw Beginning address of the peripheral registers. + */ +static inline void spi_ll_set_mosi_free_level(spi_dev_t *hw, bool level) +{ + hw->ctrl.d_pol = level; //set default level for MOSI only on IDLE state +} + /** * Set the miso delay applied to the input signal before the internal peripheral. (Preview) * From 249e7e92825649b33e7ba86bb2c644dd97f98daf Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 29 May 2024 17:56:05 +0800 Subject: [PATCH 399/548] change(dw_gdma): clean up memory allocation for link list items --- components/esp_hw_support/dma/dw_gdma.c | 29 +++++++++---------- .../dma/include/esp_private/dw_gdma.h | 6 ++-- .../hal/esp32p4/include/hal/dw_gdma_ll.h | 7 +++-- components/hal/include/hal/gdma_hal_axi.h | 2 -- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/components/esp_hw_support/dma/dw_gdma.c b/components/esp_hw_support/dma/dw_gdma.c index 33c44c4f89c..765d931c0dd 100644 --- a/components/esp_hw_support/dma/dw_gdma.c +++ b/components/esp_hw_support/dma/dw_gdma.c @@ -42,8 +42,10 @@ static const char *TAG = "dw-gdma"; #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #define DW_GDMA_GET_NON_CACHE_ADDR(addr) ((addr) ? CACHE_LL_L2MEM_NON_CACHE_ADDR(addr) : 0) +#define DW_GDMA_GET_CACHE_ADDRESS(nc_addr) ((nc_addr) ? CACHE_LL_L2MEM_CACHE_ADDR(nc_addr) : 0) #else #define DW_GDMA_GET_NON_CACHE_ADDR(addr) (addr) +#define DW_GDMA_GET_CACHE_ADDRESS(nc_addr) (nc_addr) #endif #if CONFIG_DW_GDMA_ISR_IRAM_SAFE || CONFIG_DW_GDMA_CTRL_FUNC_IN_IRAM || DW_GDMA_SETTER_FUNC_IN_IRAM @@ -385,22 +387,16 @@ esp_err_t dw_gdma_new_link_list(const dw_gdma_link_list_config_t *config, dw_gdm uint32_t num_items = config->num_items; list = heap_caps_calloc(1, sizeof(dw_gdma_link_list_t), DW_GDMA_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(list, ESP_ERR_NO_MEM, err, TAG, "no mem for link list"); - // allocate memory for link list items, from SRAM - // the link list items has itw own alignment requirement - // also we should respect the data cache line size + // allocate memory for link list items, from internal memory + // the link list items has its own alignment requirement, the heap allocator can help handle the cache alignment as well + items = heap_caps_aligned_calloc(DW_GDMA_LL_LINK_LIST_ALIGNMENT, num_items, sizeof(dw_gdma_link_list_item_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(items, ESP_ERR_NO_MEM, err, TAG, "no mem for link list items"); + // do memory sync when the link list items are cached uint32_t data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - uint32_t alignment = MAX(DW_GDMA_LL_LINK_LIST_ALIGNMENT, data_cache_line_size); - // because we want to access the link list items via non-cache address, so the memory size should also align to the cache line size - uint32_t lli_size = num_items * sizeof(dw_gdma_link_list_item_t); if (data_cache_line_size) { - lli_size = ALIGN_UP(lli_size, data_cache_line_size); - } - items = heap_caps_aligned_calloc(alignment, 1, lli_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA); - ESP_GOTO_ON_FALSE(items, ESP_ERR_NO_MEM, err, TAG, "no mem for link list items"); - if (data_cache_line_size) { // do memory sync only when the cache exists - // write back and then invalidate the cache, we won't use the cache to operate the link list items afterwards - // even the cache auto-write back happens, there's no risk the link list items will be overwritten - ESP_GOTO_ON_ERROR(esp_cache_msync(items, lli_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE), + // write back and then invalidate the cache, because later we will read/write the link list items by non-cacheable address + ESP_GOTO_ON_ERROR(esp_cache_msync(items, num_items * sizeof(dw_gdma_link_list_item_t), + ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE | ESP_CACHE_MSYNC_FLAG_UNALIGNED), err, TAG, "cache sync failed"); } @@ -466,6 +462,7 @@ dw_gdma_lli_handle_t dw_gdma_link_list_get_item(dw_gdma_link_list_handle_t list, { ESP_RETURN_ON_FALSE_ISR(list, NULL, TAG, "invalid argument"); ESP_RETURN_ON_FALSE_ISR(item_index < list->num_items, NULL, TAG, "invalid item index"); + // Note: the returned address is non-cached dw_gdma_link_list_item_t *lli = list->items_nc + item_index; return lli; } @@ -474,8 +471,8 @@ esp_err_t dw_gdma_lli_set_next(dw_gdma_lli_handle_t lli, dw_gdma_lli_handle_t ne { ESP_RETURN_ON_FALSE(lli && next, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - // the next field must use a cached address - dw_gdma_ll_lli_set_next_item_addr(lli, CACHE_LL_L2MEM_CACHE_ADDR(next)); + // the next field must use a cached address, so convert it to a cached address + dw_gdma_ll_lli_set_next_item_addr(lli, DW_GDMA_GET_CACHE_ADDRESS(next)); return ESP_OK; } diff --git a/components/esp_hw_support/dma/include/esp_private/dw_gdma.h b/components/esp_hw_support/dma/include/esp_private/dw_gdma.h index 6d1ad024c0d..dd9105e9d36 100644 --- a/components/esp_hw_support/dma/include/esp_private/dw_gdma.h +++ b/components/esp_hw_support/dma/include/esp_private/dw_gdma.h @@ -169,7 +169,7 @@ esp_err_t dw_gdma_channel_suspend_ctrl(dw_gdma_channel_handle_t chan, bool enter /** * @brief Abort the DMA channel * - * @note If the channel is aborted, it will be diabled immediately, which may cause AXI bus protocol violation. + * @note If the channel is aborted, it will be disabled immediately, which may cause AXI bus protocol violation. * @note This function is recommended to only be used when the channel hangs. Recommend to try `dw_gdma_channel_enable_ctrl` first, then opt for aborting. * * @param[in] chan DMA channel handle, allocated by `dw_gdma_new_channel` @@ -366,8 +366,8 @@ esp_err_t dw_gdma_lli_config_transfer(dw_gdma_lli_handle_t lli, dw_gdma_block_tr /** * @brief Set the next link list item for a given DMA link list item * - * @param[in] lli Link list item - * @param[in] next Next link list item + * @param[in] lli Current link list item, can be obtained from `dw_gdma_link_list_get_item` + * @param[in] next Next link list item, can be obtained from `dw_gdma_link_list_get_item` * @return * - ESP_OK: Set next link list item successfully * - ESP_ERR_INVALID_ARG: Set next link list item failed because of invalid argument diff --git a/components/hal/esp32p4/include/hal/dw_gdma_ll.h b/components/hal/esp32p4/include/hal/dw_gdma_ll.h index 021e929cf5b..6afcca79b35 100644 --- a/components/hal/esp32p4/include/hal/dw_gdma_ll.h +++ b/components/hal/esp32p4/include/hal/dw_gdma_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -932,7 +932,7 @@ static inline uint32_t dw_gdma_ll_channel_get_dst_periph_status(dw_gdma_dev_t *d /** * @brief Type of DW-DMA link list item */ -typedef struct dw_gdma_link_list_item_t { +struct dw_gdma_link_list_item_t { dmac_chn_sar0_reg_t sar_lo; /*!< Source address low 32 bits */ dmac_chn_sar1_reg_t sar_hi; /*!< Source address high 32 bits */ dmac_chn_dar0_reg_t dar_lo; /*!< Destination address low 32 bits */ @@ -949,8 +949,9 @@ typedef struct dw_gdma_link_list_item_t { dmac_chn_status1_reg_t status_hi; /*!< Channel status high 32 bits */ uint32_t reserved_38; uint32_t reserved_3c; -} dw_gdma_link_list_item_t __attribute__((aligned(DW_GDMA_LL_LINK_LIST_ALIGNMENT))); +} __attribute__((aligned(DW_GDMA_LL_LINK_LIST_ALIGNMENT))); +typedef struct dw_gdma_link_list_item_t dw_gdma_link_list_item_t; ESP_STATIC_ASSERT(sizeof(dw_gdma_link_list_item_t) == DW_GDMA_LL_LINK_LIST_ALIGNMENT, "Invalid size of dw_gdma_link_list_item_t structure"); /** diff --git a/components/hal/include/hal/gdma_hal_axi.h b/components/hal/include/hal/gdma_hal_axi.h index c9f5a8f3181..e7705217f3f 100644 --- a/components/hal/include/hal/gdma_hal_axi.h +++ b/components/hal/include/hal/gdma_hal_axi.h @@ -30,8 +30,6 @@ void gdma_axi_hal_enable_burst(gdma_hal_context_t *hal, int chan_id, gdma_channe void gdma_axi_hal_set_burst_size(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t burst_sz); -void gdma_axi_hal_set_ext_mem_align(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint8_t align); - void gdma_axi_hal_set_strategy(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool en_owner_check, bool en_desc_write_back); void gdma_axi_hal_enable_intr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask, bool en_or_dis); From 2c9aaf738d25c3b707b08266d7abe21b7e5ea8d2 Mon Sep 17 00:00:00 2001 From: gongyantao Date: Thu, 18 Jul 2024 11:09:30 +0800 Subject: [PATCH 400/548] fix(bt): fix uTask stack overflow in bt example spp_initiator --- .../bt_spp_initiator/main/console_uart.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/console_uart.c b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/console_uart.c index 7e10c2ea106..4bd1b2a0e19 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/console_uart.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_spp_initiator/main/console_uart.c @@ -1,9 +1,10 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ +#include "stdlib.h" #include "driver/uart.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -31,7 +32,7 @@ extern void spp_msg_args_parser(char *buf, int len); void spp_msg_handler(char *buf, int len) { - ESP_LOGE(TAG_CNSL, "Command [%s]", buf); + ESP_LOGI(TAG_CNSL, "Command [%s]", buf); spp_msg_args_parser(buf, len); } @@ -44,13 +45,18 @@ static void console_uart_task(void *pvParameters) spp_msg_parser_register_callback(parser, spp_msg_handler); spp_msg_show_usage(); #define TMP_BUF_LEN 128 - uint8_t tmp_buf[128] = {0}; + uint8_t *tmp_buf = NULL; + + if ((tmp_buf = (uint8_t *)calloc(TMP_BUF_LEN, sizeof(uint8_t))) == NULL) { + ESP_LOGE(TAG_CNSL,"temp buf malloc fail"); + return; + } for (;;) { //Waiting for UART event. if (xQueueReceive(uart_queue, (void * )&event, (TickType_t)portMAX_DELAY)) { switch (event.type) { - //Event of UART receving data + //Event of UART receiving data case UART_DATA: { len = uart_read_bytes(CONSOLE_UART_NUM, tmp_buf, TMP_BUF_LEN, 0); @@ -95,6 +101,8 @@ static void console_uart_task(void *pvParameters) } } } + + free(tmp_buf); vTaskDelete(NULL); } From 7f0be0c06c5a027cdbeeb2b6de849142934823ea Mon Sep 17 00:00:00 2001 From: gongyantao Date: Thu, 18 Jul 2024 12:06:02 +0800 Subject: [PATCH 401/548] feat(bt): add bt address printing for all bt examples --- .../classic_bt/a2dp_sink/main/main.c | 15 ++++++++++- .../classic_bt/a2dp_source/main/main.c | 2 ++ .../classic_bt/bt_discovery/main/main.c | 2 ++ .../bt_hid_mouse_device/main/main.c | 27 ++++++++++--------- .../bluedroid/classic_bt/hfp_ag/main/main.c | 16 ++++++++++- .../bluedroid/classic_bt/hfp_hf/main/main.c | 16 ++++++++++- .../esp_hid_host/main/esp_hid_host_main.c | 16 ++++++++++- 7 files changed, 78 insertions(+), 16 deletions(-) diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c index bda0bea2836..894f8862bb5 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_sink/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -47,6 +47,17 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param); /******************************* * STATIC FUNCTION DEFINITIONS ******************************/ +static char *bda2str(uint8_t * bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param) { @@ -176,6 +187,7 @@ static void bt_av_hdl_stack_evt(uint16_t event, void *p_param) void app_main(void) { + char bda_str[18] = {0}; /* initialize NVS — it is used to store PHY calibration data */ esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -230,6 +242,7 @@ void app_main(void) pin_code[3] = '4'; esp_bt_gap_set_pin(pin_type, 4, pin_code); + ESP_LOGI(BT_AV_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); bt_app_task_start_up(); /* bluetooth device name, connection mode and profile set up */ bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL); diff --git a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c index 16fceef2853..9bad03babff 100644 --- a/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/a2dp_source/main/main.c @@ -735,6 +735,7 @@ static void bt_av_hdl_avrc_ct_evt(uint16_t event, void *p_param) void app_main(void) { + char bda_str[18] = {0}; /* initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -788,6 +789,7 @@ void app_main(void) esp_bt_pin_code_t pin_code; esp_bt_gap_set_pin(pin_type, 0, pin_code); + ESP_LOGI(BT_AV_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); bt_app_task_start_up(); /* Bluetooth device name, connection mode and profile set up */ bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_STACK_UP_EVT, NULL, 0, NULL); diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/main.c b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/main.c index 5b4123c45e2..0c7669fadce 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_discovery/main/main.c @@ -272,6 +272,7 @@ static void bt_app_gap_start_up(void) void app_main(void) { + char bda_str[18] = {0}; /* Initialize NVS — it is used to store PHY calibration data and save key-value pairs in flash memory*/ esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -304,5 +305,6 @@ void app_main(void) return; } + ESP_LOGI(GAP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); bt_app_gap_start_up(); } diff --git a/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c b/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c index 349a8128011..0d4ca2cf2d1 100644 --- a/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -71,6 +71,18 @@ uint8_t hid_mouse_descriptor[] = { 0xc0 // END_COLLECTION }; +static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} + const int hid_mouse_descriptor_len = sizeof(hid_mouse_descriptor); /** @@ -158,16 +170,6 @@ void mouse_move_task(void *pvParameters) } } -static void print_bt_address(void) -{ - const char *TAG = "bt_address"; - const uint8_t *bd_addr; - - bd_addr = esp_bt_dev_get_address(); - ESP_LOGI(TAG, "my bluetooth address is %02X:%02X:%02X:%02X:%02X:%02X", - bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); -} - void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) { const char *TAG = "esp_bt_gap_cb"; @@ -390,6 +392,7 @@ void app_main(void) { const char *TAG = "app_main"; esp_err_t ret; + char bda_str[18] = {0}; ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -477,6 +480,6 @@ void app_main(void) esp_bt_pin_code_t pin_code; esp_bt_gap_set_pin(pin_type, 0, pin_code); - print_bt_address(); + ESP_LOGI(TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); ESP_LOGI(TAG, "exiting"); } diff --git a/examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c b/examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c index d5e6f3d30e7..c93aac3da22 100644 --- a/examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/hfp_ag/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -32,6 +32,18 @@ enum { BT_APP_EVT_STACK_UP = 0, }; +static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} + /* handler for bluetooth stack enabled events */ static void bt_hf_hdl_stack_evt(uint16_t event, void *p_param) { @@ -73,6 +85,7 @@ static void bt_hf_hdl_stack_evt(uint16_t event, void *p_param) void app_main(void) { + char bda_str[18] = {0}; /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { @@ -101,6 +114,7 @@ void app_main(void) return; } + ESP_LOGI(BT_HF_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); /* create application task */ bt_app_task_start_up(); diff --git a/examples/bluetooth/bluedroid/classic_bt/hfp_hf/main/main.c b/examples/bluetooth/bluedroid/classic_bt/hfp_hf/main/main.c index cfd1e4844f0..cdf47d7b2f9 100644 --- a/examples/bluetooth/bluedroid/classic_bt/hfp_hf/main/main.c +++ b/examples/bluetooth/bluedroid/classic_bt/hfp_hf/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -32,6 +32,18 @@ static uint8_t peer_bdname_len; static const char remote_device_name[] = "ESP_HFP_AG"; +static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} + static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len) { uint8_t *rmt_bdname = NULL; @@ -151,6 +163,7 @@ static void bt_hf_client_hdl_stack_evt(uint16_t event, void *p_param); void app_main(void) { + char bda_str[18] = {0}; /* Initialize NVS — it is used to store PHY calibration data */ esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { @@ -186,6 +199,7 @@ void app_main(void) return; } + ESP_LOGI(BT_HF_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); /* create application task */ bt_app_task_start_up(); diff --git a/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c b/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c index 420ff9d72bf..1643b8a33ea 100644 --- a/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c +++ b/examples/bluetooth/esp_hid_host/main/esp_hid_host_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -51,6 +51,18 @@ static const char *TAG = "ESP_HIDH_DEMO"; +static char *bda2str(esp_bd_addr_t bda, char *str, size_t size) +{ + if (bda == NULL || str == NULL || size < 18) { + return NULL; + } + + uint8_t *p = bda; + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + p[0], p[1], p[2], p[3], p[4], p[5]); + return str; +} + void hidh_callback(void *handler_args, esp_event_base_t base, int32_t id, void *event_data) { esp_hidh_event_t event = (esp_hidh_event_t)id; @@ -165,6 +177,7 @@ void ble_store_config_init(void); #endif void app_main(void) { + char bda_str[18] = {0}; esp_err_t ret; #if HID_HOST_MODE == HIDH_IDLE_MODE ESP_LOGE(TAG, "Please turn on BT HID host or BLE!"); @@ -188,6 +201,7 @@ void app_main(void) }; ESP_ERROR_CHECK( esp_hidh_init(&config) ); + ESP_LOGI(TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str))); #if CONFIG_BT_NIMBLE_ENABLED /* XXX Need to have template for store */ ble_store_config_init(); From 99b1e56500195af54f58c47ef2753f7ed413bebe Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Thu, 20 Jun 2024 10:41:20 +0800 Subject: [PATCH 402/548] fix(hal): correct the power up sequence for MPI/ECC peripherals in ESP32-C5 --- components/hal/esp32c2/include/hal/ecc_ll.h | 3 +++ components/hal/esp32c5/include/hal/ecc_ll.h | 15 +++++++++++++++ components/hal/esp32c5/include/hal/mpi_ll.h | 4 ++++ components/hal/esp32c6/include/hal/ecc_ll.h | 15 ++++++++++++++- components/hal/esp32c6/include/hal/mpi_ll.h | 4 ++++ components/hal/esp32h2/include/hal/ecc_ll.h | 15 ++++++++++++++- components/hal/esp32h2/include/hal/mpi_ll.h | 4 ++++ components/hal/esp32p4/include/hal/ecc_ll.h | 3 +++ .../hal/test_apps/crypto/main/ecc/test_ecc.c | 2 ++ .../hal/test_apps/crypto/main/ecdsa/test_ecdsa.c | 2 ++ components/mbedtls/port/ecc/esp_ecc.c | 2 ++ components/mbedtls/port/ecdsa/ecdsa_alt.c | 2 ++ 12 files changed, 69 insertions(+), 2 deletions(-) diff --git a/components/hal/esp32c2/include/hal/ecc_ll.h b/components/hal/esp32c2/include/hal/ecc_ll.h index 2fcca34ea0f..58ddd82dd00 100644 --- a/components/hal/esp32c2/include/hal/ecc_ll.h +++ b/components/hal/esp32c2/include/hal/ecc_ll.h @@ -49,6 +49,9 @@ static inline void ecc_ll_reset_register(void) /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define ecc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; ecc_ll_reset_register(__VA_ARGS__) +static inline void ecc_ll_power_up(void) {} +static inline void ecc_ll_power_down(void) {} + static inline void ecc_ll_enable_interrupt(void) { REG_SET_FIELD(ECC_MULT_INT_ENA_REG, ECC_MULT_CALC_DONE_INT_ENA, 1); diff --git a/components/hal/esp32c5/include/hal/ecc_ll.h b/components/hal/esp32c5/include/hal/ecc_ll.h index 7e3a7a1073e..48975e5ec81 100644 --- a/components/hal/esp32c5/include/hal/ecc_ll.h +++ b/components/hal/esp32c5/include/hal/ecc_ll.h @@ -12,6 +12,7 @@ #include "hal/ecc_types.h" #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" +#include "soc/pcr_reg.h" #ifdef __cplusplus extern "C" { @@ -51,6 +52,20 @@ static inline void ecc_ll_reset_register(void) #endif } +static inline void ecc_ll_power_up(void) +{ + /* Power up the ECC peripheral (default state is power-down) */ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); +} + +static inline void ecc_ll_power_down(void) +{ + /* Power down the ECC peripheral */ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PU); + REG_SET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); +} + static inline void ecc_ll_enable_interrupt(void) { REG_SET_FIELD(ECC_MULT_INT_ENA_REG, ECC_MULT_CALC_DONE_INT_ENA, 1); diff --git a/components/hal/esp32c5/include/hal/mpi_ll.h b/components/hal/esp32c5/include/hal/mpi_ll.h index 543a5fa60ae..8ba54a9c11f 100644 --- a/components/hal/esp32c5/include/hal/mpi_ll.h +++ b/components/hal/esp32c5/include/hal/mpi_ll.h @@ -56,11 +56,15 @@ static inline size_t mpi_ll_calculate_hardware_words(size_t words) static inline void mpi_ll_clear_power_control_bit(void) { + /* Power up the MPI peripheral (default is power-down state) */ REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PD); } static inline void mpi_ll_set_power_control_bit(void) { + /* Power down the MPI peripheral */ + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PU); REG_SET_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); } diff --git a/components/hal/esp32c6/include/hal/ecc_ll.h b/components/hal/esp32c6/include/hal/ecc_ll.h index c5e8799dcfb..cb8b4ca2cd2 100644 --- a/components/hal/esp32c6/include/hal/ecc_ll.h +++ b/components/hal/esp32c6/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "hal/ecc_types.h" #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" +#include "soc/pcr_reg.h" #ifdef __cplusplus extern "C" { @@ -41,6 +42,18 @@ static inline void ecc_ll_reset_register(void) PCR.ecc_conf.ecc_rst_en = 0; } +static inline void ecc_ll_power_up(void) +{ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); +} + +static inline void ecc_ll_power_down(void) +{ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PU); + REG_SET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); +} + static inline void ecc_ll_enable_interrupt(void) { REG_SET_FIELD(ECC_MULT_INT_ENA_REG, ECC_MULT_CALC_DONE_INT_ENA, 1); diff --git a/components/hal/esp32c6/include/hal/mpi_ll.h b/components/hal/esp32c6/include/hal/mpi_ll.h index 032ac17b47e..dbb0af11322 100644 --- a/components/hal/esp32c6/include/hal/mpi_ll.h +++ b/components/hal/esp32c6/include/hal/mpi_ll.h @@ -49,11 +49,15 @@ static inline size_t mpi_ll_calculate_hardware_words(size_t words) static inline void mpi_ll_clear_power_control_bit(void) { + /* Power up the MPI peripheral */ REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PD); } static inline void mpi_ll_set_power_control_bit(void) { + /* Power down the MPI peripheral */ + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PU); REG_SET_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); } diff --git a/components/hal/esp32h2/include/hal/ecc_ll.h b/components/hal/esp32h2/include/hal/ecc_ll.h index 47d4e8b9e6a..46667692a70 100644 --- a/components/hal/esp32h2/include/hal/ecc_ll.h +++ b/components/hal/esp32h2/include/hal/ecc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "hal/ecc_types.h" #include "soc/ecc_mult_reg.h" #include "soc/pcr_struct.h" +#include "soc/pcr_reg.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,18 @@ static inline void ecc_ll_reset_register(void) PCR.ecdsa_conf.ecdsa_rst_en = 0; } +static inline void ecc_ll_power_up(void) +{ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PD); +} + +static inline void ecc_ll_power_down(void) +{ + REG_CLR_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_FORCE_PU); + REG_SET_BIT(PCR_ECC_PD_CTRL_REG, PCR_ECC_MEM_PD); +} + static inline void ecc_ll_enable_interrupt(void) { REG_SET_FIELD(ECC_MULT_INT_ENA_REG, ECC_MULT_CALC_DONE_INT_ENA, 1); diff --git a/components/hal/esp32h2/include/hal/mpi_ll.h b/components/hal/esp32h2/include/hal/mpi_ll.h index 0eed1020d9d..774d2ce96a5 100644 --- a/components/hal/esp32h2/include/hal/mpi_ll.h +++ b/components/hal/esp32h2/include/hal/mpi_ll.h @@ -50,11 +50,15 @@ static inline size_t mpi_ll_calculate_hardware_words(size_t words) static inline void mpi_ll_clear_power_control_bit(void) { + /* Power up the MPI peripheral */ REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PD); } static inline void mpi_ll_set_power_control_bit(void) { + /* Power down the MPI peripheral */ + REG_CLR_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_FORCE_PU); REG_SET_BIT(PCR_RSA_PD_CTRL_REG, PCR_RSA_MEM_PD); } diff --git a/components/hal/esp32p4/include/hal/ecc_ll.h b/components/hal/esp32p4/include/hal/ecc_ll.h index 879a438acd5..92d747afbc4 100644 --- a/components/hal/esp32p4/include/hal/ecc_ll.h +++ b/components/hal/esp32p4/include/hal/ecc_ll.h @@ -56,6 +56,9 @@ static inline void ecc_ll_reset_register(void) /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance #define ecc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; ecc_ll_reset_register(__VA_ARGS__) +static inline void ecc_ll_power_up(void) {} +static inline void ecc_ll_power_down(void) {} + static inline void ecc_ll_enable_interrupt(void) { REG_SET_FIELD(ECC_MULT_INT_ENA_REG, ECC_MULT_CALC_DONE_INT_ENA, 1); diff --git a/components/hal/test_apps/crypto/main/ecc/test_ecc.c b/components/hal/test_apps/crypto/main/ecc/test_ecc.c index a6bc8c3fdcb..fcf72814f24 100644 --- a/components/hal/test_apps/crypto/main/ecc/test_ecc.c +++ b/components/hal/test_apps/crypto/main/ecc/test_ecc.c @@ -46,6 +46,7 @@ static void ecc_enable_and_reset(void) { ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(true); + ecc_ll_power_up(); ecc_ll_reset_register(); } } @@ -54,6 +55,7 @@ static void ecc_disable(void) { ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(false); + ecc_ll_power_down(); } } diff --git a/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c b/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c index d0777dc817b..2a7e1d4239b 100644 --- a/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c +++ b/components/hal/test_apps/crypto/main/ecdsa/test_ecdsa.c @@ -34,6 +34,7 @@ static void ecdsa_enable_and_reset(void) ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(true); + ecc_ll_power_up(); ecc_ll_reset_register(); } @@ -55,6 +56,7 @@ static void ecdsa_disable(void) ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(false); + ecc_ll_power_down(); } ECDSA_RCC_ATOMIC() { diff --git a/components/mbedtls/port/ecc/esp_ecc.c b/components/mbedtls/port/ecc/esp_ecc.c index b9fe0a8871a..0cb4e72e9cb 100644 --- a/components/mbedtls/port/ecc/esp_ecc.c +++ b/components/mbedtls/port/ecc/esp_ecc.c @@ -19,6 +19,7 @@ static void esp_ecc_acquire_hardware(void) ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(true); + ecc_ll_power_up(); ecc_ll_reset_register(); } } @@ -27,6 +28,7 @@ static void esp_ecc_release_hardware(void) { ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(false); + ecc_ll_power_down(); } esp_crypto_ecc_lock_release(); diff --git a/components/mbedtls/port/ecdsa/ecdsa_alt.c b/components/mbedtls/port/ecdsa/ecdsa_alt.c index 2e6e0a6dd4a..e28ee3aada8 100644 --- a/components/mbedtls/port/ecdsa/ecdsa_alt.c +++ b/components/mbedtls/port/ecdsa/ecdsa_alt.c @@ -35,6 +35,7 @@ static void esp_ecdsa_acquire_hardware(void) ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(true); + ecc_ll_power_up(); ecc_ll_reset_register(); } @@ -57,6 +58,7 @@ static void esp_ecdsa_release_hardware(void) ECC_RCC_ATOMIC() { ecc_ll_enable_bus_clock(false); + ecc_ll_power_down(); } #ifdef SOC_ECDSA_USES_MPI From 436bf0b1ee0156eff1810494c750f75ba761b65c Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Mon, 1 Jul 2024 14:49:17 +0800 Subject: [PATCH 403/548] feat(openthread): update openthread submodule --- components/openthread/CMakeLists.txt | 2 + components/openthread/Kconfig | 3 +- components/openthread/openthread | 2 +- .../openthread-core-esp32x-ftd-config.h | 4 +- .../openthread-core-esp32x-mtd-config.h | 4 +- .../openthread-core-esp32x-radio-config.h | 4 +- .../openthread-core-esp32x-spinel-config.h | 4 +- components/openthread/sbom_openthread.yml | 2 +- .../src/esp_openthread_netif_glue.c | 2 +- .../src/port/esp_openthread_radio.c | 26 +++++++--- .../src/port/esp_openthread_radio_spinel.cpp | 49 ++++++++++++++----- .../src/spinel/esp_radio_spinel.cpp | 20 +++++++- .../esp_radio_spinel_uart_interface.cpp | 1 + examples/openthread/ot_rcp/sdkconfig.defaults | 5 ++ 14 files changed, 96 insertions(+), 32 deletions(-) diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 39cc5b78b81..7a1db20cf12 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -266,6 +266,8 @@ if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_OPENTHREAD_SPINEL_ONLY) PUBLIC "OPENTHREAD_CONFIG_FILE=\"openthread-core-esp32x-${CONFIG_FILE_TYPE}-config.h\"" "${device_type}" + "OPENTHREAD_PROJECT_LIB_CONFIG_FILE=\"openthread-core-esp32x-${CONFIG_FILE_TYPE}-config.h\"" + "${device_type}" PRIVATE "PACKAGE_VERSION=\"${IDF_VERSION_FOR_OPENTHREAD_PACKAGE}-${OPENTHREAD_VERSION}\"" "OPENTHREAD_BUILD_DATETIME=\"${OT_BUILD_TIMESTAMP}\"" diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 740479a940a..56739b5ec3d 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -259,7 +259,8 @@ menu "OpenThread" config OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE int "The size of openthread spinel rx frame buffer" depends on OPENTHREAD_ENABLED || OPENTHREAD_SPINEL_ONLY - default 2048 + default 1024 if OPENTHREAD_MTD || OPENTHREAD_RADIO + default 2048 if OPENTHREAD_FTD || OPENTHREAD_SPINEL_ONLY config OPENTHREAD_MAC_MAX_CSMA_BACKOFFS_DIRECT int "Maximum backoffs times before declaring a channel access failure." diff --git a/components/openthread/openthread b/components/openthread/openthread index be7d36e4ff9..f32c18bc084 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit be7d36e4ff9cf7df6dfce54e58a31163c87b93f7 +Subproject commit f32c18bc0840f400182456e58ae3900fc2fb4af7 diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index bf61bc9094c..5c851511f5c 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -355,13 +355,13 @@ #define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 3 /** - * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE + * @def OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE * * Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when * `RadioSpinel` platform is used. * */ -#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE +#define OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index 40ac95b9ebd..8067323649b 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -169,13 +169,13 @@ #define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 3 /** - * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE + * @def OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE * * Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when * `RadioSpinel` platform is used. * */ -#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE 1024 +#define OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE diff --git a/components/openthread/private_include/openthread-core-esp32x-radio-config.h b/components/openthread/private_include/openthread-core-esp32x-radio-config.h index cd8ad159092..aba848fe496 100644 --- a/components/openthread/private_include/openthread-core-esp32x-radio-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-radio-config.h @@ -142,13 +142,13 @@ #define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 3 /** - * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE + * @def OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE * * Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when * `RadioSpinel` platform is used. * */ -#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE 1024 +#define OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE /** * @def OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE diff --git a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h index 68d5b8240a3..35c33d55a60 100644 --- a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h @@ -39,13 +39,13 @@ #endif /** - * @def OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE + * @def OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE * * Specifies the rx frame buffer size used by `SpinelInterface` in RCP host code. This is applicable/used when * `RadioSpinel` platform is used. * */ -#define OPENTHREAD_CONFIG_PLATFORM_RADIO_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE +#define OPENTHREAD_LIB_SPINEL_RX_FRAME_BUFFER_SIZE CONFIG_OPENTHREAD_SPINEL_RX_FRAME_BUFFER_SIZE /** * @def OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT diff --git a/components/openthread/sbom_openthread.yml b/components/openthread/sbom_openthread.yml index ae0203670fb..7738bbe0a2e 100644 --- a/components/openthread/sbom_openthread.yml +++ b/components/openthread/sbom_openthread.yml @@ -5,4 +5,4 @@ supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' originator: 'Organization: Google LLC' description: OpenThread released by Google is an open-source implementation of the Thread networking url: https://github.com/espressif/openthread -hash: be7d36e4ff9cf7df6dfce54e58a31163c87b93f7 +hash: f32c18bc0840f400182456e58ae3900fc2fb4af7 diff --git a/components/openthread/src/esp_openthread_netif_glue.c b/components/openthread/src/esp_openthread_netif_glue.c index 8e0ff030855..e7184698682 100644 --- a/components/openthread/src/esp_openthread_netif_glue.c +++ b/components/openthread/src/esp_openthread_netif_glue.c @@ -320,7 +320,7 @@ void *esp_openthread_netif_glue_init(const esp_openthread_platform_config_t *con otIp6SetAddressCallback(instance, process_thread_address, instance); otIp6SetReceiveCallback(instance, process_thread_receive, instance); otIp6SetReceiveFilterEnabled(instance, true); - otIcmp6SetEchoMode(instance, OT_ICMP6_ECHO_HANDLER_DISABLED); + otIcmp6SetEchoMode(instance, OT_ICMP6_ECHO_HANDLER_RLOC_ALOC_ONLY); s_openthread_netif_glue.event_fd = eventfd(0, 0); if (s_openthread_netif_glue.event_fd < 0) { diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index 07041438b27..4276809c528 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -64,10 +64,13 @@ static otRadioFrame s_ack_frame; static int s_ed_power; static esp_ieee802154_tx_error_t s_tx_error; static int s_radio_event_fd = -1; -static bool s_diag_mode = false; static const char *s_radio_workflow = "radio"; static uint8_t s_txrx_events; +#if CONFIG_OPENTHREAD_DIAG +static bool s_diag_mode = false; +#endif + #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT static otRadioIeInfo s_transmit_ie_info; #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT @@ -113,7 +116,7 @@ static inline bool get_event(uint8_t event) esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config) { ESP_RETURN_ON_FALSE(s_radio_event_fd == -1, ESP_ERR_INVALID_STATE, OT_PLAT_LOG_TAG, - "Radio was initalized already!"); + "Radio was initialized already!"); s_radio_event_fd = eventfd(0, EFD_SUPPORT_ISR); @@ -165,7 +168,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre if (get_event(EVENT_TX_DONE)) { clr_event(EVENT_TX_DONE); -#if OPENTHREAD_CONFIG_DIAG_ENABLE +#if CONFIG_OPENTHREAD_DIAG if (otPlatDiagModeGet()) { otPlatDiagRadioTransmitDone(aInstance, &s_transmit_frame, OT_ERROR_NONE); } else @@ -183,7 +186,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre if (get_event(EVENT_TX_FAILED)) { clr_event(EVENT_TX_FAILED); -#if OPENTHREAD_CONFIG_DIAG_ENABLE +#if CONFIG_OPENTHREAD_DIAG if (otPlatDiagModeGet()) { otPlatDiagRadioTransmitDone(aInstance, &s_transmit_frame, OT_ERROR_CHANNEL_ACCESS_FAILURE); } else @@ -219,7 +222,7 @@ esp_err_t esp_openthread_radio_process(otInstance *aInstance, const esp_openthre while (atomic_load(&s_recv_queue.used)) { if (s_receive_frame[s_recv_queue.head].mPsdu != NULL) { -#if OPENTHREAD_CONFIG_DIAG_ENABLE +#if CONFIG_OPENTHREAD_DIAG if (otPlatDiagModeGet()) { otPlatDiagRadioReceiveDone(aInstance, &s_receive_frame[s_recv_queue.head], OT_ERROR_NONE); } else @@ -302,7 +305,7 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) { esp_ieee802154_set_channel(aFrame->mChannel); - aFrame->mPsdu[-1] = aFrame->mLength; // lenth locates one byte before the psdu (esp_openthread_radio_tx_psdu); + aFrame->mPsdu[-1] = aFrame->mLength; // length locates one byte before the psdu (esp_openthread_radio_tx_psdu); if (otMacFrameIsSecurityEnabled(aFrame) && !aFrame->mInfo.mTxInfo.mIsSecurityProcessed) { if (!s_transmit_frame.mInfo.mTxInfo.mIsARetx) { @@ -447,6 +450,15 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) return ESP_RECEIVE_SENSITIVITY; } +#if CONFIG_OPENTHREAD_DIAG + +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCallback); + OT_UNUSED_VARIABLE(aContext); +} + void otPlatDiagModeSet(bool mode) { s_diag_mode = mode; @@ -479,6 +491,8 @@ void otPlatDiagAlarmCallback(otInstance *aInstance) OT_UNUSED_VARIABLE(aInstance); } +#endif // CONFIG_OPENTHREAD_DIAG + #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2 void otPlatRadioSetMacKey(otInstance *aInstance, uint8_t aKeyIdMode, uint8_t aKeyId, const otMacKeyMaterial *aPrevKey, const otMacKeyMaterial *aCurrKey, const otMacKeyMaterial *aNextKey, otRadioKeyType aKeyType) diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index a926138f9a5..34eccebc8ad 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -6,6 +6,7 @@ #include "esp_openthread_radio.h" +#include "link_raw.h" #include "sdkconfig.h" #include "esp_check.h" #include "esp_err.h" @@ -23,9 +24,11 @@ #include "openthread/platform/diag.h" #include "openthread/platform/radio.h" #include "platform/exit_code.h" +#include "spinel_driver.hpp" using ot::Spinel::RadioSpinel; using esp::openthread::SpinelInterfaceAdapter; +using ot::Spinel::SpinelDriver; #if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART using esp::openthread::UartSpinelInterface; @@ -35,7 +38,17 @@ using esp::openthread::SpiSpinelInterface; static SpinelInterfaceAdapter s_spinel_interface; #endif +static SpinelDriver s_spinel_driver; static RadioSpinel s_radio; +static otRadioCaps s_radio_caps = (OT_RADIO_CAPS_ENERGY_SCAN | +#if CONFIG_OPENTHREAD_RX_ON_WHEN_IDLE + OT_RADIO_CAPS_RX_ON_WHEN_IDLE | +#endif + OT_RADIO_CAPS_TRANSMIT_SEC | + OT_RADIO_CAPS_RECEIVE_TIMING | + OT_RADIO_CAPS_TRANSMIT_TIMING | + OT_RADIO_CAPS_ACK_TIMEOUT | + OT_RADIO_CAPS_SLEEP_TO_TX); static const char *radiospinel_workflow = "radio_spinel"; @@ -60,7 +73,7 @@ esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *conf #if CONFIG_OPENTHREAD_DIAG callbacks.mDiagReceiveDone = otPlatDiagRadioReceiveDone; callbacks.mDiagTransmitDone = otPlatDiagRadioTransmitDone; -#endif // OPENTHREAD_CONFIG_DIAG_ENABLE +#endif // CONFIG_OPENTHREAD_DIAG callbacks.mEnergyScanDone = otPlatRadioEnergyScanDone; callbacks.mReceiveDone = otPlatRadioReceiveDone; callbacks.mTransmitDone = otPlatRadioTxDone; @@ -70,14 +83,15 @@ esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *conf esp_openthread_radio_config_set(&config->radio_config); #if CONFIG_OPENTHREAD_RADIO_SPINEL_UART // CONFIG_OPENTHREAD_RADIO_SPINEL_UART ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_uart_config), OT_PLAT_LOG_TAG, - "Spinel interface init falied"); + "Spinel interface init failed"); #else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(config->radio_config.radio_spi_config), OT_PLAT_LOG_TAG, "Spinel interface init failed"); #endif - s_radio.Init(s_spinel_interface.GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); + s_spinel_driver.Init(s_spinel_interface.GetSpinelInterface(), true, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); + s_radio.Init(/*skip_rcp_compatibility_check=*/false, /*reset_radio=*/true, &s_spinel_driver, s_radio_caps); #if CONFIG_OPENTHREAD_RADIO_SPINEL_SPI // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI - ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().AfterRadioInit(), OT_PLAT_LOG_TAG, "Spinel interface init falied"); + ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().AfterRadioInit(), OT_PLAT_LOG_TAG, "Spinel interface init failed"); #endif return esp_openthread_platform_workflow_register(&esp_openthread_radio_update, &esp_openthread_radio_process, radiospinel_workflow); @@ -106,7 +120,7 @@ esp_err_t esp_openthread_rcp_init(void) const esp_openthread_radio_config_t *radio_config = esp_openthread_radio_config_get(); #if CONFIG_OPENTHREAD_RADIO_SPINEL_UART ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_uart_config), OT_PLAT_LOG_TAG, - "Spinel interface init falied"); + "Spinel interface init failed"); #else // CONFIG_OPENTHREAD_RADIO_SPINEL_SPI ESP_RETURN_ON_ERROR(s_spinel_interface.GetSpinelInterface().Enable(radio_config->radio_spi_config), OT_PLAT_LOG_TAG, "Spinel interface init failed"); @@ -128,6 +142,7 @@ void esp_openthread_radio_deinit(void) esp_err_t esp_openthread_radio_process(otInstance *instance, const esp_openthread_mainloop_context_t *mainloop) { + s_spinel_driver.Process((void *)mainloop); s_radio.Process((void *)mainloop); return ESP_OK; @@ -211,7 +226,8 @@ int8_t otPlatRadioGetRssi(otInstance *instance) otRadioCaps otPlatRadioGetCaps(otInstance *instance) { - return s_radio.GetRadioCaps(); + s_radio_caps = s_radio.GetRadioCaps(); + return s_radio_caps; } bool otPlatRadioGetPromiscuous(otInstance *instance) @@ -319,7 +335,7 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun SuccessOrDie(s_radio.SetMacFrameCounter(aMacFrameCounter, true)); } -#if OPENTHREAD_CONFIG_DIAG_ENABLE +#if CONFIG_OPENTHREAD_DIAG otError otPlatDiagProcess(otInstance *instance, int argc, char *argv[], char *output, size_t output_max_len) { // deliver the platform specific diags commands to radio only ncp. @@ -331,12 +347,19 @@ otError otPlatDiagProcess(otInstance *instance, int argc, char *argv[], char *ou cur += snprintf(cur, static_cast(end - cur), "%s ", argv[index]); } - return s_radio.PlatDiagProcess(cmd, output, output_max_len); + return s_radio.PlatDiagProcess(cmd); +} + +void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCallback); + OT_UNUSED_VARIABLE(aContext); } void otPlatDiagModeSet(bool aMode) { - SuccessOrExit(s_radio.PlatDiagProcess(aMode ? "start" : "stop", NULL, 0)); + SuccessOrExit(s_radio.PlatDiagProcess(aMode ? "start" : "stop")); s_radio.SetDiagEnabled(aMode); exit: @@ -353,7 +376,7 @@ void otPlatDiagTxPowerSet(int8_t tx_power) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "power %d", tx_power); - SuccessOrExit(s_radio.PlatDiagProcess(cmd, NULL, 0)); + SuccessOrExit(s_radio.PlatDiagProcess(cmd)); exit: return; @@ -364,7 +387,7 @@ void otPlatDiagChannelSet(uint8_t channel) char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE]; snprintf(cmd, sizeof(cmd), "channel %d", channel); - SuccessOrExit(s_radio.PlatDiagProcess(cmd, NULL, 0)); + SuccessOrExit(s_radio.PlatDiagProcess(cmd)); exit: return; @@ -378,13 +401,13 @@ void otPlatDiagAlarmCallback(otInstance *instance) { } +#endif // CONFIG_OPENTHREAD_DIAG + const char *otPlatRadioGetVersionString(otInstance *aInstance) { return s_radio.GetVersion(); } -#endif // OPENTHREAD_CONFIG_DIAG_ENABLE - uint64_t otPlatRadioGetNow(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/components/openthread/src/spinel/esp_radio_spinel.cpp b/components/openthread/src/spinel/esp_radio_spinel.cpp index 2b7bcfdf16b..2057433ce43 100644 --- a/components/openthread/src/spinel/esp_radio_spinel.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel.cpp @@ -12,17 +12,27 @@ #include "esp_radio_spinel.h" #include "esp_radio_spinel_adapter.hpp" #include "esp_radio_spinel_uart_interface.hpp" +#include "spinel_driver.hpp" using ot::Spinel::RadioSpinel; using ot::Spinel::RadioSpinelCallbacks; using esp::radio_spinel::SpinelInterfaceAdapter; using esp::radio_spinel::UartSpinelInterface; +using ot::Spinel::SpinelDriver; static SpinelInterfaceAdapter s_spinel_interface[ot::Spinel::kSpinelHeaderMaxNumIid]; static RadioSpinel s_radio[ot::Spinel::kSpinelHeaderMaxNumIid]; static esp_radio_spinel_callbacks_t s_esp_radio_spinel_callbacks[ot::Spinel::kSpinelHeaderMaxNumIid]; +static SpinelDriver s_spinel_driver[ot::Spinel::kSpinelHeaderMaxNumIid]; otRadioFrame s_transmit_frame; +static otRadioCaps s_radio_caps = (OT_RADIO_CAPS_ENERGY_SCAN | + OT_RADIO_CAPS_TRANSMIT_SEC | + OT_RADIO_CAPS_RECEIVE_TIMING | + OT_RADIO_CAPS_TRANSMIT_TIMING | + OT_RADIO_CAPS_ACK_TIMEOUT | + OT_RADIO_CAPS_SLEEP_TO_TX); + static esp_radio_spinel_idx_t get_index_from_instance(otInstance *instance) { // TZ-563: Implement the function to get the esp radio spinel idx from otInstance for multipan rcp @@ -213,7 +223,8 @@ void esp_radio_spinel_init(esp_radio_spinel_idx_t idx) // Multipan is not currently supported iidList[0] = 0; - s_radio[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), /*reset_radio=*/true, /*skip_rcp_compatibility_check=*/false, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); + s_spinel_driver[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), true, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); + s_radio[idx].Init(/*skip_rcp_compatibility_check=*/false, /*reset_radio=*/true, &s_spinel_driver[idx], s_radio_caps); } esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx) @@ -309,6 +320,7 @@ void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop void esp_radio_spinel_radio_process(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx) { + s_spinel_driver[idx].Process((void *)mainloop_context); s_radio[idx].Process(static_cast(mainloop_context)); } @@ -354,3 +366,9 @@ esp_err_t esp_radio_spinel_rcp_version_get(char *running_rcp_version, esp_radio_ strcpy(running_rcp_version, rcp_version); return ESP_OK; } + +esp_err_t esp_radio_spinel_set_rcp_ready(esp_radio_spinel_idx_t idx) +{ + s_spinel_driver[idx].SetCoprocessorReady(); + return ESP_OK; +} diff --git a/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp index 56806500590..b01ef694c27 100644 --- a/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel_uart_interface.cpp @@ -11,6 +11,7 @@ #include "esp_openthread_common_macro.h" #include "openthread/platform/time.h" #include "hdlc.hpp" +#include "core/common/code_utils.hpp" namespace esp { namespace radio_spinel { diff --git a/examples/openthread/ot_rcp/sdkconfig.defaults b/examples/openthread/ot_rcp/sdkconfig.defaults index 002c6f9f305..91439591345 100644 --- a/examples/openthread/ot_rcp/sdkconfig.defaults +++ b/examples/openthread/ot_rcp/sdkconfig.defaults @@ -8,6 +8,11 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000 CONFIG_PARTITION_TABLE_MD5=y # end of Partition Table +# +# Wireless Coexistence +# +CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n + # # OpenThread # From 6fa12ecdf8df4efcfd4c6b82bdcf11bb745c3e98 Mon Sep 17 00:00:00 2001 From: Armando Date: Thu, 18 Jul 2024 08:58:57 +0800 Subject: [PATCH 404/548] fix(psram): fixed p4 psram 20M wrong clk div --- components/esp_psram/device/esp_psram_impl_ap_hex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_psram/device/esp_psram_impl_ap_hex.c b/components/esp_psram/device/esp_psram_impl_ap_hex.c index 82a1b4e0b83..7832460eb38 100644 --- a/components/esp_psram/device/esp_psram_impl_ap_hex.c +++ b/components/esp_psram/device/esp_psram_impl_ap_hex.c @@ -384,8 +384,8 @@ esp_err_t esp_psram_impl_enable(void) s_configure_psram_ecc(); #endif //enter MSPI slow mode to init PSRAM device registers - psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, 40); - psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_3, 40); + psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_2, AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ / CONFIG_SPIRAM_SPEED); + psram_ctrlr_ll_set_bus_clock(PSRAM_CTRLR_LL_MSPI_ID_3, AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ / CONFIG_SPIRAM_SPEED); psram_ctrlr_ll_enable_dll(PSRAM_CTRLR_LL_MSPI_ID_2, true); psram_ctrlr_ll_enable_dll(PSRAM_CTRLR_LL_MSPI_ID_3, true); From d1b3845aaa6905db1496ad730b76b3fb2c10dcbc Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 26 Jun 2024 19:55:10 +0800 Subject: [PATCH 405/548] fix(common_components): unregister event handler if wifi disconnect and stop reconnecting --- .../include/protocol_examples_common.h | 32 +++++++++++++++++ .../protocol_examples_common/wifi_connect.c | 35 ++----------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/examples/common_components/protocol_examples_common/include/protocol_examples_common.h b/examples/common_components/protocol_examples_common/include/protocol_examples_common.h index fc2e54cd352..b23f452acc7 100644 --- a/examples/common_components/protocol_examples_common/include/protocol_examples_common.h +++ b/examples/common_components/protocol_examples_common/include/protocol_examples_common.h @@ -35,6 +35,38 @@ extern "C" { #define EXAMPLE_NETIF_DESC_PPP "example_netif_ppp" #endif +#if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST +#define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN +#elif CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL +#define EXAMPLE_WIFI_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN +#endif + +#if CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL +#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL +#elif CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY +#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY +#endif + +#if CONFIG_EXAMPLE_WIFI_AUTH_OPEN +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN +#elif CONFIG_EXAMPLE_WIFI_AUTH_WEP +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_ENTERPRISE +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK +#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK +#elif CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK +#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK +#endif + /* Example default interface, prefer the ethernet one if running in example-test (CI) configuration */ #if CONFIG_EXAMPLE_CONNECT_ETHERNET #define EXAMPLE_INTERFACE get_example_netif_from_desc(EXAMPLE_NETIF_DESC_ETH) diff --git a/examples/common_components/protocol_examples_common/wifi_connect.c b/examples/common_components/protocol_examples_common/wifi_connect.c index e4e14686887..ed95bccb2fe 100644 --- a/examples/common_components/protocol_examples_common/wifi_connect.c +++ b/examples/common_components/protocol_examples_common/wifi_connect.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -26,38 +26,6 @@ static SemaphoreHandle_t s_semph_get_ip_addrs = NULL; static SemaphoreHandle_t s_semph_get_ip6_addrs = NULL; #endif -#if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST -#define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN -#elif CONFIG_EXAMPLE_WIFI_SCAN_METHOD_ALL_CHANNEL -#define EXAMPLE_WIFI_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN -#endif - -#if CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL -#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL -#elif CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY -#define EXAMPLE_WIFI_CONNECT_AP_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY -#endif - -#if CONFIG_EXAMPLE_WIFI_AUTH_OPEN -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN -#elif CONFIG_EXAMPLE_WIFI_AUTH_WEP -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA_WPA2_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_ENTERPRISE -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_ENTERPRISE -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA3_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK -#elif CONFIG_EXAMPLE_WIFI_AUTH_WPA2_WPA3_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK -#elif CONFIG_EXAMPLE_WIFI_AUTH_WAPI_PSK -#define EXAMPLE_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK -#endif - static int s_retry_num = 0; static void example_handler_on_wifi_disconnect(void *arg, esp_event_base_t event_base, @@ -75,6 +43,7 @@ static void example_handler_on_wifi_disconnect(void *arg, esp_event_base_t event xSemaphoreGive(s_semph_get_ip6_addrs); } #endif + example_wifi_sta_do_disconnect(); return; } ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect..."); From 436b31be6e74f9f307ec3bd1a90af52afa2cf0db Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Mon, 22 Jul 2024 15:05:59 +0530 Subject: [PATCH 406/548] fix(nimble): Increase Timer stack size for nimble application --- examples/bluetooth/nimble/ble_htp/htp_prph/sdkconfig.defaults | 1 + examples/bluetooth/nimble/blehr/sdkconfig.defaults | 1 + examples/bluetooth/nimble/power_save/sdkconfig.defaults | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/bluetooth/nimble/ble_htp/htp_prph/sdkconfig.defaults b/examples/bluetooth/nimble/ble_htp/htp_prph/sdkconfig.defaults index c829fc5c002..09631ee6856 100644 --- a/examples/bluetooth/nimble/ble_htp/htp_prph/sdkconfig.defaults +++ b/examples/bluetooth/nimble/ble_htp/htp_prph/sdkconfig.defaults @@ -10,3 +10,4 @@ CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n CONFIG_BTDM_CTRL_MODE_BTDM=n CONFIG_BT_BLUEDROID_ENABLED=n CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4000 diff --git a/examples/bluetooth/nimble/blehr/sdkconfig.defaults b/examples/bluetooth/nimble/blehr/sdkconfig.defaults index c829fc5c002..09631ee6856 100644 --- a/examples/bluetooth/nimble/blehr/sdkconfig.defaults +++ b/examples/bluetooth/nimble/blehr/sdkconfig.defaults @@ -10,3 +10,4 @@ CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n CONFIG_BTDM_CTRL_MODE_BTDM=n CONFIG_BT_BLUEDROID_ENABLED=n CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4000 diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.defaults b/examples/bluetooth/nimble/power_save/sdkconfig.defaults index 8b57fab433b..7f51e2e7a5c 100644 --- a/examples/bluetooth/nimble/power_save/sdkconfig.defaults +++ b/examples/bluetooth/nimble/power_save/sdkconfig.defaults @@ -19,3 +19,4 @@ CONFIG_FREERTOS_USE_TICKLESS_IDLE=y CONFIG_FREERTOS_HZ=1000 # Minimum number of ticks to enter sleep mode for CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3 +CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=4000 From 2130416e2e5610dc54cb91b5804bdeff32642d7b Mon Sep 17 00:00:00 2001 From: aditi_lonkar Date: Mon, 6 Nov 2023 11:17:01 +0530 Subject: [PATCH 407/548] fix(wifi):Fix for setting wps status fail when connection fails --- .../esp_wifi/include/esp_wifi_types_generic.h | 1 + components/esp_wifi/lib | 2 +- .../esp_supplicant/src/esp_wpa_main.c | 6 +++++ .../esp_supplicant/src/esp_wps.c | 23 +++++++++++++++++++ .../esp_supplicant/src/esp_wps_i.h | 5 ++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/components/esp_wifi/include/esp_wifi_types_generic.h b/components/esp_wifi/include/esp_wifi_types_generic.h index 97bb8542ed5..d1ea00f9a2a 100644 --- a/components/esp_wifi/include/esp_wifi_types_generic.h +++ b/components/esp_wifi/include/esp_wifi_types_generic.h @@ -879,6 +879,7 @@ typedef struct { typedef enum { WPS_FAIL_REASON_NORMAL = 0, /**< WPS normal fail reason */ WPS_FAIL_REASON_RECV_M2D, /**< WPS receive M2D frame */ + WPS_FAIL_REASON_RECV_DEAUTH, /**< Recv deauth from AP while wps handshake */ WPS_FAIL_REASON_MAX } wifi_event_sta_wps_fail_reason_t; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 17509c30aec..7fbc7d9f5a2 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 17509c30aecde2c38bf4d3cc3e860b9297cf23e8 +Subproject commit 7fbc7d9f5a205177f28c4ce48e67d9eaa28908d8 diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c index 8dd2596ed76..7972a6c93f5 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wpa_main.c @@ -33,6 +33,7 @@ #include "esp_owe_i.h" #include "esp_wps.h" +#include "esp_wps_i.h" #include "eap_server/eap.h" #include "eapol_auth/eapol_auth_sm.h" #include "ap/ieee802_1x.h" @@ -303,6 +304,11 @@ static void wpa_sta_disconnected_cb(uint8_t reason_code) } break; } + + struct wps_sm_funcs *wps_sm_cb = wps_get_wps_sm_cb(); + if (wps_sm_cb && wps_sm_cb->wps_sm_notify_deauth) { + wps_sm_cb->wps_sm_notify_deauth(); + } #ifdef CONFIG_OWE_STA owe_deinit(); #endif /* CONFIG_OWE_STA */ diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c index 54a01e741b4..b68c2403c1d 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps.c +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps.c @@ -45,6 +45,7 @@ struct wps_rx_param { }; static STAILQ_HEAD(, wps_rx_param) s_wps_rxq; +static struct wps_sm_funcs *s_wps_sm_cb = NULL; static void *s_wps_task_hdl = NULL; static void *s_wps_queue = NULL; static void *s_wps_data_lock = NULL; @@ -839,6 +840,13 @@ int wps_finish(void) return ret; } +static void wps_sm_notify_deauth(void) +{ + if (gWpsSm && gWpsSm->wps->state != WPS_FINISHED) { + wps_stop_process(WPS_FAIL_REASON_RECV_DEAUTH); + } +} + /* Add current ap to discard ap list */ void wps_add_discard_ap(u8 *bssid) { @@ -1385,6 +1393,11 @@ int wps_init_cfg_pin(struct wps_config *cfg) return 0; } +struct wps_sm_funcs* wps_get_wps_sm_cb(void) +{ + return s_wps_sm_cb; +} + static int wifi_station_wps_init(const esp_wps_config_t *config) { struct wps_funcs *wps_cb; @@ -1466,6 +1479,12 @@ static int wifi_station_wps_init(const esp_wps_config_t *config) wps_cb->wps_start_pending = wps_start_pending; esp_wifi_set_wps_cb_internal(wps_cb); + s_wps_sm_cb = os_malloc(sizeof(struct wps_sm_funcs)); + if (s_wps_sm_cb == NULL) { + goto _err; + } + s_wps_sm_cb->wps_sm_notify_deauth = wps_sm_notify_deauth; + return ESP_OK; _err: @@ -1539,6 +1558,10 @@ wifi_station_wps_deinit(void) wps_deinit(sm->wps); sm->wps = NULL; } + if (s_wps_sm_cb) { + os_free(s_wps_sm_cb); + s_wps_sm_cb = NULL; + } os_free(gWpsSm); gWpsSm = NULL; diff --git a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h index a59dc897f95..4ffbb8b4ddf 100644 --- a/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h +++ b/components/wpa_supplicant/esp_supplicant/src/esp_wps_i.h @@ -118,6 +118,11 @@ int wps_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len); int wps_dev_deinit(struct wps_device_data *dev); int wps_dev_init(void); int wps_set_factory_info(const esp_wps_config_t *config); +struct wps_sm_funcs { + void (*wps_sm_notify_deauth)(void); +}; + +struct wps_sm_funcs* wps_get_wps_sm_cb(void); static inline int wps_get_type(void) { From 20932eceaf8efecd5ee79e9d31b1a9873868a908 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Tue, 28 May 2024 20:15:52 +0800 Subject: [PATCH 408/548] fix(wifi): annotate a rom function --- components/esp_rom/esp32c2/ld/esp32c2.rom.ld | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 +- components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld | 2 +- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld index 6d813e541d8..3079594ffad 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ld @@ -1517,7 +1517,7 @@ trc_SetTxAmpduState = 0x40001ccc; trc_tid_isTxAmpduOperational = 0x40001cd0; trcAmpduSetState = 0x40001cd4; wDevCheckBlockError = 0x40001cd8; -wDev_AppendRxBlocks = 0x40001cdc; +/*wDev_AppendRxBlocks = 0x40001cdc;*/ wDev_DiscardFrame = 0x40001ce0; wDev_GetNoiseFloor = 0x40001ce4; wDev_IndicateAmpdu = 0x40001ce8; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index 60c97f4923d..4fd9d58bb35 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -1623,7 +1623,7 @@ TRC_PER_IS_GOOD = 0x400017a4; trc_SetTxAmpduState = 0x400017a8; trc_tid_isTxAmpduOperational = 0x400017ac; trcAmpduSetState = 0x400017b0; -wDev_AppendRxBlocks = 0x400017b8; +/*wDev_AppendRxBlocks = 0x400017b8;*/ wDev_DiscardFrame = 0x400017bc; wDev_GetNoiseFloor = 0x400017c0; wDev_IndicateAmpdu = 0x400017c4; diff --git a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld index 30dedb924c6..24ae23143f0 100644 --- a/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld +++ b/components/esp_rom/esp32c6/ld/esp32c6.rom.pp.ld @@ -145,7 +145,7 @@ trc_SetTxAmpduState = 0x40000dc4; trc_tid_isTxAmpduOperational = 0x40000dc8; trcAmpduSetState = 0x40000dcc; //wDevCheckBlockError = 0x40000dd0; -wDev_AppendRxBlocks = 0x40000dd4; +/*wDev_AppendRxBlocks = 0x40000dd4;*/ wDev_DiscardFrame = 0x40000dd8; wDev_GetNoiseFloor = 0x40000ddc; wDev_IndicateAmpdu = 0x40000de0; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 9f23d00f6b9..8fbddf7f02e 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -1904,7 +1904,7 @@ trc_SetTxAmpduState = 0x40005838; trc_tid_isTxAmpduOperational = 0x40005844; trcAmpduSetState = 0x40005850; wDevCheckBlockError = 0x4000585c; -wDev_AppendRxBlocks = 0x40005868; +/*wDev_AppendRxBlocks = 0x40005868;*/ wDev_DiscardFrame = 0x40005874; wDev_GetNoiseFloor = 0x40005880; wDev_IndicateAmpdu = 0x4000588c; From 9e0064ba208caaf761a8530c516f2ede1236e3fc Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Mon, 8 Jul 2024 14:01:31 +0800 Subject: [PATCH 409/548] fix(wifi/mesh): fix the issue that xon request timeout constantly when root reboot Closes https://github.com/espressif/esp-idf/issues/13212 --- components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- components/esp_wifi/lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld index 7c961407ced..3a6126a9079 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld @@ -142,7 +142,7 @@ pm_extend_tbtt_adaptive_servo = 0x40000dc8; /*pm_scale_listen_interval = 0x40000dcc;*/ pm_parse_mbssid_element = 0x40000dd0; pm_disconnected_wake = 0x40000dd4; -pm_tx_data_process = 0x40000dd8; +/*pm_tx_data_process = 0x40000dd8;*/ pm_is_twt_awake = 0x40000ddc; pm_enable_twt_keep_alive = 0x40000de0; pm_twt_on_tsf_timer = 0x40000de4; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 7fbc7d9f5a2..d61cf9d3dd5 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 7fbc7d9f5a205177f28c4ce48e67d9eaa28908d8 +Subproject commit d61cf9d3dd5ea1f080034335170b8b01be35bcb3 From 1191a9e1c5e3d968f0dddd5ad0c166be32d517cb Mon Sep 17 00:00:00 2001 From: Shreyas Sheth Date: Wed, 19 Jun 2024 17:10:19 +0530 Subject: [PATCH 410/548] fix(wifi): Ignore 11R, ENT AP when disabled in sdkconfig --- components/esp_wifi/include/esp_wifi.h | 18 +++++++++++++++++- components/esp_wifi/lib | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/components/esp_wifi/include/esp_wifi.h b/components/esp_wifi/include/esp_wifi.h index b9589ad70d0..7f8cde1c859 100644 --- a/components/esp_wifi/include/esp_wifi.h +++ b/components/esp_wifi/include/esp_wifi.h @@ -254,6 +254,18 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define WIFI_ENABLE_GMAC 0 #endif +#if CONFIG_ESP_WIFI_11R_SUPPORT +#define WIFI_ENABLE_11R (1<<6) +#else +#define WIFI_ENABLE_11R 0 +#endif + +#if CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT +#define WIFI_ENABLE_ENTERPRISE (1<<7) +#else +#define WIFI_ENABLE_ENTERPRISE 0 +#endif + #if CONFIG_ESP_WIFI_ENABLE_DUMP_HESIGB && !WIFI_CSI_ENABLED #define WIFI_DUMP_HESIGB_ENABLED true #else @@ -272,6 +284,8 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; #define CONFIG_FEATURE_FTM_RESPONDER_BIT (1<<3) #define CONFIG_FEATURE_GCMP_BIT (1<<4) #define CONFIG_FEATURE_GMAC_BIT (1<<5) +#define CONFIG_FEATURE_11R_BIT (1<<6) +#define CONFIG_FEATURE_WIFI_ENT_BIT (1<<7) /* Set additional WiFi features and capabilities */ #define WIFI_FEATURE_CAPS (WIFI_ENABLE_WPA3_SAE | \ @@ -279,7 +293,9 @@ extern wifi_osi_funcs_t g_wifi_osi_funcs; WIFI_FTM_INITIATOR | \ WIFI_FTM_RESPONDER | \ WIFI_ENABLE_GCMP | \ - WIFI_ENABLE_GMAC) + WIFI_ENABLE_GMAC | \ + WIFI_ENABLE_11R | \ + WIFI_ENABLE_ENTERPRISE) #define WIFI_INIT_CONFIG_DEFAULT() { \ .osi_funcs = &g_wifi_osi_funcs, \ diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index d61cf9d3dd5..4097d081951 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit d61cf9d3dd5ea1f080034335170b8b01be35bcb3 +Subproject commit 4097d0819517d34a6977d4159f5a1fb8a8a8ebdd From 6bb959e7ee011b85748d2a512a57c94cb0e9cf1c Mon Sep 17 00:00:00 2001 From: "wangtao@espressif.com" Date: Wed, 10 Jul 2024 10:51:44 +0800 Subject: [PATCH 411/548] fix(wifi):fix get softap dtim and csa config err --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 4097d081951..17ffa928bbe 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 4097d0819517d34a6977d4159f5a1fb8a8a8ebdd +Subproject commit 17ffa928bbe8364a13689a77691bd1dbf294e211 From ecde808af9a3cc66994e04eb1d15246515ea38c2 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Wed, 10 Jul 2024 16:43:54 +0800 Subject: [PATCH 412/548] fix(wifi): fixed association refused temporarily issue 1. fixed association refused temporarily issue. 2. give some information when password length mismatch authmode threshold --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 17ffa928bbe..08b353273e9 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 17ffa928bbe8364a13689a77691bd1dbf294e211 +Subproject commit 08b353273e9190e1f8340b04b63d032c1f2c5516 From 240d300d6484a301347dda3b57a797ce00aa1e58 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Wed, 10 Jul 2024 20:37:50 +0800 Subject: [PATCH 413/548] fix(wifi): fix reset connection dns fail issue Closes https://github.com/espressif/esp-idf/issues/12315 --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 08b353273e9..74f99e08335 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 08b353273e9190e1f8340b04b63d032c1f2c5516 +Subproject commit 74f99e08335671447b5eac243c8dd643c1405a63 From b072ccac62769c23f9a2a811b74ac8f8fedaf429 Mon Sep 17 00:00:00 2001 From: muhaidong Date: Fri, 12 Jul 2024 17:51:35 +0800 Subject: [PATCH 414/548] fix(wifi): fix sta may join bad signal ap when set by signal Closes https://github.com/espressif/esp-idf/issues/13958 --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 74f99e08335..76bdd0b967a 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 74f99e08335671447b5eac243c8dd643c1405a63 +Subproject commit 76bdd0b967afa7d75c9466ab0ad05601418a074d From 9db556c20e7290072d6ec9b21092dce7e030b1f1 Mon Sep 17 00:00:00 2001 From: sibeibei Date: Mon, 15 Jul 2024 16:20:01 +0800 Subject: [PATCH 415/548] fix(pm): ssn update failed when dut wakeup from lightsleep --- components/esp_wifi/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index 76bdd0b967a..eff8552fc2c 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit 76bdd0b967afa7d75c9466ab0ad05601418a074d +Subproject commit eff8552fc2c890de9304250192e542d7a38c3480 From 2c4812092d7d43f27d1edd9744bf0e721846056d Mon Sep 17 00:00:00 2001 From: liuning Date: Fri, 19 Jul 2024 19:23:58 +0800 Subject: [PATCH 416/548] fix(coex): fix esp32 crash issue, fix esp32c6 rx issue --- components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld | 2 +- components/esp_wifi/lib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld index 3a6126a9079..54d3ae9e75f 100644 --- a/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld +++ b/components/esp_rom/esp32c5/mp/esp32c5/ld/esp32c5.rom.pp.ld @@ -260,7 +260,7 @@ trcAmpduSetState = 0x40000fa0; trc_set_bf_report_rate = 0x40000fa4; trc_onPPTxDone = 0x40000fa8; wDevCheckBlockError = 0x40000fac; -wDev_AppendRxBlocks = 0x40000fb0; +/*wDev_AppendRxBlocks = 0x40000fb0;*/ wDev_DiscardFrame = 0x40000fb4; wDev_GetNoiseFloor = 0x40000fb8; wDev_IndicateAmpdu = 0x40000fbc; diff --git a/components/esp_wifi/lib b/components/esp_wifi/lib index eff8552fc2c..ce181b3e947 160000 --- a/components/esp_wifi/lib +++ b/components/esp_wifi/lib @@ -1 +1 @@ -Subproject commit eff8552fc2c890de9304250192e542d7a38c3480 +Subproject commit ce181b3e947d3d8495c17b9881930816bb94ed58 From 715516eea5a8327e9e6f2b6fcbf6b3fe279200c8 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 23 Jul 2024 10:50:14 +0800 Subject: [PATCH 417/548] fix(camera): fixed c2m cache ops --- components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 2 +- components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 21b09869dc1..ebfcdb3fccc 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -350,7 +350,7 @@ IRAM_ATTR static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, dw_gdma_channel_enable_ctrl(chan, true); if ((ctlr->trans.buffer != ctlr->backup_buffer) || ctlr->bk_buffer_exposed) { - esp_err_t ret = esp_cache_msync((void *)(ctlr->trans.buffer), ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); + esp_err_t ret = esp_cache_msync((void *)(ctlr->trans.buffer), ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); assert(ret == ESP_OK); assert(ctlr->cbs.on_trans_finished); if (ctlr->cbs.on_trans_finished) { diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c index 852b35aba1f..10446d3749c 100644 --- a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -469,7 +469,7 @@ IRAM_ATTR static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t cha dw_gdma_channel_enable_ctrl(chan, true); if ((dvp_ctlr->trans.buffer != dvp_ctlr->backup_buffer) || dvp_ctlr->bk_buffer_exposed) { - esp_err_t ret = esp_cache_msync((void *)(dvp_ctlr->trans.buffer), dvp_ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE); + esp_err_t ret = esp_cache_msync((void *)(dvp_ctlr->trans.buffer), dvp_ctlr->trans.received_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); assert(ret == ESP_OK); assert(dvp_ctlr->cbs.on_trans_finished); if (dvp_ctlr->cbs.on_trans_finished) { From 40b3f88dfb5e4aab24721774517888f86277769c Mon Sep 17 00:00:00 2001 From: linruihao Date: Fri, 12 Jul 2024 15:00:09 +0800 Subject: [PATCH 418/548] fix(coex): Fixed coexist scheme phase index overflow issue --- components/esp_coex/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_coex/lib b/components/esp_coex/lib index 56d324c3fe3..d99dfd1883a 160000 --- a/components/esp_coex/lib +++ b/components/esp_coex/lib @@ -1 +1 @@ -Subproject commit 56d324c3fe3fb7649f8736bbb3b9f00b7f612449 +Subproject commit d99dfd1883a1468b8986362a1382a4f46e918b60 From d8798c4bd55fe7a17cec136d2424c2811b6918c0 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Wed, 17 Jul 2024 11:42:04 +0800 Subject: [PATCH 419/548] fix(ble/bluedroid): Fixed BLE cannot create connection --- components/bt/host/bluedroid/bta/dm/bta_dm_act.c | 4 ++++ components/bt/host/bluedroid/stack/btm/btm_ble_gap.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index ba5e8f02bca..ec2ce657fd9 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -5419,6 +5419,10 @@ void bta_dm_ble_scan (tBTA_DM_MSG *p_data) status = (status == BTM_CMD_STARTED ? BTA_SUCCESS : BTA_FAILURE); p_data->ble_scan.p_stop_scan_cback(status); } + + // reset BLE scan link state when stop scan + btm_ble_clear_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT); + btm_ble_clear_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index df24fa08977..e843aa391a6 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -4003,6 +4003,9 @@ static void btm_ble_stop_discover(void) if(btsnd_hcic_ble_set_scan_enable (BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE)) { osi_sem_take(&scan_enable_sem, OSI_SEM_MAX_TIMEOUT); } + /* reset status */ + btm_ble_clear_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT); + btm_ble_clear_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT); } if (p_scan_cb) { From c14eae95cd664fd89c66029a721d385ba00c6cd8 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Fri, 29 Mar 2024 21:29:01 +0800 Subject: [PATCH 420/548] refactor(usb/host): Refactor USBH function grouping This commit rearranges the USBH functions into new groupings to provide a clearer abstraction. This is in preparation for refactoring/removing the Hub related functions in the USBH API. This commit DOES NOT MAKE ANY BEHAVIORAL CHANGES to the code. Functions are now grouped into... - USBH Processing: Functions dealing with overall USBH processing - Device Pool: Functions that add/remove/open/close devices from the internal device pool - Device: Functions that pertain to setting/getting a particular device - Endpoints: Functions that pertain to a particular endpoint - Transfer: Functions that pertain to sending transfers --- components/usb/private_include/usbh.h | 88 ++++++------ components/usb/usbh.c | 196 +++++++++++++------------- 2 files changed, 144 insertions(+), 140 deletions(-) diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index 75be2b1f668..fe80799f873 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -130,7 +130,7 @@ typedef struct { void *event_cb_arg; /**< USBH event callback argument */ } usbh_config_t; -// ------------------------------------------------- USBH Functions ---------------------------------------------------- +// -------------------------------------------- USBH Processing Functions ---------------------------------------------- /** * @brief Installs the USBH driver @@ -169,6 +169,8 @@ esp_err_t usbh_uninstall(void); */ esp_err_t usbh_process(void); +// ---------------------------------------------- Device Pool Functions ------------------------------------------------ + /** * @brief Get the current number of devices * @@ -178,10 +180,6 @@ esp_err_t usbh_process(void); */ esp_err_t usbh_num_devs(int *num_devs_ret); -// ------------------------------------------------ Device Functions --------------------------------------------------- - -// --------------------- Device Pool ----------------------- - /** * @brief Fill list with address of currently connected devices * @@ -197,6 +195,17 @@ esp_err_t usbh_num_devs(int *num_devs_ret); */ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret); +/** + * @brief Mark that all devices should be freed at the next possible opportunity + * + * A device marked as free will not be freed until the last client using the device has called usbh_dev_close() + * + * @return + * - ESP_OK: There were no devices to free to begin with. Current state is all free + * - ESP_ERR_NOT_FINISHED: One or more devices still need to be freed (but have been marked "to be freed") + */ +esp_err_t usbh_dev_mark_all_free(void); + /** * @brief Open a device by address * @@ -218,18 +227,9 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl); */ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl); -/** - * @brief Mark that all devices should be freed at the next possible opportunity - * - * A device marked as free will not be freed until the last client using the device has called usbh_dev_close() - * - * @return - * - ESP_OK: There were no devices to free to begin with. Current state is all free - * - ESP_ERR_NOT_FINISHED: One or more devices still need to be freed (but have been marked "to be freed") - */ -esp_err_t usbh_dev_mark_all_free(void); +// ------------------------------------------------ Device Functions --------------------------------------------------- -// ------------------- Single Device ---------------------- +// ----------------------- Getters ------------------------- /** * @brief Get a device's address @@ -275,15 +275,6 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t */ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc_ret); -/** - * @brief Submit a control transfer (URB) to a device - * - * @param[in] dev_hdl Device handle - * @param[in] urb URB - * @return esp_err_t - */ -esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb); - // ----------------------------------------------- Endpoint Functions ------------------------------------------------- /** @@ -335,49 +326,60 @@ esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl); esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, usbh_ep_handle_t *ep_hdl_ret); /** - * @brief Enqueue a URB to an endpoint + * @brief Execute a command on a particular endpoint * - * The URB will remain enqueued until it completes (successfully or errors out). Use usbh_ep_dequeue_urb() to dequeue - * a completed URB. + * Endpoint commands allows executing a certain action on an endpoint (e.g., halting, flushing, clearing etc) * * @param[in] ep_hdl Endpoint handle - * @param[in] urb URB to enqueue + * @param[in] command Endpoint command * @return esp_err_t */ -esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb); +esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command); /** - * @brief Dequeue a URB from an endpoint + * @brief Get the context of an endpoint * - * Dequeue a completed URB from an endpoint. The USBH_EP_EVENT_URB_DONE indicates that URBs can be dequeued + * Get the context variable assigned to and endpoint on allocation. * + * @note This function can block * @param[in] ep_hdl Endpoint handle - * @param[out] urb_ret Dequeued URB, or NULL if no more URBs to dequeue + * @return Endpoint context + */ +void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl); + +// ----------------------------------------------- Transfer Functions -------------------------------------------------- + +/** + * @brief Submit a control transfer (URB) to a device + * + * @param[in] dev_hdl Device handle + * @param[in] urb URB * @return esp_err_t */ -esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret); +esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb); /** - * @brief Execute a command on a particular endpoint + * @brief Enqueue a URB to an endpoint * - * Endpoint commands allows executing a certain action on an endpoint (e.g., halting, flushing, clearing etc) + * The URB will remain enqueued until it completes (successfully or errors out). Use usbh_ep_dequeue_urb() to dequeue + * a completed URB. * * @param[in] ep_hdl Endpoint handle - * @param[in] command Endpoint command + * @param[in] urb URB to enqueue * @return esp_err_t */ -esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command); +esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb); /** - * @brief Get the context of an endpoint + * @brief Dequeue a URB from an endpoint * - * Get the context variable assigned to and endpoint on allocation. + * Dequeue a completed URB from an endpoint. The USBH_EP_EVENT_URB_DONE indicates that URBs can be dequeued * - * @note This function can block * @param[in] ep_hdl Endpoint handle - * @return Endpoint context + * @param[out] urb_ret Dequeued URB, or NULL if no more URBs to dequeue + * @return esp_err_t */ -void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl); +esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret); // -------------------------------------------------- Hub Functions ---------------------------------------------------- diff --git a/components/usb/usbh.c b/components/usb/usbh.c index a50f4fc9444..26daf4a3fff 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -561,7 +561,7 @@ static inline void handle_prop_new_dev(device_t *dev_obj) p_usbh_obj->constant.event_cb(&event_data, p_usbh_obj->constant.event_cb_arg); } -// ------------------------------------------------- USBH Functions ---------------------------------------------------- +// -------------------------------------------- USBH Processing Functions ---------------------------------------------- esp_err_t usbh_install(const usbh_config_t *usbh_config) { @@ -700,6 +700,8 @@ esp_err_t usbh_process(void) return ESP_OK; } +// ---------------------------------------------- Device Pool Functions ------------------------------------------------ + esp_err_t usbh_num_devs(int *num_devs_ret) { USBH_CHECK(num_devs_ret != NULL, ESP_ERR_INVALID_ARG); @@ -709,10 +711,6 @@ esp_err_t usbh_num_devs(int *num_devs_ret) return ESP_OK; } -// ------------------------------------------------ Device Functions --------------------------------------------------- - -// --------------------- Device Pool ----------------------- - esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret) { USBH_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG); @@ -743,6 +741,48 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num return ESP_OK; } +esp_err_t usbh_dev_mark_all_free(void) +{ + USBH_ENTER_CRITICAL(); + /* + Go through the device list and mark each device as waiting to be closed. If the device is not opened at all, we can + disable it immediately. + Note: We manually traverse the list because we need to add/remove items while traversing + */ + bool call_proc_req_cb = false; + bool wait_for_free = false; + for (int i = 0; i < 2; i++) { + device_t *dev_obj_cur; + device_t *dev_obj_next; + // Go through pending list first as it's more efficient + if (i == 0) { + dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); + } else { + dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq); + } + while (dev_obj_cur != NULL) { + // Keep a copy of the next item first in case we remove the current item + dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry); + if (dev_obj_cur->dynamic.ref_count == 0) { + // Device is not referenced. Can free immediately. + call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_FREE); + } else { + // Device is still referenced. Just mark it as waiting to be freed + dev_obj_cur->dynamic.flags.waiting_free = 1; + } + // At least one device needs to be freed. User needs to wait for USBH_EVENT_ALL_FREE event + wait_for_free = true; + dev_obj_cur = dev_obj_next; + } + } + USBH_EXIT_CRITICAL(); + + if (call_proc_req_cb) { + p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); + } + return (wait_for_free) ? ESP_ERR_NOT_FINISHED : ESP_OK; +} + esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) { USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); @@ -808,49 +848,9 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) return ESP_OK; } -esp_err_t usbh_dev_mark_all_free(void) -{ - USBH_ENTER_CRITICAL(); - /* - Go through the device list and mark each device as waiting to be closed. If the device is not opened at all, we can - disable it immediately. - Note: We manually traverse the list because we need to add/remove items while traversing - */ - bool call_proc_req_cb = false; - bool wait_for_free = false; - for (int i = 0; i < 2; i++) { - device_t *dev_obj_cur; - device_t *dev_obj_next; - // Go through pending list first as it's more efficient - if (i == 0) { - dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); - } else { - dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq); - } - while (dev_obj_cur != NULL) { - // Keep a copy of the next item first in case we remove the current item - dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry); - if (dev_obj_cur->dynamic.ref_count == 0) { - // Device is not referenced. Can free immediately. - call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_FREE); - } else { - // Device is still referenced. Just mark it as waiting to be freed - dev_obj_cur->dynamic.flags.waiting_free = 1; - } - // At least one device needs to be freed. User needs to wait for USBH_EVENT_ALL_FREE event - wait_for_free = true; - dev_obj_cur = dev_obj_next; - } - } - USBH_EXIT_CRITICAL(); - - if (call_proc_req_cb) { - p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); - } - return (wait_for_free) ? ESP_ERR_NOT_FINISHED : ESP_OK; -} +// ------------------------------------------------ Device Functions --------------------------------------------------- -// ------------------- Single Device ---------------------- +// ----------------------- Getters ------------------------- esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr) { @@ -928,40 +928,7 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config return ret; } -esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb) -{ - USBH_CHECK(dev_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - USBH_CHECK(urb_check_args(urb), ESP_ERR_INVALID_ARG); - bool xfer_is_in = ((usb_setup_packet_t *)urb->transfer.data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; - USBH_CHECK(transfer_check_usb_compliance(&(urb->transfer), USB_TRANSFER_TYPE_CTRL, dev_obj->constant.desc->bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG); - - USBH_ENTER_CRITICAL(); - USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); - // Increment the control transfer count first - dev_obj->dynamic.num_ctrl_xfers_inflight++; - USBH_EXIT_CRITICAL(); - - esp_err_t ret; - if (hcd_pipe_get_state(dev_obj->constant.default_pipe) != HCD_PIPE_STATE_ACTIVE) { - ret = ESP_ERR_INVALID_STATE; - goto hcd_err; - } - ret = hcd_urb_enqueue(dev_obj->constant.default_pipe, urb); - if (ret != ESP_OK) { - goto hcd_err; - } - ret = ESP_OK; - return ret; - -hcd_err: - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.num_ctrl_xfers_inflight--; - USBH_EXIT_CRITICAL(); - return ret; -} - -// ----------------------------------------------- Interface Functions ------------------------------------------------- +// ----------------------------------------------- Endpoint Functions ------------------------------------------------- esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, usbh_ep_handle_t *ep_hdl_ret) { @@ -1074,6 +1041,57 @@ esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddre return ret; } +esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command) +{ + USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); + + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + // Send the command to the EP's underlying pipe + return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command); +} + +void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl) +{ + assert(ep_hdl); + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + return hcd_pipe_get_context(ep_obj->constant.pipe_hdl); +} + +// ----------------------------------------------- Transfer Functions -------------------------------------------------- + +esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb) +{ + USBH_CHECK(dev_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG); + device_t *dev_obj = (device_t *)dev_hdl; + USBH_CHECK(urb_check_args(urb), ESP_ERR_INVALID_ARG); + bool xfer_is_in = ((usb_setup_packet_t *)urb->transfer.data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; + USBH_CHECK(transfer_check_usb_compliance(&(urb->transfer), USB_TRANSFER_TYPE_CTRL, dev_obj->constant.desc->bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG); + + USBH_ENTER_CRITICAL(); + USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); + // Increment the control transfer count first + dev_obj->dynamic.num_ctrl_xfers_inflight++; + USBH_EXIT_CRITICAL(); + + esp_err_t ret; + if (hcd_pipe_get_state(dev_obj->constant.default_pipe) != HCD_PIPE_STATE_ACTIVE) { + ret = ESP_ERR_INVALID_STATE; + goto hcd_err; + } + ret = hcd_urb_enqueue(dev_obj->constant.default_pipe, urb); + if (ret != ESP_OK) { + goto hcd_err; + } + ret = ESP_OK; + return ret; + +hcd_err: + USBH_ENTER_CRITICAL(); + dev_obj->dynamic.num_ctrl_xfers_inflight--; + USBH_EXIT_CRITICAL(); + return ret; +} + esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb) { USBH_CHECK(ep_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG); @@ -1104,22 +1122,6 @@ esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret) return ESP_OK; } -esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command) -{ - USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); - - endpoint_t *ep_obj = (endpoint_t *)ep_hdl; - // Send the command to the EP's underlying pipe - return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command); -} - -void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl) -{ - assert(ep_hdl); - endpoint_t *ep_obj = (endpoint_t *)ep_hdl; - return hcd_pipe_get_context(ep_obj->constant.pipe_hdl); -} - // -------------------------------------------------- Hub Functions ---------------------------------------------------- // ------------------- Device Related ---------------------- From 8aa9a42f2b9a89647aefc16bd5e7b109e8d5f7d8 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 3 Apr 2024 11:24:03 +0800 Subject: [PATCH 421/548] refactor(usb/usbh): Rename device pool functions and ref_count This commit renames the following APIs and variables in the USBH: - Rename the prefix of device pool functions from 'usbh_dev_...' to 'usbh_devs_...'. - Rename 'ref_count' to 'open_count'. This variable tracks the number of times a device has been opened. --- components/usb/private_include/usbh.h | 18 +++++++------- components/usb/usb_host.c | 12 +++++----- components/usb/usbh.c | 34 +++++++++++++-------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index fe80799f873..6dee5e55b4e 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -178,13 +178,13 @@ esp_err_t usbh_process(void); * @param[out] num_devs_ret Current number of devices * @return esp_err_t */ -esp_err_t usbh_num_devs(int *num_devs_ret); +esp_err_t usbh_devs_num(int *num_devs_ret); /** * @brief Fill list with address of currently connected devices * * - This function fills the provided list with the address of current connected devices - * - Device address can then be used in usbh_dev_open() + * - Device address can then be used in usbh_devs_open() * - If there are more devices than the list_len, this function will only fill * up to list_len number of devices. * @@ -193,18 +193,18 @@ esp_err_t usbh_num_devs(int *num_devs_ret); * @param[out] num_dev_ret Number of devices filled into list * @return esp_err_t */ -esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret); +esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret); /** * @brief Mark that all devices should be freed at the next possible opportunity * - * A device marked as free will not be freed until the last client using the device has called usbh_dev_close() + * A device marked as free will not be freed until the last client using the device has called usbh_devs_close() * * @return * - ESP_OK: There were no devices to free to begin with. Current state is all free * - ESP_ERR_NOT_FINISHED: One or more devices still need to be freed (but have been marked "to be freed") */ -esp_err_t usbh_dev_mark_all_free(void); +esp_err_t usbh_devs_mark_all_free(void); /** * @brief Open a device by address @@ -215,17 +215,17 @@ esp_err_t usbh_dev_mark_all_free(void); * @param[out] dev_hdl Device handle * @return esp_err_t */ -esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl); +esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl); /** * @brief CLose a device * - * Device can be opened by calling usbh_dev_open() + * Device can be opened by calling usbh_devs_open() * * @param[in] dev_hdl Device handle * @return esp_err_t */ -esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl); +esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl); // ------------------------------------------------ Device Functions --------------------------------------------------- @@ -282,7 +282,7 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config * * This function allows clients to allocate a non-default endpoint (i.e., not EP0) on a connected device * - * - A client must have opened the device using usbh_dev_open() before attempting to allocate an endpoint on the device + * - A client must have opened the device using usbh_devs_open() before attempting to allocate an endpoint on the device * - A client should call this function to allocate all endpoints in an interface that the client has claimed. * - A client must allocate an endpoint using this function before attempting to communicate with it * - Once the client allocates an endpoint, the client is now owns/manages the endpoint. No other client should use or diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index 11fd7810aa8..b9b12dafcc5 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -574,7 +574,7 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret) HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE); num_clients_temp = p_host_lib_obj->dynamic.flags.num_clients; HOST_EXIT_CRITICAL(); - usbh_num_devs(&num_devs_temp); + usbh_devs_num(&num_devs_temp); // Write back return values info_ret->num_devices = num_devs_temp; @@ -820,7 +820,7 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_ esp_err_t ret; usb_device_handle_t dev_hdl; - ret = usbh_dev_open(dev_addr, &dev_hdl); + ret = usbh_devs_open(dev_addr, &dev_hdl); if (ret != ESP_OK) { goto exit; } @@ -841,7 +841,7 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_ return ret; already_opened: - ESP_ERROR_CHECK(usbh_dev_close(dev_hdl)); + ESP_ERROR_CHECK(usbh_devs_close(dev_hdl)); exit: return ret; } @@ -883,7 +883,7 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_ _clear_client_opened_device(client_obj, dev_addr); HOST_EXIT_CRITICAL(); - ESP_ERROR_CHECK(usbh_dev_close(dev_hdl)); + ESP_ERROR_CHECK(usbh_devs_close(dev_hdl)); ret = ESP_OK; exit: xSemaphoreGive(p_host_lib_obj->constant.mux_lock); @@ -896,7 +896,7 @@ esp_err_t usb_host_device_free_all(void) HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); // All clients must have been deregistered HOST_EXIT_CRITICAL(); esp_err_t ret; - ret = usbh_dev_mark_all_free(); + ret = usbh_devs_mark_all_free(); // If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free return ret; } @@ -904,7 +904,7 @@ esp_err_t usb_host_device_free_all(void) esp_err_t usb_host_device_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret) { HOST_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG); - return usbh_dev_addr_list_fill(list_len, dev_addr_list, num_dev_ret); + return usbh_devs_addr_list_fill(list_len, dev_addr_list, num_dev_ret); } // ------------------------------------------------- Device Requests --------------------------------------------------- diff --git a/components/usb/usbh.c b/components/usb/usbh.c index 26daf4a3fff..06d6f8d942e 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -64,7 +64,7 @@ struct device_s { uint32_t action_flags; int num_ctrl_xfers_inflight; usb_device_state_t state; - uint32_t ref_count; + uint32_t open_count; } dynamic; // Mux protected members must be protected by the USBH mux_lock when accessed struct { @@ -702,7 +702,7 @@ esp_err_t usbh_process(void) // ---------------------------------------------- Device Pool Functions ------------------------------------------------ -esp_err_t usbh_num_devs(int *num_devs_ret) +esp_err_t usbh_devs_num(int *num_devs_ret) { USBH_CHECK(num_devs_ret != NULL, ESP_ERR_INVALID_ARG); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); @@ -711,7 +711,7 @@ esp_err_t usbh_num_devs(int *num_devs_ret) return ESP_OK; } -esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret) +esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret) { USBH_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG); USBH_ENTER_CRITICAL(); @@ -741,7 +741,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num return ESP_OK; } -esp_err_t usbh_dev_mark_all_free(void) +esp_err_t usbh_devs_mark_all_free(void) { USBH_ENTER_CRITICAL(); /* @@ -763,11 +763,11 @@ esp_err_t usbh_dev_mark_all_free(void) while (dev_obj_cur != NULL) { // Keep a copy of the next item first in case we remove the current item dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry); - if (dev_obj_cur->dynamic.ref_count == 0) { - // Device is not referenced. Can free immediately. + if (dev_obj_cur->dynamic.open_count == 0) { + // Device is not opened. Can free immediately. call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_FREE); } else { - // Device is still referenced. Just mark it as waiting to be freed + // Device is still opened. Just mark it as waiting to be freed dev_obj_cur->dynamic.flags.waiting_free = 1; } // At least one device needs to be freed. User needs to wait for USBH_EVENT_ALL_FREE event @@ -783,7 +783,7 @@ esp_err_t usbh_dev_mark_all_free(void) return (wait_for_free) ? ESP_ERR_NOT_FINISHED : ESP_OK; } -esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) +esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) { USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); esp_err_t ret; @@ -806,11 +806,11 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) } exit: if (found_dev_obj != NULL) { - // The device is not in a state to be referenced + // The device is not in a state to be opened if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_free) { ret = ESP_ERR_INVALID_STATE; } else { - dev_obj->dynamic.ref_count++; + dev_obj->dynamic.open_count++; *dev_hdl = (usb_device_handle_t)found_dev_obj; ret = ESP_OK; } @@ -822,18 +822,18 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) return ret; } -esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) +esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl) { USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; USBH_ENTER_CRITICAL(); - dev_obj->dynamic.ref_count--; + dev_obj->dynamic.open_count--; bool call_proc_req_cb = false; - if (dev_obj->dynamic.ref_count == 0) { + if (dev_obj->dynamic.open_count == 0) { // Sanity check. assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); // There cannot be any control transfer in-flight - assert(!dev_obj->dynamic.flags.waiting_free); // This can only be set when ref count reaches 0 + assert(!dev_obj->dynamic.flags.waiting_free); // This can only be set when open_count reaches 0 if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_free) { // Device is already gone or is awaiting to be freed. Trigger the USBH process to free the device call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); @@ -1152,11 +1152,11 @@ esp_err_t usbh_hub_dev_gone(usb_device_handle_t dev_hdl) USBH_ENTER_CRITICAL(); dev_obj->dynamic.flags.is_gone = 1; // Check if the device can be freed immediately - if (dev_obj->dynamic.ref_count == 0) { - // Device is not currently referenced at all. Can free immediately. + if (dev_obj->dynamic.open_count == 0) { + // Device is not currently opened at all. Can free immediately. call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); } else { - // Device is still being referenced. Flush endpoints and propagate device gone event + // Device is still opened. Flush endpoints and propagate device gone event call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_EPn_HALT_FLUSH | DEV_ACTION_EP0_FLUSH | From 3358f3ec467fdb5fb020128656fbac177e9e43c6 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 3 Apr 2024 19:23:47 +0800 Subject: [PATCH 422/548] refactor(usb/hcd): Allow port resets with allocated pipes This commit updates the HCD API to allow port resets to occur even if pipes are allocated. The pipes cannot be active and the port reset will simply restore the pipes (by reinitializing their channel registers) following the reset. Changes: - Allow port resets while channels are allocated - Remove pipe persistance API 'hcd_pipe_set_persist_reset()' --- components/hal/include/hal/usb_dwc_hal.h | 17 ++- components/usb/hcd_dwc.c | 167 +++++++---------------- components/usb/hub.c | 1 - components/usb/private_include/hcd.h | 14 -- 4 files changed, 54 insertions(+), 145 deletions(-) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index 9b2a2c3bc30..33ac57be75e 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -205,7 +205,7 @@ typedef struct { * - The peripheral must have been reset and clock un-gated * - The USB PHY (internal or external) and associated GPIOs must already be configured * - GPIO pins configured - * - Interrupt allocated but DISABLED (in case of an unknown interupt state) + * - Interrupt allocated but DISABLED (in case of an unknown interrupt state) * Exit: * - Checks to see if DWC_OTG is alive, and if HW version/config is correct * - HAl context initialized @@ -290,7 +290,7 @@ static inline void usb_dwc_hal_port_init(usb_dwc_hal_context_t *hal) /** * @brief Deinitialize the host port * - * - Will disable the host port's interrupts preventing further port aand channel events from ocurring + * - Will disable the host port's interrupts preventing further port aand channel events from occurring * * @param hal Context of the HAL layer */ @@ -333,7 +333,6 @@ static inline void usb_dwc_hal_port_toggle_power(usb_dwc_hal_context_t *hal, boo */ static inline void usb_dwc_hal_port_toggle_reset(usb_dwc_hal_context_t *hal, bool enable) { - HAL_ASSERT(hal->channels.num_allocd == 0); //Cannot reset if there are still allocated channels usb_dwc_ll_hprt_set_port_reset(hal->dev, enable); } @@ -447,7 +446,7 @@ static inline void usb_dwc_hal_port_periodic_enable(usb_dwc_hal_context_t *hal) /** * @brief Disable periodic scheduling * - * Disabling periodic scheduling will save a bit of DMA bandwith (as the controller will no longer fetch the schedule + * Disabling periodic scheduling will save a bit of DMA bandwidth (as the controller will no longer fetch the schedule * from the frame list). * * @note Before disabling periodic scheduling, it is the user's responsibility to ensure that all periodic channels have @@ -505,17 +504,17 @@ static inline usb_dwc_speed_t usb_dwc_hal_port_get_conn_speed(usb_dwc_hal_contex * @brief Disable the debounce lock * * This function must be called after calling usb_dwc_hal_port_check_if_connected() and will allow connection/disconnection - * events to occur again. Any pending connection or disconenction interrupts are cleared. + * events to occur again. Any pending connection or disconnection interrupts are cleared. * * @param hal Context of the HAL layer */ static inline void usb_dwc_hal_disable_debounce_lock(usb_dwc_hal_context_t *hal) { hal->flags.dbnc_lock_enabled = 0; - //Clear Conenction and disconenction interrupt in case it triggered again + //Clear Connection and disconnection interrupt in case it triggered again usb_dwc_ll_gintsts_clear_intrs(hal->dev, USB_DWC_LL_INTR_CORE_DISCONNINT); usb_dwc_ll_hprt_intr_clear(hal->dev, USB_DWC_LL_INTR_HPRT_PRTCONNDET); - //Reenable the hprt (connection) and disconnection interrupts + //Re-enable the hprt (connection) and disconnection interrupts usb_dwc_ll_gintmsk_en_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_DISCONNINT); } @@ -672,10 +671,10 @@ bool usb_dwc_hal_chan_request_halt(usb_dwc_hal_chan_t *chan_obj); /** * @brief Indicate that a channel is halted after a port error * - * When a port error occurs (e.g., discconect, overcurrent): + * When a port error occurs (e.g., disconnect, overcurrent): * - Any previously active channels will remain active (i.e., they will not receive a channel interrupt) * - Attempting to disable them using usb_dwc_hal_chan_request_halt() will NOT generate an interrupt for ISOC channels - * (probalby something to do with the periodic scheduling) + * (probably something to do with the periodic scheduling) * * However, the channel's enable bit can be left as 1 since after a port error, a soft reset will be done anyways. * This function simply updates the channels internal state variable to indicate it is halted (thus allowing it to be diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index f9834b7ad8e..bc0c24ddaf7 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -214,9 +214,7 @@ struct pipe_obj { uint32_t waiting_halt: 1; uint32_t pipe_cmd_processing: 1; uint32_t has_urb: 1; // Indicates there is at least one URB either pending, in-flight, or done - uint32_t persist: 1; // indicates that this pipe should persist through a run-time port reset - uint32_t reset_lock: 1; // Indicates that this pipe is undergoing a run-time reset - uint32_t reserved27: 27; + uint32_t reserved29: 29; }; uint32_t val; } cs_flags; @@ -560,28 +558,6 @@ static esp_err_t _pipe_cmd_clear(pipe_t *pipe); // ------------------------ Port --------------------------- -/** - * @brief Prepare persistent pipes for reset - * - * This function checks if all pipes are reset persistent and proceeds to free their underlying HAL channels for the - * persistent pipes. This should be called before a run time reset - * - * @param port Port object - * @return true All pipes are persistent and their channels are freed - * @return false Not all pipes are persistent - */ -static bool _port_persist_all_pipes(port_t *port); - -/** - * @brief Recovers all persistent pipes after a reset - * - * This function will recover all persistent pipes after a reset and reallocate their underlying HAl channels. This - * function should be called after a reset. - * - * @param port Port object - */ -static void _port_recover_all_pipes(port_t *port); - /** * @brief Checks if all pipes are in the halted state * @@ -1162,44 +1138,6 @@ esp_err_t hcd_uninstall(void) // ----------------------- Helpers ------------------------- -static bool _port_persist_all_pipes(port_t *port) -{ - if (port->num_pipes_queued > 0) { - // All pipes must be idle before we run-time reset - return false; - } - bool all_persist = true; - pipe_t *pipe; - // Check that each pipe is persistent - TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { - if (!pipe->cs_flags.persist) { - all_persist = false; - break; - } - } - if (!all_persist) { - // At least one pipe is not persistent. All pipes must be freed or made persistent before we can reset - return false; - } - TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { - pipe->cs_flags.reset_lock = 1; - usb_dwc_hal_chan_free(port->hal, pipe->chan_obj); - } - return true; -} - -static void _port_recover_all_pipes(port_t *port) -{ - pipe_t *pipe; - TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { - pipe->cs_flags.persist = 0; - pipe->cs_flags.reset_lock = 0; - usb_dwc_hal_chan_alloc(port->hal, pipe->chan_obj, (void *)pipe); - usb_dwc_hal_chan_set_ep_char(port->hal, pipe->chan_obj, &pipe->ep_char); - } - CACHE_SYNC_FRAME_LIST(port->frame_list); -} - static bool _port_check_all_pipes_halted(port_t *port) { bool all_halted = true; @@ -1276,20 +1214,26 @@ static esp_err_t _port_cmd_power_off(port_t *port) static esp_err_t _port_cmd_reset(port_t *port) { esp_err_t ret; - // Port can only a reset when it is in the enabled or disabled states (in case of new connection) + + // Port can only a reset when it is in the enabled or disabled (in the case of a new connection)states. if (port->state != HCD_PORT_STATE_ENABLED && port->state != HCD_PORT_STATE_DISABLED) { ret = ESP_ERR_INVALID_STATE; goto exit; } - bool is_runtime_reset = (port->state == HCD_PORT_STATE_ENABLED) ? true : false; - if (is_runtime_reset && !_port_persist_all_pipes(port)) { - // If this is a run time reset, check all pipes that are still allocated can persist the reset + // Port can only be reset if all pipes are idle + if (port->num_pipes_queued > 0) { ret = ESP_ERR_INVALID_STATE; goto exit; } - // All pipes (if any_) are guaranteed to be persistent at this point. Proceed to resetting the bus + /* + Proceed to resetting the bus + - Update the port's state variable + - Hold the bus in the reset state for RESET_HOLD_MS. + - Return the bus to the idle state for RESET_RECOVERY_MS + */ port->state = HCD_PORT_STATE_RESETTING; - // Put and hold the bus in the reset state. If the port was previously enabled, a disabled event will occur after this + + // Place the bus into the reset state. If the port was previously enabled, a disabled event will occur after this usb_dwc_hal_port_toggle_reset(port->hal, true); HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESET_HOLD_MS)); @@ -1299,7 +1243,8 @@ static esp_err_t _port_cmd_reset(port_t *port) ret = ESP_ERR_INVALID_RESPONSE; goto bailout; } - // Return the bus to the idle state and hold it for the required reset recovery time. Port enabled event should occur + + // Return the bus to the idle state. Port enabled event should occur usb_dwc_hal_port_toggle_reset(port->hal, false); HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESET_RECOVERY_MS)); @@ -1309,16 +1254,20 @@ static esp_err_t _port_cmd_reset(port_t *port) ret = ESP_ERR_INVALID_RESPONSE; goto bailout; } - // Set FIFO sizes based on the selected biasing - usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias); - // We start periodic scheduling only after a RESET command since SOFs only start after a reset - usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); - usb_dwc_hal_port_periodic_enable(port->hal); + + // Reinitialize port registers. + usb_dwc_hal_set_fifo_bias(port->hal, port->fifo_bias); // Set FIFO biases + usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); // Set periodic frame list + usb_dwc_hal_port_periodic_enable(port->hal); // Enable periodic scheduling + ret = ESP_OK; bailout: - if (is_runtime_reset) { - _port_recover_all_pipes(port); + // Reinitialize channel registers + pipe_t *pipe; + TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { + usb_dwc_hal_chan_set_ep_char(port->hal, pipe->chan_obj, &pipe->ep_char); } + CACHE_SYNC_FRAME_LIST(port->frame_list); exit: return ret; } @@ -1987,8 +1936,7 @@ esp_err_t hcd_pipe_free(hcd_pipe_handle_t pipe_hdl) HCD_ENTER_CRITICAL(); // Check that all URBs have been removed and pipe has no pending events HCD_CHECK_FROM_CRIT(!pipe->multi_buffer_control.buffer_is_executing - && !pipe->cs_flags.has_urb - && !pipe->cs_flags.reset_lock, + && !pipe->cs_flags.has_urb, ESP_ERR_INVALID_STATE); // Remove pipe from the list of idle pipes (it must be in the idle list because it should have no queued URBs) TAILQ_REMOVE(&pipe->port->pipes_idle_tailq, pipe, tailq_entry); @@ -2011,8 +1959,7 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps) HCD_ENTER_CRITICAL(); // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && - !pipe->cs_flags.has_urb && - !pipe->cs_flags.reset_lock, + !pipe->cs_flags.has_urb, ESP_ERR_INVALID_STATE); pipe->ep_char.mps = mps; // Update the underlying channel's registers @@ -2027,8 +1974,7 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr) HCD_ENTER_CRITICAL(); // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && - !pipe->cs_flags.has_urb && - !pipe->cs_flags.reset_lock, + !pipe->cs_flags.has_urb, ESP_ERR_INVALID_STATE); pipe->ep_char.dev_addr = dev_addr; // Update the underlying channel's registers @@ -2043,8 +1989,7 @@ esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback HCD_ENTER_CRITICAL(); // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && - !pipe->cs_flags.has_urb && - !pipe->cs_flags.reset_lock, + !pipe->cs_flags.has_urb, ESP_ERR_INVALID_STATE); pipe->callback = callback; pipe->callback_arg = user_arg; @@ -2052,20 +1997,6 @@ esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback return ESP_OK; } -esp_err_t hcd_pipe_set_persist_reset(hcd_pipe_handle_t pipe_hdl) -{ - pipe_t *pipe = (pipe_t *)pipe_hdl; - HCD_ENTER_CRITICAL(); - // Check if pipe is in the correct state to be updated - HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && - !pipe->cs_flags.has_urb && - !pipe->cs_flags.reset_lock, - ESP_ERR_INVALID_STATE); - pipe->cs_flags.persist = 1; - HCD_EXIT_CRITICAL(); - return ESP_OK; -} - void *hcd_pipe_get_context(hcd_pipe_handle_t pipe_hdl) { pipe_t *pipe = (pipe_t *)pipe_hdl; @@ -2102,27 +2033,22 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) esp_err_t ret = ESP_OK; HCD_ENTER_CRITICAL(); - // Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid - if (pipe->cs_flags.reset_lock) { - ret = ESP_ERR_INVALID_STATE; - } else { - pipe->cs_flags.pipe_cmd_processing = 1; - switch (command) { - case HCD_PIPE_CMD_HALT: { - ret = _pipe_cmd_halt(pipe); - break; - } - case HCD_PIPE_CMD_FLUSH: { - ret = _pipe_cmd_flush(pipe); - break; - } - case HCD_PIPE_CMD_CLEAR: { - ret = _pipe_cmd_clear(pipe); - break; - } - } - pipe->cs_flags.pipe_cmd_processing = 0; + pipe->cs_flags.pipe_cmd_processing = 1; + switch (command) { + case HCD_PIPE_CMD_HALT: { + ret = _pipe_cmd_halt(pipe); + break; + } + case HCD_PIPE_CMD_FLUSH: { + ret = _pipe_cmd_flush(pipe); + break; + } + case HCD_PIPE_CMD_CLEAR: { + ret = _pipe_cmd_clear(pipe); + break; + } } + pipe->cs_flags.pipe_cmd_processing = 0; HCD_EXIT_CRITICAL(); return ret; } @@ -2658,8 +2584,7 @@ esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb) // Check that pipe and port are in the correct state to receive URBs HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED // The pipe's port must be in the correct state && pipe->state == HCD_PIPE_STATE_ACTIVE // The pipe must be in the correct state - && !pipe->cs_flags.pipe_cmd_processing // Pipe cannot currently be processing a pipe command - && !pipe->cs_flags.reset_lock, // Pipe cannot be persisting through a port reset + && !pipe->cs_flags.pipe_cmd_processing, // Pipe cannot currently be processing a pipe command ESP_ERR_INVALID_STATE); // Use the URB's reserved_ptr to store the pipe's urb->hcd_ptr = (void *)pipe; diff --git a/components/usb/hub.c b/components/usb/hub.c index 52aa84e00a9..6709bea64a3 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -285,7 +285,6 @@ static bool enum_stage_start(enum_ctrl_t *enum_ctrl) static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl) { - ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe)); // Persist the default pipe through the reset if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset"); return false; diff --git a/components/usb/private_include/hcd.h b/components/usb/private_include/hcd.h index f0c4a364b98..24ec22b0857 100644 --- a/components/usb/private_include/hcd.h +++ b/components/usb/private_include/hcd.h @@ -434,20 +434,6 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr) */ esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback_t callback, void *user_arg); -/** - * @brief Make a pipe persist through a run time reset - * - * Normally when a HCD_PORT_CMD_RESET is called, all pipes should already have been freed. However There may be cases - * (such as during enumeration) when a pipe must persist through a reset. This function will mark a pipe as - * persistent allowing it to survive a reset. When HCD_PORT_CMD_RESET is called, the pipe can continue to be used after - * the reset. - * - * @param pipe_hdl Pipe handle - * @retval ESP_OK: Pipe successfully marked as persistent - * @retval ESP_ERR_INVALID_STATE: Pipe is not in a condition to be made persistent - */ -esp_err_t hcd_pipe_set_persist_reset(hcd_pipe_handle_t pipe_hdl); - /** * @brief Get the context variable of a pipe from its handle * From df6c6f93fa984757bec0f1a59974e4229b8c5946 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 16 Apr 2024 01:51:30 +0800 Subject: [PATCH 423/548] refactor(usb/hub): Update Hub driver port request logic --- components/usb/hub.c | 79 ++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/components/usb/hub.c b/components/usb/hub.c index 6709bea64a3..14b8f029c73 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -50,9 +50,12 @@ implement the bare minimum to control the root HCD port. // Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive #define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01 -#define HUB_DRIVER_FLAG_ACTION_PORT 0x02 +#define HUB_DRIVER_FLAG_ACTION_PORT_REQ 0x02 #define HUB_DRIVER_FLAG_ACTION_ENUM_EVENT 0x04 +#define PORT_REQ_DISABLE 0x01 +#define PORT_REQ_RECOVER 0x02 + /** * @brief Root port states * @@ -185,6 +188,7 @@ typedef struct { uint32_t val; } flags; root_port_state_t root_port_state; + unsigned int port_reqs; } dynamic; // Single thread members don't require a critical section so long as they are never accessed from multiple threads struct { @@ -679,7 +683,8 @@ static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl) HUB_DRIVER_ENTER_CRITICAL(); // Enum could have failed due to a port error. If so, we need to trigger a port recovery if (p_hub_driver_obj->dynamic.root_port_state == ROOT_PORT_STATE_RECOVERY) { - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT; + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; } else { // Otherwise, we move to the enum failed state and wait for the device to disconnect p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_ENUM_FAILED; @@ -839,7 +844,8 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) case ROOT_PORT_STATE_POWERED: // This occurred before enumeration case ROOT_PORT_STATE_ENUM_FAILED: // This occurred after a failed enumeration. // Therefore, there's no device and we can go straight to port recovery - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT; + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; break; case ROOT_PORT_STATE_ENUM: // This occurred during enumeration. Therefore, we need to cleanup the failed enumeration @@ -867,6 +873,30 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) } } +static void root_port_req(hcd_port_handle_t root_port_hdl) +{ + unsigned int port_reqs; + + HUB_DRIVER_ENTER_CRITICAL(); + port_reqs = p_hub_driver_obj->dynamic.port_reqs; + p_hub_driver_obj->dynamic.port_reqs = 0; + HUB_DRIVER_EXIT_CRITICAL(); + + if (port_reqs & PORT_REQ_DISABLE) { + ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port"); + // We allow this to fail in case a disconnect/port error happens while disabling. + hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE); + } + if (port_reqs & PORT_REQ_RECOVER) { + ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port"); + ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl)); + ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON)); + HUB_DRIVER_ENTER_CRITICAL(); + p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED; + HUB_DRIVER_EXIT_CRITICAL(); + } +} + static void enum_handle_events(void) { bool stage_pass; @@ -1055,10 +1085,24 @@ esp_err_t hub_dev_is_free(uint8_t dev_addr) { assert(dev_addr == ENUM_DEV_ADDR); assert(p_hub_driver_obj->single_thread.root_dev_hdl); - p_hub_driver_obj->single_thread.root_dev_hdl = NULL; // Device is free, we can now request its port be recycled + hcd_port_state_t port_state = hcd_port_get_state(p_hub_driver_obj->constant.root_port_hdl); + p_hub_driver_obj->single_thread.root_dev_hdl = NULL; + HUB_DRIVER_ENTER_CRITICAL(); - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT; + // How the port is recycled will depend on the port's state + switch (port_state) { + case HCD_PORT_STATE_ENABLED: + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_DISABLE; + break; + case HCD_PORT_STATE_RECOVERY: + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; + break; + default: + abort(); // Should never occur + break; + } + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; HUB_DRIVER_EXIT_CRITICAL(); p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg); @@ -1076,29 +1120,8 @@ esp_err_t hub_process(void) if (action_flags & HUB_DRIVER_FLAG_ACTION_ROOT_EVENT) { root_port_handle_events(p_hub_driver_obj->constant.root_port_hdl); } - if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT) { - // Check current state of port - hcd_port_state_t port_state = hcd_port_get_state(p_hub_driver_obj->constant.root_port_hdl); - switch (port_state) { - case HCD_PORT_STATE_ENABLED: - // Port is still enabled with a connect device. Disable it. - ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port"); - // We allow this to fail in case a disconnect/port error happens while disabling. - hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE); - break; - case HCD_PORT_STATE_RECOVERY: - // Port is in recovery after a disconnect/error. Recover it. - ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port"); - ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl)); - ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON)); - HUB_DRIVER_ENTER_CRITICAL(); - p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_POWERED; - HUB_DRIVER_EXIT_CRITICAL(); - break; - default: - abort(); // Should never occur - break; - } + if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT_REQ) { + root_port_req(p_hub_driver_obj->constant.root_port_hdl); } if (action_flags & HUB_DRIVER_FLAG_ACTION_ENUM_EVENT) { enum_handle_events(); From a602befe1b48d8d7529e23d60c9bf04c3ac520f7 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 10 Apr 2024 05:06:46 +0800 Subject: [PATCH 424/548] refactor(usb/usbh): Update USBH device creation and enumeration handling This commit updates how the USBH handles device creation and enumeration so that upper layers (such as the Hub driver) can use the USBH API for enumeration instead of calling the HCD. USBH Updates: USBH now creates unenumerated devices set to address 0 with no device/config descriptor. A newly created device can be opened and communicated with immediately (using control transfers). This allows the Hub driver to call the USBH instead of the HCD. Summary of USBH changes: - Added new APIs to add/remove a device. Devices are now created as unenumerated and can be immediately opened and communicated with. - Added new APIs to enumerate a device (see 'usbh_dev_set_...()' functions). Device must be locked (see 'usbh_dev_enum_lock()') before enumeration functions can be called. - Added UID for each device. This allows the particular USBH without needing to use the device's handle (which implies opening the device). Hub Driver Updates: Hub driver now calls the USBH for enumeration. Summary of USBH changes: - Replace all 'hcd_pipe_...()' calls with 'usbh_dev_...()' calls - Refactored port event handling to fit with new USBH API - Updated to use UID to uniquely identify devices without opening them USB Host Updates: - Reroute USBH control transfers to clients and hub driver --- components/usb/hcd_dwc.c | 14 - components/usb/hub.c | 230 ++++---- components/usb/private_include/hcd.h | 16 - components/usb/private_include/hub.h | 12 +- components/usb/private_include/usbh.h | 245 +++++---- components/usb/usb_host.c | 38 +- components/usb/usbh.c | 733 +++++++++++++++++--------- 7 files changed, 767 insertions(+), 521 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index bc0c24ddaf7..ebfd2c8e79c 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -1983,20 +1983,6 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr) return ESP_OK; } -esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback_t callback, void *user_arg) -{ - pipe_t *pipe = (pipe_t *)pipe_hdl; - HCD_ENTER_CRITICAL(); - // Check if pipe is in the correct state to be updated - HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && - !pipe->cs_flags.has_urb, - ESP_ERR_INVALID_STATE); - pipe->callback = callback; - pipe->callback_arg = user_arg; - HCD_EXIT_CRITICAL(); - return ESP_OK; -} - void *hcd_pipe_get_context(hcd_pipe_handle_t pipe_hdl) { pipe_t *pipe = (pipe_t *)pipe_hdl; diff --git a/components/usb/hub.c b/components/usb/hub.c index 14b8f029c73..2735ef5a469 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -40,6 +40,7 @@ implement the bare minimum to control the root HCD port. #define ENUM_CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE #define ENUM_DEV_ADDR 1 // Device address used in enumeration +#define ENUM_DEV_UID 1 // Unique ID for device connected to root port #define ENUM_CONFIG_INDEX_DEFAULT 0 // Index used to get the first configuration descriptor of the device #define ENUM_SHORT_DESC_REQ_LEN 8 // Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength) #define ENUM_WORST_CASE_MPS_LS 8 // The worst case MPS of EP0 for a LS device @@ -63,9 +64,8 @@ implement the bare minimum to control the root HCD port. typedef enum { ROOT_PORT_STATE_NOT_POWERED, /**< Root port initialized and/or not powered */ ROOT_PORT_STATE_POWERED, /**< Root port is powered, device is not connected */ - ROOT_PORT_STATE_ENUM, /**< A device has been connected to the root port and is undergoing enumeration */ - ROOT_PORT_STATE_ENUM_FAILED, /**< Enumeration of a connected device has failed. Waiting for that device to be disconnected */ - ROOT_PORT_ACTIVE, /**< The connected device was enumerated and port is active */ + ROOT_PORT_STATE_DISABLED, /**< A device is connected but is disabled (i.e., not reset, no SOFs are sent) */ + ROOT_PORT_STATE_ENABLED, /**< A device is connected, port has been reset, SOFs are sent */ ROOT_PORT_STATE_RECOVERY, /**< Root port encountered an error and needs to be recovered */ } root_port_state_t; @@ -159,7 +159,6 @@ typedef struct { urb_t *urb; /**< URB used for enumeration control transfers. Max data length of ENUM_CTRL_TRANSFER_MAX_DATA_LEN */ // Initialized at start of a particular enumeration usb_device_handle_t dev_hdl; /**< Handle of device being enumerated */ - hcd_pipe_handle_t pipe; /**< Default pipe handle of the device being enumerated */ // Updated during enumeration enum_stage_t stage; /**< Current enumeration stage */ int expect_num_bytes; /**< Expected number of bytes for IN transfers stages. Set to 0 for OUT transfer */ @@ -192,7 +191,7 @@ typedef struct { } dynamic; // Single thread members don't require a critical section so long as they are never accessed from multiple threads struct { - usb_device_handle_t root_dev_hdl; // Indicates if an enumerated device is connected to the root port + unsigned int root_dev_uid; // UID of the device connected to root port. 0 if no device connected enum_ctrl_t enum_ctrl; } single_thread; // Constant members do no change after installation thus do not require a critical section @@ -245,40 +244,26 @@ const char *HUB_DRIVER_TAG = "HUB"; static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr); /** - * @brief HCD pipe callback for the default pipe of the device under enumeration + * @brief Control transfer callback used for enumeration * - * - This callback is called from the context of the HCD, so any event handling should be deferred to hub_process() - * - This callback needs to call proc_req_cb to ensure that hub_process() gets a chance to run - * - * @param pipe_hdl HCD pipe handle - * @param pipe_event Pipe event - * @param user_arg Callback argument - * @param in_isr Whether callback is in an ISR context - * @return Whether a yield is required + * @param transfer Transfer object */ -static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr); +static void enum_transfer_callback(usb_transfer_t *transfer); // ------------------------------------------------- Enum Functions ---------------------------------------------------- static bool enum_stage_start(enum_ctrl_t *enum_ctrl) { - // Get the speed of the device, and set the enum MPS to the worst case size for now - usb_speed_t speed; - if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) { - return false; - } - enum_ctrl->bMaxPacketSize0 = (speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS; - // Try to add the device to USBH - usb_device_handle_t enum_dev_hdl; - hcd_pipe_handle_t enum_dflt_pipe_hdl; - // We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device - if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) { - return false; - } - // Set our own default pipe callback - ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL)); - enum_ctrl->dev_hdl = enum_dev_hdl; - enum_ctrl->pipe = enum_dflt_pipe_hdl; + // Open the newly added device (at address 0) + ESP_ERROR_CHECK(usbh_devs_open(0, &p_hub_driver_obj->single_thread.enum_ctrl.dev_hdl)); + + // Get the speed of the device to set the initial MPS of EP0 + usb_device_info_t dev_info; + ESP_ERROR_CHECK(usbh_dev_get_info(p_hub_driver_obj->single_thread.enum_ctrl.dev_hdl, &dev_info)); + enum_ctrl->bMaxPacketSize0 = (dev_info.speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS; + + // Lock the device for enumeration. This allows us call usbh_dev_set_...() functions during enumeration + ESP_ERROR_CHECK(usbh_dev_enum_lock(p_hub_driver_obj->single_thread.enum_ctrl.dev_hdl)); // Flag to gracefully exit the enumeration process if requested by the user in the enumeration filter cb #ifdef ENABLE_ENUM_FILTER_CALLBACK @@ -445,7 +430,7 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) abort(); break; } - if (hcd_urb_enqueue(enum_ctrl->pipe, enum_ctrl->urb) != ESP_OK) { + if (usbh_dev_submit_ctrl_urb(enum_ctrl->dev_hdl, enum_ctrl->urb) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to submit: %s", enum_stage_strings[enum_ctrl->stage]); return false; } @@ -470,18 +455,10 @@ static bool enum_stage_wait(enum_ctrl_t *enum_ctrl) static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) { - // Dequeue the URB - urb_t *dequeued_enum_urb = hcd_urb_dequeue(enum_ctrl->pipe); - assert(dequeued_enum_urb == enum_ctrl->urb); - // Check transfer status - usb_transfer_t *transfer = &dequeued_enum_urb->transfer; + usb_transfer_t *transfer = &enum_ctrl->urb->transfer; if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) { ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status %d: %s", transfer->status, enum_stage_strings[enum_ctrl->stage]); - if (transfer->status == USB_TRANSFER_STATUS_STALL) { - // EP stalled, clearing the pipe to execute further stages - ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_CLEAR)); - } return false; } // Check IN transfer returned the expected correct number of bytes @@ -508,8 +485,8 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) ret = false; break; } - // Update and save the MPS of the default pipe - if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) { + // Update and save the MPS of the EP0 + if (usbh_dev_set_ep0_mps(enum_ctrl->dev_hdl, device_desc->bMaxPacketSize0) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS"); ret = false; break; @@ -520,16 +497,15 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) break; } case ENUM_STAGE_CHECK_ADDR: { - // Update the pipe and device's address, and fill the address into the device object - ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR)); - ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR)); + // Update the device's address + ESP_ERROR_CHECK(usbh_dev_set_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR)); ret = true; break; } case ENUM_STAGE_CHECK_FULL_DEV_DESC: { - // Fill device descriptor into the device object + // Set the device's descriptor const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc)); + ESP_ERROR_CHECK(usbh_dev_set_desc(enum_ctrl->dev_hdl, device_desc)); enum_ctrl->iManufacturer = device_desc->iManufacturer; enum_ctrl->iProduct = device_desc->iProduct; enum_ctrl->iSerialNumber = device_desc->iSerialNumber; @@ -558,10 +534,10 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) break; } case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: { - // Fill configuration descriptor into the device object + // Set the device's configuration descriptor const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); enum_ctrl->bConfigurationValue = config_desc->bConfigurationValue; - ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc)); + ESP_ERROR_CHECK(usbh_dev_set_config_desc(enum_ctrl->dev_hdl, config_desc)); ret = true; break; } @@ -638,7 +614,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) } else { // ENUM_STAGE_CHECK_FULL_PROD_STR_DESC select = 2; } - ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select)); + ESP_ERROR_CHECK(usbh_dev_set_str_desc(enum_ctrl->dev_hdl, str_desc, select)); ret = true; break; } @@ -653,43 +629,27 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl) { - // We currently only support a single device connected to the root port. Move the device handle from enum to root - HUB_DRIVER_ENTER_CRITICAL(); - p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_ACTIVE; - HUB_DRIVER_EXIT_CRITICAL(); - p_hub_driver_obj->single_thread.root_dev_hdl = enum_ctrl->dev_hdl; - usb_device_handle_t dev_hdl = enum_ctrl->dev_hdl; + // Unlock the device as we are done with the enumeration + ESP_ERROR_CHECK(usbh_dev_enum_unlock(enum_ctrl->dev_hdl)); + // Propagate a new device event + ESP_ERROR_CHECK(usbh_devs_new_dev_event(enum_ctrl->dev_hdl)); + // We are done with using the device. Close it. + ESP_ERROR_CHECK(usbh_devs_close(enum_ctrl->dev_hdl)); // Clear values in enum_ctrl enum_ctrl->dev_hdl = NULL; - enum_ctrl->pipe = NULL; - // Update device object after enumeration is done - ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl)); } static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl) { - // Enumeration failed. Clear the enum device handle and pipe if (enum_ctrl->dev_hdl) { - // If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there - // was an in-flight URB. - ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_HALT)); - ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_FLUSH)); - hcd_urb_dequeue(enum_ctrl->pipe); // This could return NULL if there - ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); // Free the underlying device object first before recovering the port + // Close the device and unlock it as we done with enumeration + ESP_ERROR_CHECK(usbh_dev_enum_unlock(enum_ctrl->dev_hdl)); + ESP_ERROR_CHECK(usbh_devs_close(enum_ctrl->dev_hdl)); + // We allow this to fail in case the device object was already freed + usbh_devs_remove(ENUM_DEV_UID); } // Clear values in enum_ctrl enum_ctrl->dev_hdl = NULL; - enum_ctrl->pipe = NULL; - HUB_DRIVER_ENTER_CRITICAL(); - // Enum could have failed due to a port error. If so, we need to trigger a port recovery - if (p_hub_driver_obj->dynamic.root_port_state == ROOT_PORT_STATE_RECOVERY) { - p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; - } else { - // Otherwise, we move to the enum failed state and wait for the device to disconnect - p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_ENUM_FAILED; - } - HUB_DRIVER_EXIT_CRITICAL(); } static enum_stage_t get_next_stage(enum_stage_t old_stage, enum_ctrl_t *enum_ctrl) @@ -803,13 +763,13 @@ static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg); } -static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) +static void enum_transfer_callback(usb_transfer_t *transfer) { - // Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset) + // We simply trigger a processing request to handle the completed enumeration control transfer HUB_DRIVER_ENTER_CRITICAL_SAFE(); p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; HUB_DRIVER_EXIT_CRITICAL_SAFE(); - return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg); + p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg); } // ---------------------- Handlers ------------------------- @@ -822,17 +782,32 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) // Nothing to do break; case HCD_PORT_EVENT_CONNECTION: { - if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) { - ESP_LOGD(HUB_DRIVER_TAG, "Root port reset"); - // Start enumeration - HUB_DRIVER_ENTER_CRITICAL(); - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; - p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_ENUM; - HUB_DRIVER_EXIT_CRITICAL(); - p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_START; - } else { + if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Root port reset failed"); + goto reset_err; + } + ESP_LOGD(HUB_DRIVER_TAG, "Root port reset"); + usb_speed_t speed; + if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) { + goto new_dev_err; } + // Allocate a new device. We use a fixed ENUM_DEV_UID for now since we only support a single device + if (usbh_devs_add(ENUM_DEV_UID, speed, p_hub_driver_obj->constant.root_port_hdl) != ESP_OK) { + ESP_LOGE(HUB_DRIVER_TAG, "Failed to add device"); + goto new_dev_err; + } + p_hub_driver_obj->single_thread.root_dev_uid = ENUM_DEV_UID; + // Start enumeration + HUB_DRIVER_ENTER_CRITICAL(); + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; + p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_ENABLED; + HUB_DRIVER_EXIT_CRITICAL(); + p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_START; + break; +new_dev_err: + // We allow this to fail in case a disconnect/port error happens while disabling. + hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE); +reset_err: break; } case HCD_PORT_EVENT_DISCONNECTION: @@ -842,18 +817,13 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) HUB_DRIVER_ENTER_CRITICAL(); switch (p_hub_driver_obj->dynamic.root_port_state) { case ROOT_PORT_STATE_POWERED: // This occurred before enumeration - case ROOT_PORT_STATE_ENUM_FAILED: // This occurred after a failed enumeration. - // Therefore, there's no device and we can go straight to port recovery + case ROOT_PORT_STATE_DISABLED: // This occurred after the device has already been disabled + // Therefore, there's no device object to clean up, and we can go straight to port recovery p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; break; - case ROOT_PORT_STATE_ENUM: - // This occurred during enumeration. Therefore, we need to cleanup the failed enumeration - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; - p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED; - break; - case ROOT_PORT_ACTIVE: - // There was an enumerated device. We need to indicate to USBH that the device is gone + case ROOT_PORT_STATE_ENABLED: + // There is an enabled (active) device. We need to indicate to USBH that the device is gone pass_event_to_usbh = true; break; default: @@ -863,7 +833,10 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) p_hub_driver_obj->dynamic.root_port_state = ROOT_PORT_STATE_RECOVERY; HUB_DRIVER_EXIT_CRITICAL(); if (pass_event_to_usbh) { - ESP_ERROR_CHECK(usbh_hub_dev_gone(p_hub_driver_obj->single_thread.root_dev_hdl)); + // The port must have a device object + assert(p_hub_driver_obj->single_thread.root_dev_uid != 0); + // We allow this to fail in case the device object was already freed + usbh_devs_remove(p_hub_driver_obj->single_thread.root_dev_uid); } break; } @@ -955,7 +928,6 @@ static void enum_handle_events(void) stage_pass = true; break; default: - // Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup. stage_pass = true; break; } @@ -977,18 +949,22 @@ static void enum_handle_events(void) // ---------------------------------------------- Hub Driver Functions ------------------------------------------------- -esp_err_t hub_install(hub_config_t *hub_config) +esp_err_t hub_install(hub_config_t *hub_config, void **client_ret) { HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_EXIT_CRITICAL(); + esp_err_t ret; + // Allocate Hub driver object hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT); urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_DATA_LEN, 0); if (hub_driver_obj == NULL || enum_urb == NULL) { return ESP_ERR_NO_MEM; } - esp_err_t ret; + enum_urb->usb_host_client = (void *)hub_driver_obj; + enum_urb->transfer.callback = enum_transfer_callback; + // Install HCD port hcd_port_config_t port_config = { .fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS, @@ -1001,6 +977,7 @@ esp_err_t hub_install(hub_config_t *hub_config) if (ret != ESP_OK) { goto err; } + // Initialize Hub driver object hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE; hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb; @@ -1020,6 +997,9 @@ esp_err_t hub_install(hub_config_t *hub_config) } p_hub_driver_obj = hub_driver_obj; HUB_DRIVER_EXIT_CRITICAL(); + + // Write-back client_ret pointer + *client_ret = (void *)hub_driver_obj; ret = ESP_OK; return ret; @@ -1081,31 +1061,31 @@ esp_err_t hub_root_stop(void) return ret; } -esp_err_t hub_dev_is_free(uint8_t dev_addr) +esp_err_t hub_port_recycle(unsigned int dev_uid) { - assert(dev_addr == ENUM_DEV_ADDR); - assert(p_hub_driver_obj->single_thread.root_dev_hdl); - // Device is free, we can now request its port be recycled - hcd_port_state_t port_state = hcd_port_get_state(p_hub_driver_obj->constant.root_port_hdl); - p_hub_driver_obj->single_thread.root_dev_hdl = NULL; + if (dev_uid == p_hub_driver_obj->single_thread.root_dev_uid) { + // Device is free, we can now request its port be recycled + hcd_port_state_t port_state = hcd_port_get_state(p_hub_driver_obj->constant.root_port_hdl); + p_hub_driver_obj->single_thread.root_dev_uid = 0; + HUB_DRIVER_ENTER_CRITICAL(); + // How the port is recycled will depend on the port's state + switch (port_state) { + case HCD_PORT_STATE_ENABLED: + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_DISABLE; + break; + case HCD_PORT_STATE_RECOVERY: + p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; + break; + default: + abort(); // Should never occur + break; + } + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; + HUB_DRIVER_EXIT_CRITICAL(); - HUB_DRIVER_ENTER_CRITICAL(); - // How the port is recycled will depend on the port's state - switch (port_state) { - case HCD_PORT_STATE_ENABLED: - p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_DISABLE; - break; - case HCD_PORT_STATE_RECOVERY: - p_hub_driver_obj->dynamic.port_reqs |= PORT_REQ_RECOVER; - break; - default: - abort(); // Should never occur - break; + p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg); } - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_REQ; - HUB_DRIVER_EXIT_CRITICAL(); - p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg); return ESP_OK; } diff --git a/components/usb/private_include/hcd.h b/components/usb/private_include/hcd.h index 24ec22b0857..1fd36173071 100644 --- a/components/usb/private_include/hcd.h +++ b/components/usb/private_include/hcd.h @@ -418,22 +418,6 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps); */ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr); -/** - * @brief Update a pipe's callback - * - * This function is intended to be called on default pipes at the end of enumeration to switch to a callback that - * handles the completion of regular control transfer. - * - Pipe is not current processing a command - * - Pipe does not have any enqueued URBs - * - Port cannot be resetting - * - * @param pipe_hdl Pipe handle - * @param callback Callback - * @param user_arg Callback argument - * @return esp_err_t - */ -esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback_t callback, void *user_arg); - /** * @brief Get the context variable of a pipe from its handle * diff --git a/components/usb/private_include/hub.h b/components/usb/private_include/hub.h index a096de8fd96..cf85ad861d2 100644 --- a/components/usb/private_include/hub.h +++ b/components/usb/private_include/hub.h @@ -42,9 +42,10 @@ typedef struct { * - Initializes the HCD root port * * @param[in] hub_config Hub driver configuration + * @param[out] client_ret Unique pointer to identify the Hub as a USB Host client * @return esp_err_t */ -esp_err_t hub_install(hub_config_t *hub_config); +esp_err_t hub_install(hub_config_t *hub_config, void **client_ret); /** * @brief Uninstall Hub driver @@ -78,15 +79,16 @@ esp_err_t hub_root_start(void); esp_err_t hub_root_stop(void); /** - * @brief Indicate to the Hub driver that a device has been freed + * @brief Indicate to the Hub driver that a device's port can be recycled * - * Hub driver can now recover the port that the device was connected to + * The device connected to the port has been freed. The Hub driver can now + * recycled the port. * - * @param dev_addr Device address + * @param dev_uid Device's unique ID * @return * - ESP_OK: Success */ -esp_err_t hub_dev_is_free(uint8_t dev_addr); +esp_err_t hub_port_recycle(unsigned int dev_uid); /** * @brief Hub driver's processing function diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index 6dee5e55b4e..a1b5b2a8452 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -58,7 +58,7 @@ typedef struct { usb_device_handle_t dev_hdl; } dev_gone_data; struct { - uint8_t dev_addr; + unsigned int dev_uid; } dev_free_data; }; } usbh_event_data_t; @@ -195,6 +195,32 @@ esp_err_t usbh_devs_num(int *num_devs_ret); */ esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret); +/** + * @brief Create a device and add it to the device pool + * + * The created device will not be enumerated where the device's address is 0, + * device and config descriptor are NULL. The device will still have a default + * pipe, thus allowing control transfers to be submitted. + * + * - Call usbh_devs_open() before communicating with the device + * - Call usbh_dev_enum_lock() before enumerating the device via the various + * usbh_dev_set_...() functions. + * + * @param[in] uid Unique ID assigned to the device + * @param[in] dev_speed Device's speed + * @param[in] port_hdl Handle of the port that the device is connected to + * @return esp_err_t + */ +esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle_t port_hdl); + +/** + * @brief Indicates to the USBH that a device is gone + * + * @param[in] uid Unique ID assigned to the device on creation (see 'usbh_devs_add()') + * @return esp_err_t + */ +esp_err_t usbh_devs_remove(unsigned int uid); + /** * @brief Mark that all devices should be freed at the next possible opportunity * @@ -227,6 +253,16 @@ esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl); */ esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl); +/** + * @brief Trigger a USBH_EVENT_NEW_DEV event for the device + * + * This is typically called after a device has been fully enumerated. + * + * @param[in] dev_hdl Device handle + * @return esp_err_t + */ +esp_err_t usbh_devs_new_dev_event(usb_device_handle_t dev_hdl); + // ------------------------------------------------ Device Functions --------------------------------------------------- // ----------------------- Getters ------------------------- @@ -245,7 +281,8 @@ esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr); /** * @brief Get a device's information * - * @note This function can block + * @note It is possible that the device has not been enumerated yet, thus some + * fields may be NULL. * @param[in] dev_hdl Device handle * @param[out] dev_info Device information * @return esp_err_t @@ -257,6 +294,8 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_ * * - The device descriptor is cached when the device is created by the Hub driver * + * @note It is possible that the device has not been enumerated yet, thus the + * device descriptor could be NULL. * @param[in] dev_hdl Device handle * @param[out] dev_desc_ret Device descriptor * @return esp_err_t @@ -268,13 +307,109 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t * * Simply returns a reference to the internally cached configuration descriptor * - * @note This function can block + * @note It is possible that the device has not been enumerated yet, thus the + * configuration descriptor could be NULL. * @param[in] dev_hdl Device handle * @param config_desc_ret * @return esp_err_t */ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc_ret); +// ----------------------- Setters ------------------------- + +/** + * @brief Lock a device for enumeration + * + * - A device's enumeration lock must be set before any of its enumeration fields + * (e.g., address, device/config descriptors) can be set/updated. + * - The caller must be the sole opener of the device (see 'usbh_devs_open()') + * when locking the device for enumeration. + * + * @param[in] dev_hdl Device handle + * @return esp_err_t + */ +esp_err_t usbh_dev_enum_lock(usb_device_handle_t dev_hdl); + +/** + * @brief Release a device's enumeration lock + * + * @param[in] dev_hdl Device handle + * @return esp_err_t + */ +esp_err_t usbh_dev_enum_unlock(usb_device_handle_t dev_hdl); + +/** + * @brief Set the maximum packet size of EP0 for a device + * + * Typically called during enumeration after obtaining the first 8 bytes of the + * device's descriptor. + * + * @note The device's enumeration lock must be set before calling this function + * (see 'usbh_dev_enum_lock()') + * @param[in] dev_hdl Device handle + * @param[in] wMaxPacketSize Maximum packet size + * @return esp_err_t + */ +esp_err_t usbh_dev_set_ep0_mps(usb_device_handle_t dev_hdl, uint16_t wMaxPacketSize); + +/** + * @brief Set a device's address + * + * Typically called during enumeration after a SET_ADDRESSS request has be + * sent to the device. + * + * @note The device's enumeration lock must be set before calling this function + * (see 'usbh_dev_enum_lock()') + * @param[in] dev_hdl Device handle + * @param[in] dev_addr + * @return esp_err_t + */ +esp_err_t usbh_dev_set_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr); + +/** + * @brief Set a device's descriptor + * + * Typically called during enumeration after obtaining the device's descriptor + * via a GET_DESCRIPTOR request. + * + * @note The device's enumeration lock must be set before calling this function + * (see 'usbh_dev_enum_lock()') + * @param[in] dev_hdl Device handle + * @param[in] device_desc Device descriptor to copy + * @return esp_err_t + */ +esp_err_t usbh_dev_set_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc); + +/** + * @brief Set a device's configuration descriptor + * + * Typically called during enumeration after obtaining the device's configuration + * descriptor via a GET_DESCRIPTOR request. + * + * @note The device's enumeration lock must be set before calling this function + * (see 'usbh_dev_enum_lock()') + * @param[in] dev_hdl Device handle + * @param[in] config_desc_full Configuration descriptor to copy + * @return esp_err_t + */ +esp_err_t usbh_dev_set_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full); + +/** + * @brief Set a device's string descriptor + * + * Typically called during enumeration after obtaining one of the device's string + * descriptor via a GET_DESCRIPTOR request. + * + * @note The device's enumeration lock must be set before calling this function + * (see 'usbh_dev_enum_lock()') + * @param[in] dev_hdl Device handle + * @param[in] str_desc String descriptor to copy + * @param[in] select Select string descriptor. 0/1/2 for Manufacturer/Product/Serial + * Number string descriptors respectively + * @return esp_err_t + */ +esp_err_t usbh_dev_set_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select); + // ----------------------------------------------- Endpoint Functions ------------------------------------------------- /** @@ -381,110 +516,6 @@ esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb); */ esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret); -// -------------------------------------------------- Hub Functions ---------------------------------------------------- - -// ------------------- Device Related ---------------------- - -/** - * @brief Indicates to USBH the start of enumeration for a device - * - * - The Hub driver calls this function before it starts enumerating a new device. - * - The USBH will allocate a new device that will be initialized by the Hub driver using the remaining hub enumeration - * functions. - * - The new device's default pipe handle is returned to all the Hub driver to be used during enumeration. - * - * @note Hub Driver only - * @param[in] port_hdl Handle of the port that the device is connected to - * @param[in] dev_speed Device's speed - * @param[out] new_dev_hdl Device's handle - * @param[out] default_pipe_hdl Device's default pipe handle - * @return esp_err_t - */ -esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl); - -/** - * @brief Indicates to the USBH that a device is gone - * - * @param dev_hdl Device handle - * @return esp_err_t - */ -esp_err_t usbh_hub_dev_gone(usb_device_handle_t dev_hdl); - -// ----------------- Enumeration Related ------------------- - -/** - * @brief Assign the enumerating device's address - * - * @note Hub Driver only - * @note Must call in sequence - * @param[in] dev_hdl Device handle - * @param dev_addr - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr); - -/** - * @brief Fill the enumerating device's descriptor - * - * @note Hub Driver only - * @note Must call in sequence - * @param[in] dev_hdl Device handle - * @param device_desc - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc); - -/** - * @brief Fill the enumerating device's active configuration descriptor - * - * @note Hub Driver only - * @note Must call in sequence - * @note This function can block - * @param[in] dev_hdl Device handle - * @param config_desc_full - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full); - -/** - * @brief Fill one of the string descriptors of the enumerating device - * - * @note Hub Driver only - * @note Must call in sequence - * @param dev_hdl Device handle - * @param str_desc Pointer to string descriptor - * @param select Select which string descriptor. 0/1/2 for Manufacturer/Product/Serial Number string descriptors respectively - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select); - -/** - * @brief Indicate the device enumeration is completed - * - * This will allow the device to be opened by clients, and also trigger a USBH_EVENT_NEW_DEV event. - * - * @note Hub Driver only - * @note Must call in sequence - * @note This function can block - * @param[in] dev_hdl Device handle - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl); - -/** - * @brief Indicate that device enumeration has failed - * - * This will cause the enumerating device's resources to be cleaned up - * The Hub Driver must guarantee that the enumerating device's default pipe is already halted, flushed, and dequeued. - * - * @note Hub Driver only - * @note Must call in sequence - * @note This function can block - * @param[in] dev_hdl Device handle - * @return esp_err_t - */ -esp_err_t usbh_hub_enum_failed(usb_device_handle_t dev_hdl); - #ifdef __cplusplus } #endif diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index b9b12dafcc5..b2e5ed137a9 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -148,6 +148,7 @@ typedef struct { SemaphoreHandle_t event_sem; SemaphoreHandle_t mux_lock; usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup + void *hub_client; // Pointer to Hub driver (acting as a client). Used to reroute completed USBH control transfers } constant; } host_lib_t; @@ -171,8 +172,15 @@ static inline void _clear_client_opened_device(client_t *client_obj, uint8_t dev static inline bool _check_client_opened_device(client_t *client_obj, uint8_t dev_addr) { - assert(dev_addr != 0); - return (client_obj->dynamic.opened_dev_addr_map & (1 << (dev_addr - 1))); + bool ret; + + if (dev_addr != 0) { + ret = client_obj->dynamic.opened_dev_addr_map & (1 << (dev_addr - 1)); + } else { + ret = false; + } + + return ret; } static bool _unblock_client(client_t *client_obj, bool in_isr) @@ -268,14 +276,18 @@ static void usbh_event_callback(usbh_event_data_t *event_data, void *arg) case USBH_EVENT_CTRL_XFER: { assert(event_data->ctrl_xfer_data.urb != NULL); assert(event_data->ctrl_xfer_data.urb->usb_host_client != NULL); - // Redistribute done control transfer to the clients that submitted them - client_t *client_obj = (client_t *)event_data->ctrl_xfer_data.urb->usb_host_client; - - HOST_ENTER_CRITICAL(); - TAILQ_INSERT_TAIL(&client_obj->dynamic.done_ctrl_xfer_tailq, event_data->ctrl_xfer_data.urb, tailq_entry); - client_obj->dynamic.num_done_ctrl_xfer++; - _unblock_client(client_obj, false); - HOST_EXIT_CRITICAL(); + // Redistribute completed control transfers to the clients that submitted them + if (event_data->ctrl_xfer_data.urb->usb_host_client == p_host_lib_obj->constant.hub_client) { + // Redistribute to Hub driver. Simply call the transfer callback + event_data->ctrl_xfer_data.urb->transfer.callback(&event_data->ctrl_xfer_data.urb->transfer); + } else { + client_t *client_obj = (client_t *)event_data->ctrl_xfer_data.urb->usb_host_client; + HOST_ENTER_CRITICAL(); + TAILQ_INSERT_TAIL(&client_obj->dynamic.done_ctrl_xfer_tailq, event_data->ctrl_xfer_data.urb, tailq_entry); + client_obj->dynamic.num_done_ctrl_xfer++; + _unblock_client(client_obj, false); + HOST_EXIT_CRITICAL(); + } break; } case USBH_EVENT_NEW_DEV: { @@ -297,8 +309,8 @@ static void usbh_event_callback(usbh_event_data_t *event_data, void *arg) break; } case USBH_EVENT_DEV_FREE: { - // Let the Hub driver know that the device is free - ESP_ERROR_CHECK(hub_dev_is_free(event_data->dev_free_data.dev_addr)); + // Let the Hub driver know that the device is free and its port can be recycled + ESP_ERROR_CHECK(hub_port_recycle(event_data->dev_free_data.dev_uid)); break; } case USBH_EVENT_ALL_FREE: { @@ -420,7 +432,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) .enum_filter_cb = config->enum_filter_cb, #endif // ENABLE_ENUM_FILTER_CALLBACK }; - ret = hub_install(&hub_config); + ret = hub_install(&hub_config, &host_lib_obj->constant.hub_client); if (ret != ESP_OK) { goto hub_err; } diff --git a/components/usb/usbh.c b/components/usb/usbh.c index 06d6f8d942e..b402e72a996 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -57,7 +57,8 @@ struct device_s { uint32_t in_pending_list: 1; uint32_t is_gone: 1; // Device is gone (disconnected or port error) uint32_t waiting_free: 1; // Device object is awaiting to be freed - uint32_t reserved29: 29; + uint32_t enum_lock: 1; // Device is locked for enumeration. Enum information (e.g., address, device/config desc etc) may change + uint32_t reserved28: 28; }; uint32_t val; } flags; @@ -74,17 +75,22 @@ struct device_s { */ endpoint_t *endpoints[NUM_NON_DEFAULT_EP]; } mux_protected; - // Constant members do not change after device allocation and enumeration thus do not require a critical section + // Constant members do not require a critical section struct { + // Assigned on device allocation and remain constant for the device's lifetime hcd_pipe_handle_t default_pipe; hcd_port_handle_t port_hdl; - uint8_t address; usb_speed_t speed; - const usb_device_desc_t *desc; - const usb_config_desc_t *config_desc; - const usb_str_desc_t *str_desc_manu; - const usb_str_desc_t *str_desc_product; - const usb_str_desc_t *str_desc_ser_num; + unsigned int uid; + /* + These fields are can only be changed when enum_lock is set, thus can be treated as constant + */ + uint8_t address; + usb_device_desc_t *desc; + usb_config_desc_t *config_desc; + usb_str_desc_t *str_desc_manu; + usb_str_desc_t *str_desc_product; + usb_str_desc_t *str_desc_ser_num; } constant; }; @@ -143,6 +149,50 @@ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags); // ----------------------------------------------------- Helpers ------------------------------------------------------- +static device_t *_find_dev_from_uid(unsigned int uid) +{ + /* + THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION + */ + device_t *dev_iter; + + // Search the device lists for a device with the specified address + TAILQ_FOREACH(dev_iter, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { + if (dev_iter->constant.uid == uid) { + return dev_iter; + } + } + TAILQ_FOREACH(dev_iter, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { + if (dev_iter->constant.uid == uid) { + return dev_iter; + } + } + + return NULL; +} + +static device_t *_find_dev_from_addr(uint8_t dev_addr) +{ + /* + THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION + */ + device_t *dev_iter; + + // Search the device lists for a device with the specified address + TAILQ_FOREACH(dev_iter, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { + if (dev_iter->constant.address == dev_addr) { + return dev_iter; + } + } + TAILQ_FOREACH(dev_iter, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { + if (dev_iter->constant.address == dev_addr) { + return dev_iter; + } + } + + return NULL; +} + static inline bool check_ep_addr(uint8_t bEndpointAddress) { /* @@ -204,13 +254,21 @@ static bool urb_check_args(urb_t *urb) return true; } -static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in) +static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, unsigned int mps, bool is_in) { if (type == USB_TRANSFER_TYPE_CTRL) { // Check that num_bytes and wLength are set correctly usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; - if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) { - ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes and usb_setup_packet_t wLength mismatch"); + bool mismatch = false; + if (is_in) { + // For IN transfers, 'num_bytes >= sizeof(usb_setup_packet_t) + setup_pkt->wLength' due to MPS rounding + mismatch = (transfer->num_bytes < sizeof(usb_setup_packet_t) + setup_pkt->wLength); + } else { + // For OUT transfers, num_bytes must match 'sizeof(usb_setup_packet_t) + setup_pkt->wLength' + mismatch = (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength); + } + if (mismatch) { + ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes %d and usb_setup_packet_t wLength %d mismatch", transfer->num_bytes, setup_pkt->wLength); return false; } } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) { @@ -300,19 +358,21 @@ static void endpoint_free(endpoint_t *ep_obj) heap_caps_free(ep_obj); } -static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, device_t **dev_obj_ret) +static esp_err_t device_alloc(unsigned int uid, + usb_speed_t speed, + hcd_port_handle_t port_hdl, + device_t **dev_obj_ret) { - esp_err_t ret; device_t *dev_obj = heap_caps_calloc(1, sizeof(device_t), MALLOC_CAP_DEFAULT); - usb_device_desc_t *dev_desc = heap_caps_calloc(1, sizeof(usb_device_desc_t), MALLOC_CAP_DEFAULT); - if (dev_obj == NULL || dev_desc == NULL) { - ret = ESP_ERR_NO_MEM; - goto err; + if (dev_obj == NULL) { + return ESP_ERR_NO_MEM; } - // Allocate a pipe for EP0. We set the pipe callback to NULL for now + + esp_err_t ret; + // Allocate a pipe for EP0 hcd_pipe_config_t pipe_config = { - .callback = NULL, - .callback_arg = NULL, + .callback = ep0_pipe_callback, + .callback_arg = (void *)dev_obj, .context = (void *)dev_obj, .ep_desc = NULL, // No endpoint descriptor means we're allocating a pipe for EP0 .dev_speed = speed, @@ -327,15 +387,17 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev dev_obj->dynamic.state = USB_DEVICE_STATE_DEFAULT; dev_obj->constant.default_pipe = default_pipe_hdl; dev_obj->constant.port_hdl = port_hdl; - // Note: dev_obj->constant.address is assigned later during enumeration dev_obj->constant.speed = speed; - dev_obj->constant.desc = dev_desc; + dev_obj->constant.uid = uid; + // Note: Enumeration related dev_obj->constant fields are initialized later using usbh_dev_set_...() functions + + // Write-back device object *dev_obj_ret = dev_obj; ret = ESP_OK; + return ret; err: - heap_caps_free(dev_desc); heap_caps_free(dev_obj); return ret; } @@ -345,21 +407,24 @@ static void device_free(device_t *dev_obj) if (dev_obj == NULL) { return; } - // Configuration might not have been allocated (in case of early enumeration failure) + // Device descriptor might not have been set yet + if (dev_obj->constant.desc) { + heap_caps_free(dev_obj->constant.desc); + } + // Configuration descriptor might not have been set yet if (dev_obj->constant.config_desc) { - heap_caps_free((usb_config_desc_t *)dev_obj->constant.config_desc); + heap_caps_free(dev_obj->constant.config_desc); } - // String descriptors might not have been allocated (in case of early enumeration failure) + // String descriptors might not have been set yet if (dev_obj->constant.str_desc_manu) { - heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_manu); + heap_caps_free(dev_obj->constant.str_desc_manu); } if (dev_obj->constant.str_desc_product) { - heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_product); + heap_caps_free(dev_obj->constant.str_desc_product); } if (dev_obj->constant.str_desc_ser_num) { - heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_ser_num); + heap_caps_free(dev_obj->constant.str_desc_ser_num); } - heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc); ESP_ERROR_CHECK(hcd_pipe_free(dev_obj->constant.default_pipe)); heap_caps_free(dev_obj); } @@ -426,6 +491,9 @@ static bool epN_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags) { + /* + THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION + */ if (action_flags == 0) { return false; } @@ -512,7 +580,7 @@ static inline void handle_prop_gone_evt(device_t *dev_obj) static inline void handle_free(device_t *dev_obj) { // Cache a copy of the device's address as we are about to free the device object - const uint8_t dev_addr = dev_obj->constant.address; + const unsigned int dev_uid = dev_obj->constant.uid; bool all_free; ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address); @@ -536,7 +604,7 @@ static inline void handle_free(device_t *dev_obj) usbh_event_data_t event_data = { .event = USBH_EVENT_DEV_FREE, .dev_free_data = { - .dev_addr = dev_addr, + .dev_uid = dev_uid, } }; p_usbh_obj->constant.event_cb(&event_data, p_usbh_obj->constant.event_cb_arg); @@ -661,8 +729,6 @@ esp_err_t usbh_process(void) --------------------------------------------------------------------- */ USBH_EXIT_CRITICAL(); ESP_LOGD(USBH_TAG, "Processing actions 0x%"PRIx32"", action_flags); - // Sanity check. If the device is being freed, there must not be any other action flags set - assert(!(action_flags & DEV_ACTION_FREE) || action_flags == DEV_ACTION_FREE); if (action_flags & DEV_ACTION_EPn_HALT_FLUSH) { handle_epn_halt_flush(dev_obj); @@ -714,24 +780,42 @@ esp_err_t usbh_devs_num(int *num_devs_ret) esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret) { USBH_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG); - USBH_ENTER_CRITICAL(); int num_filled = 0; device_t *dev_obj; - // Fill list with devices from idle tailq + + USBH_ENTER_CRITICAL(); + /* + Fill list with devices from idle tailq and pending tailq. Only devices that + are fully enumerated are added to the list. Thus, the following devices are + not excluded: + - Devices with their enum_lock set + - Devices not in the configured state + - Devices with address 0 + */ TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { if (num_filled < list_len) { - dev_addr_list[num_filled] = dev_obj->constant.address; - num_filled++; + if (!dev_obj->dynamic.flags.enum_lock && + dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED && + dev_obj->constant.address != 0) { + dev_addr_list[num_filled] = dev_obj->constant.address; + num_filled++; + } } else { + // Address list is already full break; } } // Fill list with devices from pending tailq TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { if (num_filled < list_len) { - dev_addr_list[num_filled] = dev_obj->constant.address; - num_filled++; + if (!dev_obj->dynamic.flags.enum_lock && + dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED && + dev_obj->constant.address != 0) { + dev_addr_list[num_filled] = dev_obj->constant.address; + num_filled++; + } } else { + // Address list is already full break; } } @@ -741,6 +825,82 @@ esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *nu return ESP_OK; } +esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle_t port_hdl) +{ + USBH_CHECK(port_hdl != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj; + + // Allocate a device object (initialized to address 0) + ret = device_alloc(uid, dev_speed, port_hdl, &dev_obj); + if (ret != ESP_OK) { + return ret; + } + + // We need to take the mux_lock to access mux_protected members + xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); + USBH_ENTER_CRITICAL(); + + // Check that there is not already a device with the same uid + if (_find_dev_from_uid(uid) != NULL) { + ret = ESP_ERR_INVALID_ARG; + goto exit; + } + // Check that there is not already a device currently with address 0 + if (_find_dev_from_addr(0) != NULL) { + ret = ESP_ERR_NOT_FINISHED; + goto exit; + } + // Add the device to the idle device list + TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); + p_usbh_obj->mux_protected.num_device++; + ret = ESP_OK; + +exit: + USBH_EXIT_CRITICAL(); + xSemaphoreGive(p_usbh_obj->constant.mux_lock); + + return ret; +} + +esp_err_t usbh_devs_remove(unsigned int uid) +{ + esp_err_t ret; + device_t *dev_obj; + bool call_proc_req_cb = false; + + USBH_ENTER_CRITICAL(); + dev_obj = _find_dev_from_uid(uid); + if (dev_obj == NULL) { + ret = ESP_ERR_NOT_FOUND; + goto exit; + } + // Mark the device as gone + dev_obj->dynamic.flags.is_gone = 1; + // Check if the device can be freed immediately + if (dev_obj->dynamic.open_count == 0) { + // Device is not currently opened at all. Can free immediately. + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); + } else { + // Device is still opened. Flush endpoints and propagate device gone event + call_proc_req_cb = _dev_set_actions(dev_obj, + DEV_ACTION_EPn_HALT_FLUSH | + DEV_ACTION_EP0_FLUSH | + DEV_ACTION_EP0_DEQUEUE | + DEV_ACTION_PROP_GONE_EVT); + } + ret = ESP_OK; +exit: + USBH_EXIT_CRITICAL(); + + // Call the processing request callback + if (call_proc_req_cb) { + p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); + } + + return ret; +} + esp_err_t usbh_devs_mark_all_free(void) { USBH_ENTER_CRITICAL(); @@ -790,28 +950,17 @@ esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) USBH_ENTER_CRITICAL(); // Go through the device lists to find the device with the specified address - device_t *found_dev_obj = NULL; - device_t *dev_obj; - TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { - if (dev_obj->constant.address == dev_addr) { - found_dev_obj = dev_obj; - goto exit; - } - } - TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { - if (dev_obj->constant.address == dev_addr) { - found_dev_obj = dev_obj; - goto exit; - } - } -exit: - if (found_dev_obj != NULL) { - // The device is not in a state to be opened - if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_free) { + device_t *dev_obj = _find_dev_from_addr(dev_addr); + if (dev_obj != NULL) { + // Check if the device is in a state to be opened + if (dev_obj->dynamic.flags.is_gone || // Device is already gone (disconnected) + dev_obj->dynamic.flags.waiting_free) { // Device is waiting to be freed ret = ESP_ERR_INVALID_STATE; + } else if (dev_obj->dynamic.flags.enum_lock) { // Device's enum_lock is set + ret = ESP_ERR_NOT_ALLOWED; } else { dev_obj->dynamic.open_count++; - *dev_hdl = (usb_device_handle_t)found_dev_obj; + *dev_hdl = (usb_device_handle_t)dev_obj; ret = ESP_OK; } } else { @@ -828,6 +977,8 @@ esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl) device_t *dev_obj = (device_t *)dev_hdl; USBH_ENTER_CRITICAL(); + // Device should never be closed while its enum_lock is + USBH_CHECK_FROM_CRIT(!dev_obj->dynamic.flags.enum_lock, ESP_ERR_NOT_ALLOWED); dev_obj->dynamic.open_count--; bool call_proc_req_cb = false; if (dev_obj->dynamic.open_count == 0) { @@ -845,6 +996,26 @@ esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl) if (call_proc_req_cb) { p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); } + + return ESP_OK; +} + +esp_err_t usbh_devs_new_dev_event(usb_device_handle_t dev_hdl) +{ + device_t *dev_obj = (device_t *)dev_hdl; + bool call_proc_req_cb = false; + + USBH_ENTER_CRITICAL(); + // Device must be in the configured state + USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW_DEV); + USBH_EXIT_CRITICAL(); + + // Call the processing request callback + if (call_proc_req_cb) { + p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); + } + return ESP_OK; } @@ -870,28 +1041,26 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_ USBH_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - esp_err_t ret; - // Device must be configured, or not attached (if it suddenly disconnected) - USBH_ENTER_CRITICAL(); - if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) { - USBH_EXIT_CRITICAL(); - ret = ESP_ERR_INVALID_STATE; - goto exit; - } - // Critical section for the dynamic members dev_info->speed = dev_obj->constant.speed; dev_info->dev_addr = dev_obj->constant.address; - dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0; - USBH_EXIT_CRITICAL(); - assert(dev_obj->constant.config_desc); - dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue; - // String descriptors are allowed to be NULL as not all devices support them + // Device descriptor might not have been set yet + if (dev_obj->constant.desc) { + dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0; + } else { + // Use the default pipe's MPS instead + dev_info->bMaxPacketSize0 = hcd_pipe_get_mps(dev_obj->constant.default_pipe); + } + // Configuration descriptor might not have been set yet + if (dev_obj->constant.config_desc) { + dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue; + } else { + dev_info->bConfigurationValue = 0; + } dev_info->str_desc_manufacturer = dev_obj->constant.str_desc_manu; dev_info->str_desc_product = dev_obj->constant.str_desc_product; dev_info->str_desc_serial_num = dev_obj->constant.str_desc_ser_num; - ret = ESP_OK; -exit: - return ret; + + return ESP_OK; } esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t **dev_desc_ret) @@ -899,10 +1068,6 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t USBH_CHECK(dev_hdl != NULL && dev_desc_ret != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - USBH_ENTER_CRITICAL(); - USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); - USBH_EXIT_CRITICAL(); - *dev_desc_ret = dev_obj->constant.desc; return ESP_OK; } @@ -912,19 +1077,256 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config USBH_CHECK(dev_hdl != NULL && config_desc_ret != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; + *config_desc_ret = dev_obj->constant.config_desc; + + return ESP_OK; +} + +// ----------------------- Setters ------------------------- + +esp_err_t usbh_dev_enum_lock(usb_device_handle_t dev_hdl) +{ + USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + + // We need to take the mux_lock to access mux_protected members + xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); + + /* + The device's enum_lock can only be set when the following conditions are met: + - No other endpoints except EP0 have been allocated + - We are the sole opener + - Device's enum_lock is not already set + */ + // Check that no other endpoints except EP0 have been allocated + bool ep_found = false; + for (int i = 0; i < NUM_NON_DEFAULT_EP; i++) { + if (dev_obj->mux_protected.endpoints[i] != NULL) { + ep_found = true; + break; + } + } + if (ep_found) { + ret = ESP_ERR_INVALID_STATE; + goto exit; + } + // Check that we are the sole opener and enum_lock is not already set + USBH_ENTER_CRITICAL(); + if (!dev_obj->dynamic.flags.enum_lock && (dev_obj->dynamic.open_count == 1)) { + dev_obj->dynamic.flags.enum_lock = true; + ret = ESP_OK; + } else { + ret = ESP_ERR_INVALID_STATE; + } + USBH_EXIT_CRITICAL(); + +exit: + xSemaphoreGive(p_usbh_obj->constant.mux_lock); + + return ret; +} + +esp_err_t usbh_dev_enum_unlock(usb_device_handle_t dev_hdl) +{ + USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); esp_err_t ret; - // Device must be in the configured state + device_t *dev_obj = (device_t *)dev_hdl; + USBH_ENTER_CRITICAL(); - if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { - USBH_EXIT_CRITICAL(); + // Device's enum_lock must have been previously set + if (dev_obj->dynamic.flags.enum_lock) { + assert(dev_obj->dynamic.open_count == 1); // We must still be the sole opener + dev_obj->dynamic.flags.enum_lock = false; + ret = ESP_OK; + } else { + ret = ESP_ERR_INVALID_STATE; + } + USBH_EXIT_CRITICAL(); + + return ret; +} + +esp_err_t usbh_dev_set_ep0_mps(usb_device_handle_t dev_hdl, uint16_t wMaxPacketSize) +{ + USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + + USBH_ENTER_CRITICAL(); + // Device's EP0 MPS can only be updated when in the default state + if (dev_obj->dynamic.state != USB_DEVICE_STATE_DEFAULT) { ret = ESP_ERR_INVALID_STATE; goto exit; } + // Device's enum_lock must be set before enumeration related data fields can be set + if (dev_obj->dynamic.flags.enum_lock) { + ret = hcd_pipe_update_mps(dev_obj->constant.default_pipe, wMaxPacketSize); + } else { + ret = ESP_ERR_NOT_ALLOWED; + } +exit: USBH_EXIT_CRITICAL(); - assert(dev_obj->constant.config_desc); - *config_desc_ret = dev_obj->constant.config_desc; + + return ret; +} + +esp_err_t usbh_dev_set_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr) +{ + USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + + USBH_ENTER_CRITICAL(); + // Device's address can only be set when in the default state + USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_DEFAULT, ESP_ERR_INVALID_STATE); + // Device's enum_lock must be set before enumeration related data fields can be set + USBH_CHECK_FROM_CRIT(dev_obj->dynamic.flags.enum_lock, ESP_ERR_NOT_ALLOWED); + // Update the device and default pipe's target address + ret = hcd_pipe_update_dev_addr(dev_obj->constant.default_pipe, dev_addr); + if (ret == ESP_OK) { + dev_obj->constant.address = dev_addr; + dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS; + } + USBH_EXIT_CRITICAL(); + + return ret; +} + +esp_err_t usbh_dev_set_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc) +{ + USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + usb_device_desc_t *new_desc, *old_desc; + + // Allocate and copy new device descriptor + new_desc = heap_caps_malloc(sizeof(usb_device_desc_t), MALLOC_CAP_DEFAULT); + if (new_desc == NULL) { + return ESP_ERR_NO_MEM; + } + memcpy(new_desc, device_desc, sizeof(usb_device_desc_t)); + + USBH_ENTER_CRITICAL(); + // Device's descriptor can only be set in the default or addressed state + if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_DEFAULT || dev_obj->dynamic.state == USB_DEVICE_STATE_ADDRESS)) { + ret = ESP_ERR_INVALID_STATE; + goto err; + } + // Device's enum_lock must be set before we can set its device descriptor + if (!dev_obj->dynamic.flags.enum_lock) { + ret = ESP_ERR_NOT_ALLOWED; + goto err; + } + old_desc = dev_obj->constant.desc; // Save old descriptor for cleanup + dev_obj->constant.desc = new_desc; // Assign new descriptor + USBH_EXIT_CRITICAL(); + + // Clean up old descriptor or failed assignment + heap_caps_free(old_desc); ret = ESP_OK; -exit: + + return ret; + +err: + USBH_EXIT_CRITICAL(); + heap_caps_free(new_desc); + return ret; +} + +esp_err_t usbh_dev_set_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full) +{ + USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + usb_config_desc_t *new_desc, *old_desc; + + // Allocate and copy new config descriptor + new_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); + if (new_desc == NULL) { + return ESP_ERR_NO_MEM; + } + memcpy(new_desc, config_desc_full, config_desc_full->wTotalLength); + + USBH_ENTER_CRITICAL(); + // Device's config descriptor can only be set when in the addressed state + if (dev_obj->dynamic.state != USB_DEVICE_STATE_ADDRESS) { + ret = ESP_ERR_INVALID_STATE; + goto err; + } + // Device's enum_lock must be set before we can set its config descriptor + if (!dev_obj->dynamic.flags.enum_lock) { + ret = ESP_ERR_NOT_ALLOWED; + goto err; + } + old_desc = dev_obj->constant.config_desc; // Save old descriptor for cleanup + dev_obj->constant.config_desc = new_desc; // Assign new descriptor + dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED; + USBH_EXIT_CRITICAL(); + + // Clean up old descriptor or failed assignment + heap_caps_free(old_desc); + ret = ESP_OK; + + return ret; + +err: + USBH_EXIT_CRITICAL(); + heap_caps_free(new_desc); + return ret; +} + +esp_err_t usbh_dev_set_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select) +{ + USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + usb_str_desc_t *new_desc, *old_desc; + + // Allocate and copy new string descriptor + new_desc = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT); + if (new_desc == NULL) { + return ESP_ERR_NO_MEM; + } + memcpy(new_desc, str_desc, str_desc->bLength); + + USBH_ENTER_CRITICAL(); + // Device's string descriptors can only be set when in the default state + if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { + ret = ESP_ERR_INVALID_STATE; + goto err; + } + // Device's enum_lock must be set before we can set its string descriptors + if (!dev_obj->dynamic.flags.enum_lock) { + ret = ESP_ERR_NOT_ALLOWED; + goto err; + } + // Assign to the selected descriptor + switch (select) { + case 0: + old_desc = dev_obj->constant.str_desc_manu; + dev_obj->constant.str_desc_manu = new_desc; + break; + case 1: + old_desc = dev_obj->constant.str_desc_product; + dev_obj->constant.str_desc_product = new_desc; + break; + default: // 2 + old_desc = dev_obj->constant.str_desc_ser_num; + dev_obj->constant.str_desc_ser_num = new_desc; + break; + } + USBH_EXIT_CRITICAL(); + + // Clean up old descriptor or failed assignment + heap_caps_free(old_desc); + ret = ESP_OK; + + return ret; + +err: + USBH_EXIT_CRITICAL(); + heap_caps_free(new_desc); return ret; } @@ -939,6 +1341,7 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config esp_err_t ret; device_t *dev_obj = (device_t *)dev_hdl; endpoint_t *ep_obj; + USBH_CHECK(dev_obj->constant.config_desc, ESP_ERR_INVALID_STATE); // Configuration descriptor must be set // Find the endpoint descriptor from the device's current configuration descriptor const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(dev_obj->constant.config_desc, ep_config->bInterfaceNumber, ep_config->bAlternateSetting, ep_config->bEndpointAddress, NULL); @@ -1065,10 +1468,11 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb) device_t *dev_obj = (device_t *)dev_hdl; USBH_CHECK(urb_check_args(urb), ESP_ERR_INVALID_ARG); bool xfer_is_in = ((usb_setup_packet_t *)urb->transfer.data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; - USBH_CHECK(transfer_check_usb_compliance(&(urb->transfer), USB_TRANSFER_TYPE_CTRL, dev_obj->constant.desc->bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG); + // Device descriptor could still be NULL at this point, so we get the MPS from the pipe instead. + unsigned int mps = hcd_pipe_get_mps(dev_obj->constant.default_pipe); + USBH_CHECK(transfer_check_usb_compliance(&(urb->transfer), USB_TRANSFER_TYPE_CTRL, mps, xfer_is_in), ESP_ERR_INVALID_ARG); USBH_ENTER_CRITICAL(); - USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); // Increment the control transfer count first dev_obj->dynamic.num_ctrl_xfers_inflight++; USBH_EXIT_CRITICAL(); @@ -1121,156 +1525,3 @@ esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret) *urb_ret = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); return ESP_OK; } - -// -------------------------------------------------- Hub Functions ---------------------------------------------------- - -// ------------------- Device Related ---------------------- - -esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl) -{ - // Note: Parent device handle can be NULL if it's connected to the root hub - USBH_CHECK(new_dev_hdl != NULL, ESP_ERR_INVALID_ARG); - esp_err_t ret; - device_t *dev_obj; - ret = device_alloc(port_hdl, dev_speed, &dev_obj); - if (ret != ESP_OK) { - return ret; - } - // Write-back device handle - *new_dev_hdl = (usb_device_handle_t)dev_obj; - *default_pipe_hdl = dev_obj->constant.default_pipe; - ret = ESP_OK; - return ret; -} - -esp_err_t usbh_hub_dev_gone(usb_device_handle_t dev_hdl) -{ - USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - bool call_proc_req_cb; - - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.flags.is_gone = 1; - // Check if the device can be freed immediately - if (dev_obj->dynamic.open_count == 0) { - // Device is not currently opened at all. Can free immediately. - call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); - } else { - // Device is still opened. Flush endpoints and propagate device gone event - call_proc_req_cb = _dev_set_actions(dev_obj, - DEV_ACTION_EPn_HALT_FLUSH | - DEV_ACTION_EP0_FLUSH | - DEV_ACTION_EP0_DEQUEUE | - DEV_ACTION_PROP_GONE_EVT); - } - USBH_EXIT_CRITICAL(); - - if (call_proc_req_cb) { - p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); - } - return ESP_OK; -} - -// ----------------- Enumeration Related ------------------- - -esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr) -{ - USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS; - USBH_EXIT_CRITICAL(); - - // We can modify the info members outside the critical section - dev_obj->constant.address = dev_addr; - return ESP_OK; -} - -esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc) -{ - USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - // We can modify the info members outside the critical section - memcpy((usb_device_desc_t *)dev_obj->constant.desc, device_desc, sizeof(usb_device_desc_t)); - return ESP_OK; -} - -esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full) -{ - USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - // Allocate memory to store the configuration descriptor - usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); // Buffer to copy over full configuration descriptor (wTotalLength) - if (config_desc == NULL) { - return ESP_ERR_NO_MEM; - } - // Copy the configuration descriptor - memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength); - // Assign the config desc to the device object - assert(dev_obj->constant.config_desc == NULL); - dev_obj->constant.config_desc = config_desc; - return ESP_OK; -} - -esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select) -{ - USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - // Allocate memory to store the manufacturer string descriptor - usb_str_desc_t *str_desc_fill = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT); - if (str_desc_fill == NULL) { - return ESP_ERR_NO_MEM; - } - // Copy the string descriptor - memcpy(str_desc_fill, str_desc, str_desc->bLength); - // Assign filled string descriptor to the device object - switch (select) { - case 0: - assert(dev_obj->constant.str_desc_manu == NULL); - dev_obj->constant.str_desc_manu = str_desc_fill; - break; - case 1: - assert(dev_obj->constant.str_desc_product == NULL); - dev_obj->constant.str_desc_product = str_desc_fill; - break; - default: // 2 - assert(dev_obj->constant.str_desc_ser_num == NULL); - dev_obj->constant.str_desc_ser_num = str_desc_fill; - break; - } - return ESP_OK; -} - -esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl) -{ - USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - - // We need to take the mux_lock to access mux_protected members - xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED; - // Add the device to list of devices, then trigger a device event - TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); // Add it to the idle device list first - bool call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW_DEV); - USBH_EXIT_CRITICAL(); - p_usbh_obj->mux_protected.num_device++; - xSemaphoreGive(p_usbh_obj->constant.mux_lock); - - // Update the EP0's underlying pipe's callback - ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, ep0_pipe_callback, (void *)dev_obj)); - // Call the processing request callback - if (call_proc_req_cb) { - p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); - } - return ESP_OK; -} - -esp_err_t usbh_hub_enum_failed(usb_device_handle_t dev_hdl) -{ - USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - device_free(dev_obj); - return ESP_OK; -} From 7db459d85f6db1388c25a7cc96dc79dabee8e944 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Wed, 17 Apr 2024 01:52:21 +0800 Subject: [PATCH 425/548] docs(usb): Add USBH maintainer notes --- docs/conf_common.py | 3 +- docs/docs_not_updated/esp32c5.txt | 1 + docs/docs_not_updated/esp32p4.txt | 1 + .../usb_host/usb_host_notes_index.rst | 2 +- .../usb_host/usb_host_notes_usbh.rst | 115 ++++++++++++++++++ .../usb_host/usb_host_notes_arch.rst | 3 +- .../usb_host/usb_host_notes_index.rst | 8 +- .../usb_host/usb_host_notes_usbh.rst | 1 + 8 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 docs/en/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst create mode 100644 docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst diff --git a/docs/conf_common.py b/docs/conf_common.py index a0b4ace54c4..2bdebec6ca0 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -117,7 +117,8 @@ 'api-reference/peripherals/usb_host/usb_host_notes_arch.rst', 'api-reference/peripherals/usb_host/usb_host_notes_design.rst', 'api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst', - 'api-reference/peripherals/usb_host/usb_host_notes_index.rst'] + 'api-reference/peripherals/usb_host/usb_host_notes_index.rst', + 'api-reference/peripherals/usb_host/usb_host_notes_usbh.rst'] I80_LCD_DOCS = ['api-reference/peripherals/lcd/i80_lcd.rst'] RGB_LCD_DOCS = ['api-reference/peripherals/lcd/rgb_lcd.rst'] diff --git a/docs/docs_not_updated/esp32c5.txt b/docs/docs_not_updated/esp32c5.txt index 786d0766876..10ed4b965cf 100644 --- a/docs/docs_not_updated/esp32c5.txt +++ b/docs/docs_not_updated/esp32c5.txt @@ -87,6 +87,7 @@ api-reference/peripherals/usb_host/usb_host_notes_arch.rst api-reference/peripherals/usb_host/usb_host_notes_index.rst api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst api-reference/peripherals/usb_host/usb_host_notes_design.rst +api-reference/peripherals/usb_host/usb_host_notes_usbh.rst api-reference/peripherals/hmac.rst api-reference/peripherals/usb_device.rst api-reference/peripherals/sdspi_host.rst diff --git a/docs/docs_not_updated/esp32p4.txt b/docs/docs_not_updated/esp32p4.txt index 419e2293dbd..9568af83ef8 100644 --- a/docs/docs_not_updated/esp32p4.txt +++ b/docs/docs_not_updated/esp32p4.txt @@ -16,6 +16,7 @@ api-reference/peripherals/usb_host/usb_host_notes_arch.rst api-reference/peripherals/usb_host/usb_host_notes_index.rst api-reference/peripherals/usb_host/usb_host_notes_dwc_otg.rst api-reference/peripherals/usb_host/usb_host_notes_design.rst +api-reference/peripherals/usb_host/usb_host_notes_usbh.rst api-reference/peripherals/usb_device.rst api-reference/peripherals/touch_element.rst api-reference/peripherals/spi_flash/xip_from_psram.inc diff --git a/docs/en/api-reference/peripherals/usb_host/usb_host_notes_index.rst b/docs/en/api-reference/peripherals/usb_host/usb_host_notes_index.rst index 0cff74a4668..2d23befb42f 100644 --- a/docs/en/api-reference/peripherals/usb_host/usb_host_notes_index.rst +++ b/docs/en/api-reference/peripherals/usb_host/usb_host_notes_index.rst @@ -21,12 +21,12 @@ This document is split into the following sections: usb_host_notes_design usb_host_notes_arch usb_host_notes_dwc_otg + usb_host_notes_usbh Todo: - USB Host Maintainers Notes (HAL & LL) - USB Host Maintainers Notes (HCD) -- USB Host Maintainers Notes (USBH) - USB Host Maintainers Notes (Hub) - USB Host Maintainers Notes (USB Host Library) diff --git a/docs/en/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst b/docs/en/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst new file mode 100644 index 00000000000..b1cd35fad90 --- /dev/null +++ b/docs/en/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst @@ -0,0 +1,115 @@ +USB Host Driver (USBH) +====================== + +Introduction +------------ + +The USB Host Driver (henceforth referred to as USBH) provides a USB Host software interface which abstracts USB devices. The USBH interface provides APIs to... + +- manage the device pool (i.e., adding and removing devices) +- address and configure a device (i.e., setting device and configuration descriptors) +- submit transfers to a particular endpoint of a device + +Requirements +------------ + +USB Specification Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Chapter 10 of the USB 2.0 specification outlines some requirements of the USBH (referred to as USBD in the specification). The design of the USBH takes into consideration these requirements from the specification. + +- Default pipe of a device is owned by the USBH +- All other pipes are owned and managed by clients of the USBH +- USBH interface must provide the following services + + - Configuration and command mechanism + - Transfer services via both command and pipe mechanisms + - Event notification + - Status reporting and error recovery + +Host Stack Requirements +^^^^^^^^^^^^^^^^^^^^^^^ + +In addition to the USB 2.0 specification requirements, the USBH also takes into consideration the requirements set for the overall Host Stack (see :doc:`./usb_host_notes_design`): + +- USBH must not instantiate any tasks/threads +- USBH must be event driven, providing event callbacks and an event processing function + +Implementation & Usage +---------------------- + +Events & Processing +^^^^^^^^^^^^^^^^^^^ + +The USBH is completely event driven and all event handling is done via then ``usbh_process()`` function. The ``usbh_config_t.proc_req_cb`` callback provided on USBH installation will be called when processing is required. Typically, ``usbh_process()`` will be called from a dedicated thread/task. + +The USBH exposes the following event callbacks: + +- ``usbh_event_cb_t`` used to indicate various events regarding a particular device and control transfers to EP0. This callback is called from the context of ``usbh_process()`` +- ``usbh_ep_cb_t`` used to indicate events for all other endpoints. This callback is not called from the ``usbh_process()`` context (currently called from an HCD interrupt context). + +Device Pool +^^^^^^^^^^^ + +The USBH keeps track of all currently connected devices by internally maintaining a device pool (simply a linked list) where each device is represented by a device object. + +The USB 2.0 specification "assumes a specialized client of the USBD, called a hub driver, that acts as a clearinghouse for the addition and removal of devices from a particular hub". As a result, the USBH is completely reliant on an external client(s) (typically a Hub Driver) to inform the USBH of device addition and removal. The USBH provides the following APIs for device addition and removal: + +- ``usbh_devs_add()`` which will allocate a new device object and add it to the device pool. The newly added device will be unenumerated, meaning the device object will... + + - be assigned to address 0 + - have no device and configuration descriptor + +- ``usbh_devs_remove()`` which will indicate to the USBH that a device has been removed (such as due to a disconnection or a port error). + + - If the device is not currently opened (i.e., used by one or more clients), the USBH will free the underlying device object immediately. + - If the device is currently opened, a ``USBH_EVENT_DEV_GONE`` event will be propagated and the device will be flagged for removal. The last client to close the device will free the device object. + - When a device object is freed, a ``USBH_EVENT_DEV_FREE`` event will be propagated. This event is used to indicate that the device's upstream port can be recycled. + +Device Enumeration +^^^^^^^^^^^^^^^^^^ + +Newly added devices will need to be enumerated. The USBH provides various ``usbh_dev_set_...()`` functions to enumerate the device, such as assigning the device's address and setting device/configuration/string descriptors. Given that USBH devices can be shared by multiple clients, attempting to enumerate a device while another client has opened the device can cause issues. + +Thus, before calling any ``usbh_dev_set_...()`` enumeration function, a device must be locked for enumeration by calling ``usbh_dev_enum_lock()``. This prevents the device from being opened by any other client but the enumerating client. + +After enumeration is complete, the enumerating client can call ``usbh_devs_trigger_new_dev_event()`` to propagate a ``USBH_EVENT_NEW_DEV`` event. + +Device Usage +^^^^^^^^^^^^ + +Clients that want to use a device must open the device by calling ``usbh_devs_open()`` and providing the device's address. The device's address can either be obtained from a ``USBH_EVENT_NEW_DEV`` event or by calling ``usbh_devs_addr_list_fill()``. + +Opening a device will do the following: + +- Return a ``usb_device_handle_t`` device handle which can be used to refer to the device in various USBH functions +- Increment the device's internal ``open_count`` which indicates how many clients have opened the device. As long as ``open_count > 0``, the underlying device object will not be freed, thus guaranteeing that the device handle refers to a valid device object. + +Once a client no longer needs to use a device, the client should call ``usbh_devs_close()`` thus invalidating the device handle. + +.. note:: + + Most device related APIs accept ``usb_device_handle_t`` as an argument, which means that the calling client must have previously opened the device to obtain the device handle beforehand. This design choice is intentional in order to enforce an "open before use" pattern. + + However, a limited set of APIs (e.g., ``usbh_devs_remove()``) refer to devices using a Unique Identifier (``uid``) which is assigned on device addition (see ``usbh_devs_add()``). The use of ``uid`` in these functions allows their callers to refer to a device **without needing to open it** due to the lack of a ``usb_device_handle_t``. + + As a result, it is possible that a caller of a ``uid`` function may refer to a device that has already been freed. Thus, callers should account for a fact that these functions may return :c:macro:`ESP_ERR_NOT_FOUND`. + +Endpoints & Transfers +^^^^^^^^^^^^^^^^^^^^^ + +USBH supports transfer to default (i.e., EP0) and non-default endpoints. + +For non-default endpoints: + +- A client must first allocate the endpoint by calling ``usbh_ep_alloc()`` which assigns a ``usbh_ep_cb_t`` callback and returns a ``usbh_ep_handle_t`` endpoint handle so that the endpoint can be referred to. +- A client can then enqueue a ``urb_t`` transfer to the endpoint by calling ``usbh_ep_enqueue_urb()``. +- The ``usbh_ep_cb_t`` callback is called to indicate transfer completion +- The client must then dequeue the transfer using ``usbh_ep_dequeue_urb()`` + +Default endpoints are owned and managed by the USBH, thus API for control transfers are different: + +- EP0 is always allocated for each device, thus clients do no need to allocate EP0 or provide an endpoint callback. +- Clients call should call ``usbh_dev_submit_ctrl_urb()`` to submit a control transfer to a device's EP0. +- A ``USBH_EVENT_CTRL_XFER`` event will be propagated when the transfer is complete +- Control transfers do not need to be dequeued diff --git a/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_arch.rst b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_arch.rst index bebedf8f358..3670348e5a2 100644 --- a/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_arch.rst +++ b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_arch.rst @@ -1,2 +1 @@ -.. include:: ../../../../en/api-reference/peripherals/usb_host/usb_host_notes_arch - .rst +.. include:: ../../../../en/api-reference/peripherals/usb_host/usb_host_notes_arch.rst diff --git a/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_index.rst b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_index.rst index 020a913ef7c..1ab83954de2 100644 --- a/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_index.rst +++ b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_index.rst @@ -21,14 +21,14 @@ USB 主机维护者注意事项(简介) usb_host_notes_design usb_host_notes_arch usb_host_notes_dwc_otg + usb_host_notes_usbh 待写章节: - USB 主机维护者注意事项(HAL 和 LL) -- USB 主机维护者注意事项 (HCD) -- USB 主机维护者注意事项 (USBH) -- USB 主机维护者注意事项 (Hub) -- USB 主机维护者注意事项 (USB Host Library) +- USB 主机维护者注意事项(HCD) +- USB 主机维护者注意事项(Hub) +- USB 主机维护者注意事项(USB Host Library) .. -------------------------------------------------- Introduction ----------------------------------------------------- diff --git a/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst new file mode 100644 index 00000000000..262547c0f01 --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst @@ -0,0 +1 @@ +.. include:: ../../../../en/api-reference/peripherals/usb_host/usb_host_notes_usbh.rst From a2666d6f2c5473fa1507aae92210ff7cf0da8b30 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 16 Jul 2024 13:43:56 +0530 Subject: [PATCH 426/548] fix(wifi_prov): Added API to set random address --- .../include/transports/protocomm_ble.h | 5 ++ .../protocomm/src/simple_ble/simple_ble.c | 14 +++++- .../protocomm/src/simple_ble/simple_ble.h | 3 ++ .../protocomm/src/transports/protocomm_ble.c | 11 ++++- .../src/transports/protocomm_nimble.c | 41 +++++++++++++--- .../include/wifi_provisioning/scheme_ble.h | 47 +++++++++++++------ components/wifi_provisioning/src/scheme_ble.c | 24 +++++++++- .../wifi_prov_mgr/main/app_main.c | 2 +- tools/ci/check_copyright_ignore.txt | 1 - 9 files changed, 121 insertions(+), 27 deletions(-) diff --git a/components/protocomm/include/transports/protocomm_ble.h b/components/protocomm/include/transports/protocomm_ble.h index 51aec06e99f..cbc7c81bd52 100644 --- a/components/protocomm/include/transports/protocomm_ble.h +++ b/components/protocomm/include/transports/protocomm_ble.h @@ -41,6 +41,7 @@ typedef enum { * (29 - (BLE device name length) - 2). */ #define MAX_BLE_MANUFACTURER_DATA_LEN 29 +#define BLE_ADDR_LEN 6 /** * @brief This structure maps handler required by protocomm layer to * UUIDs which are used to uniquely identify BLE characteristics @@ -137,6 +138,10 @@ typedef struct protocomm_ble_config { */ unsigned ble_link_encryption:1; + /** + * BLE address + */ + uint8_t *ble_addr; } protocomm_ble_config_t; /** diff --git a/components/protocomm/src/simple_ble/simple_ble.c b/components/protocomm/src/simple_ble/simple_ble.c index 79100f2db62..709024d3025 100644 --- a/components/protocomm/src/simple_ble/simple_ble.c +++ b/components/protocomm/src/simple_ble/simple_ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,12 +49,24 @@ static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: adv_config_done &= (~adv_config_flag); + + if (g_ble_cfg_p->ble_addr) { + esp_ble_gap_set_rand_addr(g_ble_cfg_p->ble_addr); + g_ble_cfg_p->adv_params.own_addr_type = BLE_ADDR_TYPE_RANDOM; + } + if (adv_config_done == 0) { esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params); } break; case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT: adv_config_done &= (~scan_rsp_config_flag); + + if (g_ble_cfg_p->ble_addr) { + esp_ble_gap_set_rand_addr(g_ble_cfg_p->ble_addr); + g_ble_cfg_p->adv_params.own_addr_type = BLE_ADDR_TYPE_RANDOM; + } + if (adv_config_done == 0) { esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params); } diff --git a/components/protocomm/src/simple_ble/simple_ble.h b/components/protocomm/src/simple_ble/simple_ble.h index 06d2bfa7b2b..259225de830 100644 --- a/components/protocomm/src/simple_ble/simple_ble.h +++ b/components/protocomm/src/simple_ble/simple_ble.h @@ -51,6 +51,9 @@ typedef struct { unsigned ble_bonding:1; /** BLE Secure Connection flag */ unsigned ble_sm_sc:1; + /** BLE Address */ + uint8_t *ble_addr; + } simple_ble_cfg_t; diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index 322c6086411..6fedd85abb9 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -103,6 +103,7 @@ static esp_ble_adv_params_t adv_params = { static char *protocomm_ble_device_name = NULL; static uint8_t *protocomm_ble_mfg_data = NULL; static size_t protocomm_ble_mfg_data_len; +static uint8_t *protocomm_ble_addr = NULL; static void hexdump(const char *msg, uint8_t *buf, int len) { @@ -524,6 +525,10 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con protocomm_ble_mfg_data_len = config->manufacturer_data_len; } + if (config->ble_addr != NULL) { + protocomm_ble_addr = config->ble_addr; + } + protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t)); if (protoble_internal == NULL) { ESP_LOGE(TAG, "Error allocating internal protocomm structure"); @@ -594,6 +599,10 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con ble_config->ble_bonding = config->ble_bonding; ble_config->ble_sm_sc = config->ble_sm_sc; + if (config->ble_addr != NULL) { + ble_config->ble_addr = protocomm_ble_addr; + } + if (ble_config->gatt_db_count == -1) { ESP_LOGE(TAG, "Invalid GATT database count"); simple_ble_deinit(); diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c index 1f6e5565783..8aa2e4ec6de 100644 --- a/components/protocomm/src/transports/protocomm_nimble.c +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -79,6 +79,7 @@ static struct ble_hs_adv_fields adv_data, resp_data; static uint8_t *protocomm_ble_mfg_data; static size_t protocomm_ble_mfg_data_len; +static uint8_t *protocomm_ble_addr; /********************************************************************** * Maintain database of uuid_name addresses to free memory afterwards * **********************************************************************/ @@ -130,6 +131,8 @@ typedef struct { unsigned ble_sm_sc:1; /** BLE Link Encryption flag */ unsigned ble_link_encryption:1; + /** BLE address */ + uint8_t *ble_addr; } simple_ble_cfg_t; static simple_ble_cfg_t *ble_cfg_p; @@ -461,10 +464,25 @@ simple_ble_on_sync(void) { int rc; - rc = ble_hs_util_ensure_addr(0); - if (rc != 0) { - ESP_LOGE(TAG, "Error loading address"); - return; + if (protocomm_ble_addr) { + rc = ble_hs_id_set_rnd(protocomm_ble_addr); + if (rc != 0) { + ESP_LOGE(TAG,"Error in setting address"); + return; + } + + rc = ble_hs_util_ensure_addr(1); + if (rc != 0) { + ESP_LOGE(TAG,"Error loading address"); + return; + } + } + else { + rc = ble_hs_util_ensure_addr(0); + if (rc != 0) { + ESP_LOGE(TAG, "Error loading address"); + return; + } } /* Figure out address to use while advertising (no privacy for now) */ @@ -727,7 +745,7 @@ ble_gatt_add_primary_svcs(struct ble_gatt_svc_def *gatt_db_svcs, int char_count) gatt_db_svcs->type = BLE_GATT_SVC_TYPE_PRIMARY; /* Allocate (number of characteristics + 1) memory for characteristics, the - * addtional characteristic consist of all 0s indicating end of + * additional characteristic consist of all 0s indicating end of * characteristics */ gatt_db_svcs->characteristics = (struct ble_gatt_chr_def *) calloc((char_count + 1), sizeof(struct ble_gatt_chr_def)); @@ -781,7 +799,7 @@ populate_gatt_db(struct ble_gatt_svc_def **gatt_db_svcs, const protocomm_ble_con rc = ble_gatt_add_char_dsc((void *) (*gatt_db_svcs)->characteristics, i, BLE_GATT_UUID_CHAR_DSC); if (rc != 0) { - ESP_LOGE(TAG, "Error adding GATT Discriptor !!"); + ESP_LOGE(TAG, "Error adding GATT Descriptor !!"); return rc; } } @@ -813,6 +831,11 @@ static void protocomm_ble_cleanup(void) protocomm_ble_mfg_data = NULL; protocomm_ble_mfg_data_len = 0; } + + if (protocomm_ble_addr) { + free(protocomm_ble_addr); + protocomm_ble_addr = NULL; + } } static void free_gatt_ble_misc_memory(simple_ble_cfg_t *ble_config) @@ -970,6 +993,10 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con ble_config->ble_bonding = config->ble_bonding; ble_config->ble_sm_sc = config->ble_sm_sc; + if (config->ble_addr != NULL) { + protocomm_ble_addr = config->ble_addr; + } + if (populate_gatt_db(&ble_config->gatt_db, config) != 0) { ESP_LOGE(TAG, "Error populating GATT Database"); free_gatt_ble_misc_memory(ble_config); diff --git a/components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h b/components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h index fc19e16b171..c30a3a86b8b 100644 --- a/components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h +++ b/components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h @@ -1,16 +1,8 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once @@ -65,9 +57,9 @@ void wifi_prov_scheme_ble_event_cb_free_bt (void *user_data, wifi_prov_cb_event * the default UUID will be used. * * @note The data being pointed to by the argument must be valid - * atleast till provisioning is started. Upon start, the + * at least till provisioning is started. Upon start, the * manager will store an internal copy of this UUID, and - * this data can be freed or invalidated afterwords. + * this data can be freed or invalidated afterwards. * * @param[in] uuid128 A custom 128 bit UUID * @@ -100,6 +92,31 @@ esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128); */ esp_err_t wifi_prov_scheme_ble_set_mfg_data(uint8_t *mfg_data, ssize_t mfg_data_len); +/** + * @brief Set Bluetooth Random address + * + * This must be called before starting provisioning, i.e. before + * making a call to wifi_prov_mgr_start_provisioning(). + * + * This API can be used in cases where a new identity address is to be used during + * provisioning. This will result in this device being treated as a new device by remote + * devices. + * + * @note This API will change the existing BD address for the device. The address once + * set will remain unchanged until BLE stack tear down happens when + * wifi_prov_mgr_deinit is invoked. + * + * This API is only to be called to set random address. Re-invoking this API + * after provisioning is started will have no effect. + * + * @param[in] rand_addr The static random address to be set of length 6 bytes. + * + * @return + * - ESP_OK : Success + * - ESP_ERR_INVALID_ARG : Null argument + */ +esp_err_t wifi_prov_scheme_ble_set_random_addr(const uint8_t *rand_addr); + #ifdef __cplusplus } #endif diff --git a/components/wifi_provisioning/src/scheme_ble.c b/components/wifi_provisioning/src/scheme_ble.c index 6b594f22c46..f1240fbaea9 100644 --- a/components/wifi_provisioning/src/scheme_ble.c +++ b/components/wifi_provisioning/src/scheme_ble.c @@ -22,7 +22,7 @@ static const char *TAG = "wifi_prov_scheme_ble"; extern const wifi_prov_scheme_t wifi_prov_scheme_ble; static uint8_t *custom_service_uuid; - +static uint8_t *custom_ble_addr; static uint8_t *custom_manufacturer_data; static size_t custom_manufacturer_data_len; @@ -59,6 +59,22 @@ static esp_err_t prov_start(protocomm_t *pc, void *config) return ESP_OK; } +esp_err_t wifi_prov_scheme_ble_set_random_addr(const uint8_t *addr) +{ + if (!addr) { + return ESP_ERR_INVALID_ARG; + } + + custom_ble_addr = (uint8_t *) malloc(BLE_ADDR_LEN); + if (custom_ble_addr == NULL) { + ESP_LOGE(TAG, "Error allocating memory for random address"); + return ESP_ERR_NO_MEM; + } + + memcpy(custom_ble_addr, addr, BLE_ADDR_LEN); + return ESP_OK; +} + esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128) { if (!uuid128) { @@ -159,6 +175,12 @@ static esp_err_t set_config_service(void *config, const char *service_name, cons ble_config->manufacturer_data_len = 0; } + if (custom_ble_addr){ + ble_config->ble_addr = custom_ble_addr; + } else { + ble_config->ble_addr = NULL; + } + return ESP_OK; } diff --git a/examples/provisioning/wifi_prov_mgr/main/app_main.c b/examples/provisioning/wifi_prov_mgr/main/app_main.c index 9c5f2a50648..233e450fea8 100644 --- a/examples/provisioning/wifi_prov_mgr/main/app_main.c +++ b/examples/provisioning/wifi_prov_mgr/main/app_main.c @@ -136,7 +136,7 @@ static void event_handler(void* arg, esp_event_base_t event_base, #ifdef CONFIG_EXAMPLE_RESET_PROV_MGR_ON_FAILURE retries++; if (retries >= CONFIG_EXAMPLE_PROV_MGR_MAX_RETRY_CNT) { - ESP_LOGI(TAG, "Failed to connect with provisioned AP, reseting provisioned credentials"); + ESP_LOGI(TAG, "Failed to connect with provisioned AP, resetting provisioned credentials"); wifi_prov_mgr_reset_sm_state_on_failure(); retries = 0; } diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index e0fcb163efb..2820f4b8342 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -731,7 +731,6 @@ components/spi_flash/spi_flash_chip_boya.c components/spi_flash/spi_flash_chip_issi.c components/tcp_transport/include/esp_transport_ws.h components/vfs/include/esp_vfs_common.h -components/wifi_provisioning/include/wifi_provisioning/scheme_ble.h components/wifi_provisioning/include/wifi_provisioning/scheme_console.h components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h From 6a9e8278a16cb805ed515d2a17d87b0aae2ea01b Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 24 Jul 2024 17:06:53 +0700 Subject: [PATCH 427/548] feat(examples): upgrade esp_cam_sensor component for isp/auto_focus --- examples/peripherals/isp/auto_focus/main/idf_component.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/peripherals/isp/auto_focus/main/idf_component.yml b/examples/peripherals/isp/auto_focus/main/idf_component.yml index e424be9e274..118d17a8428 100644 --- a/examples/peripherals/isp/auto_focus/main/idf_component.yml +++ b/examples/peripherals/isp/auto_focus/main/idf_component.yml @@ -1,5 +1,5 @@ dependencies: - espressif/esp_cam_sensor: "^0.2.2" + espressif/esp_cam_sensor: "^0.5.*" espressif/esp_lcd_ili9881c: "*" idf: version: ">=5.3.0" From 215e1391cebf3c57c1b70f5b0f5f3366f6620c8d Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Tue, 28 May 2024 12:24:08 +0530 Subject: [PATCH 428/548] fix(hal): updated ecdsa reset api to execute correctly This commit updated API to ensure ECDSA peripheral resets and waits until the state returns to idle. --- components/hal/esp32p4/include/hal/ecdsa_ll.h | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/components/hal/esp32p4/include/hal/ecdsa_ll.h b/components/hal/esp32p4/include/hal/ecdsa_ll.h index 898ce1fd275..f3429cf1b28 100644 --- a/components/hal/esp32p4/include/hal/ecdsa_ll.h +++ b/components/hal/esp32p4/include/hal/ecdsa_ll.h @@ -71,6 +71,16 @@ typedef enum { ECDSA_MODE_SHA_CONTINUE } ecdsa_ll_sha_mode_t; +/** + * @brief Get the state of ECDSA peripheral + * + * @return State of ECDSA + */ +static inline uint32_t ecdsa_ll_get_state(void) +{ + return REG_GET_FIELD(ECDSA_STATE_REG, ECDSA_BUSY); +} + /** * @brief Enable the bus clock for ECDSA peripheral module * @@ -95,6 +105,10 @@ static inline void ecdsa_ll_reset_register(void) // Clear reset on parent crypto, otherwise ECDSA is held in reset HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_crypto = 0; + + while (ecdsa_ll_get_state() != ECDSA_STATE_IDLE) { + ; + } } /** @@ -273,16 +287,6 @@ static inline void ecdsa_ll_set_stage(ecdsa_ll_stage_t stage) } } -/** - * @brief Get the state of ECDSA peripheral - * - * @return State of ECDSA - */ -static inline uint32_t ecdsa_ll_get_state(void) -{ - return REG_GET_FIELD(ECDSA_STATE_REG, ECDSA_BUSY); -} - /** * @brief Set the SHA type * From ee788924eb2d63cf526bf404d7e3100710fecd8c Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Mon, 1 Jul 2024 20:10:31 +0800 Subject: [PATCH 429/548] feat(openthread): support changing openthread version information --- components/openthread/CMakeLists.txt | 4 ++-- components/openthread/Kconfig | 16 ++++++++++++++++ .../openthread-core-esp32x-ftd-config.h | 4 ++-- .../openthread-core-esp32x-mtd-config.h | 4 ++-- .../openthread-core-esp32x-radio-config.h | 4 ++-- .../openthread-core-esp32x-spinel-config.h | 17 +++++++++++++++++ 6 files changed, 41 insertions(+), 8 deletions(-) diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 7a1db20cf12..a4579556029 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -237,9 +237,9 @@ execute_process( string(TIMESTAMP OT_BUILD_TIMESTAMP " %Y-%m-%d %H:%M:%S UTC" UTC) string(CONCAT OT_FULL_VERSION_STRING - "openthread-esp32/" + "${CONFIG_OPENTHREAD_PACKAGE_NAME}/" "${IDF_VERSION_FOR_OPENTHREAD_PACKAGE}-${OPENTHREAD_VERSION}\; " - "${CONFIG_IDF_TARGET}\; ${OT_BUILD_TIMESTAMP}") + "${CONFIG_OPENTHREAD_PLATFORM_INFO}\; ${OT_BUILD_TIMESTAMP}") idf_component_register(SRC_DIRS "${src_dirs}" EXCLUDE_SRCS "${exclude_srcs}" diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 56739b5ec3d..e3166c87ffb 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -170,6 +170,22 @@ menu "OpenThread" Select this to enable SPI connection to host. endchoice + menu "OpenThread version message" + depends on OPENTHREAD_ENABLED + + config OPENTHREAD_PACKAGE_NAME + string "OpenThread package name" + default "openthread-esp32" + help + The OpenThread package name. + + config OPENTHREAD_PLATFORM_INFO + string "platform information" + default IDF_TARGET + help + The OpenThread platform information. + endmenu + config OPENTHREAD_NCP_VENDOR_HOOK bool "Enable vendor command for RCP" depends on OPENTHREAD_RADIO diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 5c851511f5c..aa8882f2341 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -14,7 +14,7 @@ * The platform-specific string to insert into the OpenThread version string. * */ -#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_IDF_TARGET +#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO /** * @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT @@ -317,7 +317,7 @@ * Define to the full name of this package. * */ -#define PACKAGE_NAME "openthread-esp32" +#define PACKAGE_NAME CONFIG_OPENTHREAD_PACKAGE_NAME /** * @def PACKAGE_STRING diff --git a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h index 8067323649b..f21c9ce01ea 100644 --- a/components/openthread/private_include/openthread-core-esp32x-mtd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-mtd-config.h @@ -14,7 +14,7 @@ * The platform-specific string to insert into the OpenThread version string. * */ -#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_IDF_TARGET +#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO /** * @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT @@ -131,7 +131,7 @@ * Define to the full name of this package. * */ -#define PACKAGE_NAME "openthread-esp32" +#define PACKAGE_NAME CONFIG_OPENTHREAD_PACKAGE_NAME /** * @def PACKAGE_STRING diff --git a/components/openthread/private_include/openthread-core-esp32x-radio-config.h b/components/openthread/private_include/openthread-core-esp32x-radio-config.h index aba848fe496..8a954c86d3b 100644 --- a/components/openthread/private_include/openthread-core-esp32x-radio-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-radio-config.h @@ -13,7 +13,7 @@ * The platform-specific string to insert into the OpenThread version string. * */ -#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_IDF_TARGET +#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO /** * @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT @@ -112,7 +112,7 @@ * Define to the full name of this package. * */ -#define PACKAGE_NAME "openthread-esp32" +#define PACKAGE_NAME CONFIG_OPENTHREAD_PACKAGE_NAME /** * @def PACKAGE_STRING diff --git a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h index 35c33d55a60..a1866a3bf29 100644 --- a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h @@ -6,6 +6,23 @@ #pragma once +#include "sdkconfig.h" +/** + * @def OPENTHREAD_CONFIG_PLATFORM_INFO + * + * The platform-specific string to insert into the OpenThread version string. + * + */ +#define OPENTHREAD_CONFIG_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO + +/** + * @def PACKAGE_NAME + * + * Define to the full name of this package. + * + */ +#define PACKAGE_NAME CONFIG_OPENTHREAD_PACKAGE_NAME + /** * @def OPENTHREAD_SPINEL_CONFIG_OPENTHREAD_MESSAGE_ENABLE * From bed5aa54292b563f2b122a152979c5ded3dc8375 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 18 Jul 2024 19:34:50 +0800 Subject: [PATCH 430/548] feat(openthread): support restoring vendor properties of rcp --- components/openthread/Kconfig | 2 +- .../openthread-core-esp32x-spinel-config.h | 4 +- .../src/spinel/esp_radio_spinel.cpp | 72 ++++++++++++++++--- 3 files changed, 66 insertions(+), 12 deletions(-) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index e3166c87ffb..0b90b78b015 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -189,7 +189,7 @@ menu "OpenThread" config OPENTHREAD_NCP_VENDOR_HOOK bool "Enable vendor command for RCP" depends on OPENTHREAD_RADIO - default n + default y help Select this to enable OpenThread NCP vendor commands. diff --git a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h index a1866a3bf29..3c9def78404 100644 --- a/components/openthread/private_include/openthread-core-esp32x-spinel-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-spinel-config.h @@ -42,9 +42,11 @@ */ #ifndef OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT // TZ-567: Set OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT to 3 after adding rcp failure notification mechanism -#define OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT 0 +#define OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT 3 #endif +#define OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE 1 + /** * @def OPENTHREAD_SPINEL_CONFIG_RCP_CUSTOM_RESTORATION * diff --git a/components/openthread/src/spinel/esp_radio_spinel.cpp b/components/openthread/src/spinel/esp_radio_spinel.cpp index 2057433ce43..fbf794046df 100644 --- a/components/openthread/src/spinel/esp_radio_spinel.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel.cpp @@ -14,6 +14,12 @@ #include "esp_radio_spinel_uart_interface.hpp" #include "spinel_driver.hpp" +#define SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE BIT(0) +#define SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR BIT(1) +static esp_ieee802154_pending_mode_t s_spinel_vendor_property_pendingmode[ot::Spinel::kSpinelHeaderMaxNumIid] = {ESP_IEEE802154_AUTO_PENDING_DISABLE}; +static bool s_spinel_vendor_property_coordinator[ot::Spinel::kSpinelHeaderMaxNumIid] = {false}; +static uint64_t s_spinel_vendor_property_mask[ot::Spinel::kSpinelHeaderMaxNumIid] = {0}; + using ot::Spinel::RadioSpinel; using ot::Spinel::RadioSpinelCallbacks; using esp::radio_spinel::SpinelInterfaceAdapter; @@ -45,6 +51,22 @@ static otInstance* get_instance_from_index(esp_radio_spinel_idx_t idx) return nullptr; } +static void esp_radio_spinel_restore_vendor_properities(void *context) +{ + esp_radio_spinel_idx_t idx = get_index_from_instance((otInstance*)context); + if (s_spinel_vendor_property_mask[idx] & SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE) { + if (esp_radio_spinel_set_pending_mode(s_spinel_vendor_property_pendingmode[idx], idx) != ESP_OK) { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to restore pendingmode: %d", idx); + } + } + + if (s_spinel_vendor_property_mask[idx] & SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR) { + if (esp_radio_spinel_set_pan_coord(s_spinel_vendor_property_coordinator[idx], idx) != ESP_OK) { + ESP_LOGE(ESP_SPINEL_LOG_TAG, "Fail to restore coordinator: %d", idx); + } + } +} + void ReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError) { esp_radio_spinel_idx_t idx = get_index_from_instance(aInstance); @@ -225,6 +247,8 @@ void esp_radio_spinel_init(esp_radio_spinel_idx_t idx) iidList[0] = 0; s_spinel_driver[idx].Init(s_spinel_interface[idx].GetSpinelInterface(), true, iidList, ot::Spinel::kSpinelHeaderMaxNumIid); s_radio[idx].Init(/*skip_rcp_compatibility_check=*/false, /*reset_radio=*/true, &s_spinel_driver[idx], s_radio_caps); + otInstance *instance = get_instance_from_index(idx); + s_radio[idx].SetVendorRestorePropertiesCallback(esp_radio_spinel_restore_vendor_properities, instance); } esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx) @@ -233,11 +257,6 @@ esp_err_t esp_radio_spinel_enable(esp_radio_spinel_idx_t idx) return (s_radio[idx].Enable(instance) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; } -esp_err_t esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx) -{ - return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE, SPINEL_DATATYPE_INT32_S, static_cast(pending_mode)) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; -} - esp_err_t esp_radio_spinel_get_eui64(uint8_t *eui64, esp_radio_spinel_idx_t idx) { return (s_radio[idx].GetIeeeEui64(eui64) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; @@ -260,11 +279,6 @@ esp_err_t esp_radio_spinel_set_extended_address(uint8_t *ext_address, esp_radio_ return (s_radio[idx].SetExtendedAddress(aExtAddress) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; } -esp_err_t esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx) -{ - return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR, SPINEL_DATATYPE_BOOL_S, enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; -} - esp_err_t esp_radio_spinel_receive(uint8_t channel, esp_radio_spinel_idx_t idx) { return (s_radio[idx].Receive(channel) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; @@ -313,6 +327,24 @@ esp_err_t esp_radio_spinel_set_promiscuous_mode(bool enable, esp_radio_spinel_id return (s_radio[idx].SetPromiscuous(enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; } +/*------------------------------------------------Vendor Property Set-------------------------------------------------------*/ +esp_err_t esp_radio_spinel_set_pending_mode(esp_ieee802154_pending_mode_t pending_mode, esp_radio_spinel_idx_t idx) +{ + s_spinel_vendor_property_pendingmode[idx] = pending_mode; + s_spinel_vendor_property_mask[idx] |= SPINEL_VENDOR_PROPERTY_BIT_PENDINGMODE; + return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE, SPINEL_DATATYPE_INT32_S, static_cast(pending_mode)) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +esp_err_t esp_radio_spinel_set_pan_coord(bool enable, esp_radio_spinel_idx_t idx) +{ + s_spinel_vendor_property_coordinator[idx] = enable; + s_spinel_vendor_property_mask[idx] |= SPINEL_VENDOR_PROPERTY_BIT_COORDINATOR; + return (s_radio[idx].Set(SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR, SPINEL_DATATYPE_BOOL_S, enable) == OT_ERROR_NONE) ? ESP_OK : ESP_FAIL; +} + +/*---------------------------------------------------------------------------------------------------------------------------*/ + + void esp_radio_spinel_radio_update(esp_radio_spinel_mainloop_context_t *mainloop_context, esp_radio_spinel_idx_t idx) { s_spinel_interface[idx].GetSpinelInterface().UpdateFdSet(static_cast(mainloop_context)); @@ -372,3 +404,23 @@ esp_err_t esp_radio_spinel_set_rcp_ready(esp_radio_spinel_idx_t idx) s_spinel_driver[idx].SetCoprocessorReady(); return ESP_OK; } + +namespace ot { +namespace Spinel { + +otError RadioSpinel::VendorHandleValueIs(spinel_prop_key_t aPropKey) +{ + otError error = OT_ERROR_NONE; + + switch (aPropKey) + { + default: + ESP_LOGW(ESP_SPINEL_LOG_TAG, "Not Implemented!"); + error = OT_ERROR_NOT_FOUND; + break; + } + return error; +} + +} // namespace Spinel +} // namespace ot From 5a1f4f389c8e31f3350d561ae3777126fd672f5e Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Thu, 25 Jul 2024 13:53:10 +0530 Subject: [PATCH 431/548] fix(ci): Update LATEST_GIT_TAG variable --- .gitlab/ci/common.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/common.yml b/.gitlab/ci/common.yml index 687d8516406..4381cea9703 100644 --- a/.gitlab/ci/common.yml +++ b/.gitlab/ci/common.yml @@ -39,7 +39,7 @@ variables: GIT_FETCH_EXTRA_FLAGS: "--no-recurse-submodules --prune --prune-tags" # we're using .cache folder for caches GIT_CLEAN_FLAGS: -ffdx -e .cache/ - LATEST_GIT_TAG: v5.3-dev + LATEST_GIT_TAG: v5.3 SUBMODULE_FETCH_TOOL: "tools/ci/ci_fetch_submodule.py" # by default we will fetch all submodules From ab5b9a0c29d21537985d8c8dd5ee74fe75bc62c0 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 14 Jun 2024 16:57:48 +0800 Subject: [PATCH 432/548] fix(hal): functions that may generate invalid load/store byte/half-word instructions because the APB regsiters can't behave correctly on these instructions --- .../hal/esp32/include/hal/sdio_slave_ll.h | 3 +- components/hal/esp32c6/include/hal/etm_ll.h | 8 ++--- .../hal/esp32c6/include/hal/sdio_slave_ll.h | 3 +- components/hal/esp32h2/include/hal/etm_ll.h | 4 +-- .../hal/esp32h2/include/hal/parlio_ll.h | 8 ++--- .../hal/esp32p4/include/hal/dw_gdma_ll.h | 4 +-- components/hal/esp32p4/include/hal/emac_ll.h | 12 +++---- components/hal/esp32p4/include/hal/etm_ll.h | 4 +-- .../hal/esp32p4/include/hal/parlio_ll.h | 2 +- components/hal/esp32p4/include/hal/ppa_ll.h | 36 +++++++++---------- .../hal/esp32p4/include/hal/psram_ctrlr_ll.h | 8 ++--- .../hal/esp32p4/include/hal/spimem_flash_ll.h | 2 +- .../soc/esp32c6/include/soc/soc_etm_struct.h | 4 +-- .../soc/esp32h2/include/soc/soc_etm_struct.h | 4 +-- .../soc/esp32p4/include/soc/soc_etm_struct.h | 4 +-- 15 files changed, 54 insertions(+), 52 deletions(-) diff --git a/components/hal/esp32/include/hal/sdio_slave_ll.h b/components/hal/esp32/include/hal/sdio_slave_ll.h index 2c94f217e78..aa0a001ca64 100644 --- a/components/hal/esp32/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32/include/hal/sdio_slave_ll.h @@ -17,6 +17,7 @@ #pragma once #include "hal/sdio_slave_types.h" +#include "hal/misc.h" #include "soc/slc_struct.h" #include "soc/slc_reg.h" #include "soc/host_struct.h" @@ -514,7 +515,7 @@ static inline void sdio_slave_ll_host_send_int(slc_dev_t *slc, const sdio_slave_ { //use registers in SLC to trigger, rather than write HOST registers directly //other interrupts than tohost interrupts are not supported yet - slc->intvec_tohost.slc0_intvec = (*mask); + HAL_FORCE_MODIFY_U32_REG_FIELD(slc->intvec_tohost, slc0_intvec, *mask); } /** diff --git a/components/hal/esp32c6/include/hal/etm_ll.h b/components/hal/esp32c6/include/hal/etm_ll.h index a40dd68b125..9a46f46a1da 100644 --- a/components/hal/esp32c6/include/hal/etm_ll.h +++ b/components/hal/esp32c6/include/hal/etm_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -98,7 +98,7 @@ static inline bool etm_ll_is_channel_enabled(soc_etm_dev_t *hw, uint32_t chan) */ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, uint32_t event) { - hw->channel[chan].evt_id.evt_id = event; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].eid, evt_id, event); } /** @@ -110,10 +110,10 @@ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, ui */ static inline void etm_ll_channel_set_task(soc_etm_dev_t *hw, uint32_t chan, uint32_t task) { - hw->channel[chan].task_id.task_id = task; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].tid, task_id, task); } -#define etm_ll_is_lpcore_wakeup_triggered() lp_aon_ll_get_lpcore_etm_wakeup_flag() +#define etm_ll_is_lpcore_wakeup_triggered() lp_aon_ll_get_lpcore_etm_wakeup_flag() #define etm_ll_clear_lpcore_wakeup_status() lp_aon_ll_clear_lpcore_etm_wakeup_flag() diff --git a/components/hal/esp32c6/include/hal/sdio_slave_ll.h b/components/hal/esp32c6/include/hal/sdio_slave_ll.h index 97c4b544100..2831edd57bc 100644 --- a/components/hal/esp32c6/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32c6/include/hal/sdio_slave_ll.h @@ -17,6 +17,7 @@ #pragma once #include "hal/sdio_slave_types.h" +#include "hal/misc.h" #include "soc/slc_struct.h" #include "soc/slc_reg.h" #include "soc/host_struct.h" @@ -503,7 +504,7 @@ static inline void sdio_slave_ll_host_send_int(slc_dev_t *slc, const sdio_slave_ { //use registers in SLC to trigger, rather than write HOST registers directly //other interrupts than tohost interrupts are not supported yet - slc->slcintvec_tohost.slc0_tohost_intvec = (*mask); + HAL_FORCE_MODIFY_U32_REG_FIELD(slc->slcintvec_tohost, slc0_tohost_intvec, *mask); } /** diff --git a/components/hal/esp32h2/include/hal/etm_ll.h b/components/hal/esp32h2/include/hal/etm_ll.h index 9d341ae2ed7..210933eaba0 100644 --- a/components/hal/esp32h2/include/hal/etm_ll.h +++ b/components/hal/esp32h2/include/hal/etm_ll.h @@ -97,7 +97,7 @@ static inline bool etm_ll_is_channel_enabled(soc_etm_dev_t *hw, uint32_t chan) */ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, uint32_t event) { - hw->channel[chan].evt_id.evt_id = event; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].eid, evt_id, event); } /** @@ -109,7 +109,7 @@ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, ui */ static inline void etm_ll_channel_set_task(soc_etm_dev_t *hw, uint32_t chan, uint32_t task) { - hw->channel[chan].task_id.task_id = task; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].tid, task_id, task); } #ifdef __cplusplus diff --git a/components/hal/esp32h2/include/hal/parlio_ll.h b/components/hal/esp32h2/include/hal/parlio_ll.h index e0236e0f8a7..ac3f5d74706 100644 --- a/components/hal/esp32h2/include/hal/parlio_ll.h +++ b/components/hal/esp32h2/include/hal/parlio_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -326,7 +326,7 @@ static inline void parlio_ll_rx_treat_data_line_as_en(parl_io_dev_t *dev, uint32 } /** - * @brief Wether to enable the RX clock gating + * @brief Whether to enable the RX clock gating * * @param dev Parallel IO register base address * @param en True to enable, False to disable @@ -457,7 +457,7 @@ static inline void parlio_ll_tx_set_trans_bit_len(parl_io_dev_t *dev, uint32_t b } /** - * @brief Wether to enable the TX clock gating + * @brief Whether to enable the TX clock gating * * @note The MSB of TXD will be taken as the gating enable signal * @@ -571,7 +571,7 @@ static inline void parlio_ll_tx_reset_fifo(parl_io_dev_t *dev) __attribute__((always_inline)) static inline void parlio_ll_tx_set_idle_data_value(parl_io_dev_t *dev, uint32_t value) { - dev->tx_genrl_cfg.tx_idle_value = value; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_genrl_cfg, tx_idle_value, value); } /** diff --git a/components/hal/esp32p4/include/hal/dw_gdma_ll.h b/components/hal/esp32p4/include/hal/dw_gdma_ll.h index 6afcca79b35..efe817b8e37 100644 --- a/components/hal/esp32p4/include/hal/dw_gdma_ll.h +++ b/components/hal/esp32p4/include/hal/dw_gdma_ll.h @@ -1112,7 +1112,7 @@ __attribute__((always_inline)) static inline void dw_gdma_ll_lli_set_src_burst_len(dw_gdma_link_list_item_t *lli, uint8_t len) { lli->ctrl_hi.arlen_en = len > 0; - lli->ctrl_hi.arlen = len; + HAL_FORCE_MODIFY_U32_REG_FIELD(lli->ctrl_hi, arlen, len); } /** @@ -1125,7 +1125,7 @@ __attribute__((always_inline)) static inline void dw_gdma_ll_lli_set_dst_burst_len(dw_gdma_link_list_item_t *lli, uint8_t len) { lli->ctrl_hi.awlen_en = len > 0; - lli->ctrl_hi.awlen = len; + HAL_FORCE_MODIFY_U32_REG_FIELD(lli->ctrl_hi, awlen, len); } /** diff --git a/components/hal/esp32p4/include/hal/emac_ll.h b/components/hal/esp32p4/include/hal/emac_ll.h index 6f7e484edf1..33a5ed8a5c9 100644 --- a/components/hal/esp32p4/include/hal/emac_ll.h +++ b/components/hal/esp32p4/include/hal/emac_ll.h @@ -628,11 +628,11 @@ static inline void emac_ll_clock_enable_mii(void *ext_regs) HP_SYS_CLKRST.peri_clk_ctrl00.reg_emac_rx_clk_en = 1; HP_SYS_CLKRST.peri_clk_ctrl00.reg_emac_rx_clk_src_sel = 1; // 0-pad_emac_txrx_clk, 1-pad_emac_rx_clk - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_rx_clk_div_num = 0; // 25MHz + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_rx_clk_div_num, 0); // 25MHz HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_en = 1; HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_src_sel = 1; // 0-pad_emac_txrx_clk, 1-pad_emac_tx_clk - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_div_num = 0; // 25MHz + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_tx_clk_div_num, 0); // 25MHz LP_AON_CLKRST.hp_clk_ctrl.hp_pad_emac_tx_clk_en = 1; LP_AON_CLKRST.hp_clk_ctrl.hp_pad_emac_rx_clk_en = 1; @@ -653,11 +653,11 @@ static inline void emac_ll_clock_enable_rmii_input(void *ext_regs) HP_SYS_CLKRST.peri_clk_ctrl00.reg_emac_rx_clk_en = 1; HP_SYS_CLKRST.peri_clk_ctrl00.reg_emac_rx_clk_src_sel = 0; // 0-pad_emac_txrx_clk, 1-pad_emac_rx_clk - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_rx_clk_div_num = 1; // set default divider + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_rx_clk_div_num, 1); // set default divider HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_en = 1; HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_src_sel = 0; // 0-pad_emac_txrx_clk, 1-pad_emac_tx_clk - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_div_num = 1; // set default divider + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_tx_clk_div_num, 1); // set default divider LP_AON_CLKRST.hp_clk_ctrl.hp_pad_emac_tx_clk_en = 0; LP_AON_CLKRST.hp_clk_ctrl.hp_pad_emac_rx_clk_en = 0; @@ -670,8 +670,8 @@ static inline void emac_ll_clock_enable_rmii_input(void *ext_regs) static inline void emac_ll_clock_rmii_rx_tx_div(void *ext_regs, int div) { - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_rx_clk_div_num = div; - HP_SYS_CLKRST.peri_clk_ctrl01.reg_emac_tx_clk_div_num = div; + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_rx_clk_div_num, div); + HAL_FORCE_MODIFY_U32_REG_FIELD(HP_SYS_CLKRST.peri_clk_ctrl01, reg_emac_tx_clk_div_num, div); } /// use a macro to wrap the function, force the caller to use it in a critical section diff --git a/components/hal/esp32p4/include/hal/etm_ll.h b/components/hal/esp32p4/include/hal/etm_ll.h index 6904d170ac7..12e11d64323 100644 --- a/components/hal/esp32p4/include/hal/etm_ll.h +++ b/components/hal/esp32p4/include/hal/etm_ll.h @@ -106,7 +106,7 @@ static inline bool etm_ll_is_channel_enabled(soc_etm_dev_t *hw, uint32_t chan) */ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, uint32_t event) { - hw->channel[chan].evt_id.evt_id = event; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].eid, evt_id, event); } /** @@ -118,7 +118,7 @@ static inline void etm_ll_channel_set_event(soc_etm_dev_t *hw, uint32_t chan, ui */ static inline void etm_ll_channel_set_task(soc_etm_dev_t *hw, uint32_t chan, uint32_t task) { - hw->channel[chan].task_id.task_id = task; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->channel[chan].tid, task_id, task); } /** diff --git a/components/hal/esp32p4/include/hal/parlio_ll.h b/components/hal/esp32p4/include/hal/parlio_ll.h index b7cc5558d51..f863acf2771 100644 --- a/components/hal/esp32p4/include/hal/parlio_ll.h +++ b/components/hal/esp32p4/include/hal/parlio_ll.h @@ -636,7 +636,7 @@ static inline void parlio_ll_tx_reset_fifo(parl_io_dev_t *dev) __attribute__((always_inline)) static inline void parlio_ll_tx_set_idle_data_value(parl_io_dev_t *dev, uint32_t value) { - dev->tx_genrl_cfg.tx_idle_value = value; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->tx_genrl_cfg, tx_idle_value, value); } /** diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index 687e63c5ef2..60facd94fec 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -660,9 +660,9 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, color_pi */ static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) { - dev->blend_rgb.blend1_rx_b = rgb->b; - dev->blend_rgb.blend1_rx_g = rgb->g; - dev->blend_rgb.blend1_rx_r = rgb->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_r, rgb->r); } /* @@ -682,13 +682,13 @@ static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rg */ static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) { - dev->ck_bg_low.colorkey_bg_b_low = rgb_thres_low->b; - dev->ck_bg_low.colorkey_bg_g_low = rgb_thres_low->g; - dev->ck_bg_low.colorkey_bg_r_low = rgb_thres_low->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_r_low, rgb_thres_low->r); - dev->ck_bg_high.colorkey_bg_b_high = rgb_thres_high->b; - dev->ck_bg_high.colorkey_bg_g_high = rgb_thres_high->g; - dev->ck_bg_high.colorkey_bg_r_high = rgb_thres_high->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_r_high, rgb_thres_high->r); } /** @@ -700,13 +700,13 @@ static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, color_p */ static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) { - dev->ck_fg_low.colorkey_fg_b_low = rgb_thres_low->b; - dev->ck_fg_low.colorkey_fg_g_low = rgb_thres_low->g; - dev->ck_fg_low.colorkey_fg_r_low = rgb_thres_low->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_r_low, rgb_thres_low->r); - dev->ck_fg_high.colorkey_fg_b_high = rgb_thres_high->b; - dev->ck_fg_high.colorkey_fg_g_high = rgb_thres_high->g; - dev->ck_fg_high.colorkey_fg_r_high = rgb_thres_high->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_r_high, rgb_thres_high->r); } /** @@ -717,9 +717,9 @@ static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, color_p */ static inline void ppa_ll_blend_set_ck_default_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) { - dev->ck_default.colorkey_default_b = rgb->b; - dev->ck_default.colorkey_default_g = rgb->g; - dev->ck_default.colorkey_default_r = rgb->r; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_r, rgb->r); } /** diff --git a/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h b/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h index 438f474d524..822a4759be4 100644 --- a/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h +++ b/components/hal/esp32p4/include/hal/psram_ctrlr_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,7 +53,7 @@ static inline void psram_ctrlr_ll_set_wr_cmd(uint32_t mspi_id, uint32_t cmd_bitl HAL_ASSERT(cmd_bitlen > 0); SPIMEM2.mem_cache_sctrl.mem_cache_sram_usr_wcmd = 1; SPIMEM2.mem_sram_dwr_cmd.mem_cache_sram_usr_wr_cmd_bitlen = cmd_bitlen - 1; - SPIMEM2.mem_sram_dwr_cmd.mem_cache_sram_usr_wr_cmd_value = cmd_val; + HAL_FORCE_MODIFY_U32_REG_FIELD(SPIMEM2.mem_sram_dwr_cmd, mem_cache_sram_usr_wr_cmd_value, cmd_val); } /** @@ -70,7 +70,7 @@ static inline void psram_ctrlr_ll_set_rd_cmd(uint32_t mspi_id, uint32_t cmd_bitl HAL_ASSERT(cmd_bitlen > 0); SPIMEM2.mem_cache_sctrl.mem_cache_sram_usr_rcmd = 1; SPIMEM2.mem_sram_drd_cmd.mem_cache_sram_usr_rd_cmd_bitlen = cmd_bitlen - 1; - SPIMEM2.mem_sram_drd_cmd.mem_cache_sram_usr_rd_cmd_value = cmd_val; + HAL_FORCE_MODIFY_U32_REG_FIELD(SPIMEM2.mem_sram_drd_cmd, mem_cache_sram_usr_rd_cmd_value, cmd_val); } /** @@ -501,7 +501,7 @@ static inline void psram_ctrlr_ll_enable_skip_page_corner(uint32_t mspi_id, bool } /** - * @brief Enable spliting transactions + * @brief Enable splitting transactions * * @param mspi_id mspi_id * @param en enable / disable diff --git a/components/hal/esp32p4/include/hal/spimem_flash_ll.h b/components/hal/esp32p4/include/hal/spimem_flash_ll.h index d91af4839e6..90cdd8ca3eb 100644 --- a/components/hal/esp32p4/include/hal/spimem_flash_ll.h +++ b/components/hal/esp32p4/include/hal/spimem_flash_ll.h @@ -567,7 +567,7 @@ static inline void spimem_flash_ll_set_addr_bitlen(spi_mem_dev_t *dev, uint32_t static inline void spimem_flash_ll_set_extra_address(spi_mem_dev_t *dev, uint32_t extra_addr) { dev->cache_fctrl.cache_usr_addr_4byte = 0; - dev->rd_status.wb_mode = extra_addr; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rd_status, wb_mode, extra_addr); } /** diff --git a/components/soc/esp32c6/include/soc/soc_etm_struct.h b/components/soc/esp32c6/include/soc/soc_etm_struct.h index 5e8f2dea6bb..3c62027ae5a 100644 --- a/components/soc/esp32c6/include/soc/soc_etm_struct.h +++ b/components/soc/esp32c6/include/soc/soc_etm_struct.h @@ -735,8 +735,8 @@ typedef struct soc_etm_dev_t { volatile soc_etm_ch_ena_ad1_set_reg_t ch_ena_ad1_set; volatile soc_etm_ch_ena_ad1_clr_reg_t ch_ena_ad1_clr; volatile struct { - soc_etm_chn_evt_id_reg_t evt_id; - soc_etm_chn_task_id_reg_t task_id; + soc_etm_chn_evt_id_reg_t eid; + soc_etm_chn_task_id_reg_t tid; } channel[50]; volatile soc_etm_clk_en_reg_t clk_en; volatile soc_etm_date_reg_t date; diff --git a/components/soc/esp32h2/include/soc/soc_etm_struct.h b/components/soc/esp32h2/include/soc/soc_etm_struct.h index 5e8f2dea6bb..3c62027ae5a 100644 --- a/components/soc/esp32h2/include/soc/soc_etm_struct.h +++ b/components/soc/esp32h2/include/soc/soc_etm_struct.h @@ -735,8 +735,8 @@ typedef struct soc_etm_dev_t { volatile soc_etm_ch_ena_ad1_set_reg_t ch_ena_ad1_set; volatile soc_etm_ch_ena_ad1_clr_reg_t ch_ena_ad1_clr; volatile struct { - soc_etm_chn_evt_id_reg_t evt_id; - soc_etm_chn_task_id_reg_t task_id; + soc_etm_chn_evt_id_reg_t eid; + soc_etm_chn_task_id_reg_t tid; } channel[50]; volatile soc_etm_clk_en_reg_t clk_en; volatile soc_etm_date_reg_t date; diff --git a/components/soc/esp32p4/include/soc/soc_etm_struct.h b/components/soc/esp32p4/include/soc/soc_etm_struct.h index 93090a023df..1feb1950eca 100644 --- a/components/soc/esp32p4/include/soc/soc_etm_struct.h +++ b/components/soc/esp32p4/include/soc/soc_etm_struct.h @@ -5084,8 +5084,8 @@ typedef struct soc_etm_dev_t { volatile soc_etm_ch_ena_ad1_set_reg_t ch_ena_ad1_set; volatile soc_etm_ch_ena_ad1_clr_reg_t ch_ena_ad1_clr; volatile struct { - soc_etm_chn_evt_id_reg_t evt_id; - soc_etm_chn_task_id_reg_t task_id; + soc_etm_chn_evt_id_reg_t eid; + soc_etm_chn_task_id_reg_t tid; } channel[50]; volatile soc_etm_evt_st0_reg_t evt_st0; volatile soc_etm_evt_st0_clr_reg_t evt_st0_clr; From c20cc2d9b28a157a2e1e73e0a17b6db923350401 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Sat, 15 Jun 2024 16:24:29 +0800 Subject: [PATCH 433/548] docs(ble): Revised the esp32 controller API explanations --- components/bt/include/esp32/include/esp_bt.h | 444 +++++++++++-------- 1 file changed, 251 insertions(+), 193 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index b31ce276f58..bdb7ed325e8 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -53,28 +53,29 @@ extern "C" { #define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20240315 /** - * @brief Bluetooth mode for controller enable/disable + * @brief Bluetooth Controller mode */ typedef enum { - ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not running */ - ESP_BT_MODE_BLE = 0x01, /*!< Run BLE mode */ - ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Run Classic BT mode */ - ESP_BT_MODE_BTDM = 0x03, /*!< Run dual mode */ + ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not operating */ + ESP_BT_MODE_BLE = 0x01, /*!< Bluetooth is operating in BLE mode. */ + ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Bluetooth is operating in Classic Bluetooth mode */ + ESP_BT_MODE_BTDM = 0x03, /*!< Bluetooth is operating in Dual mode */ } esp_bt_mode_t; /** - * @brief BLE sleep clock accuracy(SCA), values for ble_sca field in esp_bt_controller_config_t, - * currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported + * @brief BLE sleep clock accuracy(SCA) + * + * @note Currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported */ enum { - ESP_BLE_SCA_500PPM = 0, /*!< BLE SCA at 500ppm */ - ESP_BLE_SCA_250PPM, /*!< BLE SCA at 250ppm */ - ESP_BLE_SCA_150PPM, /*!< BLE SCA at 150ppm */ - ESP_BLE_SCA_100PPM, /*!< BLE SCA at 100ppm */ - ESP_BLE_SCA_75PPM, /*!< BLE SCA at 75ppm */ - ESP_BLE_SCA_50PPM, /*!< BLE SCA at 50ppm */ - ESP_BLE_SCA_30PPM, /*!< BLE SCA at 30ppm */ - ESP_BLE_SCA_20PPM, /*!< BLE SCA at 20ppm */ + ESP_BLE_SCA_500PPM = 0, /*!< BLE SCA at 500 ppm */ + ESP_BLE_SCA_250PPM, /*!< BLE SCA at 250 ppm */ + ESP_BLE_SCA_150PPM, /*!< BLE SCA at 150 ppm */ + ESP_BLE_SCA_100PPM, /*!< BLE SCA at 100 ppm */ + ESP_BLE_SCA_75PPM, /*!< BLE SCA at 75 ppm */ + ESP_BLE_SCA_50PPM, /*!< BLE SCA at 50 ppm */ + ESP_BLE_SCA_30PPM, /*!< BLE SCA at 30 ppm */ + ESP_BLE_SCA_20PPM, /*!< BLE SCA at 20 ppm */ }; #ifdef CONFIG_BT_ENABLED @@ -172,7 +173,9 @@ the adv packet will be discarded until the memory is restored. */ #else #define BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX 0 #endif - +/** +* @brief Default configuration of Bluetooth Controller +*/ #define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \ .controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \ .controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO, \ @@ -205,20 +208,31 @@ the adv packet will be discarded until the memory is restored. */ #endif /** - * @brief Controller config options, depend on config mask. - * Config mask indicate which functions enabled, this means - * some options or parameters of some functions enabled by config mask. + * @brief Bluetooth Controller config options + * @note + * 1. The following parameters can be configured at runtime when calling esp_bt_controller_init(): + * + * `controller_task_stack_size`, `controller_task_prio`, `hci_uart_no`, `hci_uart_baudrate` + * `scan_duplicate_mode`, `scan_duplicate_type`, `normal_adv_size`, `mesh_adv_size`, `send_adv_reserved_size`, + * `controller_debug_flag`, `mode`, `ble_max_conn`, `bt_max_acl_conn`, `bt_sco_datapath`, `auto_latency`, + * `bt_legacy_auth_vs_evt` + * + * 2. The following parameters cannot be configured at runtime when calling `esp_bt_controller_init()`. + * They will be overwritten with values in menuconfig or from a macro: + * + * `bt_max_sync_conn`, `ble_sca`, `pcm_role`, `pcm_polar`, `hli`, `dup_list_refresh_period`, `ble_scan_backoff`, + * `magic`. */ typedef struct { /* * Following parameters can be configured runtime, when call esp_bt_controller_init() */ - uint16_t controller_task_stack_size; /*!< Bluetooth controller task stack size */ - uint8_t controller_task_prio; /*!< Bluetooth controller task priority */ + uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size */ + uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */ uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */ - uint8_t scan_duplicate_mode; /*!< scan duplicate mode */ - uint8_t scan_duplicate_type; /*!< scan duplicate type */ + uint8_t scan_duplicate_mode; /*!< Scan duplicate mode */ + uint8_t scan_duplicate_type; /*!< Scan duplicate type */ uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */ uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */ uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */ @@ -245,61 +259,65 @@ typedef struct { } esp_bt_controller_config_t; /** - * @brief Bluetooth controller enable/disable/initialised/de-initialised status + * @brief Bluetooth Controller status */ typedef enum { - ESP_BT_CONTROLLER_STATUS_IDLE = 0, - ESP_BT_CONTROLLER_STATUS_INITED, - ESP_BT_CONTROLLER_STATUS_ENABLED, - ESP_BT_CONTROLLER_STATUS_NUM, + ESP_BT_CONTROLLER_STATUS_IDLE = 0, /*!< The Controller is not initialized or has been de-initialized.*/ + ESP_BT_CONTROLLER_STATUS_INITED, /*!< The Controller has been initialized. But it is not enabled or has been disabled. */ + ESP_BT_CONTROLLER_STATUS_ENABLED, /*!< The Controller has been initialized and enabled. */ + ESP_BT_CONTROLLER_STATUS_NUM, /*!< Controller status numbers */ } esp_bt_controller_status_t; /** - * @brief BLE tx power type - * ESP_BLE_PWR_TYPE_CONN_HDL0-8: for each connection, and only be set after connection completed. + * @brief BLE TX power type + * @note + * 1. The connection TX power can only be set after the connection is established. + * After disconnecting, the corresponding TX power will not be affected. + * 2. + * ESP_BLE_PWR_TYPE_CONN_HDL0-8: TX power for each connection, and only be set after connection completed. * when disconnect, the correspond TX power is not effected. * ESP_BLE_PWR_TYPE_ADV : for advertising/scan response. * ESP_BLE_PWR_TYPE_SCAN : for scan. * ESP_BLE_PWR_TYPE_DEFAULT : if each connection's TX power is not set, it will use this default value. * if neither in scan mode nor in adv mode, it will use this default value. - * If none of power type is set, system will use ESP_PWR_LVL_P3 as default for ADV/SCAN/CONN0-9. + * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for ADV/SCAN/CONN0-9. */ typedef enum { - ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< For connection handle 0 */ - ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, /*!< For connection handle 1 */ - ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, /*!< For connection handle 2 */ - ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, /*!< For connection handle 3 */ - ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, /*!< For connection handle 4 */ - ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, /*!< For connection handle 5 */ - ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, /*!< For connection handle 6 */ - ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, /*!< For connection handle 7 */ - ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, /*!< For connection handle 8 */ - ESP_BLE_PWR_TYPE_ADV = 9, /*!< For advertising */ - ESP_BLE_PWR_TYPE_SCAN = 10, /*!< For scan */ + ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< TX power for connection handle 0 */ + ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, /*!< TX power for connection handle 1 */ + ESP_BLE_PWR_TYPE_CONN_HDL2 = 2, /*!< TX power for connection handle 2 */ + ESP_BLE_PWR_TYPE_CONN_HDL3 = 3, /*!< TX power for connection handle 3 */ + ESP_BLE_PWR_TYPE_CONN_HDL4 = 4, /*!< TX power for connection handle 4 */ + ESP_BLE_PWR_TYPE_CONN_HDL5 = 5, /*!< TX power for connection handle 5 */ + ESP_BLE_PWR_TYPE_CONN_HDL6 = 6, /*!< TX power for connection handle 6 */ + ESP_BLE_PWR_TYPE_CONN_HDL7 = 7, /*!< TX power for connection handle 7 */ + ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, /*!< TX power for connection handle 8 */ + ESP_BLE_PWR_TYPE_ADV = 9, /*!< TX power for advertising */ + ESP_BLE_PWR_TYPE_SCAN = 10, /*!< TX power for scan */ ESP_BLE_PWR_TYPE_DEFAULT = 11, /*!< For default, if not set other, it will use default value */ ESP_BLE_PWR_TYPE_NUM = 12, /*!< TYPE numbers */ } esp_ble_power_type_t; /** - * @brief Bluetooth TX power level(index), it's just a index corresponding to power(dbm). + * @brief Bluetooth TX power level (index). Each index corresponds to a specific power value in dBm. */ typedef enum { - ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12dbm */ - ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9dbm */ - ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6dbm */ - ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3dbm */ - ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0dbm */ - ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3dbm */ - ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6dbm */ - ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9dbm */ - ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14dbm will actually result to -12dbm */ - ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11dbm will actually result to -9dbm */ - ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8dbm will actually result to -6dbm */ - ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5dbm will actually result to -3dbm */ - ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2dbm will actually result to 0dbm */ - ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1dbm will actually result to +3dbm */ - ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4dbm will actually result to +6dbm */ - ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7dbm will actually result to +9dbm */ + ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12 dBm */ + ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9 dBm */ + ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6 dBm */ + ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3 dBm */ + ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0 dBm */ + ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3 dBm */ + ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6 dBm */ + ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9 dBm */ + ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14 dBm will actually result in -12 dBm */ + ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11 dBm will actually result in -9 dBm */ + ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8 dBm will actually result in -6 dBm */ + ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5 dBm will actually result in -3 dBm */ + ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2 dBm will actually result in 0 dBm */ + ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1 dBm will actually result in +3 dBm */ + ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4 dBm will actually result in +6 dBm */ + ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7 dBm will actually result in +9 dBm */ } esp_power_level_t; /** @@ -312,242 +330,282 @@ typedef enum { /** * @brief Set BLE TX power - * Connection Tx power should only be set after connection created. - * @param power_type : The type of which tx power, could set Advertising/Connection/Default and etc - * @param power_level: Power level(index) corresponding to absolute value(dbm) - * @return ESP_OK - success, other - failed + * @note Connection TX power should only be set after the connection is established. + * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. + * @param[in] power_level Power level (index) corresponding to the absolute value(dbm) + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument */ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_t power_level); /** * @brief Get BLE TX power - * Connection Tx power should only be get after connection created. - * @param power_type : The type of which tx power, could set Advertising/Connection/Default and etc - * @return >= 0 - Power level, < 0 - Invalid + * @note Connection TX power should only be get after the connection is established. + * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. + * @return + * - Power level + * */ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type); /** * @brief Set BR/EDR TX power - * BR/EDR power control will use the power in range of minimum value and maximum value. - * The power level will effect the global BR/EDR TX power, such inquire, page, connection and so on. - * Please call the function after esp_bt_controller_enable and before any function which cause RF do TX. - * So you can call the function before doing discovery, profile init and so on. - * For example, if you want BR/EDR use the new TX power to do inquire, you should call - * this function before inquire. Another word, If call this function when BR/EDR is in inquire(ING), - * please do inquire again after call this function. - * Default minimum power level is ESP_PWR_LVL_N0, and maximum power level is ESP_PWR_LVL_P3. - * @param min_power_level: The minimum power level - * @param max_power_level: The maximum power level - * @return ESP_OK - success, other - failed + * + * BR/EDR power control will use the power within the range of minimum value and maximum value. + * The power level will affect the global BR/EDR TX power for operations such as inquiry, page, and connection. + * + * @note + * 1. Please call the function after `esp_bt_controller_enable()` and before any function that causes RF transmission, + * such as performing discovery, profile initialization, and so on. + * + * 2. For BR/EDR to use the new TX power for inquiry, call this function before starting an inquiry. + * If BR/EDR is already inquiring, restart the inquiry after calling this function. + * + * 3. The default minimum power level is `ESP_PWR_LVL_N0`, and the maximum power level is `ESP_PWR_LVL_P3`. + * + * @param[in] min_power_level The minimum power level + * @param[in] max_power_level The maximum power level + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_level_t max_power_level); /** * @brief Get BR/EDR TX power - * If the argument is not NULL, then store the corresponding value. - * @param min_power_level: The minimum power level - * @param max_power_level: The maximum power level - * @return ESP_OK - success, other - failed + * + * The corresponding power level will be stored into the arguments. + * @param[out] min_power_level The minimum power level + * @param[out] max_power_level The maximum power level + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument */ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_level_t *max_power_level); /** * @brief Set default SCO data path - * Should be called after controller is enabled, and before (e)SCO link is established - * @param data_path: SCO data path - * @return ESP_OK - success, other - failed + * @note This function should be called after the Controller is enabled, and before (e)SCO link is established + * @param[in] data_path SCO data path + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path); /** - * @brief Initialize BT controller to allocate task and other resource. - * This function should be called only once, before any other BT functions are called. - * @param cfg: Initial configuration of BT controller. Different from previous version, there's a mode and some - * connection configuration in "cfg" to configure controller work mode and allocate the resource which is needed. - * @return ESP_OK - success, other - failed + * @brief Initialize the Bluetooth Controller to allocate tasks and other resources. + * @note This function should be called only once, before any other Bluetooth functions. + * @param[in] cfg Initial configuration of Bluetooth Controller. + * Different from previous version, there's a mode and some + * connection configuration in `cfg` to configure the Controller work mode and allocate the resource which is needed. + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); /** - * @brief De-initialize BT controller to free resource and delete task. - * You should stop advertising and scanning, as well as - * disconnect all existing connections before de-initializing BT controller. - * - * This function should be called only once, after any other BT functions are called. - * @return ESP_OK - success, other - failed + * @brief De-initialize Bluetooth Controller to free resources and delete tasks. + * @note + * 1. You should stop advertising and scanning, as well as disconnect all existing connections before de-initializing Bluetooth Controller. + * 2. This function should be called only once, after any other Bluetooth functions. + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state + * - ESP_ERR_NO_MEM: Out of memory */ esp_err_t esp_bt_controller_deinit(void); /** - * @brief Enable BT controller. - * Due to a known issue, you cannot call esp_bt_controller_enable() a second time - * to change the controller mode dynamically. To change controller mode, call - * esp_bt_controller_disable() and then call esp_bt_controller_enable() with the new mode. - * @param mode : the mode(BLE/BT/BTDM) to enable. For compatible of API, retain this argument. This mode must be - * equal as the mode in "cfg" of esp_bt_controller_init(). - * @return ESP_OK - success, other - failed + * @brief Enable Bluetooth Controller. + * @note + * 1. Bluetooth Controller cannot be enabled in `ESP_BT_CONTROLLER_STATUS_IDLE` status. It have to be initialized first. + * 2. Due to a known issue, you cannot call `esp_bt_controller_enable()` a second time + * to change the Controller mode dynamically. To change the Controller mode, call + * `esp_bt_controller_disable()` and then call `esp_bt_controller_enable()` with the new mode. + * + @param[in] mode the Bluetooth Controller mode (BLE/Classic BT/BTDM) to enable + * + * For API compatibility, retain this argument. This mode must match the mode specified in the `cfg` of `esp_bt_controller_init()`. + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); /** - * @brief Disable BT controller - * @return ESP_OK - success, other - failed + * @brief Disable Bluetooth Controller + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_bt_controller_disable(void); /** - * @brief Get BT controller is initialised/de-initialised/enabled/disabled - * @return status value + * @brief Get Bluetooth Controller status + * + * @return + * - ESP_BT_CONTROLLER_STATUS_IDLE: The Controller is not initialized or has been de-initialized. + * - ESP_BT_CONTROLLER_STATUS_INITED: The Controller has been initialized. But it is not enabled or has been disabled.. + * - ESP_BT_CONTROLLER_STATUS_ENABLED: The Controller has been initialized and enabled. */ esp_bt_controller_status_t esp_bt_controller_get_status(void); -/** @brief esp_vhci_host_callback - * used for vhci call host function to notify what host need to do +/** + * @brief Vendor HCI (VHCI) callback functions to notify the Host on the next operation */ typedef struct esp_vhci_host_callback { - void (*notify_host_send_available)(void); /*!< callback used to notify that the host can send packet to controller */ - int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< callback used to notify that the controller has a packet to send to the host*/ + void (*notify_host_send_available)(void); /*!< Callback to notify the Host that the Controller is ready to receive the packet */ + int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< Callback to notify the Host that the Controller has a packet to send */ } esp_vhci_host_callback_t; -/** @brief esp_vhci_host_check_send_available - * used for check actively if the host can send packet to controller or not. - * @return true for ready to send, false means cannot send packet +/** + * @brief Check whether the Controller is ready to receive the packet + * + * If the return value is True, the Host can send the packet to the Controller. + * + * @note This function should be called before each `esp_vhci_host_send_packet()`. + * @return + * True if the Controller is ready to receive packets; false otherwise */ bool esp_vhci_host_check_send_available(void); -/** @brief esp_vhci_host_send_packet - * host send packet to controller - * - * Should not call this function from within a critical section - * or when the scheduler is suspended. - * - * @param data the packet point - * @param len the packet length +/** + * @brief Send the packet to the Controller + * @note + * 1. This function shall not be called within a critical section or when the scheduler is suspended. + * 2. This function should be called only if `esp_vhci_host_check_send_available()` returns True. + * @param[in] data the packet point + * @param[in] len the packet length */ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); -/** @brief esp_vhci_host_register_callback - * register the vhci reference callback - * struct defined by vhci_host_callback structure. - * @param callback esp_vhci_host_callback type variable - * @return ESP_OK - success, ESP_FAIL - failed +/** + * @brief Register the VHCI callback funations defined in `esp_vhci_host_callback` structure. + * @param[in] callback `esp_vhci_host_callback` type variable + * @return + * - ESP_OK: Success + * - ESP_FAIL: Failure */ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callback); -/** @brief esp_bt_controller_mem_release - * release the controller memory as per the mode - * - * This function releases the BSS, data and other sections of the controller to heap. The total size is about 70k bytes. +/** + * @brief Release the Controller memory as per the mode * - * esp_bt_controller_mem_release(mode) should be called only before esp_bt_controller_init() - * or after esp_bt_controller_deinit(). + * This function releases the BSS, data and other sections of the Controller to heap. The total size is about 70k bytes. * - * Note that once BT controller memory is released, the process cannot be reversed. It means you cannot use the bluetooth - * mode which you have released by this function. + * If the app calls `esp_bt_controller_enable(ESP_BT_MODE_BLE)` to use BLE only, + * then it is safe to call `esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)` at initialization time to free unused Classic Bluetooth memory. * - * If your firmware will later upgrade the Bluetooth controller mode (BLE -> BT Classic or disabled -> enabled) - * then do not call this function. + * If the mode is `ESP_BT_MODE_BTDM`, then it may be useful to call API `esp_bt_mem_release(ESP_BT_MODE_BTDM)` instead, + * which internally calls `esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)` and additionally releases the BSS and data + * consumed by the BT/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function * - * If the app calls esp_bt_controller_enable(ESP_BT_MODE_BLE) to use BLE only then it is safe to call - * esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT) at initialization time to free unused BT Classic memory. + * @note + * 1. This function should be called only before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. + * 2. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. + * 3. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * - * If the mode is ESP_BT_MODE_BTDM, then it may be useful to call API esp_bt_mem_release(ESP_BT_MODE_BTDM) instead, - * which internally calls esp_bt_controller_mem_release(ESP_BT_MODE_BTDM) and additionally releases the BSS and data - * consumed by the BT/BLE host stack to heap. For more details about usage please refer to the documentation of - * esp_bt_mem_release() function * - * @param mode : the mode want to release memory - * @return ESP_OK - success, other - failed + * @param mode the Bluetooth Controller mode + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state + * - ESP_ERR_NOT_FOUND: Requested resource not found */ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); -/** @brief esp_bt_mem_release - * release controller memory and BSS and data section of the BT/BLE host stack as per the mode +/** @brief Release Controller memory, BSS and data section of the BT/BLE Host stack as per the mode * - * This function first releases controller memory by internally calling esp_bt_controller_mem_release(). - * Additionally, if the mode is set to ESP_BT_MODE_BTDM, it also releases the BSS and data consumed by the BT/BLE host stack to heap + * This function first releases Controller memory by internally calling `esp_bt_controller_mem_release()`. + * Additionally, if the mode is set to `ESP_BT_MODE_BTDM`, it also releases the BSS and data consumed by the BT/BLE Host stack to heap * - * Note that once BT memory is released, the process cannot be reversed. It means you cannot use the bluetooth - * mode which you have released by this function. + * If you never intend to use Bluetooth in a current boot-up cycle, you can call `esp_bt_mem_release(ESP_BT_MODE_BTDM)` + * before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. * - * If your firmware will later upgrade the Bluetooth controller mode (BLE -> BT Classic or disabled -> enabled) - * then do not call this function. - * - * If you never intend to use bluetooth in a current boot-up cycle, you can call esp_bt_mem_release(ESP_BT_MODE_BTDM) - * before esp_bt_controller_init or after esp_bt_controller_deinit. - * - * For example, if a user only uses bluetooth for setting the WiFi configuration, and does not use bluetooth in the rest of the product operation". - * In such cases, after receiving the WiFi configuration, you can disable/deinit bluetooth and release its memory. + * For example, if a user only uses Bluetooth for setting the WiFi configuration, and does not use Bluetooth in the rest of the product operation. + * In such cases, after receiving the WiFi configuration, you can disable/de-init Bluetooth and release its memory. * Below is the sequence of APIs to be called for such scenarios: * - * esp_bluedroid_disable(); - * esp_bluedroid_deinit(); - * esp_bt_controller_disable(); - * esp_bt_controller_deinit(); - * esp_bt_mem_release(ESP_BT_MODE_BTDM); + * esp_bluedroid_disable(); + * esp_bluedroid_deinit(); + * esp_bt_controller_disable(); + * esp_bt_controller_deinit(); + * esp_bt_mem_release(ESP_BT_MODE_BTDM); + * + * @note + * 1. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. + * 2. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. + * 3. In case of NimBLE Host, to release BSS and data memory to heap, the mode needs to be set to `ESP_BT_MODE_BTDM` as the Controller is in Dual mode. * - * @note In case of NimBLE host, to release BSS and data memory to heap, the mode needs to be - * set to ESP_BT_MODE_BTDM as controller is dual mode. - * @param mode : the mode whose memory is to be released - * @return ESP_OK - success, other - failed + * @param[in] mode the Bluetooth Controller mode + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state + * - ESP_ERR_NOT_FOUND: Requested resource not found */ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode); /** - * @brief enable bluetooth to enter modem sleep - * - * Note that this function shall not be invoked before esp_bt_controller_enable() - * - * There are currently two options for bluetooth modem sleep, one is ORIG mode, and another is EVED Mode. EVED Mode is intended for BLE only. + * @brief Enable Bluetooth modem sleep * - * For ORIG mode: - * Bluetooth modem sleep is enabled in controller start up by default if CONFIG_CTRL_BTDM_MODEM_SLEEP is set and "ORIG mode" is selected. In ORIG modem sleep mode, bluetooth controller will switch off some components and pause to work every now and then, if there is no event to process; and wakeup according to the scheduled interval and resume the work. It can also wakeup earlier upon external request using function "esp_bt_controller_wakeup_request". + * There are currently two options for Bluetooth modem sleep: ORIG mode and EVED mode, the latter being intended for BLE only. + * The modem sleep mode could be configured in menuconfig. * + * In ORIG mode, if there is no event to process, the Bluetooth Controller will periodically switch off some components and pause operation, then wake up according to the scheduled interval and resume work. + * It can also wakeup earlier upon external request using function `esp_bt_controller_wakeup_request()`. + * @note This function shall not be invoked before `esp_bt_controller_enable()` * @return - * - ESP_OK : success - * - other : failed + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state + * - ESP_ERR_NOT_SUPPORTED: Operation or feature not supported */ esp_err_t esp_bt_sleep_enable(void); /** - * @brief disable bluetooth modem sleep + * @brief Disable Bluetooth modem sleep * - * Note that this function shall not be invoked before esp_bt_controller_enable() - * - * If esp_bt_sleep_disable() is called, bluetooth controller will not be allowed to enter modem sleep; - * - * If ORIG modem sleep mode is in use, if this function is called, bluetooth controller may not immediately wake up if it is dormant then. - * In this case, esp_bt_controller_wakeup_request() can be used to shorten the time for wakeup. + * @note + * 1. Bluetooth Controller will not be allowed to enter modem sleep after calling this function. + * 2. In ORIG modem sleep mode, calling this function may not immediately wake up the Controller if it is currently dormant. + * In this case, `esp_bt_controller_wakeup_request()` can be used to shorten the wake-up time. + * 3. This function shall not be invoked before `esp_bt_controller_enable()`. * * @return - * - ESP_OK : success - * - other : failed + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state + * - ESP_ERR_NOT_SUPPORTED: Operation or feature not supported */ esp_err_t esp_bt_sleep_disable(void); /** * @brief Manually clear scan duplicate list * - * Note that scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached - * the amount of device in the filter can be configured in menuconfig. - * - * @note This function name is incorrectly spelled, it will be fixed in release 5.x version. + * @note + * 1. This function name is incorrectly spelled, it will be fixed in release 5.x version. + * 2. The scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached. + * The amount of device in the filter can be configured in menuconfig. * * @return - * - ESP_OK : success - * - other : failed + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state */ esp_err_t esp_ble_scan_dupilcate_list_flush(void); /** - * @brief bt Wi-Fi power domain power on + * @brief Power on BT Wi-Fi power domain + * @note This function is not recommended to use due to potential risk. */ void esp_wifi_bt_power_domain_on(void); /** - * @brief bt Wi-Fi power domain power off + * @brief Power off BT Wi-Fi power domain + * @note This function is not recommended to use due to potential risk. */ void esp_wifi_bt_power_domain_off(void); From 73509ce16b05ca865708bcad8dee9f8208f38627 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Wed, 3 Jul 2024 14:50:55 +0800 Subject: [PATCH 434/548] docs(ble): Added a name for BLE sleep clock accuracy enum --- components/bt/include/esp32/include/esp_bt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index bdb7ed325e8..8db30088b63 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -76,7 +76,7 @@ enum { ESP_BLE_SCA_50PPM, /*!< BLE SCA at 50 ppm */ ESP_BLE_SCA_30PPM, /*!< BLE SCA at 30 ppm */ ESP_BLE_SCA_20PPM, /*!< BLE SCA at 20 ppm */ -}; +} esp_ble_sca_t; #ifdef CONFIG_BT_ENABLED /* While scanning, if the free memory value in controller is less than SCAN_SEND_ADV_RESERVED_SIZE, From 56f8419f5f70b132eff3295c49cc9ca6d8053348 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Wed, 3 Jul 2024 18:53:07 +0800 Subject: [PATCH 435/548] docs(ble): Added typeof for BLE sleep clock accuracy enum --- components/bt/include/esp32/include/esp_bt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 8db30088b63..36faa7a3089 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -67,7 +67,7 @@ typedef enum { * * @note Currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported */ -enum { +typedef enum { ESP_BLE_SCA_500PPM = 0, /*!< BLE SCA at 500 ppm */ ESP_BLE_SCA_250PPM, /*!< BLE SCA at 250 ppm */ ESP_BLE_SCA_150PPM, /*!< BLE SCA at 150 ppm */ From d600d97c0482ba439cba98ecec5a57ab01bb2214 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Mon, 17 Jun 2024 13:53:45 +0800 Subject: [PATCH 436/548] docs(ble): Fixed the explanation of TX power type --- components/bt/include/esp32/include/esp_bt.h | 39 +++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 36faa7a3089..623624c6877 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -50,6 +50,11 @@ extern "C" { #endif //CONFIG_BT_ENABLED +/** +* @brief Internal use only +* +* @note Please do not modify this value. +*/ #define ESP_BT_CONTROLLER_CONFIG_MAGIC_VAL 0x20240315 /** @@ -174,7 +179,7 @@ the adv packet will be discarded until the memory is restored. */ #define BTDM_CTRL_SCAN_BACKOFF_UPPERLIMITMAX 0 #endif /** -* @brief Default configuration of Bluetooth Controller +* @brief Default Bluetooth Controller configuration */ #define BT_CONTROLLER_INIT_CONFIG_DEFAULT() { \ .controller_task_stack_size = ESP_TASK_BT_CONTROLLER_STACK, \ @@ -204,6 +209,9 @@ the adv packet will be discarded until the memory is restored. */ } #else +/** +* @brief Default Bluetooth Controller configuration +*/ #define BT_CONTROLLER_INIT_CONFIG_DEFAULT() {0}; ESP_STATIC_ASSERT(0, "please enable bluetooth in menuconfig to use esp_bt.h"); #endif @@ -227,15 +235,15 @@ typedef struct { /* * Following parameters can be configured runtime, when call esp_bt_controller_init() */ - uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size */ + uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size in bytes */ uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */ uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */ - uint8_t scan_duplicate_mode; /*!< Scan duplicate mode */ - uint8_t scan_duplicate_type; /*!< Scan duplicate type */ - uint16_t normal_adv_size; /*!< Normal adv size for scan duplicate */ - uint16_t mesh_adv_size; /*!< Mesh adv size for scan duplicate */ - uint16_t send_adv_reserved_size; /*!< Controller minimum memory value */ + uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode */ + uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type */ + uint16_t normal_adv_size; /*!< Scan duplicate filtering list size with normal ADV */ + uint16_t mesh_adv_size; /*!< Scan duplicate filtering list size with mesh ADV */ + uint16_t send_adv_reserved_size; /*!< Controller minimum memory value*/ uint32_t controller_debug_flag; /*!< Controller debug log flag */ uint8_t mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */ uint8_t ble_max_conn; /*!< BLE maximum connection numbers */ @@ -253,7 +261,7 @@ typedef struct { uint8_t pcm_role; /*!< PCM role (master & slave)*/ uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */ bool hli; /*!< Using high level interrupt or not */ - uint16_t dup_list_refresh_period; /*!< Duplicate scan list refresh period */ + uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period */ bool ble_scan_backoff; /*!< BLE scan backoff */ uint32_t magic; /*!< Magic number */ } esp_bt_controller_config_t; @@ -273,14 +281,9 @@ typedef enum { * @note * 1. The connection TX power can only be set after the connection is established. * After disconnecting, the corresponding TX power will not be affected. - * 2. - * ESP_BLE_PWR_TYPE_CONN_HDL0-8: TX power for each connection, and only be set after connection completed. - * when disconnect, the correspond TX power is not effected. - * ESP_BLE_PWR_TYPE_ADV : for advertising/scan response. - * ESP_BLE_PWR_TYPE_SCAN : for scan. - * ESP_BLE_PWR_TYPE_DEFAULT : if each connection's TX power is not set, it will use this default value. - * if neither in scan mode nor in adv mode, it will use this default value. - * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for ADV/SCAN/CONN0-9. + * 2. `ESP_BLE_PWR_TYPE_DEFAULT` can be used to set the TX power for power types that have not been set before. + * It will not affect the TX power values which have been set the following CONN0-8/ADV/SCAN power types. + * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for ADV/SCAN/CONN0-8. */ typedef enum { ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< TX power for connection handle 0 */ @@ -294,7 +297,7 @@ typedef enum { ESP_BLE_PWR_TYPE_CONN_HDL8 = 8, /*!< TX power for connection handle 8 */ ESP_BLE_PWR_TYPE_ADV = 9, /*!< TX power for advertising */ ESP_BLE_PWR_TYPE_SCAN = 10, /*!< TX power for scan */ - ESP_BLE_PWR_TYPE_DEFAULT = 11, /*!< For default, if not set other, it will use default value */ + ESP_BLE_PWR_TYPE_DEFAULT = 11, /*!< Default TX power type, which can be used to set the TX power for power types that have not been set before.*/ ESP_BLE_PWR_TYPE_NUM = 12, /*!< TYPE numbers */ } esp_ble_power_type_t; @@ -332,7 +335,7 @@ typedef enum { * @brief Set BLE TX power * @note Connection TX power should only be set after the connection is established. * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. - * @param[in] power_level Power level (index) corresponding to the absolute value(dbm) + * @param[in] power_level Power level (index) corresponding to the absolute value (dBm) * @return * - ESP_OK: Success * - ESP_ERR_INVALID_ARG: Invalid argument From 2a3b3ab6f91c4be9de889523e61bee762336cb31 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Tue, 18 Jun 2024 11:18:29 +0800 Subject: [PATCH 437/548] docs(ble): Added corresponding values to the controller mode --- components/bt/include/esp32/include/esp_bt.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 623624c6877..86df12ee63c 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -61,10 +61,10 @@ extern "C" { * @brief Bluetooth Controller mode */ typedef enum { - ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not operating */ + ESP_BT_MODE_IDLE = 0x00, /*!< Bluetooth is not operating. */ ESP_BT_MODE_BLE = 0x01, /*!< Bluetooth is operating in BLE mode. */ - ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Bluetooth is operating in Classic Bluetooth mode */ - ESP_BT_MODE_BTDM = 0x03, /*!< Bluetooth is operating in Dual mode */ + ESP_BT_MODE_CLASSIC_BT = 0x02, /*!< Bluetooth is operating in Classic Bluetooth mode. */ + ESP_BT_MODE_BTDM = 0x03, /*!< Bluetooth is operating in Dual mode. */ } esp_bt_mode_t; /** @@ -245,7 +245,7 @@ typedef struct { uint16_t mesh_adv_size; /*!< Scan duplicate filtering list size with mesh ADV */ uint16_t send_adv_reserved_size; /*!< Controller minimum memory value*/ uint32_t controller_debug_flag; /*!< Controller debug log flag */ - uint8_t mode; /*!< Controller mode: BR/EDR, BLE or Dual Mode */ + uint8_t mode; /*!< Controller mode: BLE mode (1), Classic BT mode (2) or Dual mode (3) */ uint8_t ble_max_conn; /*!< BLE maximum connection numbers */ uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */ uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ From 294c17e08b7f74c122d23aa7210595d35cf36ac6 Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Tue, 18 Jun 2024 12:06:43 +0800 Subject: [PATCH 438/548] docs(ble): Removed unnecessary explanations --- components/bt/include/esp32/include/esp_bt.h | 52 +++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 86df12ee63c..aac7cc9eb20 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -245,7 +245,7 @@ typedef struct { uint16_t mesh_adv_size; /*!< Scan duplicate filtering list size with mesh ADV */ uint16_t send_adv_reserved_size; /*!< Controller minimum memory value*/ uint32_t controller_debug_flag; /*!< Controller debug log flag */ - uint8_t mode; /*!< Controller mode: BLE mode (1), Classic BT mode (2) or Dual mode (3) */ + uint8_t mode; /*!< Controller mode: BLE mode (1), Classic Bluetooth mode (2) or Dual mode (3) */ uint8_t ble_max_conn; /*!< BLE maximum connection numbers */ uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */ uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ @@ -282,7 +282,7 @@ typedef enum { * 1. The connection TX power can only be set after the connection is established. * After disconnecting, the corresponding TX power will not be affected. * 2. `ESP_BLE_PWR_TYPE_DEFAULT` can be used to set the TX power for power types that have not been set before. - * It will not affect the TX power values which have been set the following CONN0-8/ADV/SCAN power types. + * It will not affect the TX power values which have been set for the following CONN0-8/ADV/SCAN power types. * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for ADV/SCAN/CONN0-8. */ typedef enum { @@ -333,9 +333,12 @@ typedef enum { /** * @brief Set BLE TX power + * * @note Connection TX power should only be set after the connection is established. + * * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. * @param[in] power_level Power level (index) corresponding to the absolute value (dBm) + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_ARG: Invalid argument @@ -344,8 +347,11 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ /** * @brief Get BLE TX power + * * @note Connection TX power should only be get after the connection is established. + * * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. + * * @return * - Power level * @@ -361,14 +367,13 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type); * @note * 1. Please call the function after `esp_bt_controller_enable()` and before any function that causes RF transmission, * such as performing discovery, profile initialization, and so on. - * * 2. For BR/EDR to use the new TX power for inquiry, call this function before starting an inquiry. * If BR/EDR is already inquiring, restart the inquiry after calling this function. - * * 3. The default minimum power level is `ESP_PWR_LVL_N0`, and the maximum power level is `ESP_PWR_LVL_P3`. * * @param[in] min_power_level The minimum power level * @param[in] max_power_level The maximum power level + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_ARG: Invalid argument @@ -380,8 +385,10 @@ esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_le * @brief Get BR/EDR TX power * * The corresponding power level will be stored into the arguments. + * * @param[out] min_power_level The minimum power level * @param[out] max_power_level The maximum power level + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_ARG: Invalid argument @@ -390,8 +397,11 @@ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_l /** * @brief Set default SCO data path + * * @note This function should be called after the Controller is enabled, and before (e)SCO link is established + * * @param[in] data_path SCO data path + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -399,11 +409,12 @@ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_l esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path); /** - * @brief Initialize the Bluetooth Controller to allocate tasks and other resources. + * @brief Initialize the Bluetooth Controller to allocate tasks and other resources + * * @note This function should be called only once, before any other Bluetooth functions. - * @param[in] cfg Initial configuration of Bluetooth Controller. - * Different from previous version, there's a mode and some - * connection configuration in `cfg` to configure the Controller work mode and allocate the resource which is needed. + * + * @param[in] cfg Initial Bluetooth Controller configuration. + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -411,10 +422,12 @@ esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path); esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); /** - * @brief De-initialize Bluetooth Controller to free resources and delete tasks. + * @brief De-initialize Bluetooth Controller to free resources and delete tasks + * * @note * 1. You should stop advertising and scanning, as well as disconnect all existing connections before de-initializing Bluetooth Controller. * 2. This function should be called only once, after any other Bluetooth functions. + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_ARG: Invalid argument @@ -424,16 +437,18 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); esp_err_t esp_bt_controller_deinit(void); /** - * @brief Enable Bluetooth Controller. + * @brief Enable Bluetooth Controller + * * @note * 1. Bluetooth Controller cannot be enabled in `ESP_BT_CONTROLLER_STATUS_IDLE` status. It have to be initialized first. * 2. Due to a known issue, you cannot call `esp_bt_controller_enable()` a second time * to change the Controller mode dynamically. To change the Controller mode, call * `esp_bt_controller_disable()` and then call `esp_bt_controller_enable()` with the new mode. * - @param[in] mode the Bluetooth Controller mode (BLE/Classic BT/BTDM) to enable + * @param[in] mode the Bluetooth Controller mode (BLE/Classic BT/BTDM) to enable * * For API compatibility, retain this argument. This mode must match the mode specified in the `cfg` of `esp_bt_controller_init()`. + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -442,6 +457,7 @@ esp_err_t esp_bt_controller_enable(esp_bt_mode_t mode); /** * @brief Disable Bluetooth Controller + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -453,7 +469,7 @@ esp_err_t esp_bt_controller_disable(void); * * @return * - ESP_BT_CONTROLLER_STATUS_IDLE: The Controller is not initialized or has been de-initialized. - * - ESP_BT_CONTROLLER_STATUS_INITED: The Controller has been initialized. But it is not enabled or has been disabled.. + * - ESP_BT_CONTROLLER_STATUS_INITED: The Controller has been initialized. But it is not enabled or has been disabled. * - ESP_BT_CONTROLLER_STATUS_ENABLED: The Controller has been initialized and enabled. */ esp_bt_controller_status_t esp_bt_controller_get_status(void); @@ -472,6 +488,7 @@ typedef struct esp_vhci_host_callback { * If the return value is True, the Host can send the packet to the Controller. * * @note This function should be called before each `esp_vhci_host_send_packet()`. + * * @return * True if the Controller is ready to receive packets; false otherwise */ @@ -479,9 +496,11 @@ bool esp_vhci_host_check_send_available(void); /** * @brief Send the packet to the Controller + * * @note * 1. This function shall not be called within a critical section or when the scheduler is suspended. * 2. This function should be called only if `esp_vhci_host_check_send_available()` returns True. + * * @param[in] data the packet point * @param[in] len the packet length */ @@ -489,7 +508,9 @@ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); /** * @brief Register the VHCI callback funations defined in `esp_vhci_host_callback` structure. + * * @param[in] callback `esp_vhci_host_callback` type variable + * * @return * - ESP_OK: Success * - ESP_FAIL: Failure @@ -513,8 +534,8 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba * 2. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. * 3. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * + * @param[in] mode the Bluetooth Controller mode * - * @param mode the Bluetooth Controller mode * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -546,6 +567,7 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * 3. In case of NimBLE Host, to release BSS and data memory to heap, the mode needs to be set to `ESP_BT_MODE_BTDM` as the Controller is in Dual mode. * * @param[in] mode the Bluetooth Controller mode + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -561,7 +583,9 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode); * * In ORIG mode, if there is no event to process, the Bluetooth Controller will periodically switch off some components and pause operation, then wake up according to the scheduled interval and resume work. * It can also wakeup earlier upon external request using function `esp_bt_controller_wakeup_request()`. + * * @note This function shall not be invoked before `esp_bt_controller_enable()` + * * @return * - ESP_OK: Success * - ESP_ERR_INVALID_STATE: Invalid Bluetooth Controller state @@ -602,12 +626,14 @@ esp_err_t esp_ble_scan_dupilcate_list_flush(void); /** * @brief Power on BT Wi-Fi power domain + * * @note This function is not recommended to use due to potential risk. */ void esp_wifi_bt_power_domain_on(void); /** * @brief Power off BT Wi-Fi power domain + * * @note This function is not recommended to use due to potential risk. */ void esp_wifi_bt_power_domain_off(void); From dcece3822ecad6d8664fd41fa3d5e0793b0f9adf Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Tue, 18 Jun 2024 16:42:34 +0800 Subject: [PATCH 439/548] docs(ble): Replaced BT with Bluetooth --- components/bt/include/esp32/include/esp_bt.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index aac7cc9eb20..c30c98f1154 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -249,7 +249,7 @@ typedef struct { uint8_t ble_max_conn; /*!< BLE maximum connection numbers */ uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */ uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ - bool auto_latency; /*!< BLE auto latency, used to enhance classic BT performance */ + bool auto_latency; /*!< BLE auto latency, used to enhance Classic Bluetooth performance */ bool bt_legacy_auth_vs_evt; /*!< BR/EDR Legacy auth complete event required to protect from BIAS attack */ /* * Following parameters can not be configured runtime when call esp_bt_controller_init() @@ -445,7 +445,7 @@ esp_err_t esp_bt_controller_deinit(void); * to change the Controller mode dynamically. To change the Controller mode, call * `esp_bt_controller_disable()` and then call `esp_bt_controller_enable()` with the new mode. * - * @param[in] mode the Bluetooth Controller mode (BLE/Classic BT/BTDM) to enable + * @param[in] mode the Bluetooth Controller mode (BLE/Classic Bluetooth/BTDM) to enable * * For API compatibility, retain this argument. This mode must match the mode specified in the `cfg` of `esp_bt_controller_init()`. * @@ -527,7 +527,7 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba * * If the mode is `ESP_BT_MODE_BTDM`, then it may be useful to call API `esp_bt_mem_release(ESP_BT_MODE_BTDM)` instead, * which internally calls `esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)` and additionally releases the BSS and data - * consumed by the BT/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function + * consumed by the Classic Bluetooth/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function * * @note * 1. This function should be called only before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. @@ -543,10 +543,10 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba */ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); -/** @brief Release Controller memory, BSS and data section of the BT/BLE Host stack as per the mode +/** @brief Release the Controller memory, BSS and data section of the Classic Bluetooth/BLE Host stack as per the mode * * This function first releases Controller memory by internally calling `esp_bt_controller_mem_release()`. - * Additionally, if the mode is set to `ESP_BT_MODE_BTDM`, it also releases the BSS and data consumed by the BT/BLE Host stack to heap + * Additionally, if the mode is set to `ESP_BT_MODE_BTDM`, it also releases the BSS and data consumed by the Classic Bluetooth and BLE Host stack to heap. * * If you never intend to use Bluetooth in a current boot-up cycle, you can call `esp_bt_mem_release(ESP_BT_MODE_BTDM)` * before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. @@ -625,14 +625,14 @@ esp_err_t esp_bt_sleep_disable(void); esp_err_t esp_ble_scan_dupilcate_list_flush(void); /** - * @brief Power on BT Wi-Fi power domain + * @brief Power on Bluetooth Wi-Fi power domain * * @note This function is not recommended to use due to potential risk. */ void esp_wifi_bt_power_domain_on(void); /** - * @brief Power off BT Wi-Fi power domain + * @brief Power off Bluetooth Wi-Fi power domain * * @note This function is not recommended to use due to potential risk. */ From 2f9af2ce02626b90a024541ff8cdc5e8a191d59f Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Thu, 20 Jun 2024 11:46:22 +0800 Subject: [PATCH 440/548] docs(ble): Removed note in esp_bt_controller_config_t --- components/bt/include/esp32/include/esp_bt.h | 29 ++------------------ 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index c30c98f1154..eb521abe209 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -217,24 +217,8 @@ the adv packet will be discarded until the memory is restored. */ /** * @brief Bluetooth Controller config options - * @note - * 1. The following parameters can be configured at runtime when calling esp_bt_controller_init(): - * - * `controller_task_stack_size`, `controller_task_prio`, `hci_uart_no`, `hci_uart_baudrate` - * `scan_duplicate_mode`, `scan_duplicate_type`, `normal_adv_size`, `mesh_adv_size`, `send_adv_reserved_size`, - * `controller_debug_flag`, `mode`, `ble_max_conn`, `bt_max_acl_conn`, `bt_sco_datapath`, `auto_latency`, - * `bt_legacy_auth_vs_evt` - * - * 2. The following parameters cannot be configured at runtime when calling `esp_bt_controller_init()`. - * They will be overwritten with values in menuconfig or from a macro: - * - * `bt_max_sync_conn`, `ble_sca`, `pcm_role`, `pcm_polar`, `hli`, `dup_list_refresh_period`, `ble_scan_backoff`, - * `magic`. */ typedef struct { - /* - * Following parameters can be configured runtime, when call esp_bt_controller_init() - */ uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size in bytes */ uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */ @@ -251,11 +235,6 @@ typedef struct { uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ bool auto_latency; /*!< BLE auto latency, used to enhance Classic Bluetooth performance */ bool bt_legacy_auth_vs_evt; /*!< BR/EDR Legacy auth complete event required to protect from BIAS attack */ - /* - * Following parameters can not be configured runtime when call esp_bt_controller_init() - * It will be overwrite with a constant value which in menuconfig or from a macro. - * So, do not modify the value when esp_bt_controller_init() - */ uint8_t bt_max_sync_conn; /*!< BR/EDR maximum ACL connection numbers. Effective in menuconfig */ uint8_t ble_sca; /*!< BLE low power crystal accuracy index */ uint8_t pcm_role; /*!< PCM role (master & slave)*/ @@ -625,16 +604,12 @@ esp_err_t esp_bt_sleep_disable(void); esp_err_t esp_ble_scan_dupilcate_list_flush(void); /** - * @brief Power on Bluetooth Wi-Fi power domain - * - * @note This function is not recommended to use due to potential risk. + * @brief bt Wi-Fi power domain power on */ void esp_wifi_bt_power_domain_on(void); /** - * @brief Power off Bluetooth Wi-Fi power domain - * - * @note This function is not recommended to use due to potential risk. + * @brief bt Wi-Fi power domain power off */ void esp_wifi_bt_power_domain_off(void); From f0cb44a69c0411adf5a2684ba23598d3ec5c8726 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Thu, 20 Jun 2024 17:18:56 +0800 Subject: [PATCH 441/548] Apply 35 suggestion(s) to 1 file(s) Co-authored-by: Wang Ning --- components/bt/include/esp32/include/esp_bt.h | 70 ++++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index eb521abe209..23ff519db00 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -70,7 +70,7 @@ typedef enum { /** * @brief BLE sleep clock accuracy(SCA) * - * @note Currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported + * @note Currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported. */ typedef enum { ESP_BLE_SCA_500PPM = 0, /*!< BLE SCA at 500 ppm */ @@ -221,8 +221,8 @@ the adv packet will be discarded until the memory is restored. */ typedef struct { uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size in bytes */ uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ - uint8_t hci_uart_no; /*!< If use UART1/2 as HCI IO interface, indicate UART number */ - uint32_t hci_uart_baudrate; /*!< If use UART1/2 as HCI IO interface, indicate UART baudrate */ + uint8_t hci_uart_no; /*!< Indicates UART number if using UART1/2 as HCI I/O interface */ + uint32_t hci_uart_baudrate; /*!< Indicates UART baudrate if using UART1/2 as HCI I/O interface */ uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode */ uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type */ uint16_t normal_adv_size; /*!< Scan duplicate filtering list size with normal ADV */ @@ -230,12 +230,12 @@ typedef struct { uint16_t send_adv_reserved_size; /*!< Controller minimum memory value*/ uint32_t controller_debug_flag; /*!< Controller debug log flag */ uint8_t mode; /*!< Controller mode: BLE mode (1), Classic Bluetooth mode (2) or Dual mode (3) */ - uint8_t ble_max_conn; /*!< BLE maximum connection numbers */ - uint8_t bt_max_acl_conn; /*!< BR/EDR maximum ACL connection numbers */ + uint8_t ble_max_conn; /*!< Maximum number of BLE connections */ + uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections */ uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ bool auto_latency; /*!< BLE auto latency, used to enhance Classic Bluetooth performance */ bool bt_legacy_auth_vs_evt; /*!< BR/EDR Legacy auth complete event required to protect from BIAS attack */ - uint8_t bt_max_sync_conn; /*!< BR/EDR maximum ACL connection numbers. Effective in menuconfig */ + uint8_t bt_max_sync_conn; /*!< Maximum number of BR/EDR synchronous connections. Effective in menuconfig */ uint8_t ble_sca; /*!< BLE low power crystal accuracy index */ uint8_t pcm_role; /*!< PCM role (master & slave)*/ uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */ @@ -250,9 +250,9 @@ typedef struct { */ typedef enum { ESP_BT_CONTROLLER_STATUS_IDLE = 0, /*!< The Controller is not initialized or has been de-initialized.*/ - ESP_BT_CONTROLLER_STATUS_INITED, /*!< The Controller has been initialized. But it is not enabled or has been disabled. */ + ESP_BT_CONTROLLER_STATUS_INITED, /*!< The Controller has been initialized, but not enabled or has been disabled. */ ESP_BT_CONTROLLER_STATUS_ENABLED, /*!< The Controller has been initialized and enabled. */ - ESP_BT_CONTROLLER_STATUS_NUM, /*!< Controller status numbers */ + ESP_BT_CONTROLLER_STATUS_NUM, /*!< Number of Controller statuses */ } esp_bt_controller_status_t; /** @@ -277,7 +277,7 @@ typedef enum { ESP_BLE_PWR_TYPE_ADV = 9, /*!< TX power for advertising */ ESP_BLE_PWR_TYPE_SCAN = 10, /*!< TX power for scan */ ESP_BLE_PWR_TYPE_DEFAULT = 11, /*!< Default TX power type, which can be used to set the TX power for power types that have not been set before.*/ - ESP_BLE_PWR_TYPE_NUM = 12, /*!< TYPE numbers */ + ESP_BLE_PWR_TYPE_NUM = 12, /*!< Number of types */ } esp_ble_power_type_t; /** @@ -315,7 +315,7 @@ typedef enum { * * @note Connection TX power should only be set after the connection is established. * - * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. + * @param[in] power_type The type of TX power. It could be Advertising, Connection, Default, etc. * @param[in] power_level Power level (index) corresponding to the absolute value (dBm) * * @return @@ -327,7 +327,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ /** * @brief Get BLE TX power * - * @note Connection TX power should only be get after the connection is established. + * @note Connection TX power should only be retrived after the connection is established. * * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. * @@ -344,13 +344,13 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type); * The power level will affect the global BR/EDR TX power for operations such as inquiry, page, and connection. * * @note - * 1. Please call the function after `esp_bt_controller_enable()` and before any function that causes RF transmission, + * 1. Please call this function after `esp_bt_controller_enable()` and before any functions that cause RF transmission, * such as performing discovery, profile initialization, and so on. * 2. For BR/EDR to use the new TX power for inquiry, call this function before starting an inquiry. * If BR/EDR is already inquiring, restart the inquiry after calling this function. * 3. The default minimum power level is `ESP_PWR_LVL_N0`, and the maximum power level is `ESP_PWR_LVL_P3`. * - * @param[in] min_power_level The minimum power level + * @param[in] min_power_level The minimum power level. The default value is `ESP_PWR_LVL_N0` * @param[in] max_power_level The maximum power level * * @return @@ -363,9 +363,9 @@ esp_err_t esp_bredr_tx_power_set(esp_power_level_t min_power_level, esp_power_le /** * @brief Get BR/EDR TX power * - * The corresponding power level will be stored into the arguments. + * The corresponding power levels will be stored into the arguments. * - * @param[out] min_power_level The minimum power level + * @param[out] min_power_level Pointer to store the minimum power level * @param[out] max_power_level The maximum power level * * @return @@ -377,7 +377,7 @@ esp_err_t esp_bredr_tx_power_get(esp_power_level_t *min_power_level, esp_power_l /** * @brief Set default SCO data path * - * @note This function should be called after the Controller is enabled, and before (e)SCO link is established + * @note This function should be called after the Controller is enabled, and before (e)SCO link is established. * * @param[in] data_path SCO data path * @@ -392,7 +392,7 @@ esp_err_t esp_bredr_sco_datapath_set(esp_sco_data_path_t data_path); * * @note This function should be called only once, before any other Bluetooth functions. * - * @param[in] cfg Initial Bluetooth Controller configuration. + * @param[in] cfg Initial Bluetooth Controller configuration * * @return * - ESP_OK: Success @@ -404,7 +404,7 @@ esp_err_t esp_bt_controller_init(esp_bt_controller_config_t *cfg); * @brief De-initialize Bluetooth Controller to free resources and delete tasks * * @note - * 1. You should stop advertising and scanning, as well as disconnect all existing connections before de-initializing Bluetooth Controller. + * 1. You should stop advertising and scanning, and disconnect all existing connections before de-initializing Bluetooth Controller. * 2. This function should be called only once, after any other Bluetooth functions. * * @return @@ -419,12 +419,12 @@ esp_err_t esp_bt_controller_deinit(void); * @brief Enable Bluetooth Controller * * @note - * 1. Bluetooth Controller cannot be enabled in `ESP_BT_CONTROLLER_STATUS_IDLE` status. It have to be initialized first. - * 2. Due to a known issue, you cannot call `esp_bt_controller_enable()` a second time + * 1. Bluetooth Controller cannot be enabled in `ESP_BT_CONTROLLER_STATUS_IDLE` status. It has to be initialized first. + * 2. Due to a known issue, you cannot call `esp_bt_controller_enable()` for the second time * to change the Controller mode dynamically. To change the Controller mode, call * `esp_bt_controller_disable()` and then call `esp_bt_controller_enable()` with the new mode. * - * @param[in] mode the Bluetooth Controller mode (BLE/Classic Bluetooth/BTDM) to enable + * @param[in] mode The Bluetooth Controller mode (BLE/Classic Bluetooth/BTDM) to enable * * For API compatibility, retain this argument. This mode must match the mode specified in the `cfg` of `esp_bt_controller_init()`. * @@ -448,7 +448,7 @@ esp_err_t esp_bt_controller_disable(void); * * @return * - ESP_BT_CONTROLLER_STATUS_IDLE: The Controller is not initialized or has been de-initialized. - * - ESP_BT_CONTROLLER_STATUS_INITED: The Controller has been initialized. But it is not enabled or has been disabled. + * - ESP_BT_CONTROLLER_STATUS_INITED: The Controller has been initialized, but not enabled or has been disabled. * - ESP_BT_CONTROLLER_STATUS_ENABLED: The Controller has been initialized and enabled. */ esp_bt_controller_status_t esp_bt_controller_get_status(void); @@ -480,8 +480,8 @@ bool esp_vhci_host_check_send_available(void); * 1. This function shall not be called within a critical section or when the scheduler is suspended. * 2. This function should be called only if `esp_vhci_host_check_send_available()` returns True. * - * @param[in] data the packet point - * @param[in] len the packet length + * @param[in] Pointer to the packet data + * @param[in] len The packet length */ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); @@ -499,21 +499,21 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba /** * @brief Release the Controller memory as per the mode * - * This function releases the BSS, data and other sections of the Controller to heap. The total size is about 70k bytes. + * This function releases the BSS, data and other sections of the Controller to heap. The total size is about 70 KB. * * If the app calls `esp_bt_controller_enable(ESP_BT_MODE_BLE)` to use BLE only, - * then it is safe to call `esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)` at initialization time to free unused Classic Bluetooth memory. + * then it is safe to call `esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)` at initialization time to free unused Classic Bluetooth memory. * * If the mode is `ESP_BT_MODE_BTDM`, then it may be useful to call API `esp_bt_mem_release(ESP_BT_MODE_BTDM)` instead, * which internally calls `esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)` and additionally releases the BSS and data - * consumed by the Classic Bluetooth/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function + * consumed by the Classic Bluetooth/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function. * * @note * 1. This function should be called only before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. * 2. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. * 3. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * - * @param[in] mode the Bluetooth Controller mode + * @param[in] mode The Bluetooth Controller mode * * @return * - ESP_OK: Success @@ -530,7 +530,7 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * If you never intend to use Bluetooth in a current boot-up cycle, you can call `esp_bt_mem_release(ESP_BT_MODE_BTDM)` * before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. * - * For example, if a user only uses Bluetooth for setting the WiFi configuration, and does not use Bluetooth in the rest of the product operation. + * For example, if you only use Bluetooth for setting the Wi-Fi configuration, and do not use Bluetooth in the rest of the product operation, * In such cases, after receiving the WiFi configuration, you can disable/de-init Bluetooth and release its memory. * Below is the sequence of APIs to be called for such scenarios: * @@ -545,7 +545,7 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * 2. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * 3. In case of NimBLE Host, to release BSS and data memory to heap, the mode needs to be set to `ESP_BT_MODE_BTDM` as the Controller is in Dual mode. * - * @param[in] mode the Bluetooth Controller mode + * @param[in] mode The Bluetooth Controller mode * * @return * - ESP_OK: Success @@ -557,13 +557,13 @@ esp_err_t esp_bt_mem_release(esp_bt_mode_t mode); /** * @brief Enable Bluetooth modem sleep * - * There are currently two options for Bluetooth modem sleep: ORIG mode and EVED mode, the latter being intended for BLE only. + * There are currently two options for Bluetooth modem sleep: ORIG mode and EVED mode. The latter is intended for BLE only. * The modem sleep mode could be configured in menuconfig. * * In ORIG mode, if there is no event to process, the Bluetooth Controller will periodically switch off some components and pause operation, then wake up according to the scheduled interval and resume work. * It can also wakeup earlier upon external request using function `esp_bt_controller_wakeup_request()`. * - * @note This function shall not be invoked before `esp_bt_controller_enable()` + * @note This function shall not be invoked before `esp_bt_controller_enable()`. * * @return * - ESP_OK: Success @@ -590,12 +590,12 @@ esp_err_t esp_bt_sleep_enable(void); esp_err_t esp_bt_sleep_disable(void); /** - * @brief Manually clear scan duplicate list + * @brief Manually clear the scan duplicate list * * @note * 1. This function name is incorrectly spelled, it will be fixed in release 5.x version. - * 2. The scan duplicate list will be automatically cleared when the maximum amount of device in the filter is reached. - * The amount of device in the filter can be configured in menuconfig. + * 2. The scan duplicate list will be automatically cleared when the maximum amount of devices in the filter is reached. + * The amount of devices in the filter can be configured in menuconfig. * * @return * - ESP_OK: Success From d0a5c72c7504e796de3b011151d75df153d8a07b Mon Sep 17 00:00:00 2001 From: Yuhan Wei Date: Tue, 25 Jun 2024 13:40:03 +0800 Subject: [PATCH 442/548] docs(ble): Add the explanations to controller parameters configurable in menuconfig --- components/bt/include/esp32/include/esp_bt.h | 98 +++++++++++--------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 23ff519db00..efa23deb1bf 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -68,7 +68,7 @@ typedef enum { } esp_bt_mode_t; /** - * @brief BLE sleep clock accuracy(SCA) + * @brief BLE sleep clock accuracy (SCA) * * @note Currently only ESP_BLE_SCA_500PPM and ESP_BLE_SCA_250PPM are supported. */ @@ -217,31 +217,40 @@ the adv packet will be discarded until the memory is restored. */ /** * @brief Bluetooth Controller config options + * @note + * 1. For parameters configurable in menuconfig, please refer to menuconfig for details on range and default values. + * 2. It is not recommended to modify the default values of `controller_task_stack_size`, `controller_task_prio`. */ typedef struct { uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size in bytes */ uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ - uint8_t hci_uart_no; /*!< Indicates UART number if using UART1/2 as HCI I/O interface */ - uint32_t hci_uart_baudrate; /*!< Indicates UART baudrate if using UART1/2 as HCI I/O interface */ - uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode */ - uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type */ - uint16_t normal_adv_size; /*!< Scan duplicate filtering list size with normal ADV */ - uint16_t mesh_adv_size; /*!< Scan duplicate filtering list size with mesh ADV */ - uint16_t send_adv_reserved_size; /*!< Controller minimum memory value*/ - uint32_t controller_debug_flag; /*!< Controller debug log flag */ - uint8_t mode; /*!< Controller mode: BLE mode (1), Classic Bluetooth mode (2) or Dual mode (3) */ - uint8_t ble_max_conn; /*!< Maximum number of BLE connections */ - uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections */ - uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module */ - bool auto_latency; /*!< BLE auto latency, used to enhance Classic Bluetooth performance */ - bool bt_legacy_auth_vs_evt; /*!< BR/EDR Legacy auth complete event required to protect from BIAS attack */ - uint8_t bt_max_sync_conn; /*!< Maximum number of BR/EDR synchronous connections. Effective in menuconfig */ - uint8_t ble_sca; /*!< BLE low power crystal accuracy index */ - uint8_t pcm_role; /*!< PCM role (master & slave)*/ - uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge) */ - bool hli; /*!< Using high level interrupt or not */ - uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period */ - bool ble_scan_backoff; /*!< BLE scan backoff */ + uint8_t hci_uart_no; /*!< Indicates UART number if using UART1/2 as HCI I/O interface. Configurable in menuconfig. */ + uint32_t hci_uart_baudrate; /*!< Indicates UART baudrate if using UART1/2 as HCI I/O interface. Configurable in menuconfig. */ + uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode. Configurable in menuconfig. */ + uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type. Configurable in menuconfig. */ + uint16_t normal_adv_size; /*!< Maximum number of devices in scan duplicate filtering list. Configurable in menuconfig. */ + uint16_t mesh_adv_size; /*!< Maximum number of Mesh ADV packets in scan duplicate filtering list. Configurable in menuconfig. */ + uint16_t send_adv_reserved_size; /*!< Controller minimum memory value in bytes. Internal use only */ + uint32_t controller_debug_flag; /*!< Controller debug log flag. Internal use only */ + uint8_t mode; /*!< Controller mode: + 1: BLE mode + 2: Classic Bluetooth mode + 3: Dual mode + Others: Invalid + Configurable in menuconfig. + */ + uint8_t ble_max_conn; /*!< Maximum number of BLE connections. Configurable in menuconfig. */ + uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections. Configurable in menuconfig. */ + uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module. Configurable in menuconfig. */ + bool auto_latency; /*!< True if BLE auto latency is enabled, used to enhance Classic Bluetooth performance; false otherwise. Configurable in menuconfig.*/ + bool bt_legacy_auth_vs_evt; /*!< True if BR/EDR Legacy Authentication Vendor Specific Event is enabled, which is required to protect from BIAS attack; false otherwise. Configurable in menuconfig. */ + uint8_t bt_max_sync_conn; /*!< Maximum number of BR/EDR synchronous connections. Configurable in menuconfig. */ + uint8_t ble_sca; /*!< BLE low power crystal accuracy index. Configurable in menuconfig. */ + uint8_t pcm_role; /*!< PCM role (master & slave). Configurable in menuconfig.*/ + uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge). Configurable in menuconfig. */ + bool hli; /*!< True if using high level interrupt; false otherwise. Configurable in menuconfig. */ + uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period in seconds. Configurable in menuconfig.*/ + bool ble_scan_backoff; /*!< True if BLE scan backoff is enabled; false otherwise. Configurable in menuconfig.*/ uint32_t magic; /*!< Magic number */ } esp_bt_controller_config_t; @@ -285,21 +294,21 @@ typedef enum { */ typedef enum { ESP_PWR_LVL_N12 = 0, /*!< Corresponding to -12 dBm */ - ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9 dBm */ - ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6 dBm */ - ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3 dBm */ - ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0 dBm */ - ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3 dBm */ - ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6 dBm */ - ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9 dBm */ + ESP_PWR_LVL_N9 = 1, /*!< Corresponding to -9 dBm */ + ESP_PWR_LVL_N6 = 2, /*!< Corresponding to -6 dBm */ + ESP_PWR_LVL_N3 = 3, /*!< Corresponding to -3 dBm */ + ESP_PWR_LVL_N0 = 4, /*!< Corresponding to 0 dBm */ + ESP_PWR_LVL_P3 = 5, /*!< Corresponding to +3 dBm */ + ESP_PWR_LVL_P6 = 6, /*!< Corresponding to +6 dBm */ + ESP_PWR_LVL_P9 = 7, /*!< Corresponding to +9 dBm */ ESP_PWR_LVL_N14 = ESP_PWR_LVL_N12, /*!< Backward compatibility! Setting to -14 dBm will actually result in -12 dBm */ - ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11 dBm will actually result in -9 dBm */ - ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8 dBm will actually result in -6 dBm */ - ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5 dBm will actually result in -3 dBm */ - ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2 dBm will actually result in 0 dBm */ - ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1 dBm will actually result in +3 dBm */ - ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4 dBm will actually result in +6 dBm */ - ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7 dBm will actually result in +9 dBm */ + ESP_PWR_LVL_N11 = ESP_PWR_LVL_N9, /*!< Backward compatibility! Setting to -11 dBm will actually result in -9 dBm */ + ESP_PWR_LVL_N8 = ESP_PWR_LVL_N6, /*!< Backward compatibility! Setting to -8 dBm will actually result in -6 dBm */ + ESP_PWR_LVL_N5 = ESP_PWR_LVL_N3, /*!< Backward compatibility! Setting to -5 dBm will actually result in -3 dBm */ + ESP_PWR_LVL_N2 = ESP_PWR_LVL_N0, /*!< Backward compatibility! Setting to -2 dBm will actually result in 0 dBm */ + ESP_PWR_LVL_P1 = ESP_PWR_LVL_P3, /*!< Backward compatibility! Setting to +1 dBm will actually result in +3 dBm */ + ESP_PWR_LVL_P4 = ESP_PWR_LVL_P6, /*!< Backward compatibility! Setting to +4 dBm will actually result in +6 dBm */ + ESP_PWR_LVL_P7 = ESP_PWR_LVL_P9, /*!< Backward compatibility! Setting to +7 dBm will actually result in +9 dBm */ } esp_power_level_t; /** @@ -348,10 +357,9 @@ esp_power_level_t esp_ble_tx_power_get(esp_ble_power_type_t power_type); * such as performing discovery, profile initialization, and so on. * 2. For BR/EDR to use the new TX power for inquiry, call this function before starting an inquiry. * If BR/EDR is already inquiring, restart the inquiry after calling this function. - * 3. The default minimum power level is `ESP_PWR_LVL_N0`, and the maximum power level is `ESP_PWR_LVL_P3`. * - * @param[in] min_power_level The minimum power level. The default value is `ESP_PWR_LVL_N0` - * @param[in] max_power_level The maximum power level + * @param[in] min_power_level The minimum power level. The default value is `ESP_PWR_LVL_N0`. + * @param[in] max_power_level The maximum power level. The default value is `ESP_PWR_LVL_P3`. * * @return * - ESP_OK: Success @@ -604,13 +612,17 @@ esp_err_t esp_bt_sleep_disable(void); esp_err_t esp_ble_scan_dupilcate_list_flush(void); /** - * @brief bt Wi-Fi power domain power on - */ + * @brief Power on Bluetooth Wi-Fi power domain + * + * @note This function is not recommended to use due to potential risk. +*/ void esp_wifi_bt_power_domain_on(void); /** - * @brief bt Wi-Fi power domain power off - */ + * @brief Power off Bluetooth Wi-Fi power domain + * + * @note This function is not recommended to use due to potential risk. +*/ void esp_wifi_bt_power_domain_off(void); #ifdef __cplusplus From 4aaad560b39fb200e39627766bd8b62b5a6d1cf9 Mon Sep 17 00:00:00 2001 From: Wang Ning Date: Tue, 25 Jun 2024 13:43:24 +0800 Subject: [PATCH 443/548] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: Wang Ning --- components/bt/include/esp32/include/esp_bt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index efa23deb1bf..e6aa15aaa77 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -539,7 +539,7 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. * * For example, if you only use Bluetooth for setting the Wi-Fi configuration, and do not use Bluetooth in the rest of the product operation, - * In such cases, after receiving the WiFi configuration, you can disable/de-init Bluetooth and release its memory. + * after receiving the Wi-Fi configuration, you can disable/de-init Bluetooth and release its memory. * Below is the sequence of APIs to be called for such scenarios: * * esp_bluedroid_disable(); From efbc3bbbf50ee4ae639a665137166377358f3478 Mon Sep 17 00:00:00 2001 From: weiyuhan Date: Fri, 5 Jul 2024 18:25:00 +0800 Subject: [PATCH 444/548] docs(ble): Removed period for incomplete sentences --- components/bt/include/esp32/include/esp_bt.h | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index e6aa15aaa77..e2b95858feb 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -224,12 +224,12 @@ the adv packet will be discarded until the memory is restored. */ typedef struct { uint16_t controller_task_stack_size; /*!< Bluetooth Controller task stack size in bytes */ uint8_t controller_task_prio; /*!< Bluetooth Controller task priority */ - uint8_t hci_uart_no; /*!< Indicates UART number if using UART1/2 as HCI I/O interface. Configurable in menuconfig. */ - uint32_t hci_uart_baudrate; /*!< Indicates UART baudrate if using UART1/2 as HCI I/O interface. Configurable in menuconfig. */ - uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode. Configurable in menuconfig. */ - uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type. Configurable in menuconfig. */ - uint16_t normal_adv_size; /*!< Maximum number of devices in scan duplicate filtering list. Configurable in menuconfig. */ - uint16_t mesh_adv_size; /*!< Maximum number of Mesh ADV packets in scan duplicate filtering list. Configurable in menuconfig. */ + uint8_t hci_uart_no; /*!< Indicates UART number if using UART1/2 as HCI I/O interface. Configurable in menuconfig */ + uint32_t hci_uart_baudrate; /*!< Indicates UART baudrate if using UART1/2 as HCI I/O interface. Configurable in menuconfig */ + uint8_t scan_duplicate_mode; /*!< Scan duplicate filtering mode. Configurable in menuconfig */ + uint8_t scan_duplicate_type; /*!< Scan duplicate filtering type. Configurable in menuconfig */ + uint16_t normal_adv_size; /*!< Maximum number of devices in scan duplicate filtering list. Configurable in menuconfig */ + uint16_t mesh_adv_size; /*!< Maximum number of Mesh ADV packets in scan duplicate filtering list. Configurable in menuconfig */ uint16_t send_adv_reserved_size; /*!< Controller minimum memory value in bytes. Internal use only */ uint32_t controller_debug_flag; /*!< Controller debug log flag. Internal use only */ uint8_t mode; /*!< Controller mode: @@ -239,18 +239,18 @@ typedef struct { Others: Invalid Configurable in menuconfig. */ - uint8_t ble_max_conn; /*!< Maximum number of BLE connections. Configurable in menuconfig. */ - uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections. Configurable in menuconfig. */ - uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module. Configurable in menuconfig. */ - bool auto_latency; /*!< True if BLE auto latency is enabled, used to enhance Classic Bluetooth performance; false otherwise. Configurable in menuconfig.*/ - bool bt_legacy_auth_vs_evt; /*!< True if BR/EDR Legacy Authentication Vendor Specific Event is enabled, which is required to protect from BIAS attack; false otherwise. Configurable in menuconfig. */ - uint8_t bt_max_sync_conn; /*!< Maximum number of BR/EDR synchronous connections. Configurable in menuconfig. */ - uint8_t ble_sca; /*!< BLE low power crystal accuracy index. Configurable in menuconfig. */ - uint8_t pcm_role; /*!< PCM role (master & slave). Configurable in menuconfig.*/ - uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge). Configurable in menuconfig. */ - bool hli; /*!< True if using high level interrupt; false otherwise. Configurable in menuconfig. */ - uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period in seconds. Configurable in menuconfig.*/ - bool ble_scan_backoff; /*!< True if BLE scan backoff is enabled; false otherwise. Configurable in menuconfig.*/ + uint8_t ble_max_conn; /*!< Maximum number of BLE connections. Configurable in menuconfig */ + uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections. Configurable in menuconfig */ + uint8_t bt_sco_datapath; /*!< SCO data path, i.e. HCI or PCM module. Configurable in menuconfig */ + bool auto_latency; /*!< True if BLE auto latency is enabled, used to enhance Classic Bluetooth performance; false otherwise. Configurable in menuconfig */ + bool bt_legacy_auth_vs_evt; /*!< True if BR/EDR Legacy Authentication Vendor Specific Event is enabled, which is required to protect from BIAS attack; false otherwise. Configurable in menuconfig */ + uint8_t bt_max_sync_conn; /*!< Maximum number of BR/EDR synchronous connections. Configurable in menuconfig */ + uint8_t ble_sca; /*!< BLE low power crystal accuracy index. Configurable in menuconfig */ + uint8_t pcm_role; /*!< PCM role (master & slave). Configurable in menuconfig */ + uint8_t pcm_polar; /*!< PCM polar trig (falling clk edge & rising clk edge). Configurable in menuconfig */ + bool hli; /*!< True if using high level interrupt; false otherwise. Configurable in menuconfig */ + uint16_t dup_list_refresh_period; /*!< Scan duplicate filtering list refresh period in seconds. Configurable in menuconfig */ + bool ble_scan_backoff; /*!< True if BLE scan backoff is enabled; false otherwise. Configurable in menuconfig */ uint32_t magic; /*!< Magic number */ } esp_bt_controller_config_t; From 6df549d6b0ac244a2a3e6062863f51b907069aaf Mon Sep 17 00:00:00 2001 From: Wei Yu Han Date: Wed, 10 Jul 2024 10:34:14 +0800 Subject: [PATCH 445/548] docs(ble):Added the parameter name data in esp_vhci_host_send_packet --- components/bt/include/esp32/include/esp_bt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index e2b95858feb..0a486b99cbd 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -336,7 +336,7 @@ esp_err_t esp_ble_tx_power_set(esp_ble_power_type_t power_type, esp_power_level_ /** * @brief Get BLE TX power * - * @note Connection TX power should only be retrived after the connection is established. + * @note Connection TX power should only be retrieved after the connection is established. * * @param[in] power_type The type of TX power. It could be Advertising/Connection/Default and etc. * @@ -488,7 +488,7 @@ bool esp_vhci_host_check_send_available(void); * 1. This function shall not be called within a critical section or when the scheduler is suspended. * 2. This function should be called only if `esp_vhci_host_check_send_available()` returns True. * - * @param[in] Pointer to the packet data + * @param[in] data Pointer to the packet data * @param[in] len The packet length */ void esp_vhci_host_send_packet(uint8_t *data, uint16_t len); From 300750b8c60dc4ec16dcfab72242546011d3694e Mon Sep 17 00:00:00 2001 From: Wei Yu Han Date: Fri, 12 Jul 2024 08:11:45 +0800 Subject: [PATCH 446/548] docs(ble): Revised the explanation for esp_bt_mem_release and esp_bt_controller_mem_release --- components/bt/include/esp32/include/esp_bt.h | 48 +++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 0a486b99cbd..5eacae8112d 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -472,11 +472,11 @@ typedef struct esp_vhci_host_callback { /** * @brief Check whether the Controller is ready to receive the packet * - * If the return value is True, the Host can send the packet to the Controller. + *If the return value is True, the Host can send the packet to the Controller. * - * @note This function should be called before each `esp_vhci_host_send_packet()`. + *@note This function should be called before each `esp_vhci_host_send_packet()`. * - * @return + *@return * True if the Controller is ready to receive packets; false otherwise */ bool esp_vhci_host_check_send_available(void); @@ -509,17 +509,17 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba * * This function releases the BSS, data and other sections of the Controller to heap. The total size is about 70 KB. * - * If the app calls `esp_bt_controller_enable(ESP_BT_MODE_BLE)` to use BLE only, - * then it is safe to call `esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)` at initialization time to free unused Classic Bluetooth memory. + * @note + * 1. This function is optional and should be called only if you want to free up memory for other components. + * 2. This function should only be called when the controller is in `ESP_BT_CONTROLLER_STATUS_IDLE` status. + * 3. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. + * 4. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * - * If the mode is `ESP_BT_MODE_BTDM`, then it may be useful to call API `esp_bt_mem_release(ESP_BT_MODE_BTDM)` instead, - * which internally calls `esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)` and additionally releases the BSS and data - * consumed by the Classic Bluetooth/BLE Host stack to heap. For more details about usage please refer to the documentation of `esp_bt_mem_release()` function. + * If you never intend to use Bluetooth in a current boot-up cycle, calling `esp_bt_controller_mem_release(ESP_BT_MODE_BTDM)` could release the BSS and data consumed by both Classic Bluetooth and BLE Controller to heap. * - * @note - * 1. This function should be called only before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. - * 2. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. - * 3. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. + * If you intend to use BLE only, calling `esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)` could release the BSS and data consumed by Classic Bluetooth Controller. You can then continue using BLE. + * + * If you intend to use Classic Bluetooth only, calling `esp_bt_controller_mem_release(ESP_BT_MODE_BLE)` could release the BSS and data consumed by BLE Controller. You can then continue using Classic Bluetooth. * * @param[in] mode The Bluetooth Controller mode * @@ -530,13 +530,22 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba */ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); -/** @brief Release the Controller memory, BSS and data section of the Classic Bluetooth/BLE Host stack as per the mode +/** + * @brief Release the Controller memory, BSS and data section of the Classic Bluetooth/BLE Host stack as per the mode + * + * @note + * 1. This function is optional and should be called only if you want to free up memory for other components. + * 2. This function should only be called when the controller is in `ESP_BT_CONTROLLER_STATUS_IDLE` status. + * 3. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. + * 4. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. * - * This function first releases Controller memory by internally calling `esp_bt_controller_mem_release()`. - * Additionally, if the mode is set to `ESP_BT_MODE_BTDM`, it also releases the BSS and data consumed by the Classic Bluetooth and BLE Host stack to heap. + * This function first releases Controller memory by internally calling `esp_bt_controller_mem_release()`, then releases Host memory. * - * If you never intend to use Bluetooth in a current boot-up cycle, you can call `esp_bt_mem_release(ESP_BT_MODE_BTDM)` - * before `esp_bt_controller_init()` or after `esp_bt_controller_deinit()`. + * If you never intend to use Bluetooth in a current boot-up cycle, calling `esp_bt_mem_release(ESP_BT_MODE_BTDM)` could release the BSS and data consumed by both Classic Bluetooth and BLE stack to heap. + * + * If you intend to use BLE only, calling `esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT)` could release the BSS and data consumed by Classic Bluetooth. You can then continue using BLE. + * + * If you intend to use Classic Bluetooth only, calling `esp_bt_mem_release(ESP_BT_MODE_BLE)` could release the BSS and data consumed by BLE. You can then continue using Classic Bluetooth. * * For example, if you only use Bluetooth for setting the Wi-Fi configuration, and do not use Bluetooth in the rest of the product operation, * after receiving the Wi-Fi configuration, you can disable/de-init Bluetooth and release its memory. @@ -548,11 +557,6 @@ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); * esp_bt_controller_deinit(); * esp_bt_mem_release(ESP_BT_MODE_BTDM); * - * @note - * 1. Once Bluetooth Controller memory is released, the process cannot be reversed. This means you cannot use the Bluetooth Controller mode that you have released using this function. - * 2. If your firmware will upgrade the Bluetooth Controller mode later (such as switching from BLE to Classic Bluetooth or from disabled to enabled), then do not call this function. - * 3. In case of NimBLE Host, to release BSS and data memory to heap, the mode needs to be set to `ESP_BT_MODE_BTDM` as the Controller is in Dual mode. - * * @param[in] mode The Bluetooth Controller mode * * @return From cd05dfede7a359586ff3e8a1a84c2bc94ff4dd88 Mon Sep 17 00:00:00 2001 From: Wei Yu Han Date: Fri, 12 Jul 2024 08:49:26 +0800 Subject: [PATCH 447/548] docs(ble): Added newline for mode in esp_bt_controller_config_t --- components/bt/include/esp32/include/esp_bt.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index 5eacae8112d..be435918451 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -233,11 +233,16 @@ typedef struct { uint16_t send_adv_reserved_size; /*!< Controller minimum memory value in bytes. Internal use only */ uint32_t controller_debug_flag; /*!< Controller debug log flag. Internal use only */ uint8_t mode; /*!< Controller mode: + 1: BLE mode + 2: Classic Bluetooth mode + 3: Dual mode + Others: Invalid - Configurable in menuconfig. + + Configurable in menuconfig */ uint8_t ble_max_conn; /*!< Maximum number of BLE connections. Configurable in menuconfig */ uint8_t bt_max_acl_conn; /*!< Maximum number of BR/EDR ACL connections. Configurable in menuconfig */ @@ -474,9 +479,9 @@ typedef struct esp_vhci_host_callback { * *If the return value is True, the Host can send the packet to the Controller. * - *@note This function should be called before each `esp_vhci_host_send_packet()`. + * @note This function should be called before each `esp_vhci_host_send_packet()`. * - *@return + * @return * True if the Controller is ready to receive packets; false otherwise */ bool esp_vhci_host_check_send_available(void); From 9c507c76f1591a0064157e04bf29b19950888e81 Mon Sep 17 00:00:00 2001 From: Wei Yu Han Date: Fri, 12 Jul 2024 09:12:30 +0800 Subject: [PATCH 448/548] docs(ble): Removed trailing whitespaces --- components/bt/include/esp32/include/esp_bt.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/bt/include/esp32/include/esp_bt.h b/components/bt/include/esp32/include/esp_bt.h index be435918451..ed7cfa1df2b 100644 --- a/components/bt/include/esp32/include/esp_bt.h +++ b/components/bt/include/esp32/include/esp_bt.h @@ -233,15 +233,15 @@ typedef struct { uint16_t send_adv_reserved_size; /*!< Controller minimum memory value in bytes. Internal use only */ uint32_t controller_debug_flag; /*!< Controller debug log flag. Internal use only */ uint8_t mode; /*!< Controller mode: - + 1: BLE mode - + 2: Classic Bluetooth mode - + 3: Dual mode - + Others: Invalid - + Configurable in menuconfig */ uint8_t ble_max_conn; /*!< Maximum number of BLE connections. Configurable in menuconfig */ @@ -276,7 +276,7 @@ typedef enum { * After disconnecting, the corresponding TX power will not be affected. * 2. `ESP_BLE_PWR_TYPE_DEFAULT` can be used to set the TX power for power types that have not been set before. * It will not affect the TX power values which have been set for the following CONN0-8/ADV/SCAN power types. - * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for ADV/SCAN/CONN0-8. + * 3. If none of power type is set, the system will use `ESP_PWR_LVL_P3` as default for all power types. */ typedef enum { ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, /*!< TX power for connection handle 0 */ @@ -535,7 +535,7 @@ esp_err_t esp_vhci_host_register_callback(const esp_vhci_host_callback_t *callba */ esp_err_t esp_bt_controller_mem_release(esp_bt_mode_t mode); -/** +/** * @brief Release the Controller memory, BSS and data section of the Classic Bluetooth/BLE Host stack as per the mode * * @note From e5c1a03e52dc23e194510a9f16d8739b40257290 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 14 May 2024 15:58:17 +0530 Subject: [PATCH 449/548] fix(nimble): Fixed BLE security vulnerability when using fixed IRK --- components/bt/host/nimble/Kconfig.in | 10 ++++++++++ components/bt/host/nimble/nimble | 2 +- .../bt/host/nimble/port/include/esp_nimble_cfg.h | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index d02293a87a3..5bb08e5ac70 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -164,6 +164,16 @@ config BT_NIMBLE_NVS_PERSIST help Enable this flag to make bonding persistent across device reboots +config BT_NIMBLE_SMP_ID_RESET + bool "Reset device identity when all bonding records are deleted" + default n + help + There are tracking risks associated with using a fixed or static IRK. + If enabled this option, Bluedroid will assign a new randomly-generated IRK + when all pairing and bonding records are deleted. This would decrease the ability + of a previously paired peer to be used to determine whether a device + with which it previously shared an IRK is within range. + menuconfig BT_NIMBLE_SECURITY_ENABLE bool "Enable BLE SM feature" depends on BT_NIMBLE_ENABLED diff --git a/components/bt/host/nimble/nimble b/components/bt/host/nimble/nimble index ec9f21253ae..46ae5865554 160000 --- a/components/bt/host/nimble/nimble +++ b/components/bt/host/nimble/nimble @@ -1 +1 @@ -Subproject commit ec9f21253ae539b44855fed223bee52979a9d251 +Subproject commit 46ae5865554f2fd7df829b6b9b5ca24522b9ad76 diff --git a/components/bt/host/nimble/port/include/esp_nimble_cfg.h b/components/bt/host/nimble/port/include/esp_nimble_cfg.h index d2fa3338866..fc77f592f98 100644 --- a/components/bt/host/nimble/port/include/esp_nimble_cfg.h +++ b/components/bt/host/nimble/port/include/esp_nimble_cfg.h @@ -892,6 +892,14 @@ #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif +#ifndef MYNEWT_VAL_BLE_SMP_ID_RESET +#ifdef CONFIG_BT_NIMBLE_SMP_ID_RESET +#define MYNEWT_VAL_BLE_SMP_ID_RESET CONFIG_BT_NIMBLE_SMP_ID_RESET +#else +#define MYNEWT_VAL_BLE_SMP_ID_RESET (0) +#endif +#endif + #ifndef MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS #define MYNEWT_VAL_BLE_CRYPTO_STACK_MBEDTLS (CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS) #endif From bec7b260c64623f6e6cf3d67594ddc432ecc30f8 Mon Sep 17 00:00:00 2001 From: chenjianhua Date: Tue, 25 Jun 2024 17:00:50 +0800 Subject: [PATCH 450/548] fix(bt): Update bt lib for ESP32-C3 and ESP32-S3(66b5cc0) - Fixed vendor hci get controller status command - Prevent BLE interrupt from being preempted --- components/bt/controller/lib_esp32c3_family | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index 29d5555ca1f..a6ca5e21f7a 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit 29d5555ca1febeb132f5a13556893f3419d2d640 +Subproject commit a6ca5e21f7afabe00db544003419be77e89b9a99 From ed0cc117506b1610e4a285733ad8b591048bd4cf Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Wed, 10 Jul 2024 16:10:13 +0800 Subject: [PATCH 451/548] fix(bt): Update bt lib for ESP32-C3 and ESP32-S3(abd7733) - Fix the issue where RSSI is incorrect when latency is not zero --- components/bt/controller/lib_esp32c3_family | 2 +- components/esp_rom/esp32c3/ld/esp32c3.rom.ld | 2 +- components/esp_rom/esp32s3/ld/esp32s3.rom.ld | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index a6ca5e21f7a..d53a6a695af 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit a6ca5e21f7afabe00db544003419be77e89b9a99 +Subproject commit d53a6a695af1e78a6f36691e2cf525f9787abfdb diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld index 77b4cfbdc6c..100c145899b 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.ld @@ -1036,7 +1036,7 @@ r_lld_con_pref_slave_evt_dur_set = 0x400010f0; r_lld_con_pref_slave_latency_set = 0x400010f4; r_lld_con_rssi_get = 0x400010f8; r_lld_con_rx = 0x400010fc; -r_lld_con_rx_channel_assess = 0x40001100; +/* r_lld_con_rx_channel_assess = 0x40001100; */ r_lld_con_rx_enc = 0x40001104; r_lld_con_rx_isr = 0x40001108; r_lld_con_rx_link_info_check = 0x4000110c; diff --git a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld index 6e6187961da..00ba56b36cd 100644 --- a/components/esp_rom/esp32s3/ld/esp32s3.rom.ld +++ b/components/esp_rom/esp32s3/ld/esp32s3.rom.ld @@ -1286,7 +1286,7 @@ r_lld_con_pref_slave_evt_dur_set = 0x400042b4; r_lld_con_pref_slave_latency_set = 0x400042c0; r_lld_con_rssi_get = 0x400042cc; r_lld_con_rx = 0x400042d8; -r_lld_con_rx_channel_assess = 0x400042e4; +/* r_lld_con_rx_channel_assess = 0x400042e4; */ r_lld_con_rx_enc = 0x400042f0; r_lld_con_rx_isr = 0x400042fc; r_lld_con_rx_link_info_check = 0x40004308; From 313f7be30bbcb2c23e3b593d4e07f1200ce23393 Mon Sep 17 00:00:00 2001 From: linruihao Date: Fri, 12 Jul 2024 11:35:20 +0800 Subject: [PATCH 452/548] fix(coex): Update bt lib for ESP32-C3 and ESP32-S3(e4ba7f6) - Fixed coexist LoadProhibited issue --- components/bt/controller/lib_esp32c3_family | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index d53a6a695af..55485554203 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit d53a6a695af1e78a6f36691e2cf525f9787abfdb +Subproject commit 55485554203a225ff09a8dfcf5284c46b70aa0bd From 2233244c86628dd4088173d36f61b55f6a945f0a Mon Sep 17 00:00:00 2001 From: zhiweijian Date: Thu, 18 Jul 2024 14:52:49 +0800 Subject: [PATCH 453/548] feat(bt/controller): support mesh duplicate with extend scan --- components/bt/controller/lib_esp32c3_family | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c3_family b/components/bt/controller/lib_esp32c3_family index 55485554203..bfdfe8f851c 160000 --- a/components/bt/controller/lib_esp32c3_family +++ b/components/bt/controller/lib_esp32c3_family @@ -1 +1 @@ -Subproject commit 55485554203a225ff09a8dfcf5284c46b70aa0bd +Subproject commit bfdfe8f851c99ced8316b133b0b15521917ea049 From c9e769a5f4c6ee99a9a66de19210ccb46b1ef00d Mon Sep 17 00:00:00 2001 From: zhangshuxian Date: Fri, 7 Jun 2024 16:09:03 +0800 Subject: [PATCH 454/548] docs: Delete user guide esp32-s2-devkitc-1 --- .../esp32-s2-devkitc-1-v1-annotated-photo.png | Bin 430206 -> 0 bytes .../esp32-s2-devkitc-1-v1-block-diags.png | Bin 73587 -> 0 bytes .../esp32-s2-devkitc-1-v1-isometric.png | Bin 297765 -> 0 bytes docs/_static/esp32-s2-devkitc-1-v1-pinout.png | Bin 505345 -> 0 bytes docs/en/get-started/index.rst | 2 +- .../esp32s2/user-guide-s2-devkitc-1.rst | 313 ------------------ docs/zh_CN/get-started/index.rst | 2 +- .../esp32s2/user-guide-s2-devkitc-1.rst | 313 ------------------ 8 files changed, 2 insertions(+), 628 deletions(-) delete mode 100644 docs/_static/esp32-s2-devkitc-1-v1-annotated-photo.png delete mode 100644 docs/_static/esp32-s2-devkitc-1-v1-block-diags.png delete mode 100644 docs/_static/esp32-s2-devkitc-1-v1-isometric.png delete mode 100644 docs/_static/esp32-s2-devkitc-1-v1-pinout.png delete mode 100644 docs/en/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst delete mode 100644 docs/zh_CN/hw-reference/esp32s2/user-guide-s2-devkitc-1.rst diff --git a/docs/_static/esp32-s2-devkitc-1-v1-annotated-photo.png b/docs/_static/esp32-s2-devkitc-1-v1-annotated-photo.png deleted file mode 100644 index 1b33bf4787962952a885bb79ce12b7ba2e59867e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 430206 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
VtmamKZW-o!+!*Fxg#Vvn)kN|xl{@{MZkSHF5 zz)X$hTmDDLFjp-&TZF^elQ2oK1{pu`h(Z|NvkRV!LmYc+&4#Q%=71Q$!t0D%Zuwn& z^$VXRIRIge05`$HID;-utNYu4Uke(3GjS=CC4hGHL8$H_Rd(shwZMxu`_0uc|H;{j z>1Qwk^@JkAb1%9$o|-d@r@=^pXR;4bcaaf^!2oDr$H#136T;LM8ou|qT7{T}pQbGv zu(r_7qz+kJ7kjOXMmM8OTehkjPmhMe>%XJk1cOJ8<`Aj+IEZqkfXWDJ=~l3+(lIdeQ;A{&xKAsawXxPTYvu(BfG7wQ zVCB`uKD1oh;SJi*soe?J0bus1DSmzHU2!~$)XArxj&OwO;&G9S30}lHYAK={GiFfi;p}StvaU&D>O|}7 z!AyH|jX7dOBH-qxEGmKrC;x1lLBq`C$lb|=Nx>7t5J9utxPo-e6XLMYI})i$Z%B{m{3x%9Mc#DpkQ9OO^K~J zh6+;Je?GSzkygG|R#GH*?|!Bi2Q-yn5qOS|8IjebI}1P5|Fq7ONruAVoKw4g89CZe z@=EZYM=__YSh{X~EM2uO%}Y3gD(O3^tPlk>wcclC;-fq44)_@Hy&IQbGc$RaRo8e?;666e%W241N_hwwcHn**Tenmp-F91K%rZB$nil-01*XP;t=2c_;&Os&n0yG~wntNSH-|#O z5Ya%Z4>gL~SZF+p`K5+>FqsaRvYMK4pUqeuu3rN1O)~p^%lc(bYFeHZtw8fSrkUnx z;hIbsPMzTHcW@N%OwA1y&N)d_Lu4?P0(A7qv9Xe7cD^h|L;_Q-JT~fSlbs9Wbv;X$ zFH6}d3RCy9kYhm+&k6o&yY8b}xMRw7jJb4LEsm>g>5>I}&qVkuqx5_gt)P^J;|(w( zfQ2RLdYK=e@dF5{m7;62$5v6x$lTck1fH(SXb@XQBD=VTNWgXS%4d!@*O9wFg7xVU2lCiyE`;Ow-i6a6_8jY&A66 z3yuGV$B(}CH3||d z+%uh~iDPYf?l|fiLQMg~i}AINe6INJfn>ht5&R?Z!7MBGEH|eRIO&qiz|Or;$hjp6 z9@)Z!r$IPbz}OBE!-kY{)(r6p`q3$V{gJPCg4=Z6W`wzR6fYO+COe+{%CmTE!Wk_! z8M{;SnoJuQEkCYhEvkc(g=3@+&3vk5&WsX0q(D4h`~3^@HG`}CF0$bSLziHD9tf1g zDS@A+E24!$kj+(SvwG3hn`nT<@D#qEaqzHzW5FUY10He2}y%;7hwrtZ42WyWt_={o(THVaqKdABbsKlWl*#Eq8-=~X0AWNT81$8gW^J&$5!2o2*~6<* zuBUKAgZ3Gop{$RVi&?j1%&Hkr&1>}dk(?(^XHhizM$cq9wI^KG8Vrkf>tZ@9~V%gf&c@)E%9QrF=88aWg9~i+# zaZlMLM2;qoX^Aw5a9u&Wx9?z^{A=QTw4tv#|_Fnvw?DtNHIh7^K!Ce72|ZV5*~WKb))R;V5d>GFPaPr}8Y|oe?bJtIU%501xs1%nQ$r z*-t!1KpA*3khI`<#UvJ-a{h%;N9*+Ut5$(0&XEzpXO*dJaPZuVFNzD!IEi%f1F>!U z?l|kr)8Zqa_!O{p#_SvGw)a;#LRjmu2zsri5vmG+CoPVfa73JP(vi3e#j}Xt-~Lcq zKa`h1C+$gbDTc(FUa&2aQf11v*^%OHLIhyN)Rlk95)y~RF=;cUb@RP6$tTQ=Yq(ZH zD2@9t_2U#~6%GW+y0V`l0$>;nV|D%vFviIuUDdP*9svJY|D;jo+lDOxqMF64=x_vOya`` z`br&yfvZUxm@|H$z_QJW?wBsxISiv8lme}~nj%4v-B^W~q!Xe8?XVl+sGmHktPEO! zW_jsdGh@`2O0J9ezz_ZuzyJ76(Mmie)w!VEb`s~v%I_rob2lA5`vMZJEP{$^ri`^` z+irwMF_uX^onO(J3=G3W$4?xC+e;ynMI25xjj* zgOAS!<{68vj4Jm;X56cAGoE7BR|!XnPQ-;)Pgabs7lZ7BIW=+N{JB_d#YuCumzfML zGXT#=XxMbIj4U&c-)$Av&J!3Gus0nrO5GSaz|I{YD1g-?$@_xP70x_I=BI|AGTC5; zp1Co2*brK}Y-gP?C^T2c%}56zz?_ZScpkPfoCX>;7E?S401`u$*=?uFy8y}B!d~Z* z)$>pP_+cvl_r|p2rVu0B#JTmm;=viurogOBMmSUq7)Gxo0{dj_XhBs~15>PRytx@c zkrvK85InYkF|}3;%RbTT*Kc6`6yI`T=_OXqIXtCt-y;v>J|rQ7wcLK& zouq@;#GwNR;+{X+3TX$BIe^T?LstkBd5V%5GLTWE>ynF=u`-!>Qj!Dl zljjH{S(R=}`?|rM(!D;f_x0*R;N=Afn<328p*}JxT@UJ(oJg$?MHpAMnZJe zByB;#z@}R{sy^VRs)1!RNRWk{)W4ccU-bt0w;PU%qXybQTLU;+(h~bp+1#40M?*uS z(M{I3f1l(RmN69*P`6iB3$+sZ_DSMHkf0UWm=1SDb&atY$Ogj9N83)CF&s#XDVKnx z+I=@}BdgUlku55$f%%VO=DwV_J+xB11a05-rvs4C>?-=g7%C5OW^+k8%OVTwCySKX zQqOP(`PKHD@TC;1<-<@@5&-_~YEl;aa0Y^wgWPoLu}4K#Yi$gm{=<&FDVQ(u08fRf zsgX!5;D#lqC55Z5U5U+0wxwGz?GyU|EyjVpJDIr8N8ac6k8BPL%BST;K9*pbBg`ae zZ9K!Ds+4rhOh0uuj-$YC)rzHY(@odJlTXd3t;&|@oPws#Uiv&pIT3wwPx-r)X$*?} z@f`XzFPTO{7GeO@?RX+%6U@_Do7`YsKx+4&en(t-LL6(?9pTHMy6!GrMJ+FknV1aU znf0WWDKnBW*+4R_ha;tax<#V=;w;gzRi^JWO^baVE3P zQVV~d4bwU4q?0%fc}1Le`e_K8J@M#_r?Hy)L{sCwWI-gM4IU+C$J3LQ2`bA>e|P(x zSdy$C8W5kVD3naXp48OTED&LB%*ZrZJgw)&|g8)(Ei4w$yZbb6Q#L7CdUuRg&5IUOrju8PYq zI1_pX?hOCFx7`#!{N-KXR~K1h8!-YA4$RZww6$4wTiAiy4N4XA>G^3|C~y`drqyG? zbk)~HZ9{FMr#<_Z0|#cB2qz;Xdg`-HVqxO^%Y2=wFX0!KAkXOe&fhcNy#OqcocXF) zng!-uTz_ZMV#QDXuopQf9~sY;iVW8{Q19zig}}=S5dDVW55PC;1acHP`D+oCx{#W1 z>afX%w$W<9?NMVzjG)D!y;nWn=KoZ7))dh^9-J(T6=0rOG z!gkTt4amr~8ai=(c%DNOX?=TfW7+Py#q>e34vNeHiDhmwjS0A!Hm%=5U!S6A1Nl9H zuz>hP7lBO~g)Gz*Tr1nVaS`dVdHT}RMFIZP9h7L7WJbPWnpipj~?rX^AP* zi)&@oGNt4mf-&Z!`nHi&pqnJMNyplPbEG-RAccJr@a)rwF%x6?#>%+!iA9VA>5w>3 zgm5+J*q08*9o%Pq1!XmS%ecTTwSqu6+Z}m7y{!fyq)UKzEp6K?cwb$80Jt0QM;Oo* zIWc(d6()}1c%HYQKRyX(7-#B?%LbPt=o@*4ZD(reT~#4E3Oc$2GP&6d>YT>GlfsSE*$17zJWyXf%m*SPCn^)`UcUtc=f7ydd}Q< zo`#7QJGNU`2xB#7vGBP?@%-Xd1YjTbsQSbX?a-_O;!Df9fjydf3=I{*i)NAquD|gu zvG?Hqc>0MM%#Ar=22{f&OA5+xy5Okedg()9YBzy&qyZL3HcWT$(7|!&Pz}lsMX(6N z!Tl=ISXUi0#-|bc%crGBEd_=7WFIv%K5-4!1A4e%6bXfjU}3U6TdA4a@5{3jO@Q-& zjkn4eVkylr`^mZddn)}dc1UafRH)zi``;#IEjxC_Q%~NP;$|u3ock5V4|9l@?li~K zchvd9zIc*kV#Dq+<4Nfzj+oV`SHYBjEfc4h`d&F-1tGYg>)PW1#5rquno)v^O}B^6 zRT{LSoUBV$3vwO)m%3o{ogH?yP_;Ov0pna!I1dFESU(F(pYglXwipx);tg=&p3K00 z)BAcgA@H&SgdMUTEcs(C{kMKVOq5WpgTSh$wYr%u3Ip5=Fc2A~{_9L84lV<}(-KK( zt_JJ)-Z9nSOh=U{*z**mmts0WjC8;f&uFM?f#DU<*be63-I7f7G7j3QqBCb_M|F%I zJBq+J%nQa^3a&KKVYCbD1N}UP5da+sgW5nEuNhw>2KR|wFsVGAE7Mj`c=B5lt*oII zm=)-V3r3=`zQRJZl=0;HxW_mFe;Jt-fb_ZeoCggb#34nbwUP}61_KY~Pp~$NwA)rH zf%kIio}MT;D#%QVDTxL3xZlPM92VlRBM#Ra?7uCK%;HiNw&yTfC)nBgb zQpz-GpcU=j8W@Q_m-%9(#y59Y#~BS7i-a%YLnA9M7;ZMbFNU;UkCP5-N&2A9;uj zvc75m?bFmqT}Bam*U7rmIp%z(Wn`?rqHn(>KpMbDt@AqI)=p7tP7c|H^u%hw;?aNK zNTyf2G=Uia0cM%8m)INWzQH<;}ai*VGGC2 ziqDQ!K!S<|y1F1u)Mz1C&y_IbQkXaJgP}WrwguXyv82ft(5;=1JFrlS$-2tRD(4&^ zTx|99HDfMb3kmZm=m#2c?{tNFPd?922_>$H>s0zgVwFJmvWWg{YzG1jzJeD(fy5O+ zof}xAV|ZAY42q#~gSikc;zuUnF6QwMyw_5jQ4x>!LVfMTc4O^z; z=7Spv@f=YG04}A}$3mW?C836B6|9=fpo)r=y6RKCx!m4MG|4k<&-MvBcJ60xRH`z; zgSdrq(P&I>)sMb+-+rEtJ7(Mn4zJlAyEg5@y~Q{%wmdR+3`?XAqNg;s$?k6neJg-I}Z z2{@%sE7f=vkW64G*YR4Yn~@+3WUM*;AVMq{goR7AiXBpCo+KwANTpEEzR;y&49hgm zlTJD@);vECK{Plj(Toj-7E>uclxpf-z}0(`rRioeHyab$4@=!oIUvExS#BR(9;Y`P z;L{ZEk1fQnFg7wpg>aP|gcV!~rUEzTtwJwLAcI3@Y9%2<9Z31WA<>tjz*9~>gE&PM z@sLWIHs*1>>S}r&aibgqeE6q-{!D_af=Pu%M(mNOc4W=Q>QVb`V=r8zF|)oLpX;Gw z9x>a_vqy~>9c!>yxRV48`*#(`sV7dONc8|NSE1&9s6eq&)}CsLxKD=W#%bYnAt=s0 z=R8u)55&w_^VmDqmn_L3v+7V15G`179x2d?BuIsE-0pRCSgSHU<7nw8^H-b4=1y9) z43=NX+$!X8d`fzUY>gL2{B^Gz&P`iQ?P=oV?W(>Z@>2eT%=i8 zQ#Z!_f4nt@QkZ(-xo5MVQaHV>NdI2HYeu}`4Oc|p(t;RFY;M8gWpODdK7Q`=Ut|`< zZ@@z14_3J+Ws3c_Jx~{o*lZsnJzsj>dB6^(ZP)?r2;`7Vg?m};2ZB1#$J`#1sO?3>Em1B&pwz8p>hRiMJui(F2?^_BH3y* zy{}gt0+Rd7y`(x+9`ph<6jStMGBzsH2XBUl{zr*DL%AXbZ`n3ft@K{OBa*9m_>C|3 zTMa>B)CKmdRmo6Otp$%Wjn*p<9@#)tOU&a-5QZMHGtTC;W30t@lUcVOA% za~x|M^%wc1f{KU=&Xg&{d5%)wP|jG=td0Z*io3MnyPc{Bo+WCO^nR6TVdP+%z-{|C3V=gD8ilJZ9G}X zd%Mjl@NDWSp)1L6o3WI(@3IxN-R36~LmoY9MCy-Z%5j1T#HuSv4c7En_sXKXb_n?C zXIIk_1Iq$|HgFKaWb+z=ttH6W?)b#VKfpvgIrXtMzVn?Q0E2$KCq~0(o@a07+Zu%8 zufFj9c>DKnjVHePu{eJDVotullQszFp9Lv*KiW+`)Y*@ZD^&$Jg4}a;FfS+)s<~rVi z1t=h9=fUZK0eB3|W$fC7;@h7HIv2ozwXa%74X&+WMPopl&msa3lx|ox`htB6bw!R z%Fh!3ghpB;aDhn(KV67PtN^?uM7YM8$rE&KrrIN}^I76^`kP?I1A1StDg^#J0V2!9 z{3g{f>APlOvx%7bFPwD(A-L^stlBz4#a)B2q;Jzy~&y4b~?q!fD#- z)Y7GubbUT-2f2$-l{J6!AodQb0o{AgO>ZHSr?I9rh7Ik{ICfsm^vE)}C%!4i(s7pr zXZj85lb*9_^ET$}6m^!NEi$eQQ{iFtwXp@=B3<;;N^`^nZvX$WcNPGWRaf3W)m>Fx z?Jnc)t}rt&g1bYIkZcSH(alCT*<>RdcZWCxf;$WY1B|=7cF(lCYjt(i_xs>~NqJK&YHlq(mnC5F*Ih0go-c zxgBuQ3DFuk{HrS)cpn5(Qa=P^19$r^XU)SH-GSB2M=Xdi#dJj z(;r8gtw1`>jm{%&6%}ULx#uphhaZ0toaM9w~Hi^Bk0V95Z0-Kk14oR0I z?3efc-f3%Ce`}>Q$Ru;$b3MTPM1lc?wrm21EV|N48Lpl&t!V@BBmv0d7G^VOYv> zNv9B`%poFfLetBxz5%UuuYK}kAGTT|m45iM-*Ydf9eN;q@Zv8^rC$ndSBVx$z|x@Q z&*)+NUSBdWXmuJPX@ru&qM8cxEmv6>92N7B;KT>r1BZ1&YX}A=T$H5W2X1P2OquD# zJS0r$9TAsgBX%e41)m_#sxA2!BDAd>h;RJ(9!ur9W}@!`jMJZ4NT5cVZQs1XMva+Z zzx&gp)cvw$IjvZ$x;4BPH6yI&Y#vQ^iQ41Hr52UCig4A zBZR;zq0g0J(V#gLoh62%cSok*-Juj(gpBKM5O^9nUG5SSCg%ANYRRVoFUBrl_N11Mr&LyR?K$FE-Kspo`9P~(;EL>NXLgp0~ zjH@yXC3G3Q+$W}>y|#Dqt}fQ$k*TCdJ}{c2JTx;tD zKskoY!#JtYNf_7Q{8Ve|fsjEsCypL#m38$J7a?k5OgzG&g{EgE!$qqkQ&NQBgkZ44 zUV8Zz8#Z8o9U;uMm7U?z$Q18I8`yhbkIg=7mXidp_sk zJY-st=BCeB4LC2pkxl|EWEPd*#>ZUGnl+Qnz^cH9CVT(8Z?PZ$;&=AWTW+-b9(=^E zz3M7kzhMobyFqewaKMw_^Um9@w%`2jetZ9W-p58$zk|REvcQ)K@5K?%5ZoFPz;#Z{ zMtCM>pkRhA>(+9K@MErnn%2llR}0l3r{)>7VVvqWqlGcZ%%?4A>uPJ=%xDei1ukll z*kCY?b`YlYATSc%X-$eYh}%gJ(l5O~fClT#kNlQ7Pz%(n^$i?2fuMt)fuN=SNQiT$ za=y#D;lvnja|yDX)8QDWu7Ol8sh00TTlGPBt2vX_C>Tf!6fYLI=#670s*nLPL>r6$ z|F%NllnexhpfxVcfaq%im=z|&?Gu0$CF6*$NA2n`2#`d7po}a!CK<%iB&)EW=)ZfG zPa!8yI@6WDYeO2<)e1m(pyfCraqKD769TDxf)tfdhZ)Ff;LoB<)E1E>uLYV+;YBUr z=6a+(-lsh(RHj4-EC;jpn=Y%U#iT`a3)d8Z<@Q>@$*8Nf4^vjIlh{<{SDWf&3`r(@xW{VAztD4iXefP{ z%H&{Fo=F7+S+G$hUM;V-_E!80=~e;Jflfi(DZocgh(dv-P54Qil#jw?-;WuA52TAS zBqdrsw1I9&Ksit^D0x;lY#suw1Zqge+Z zAPi#2G$hkSJL3s3cS50LB=SP4$*TN}s7;j60Y4bkh~cBqz|z187&G(b_orGTgiKnT z^R-b-Gpk^Li@@>wlWo@AIkuF_paT}>?H~PNB8{B_34ifKEzV-*o#YF#1Dw6ke;<`5X|d6 zzy3XA@Yy~0{+cecs<;oG+%XQlMMN7h08mD41Db!~eAMpeLskTFC-8!c+i>c_E zqQ(@h7gU?H0opNF%F5?nzN@#w>1fZ~Prk>Gw+jNNWFRhn8;q0LN5o9hs#M56CR*~2 zCR+!4Lh(z;fW4Q=6vj%jkwoA$2kzu76A2;`&83-jk}qvVAY@JvM>T0>1E@AXv7(zYQgbXbhg}B=Ab{mKhMP~4VH1Ta@hU;!M7(<0 z3~LtVy`e6tY!Y)Xvs*7rL_5~G$Qw{c!3Tx;gV4V6?eO7a>?e}u7*Kku&vNn#offDf ze13u>N=lA7Q=OQ9aK}Ef{m0tg-Ft<8yqEridkO~@j)`cT0~6v z=Ol4(Q6|)0r2j-8ky7Aq3L4$yS!dfwBKfrMjhybvH`=;k6B~c6a|Hrbzf2wn?Ut!% zG*?Q8jl2}f9o-NL@&=RX#9txbo`Otd+SNMp5((9XBVD23>ac2z0H#1$zcL84V3-$@ zbUP7wP6LLDYi<-!AwPxi!sSvS^f;WYJ=(-d5@Mp%MogEsZ2=@)vo{JGoK+GzRZ5}`}J|y6X?L;*#xF_o|!N&9a5G)KnRW`sISjT=SHEf4_q_P?q zVs_)@@6ulPW7-osiH5s36T{83*h9H;aTPPDZ)x9tRC8x1Ty+b2yZ5j<%#_7pBq;-XnMxDllq!kt;VcaSr=c7J(CYvWU z)-|}TcN4fz?~#^q?06-_a{wkZsrLofOMhdV!zY4G)5K1SX=A8gin#LUNMmVR|yN^Z@Hd%t10K3@^&D zw!~~0WvdN@nAbMd(>`NjN)8?>HkpDX;cIRkL#L-nn3D!lCjZEhL-yrwejfq_F%ZK9 z-YP`d3lqQM(yOhqwvt7!inAd*XZ~4MMy5EeI2dSuj*&wO*)cNLybwOkODoY_XS44` z3-Dps&deoEv66i#N?{IT@s+f-bWxnL#iq0KVguRq(ggh2!^5Et#(=+vJs(sLt)}Fl zwL(l?-vO!%LuIa1{u`h=Jmo3IBxWKx6#}T2f@3QFDZ+wx&Rui0(nORXMqmT*NkkB# zQZVKJYny6q1hCk>b(3w}dx)u#zl3Lzf>{9$l@*Gs7rNSBXe`1dNyuT^QNL0s_aQ;W ztpxg}_h^GK6&dv4M-#zSZ8D8TRjpm9t@0zl6>Y%fa()zPPGp}(CUOjK{eHe6_}8YEqzrM8>EO^L2&*s5GxmdlUXdSHELA`W36d&603Z)@S=MYdt%78}6+=*5-C z7&halPkDoev5vbf9RahED6`bQG{@{m3@oHHe5U0ND58o$CjIDR3y2)dzB!pYc5Gkk zW3TJB_VxgUNk{g!*Y{p@?X6?U0crrE@#8H(;FJtRD^LioWI7QMR)SNT!*bw(BvA$c zg6PFaN#L_nSrww_q!bpp%Ub8M(9RJU2&6O%3B4*lr#8hZq0)GC+ z1bi$5trT-pLVCUpiZok72R??fDw5e+oXJ7<nDwsY-XOe@kR+yo;ysFo5kHB6L(hJ-Xjis_TrmaSf6%T}#&zJQm| z3h(&z=eYvYhJmMKWZ>|I5JOm>e`Pslzlbe;^%b-w%xh#ZOXyJTreunDCL$0h9ic}NSKC6s~sQ7CqDKu8#;8Lo6owsDsD;QeS~Ne3?Y+=@|L<8n*tw{ zc$UPNGqba-fHEWU5qvh~03^M7X zig+rP#04ifg_-|Y58_xFi;^Opmd!h5?qRx|$xt=rlIUk2jzXC~wXP&+0bB=nrx|0e zRIZS;kf`>=r&{Jd%}@%`dx%{vWdf6mpgf^02xeOyT0HnH6j7}%ZKkE^|f66{<%cJMHobJ(t4crMS2xuT7cYtzjf zTr_u*3mOZs>-tHPuXvJMgwg1q%fo!hqPRCW(J zOsj=S^*;b3)jLLz72k%69bl0XbOlV2WC_!qOZaLK$vccR<>LP#0y4>o znKd`GI$|MrRDFE|=Dkh`8jOZT=*$Ho{It!wHV@`CRYq3mWiO_br(axd1t}1%RJIAt zgu$|9s}J8z9}=caLz1RZKhSa@jC9mXR&^5EPAB_zgkjtY)6`xkK8Vxq{o8>pCMtOj zn7b53FTo^5d?fkj6&6`zO$}S6CQ-Vh*^N;qoU_>4HSviTZ8&>VbV5kFTAQfk+G5?n zFqQm{0v5Dj79d$qM7~)>kUr&R=RqK-EIfRiZQHTUW?&L4Bfy{qt!43&1-54GTKm|Y zAGI-~hJ%CMPV>v9azPS(88v($FyV2KO_5c>?iLpWp-rZ|)X9=#Ui0D(`Utw%z4!cr zsJRMz35NF6(=XZ~GT9Xb@x+m%T$lM$mi6d*kem}ipc0`|Mzt7xG?$3Twv23Bv}6f9 zG-9>Xk;=+s$2{P!P0mzaUfZtLvvZ=xxO?kXr_ssZG;ZPqh&0s~*vtLEo^3ApB7*bZ zZOw{SDF&jok_?k>!5`)81&5e}p%bULP1kaiGeweOE7JVYqh;VHIY*S#naGA}!m|z{ z>&o$`4aVOjlUn(4w!011yZy&&nyYQhfP7mpV~pc_hbkJZqP!xisexa-*}+m_>RJoh z;|1vQT?|RgP^K){8DrCV7b%AsHwhs@36ok65|E^YOXPz(*x`~=+t03w(&SW_Q`&eI zLSGBaQ16HYF*C!BQYaII0mOPRTW4TSZ13cS2(;ZW4wdg$2!9uNm4h(QOz=lK?S&Nq zC(RJ_R{n=d?1x)nA}X_wRUn0^jprV@|B02$@*>%J`A2Vg_j||Fadkd^yh#Y0l7Xl# zkqr4JBtZ$4q@qhA5yOxO?BpPjOpa&~A(;xaP{mYwvDrJTBMUSU!US!DSg9qxi17#y zc}PYE6(_{{#X=#^0ko2dDa^hDDup5wm1;s&(slvP<`B6a8QC5r>JG~*5`y(Qb506G zTh)5OEQlccDu5D=4RUmfQ;<1~os6zSY$Uzl1Qjx&Iu9I_Z&j7`&SVl{o7dz%@bvq2O4sV|s62NPT&IW`T}MA5<3oA%qCH{arNCLVhD5&P(!@3Qr4H;{>6 z#6H@swtn*-G{!bNf6>`?2uZyY_^66RyP&NSj+E>41`*-iQpWb^P0&hBPw>yHW8Pr_4KoM}xF$W0c z#rPa@C@d&*=8=6nt>i$x4J;gB+xHgRJKlLKzxUYCyi6B)mz~f7(+}GCdGqXr=a;bu zdmb>^YokXGXZzu51RtWos1)4=F8UEVB(O;{mx)j&F$rCjhYwk8sn0Sf0k3j84K-CZ zWXwcNnwTQl8a4%DUj<_M*R!mni%XMaHluGCUA>3$6 z>4}-P;<|qoX60qeE|NY;4R~wrttO2za3-OP0Kr zmzP)HzZbeUB_*X(ZR?)?*Z$Vu{}KZs$`#Ur6cK{hikWC}svL;;wcBM3xQn647OGFF ztI-|#SjgO?84%(_XJ1DkiOO8#oN!XnE7Dw)fQ6ZtJqKg~k))5>OXN}#4rUKT(S?|@ zU^-MwiJC(4U1Vkjtfs0KsTzhtC}tB$dm^^Z(FpUB1YN{NJ*qR6iW;v-tUd^F7>x!w z+(}MBv=MEOIe^@fcH-rgG?zgE$3~>+-0VU4JA&3kc&%UAzZ@bquHTGdFa)L>^NAQ% z6;*-z*f&Lss6!hdA+@WxWCDy)n>C4Hbiovwn~}i9z|;u+3&AbYvr}*c7GRT3usu5t zJ9A+!^^$sU+}5xcMX*DQQi$KpVgzoO%3MFBMF4le?ij8j$+Qcf?1LgOVst&VyRAKx zWA*Iz#?YPPG@S&;7hheCG>b&WB6N{wV1i6B+VE-G^l1=>F7^S(4h{jAG<_T&hx{O3 z`kYCIc01K#1B|nYf8C5VC6Z+0#*VisNW|Tg=4fNF|N4)QNAZHORudF(?*mU!?rE(QYfRrh3%$TucPv=?(WyD7m6j%m37nYY+SPE+5fGIPOGP7;`*fB7@ zK0E)yi}01qur8A1nj1Q!c6Ld?Fz$w$Blr`L&{Og-dkH_pv?;I&UWFi*uvun5Wc4-0 z6v8Z`A7rItK1-(HWFZ9yWpeaE?Y5AWzVWUPp>3e8(ofl`l-C31W8R4hOqy9a>)izL zy&OmIhKj@X&a1Ami_c#I92JJ%X}gJe5#JHRhQsKow6OmW4lJ)-bj4-18)lUTlVQ*< z=~w1kKc=oOwhjK>_9F;L5!=shpI@6co*H%#{~qn>(`_%kw%)G0aG`b3XBAPD`Arsq z9uhsYDOVCgfwXrmYH6=7+n;wNu@=}i2)JqSA~1pXdR`in!lXqP6tv<}F(3-^m8xk1 z(%c$U#1^$JnAcAG(szIC1Pn=03f4#^IxiJ%U+Y@Fr>ibFhfr$t3^=@xt%}pLh{(k3 znTPOoez`d+zF|pMLu4dGqG2KYaM`m?KAyjAj$K%8M?#=%s)Aw}1QI<(FUn z{N~MD=1iJ2aqsl$(|6o`_uW6QuC6Y+A0UQA-6xXfN8a;gXA>nDKIvfA+wVkSrR^goBT2J%~Dhk0yvLm`n_GQJ#E1s&8wk5M@ z3)cqfV1)>Qg@3qm*2=t30m-|%fFn#(_J19+eQR-**Hn}7F3*e>9Zv3pB`hvHE0~)+ z5QcUl)3i0N-mgB(1gHX){BR7Q2Zk9?5(>|EBDu*P{L2Sk!P(C^F*PM@-HVop834z> z;FC^Jfy@g5h=MY=mH4NHt%8TY{>_6db~GR6qnr1N-5w;9xwNbt(}>@G{m@e`3ahlX zh1XGHCMDa!ed+S$j%c}3`UEnl6n_HykV_h$JbnshwLUb9&5rms!cfLfo?t^prZ^MO ztFJ601AU`y6s*Cy1oqz0Mor;fd`Q^1s|XAzCzogF*wMTzVjI_Qz*n;p1|N;yn=|)p zw@FidRS6)$M?_?tv{8?W9oCdt&P(g92U~hcZySz!b^{zS*0OV`7|>ipsrwQ3$3OfD zL4o@r&H?H^B``+;He5pVfjJ2`(OJOLE~4t3{{gs%6fgpgC%}MQ-U2W@v~Lghw%Q;5 z_$y$l=>Z|w7)`k-y=cYlDw~4PQGC42Mc=8aLuA)s2s9dON}Gdk0UAp(lD?}J0FhML z9tj01p&!OK;qj%~uyNC@rQw+E-Lu_h%$sj>&sjv^Ns>MD)RUHjgSiy}C~UdtS+vg@ z2@;I*lU+wFLuxt4RO*X;XY(%00{_Gi`0M5{spK)n?6Eu0jC6pCum7j(PC$;HD0;nABI%2o#s=oW3ISly91jaL(TOA5VPHa%YQ+#F{|&-c8Gg zqZVQ_`=1B>4vR5lWMs77bI(0@N@KX@nroi=#y7t4xq}A}j=S>8E1#{atIHQ7U|;s8 z$&)AViM62bVie!~?sq>)<%ync+qTX8&2N7FzMuW%Y^p+qj1JHe#Lf!K*OE9V=5OOCKbnT#%C>OczU0$Eknvz<~Aevn<72Pmb7Aa6eK2#TZyXyiPRU_uG;IHtQjO6NRC1c8}w9S((z)p>O^uD zrfGww5K^WPR<>>7Pg@hA!OgsjAH0cn#psZjfPt>-=%EiXulaz3ha!cIl*EuDvkRi7 zdKAIAv$L4M0RsL?o@y6XX5rzq3rsQ@sr7t-_F8<_ZX`ALiy~cf2+?cNi^1kYKQqG_==BqL+ISDE95&X6K(b&k{yu zI_K*+5(-~_b+aAV+rXSB+sx_Hfq6H=N0bmqfarpmBrE6vDYUVv!OmT{$X2|(+(u2D z1m5sYnKKx>O6sVdlbEU|ONpux`Xe0lZ`x)fKKD~McXt1aR*1Iqx%1hJ8xu=f8Zd?! zYZ3S{m81ZN=-%+)5l#E3K8pa34*_hD_R6Viae*^FN} zjsHmfk?@2wIIQSEaPo8i`EP7Q)Vgj7 zXy8Z!q318?B8ZUE~cntghy422&84XPgxgwu^x1TpR%iY@jEp))LH}YNhD}P+DZoN0_hN~2a85; ziyhcsVnZfRw*iH@jdSNO9t^%?+aKd4?lMG)mJ|)4MD%l%F2f5v;QH6 z68nADS!ZpGec!)-|Ag50^Ugc(Reg`$d*_{Z-V?hP``o#6=QMq1{TQ+FHc4UA7*4g0urUh-z`B*ff!&?Z_);8Wz9w2#K>5@;Dk3}GnIo&3xuj2ma$ zcOS4U`ly_d0Gf^R3FNmpdT76$JAW?EDx;fHBjd;8Sbh~4YwjS{y!N6c=OP`4>|vbE z%6X~9DXfUDS#!>!>Tw}jVwY7^SJ|%pWoR8}6g-qmNbkCJ+labpK_X7HqjhU>!ZU|J zhGOe1=!5pocfP}!AVi^ix?9m6pQOGPS@a`^vPJKHd;0OGF_rjj|CY^Y4o&vXTW_%8 z>~~QEkxk(|C_{wXV2HWoNs{D8?_%Lsl|Zu1EOB+5n}{X1NCQ@_;v^ zr%bS}#!Ae+;Fy>&c$5VGsdDemy@y>u$5+1eO|IjQ!z?5XWy`wt_Toz~L7F*3bHrm&BH{1dzl(_})b9X_zrZDciMI2ss2Q7ud%Lc!1BL-Xz6fn(%F z5ClT|(wuXN%JM;En_7D85N6cl!;6?t27={4Yq6Vc1~iXZ>8aMj+8Qy?=aNYW4;g9a zFPu+R=9P8;_@6arhFi~)uq5CO9R#ekcMpOKAaJHxtu^I|oilH?t=q5zC`9b=p*_}A zSM5rkNW+^lWs<`qSty=(>@j=zPxmu!2^{PW3e1D_O|+sQugP-HnS_>~X6-O>6<^FG zs6*g%;4hYsFQNmJ2hW8bNxGAEL-`0IIFgXMgqR(e3uIm>CaH*5LFMk_f;J?ZF#HmvhY>LrnZ&dMTP`M$4vHcc!H0B+79R4$QNPxax%|iO>`f*4x_Ng!I{pX$Z$Fa7tpK&!0C939#MDaXPo+ zfM*0Yo=75B5(KGg*S>_}aXumOAmwtjlN9JCC{qP0vmIPokb-?MwKPhQD1X5D zbC@$#;Z0>@r9c+i9SMMn4r*#FcAHQ&Vn(dNVcSY{nsz%Ji3V0vS>^Df0ZDc2_z~6= zU~Xah$}BG-BVS>dihP?oYX;-5WcR=lBxcHlke|>71IsHavYesAEa`ZOO&B#9$9%En z4jgM`hj-YN88cxL5W8c=2oEZm0;2{tdHEx7C{t#?soZJMy+8PzrN6j}en6a%jxC4@ zly_$34}c+v6e93Igtu+pYM22WEL7&-hnHEwA)t{H9Hc!+!x8=ncA8UX!U9?KZdD{6 zk7jpdUyt2#{gr5@Dxu!T249u-lV3e(ixw@gZR^+ARhM3b$+f{AB05bBT=_EEl`_Pf zwh*E{X2Lkzvu&GQdD(?%%w6`}3olq66$Czb$9ve{WTQRz+$%O>+!Sk}7T8uI)be23 zg_MLDfZu5Iru8;%(oCzOny`F_GE5H1O1J$86$$u%lwZ*Uvk+oP2yqF&2!MkNvTgp9 ziGD*FF{$3@q4;c!V{9LZQ+`o7pEt z5nn0Hi4rp>PoHC3H?6R#Q|H)$-P>&6o*fQX6-KO0yhe{4PkEwJ=i@3NFG#S=z#pYb z6F!8@dIY9Cm=)c`2TGI{!7yEz9tRV#CT623unFVGqU|OT1&B7pjXvl=PoK0B=nnK@ zC`CAX$R{c(F2m1OAR@rp@gqDI@V5BzRw2M@I`tt{HPj|U0TQ-+9hezcp9pXQT82v^VgZXG>9_Jpe2Pwi5j81i0REjZ^k*$}o-!yy%sSQ?$ixozt@&i2}8-+KvBRh_n{ zCTNQmoNccxf6dlx*p6QU$0D%FB=k9m`7ncp4R?|gTZx`F%cH&FOWG+IscEu`d#b*-1WQn&4$0)uRJ;mV0j2mMYU$n^9 zVWyBt=d6Vn*!>SbY~3l`&!6qvcR?fxMHO*_QFWkw33v3)LuhDo<}IdT?*OYM@+-{T zlgpLUlCtEQZSrd3E zja1Q7!>O0Hg=)qX1Qp~!IGZRg2{*UtGv|?gUFE7J@7lG;<}F%erTG0)2{bu)q|y$P z|C57>Y0}uCPD`t$%{A*bBLso{jAh!CaW(=b-N`&|JAk%|w9!UXAe_O4_-@#=j`d0v z2*%+7P7AEq zigJQ@2Mi%O9bX?c!DMMj!R%e%SZCR2Cp9o;>9yUg@s2jCJfKx22Ke35N*J);7EGDu zEC~l;PCfXSI$5Lf{r>Rojrb?qaBRgHNdw48MeReLn= z+P#x8i*$<65dXv2Mf7{xf>v^bdP*!n5ggUkick_o8|=uOR)rajt}>23ObB&6t6`v| zgX1!Z2&M`nmg!4}%t*BCr0zZzzN?qy7z?mvz7*OU1_<7SMi=_q*xKwQ$b$SlO2X9h zZs5Q@?JPt|eKJ$NyzC{OL-Kvj~|ntfGHOWjfajLn=e-}PV7Uku&h_W~&7@vtaBkWUALtzJG9G9t;%r1Yb_VTml5_JKz2RucI~^ z1S}QpP}|@t+D*GK<`DHXv%HqJlWYy$N&ZMC2l^!d%1K?XSNtvDPc+@j|-(_F;!dGCj zKAS#alx^6)4WUT_p2r?~>=`G>NRxK^cYs5xe5|^44?p~b>%X+TobiP1Yyb64zRAxC-XIiqVD=3%XA$PLsI}K-OdY};;O9eFOhco}9XN#b zKzKV0As-Ex5+w+C9vkNyXqgwkhXoJLfXqj~{xJ(+RY+7N07}dhvc*C>w4(`;S3>Z))2RW6${qk#k^PAuNtfI5z9KZJ3Yo9DBDH$Oj$LiIq z&qa{&TzB1d04?exS+#1_!rN}U?Sc08_B2I=#X@}Fs9pIzeBu+I`2NI+6ZaiBaA15+PEMoR+qiM#Sxrq%+3L&GsZ)39IifrR>1pZh2nmWz zOQ@--DOBIokCOrClng`*OyRadP;rtph*?(;8Uh9Q6yBMUQRNSu%x>XHJD%!v=em_ z^U|aYHUetJmqE`WAT(`<34=tmcGw^y(ayWIw}qUm5fDvG%9T!02lOsJLdp0~U=S*b z7ldiZ94DM|{u(ih6c__-1VO^6;7MDwqrF0;4QOj!hl3C_<(CB9(hQNcor5U{vjGyU zm&mR#4rxr%dab2rq{1*D{%C4S_!2YGhDRX^BdU{$0TvY6QW(1#Z*z|7blR4>E{3cq zIE9g_OtnI5Mf_EkUiRk@glW{M@pinb#lH31m*_KNLrYtUbUTcFM^sv)sR3UM#Gh%S z?}?VJ5+T4!j`L3Xr3`6Smic=T1R&lD^;KUJc!%JV1=A4Wlu1#0p{GD(6?UzSnN&Zm zM?wPTg2cXdQ*_mb@yo1Sfgc5kYmQ~N?jWja^{dOBU?Elus5vxu`lB<yKksyW&o+{Hhh&0&^?ldt4yr1%=1;{C z6Fu~wxmB)3G@3^YIciQ-EiuPbA-<~dB&WXX6CWBw%pWAXib~3-dehxK3iMd|!gG#6 z$uYfV#VYqcCNsJ=fS+rMpN~FR!a4eg0Oj&VA_sZ9FhJr6ffuzCk-EH6o&e8R# zhNK~Kr!+kUaL62}=XY;di@zXZ7cN9~(ks!)TQ_sbs>|RstT1hQdVJ+%BYveQnmad7ov9dFWtl z172K9c=K3GL;F{WA1`LFRMv*_MFh?)LbQ_tC6?aQ?2GI?@}97w8Q$vQ_XQKKzv}m= zdR+M$Vj{dhxNqOSiKV5bLq(+Zj0pa(fBozCf9zu)`;qS3ym|8+MP4bI>f7J`_NS>D z;Qitkzxb8k{qA?~5%G^br)PD)2>p+L{Ns-*?DxhSZ+ukO6}2VeuPCq>(};cQIUOrj ztXN!8Q88%CmMyat)%Cyw58Nh4{q@&h|M*Qe-SkLWT3WmM5xx73{|6OMenb~C*udWe zt#FW75f9zkA4H}WF1QM`T+*5s0x7Ovi!(?Fr%DWXKvG3ec_0P~>r}amWTYn%2MOtN zjw}3EldAT#;ZGf5wJ*H94V&>oJHjSL&p*A?+93>sh77Yg=bjVYLRMxS{0EH{6@>I+ zMoLZxIikLSY(iB#VJ00!W=MM}FF9f(Mvua|+GMHhtS5<4wtrOtZ6Svsn=MEyaeU`- zuS^%2*_rI4UQEJT4i0HHGb+Hpf|I%qCwCeVN04~hAi4#Afik`k8C_^@b4RNq!gzXF z3<=iQ2J<0Y*6#`6a3|&*?X0z_k??1(L!ei!T4Coco`;l75k`{KLTFv`Ysg%rnD<_3 zTENBw@{3stcG|Yr2d*DJc!cQ)+0>b{3B66`nqu31WE%VJ{zsm2i(9&(=11C}!kwFu z;L|YAbW%|k&cX6#zWC#8;(S+Jzch<>icY2ze(O9pOsZsjF=*uhb&@lahrmn6N1WgkxQ<)BFNroW%__R68`!y)Mbt%%X)1xXl+3C^RCgj}&c;3ctL+q)7`?ha|MPL!8KFV?9c@t+iD5pyvSchH8+mL%+GJZ6462s1u*^pKki z583V7@o?|(pAtCuJ-<+OCLhPwzj zDZpPNElazL?%cJD;E{U#Uoa;$y3UR!7*z+t3H!_tik}!64~(%=5LlB0ZuTNjs<5To zNs{@@QdoLlx_K`eY^7(<0VfcUXg7g(LJsH%mAozh07?D)GekU;=g0Zj_J}2^l#6eJ(CX|Iy6>^ zg1`91FFvTSU-dxR$jFf+i=~lByTDA}`<1VJ<%{~K>(XfYx4V7&_8E%0Qv1h_9UCr& zB4(w$lf8TQPExzNU)S}#jww^7>{h67OtVp#@iWgnbJcUtJ$D6Bw8>dnSF$N#bUR zHO?}mS09_%I0#9S7M5{Hx^quLgd|nBv)_bFUb{$)TEBfO)ikm9bC0&GttT`3=|`V} zP(s8YmP%IAwxSWDER^`=9J+^OHqIC&L!o`N)^JOY(N z(Ebi>DiHzUQFIv%VXjHTIXBKWt=k0BVLC&F$cDKzD?=RQRhVrbrXtyb#7>npE2pQE z8l8A1sBv&z(j?T=Ey6_1Vk)5LXF)vt#B(qW76kov$ycHdJSDSW^pK}U47Se-G2Jvb z);qf`-Nbj1VFw<4HY&Yy0wb1V>;d4cXeT)+RZgZC&C!b;EGQx^c|!ApIF3$aeVDLh z5(89juEHckCIkN-`YeLwQ@s~JnuHyC^0;BPXXhR#v8#BbivRUMZ2Z746|F?(ux#x4 zA_Uqi#cky(D$5~#PovT=O}!*;2Nw}le#<1}v=A<8`(Bl|aGIk`k<7DbG-$xw6Kp{% z4p$VC&7r+LUG=hcyLa3Vg`CCv7h%zZ)Zg2RWiGGnO>MpzdQJ8mBZY4Np8YN>G^t!I=K&9%&8o z(`owxIkDv|?g0+!hwxcK12=FNZ+3zh+O6;c9QyCwJ9($-OleoYi0}*82+9)wVK->N z2tztaztS@N{7YvHgue2eOunwqNth%f_`z5oK-uA=!kG11w_74Or5qydqoCPS`+|le z8uWiY(R!sN#kT+GalpuPyiXfjWvZ$G0RyX7Z6tcI5x?Ign=pAiV^G7GXpS95*rVJC zo|PfPhS_!3U1?80@fi4>PqY_4H~LUULDG>UN4fGQ4ebbZ1k`j93f)L>MIIVU8p777 z%)!nNN1&v`jTRZ)h-z5lgXKXm?$j#Dy_-Fx=j1+h(WTi3Gi zRD@7y6oe>AVw7`KL{A8(av1upL&z>PmUJnThBB;WzJYv#d`QJivKF(WTKc5j0E;V$ zi4Bky+X(T~wwqu7{5$Q{XV+RbWwkGwmuH{&+o<5DT=&=8WvI&wOXS zedCMQ5nJADjUd~&;XeDxFP^s+%qw5KeVlD9C7Tt(HX*gdzV?URrgGt*zInPe1SZ<> zynt<5_M|!)=zw(k@feQ1F8lY}CR<&?7?cyL z?{@FCuRnMMrqy8|yC6BfdgDEKZ$TE9oXS-c@=@c8A13}H6XoK?n_Py`^-l`}~ zan)o>V9dM;jSi{5YJ>ggp=~yMQlXtaezXPC3#f^dWM#Wn*&kl5b0M*-^B|e>M;fUJ5ByjNAf%>EaD?w7nF*52 z`6fJ(Ls}T*$P~ZnD)=Hi5o@G>FkY2*NrFH@3m6Lxais@_q2~2}B#a;_l%ydguF5YY z2B|H7wf(8gfO>{S>LRqHEqE~7DSAsd3hzL(;GEz9Ly|`1G&mTO7@mh~$~O|lQbhoL zRoFPx-bvXGR=h#M8Y1{&AR0Sh0k%SQ)`Lc){^=R+2~ts7%fP{i>)KyO4Re=kGX$RN zz0M>IJOnSbEhfa2>Mr-k0Rbim5FC7z;M(i%;}me_G|kdi2t99gbFcamoN&xY{Dxbi zIKle`hc?>KJfuh%iCVney9ECypL!0sA`H@|a;!2^GYJA9QL{B-B@aL6-lzX|p}p+h ziQ}HWhz7t)1!Q30v!DLt7cLM&eNg{IJCZSx&zm#THtyJOn|2+-hn0zWm*_}@#P`4J zM#>LOwFp}m@87)Lrp=lrP|zmf=;@jxW`I&9i2z(M4H8wRohR#XvZo@bC1(-&7|5_3 zBC+=G*=>s!E`VICh4}GSAaF_sGJoE@uP&HB|Eq7J;s0+UWL9_`<)h7L#c5^e(A}?p z7uUsMl=HzmKUAEal#;HD>t(MVv@73nhwUf3x2$cT-TE$eXS?rF8*|aeYz&CfM1eS! z=I#rxxA%SIKKtW?za!JP0|_?41`I!9)$G5$t$mWsUO0vw3)6@vUu@}5f7KcqTC8x! zzgRYYoK`{v7v216dw%zS+S+Z!_QAV9Z*|l|>P1RD|B7yVdF3{H(L{ys;r%k{h&YHq zN=c*2n3Hf7#DH=bU3h%gMOAC17&1q3#%V6OC2$3-wub8^Z` z=oBfFHlWG?Zr^R*qyEZvFY@j73!yVg9F>m>K^pKk#l4gN z#R{bAI0i^(6!IV|m4+gsuB{Kkm^@WSLQ#*pqC6-j!x3KBJWNNYl;D+VX(tXwx(SY)C`oO=B z+;+R|scmy_oI0935F!Ng$qh+UkyOmw0m|BhaL~_~HN}Q7M+!L}PF~+fi3Ra*+AK2mff#Q9CC@2#ca^JS+kY`h9nQ z80Ld%jh;ygRm4&<2=?v|>O6W9L?(#yRkrX-vWvIx-RTIG%0VkXK+!&TeB>jJ_^3=o zIs{x>oc`hdKe{~_M6{$b_h6Efx$XA%-Ql8^!h{7YsZxn=3PSk!CqKu#63HcD|B32G z;@{b_x2BdX(V@qBbKp&cd-ut=#{Hik-$@wX1QISZyDT96ZYu|DvAFTsrx8wM7 z#6ZkjA+AnKaD=1Hr`xp~9PVp6<{O2#lDAD4YBO3h(U1N$tdT z5gD!vTbT-owaBhC1fJ!*_V)1 zBoC$x%tC~pOY@R{KxQRrJHlDLR_5LmUZ%1-&{ysSN4Za7^H5w1u#NDgmtBn0xr`i( z9kc`2fWav^Lkv>dgESsX0RDuVkD5LM?LEsfG0Ps@yW5VlCk;kZ_iiyU@ij3(aad>3 z;XR3%nR1A%tH*DV$T+o5T8YflE`+&M9hLyM5k%$d>wcx~3X%+)E#^*g9Ny zeks~jNOepj6=Bgo<&|l>2)(nA(Cb@oxWwk2JI_@$ZYKz(k?oDCcgPT!Yy2PixdWWJ z+?Peb2a#?m%%=nf9}Gg-`@t06BlyE;Qc|;Q`n>t%kq|VZ{18B=>eh=dxx{JVW$gPt zcI0q+DWJxWw*rAvGLW~@;Q!_sY_tjv@d)|B02kMtnJgmtAB9Nb?8Dv@RMj%wBr_S+T|8|Dp#g~$RsVKmwh*&ofD>6^0Y>RC0$*AFO5wS2TE9%{X_G8=Wg;2KB zXDtI)Zys(TBCZIl5DZq8O7(mK?ZPh!Fo40}!*MGFLWG6TEg~rtaxu#sBgvGd>ZDJZ za`xi99Ed6J@jpJuUgT4`g1>|D1(Et4!vW?Y#J>Q{@A@0Bw`xL`Ys!w>psCYr>9G=+ zEL8{4LX-<6t)d(IMgmN+53Onax>cAw0yc5dM5|DeUvahS{6V2Gok1A8@Qo=*z%R*{ zIclk`V2j)d8m;T4datoakPva;i_4ktp%p67CZv2J;0T#=w~7>rc*|reCZ#!tL^AEIL%3nO4?Nb-__XhQ*9WN3Ryxgn}az{J1-Zg*pm$!YYMVODaqlt`OFUO zBU+`dYlMtbW%}KwQ)pNca8&L@Np@FUbrlJl#SRyxUCG}eM(L-&4p+$hzV012+RGGI zOi$>shKM59fG^-yfQ(Ah)DjGm0{(5;xPiK3nKpIWT*9mK@nt+h)Fs3oCf#Xws@_)`jCdK;)(uzeofVe04>+s!*_l za!)xL=-cW*=jH!2$7#ht*mVvcyw8(Gj>We(uamF|GDxl0qR<}>Eo%3jB)%Q1UG-T> z-IC5!zC*G^6n&zfvJ*o$%zt>7v$ZOEM^fJ%S~#!YtNYcq{z-oE@7j!+L~^2@ef|Bk zqaMWWjkfOA2a7?A3TYoi*H*id{N17U`6sDcKPYR0LjMFiF!tu~^`@4px?dU2z=D!@LzHtY@-kj$br(ib;v z#LJJDug-mt>OEJ8svcq^=(}$_cao}bjg>5SDF_fo(`b|Rt48w*eK5jr4tGx1=X;QF1 zWxIjxp$u_rqmSe)1wBws)u9r-R%y1h(o{)EC#ItHC)9z;f^8RvP#RjQ!R1 zhiC6QOwLL%8Y&Dw;xg&8rXm~|-`8-zSujhY?Lg<1M* zP1eD0(>sz4`(~b{h_N!bMtr_+k^9TFgZ5kH<<>(!H>tb9-uOw8KCn5yga$uefe5JX z+!Xe%9^=K?P8TsuR)ZzbzxIxamUo{&&zb?M9)t88XzB9jV~CaxjH;oNytsn9ML5u) zG+?#jA`66Jz^r2g#E4f3MSrOPz>%+Wt+Km9{3s$(5Qm zj_(Z+6Y{#}RRc=g?6^T-;M zI}PV@k;d33zm^#GLJiPXcvLzrIpF|a6{f*0to%lrY|cvaq){M>C}_lwrW90d4%-}2d5ZOKK`E9hR&~D`raYQ-B zLB@un7#2$Jb6#7YBwBqWbNdH+b~D0o@zoCZt}pq&)1Jv@yhvY1DMX7qkPZYAjx^FF zj*q|Cy%uFPIsKEBt!r3SIEA}j%16t+N3iV=meF)Q_5X+7%bVV@T)%gd`|G~$-{^?y z1r-~^>X}_kd&KzH^)h;aYZsY(ySHtvb%T?CLoxAY_aBPNWaY7Rq+i7<(tf*F2A^0Y zoXke1AFa55yZG)%@9?h~?PVI0{XZj`@RJ>tOGqu1D$3H_KVDdMs5_}{Bbl92T$QQn zp^Oy@YKhf{9>GB0RmqN~h?x)x`dj>HcoY?ZO+>TnVJ#C+cWBzRGy8!L1+@4*A8TV%MRD~8VR}I+l^iJXu2R~H?B}1;hRZe@?O4IP91}> zZ6ohDT}Il|{y`rvhc*5EWZ9>D)$g(IqQw@x&d0U#0KCNd{Iu|+YZG1-wJ3_>*H0hS z^jEX+Yx4uGsd781F3#w7sGVOr|6JVA}qVhjMZ_ZcTd}< zCCLO|It7TUV%`>v0Q3sv43LBqN>NVENZGgqZN7fbKw9wEYHn;+(0<#A1Zq2Nhqz-n zt-jzM9SFUe7URH(tX#U^!DA(ce~pLm(~T70iqiyx=qx^@TWR3-#~x7!@JFIA*CMLR zuQ!_$BGK*On!}fQp}FZMk57>AaS+ z)6U^07=(MQXxutnT;>$6F}JL3XQmw=lw^%Bn|m^08I!qag~R)4ZCODB%xJR;|+Pd6qOUn)_qQFjUcol^S*B zDpQK()m1cQ*$xy$wP5^5<2M571ReCm?Ye{PMqh9D79U(|dX!3()*hL|l_)xKGfg&m z3StnLZeO3KJ2Zwsv|%U_RD&XtySh;AiDRJ{8iU6IR!34W|4!n0tMZu+t>#FrxO?v_ zeYnnne8dEAtT;pBWVkWqnO7i#A86Fuj%q*kD6uH6IfzA6;?U{4N5t}|&@G-F&YtDc z@HFLGkv^0|ca z!ikcGUFaEtk+!#Hz-F24dmHv(T=Y?oyz&>ynnMQf(&r@)1;UV#>RrkcAShdaD~hhb z`4dxbSe$s(yfGe-BqB`gw9%Ci9guPA;hYsW_w|8;CG3dH_gsD~&e;3Dr7#I&q+!|F z0weFwI#-47zO4Z8kgg&Se1x0th#r%2Abqi2< z7<(C0qIruPf+{2xFJl}1h-Zzo1_kve=VYw8p8{^7W^4qMD+`T$c4e7LK4lCq&U4&{ zP)H|c9aqQpIK}@*tBu-;z0`VCT$Si?R*3!-{cXOOAwJ$#QRB z^t;X{6<+gRuW}t(`m;(diB+?yl|me%y=@k}gqr6zgQNA$By+J+s*b!1>WG`SajgP} z&{@)-ZS~V~tCnGpy;5NI&U|&}%5}u?Ovloxr`7WY{Kf{48&MzZKr zh&T|gzjR?igh+Qa(~ct8X?3DQF*2~zI6;P@NMLm^IcUbJ;q734yv89nb4%gwRP zXsMeVy$@#l*MEy_Kbf62&_uHMoN17G=Ha6VOoxmqOv6x{&boP{0Yn;4A#N;+u!xTR zVh5<`;w+xMc!aC~1n?z zee$b=9~O@4`#k(UMrDwvc+rS$+7C46+-J2?Dw|NRFZd)`{?hb8{5sPDEG>%$I@|Jk z>*y6dbIzapmFA)rW)Y1OQx+A9ni>QpQe^Jd>YYFJq9h0sn4|sUOA_0KGR#Nyt3g;o z5jCMM13!#+GOt3u}yt5cOWW)M$rlZ-6t|&;xVCEzORh5D- zFX2q>D~_zgrJer0QK6oqG{lQ7@-wNlUslQEpeNI%_RFJ?e>WsP370$?9UlWok$J(? z6fSVb*SI@oCRZ`^ufZ;QP-<&3)hsou1dSU$FOk{TPg1p!O;qM(CzBybuyYqUCQx|URv=D!CT&(gko2I>$?_Y!yH4<#uR%FB9iX9oT zEQCm-nWKM)9IprHuQK+&(OZjyAI;qIW)n&xitD$6srQY(GIL!m}l!Mt~pG2003`TigPN-7MBgfUY8xsNrg2|F7s%yfpiS99o7 z9^7)C+obJ{*`GCY{^Y$=BKvU=ru**DDq6to&w#yyy=31<%8S)? zbuHd(t5|6)&L2*6mQ&dPwwgnjl8H(g0WPNzA3{bVOiXgdFFNvN?QC9zI#KlL{Rt1Z z9$&Tbj%I1S_T|%ZapZaL_{TnSO3U*j?4)|or5lYm1o+~}w3$j5;rttG*p`D{*!UUD zn4Et9Soxb?m^zy4J)((;2sguFvsMl4ntf_)8Xek+8;R(X(mG-m@8iZ1Ixx;(N zuoVifVYWVTf9rR{mcPFUw^{Ke$upWn`;`mU#$WHs#Ibn*&EeSYojSDCGkMj`l#2$WTrLK|*?Uz*6U zVJ@3ba!i>wO|jR=HkXDQ;=s+4T5LmpLR|V(P5h`-Iq@yD@s3#Gv~{U%$s);JPnxn@I{9 zw0RTI_6&YT+GOT-3RCn&Gkx_R^x7EbetDjAf151Nc^L!0_$C-ufk}Br2Drcap4hoN zKSv)mC!t)$EnOXKD*L=1y3-l`>vw)-et^(BKq@u}o^zsKWBGQ3Ha^2Deu2N%M8E(t zp$4!6pn-Ct_rR;F<|PXurfG+|XLhu#bFd!rZvSrdM3#rr%flur^bh#!<{;M>g&%-^ za`donA#B(kbKZJCbzU~^?d?@9*IPQ|nZ54S)zy)gYgX!dtlBjTOl@pr7xlW>4$kIH z3%xz=E}noO@G9qn*N06YAK`t&gHZ8Js=nJYl3tT-`l})M&M*hujUaegzP7d&3IzkN zuA!y%sdif3V|Osxl9Q9uyqpvQ?$T|s7|(DPeC$Dc+j+0vOsqEm!EcD=TGfK7qCVLt zRc+^pe`9F}pL3lhBqZirrCvvdhppxtA!TL?K8JZ>_C=?iT4(Lkpv}K6+BwBaIi04* zbER#tneFZEUOkP?&5Okk<@)QzeiJ!D!1cwhw>uzsDopT}y+_MA*W1Ox($ey0XZfa` zo!t>JF>$Gq;L~2C``VA8j#^M_TN?}k3__;vTZ?bU?tZ3&-{C_S__YfbI^cY}FO2lP zko6bj+GKB_?Y#9Q_4`dIp}hwKJA1vv!(c2A>;~X{H%cl$(el#n&<8S7aJU>!&Fl`v zqG8nvf==tXZC4tstGdbH=y}UccB^9$suN_4 zKW_&v)#qw@5MhVF!NE0B{G<)ky7&YInkyE(%OV9o4v}_Tbb>aLlauFPZgRjc=aYW- z^_z1C5tIFXr2HO^zd9q+1RuA8n%^LW0j-5~bxvCaGKu$s&xiTkgXe^hC!XG!SKK25 z`X{m;=_yD+v=BrJzj1Hys{<{}G@n+5cI}_vzfI!OQqt->H@!|O(d;+cT_;YL*_#j7 zTa{SsAXG|6$H%g`&QnAYEl5@WF*JZK`_Q^f|0dD5EfbZUwn0jKX$Jr);@IG%jsKR5n7&F!{udHN5zrpRB1NAc)c>YVi$?@2UII(X%Dw2W)<-FY% zJJiwC>;5DKGyHdKQqui`ehh{ehD%yoA1ODjqx>YR-}JDMm6a_fiMOCAqJVCIY$|KP zoN6t3k;Q&(ab)UJR3e@l)tTEUeDMs=~%y8RsqV;o74J9gBIhy z(E7W#cQT4)NC9Kg&dyFe#nQ1DgheVPt!LnqVf(52m{`BsWaNm97j9zQUdMaIO_~m6j-o){GDwI7a9JQV&mo@r-KRJ zeVrD*x>knr3j;$1Ju@?DMGNLP$U0fxvMziMNC$jw_2j?VNyD_g1Lh;v-A|Wlw*yeqaR7^Fc-GO>6^XO z1)3N9BkRd}~6jp>zdpvqq#s8^#H8HXYVMUaj$NB$fC{g%* z=>LaLZABTAo$Bo%hKN>mk;KyO+dCCK>Edlibv1K*{zd-< zq>ON~M89j3bk4zd@#c90d+N|6 zCP3KT*w}b{t0!obkdV;%{%n=|3Q}~OABIY-n-L#By#ldeP4A`x{9Fxw4*F#1bCm#k z^VmF7;=k{|o8-S4)98Bn$9w@Pdo0hMhCN=!XScAO93QuP9F`KiPJA~k5r|kcr&@&G z_owL$@P#1z&Zqq_lM8w#CXyDv*JsZQuf?|W*}DrM7?gv@VkE4=L!`*_uDB21lD}v% z9RpvF%d7o#4|a#r;h+$|uo8v)UNGYwwn@$z8a>%a;@QYO+=EH5+!SrO@AV$!v}Y_| z!o{{+0=n`0gsF~%F1ulx$1}MdI&e2GxBFs~laiv)Vd6u{{7JsLSlODJ|LX=_bb;L% zoBpH7d1uV|J33k}*eL{=KiqT3yfnD_$>G zL)8v;cH_e%Bi3^}zGsb#Dg7Ii`&6N-nwnhV8RHPXMcMPVi%$0eK=irL)iZVKw`&ts zRn^Jsf1}Kg|G5wUF>z^u_}os@{6-m@U#y4Y$RQNoZ2cgN5dZL}_X_Y3_Key00`A7( z__Xe;JT%`!%N)?!K_>>5c9X-VpjcpVHg3!*gwtas5DsY}8!*ZJ-F>!5!8rt}dD9Q{ z>SaHbD}wXA8N$YQ_ima<^{G;F_W$`1H~mi<5=QdKXCT$!^y!`lGkV`_6-&vTI(y z7k=07fQ$M`LGOPrPdAGZcsAP+5o6f`-f|im^B=6ykB*M)bo;s29Q#ajUiN6aKxYuI zXx0!S8*qMWYimhEgUcZ#5qY%+bo%Cf)~NKh+V#5nAb1s_zNIn z8}wkM$^5o9zT9l<^I*MKxEN;NBRRtb&TSnDiGf_4FPaRvipOi9P4Jr`sgR#f8f@r8 z`+-1LqUS9d@UgGWv}g`%b)NlQ{=myZV+qrt>=Q`mzRIh z5jRL!oz9n%l3||~)o*hixPCXSq#HHHeakQis1-hMPY2AYdqNQ9Z#OwM_Ac+DI$W;2eMw(2QkOmAvf5&}O>g0)TsVg>G(P@b#q8v!{GqyA+s zcBw(`g!k%M$?rNb)=DG-V1*%5kHN}&@XL9jKbucq$P_jg2!4JyC4tfBu^5eSlby>K ztUHxYJowWmNGJ$71~O-U5*-yWa3&|oL<;3=S; zp8ll@RS(eYb)D9Y8vN((Fz&sBBmSep;>EC9rxi~Q{ZGb0y0@Fp3(bPg|B|%?%R}hd z{c+Pcpr7~)N~Kljpi_8_Zx5%X=Ca4sbkk-qO)lacB#>N}YK(_C^>vNB4hmBZTGd|@ zT4al2-WDZZ`n6pY&!kl$kjJw}ko3u>v+W>Fn-zt8*RRWN_F3DF`G z7~6c{mm9-~bR)CB80>=aX|Ig}=#=O^iIe3JvOGiQYf0D=p&wBg>H?IaZjYDSti3pp z##gEX?cj`u$S1^DahCz~5N<>8^CDP)#!;FMLO)Nsva&KG@n?W%u4!NI6}w_)W@csn zQ;#Hc#0p>SdZApZ!RK!q5LZ{;nya_?`ue(OCX^b__Z=-ZJ@U-(lB7&sU$wu18{QYhZ0Xh$0}OCNto}>B zkXVFt^Jy32CFfsr%j(U1#jLW4`mQ7|lhN^9=042NkXQq0iNXX2OpjFJN_l)@$AY#* zhKYBf)N@20qp%WH^!={#x2IA`{}WW)g(#9Fl0IfWp92v0OzObjQq!c$_$qM1}aU39KwZ;mS-sg?2*8 zztI`@bOebhMXHz#z8;l}*r$P0y(`;-hO0Mfm?O3I)D_`MI zt#M4KGNklVyYt-cn9}J6#){+}x#r6sKH^gEm0&SY!i(IldzOcVE*+Gk#8a^dnJ z0VI3J6PU$`g=oibR? zYDGMNA5L}?>k4rM#EoJx?w7E`FNZpFJQNO07dH%Mfd%@x1S%vOCmpncXv&Yv^8ba_op zO-7Kwi%*G4858!FNoKkhz{LtJvp})qAWq~8JPpT?UH`;K8_i5ZJT&oIs061cT|f72 z05;?edIULE<}=^*Q!m2@O-kG%)f z#T@9YxwJVx*SZ2<>r59JGm&42SiDe8MYHyZ)|qVr~+4;s2N!k-w5E_uJF4-bowkyftg_Q zVUO6Y>_g)S<6jtptZ#wQ??9>kCwd~(S87j$s&X9z`=Vo$ijf5OrBio;iJZ4=u z+iegZ$gecy`W=SZp-bhI_Pyt5Bh6F%0A#q>yWrY*b33bKSXsitxRq+?_aw@@?Rw_I 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

nl*oyeHV zhM3b>oBqTR3ksYX3DT@lX!`kI-l8*9gX7in&vH--i>m@3|E!+oRusF(W~^1kk^5Ux ze(g1=X=CGbp-mGQ^4N= ztXX$by58yo1aCtA`-Fn2)cW;18k}J|m8Vsd6Q|Fl83&3pAwC*rr%xY;Tuo|DY_e>B zxPv;Tl}>j?G{>PNE@hGxhh18V@yxX5@^wuz3`r(%w0|;8TBnD=cINiQ-qrdI;p>od z`O2BHR7C6%iE1%3G^{Eq&|`fcAUBObl#;%5TP?p1^uPx!5T(XLYtEpHEX?44?)#%6 zd5NyIRK=IiMlX?jH~zd6S&Uy$$_&@=)sDLLlvRKzMR@0Nvxi6zKHRwM$~Ggcf=t6& zgyprlGs#eGM*IQBkR)sX^AtkH+% zslcTSVt~xAU5)R+68Y&3ErUVnxLGi4TmnsUuyhn+V5qC>VV*~lpk^NuBjf;#h0(#I ze>TQ&j!AG(IXoMllZMjH^3rWRH}w6=bJcQRib;dC4~YsDfU)2DqLk8CW{5M?PfoU5 zy2(!XBMVcH5+>AUOo%RD&L>GRm@CAr%t!4ik9-omG;VWnN!`;2>?rXO> zz00wa_B(ryTWoufNf`H?{QHG%`@f;oqLQ~@oyX5S4z-la`b79|6e5Bo)6s1YlWl*! z2n21wQx6_z1)k*~JI6u4qfpQEz{LUl82bvPeI>yYLz}{V;z@fodZqW-)uQv}f_7te zLti(E@m|ex!MG=+U!2aJlg{)V9@{&inG+|~YeV_CT`g4K%h;A619*fcr44(JP2N>0 z2rj(WKQTgFaWMJlEhLNRVWxQ(d}fJHGn_H#ovG}oEME?4dnNQ!V^^k4#T@Bmbs*$K zmSs49YR1C%@!+WVM0n!y$^Ji~?)oH0ajH6O5a8jf_Y5;Radd2bU(JFiUZP)9KY}y<-I23{p?X(AlAIq{0 z-Xwg?5Z$&(jRWW?(7iPp!28*eMg4Sn{X`QDWRTq0C0$I+iW|UaqTvsUVQ11Qy}rhp zp%1CH%tAxYVwGP~7UVo&k8UHec{&7n_wL;!TXfqu+A!<;*}sDH*}~v(ZNs5TQPWoh zMQ@fYe?8v&>NCH4v6dyBp9`bAHNr;EAAad?Xhirv{aO6apL;oywdDk<>&aow2qYQ7 zTRzjG#RRh7d2XhqT|7EUT~Rz!<4f7GGLV1w_|XG!z8`4Fam;+j`-_@JJ$^}>&}&kC zOg~VqHzXepMVaM3))ZulZhcrjQI7m}ma=Q7z*AbrdFx^h`#F8Vp3!tBoIAC_?VK^p zEerzGLwQ7)qUG14+;HCqf{dWW5%lxhhpOc!E;cAnps>8Jwb++=F6?nK$+YIhSEZhWqC0 zSIs|EImsEReycq4q+mkMZ3jp~<$Li}!yl8i8Wf+!7%Ufdl4MvfDk-2|aRp+rfnzx- zYWIIA{JZYV@XK$ZUO=#A#2So<44ZwVS$Wj`SiHeYd0l`Jb{mcmAqb^S@J8&ve=KfB z7u~ia`XpL4JkhRv^aRrk0dd88fLtgDyuJAl86uU>&NVX?@cgq_rPmj|-RH0GXA7vt zF#l@G$+72Ry8BdFkm&^25CzuF93b$@V5I2_^{@i7i`y?V-}2Gn=_;sdeR~^>Yv46P$$pu=Wp`qKL^=KF|eD`8bPiwlovx@y)a0H9M zGzVjix8E<`+%Rp!{U@|XREMNxj79+`UoY!XPF9}fubKt3Q^q?cCK#8lYa@Ec7*68g zk?s4tdM_3VyKcriKg@-Ze}8IqTa+rO9W_{rbh-O^xZlhs0hJUvJVG-5XeCcd(0~_q zWD=6qZelZyLz$&Ju(>|?&2N^2`mz5(G6-%j@TukGu&^+r$`l4`B#1^xT z5Vk+mkK3?3FIaWvhHXSRpc*vcHPD?hr61N)mBLe@W)JVaCl~DYi&M#gjM7r1Sda&Q z@Ch0DN+A2yMH-#&-dY%;0^xnsD*c1B8R}Ds-+mIezO#3Q*e<GF#K(5`34h7}7`^JNw<(ymO{ggM` zpMCGJjkugP2?Z~v-70}7qFD=GL$s;kS`Ius^jX&`oyWGDm<9=wKN&HUfprb?EWa(IZ+OFn=lF$+8caAzZCK z#KR8Q2C8=2AKQRr^3$7I=XdJP-Qt^-AT$lo=Bs|8L{g+$x;FbMCW1*J_uqV^ew)tu zRU!176;gM|bvXOHC*cO>mC3sv=JmD>-gTKtS&n#g;ytVG3)A+`xiw5{vi+lTd3A9x z@5$ZwXjk)Lhj?vskA>}xg(Rq~T5G+UnRrP?MaYhI;>&9O1J9k7;yT>34Es`HE&g;) zNcHZu_2Deq=f~~>=921FstL%ymn~mCH-G+s!5_2eEf(>`A_=qC-#}%u#XdSIV&d0i z?sv_D-9w_^5RqonzN8Uxt(>f1GsX|^+fL~j_MOrl%{$!@XG=P(JB!ft{liZC!|#+e z5wF(WHj+#)TE8ZSs2&~Sz;k+3A%E-qI%BZmxW!$yPPN|T`!(uEFToivjQY#ynJeAW z;jQl1bcEB|LXb_AC|;D87bE##x~EklWu6$(v*q1>!K z>%!FvrvroeI_w|BEFGd*$RuV=gu25%C9`|z=uh2mysHsXjedRV25?M-GSQuP3u?#9 ze#1#RaX=Va{yPN-1~LGNDi5}E1<_0(06YF#Jz~|k1{|Q%^;~gw6br*`k(>Pd4Y!pC zy|_xjFrdpxFVmgR?+U$n0z@8o0^(Ly1Kfc zMobtaWd7oDo`z7+G}s-r%P(^Ep(gcWuN7 zQz7jZD4eh@>R;Ym>e-8N`R>A=6(ERm&+M(3qI^;pWcIpEAUJNW1(o=}g8iDcSQ^$!F1k zer=?Bo4!kV{_sA$hJ;)trv+8wb=!35p_k%r_<8;+L+!aXMijGgmnj^%M+irB)c5U+ zKHptdI{q;y&SPCY8Of*X7avpHJ`GhOvZ;&EF1^_t2oMbL^1;O zVrAak3h47X`ABPa9yW^Gik96Z!3?5~KZ^-wL|>)tc-8SYZpEbgmdOPB$V~*EPrO(D zmU5T}#~Cy@?&_B~f4o8|%1(^U8KXPuxPMAB-Rr z?dU!Ht7eC=oNG6_4omQT<73Lkfky6qlcq)Z-mS|*wkGy!m7P8nWX-iUA?e0j>G<6r zvl(mL#NDAhQIHFBo$x(y}7tt>0u@1q zzU9c^IEMjw6sk0Lw1#Ps(wa#wUU{8ZF4H!~@)qyR9W$*5j<~q~tA~7V%E^nnzF((F zgQB5|*X5OuZN}mmBaToFx^SyDb@iO%4HsRfZ&3XUiN##Lq(0J?xVDFVHhQE2>Ve0uq7wb$0>SlMJQ(wUNxq;3Ka#H#eby zYI7YUNB5nR&td0h3oF9_)7b`Z7@J^h)56;u8VBE-N-pgDSd8@6gR$pi#^PM%~_YNQ-njASetio$An~z`)Sm-5`y0hlHdeIdn@8ozmS(jI?ya_xQf|e)kU+ zuvlwm*5Nt(?6ZG0rZYG%k9VH+Zb{DC+I*>$4U>KEnOjfH!kz;0R%R(G)<~eP0w_t` zT5oUj%pgYm$&4^e0ugh)!P8V0FTH66^}|fQ`9Yto{&CJefQDR-d(`hRQvP#H$P?_r zsly|_5lSIx$Vd3DV7l+zxs=wrP+3@y9(W#X3EYK9nn-^rK`NX^v*;0-^OtAz7GlDN z|Gb5WRtnLp27aT>6~6cz93d7pbK}e4>LkVns)zEww-b8eisct&PE7lWirFUwew+iY2r;;PETGICQF`GxLy4Q-%<(Y*vbNILX9U4h$=pvGLhAn^f@X+ zc1_kE`7;W!qTnppZ4yt!=!HnR}Rl_Q~ z#?;;2n;+n`7YG3GuW}td>sn#R-uTKYY*rLGu!RUUE})ekAoWn6sf3sb?k{)=dK@ix z#o9-}E%46hgXK>Po=hJ_XCFPW4Dz9m@6DN@Fdj1`OZ*1^nC&VBb{_U5Pc*KGXPM`J zA0f{@+MknxC%yRq?ZQm&b|3=3+d%`fZ;9>eyd+N+^6j)=!fd(NGaj4n zOFz9KhGx@=6js*3&5#g*#5*HpIU{ps>R3*Mff-_wNbvO=vp?O4HwzEHkFT_5_9eZh z#w^ltW{YyE@)5$4V*F#JKPUt|(J%g;K^9SrF6&cj%w3QXt7?g)gboVOeEwbudf(qJ z11<;6ntzaoI&Q4o(8!*~bY*fs`8lbxrzDq>?wBwKW<6-X!S8$2*dv{!>V|x6;iSt} zjK%H{B0D>y`y6OXxv7)saL$e%gu#zz7k?FFhTX ztox}9Uwj80g908Qu~ZRpFZgoNmr8f#=e@IHN~gXAbr|(}sxMH?83HgLX%jgdx+7`1b*R z(@vk4HxR*rNXGeFL&UrE=VD?-)EF_iHTyj_7?QYm>d?jyGY8zS+Lzuff%`|5{h%vP zU7sGr$ZKJ0nCV5x8IB+x(45>vkm0cEeZml4{vMn1Ed16DG^`u6HSAF$S*;OV61zsc zRI01?+gA3AEbrX?{Gn$%(NtGOVG_PPN!t?|XY32jp8M-y8^(Ro}0_JA}ZuhBm zWt6T`ZvE{o)yy?48|hhww8=(GPp!5`kF#MY#)8llT-Wuq-&tITB8Rc^&K_MAq2H@* z+qgU&v*bZjmIA5SRPTd@XLg(RjC{Z}%y+&@Y2LMg@Go*Sp&0`xgQ19xn^dsN zPQS8P#x>nU6y0c*{xKx$iQ+xPtLp=~2cQ@{QKg4$YJh{W!MxVw7Dmx6=YG}2^?^GX zFH@=WyBI!EoVFBBVfxld`=oaEbUrvHr1?;Il2nLk0P-H{{)KKVO0JDDgEIQ1KDEs$!MGe0 z8FrIHc!nqO13&CA{Z|FMMVeJ$c9D`Vtx(l+dwUNp>KCh6s%W)i0L&96`7yl0po+-S zZmJ=FIq<;-{+pJS30;Rr`Bf@-`%#l|%{qO5nHex-Up&N6AyH=auClmD}5kqS;G zh?$VZBgqJ^r{cCU8;P0K)}4>~%nYa|;eECDSZ>BKGw9SOIiVvXux-wxdl%y%gev5D zTgVtLr}|gCiySN#$@7I~LKW!c$SOSe2`-q#I>?;Ot&dsV3*2%UViKuZ)@P<)`VhX5mnm65$&m ztbi~p&p`1h-M#&0kKPXuKK&T$?tJzaKJ6Weu8Wc^44Dtsb>#?ly1%CxW|8MSB-{?4 zXNE&)hEbnFUXF~+v%PUL$^7vrW!FqvsfQ&bJf2qgWYW!DWRkd5%;IF(FAt6$$XN|5 z^LR~Nev;63v1p5aL?iWM{+cyimbcu%!Q0zA;f4An;KaeD9uo`Prh;Q+f0euiLZvEz z`!s_Tq5y`9A}u2>sEY5vj4--cgmO|VFj9mSP* zR}7k;)7y5Zv%@Bf&L>jzU&6s051|XgMLZ7M=pvq5o+z&?=i*?wNVR6&?ee=ETb3M+ z9r1k6JtpCgw|E7%wQVm4_%geKp^_(^%Si8&B^vj^#Sp!7@0MkdsNh;rUZpK-w%(wD z^Fu|W{G5eF=FRUpK`LQ$qpHfb)R$UnGmMF(obHeEN;(@Hb|>V2n%7uCTBSB4{2i!# zLL=QV%ydBv*)cv_D)dAsm} zHdTvz(B^CkL)G+|2G=ePUMCAvJ+Hvi1+?h=y;$=foQQVhn^BmT2O&wMF(GyiX(HOp zx$6(}oeqzTV!<(n1kR<`Uxx(<*jBXq{aO<;bHB8yEF5|#4mJL{3e&;`_u)?klj&8& zuP~K%qk&C+G@mYTvsVe9X($!$N?Q)RL}Y;mb&P{tTQ~shS&lWunU?(98pe+|kczHD zrZ-{I2`|QJ_^dELCnbc!h~!d^4239AsQP54($c2imla0{LgWi3sN%8UfTlBrCKUVdS)tKQ(tB2BFg+~NeJ zKMZm>H$;8py6oJFomB*fp55u+vg%7pqJ7tsbWL8e_$3MRfD)~XJe_l{z&L0eoQJbT zS23c+BmIDeIBke9;TUE#E;SP839-s_BTQgQl2FA~nU6Sc)tju9gKCFdgLybeF$!T#ikx>qX&)mE+jwA+7B!yZ0CaW$JmyXdbWy_gCKF=hdJ zy0H)GOzxZ)cOo*-09>l=WMqV2Akn+AdAoB-2bK@BC`wQF3HA*Zg5iXz60rM1r+`M5 zdh7kZtXJd6%J~)_GCdDVOQl^lm?oYpBeP|fJE{bs-)b~`fg_;*b7FhykXpg{yZiIb zT@U5}LH*@p=G<^jg!s2={jfn;J;I-%7p5ueMCaD;uUNt>6?|htlTC1l64`5lF7HLg zFlJ6eay_Wuq5IEzg(xWs2_P&g^TTh+PEJnf*}1qFuMwv7EO-DKV`!^qz0J(Wc0gB1ScbS3PQTE7F*Gz3%&-+NdQhhx%JMZrtO9O{ zdaLhuKGOz-O=!wyf3VY7p=^j%P0CA<_g!iKCl|R}zNAH&`5G0)hO((7ho6^; zn&+ZUx0XnDsp#ez=4=x=Z#xGRMKi5XIY1#N0(DasX7UBu4`-G!tH%hr%PudRFpj|Z+^#nZHo>wuN56Q z(=HvGprodOw-=5aD&78|r5&B;EnhqsPT6b~_DE00b;oe)L(gx=n{mj!Gkg(5#WvIR z*5NzZ@jakV^yKWLp2XxSRQ>_pXwi8GdAL8d^v?d?gLwJXr_$>|39R4Uh&_p37%%Xt@m-W86XJvqpNp6x8BH)9sQ7xQ$kuHZCi zENkoSNcsAtQ_nw>-2K`^<#0$X(JQ}Mlv8Ww_&o`a2o)t0C|s+%^GaabN$6>^nGOX@ zp$l`VO*QQJygW%0GZ!8GEHfQr(mDOxZ+)f3-y|cQq^VDE^994Uk~$kDgu+Kq);aj^ z?{(6@znD43=&N#H(ZXAQx(I9CTsfu-i$Cu z%a%LOuhsd`)+~`D`4Zl&30dvlk6}&vK@r=ZwNP4Zx1+dxk_+Y6H#$g8_g%GF*Ioaa zkCbT+JgPELNy!kOVT`D745BLebo*i4l2u8^=4f0%zk2O09KUh>`kIpbnfsH!LGaYb z0cltR0zAi396z~g-^kh|JbsH7U%I;k@C&H$2K~+pT>h#Vjtr7K=zY-8hk6cFJ*L14 z2~iFWrXxeL=4N3sdMA`0QKlx%Bbt4VIT8HU7c1B;o?+RTE7f}(U|e#u61@Wn>~m%M zJYIe7q7%fk+b0!45{Ud~acAxGd}Vo>v3MR!EU#02c)}M@lyb^?%+J>Fe5rPkmdg6H z{#*h|@1-??X~tw#aq-Kt$^{&&GWgFb9EASziRJf+KU1Nh3w$7&*H+x#fSOaW$|?dI zKuumC%H)_Q+34eQ1Meejix&UwSxI1<(*%_UJ_pWTbwDlF20-Vz9ERJ?QCSrjVeGtN=ESeZ3iU;uB6cz*147YY;;S5ePHv4($B zlsP?DWo$5A18Wrv@K)3k75|WYVCzp+xfT5a@_Wv^fDqI#fS|TKFcrX`&&yaFEJ_SD zG(Pjb73|3Z5OCsN z>`y3#!H>aBj(_9$H`}`tbCvNe<7Y!+^H|+hfk3%U-Qj><_HFA11v_^l!;dMzZnY5o_Lao7y zyjEJdQ72q``Mft^1DV|^sMGCA_Je-E;6DKwWLKXl?CaOzWcG}paz4R_SFAK3I(Xzm)t*X6 z@nxr#^Z2bqca0LEKmqA2k&$$$qsELH303f5We&rxDTAlMtr2O9QQlQz#7h>gQ%@4A zD5{$FPEgUOfgb@F$i8~(0yxFy_+yXL<3ij_tv6}pK;@U;W30g4gr;v~@}19XCJzN{ zRH5612Hx``sEG4Nca8j*6x-o1JdR|dbv(VT$rlR>Cf_YJn*`67zEd6fwZ)LxvfaJ} zC0+$@HZB+p8 zYb&C$EQ#<%%i;um&#ntcDMB~=a|0l}h#CR5(OOsLI;EE0n`6={`!FPOI6Y`buWVFX zrPpYs?VNK&&RadTA-j5il&<>aZzqOiD8F6=l6eH{M45BL>3*NUH!lURG&h9Gpr~+_ z%@WIGEY4CoKfd_}L)Z!ZF9QixgnS(|3(z{?;Ndj!*OlQ~ygv^r$O#nW#+F;ZODAbv ziyBx;FI(08*04jF_Ua0|w04}pRVp{y++yzehb7dfVP?w@x@gyM5!UbxoWryOuij!O;xtonpyPw_H? zvw#fY=W74U1>mJsC%Sa(y_bS4ntX{4`jjVru}bZG7$_{PZvLFPR#elFnHF44k(%-p zWAn0i^cV6Qk6oyF5B~7DC+UdAmztiSJx`TMJvNvCdmUIwQO8m1eTQye@j0Nux!Fy&-i06N;@TDTt#m@B#cE2KKm+@Y#=N=1^W z?Tj0ror1KAS8Qz5`EaIc+-;0Nuh!ojKGYt+7_ytO0p_b#8u~qO+j!g>F2|Sm_AXe@ zRhan$)LjLnSR|?}KnwY-*b5Ex~C*yDv>Tw$yrm4EtGYn0x-RO^3eIaPho|v64RR(hH`U^3X?)srh(N zz;L+nsmXe8_fYAajxijymRDK8zcxdIfTm z5U@@URSx++e>>Xl;HPefc3eesONYQjSp5q{m=n6rn5*)fsO6R&@)yoZ>oDp_oSQ5Q zAi(R{3ER1Kj2(;)wT{V7#$nkx1v_DG7r$h3-d{4J?y597>WgYams9}RIN5@SxY8aR zyYf)|>JAu!)Cv>g^UM@5e$A+oPnh0@(Jqu?k_6?ciwx{E`j+FRYDm)WM0%22ote27 zo-KVBPK+4%(@62Ba#&%$0jjUET2!#VQjaU!BQZy2Tw7K}T?(xlE#8HY2$Om#LHys( zl=0K(x$RHDCMK;%1251m5`>9w#q*);13~OO=-s!V6A=q35ey-LomFwvOp5T_7pB~n z*8%S~^w~j{#-~5Wq&JoARQzyKwP)kqO+Arr72zvY$luHwGmlYntRsLqE6JCL`@WARV|QksmL}%;eni!!AypM!2!8!V&XxEQ zjclR}_9??yw8Ym9NSbh47%(sMxp-LLrc-d62H@3@3f0Fm{}KueLEpr9`qU7Ww8|49 z3o#?USo#x&$+V*M*1~}cS+)vjVD{pNqY^`uX2=ey+&Ww(Bmfy#y-Uy$w~tYO&fo_U z%1^4#6341Mw>yQpTXlg+%Y!e;O=}Xfr5g3KKR^PLG4kl8-71L(;<3pH4WYdN4A%F_hI`y-7+cZ1AgXo!VHu6NQ^q(z_KHGKuXk?>3=0AR{hqmXZI@3o0 z(2abx!>3va!h{ly(HxvwG+0;xQEaTt_Z@oJmds_okY#T2br=XN9%p zuY|8~E0pXWfT&~pf`S0x>chTl6Oo7UOc#rOZu9^iTu1s72X!ntK-bZpH>*SUNKTKP zA;(?(963+|3_1e{Pi-!GT0i1dr)B8^IWRPu**Dt~)2kA$v*fzaqKd0eZZu<~p@~^wOc!B5Un0gt4B+!y=Ix-edlr zx?BFkntxA5u!WmWp(y(kC)_}1R!)Xhyd){A+VXmj>E~{PF>*UH<`ftWIj^NXDjb=O zv$-%fji)l3<_^>1*sgNQr~Fzsh>Ay?nbr=ztj8i}mQD)8y>WbZQ(UA3#%wMrReY{l zc1E{vF6!$W@L`5QFO#Bra85gYLYy6b(;V>`CAY+8)|0kg$LYsCuEk%5SD^aW-;VU~ z_h~6V_tZ^DcCUVr@Z7M)Jj2BoHQ_aVSF_*Ff1#39p)wTz%_Dc)39Q%?1ws@14z&$z zEr*9=GAw)kt%-0`;e~H4c2uICU>pCYYui3+wmX50E2&AMEZ^hlTc|MCZz#?k zJGXTEjOwX0l~kjrK*{X2l`OsA?#C4O$GWlRou^~pw-&+SKY^&k=KJA|7Zq{Nm-=eY zTr_9;rI`usI6wsNWd6v*$YCiyO>lo!&`Oon{OY`~6`?@5@2lvEYeL>>x(@&#SHn)u z-^wIl3512^vhv>(c@PoG9<&Ejg|L&=dwekyZ8|;-Tp4x%8OP`zHe{w4FB?C|b|G44 zV>d+C)s>T0-_H!1gbt1MZmP6*MIpnE_?b#}A$0F%Kx>Zcpj&-`L6Y?DZ+tBBe8kBX zxJ%C+3Qz8?u-+!N$5F^*NEbq&NTGhjLcUX=kb~z&W=fy269?|btb*WZC4c?q=y&E# z$ZWz(oIC9k;l3R4fL=S|pFH1@lF6XXfS&e^&5vN?QTKZ{_xn}?y*xP8m@;)(f?0(6 z3>jzU$s@P!c*yuJXi|tnLu_brlos?13gqzY zG24i}OsSNw^4Xdkf1JvLt3%8T_dVNLExuyiW_Lsk{$w#si{=iO=PYwE^;U&;ht6rW zY~=#detFXyO-NinZNypvj)^x_%jL7^0sC~b$1P^N+IzWWqz8hQ?AO|<@cjLb%%r92 zVVHOaul!+KpsH>Xt4c2fq(wg|q{7P(znmiUy(*TQxpM!gEFzNf56p&g-8&meDdxOKyQSF4m zRr=aCtzB8jN2AkW2|EyTe?I1TMehSd4GBRlhemOul;J z)Z>9}1#6KnI0(>_NQpcxqn$Qykz~AY;N$;}U5GzT;r}DN&|SyX1_?0QeUj7k>nu1~ zW9@a1LDSXpo`>Rp)lp$pHsnR^t@gdmZAH>Zz({iVEsmEG zRMmZN+XU-0uzp_g^oOGV%1L*0k7(JhoyK>ZtvV$OPDe9z1 z-TvEkHmE(BPJ_4wpb~*IM9VqasR4E#541Ly;EOn)n27yIWrK!^1j6!&yD0fF49t6S zQ_|5g61~v`59$lFwG7DYBssiU4>F2!s5x`<&Ay?Fr2&{1Wr9vH#@|9OiRu@g^6k^* zKQAfE_j|EBBviO{S~H(q|Ey8GdHghS`a7O5K`tNkL-9V)cNYRKB+u& zuB6UkG_St(WDw-%*5&(lG==w-Ig7IPt#f&#{F3Xs9IS=uR4knxB86 z=O=>5h^&yA&YdzipI|SgSPlw_HCEYd2<ZP5g=e3M*b#J=?s zezH}!v%fblp(NH3!eVi1GtMA2Vwcv<$xGO}7F4`e23xuJ5}MKVi!P?6EQ89wX}=cL zBX;xi42R~Qdv&9HAYM4xw1kkR6{q=s6ba2q3?zQ<0VnrF!}zvwZcoT*8axAb8?n=ZTXjV=d$ZKW;^lQ=Pl= z#nCk#&-KMB=|_EmYZ(n}w3rO;_z$Gp1+A5%Ssh^=de_d2K8JU`y=TpCYO_8yY+{cS zmH)mLTb=D2Z1iZLSLcmS$vG8OjL?D<+fKV{t3S*%LN<+!K1ZC*><&vktm5X^^YSE~ zS5l|}qDt(2Dv1$MNwG}yCb?F7r7UB~0%yq-bu-gE_!r)(*~TNGlv=dz{YXqPzs*HW zt^QNOvWf{r#zQ+_taRzni`i)jEt7>vZIZ-3#3?LHu7URn&9nd23)gBhz7<=zsW&?i z>!pG#Ckipvg4uKuam$zr1}`bf>wHwB}Ms13YD z)zet8K_QVR3zbxb)+(^PIOf&N+`tE~G^3FWVykqj)z2vswTcMI!yTA6b%N#JbWiJQ zyjO8J>g_j9LQ4y|XyRO(7(+a0>q58e?Yf+?O6V8^&v0sn|xw5R)kM#ih zIw^(xkPs!sh6h{Yll&Y>;$+7I;U9Aa$x$EZ^5mFr$@%-c%uBNAQE&>Lq^UF)%!!xK zc!|+uMF*<$l%Gqc02H^QwQ17PWSo1V3!1D`GSw!V3-c2gwP+#BlFznyt0>YYl z`ub*sn+TG(MFgR#Lw#o7+w(vEm!X>fPMs2`9hRN|cI=SWYJSbPF#adJ|IhV?&mTp} z@W7uff!{w@vAIKIeVkOjM`&M z(I3eKR>hePq-PwP$Z@K{hoBssu^+)3nfN5B&rga!Pr284`g;jHhd0YW82~?`+Qthz zu*NwQ>Sv}-^Bcf0jLV`54Uj?A+Vn@aFDqwom}A?U2h*tNC$8lZdIcdom51x?X#R zGoP%BU4Jy{RX=CrK+SLIn+2|olC-r1)D?#^C#TPS(NvRsA4n6P1ayGUFjkG^#q4Q{s<#VuREYa*fHWv7xZ#rc&r{CpxY1qgw0r~EMQbtcZKgn7E8Y#x z7g#dF#7ryP`A)Shh6~FnGu&G|>)K54$6`S~-C+XhstYq(2Ei*lq{%ajclX~f`5M_8 zRlv!^qrN(ZlW~+0_$DeGX+k_YdDRL_cIOV$)57Xwr1Lpal}~8?dN&`p1P9+5sYDQQ zW4~uNN`?2W+*rVGOsz7-jA+XK>}8CfNFX#36bQSoelD5#$O@7RU2FV1G$kcyORqk< zkEu$kC%1N0Dk6TD1x-byOmutmN)sCJB%)|G8{u97Ab<+Ra zA_UZ|EQv!T=XhF=Bi#OsdGDLSx$bTi9!RRS%dNL#6$ge%i)s@A%uo$Boeq8W6 zM6|!>B;VW|HgRk=q~WfXdhZ))4#LPSrLBdJqHb?;Z^ID)unSaxV1SY>m|Da zTN1Yfd?oPSP(msCIG_15Y7Nl7W|g-UeZ-(*gnt|;q>n~k21P&unS#Cts=z$dZ>VMY zWrer%Z>ha3=*-UkoiwMSKw?T4uL3GP5t=o`%ttBj*}AC~5tkRIew=tT0RByYCNYIT zC3{beB>w6MG3h|!x;LfJ6{^dYcHlSK1hlHI>qiSp z=PRDYW41v#@Q?5L8(WBnA24AAzIZW}Dt>fn&&6r3(%=$1HEovY6s0z!E^Xf)2s<|c zx-4LT;LyQCoHz?xAGbx2rHdVf%Kto+PnpOm>|oPA&BO!oqIwxZzaO4jeLcLHRo6xy z|F7dm&d*5FKDpJWrGrk^vwZ445|Zk zW*A_F8EItbmtk?L&4e#saGAv2Yxok}y@N`^;x~3egb4w{t>D{XNmP%1{Oj748nkun zbwJqVt$+E&1fMi0{_Xj_%Yp^F5h{ycGqKet`Clq%gagt;Gv`xu!^DTh@U>_;qIFZF z7I*J3QA-s`=t_C>k^_EL_Z}TM+4n0P9#Pjx%Sd62{H<>Ut8k?OMsM@7P#^oR#+9TF z^ws!6AE3Fe!y-m=K19%a(9{J@@Ic?{xBs@ysw_FXm0KIPdmS1J6qNBNmanWtF}IF< zR5#uq-3`RSQ%iQ$j_&5Ui+62~?*48DN9;!n(+OZBv0=&?fU%alI#JI*st><{P&bzz zA9q&U_>wRl%7sF$JwhGfw2sRdXa0J5Z@23O-?Ja6US#jTvi~g{o`q=zgF~a-oJfQz zOYOC+g*B7Q37rgGSV!lx$kT9>ZM?zP|h5VK~ii&LlfCS+z;QBi=$h?Dhmj_=9 zml!LJI|T$_Z~N!cp7n!3^?K_Xu}_;vU98#DHx7KVPSK^HNVGyeoZEcpnP!C^?l`{J8;HkooET7Fu1&xGL&h2rghJR65wCk{ zh|qS?d`uEA{8nn7UJ8G4hTjzLSyEY~mv7zBCr@8kK$8pICt;?6i-;8j{Trt1fQwPl z_9$MTjWt(N5j0SQ5o$|d8=kfmXY31`g91%qdBfTM<7^CQM?`Npa zY1N8OGI}ggZG=hrE7HkYAur(6@B9E)`G> zh7hY*5un4XqO1B6K^scq3Zz-RB@xELsoMPfgv6V?G*17|TpMOF8hv-g97j;lyyK4B zx{8v713SqVT-s7N!*Flci3ytsL`EImfe7_QOauG+`oJ&DBRPQ1s zk69mja<51Oe*gbpu>1m-s>&9oo%`w1GQ@ovEV=<%gBy^BTvBzvIhbtA!652U7B(C> zT{|YB+g1kHC(N97TyJNV-2!>sp{pPF%A03(Y(oz|LB-lRf=amuQPFD$pK28shsRAGwb0EpK+TnD&Tb$^vxE9@dynZ?C;o zWwz_(_WFkt&1qz}u^%i;@k-j6O zwtQ*)j zMkI1Sp(WTS+TTmdKC1lw>8^eP?}~~t+oJ+$GQ;$O@_2@t=>lHmJQjqIKvW{~2bx8V zYV=#Kj#?yTcnKrxyvcvCcUM16|g;07nrMApL?#=087J5kvCHoSq^ES#w81 za7le9Sx2%((*#$&K3$(8YqwH$CyP`W0L-!5BGW$A-6u`Y1(!(Tijg58s{?!nus7t* z&0p-5H_`*f;DyrBu0p$x#sIex_BGDbD1Qi%0`cnmOovvwNj4|1W9!3f_o>*9RqoFS#$ zM5Y)^JUjnIx=!@)NH6tr$qhY~&d~528?N&l1f7=C*T=nsLbYz9Vx1ny5F9$D;|9T) z?Wz+Q3Zc4z9jI;9Be&j^Z-_NL%23)7_`lwrVXi()bPw#W?g;`&_lq3>k*N(_xfz`XQYd(_^rUF6yH)yazQ#Edm$`eRBttjT z(jyjMbMDU4GVU^bHIU{dz`P8Sg7n1Wk-t~>b0wD{uD`g?ioA9atKcW&^9x$i;BVD@ z`~9f9CYvi>ohO*H4gL~RIF#0oK!<-+Ff&Z9R(PsWKNJsbS3j!$wRG0SW(r`ps&@b& zb|O|4>o|ojItN?<#V4|(Qv&{ zL4aq^r*D)zfQPIukXb-31qBcm*7FMD?-P`w9{Y>zS{2K0AhS;s0XZTjUl<{sPDA1C z`5FpR?-T;6CXfmzq?4clpqrsJ>ke_if>{K`eyJf_0?-_`#{4wtvBJ@#Dp!9+sEBiG zg8p0cyzJzW^zDnG{m;AwaH>b@dd}K8x3vE}bLbxEI-dLUiJ6Y=O&NDyf4+qaT`s%2 zcLrn55H!x4;5jt!ungAFp#Z#`rh|qhv&)r3;eN9JS0vl^fGdo@0ZU2*wUhTf_vH-IsHCGGD`ncq%Y`p1h-NENz=rxISH-FQWWa8r7)3eG)@rYe=qmG%otLEI+pm|saX z=Nc%)THoWW?+@JMnxxQUqpwuMBVXn*cRf%>I_v9Xl0nd}DN!dUlSR6DKuD3V;SnP! zaox8AfXZLV#MXCFK=8ZF13OI|D*fP@9eJVvOuE-T(fgODtGUjpa*43vI&N8=0MZCD z`(vOURVGG!@A2qUc66k*-vUNysy9cs|93SDY}2`Q2gJwu^EL8h7~bVf(1?qLe)Ul1 z8eM59iu33>Y6E#<6W~1*kF*g5?51LYl#f?1VKrT&xQNz5IO!+G0q?1Q@!FkdJ5%vk zguU~nPmE-M+&7qp#@QRwTS?$iSS`_jS4Nb9IXT-|wUz+3_PvI?y5u#C7^CCbem_N_ z;G+f1{7VEFI^zv!t8f0C409PS&-)jid(%M0)u2A;bk#Kdp!H}V<5!a{m&dmh$ABk^(T>lKfoS=32q88Akcr@C|YPUXS@fV}!4v zo?g~LP%1^1t1N1Kf!Zs;L4!x2qureo<;f>TxsH~0`oj($ixrYg+D6|n(IsNKVE*^ZXT@J*{*#m#Xlj;X5 z>dKpgPM~I&#;jAQDC3xtzMbP=N#iHXEy^MuwKC{+uZY?E6NPt`%kv3%n)?Es_@J#A4*z{8%3)@wazvB?z~LzBT{ilu8;jR|0}d_c?=>YQON z{oDWn)cj;~Fw6gD=LYc3!9gH`(3|c~hF@`Utp#EcGlFUaQtO2{v+w@i-cV1;5-r7d zqNx(0Q<%EY0-$9H$c2riqq=$yw*!5+tn6$r4qY?fyqZ3AP;P&tNEN}W?${Oa#a?<7 zTM7FvW#D6`NoR2zBtI!EbFmLtzPIHJA*r9jW6}M(KfNcEv=Z_hA5hm2^{wmK5BXpi1C!6a z1g0AiN*zUTvc#QNiDp42WpHMQm%#;^1$_2cW&e}BMo@3sFx1^bCzB(HiwXM87<0gA zUH@_Ufj*i)2d}jNZp=SU*ly4NYn@Nh16yGbP1Ryw2J7@={E8eOUeR`oJgeXZ!YAv> z58wfae4oekLM??T^m{%yGOXVZG!c;`y`N!@j&SQ4)rEa=CG$9lMYO(e?;B`}oYqhQ zEPXoKM_gLf`9=&6tX$A~gd5rWDjGCrE~|OrcJ_}r%W^tlMerPaeD~3FqF^JPLihd{ zs;MR*$m5kwCLJn}V#w(+de4s&th6O?4oXotM|b$UWv-1&j9liKmuf_zq)B4%r$H}y z^{q7YZ)1b+^$FQ%(=h`2h8R3N-5?P|FWzhmL>HDLNER0J)m{biB9{-|5I-y8kf4}~ z9u8vz!f+7@e~!1_vZYXyUC2U#JnqIWDIfAWCKHX2`yZTxv-84ps9qQ&_*zf~CeiPP zTr#oLGjuJ&c<(jz^n7i_OaB?zaa5mlZB3h})aC(NcS)xxm;>9O$0DU8gO#yi@#NH|N4yPd1m6o#%m)i z;c(Ci;kFM6rw{+<$f3Z@>CCT4JVz8iagQVHWXMpF2{TQqiJv%HDGN?Dtq=V{WSaPi z+*OAmeAia{28N-eF*6K0on!~!n6v|)9AkM%$R-(s;c#eG^TrbR)}WuEzsNfJ=KWGc zJJ(;OMK|}!H-sQKll3uEE=m)g7qQHG?Ml);;fv=eXzW7YE2oEkG`$w^2`<`@+NbWh(XRjc(K5U>VuBX zA`v^C4W?K;=C50m1&%eNm?d?9ZR~z~<}M9kV`F16-t6}Uzq91phpfi={YtyRzn?)v zE_mGDeR>=%BC=}{xvcIeThB#(qc2s!I1-QS{h#*xIfxsAbT_82;b84!=ui62D zzKY`y>EuS~RH>14_D}!a1}LC@Xf4|;7rQfi%iy4->*;m_1_b?ENmHUkK5Gnl^qCZi zPpFX1Rz@5Tg5dQKMw|=0U?U^((*7$VDPj!A=z(4o_{|s)*+y z12(OSV)q!lfcwZTJR}gueeqpbaBfMSh@?pw^7_R31&ApB=kQsi1;6ArQa{;LQZ{Np zWB>Y?Ky$D~3UWxEsK2+f;SZBpeGVgE(7dKM1g!Z!B%12J1Q|vQM1x#XBkIZm@Z6mU z$@T73J9Dck@;~-lJz~D>t@u<%oVW(bSLq6i*x&Bhpqt!oi!`_J#{)l0^ai<92B5x! zG$^+`P(%%=f?SHyHQi&xfFQH*-ACllOs)F>ZS60g)6(W{0A-EX#?|#kyySKm4OqKc zIa6TSWtbyLC1(>IT2NNT(pLqvy8>P`=`|=2UR&w>@`(Ls*Zb)WqeO^V_{RpgK_NWX zWQH+WXL*sjqh~4FXDty~T>n^izGTA+3h4ZO zI(;xuX> zxN~CFFQNui{Vh2s=((iw!B)0hLkTD`ciuf8G|>r{F0A~Y?ew~~6`3h+5N zdlXhD<6khx!mD`Ovrm>CWPk#27|zq8Sj}K6BZPd4IDy0aO5(38Gn1b-teanMs zyt1oIM}t_gB;JLn(f$0{8n%RFrMBHr>q&2uKax-7SqY454&NBi-F8AYDp3CVIB(G1QQmQw`QSsp=PlkG>0oEQSuYJzPqH58+oH%_t$oK)n}~}gbbMGu2?Ju zTJgrsRFll}I@EvAR<}?GRtZH{0WHQ0;MUNGM(K9ihu&zdvc+}4vd0_XUBdDC&0}r& zNGH{|g0^>2T^EtJvS6}u=L%sjTus>dfwM|K11)5Rk54XB+Pdi8yf5w6l;EWwMpf%W znmT&$6!>zFB&ehO%M)cp@#(}}?RuA5O_a$*2tvZ74VDQujJH{=aFpg64&QCIw09WV zV>XW)vjOo@(jSKmu@UwSU0d;-cajL1I;pSGUQwm)S!A1y$P+G!C%o3zbgC{&K)AyU zFg2wIAu6g#Brp=h$lk0yUWy0%<3Ha}?GHN}_C9(Xz7C3JjO?NGGw{R8Mv!0!!7R6) z?R$eE?E(!osM)No3FB~T@skB>TE-dTa(MZXF!4`bqZXIxoWjrT$Q{vD^49T?Xe_0m z%Ew^R38cjHIH+^|h4Il%>Q^1c)u-s-m0`Q{H+Pc17*IxlsHnUe0LvuuZg3$?xZCOkxD~1WJxZ3z+u+?K%iC*QQ62} zp@5&YpfX(n_wM14G9Cb;RnCa|Fe`>C^X06@9x`e#5!l+VrzJfgoSy4u`GXi-ZxJ4G zC)?uv^Vm#*Ni^9;=4mOr!=Ct^h?M6 zE*n+yp_LB4C2%DI6t7uNNmW(VrqWV|T!m)dX7%O<%hm56oq4_q*E@XOY+Dv)%=eJ2 zN0ec9(sKI&WW}COdsRmvBBL?9ND>0rGQ`MeGgQ5pg~v?LK@G{z-#-66XT{_NGB~+_ zB4h>GS;1N#fR5ImyKs6++$Ng`8;F-J@kge@X-8OOfg^FD8o;5TvV1v*93WKFii_RA zAWwJRt-=UsruF#HD+);Oyvf z)+qJ-N}b7m4N80@{0~oN_&9HVd7U|B^}YIQjvVoXlXc(J2{@Hbmqdmtul+BCyZtC; z#DDeELr$v|G`Xs0kMHYFw?2nlT%ezPibKdbo0;W!xKk23hNI7~6&pmPc>PTqTn#$x zZt%UXYkC(z+)m&ud)U2CZh^|kM4&=Mi0BQzR36X zYr#j3Z6DPpe_|nU%Ly9D?Ja0> zg7<&ddcn>Fa!wAkX|BjZ<~d~sMt%mdmHd76f=(!G73Xp<+L)^ z8~G*%oAOs9`BNU2d13vMqc246mVShKh>qR(VUH_oLuG2BDY~T`U6rc+FL*+NgNGW> z9VO+0Y!{^#6JQsH8_%$JCA=@or2`gB781N}FeeNeTew;YBpTB@hybIn<#9>>trEoR zHRUs#Xqi&{qkI_k{Cni%6nZ&8W-Wc353K_&j8r{|+&KJ^dJGw`3{8=`SJsq%^rVk~ zUzgR_e}X{R?l1RB;^f1D3hO8D@ayz|x7iZ&sAR@pQY5dl374E#=37;%0BkD8WsPH~ z9x!W?y4^tLiA#w#kACjJK7Abud7?CXeh$2TGPGbQ#F5?<`v zll`HU;T!RMLR7YyfL6|DK4)D}^1dD&FTAXW<7tQ>b+*x<)O^zS7NTH?f_!Q2(! z$*u!`lGf#f6|7WGfx+r=BTuhJwL_C!b$b~d8cxhJ_z&dE&CX`8r0T$4Ep@d^r~$`8 znd^4aic;$Gs?gH2B0a%$%`uk5f3c?0uH`f(A>}uvE>)LLGg9hb+NRH*8;QWm&fb9;5ax$BHaW$Fjw&-y z?-z^*WJQG{EdCH})h0lhPOEc!Ol0Q52xpvZ^QosC3Kk$l{FA?eGRAZen@Wr9VLh`O zq2(_N#3pm4B#IFbva+%o4L=tdxHVJLBpcuUM=v9`1h`VCR^}6TE)$>ZYx-MtH)5&$2SSk!e(t_3syQ=~m zy~y=Y4=xJdY;qLY8@C^M?ax%{@+zUDoi5)3NQcBfyt%SxZcA<^SGZLhVt|VM$x7to z65d#`L)0j7Q?DrtNkC3}OfDHDh<7OuKNJ@_US9xJ{UX;t89M@l+D-QG?nS-j{jrCj zRxU_+d=d0OI(AP1{D_qf|Lp1og^q)fDW8L)aulCbli5P>B~fJQ7EPNbR>xIFwBF7Ffc2(q%x}ve~Ns3`k$UL1c@9Y!mT?kg5X+(es5=LX<6tyWRjTS zDwSdSnw-S3VIqa2Zh$CCYO0}gzTq;|2h9?rNFYsc@ApZgX~UWUM>(^-fqdq|vStu` zqW;n5ckR#dTgh+x!oLOMQ@G3!n;%IY`9p%2I};c5kZV)khxNpdWNeBE%y!eSOgNea zQ1y9=(vi7d4rx`xjCs|}j$^xp?2+~ zEWx(d>^RC4Z8Uj|rjS6yvYDqe{22~cJD!XBl|sKeCdZe9QzgBQ6~2M~{QUTIqJsNx z%Meg8yFXqn803-OCr(X-F$31geCykkv0IO@(Kd**J_*FX`1xi!kR4GUz*zBsWaD(` zmzfyO_bn2KfY-$YoGu^po1R1H^GyMuR@bEXen0gaMK3M8*7EjScP%iz32UsGOOaf`q3f%=>lSesfOhC>vjjo~Mj}pT# z<)UsnY#EUGdo`x?BPjgyt(89sdj}5gx9hiMI<6wS`^w1vMI{S7L|^HLilvb{6H&{q zwdPjds;cIe)g{>6nx>3;stu3)WFVF3=ofAExyPDp+X1YYHQ{VsJBDA*>I_G>7kV{- zkYT}H!3YdkSc{L<*h`zY{QFMuR@a_C9m1x?Cat(j=b=MO(oKd{CRfktZ@Drn z>cljqg8s+?$dbas`by(gTu61}KUi;tdw3_=NvZjOA_6Q}Hn(@3zW50-y|%tW;%E$|Hhao`cACIM~(u03^6koF=7wd~W@-!-t; zd$8m?F#Z4o#w1Cq=lLHq83XVdb`|Y9>02?(D!W=VF8rPVHGRvBAy)hBSVDF{cCJm> zrYetj**=_eD$MJeZ2E}R`c7dL;%^^zH&#b!TBR;So=9A8gWX}^9QNg0%d)6!y?;J~`6kJuL z3&g@6bCfOO?mxJdLOv4)3y*XgIA%xxsbXiEXXtNszzli;-C|p;zy-r;6z*Q#uvKp@ z$UQBa>7MC#=H>s<530!}A{hxXsyBllYEMUvQ!GY*#r)NlY<>q-mG#(N{b=a7PzU(P z#0d8~(*K?uqrh=lX*nuBcfWW(<5oq`1B0Uu<_+!$uFC?Fh5Y(N7YN5tR{!&D1y|`m z#^8`QbQaFNsXoG;MI5`;o#O&bA(*YW!?~NCmiUUYmehPP0`6d#z8y_XmnV>WcLJ2Q z0y9bk?q`oLMS-I4#m!RPu~&%G)V?)F zjke56kA5!`mM)+SVsmg5nf$>PS*XE03q(2t^=VEZVMmB@SkUtv(8CV;a?D-|Z!FSc zJW+9VJl!9>=QQoSP02OUaeKSr+M7*_u_J$dBbIp=K$y8kIf!v6{PAWN6-OI_Voc>dd3=YEjj=K0$wAEC1-N*6)U-pBpQfxV)vOf5HiI^C1vHdx2`JjF) z`!&v2he3C#kbMhpv87;d?BILE(CY(N`Ml%;!!}P$P2-2*cd`dHDPr0IR61}W?UIC! z|KkGOtgi`ULkjxv%h?7yFqO9lpG8ckeZaGT#Q=20L+e}-vQ+{lg}Y<)s99?79My4)Y*SJHsUC70pytZ8ml1vLeYiW5IZX+mGHUZsc#F@}H=GGaRdd zT^0An9$fo};to=K^7mMKVPHXjyxGQaO~hmExgz(b(Z~$Qy^OWk=gMV_SwSh(Tf+(E zHo6s57P3@lXs;W7bvR>KQftX5>y2W=4(xgbfB2NyoZK}8n-YGph~g8me>6dydc<42 zOK{lXjLC5^$K5{zVS^1D@SE%4#vm5OD)(@tVe-~H$r9c%^BgWa)-mR&?T@6=mjV0Y z^4~Q5C332A0FY{7c5?FoV9h%3-a%e)&aTowwH@>NDAf>%<&Q{AW5E1*UsB#(-_I@r zA_bW4Td9DG;5QnB$7HZ{8d+~##mr7_khJAZEBT@;?ST5Ct2>&0+kdKS&hq`I9H*hr zkt%FAf^L-m$2MY$)~x;qEr*{4$bqx0bh@7jKL{ZHN$NcrH0@1^MVmgC$(GG-HvVwB z(Z^okL1Gx~?xkU%DSkB zR0M=?dzWl3H#OPMmIDd&WpML*$BxKzoOP5ZxkH=dwOW&o?!{Ly^j%}&4X(qeV2z8N ziRa83XCPbYg^Yk+9%tx$EgX1zdeWt*K_i$x+qsP*Z(R+MLNXQtis$!ZKY!j^p1q^Q8B&$E~qj~Di1%++Z_B`EhQOeZXyz$^5 zZsyjHa|1>sxV%0`8s6zVgNd2#+E$&5)-0^7q8PIzb!;pwBCKn05JosaMJNf?1{4w= z$I%=lcIml-jzYeG4^NVNS9Nu@1kKpb0@T-%p8tNmD=P-J9-L4_c>miLdtos(@7!rm zSctg}O>-jZ3p|UfC`1dg0}{p-K?pPjBI}2#t#u8fkeLEHY#?C5DC}U4`?q z^y1H;V4c~5X+VwlKdqV#6~3J9R#>prWWK0c4quet1;l0n*2iW{i3$!PT%0%1bPh{` z^$ax)l-wL(H&mM;=5N|?dJyO@$qZFhI zUA|O7Wc`v`cZq;&?EN(pGFB#+$-Ri6>_Bt+sI?=7EstcV}g^D^RWtInpg6}+-KMLU&hR+ zs}=Sk#T}u@C8VnMr^BDms%39@FLuLeSyH%&Q!ydS=>I}q(8Ub=uu@2h731dnNnjVz zn%1hy=a$}E0qD?y)q*}42=g*{Z)*m?j|4dnvhprEbECaeK#?#CJgZZN8WVRP0|TBJ zKw|u0KEif*ZtBory)x~Fj4@JfMBKLbi~YPX>YL_m-MFIYX+<9Ot+Z?^@T{V^d$ zWfLfe3bpS+sf&o|rj=0uR#`lhMq{4l{se=E(<%!`Lln6*sdiWWdznm`z7h+9Wu_0p z^w{QTuqlGx8yi317!lOS#DP+kA3oV+q&&bTr*lY1NYE{0J2e~DS^-e?-A+CnZ;=mR zLntRHdNBn?qjCgne;}q;G*vFsVPL1M;J6#5zX7A0xk@{=z6)E-Iq6aW2C*|xc)912 z17)!P31=oZ%WefetZb!4oc~|jjhFqM@v-#ZPl<@D_9^P-fB!@|1sr~BI%;yMv55oR4TwzI;e^0)~LSPk>B1I%TchoOg01hc#$ zwJwl*c6}4?rdX$M5HrNv_(Wy|Adk7^8V93_Zhi=Z3^ePpFJxwu9}R{@ZC_w*aDkmG zoz$}b5m3?Crg5S`8h1kIkEja}8!tZ0z8Wtd%BrHfrB}qe(wU<{0J3{F($HM&sFO6c za^sRzW}v3lepJ2~3zt!p{o#K>=OkwrHKvvOAVN_h`az*waUU*WSRg;} z_UOu>#+S}tD~C2Tr1d;q)sbhd0ZisQ&m;bg?}|ju&0ioeD=^Jc=I(1B2oOAzC7Q`S zyscYe_}ZvDR^Ts6h%wA&abD?nBJ${OrvKSgFF;}lZc+_`AJIP$h>V1ctirBjJK|G* zrDlJ-pdLOJBE94rBzf?ATcbLElZNb{+i~96hf^2XU+<#vGs$<{w7 z6B+g|D(PGDC>dl~j8C-k`}gnd%M2Juq1>TB(Dcu}UeT?gB+72AV5(uu+?@_f#GGBl z6za7K#K_*1rCI}5fnZLzcF0o~P<}UF?ni*-vnTTp6prjT;EjH48T;yJNY>yDo9{oq zXhpCk<$L5IWLfm=UVYIRB>O$_3AgH#ej9`pm+oVFa0+bld2M8D+@}8?0n)CKEQDZ@ zp)nlo#jS|bzgpL$+;Y%P7sdIG?`RsX3^vM#1hpoeXZ|qic9Y^a6=3Xd7G93bq?)fa z6$-d#E`>mDw^IZ5eB!KP(x+x_m{-{<&u>vHMzt4UWt2xVSqhDfD>7X^Svf@~xqS~3 zsmj0X8wWYI}aqo7n$XK5Hey7c^&A1bnOJ86VNw^ms22H!IebZ%LP^mA?_#+ z>s)QSv?U7)qQv>1)_JAx@Rk6Ld_IM?OW(d~k1qDH*2D6j5lFfuk2n zBx(2&pMi$}uB6v2psiwxW>5nn&q`LE-46tg@8oF8yXFi!-@CQ))R5>+fXu!#Nc*CJ z!C~I~4(^6LVVfy8+@xs&X@T4E0#uvnVXnU^<>NAaRFOkw{lzc)p&% zXg#LZVIvS24E4N(rZQ({Wj*6~s+Q?gXiZ@oaru7B-FI?!{jZDr6kjdGJJh3A6JWF0 z89w6D?(_2?RRxOv$3OGLu@X$i`OXtX@P4U6beAucV=ORFcQgXwEITykCQ3(6{qG~9 zAXuSlE>cOp`0BwZsUs}J5=FV{?^xD}a+0Z!+?o4uG8I1HlzI|Fn31QauP-I&vid!^ z${{>>4s0+{AYeaZG+Uv0g6*_Zm7JS~fLZso`kb!tRbEuawa>_WEfgpgjS_O$ujrEu}4t@Uw=-KYaYk-&g+h>9U zRcmg}VdVAJGxvJuN2dc#rZx7sAGW2C!_?&l6Z96T{ejNbvpZdU-DY>xShwYV?t^8@ z>q=8^*eLpFYh6!olM>U26j|24`<3Hy#Qxf8G9?qPzp#*r0;MC?iIrM~D!d%g&X)^7 z)GSD`^~l>Ig35br(H8a=slf9Xv!U|Pt`=rPZ@=zc;}BP)PbJm>Un0{dW|r={A-ySb zkNr=;RW{E{tnso{l!2Z7Q#cYHOM44m-}$1M#y4X5RjXfvW9#jIm#cF|5PCl%1$TM@7c3+NFVpTezR4PuJ>jYsd}LoWw3%(p?GkxCRw z`OD)%UJK!oXM6lz{l@|@P~wCO>d(~acmOecd=q8#9XOB!bYp(AL&YOnclFJW>-ARA ziL^ypI&vsIeVT|S;?2GDLn2tjMePXZ7?kLC*B5~7luXDneemT!Un*b**L|@|=hVm+ zOim2t1y(&DRfoop_+n#I>nS9IxRD6M=)0Ch5$IQ6BDjm$=@VB$JtT3*uUee+0u=CG zo_ctl@OltpRpItys&=dUN1j{9QGA2bNtK8Qkw8wm% zT6Xs`dqWvcWq{u69^#K%4-lZ1jzI2;xlfJ}n_U`GXxGCG z(YZLL$NMAzFEu;=zgMCez?78=rSI)#q{lJ;IEp*{hW+m9v8Y;d$@0ija4+38m7v4# z=sVvb6j?2RuIFC>F^y4i6)0b3p$Enss@#Gz?cFU^;eY|?xpl+49btps?spBcVDY~n zvWQ&kCs2Rd!bc3<=6r>I@th&fHOVO2)GO zI?Z8t9xZ$M0pu;fnb0o?AGq!uOCUFv+r#VtW>tYpDO8;~?+!d80(e3`G;;Wp%A}PS zZS}T4D@J%po_T;XP>gux@($lV0 zA4Etse`0#jCVp_CS$fbS4xMCrPrxXR;4N|IWFiz&h%gS{c`N3+p57hO{rSpg6afnua(e@23!S;nT<@z*qJ@i@SV+bw7pMT!FMJ21I#bTim?I2n_ciHwr z$a$~*NTd0B8X~8(?6nr^oGhjyyao>qOzg=r*U?Yl+56#SbV&S-b9RY}-h*ajHNOWL z$R=5ah?#*ad@)P;L%X1fccP2gTjt{ZE^ojG-$lq3?N*>yf9uwrW~F?xK8%>MIf^(v_-dI&=*hqB95N@pJ>QM z<#Cox@g>S2Z5Ur)kpsn}dAHC1VJ6QKhcRH)`LNhPy!;Y~>z$FX#R)phlJ^Ti z9@5w3zlP&xHPG*)t{txvxIGC|eZuc~e_&2hKM5_}FwKjG@0z&2{1=65zrlC>c~ znG4?rtaq5Ny0KR934`&g{xY&-gp*IUG0MC@QTa3_)(A*1%(+|F z!YcAT;K1f(|97aKfq$M}GU5#JJC}7uk z6GDW%b|v$$_`G_uXYk;D zyJ^3pUB449Fe&R0DipaQZ&Z&5T!g{*Sn0J={KcjmfWrf~8j@;QI^aM)Pf&3G31i&R zOg;4U^^HsMQ51u=92yg^rQX)BgJY?lC^sHK6>Ota7Xs=(r@TvEI{`FOq3bdDm5rUl zE&;Pvtz8~WJRG@?>}FEW+<^8;{)Aq0WT|!HS~M1Tv+Q0kd+iOali}E$U`OvbwVF;j zi|)4FG`6VN?~rA(=v_VBFW-9i&y?GJ+7jI~i(Xd+2B_Gl&zwa;sV<+UYkueecr{E#FC6niM>k$(t9^}Ydj!8Ebm z{F;(N;&Lf+f@1^#CuNe1r!LaUecjZcf(Sx8(W-=EDQ?1iVxuQ;bkJ7_S*iNeKx`um zABBqD;=J1UxP(C-iD8D4f0>ehhuMc*sP_M<3Wq`{*9RdPtwVpRy26;{t+!xuiaPSk z<|;~nMC2@ZJvh5=ad4a5^$MEja(nY1;Sx>)c~6F87Yx}{{|fW)RZ#-Regfkkr-t~r zs}R~4%PES1>sMdFk5sqYZ7I;mI`-fbJi&Mb%>*vDrG%MfRmKpGh#0EK;(wy_KN954_ivPojo+R^K*9~$w$KLelgNlJNbF!09nz0 zeiX|!^Yyjh8iyqNONUa{(BLiu_^qm6JsSRxI-%&>+NT+yyDHDf%q%RnRqp0@>+v{V zWFZ9jj~|JcDs<<8g0t6P%sSGemOFD=^pgbUCt8e5Eph%jm0!T0%*r*3Ov6Swox*IS zYPmXb@{{&_%?kd)v23>3!V-6WC&?0^&`a72W4zLP_fD)4Xr!h&Zs!cl)(R<-&O7TC z0%<|d`g38ug)cWux=MrN-=7(DODzq+0OF*a+ZEJ_mR|}{N*Gy`pjNcF8afB)mu>4S zjAot5d%s+zUldv%**(ITz&$wDeQpoTRcOL#eQijD+nS%@{cJAGL(eRVbyJ-icJaiR zPu=D4v}8@1uA&|1<%Y4n-RWutt}!T#1i#}dPtTucD7XK*Hyw0NXFJf%FVwv%K4WXO z!6_}3AHk^O6n!^a!&dG$T0!#={ET4yCobX@uRi%KMXR{o$Mp#8faU+U zy@(;Yb20J^h!RO)s=A0lduCzV2#~vAeI}&Pz||^!oU_#X(}NA+9ZAtEc2E`q81nA1 z`yV^oD1@Ga(W{FEOfw=i~5a~Owg+30fmh)Xpy3^M@is1fi zH#5K{Og-geSL7f(#0QBXi@DDs0{=XU8l8S9g$BmazACy9k;|8()_}X&iJb2dqHOlv z{qIj5j(SPvB#ZYpw;Rtg4$66XolhYVoB1o`{D!W$8~`+|oW(JMC5U`W39$9nSvWZ* zf53yRmz7$9HXjbnN}(Aw4f{k0oVc16OVQ>#lMCg7n1XFIKNW&~)hsOD5(FrH#g{@=;ig^w1u<)fT62T|uvIbN zsQU6#72g08<-)$wBYo2U{#%`iTr0I1%fz?LO*sMzC4cpMcQa>!8BLAOKk@9OLVus+ z7>MHX9(p=}d~oYd)-0e?*~stc(~L%OJ^+?x(9DY1?lmq=KKUtwKB~?qHKr5K$+=W( zk4fk4{D2wJtP~-CjTd=NDESG}DnGD%3v-r5cjrAO*Z$>?v3Upq{K8t_n#m@to>#mS zD6NRX2*P!H!KEc9epw&?Ub-Loe0$IMZH#H4LtyJra4qhYdNjFV*=Uv_$(p*%RFiy$ z8IM`o6m)ls3P_@Mjz z0#$d#(8XV$L5Oc?H4$(&kh~1*&0!4<4GX}zD#!o1&`{AcKy5+9L@JaP!_;k3G6tHi zDYonKU+RrsGp=poB21VnlWXbse;DEBQ69C@*EZLBb1}ernXap>{MUsu(dsqX^(sfh ze7FTsKMi$gs37f_@)I)|h?1IRs^3b*&@iYjS{^YIVjKIC~ zF*?KdDq+X@>H}n$Z1&V8fv=Pg+x;lM0Hz170E!(H!TVQJ zbQkc0$bwMlj~%`xZG3m);ZY8eI#~gPXdT$I`6rR~RWyog=)olbam`H;n9h$j+GaTK&~SF(byt2787-WW=PVBqy%;5_y*z6 zN4Un!nJf+Diiw})*?SdAxyyfeXm1CIhAuZey6WVu`VJXP$P;S;W4i7=!@d(Os(ehx zLWaJuXmJ4@qm(Q`VAi~+Ge>qdCP_Bw>M1RTt$_9O(QkxW_Ef@fTL-#1K5b^P36ub!Cm?mHqO8m zF-T))-w1ik-(aVDLVH~eL9YWX=I%P!DXj4ZSCmv- zcrDapHaI55@(_+|EdwYe$0pk%>WTW3cy}b?RX5InJ7dnkB7^LOjoszpLdH?)O`DnF zruwcZy*B}H6zKW8s5f#fJ@emVJR$wRp^0O3>Mx(Rlz-vVOT4ey3$CHlLu%AvEicVI zJB{UP3nG7EmszR*;ZGf7xOjU^5thC8*k6=@b4Z1$Kk$Jfb_BCGvD`G;t?~c30F?;W zh&f!nK~l(~`DUT0?|(L9mQDo9eE0?tvM&pwhr0`%LLk9#@uL$4^PC$u;7cebvdnOz zru9axZ`EmQ&2{S8bso-BKRvth+T?R(`;YQM+STOoQ1x|mal>Pq2CXgLK6s*YF!|>c z9mf*le5D!D{(TjBa4h-v9*HKPr;|Y3N@bgFk7x)oo8pLRL}c<99B?0eJyrjmn-u@} zIE6dj;bq*$1|klN2}MeLi2dn*RmLTHX$O0jRA6vO>_!%36A3VfU5yBwmtZRTO51{;~3mk4zLwa`dDk^be zyUBH~fLpD4W>8ruXm=HGAzZ|5CqLB%rTTUQ%lm5RHL{GXY~KnnPxS36vKGRR2Nd{} z!0rtmwdVW$;6P^d@Fli1o$hPuK{)Vib%1q+86G)b=`=Sj@Rd#g7Tp$Da95B9rLO?c zb3q+ysd#2DjC$F-{IC4E(tp2OX>lf-D3X5m4F#@@=jBBy#rsc4ipk{sJDI>E%JB?^ zIGYQd1_RhGvr(7S(~nGV^6k7=t-|d8|>IJmd(Hc z2+m=5y_dEVx$4Qs{8W=|YtVqncmUQiCdcQs6u^+hCpEX;aCmF}zfih*jE!!^lU0dI z`lP|!yQM&Iqn+;Al3n}86I_K88raf2B@!VNL(PUTW*VSA=31*QedzX+wdn{3$nJw5 zpp#UR?fy&el&DqUVaTZFcPoH$59+hN3D$d06KwDXvrCl_RsIw!9K;5KTJ+r;)mnC4 zvtJ(%qKW22x^ORqQ;9EjgkpibIVuh9g-TVKBe$zhQkpgSa`HWNF#cpbN@*6R=K!ka zsX|>_{ks~**3~x!&MjZ(Dz$CsF%sfg-hKa6Tof`7CT3RcOC-OUAhC*l?wn9ruOsLWAV@rTW(Np*n$gk-G{e>IME8V<`PyR5(_tIqB6$v z2iUzTn7c8tmuN0O9IWTP516cScN*nOrB4}bQP_L}$v6WL%ipeJrDN{Jkk1pO)`dW5RZRsE9i*H$Zt!~8m$d6LY5Wej|V_mJ{sjT+#uah^5a}iBvaBw}__ewq-tOuRhV1GoIC@xNQ9bMZXfKq4sJQL-rVy2n@m zfYL|GJDG9Zia;O8Z4Pz^3ohuVuO)w`;g0Lf!Q`B~-IrEm;v&IzKgIQb9HNfv&b6tu zT%k(gQqfa+@YwxeB-~Z9tQJ<7KS~l!EbhB|F1z&U;65#bC=%l}@OJo%(3eZ?jF9hS zrXW+J6qX6Rw?kJ01LS(?Dwdj2qH;1y-)Aio28E%};YOoRSy`<;9(pxsEeV5`lui;i zzE6{}vD-U48biT`u0SGOmh&IF7hiqAT~NL{_+kPT_ZlW`Gm-RXFd@fhgs%NMUGszc z!D})5vfpkR`gF2xxpG9;O-oQF$L5ND&FAloC{9$yP(9o~Tfbye8(w$E^m0#bqf!xvR@tI(} zlnESNWQJcM9r4P}8^Y$*5YyCB7n)#w^? z0!u2jBF@xhX#$w@fPNO_PN4tRGv$K`3*i!V-U>1?Vh$)RWz@*EWtNQ3G+kUe)WSOpF?k5p~ zn*Z?Yy`gqdKxH75DaEdlL0I_4>5%Dz0#FF0kN)tJ5d5(nGvc6ack#LR-Sns8L;6^U zLBK9}$}GN4{#|RxP7Wv0Se0o=L9kP8&k~O5OU0;0lKxt!QH;zButvQ;i@AYw)yBcGtj5dZ zj?qf9qV^S6&4|ZqIX-@S_tlTTT^5c9P%8@kT@IjDC8!$g#Ul9=z?Ox^j?jP1Apv~O z`R9ju<$}M*9z13DZIiXG{+BQxBL2Iax!x4qgIBYHo(?mN9%Y!ob3TYtArE2)y|+lt zNui&i(q7k|Lv?vRGZgB@?2U0T@!-g9LC*ZhyHfDh5OWiqgHoJPgFjHIn&kioTvIu} z#hU$FB?l)E97K@7p?+EtyNV6ubK-zaxIvnT%&{Z16}6vU^(V{VZv-wZ3>!}TIu%i} zXg@1p%|KG|mRei8Yx+?;sFZrJLi8`r2JI+(ViUBnG_pzuDhPXo#{O+(%g*A7g5;|9 z2NT&wisj72uAnemp_QLPqpk4jFY4dDnA7T#Q}-7>@`rr`og3y81pwnNBJ%K@>}p-<4fobs((A`3 zrw=$L&~}>Ea`#}7{d9RSi(UwQt{;(eR)mefb^q(<#(E0cxZ-~WYmS#WAJN>tztA~) z+PW#smojg}mNXg`n@61@$)48EriHO!H)}@l78kS|tkD95| zMt)a1_w|7?y&11O#R~UF%z$6`Uy05!8J(ZuFUzr9#)9n4i~)OLkpA=cg>cp9?{JqE zzvm#tk^S|8ch1XNm++J7#|Mx7tNkczTOHTdHN(g26@f)Nno^Adz98X$3n}5;-Cw+8 z@P4oRJ0i?K-?JasW*S^`K5gNXng)5P2&p_uUVrJQbX8U?QT#nMIXPZwa6(~zidN|I zr#A_h{V?diJvABs=vESITn541I>*g6^#uu;0?g10>HZM)fp{F_%+kTPp52r%< zudjp%Mb*K?SM#;#`mwP{N*!KZVJYk$NG}O6%bb!W6;N^orS>GJA|Gm~kqQ;*v__Hj%)8dB?_*j19xUtlMXCb|}fOTP# zT12&!;GLWB*gwUO4DFYdTVc6Hd#Jj`*|auSG<7REAHr`(yU5bN`~>|8C1eLo+QQ8<5P>w$0Q_8Zo}A1@@bfq?ic z9O(}`=O?IaPcYIi+Ru+rf1S4Tcon0ICpZVSRObMlPK9noe6bdLKkxCCTvpjf61OG@ z&{Io>g}nq>^)&|&C*v{ zsZcXrmHe;@QJWI4VI)qy=2pmYjKXK3;e5;t3+WAvFBOodBFOQddu8&VgJR7arX=t7 zSWmK4GG6q7*6dAc1ZLP(kZ+>ppr=?`Qhx^qXX@KV8yg)vt)P*3cLF<}k|s6rH7DO{<3 z%G_`z7~dy3MXPX^S1Gw?_}o{>)wI7`7>_}3QH&xIG1?d%*Ic>{G_G*A*-c?=iTIj5!%Wq8(XG*N*l`_6%tZQpB|C`i!iLMde~t) z)bDOcaBQf7TMU7o7yXSUSdu$GEIT{}Fr}DbX^_%R-+rZ5&i5ev)5ftA`BHz5TMoV! zW)ktv<>3Mfk4Est$dde~Pv6GwCgELk(qHt0tEsdu*g8bQC0-)A}>9C2^Z-RU~l^dI1?Sc zB&bjDe*rz*`DPZireMw)2JXlobuTnzO`UcK&(Unf$gx-8D6XICK>Uc12J|k10rljm z!i~_dBeK~yy~#dF0={`3Q*F<5#MhL`wD{(A0unlrMCX9d$ zFGGYkST=efVkYv6=BV2JsAV(*Sdr9`qKxY(Tpy!T?iXEGGkOONQLJgqML*p>iDHe3 z0g+r(tL;YFeVz17a;W<7Vm6}EE%{Oc_Al)u`f8oq7iAD2%eg!Db!ZTN^8kZ*OU(~n z1hm+ZE=ap7c$YA3Sow{knm2wiE@#`S3t$= z<6%Gu>a~eGMVZ2JdNIU9zLehfVLy}vTo*B6vDo4BUiqADbL{{_ZJ0q;pE$l8JcpFk zr%QNZB`8j6)w7FkfmVAR2d&yC1D!M4hWbw&`4E*KJlQnKId!AvRWPcw1V|K4AlT79 zH^;*tB5fML<<3!p<@pz1e^jE~JW@QG7X7!}Ewtv&cyFe9=ahQ-6clC;X(#YV(~F8T z+<|@Uef(;re@RJBC1=^=HGKsUOJL|JJNDZYR1Km0v9e=jL^*v`rTg0FowXk-57V6Q z+Vux%1FIa-rD@tIY2ufZjn_ajZ2olL*4ZmAT}UyFLrTTZ>Zw2aY=A5J!=^{4)KOd$ zs_O-Ju%6=rq#qaGge@WK39T2E8E>{`#rvDvYuEqB(^rQz`G#%Npp*jvX&K$!B{)ht z2BSwym*k`sMvEYw(xbbiyA`BcN@+nr`g{Dn-}~+#j)Ma>c<#FH^ExBogn)Dvfhu?i zqL+k7Hfg%Zns<0Sn(XwFHNQK_yY29$>;G+OBM^=$|Oh)D$?R^o4lym@rG$%uZmn1nTsr>6N zGd-{+kd*>YXc~Mcy#D}xGw{cEx`x=6%UIDbfA=}p_B~q3H>doSlDF2bsds#_+t}b* zbr}AFxGV|i$2kAs_!^M`{f3Gf3G2bF7)kU~&OUGlwUy!`Ko*sUlHv@`Rih<)rRvFX z7wZNjC(et5rpt~n-o96vx-CJ~DQx+z%Yd%*prnenn!>L=N4cl`zq1Ks2y@m2YClPO zi({afq4@UDNMLU!KQKq;`=WOqs)%PE5h@fGCAla;xyu zkrNhMJj(YrU1NQjqxn-mTSa}Uwh8zi>76TajpBe>XnbK176~h|c^_LkH!*U`w*ous zyqA>voYw&j`(^Ye$;dBc!h1|^0<@EG?aE`zfkH^I$t!F^Rzb4CRY!Q-2g65xC?Lsw zUdm)?lRqWEgUBXJG#>tujj;Oi(jAuMAwUkFo3#rDqP;b@hX$Cq%VJQKqzT5s-Qd%D z6i?Mc-rc!-8vVG&GpzYLF;drVMndg$=0Q( zEbjX7oJ*o{RiHv0f_5Z56v}MnvRLxv>Cxp`$A`X)xWmR2OwKrsqgSLFy*g=}Klq{2 zWh93>46uaWMKa;r=sM>ixPIt#@g1jju)^b<_mqsJ1U;W~AC5>~8^FU`K86liDrDz$ z#grL@3ms)xe#FyePj}Qi7rCsSp%;u=1$;?SbCEzEE9m;QoryXhPU53y8ur?nn#^B^ zeDoFXuC+P~^w|~g$*b3+INvN-#eX`|)#^$w)wQ4RluhF{o;q0e#4g^ebNB&?N=aG7 zrJ@a}xArr;6-D)|$Kn}FUhEYt=AVjrpi7-E(w zY`s*|$tO;>sh5YWb`^ZQ$aMmJJ@1l6r5pFV>-W*3T3?i-T}O10f<2PT7{1|ghWeB8 zF=-3Rm(Tkby4_?lg6AxEztjIEzPNE$iCWQbo+D3H^jCO`w267+{=h0Aw2H0atz$T- z)gr-5-!gYpko-#mx6M{s?_83N9Tud>d`(;zqxE~03V?gohgt`#Tfs^#o5F(~qKV%K zJP#_AYgYbwz!R}n_%fYXDL7BN;gSy}88U`luQ3AAr`~PJRb*$yo3zjWffzuwM%eRP zC)VHExaqJ*R^ks=lMG|N|7EggV4BMO6*`~AVxo!nUhMZusDqWMEQ%&qcBKx|{;8m=_&_Sl-)*Y^@zV zBtpH~6YVHt3g1_C37MUdOc{X%@DdsPsRWV-|I!-W8hIF0s~b))tgB z0B(?E&3Y8YV;0j++ymN_#5fPe?VVdSjo;T*FQDF~2A@84dyVqmxB!!279o`>aE-8Y^Da;98{Qk&Xes>^<9AwXw z&XCBG_;wqL|GYO4+|%%q1M<$6!bIzbv3V!FdrN{=qF^Z>^)`;o#yQb9mm=Y?nk#Nn z{*c9DAaSC3kv`Sx$VhF3&BOgDSd)D5AL91g ziR#_z%mR1YE`y2RK!tD-{q<>54f6o9(fEz^{pS`g_IM8a%l@WmWieSJ zA?MzooY_S2a+9*|Y*iX`s-rv3jt;N4zdbI@ArbO8C;WUHO14e9t^!&xgaSTw_pqlY z788GEFcYW#hUmOZXf3%VuKpYu#+R>4AZVSnzG!1bi66!vHbb8(S3#}+>^E#o>m1un zh9%(p;NcS1bVLv+QE353HOmEkOYd~KS19&p1x2`{5@fzRYmNqv&*ksOTD}g3dH49G z9*oex&{P|hJwOxBnEKJ7ZbDyHgYlm1_j8eyVz@?_9IU2aK+zUddOXnbJ+=_f)9DKn zxUB`Zk?v@I(BfMcJ=~DI&5G(l)AHNoBfB|J<*`d@zBO26Z3#Xla_CMX;Gz*X7!#+; zucQ^8QTLz)q<)Ca`Hc8;cXhzt_z3myBgTIEMIuc$3d&LP&K$gy7d$NXZ^Xzbw*H9q z(WEjzRm-Uy9W0*wj_GMz@BLsW!tYfKb?tcMUZ-1?&KI(?n{8Z6$Wi&gkd|gG^*wh*duc`SGd@1Gx#>tMiAmPe&lUvMq0C0wwk(mWxH$rNRY0X@aE8; zd-&ok*ea7|l{l4g@9o$lA@Ol>bqqi?CCNAZC5w-;9d-Kj;zn2-Lf5zVBnz^QAuHoS z38A;>WWcOm8*Wdm4|u0j+7)7dErpkOU-t2$^S{83AlxsQ|0QnFO|r~!*xO>bE$H6%S9=%GV*9NQ$o|Y{AlqZ+n zG`Vw@r_Q{VX>J=yDe-)En_+nY2FM|0xO(%G5>y~BSkfwPl(8lzY$0`1;I~O*=asfSg>rW!W7iy>U<}zd^s3%(}_lba^RpW z!kWaOh#qQ4I7m)NC2f}7(aYK&Am?t5LIJbY0@gUcq7wI;EqP-KcXauNuo?Rq?eOEs ziyIV@ps%3%qC1m00tlU62!YR8NEJ57kx0d6NE(n9$nHR7h)40npL((w=&6a}icyW0 zlR9-=0uIW++$Oq-)f*W>eOeb#)?gUFS^QT(WOoX#qW{ZDr;E4K)vmZE;nnm@O(~W# z8JPF_xmx_eXJekj?)_V-O?7gfE9~F^AIYc=NqTu;&cj;YGEB<^yx-BYhekd>x}@WF3wn8Gtm9IFRpWX86_e9gPefYbQ+m_yB*lY> zE9@6ggQ%ezm~B^aD%LBTsN2JEvUEBI9S?~HeoS?WSFxTsihEp4Ffw)wvBCDn9?B~q zFm~)@n)>yABlldc~-OCSD4BpLegCqiTXYQvY#vnMl5rTB1Xz~2^ocR5{I?iUtH!UU4tMbIN@6~3Sw zk_WEsLj{QyXGk;$U~Io&Z%+N;Z$F@8qg| ztMc=~oS#(-dd2HqnPNp03JIE4HqFSVK~Z_hM>GXQ*c3u3q3sl-UHE5auW#&_(#)aK zGPP2PQ(Qe*WVVSVdyMlwFq?ta$D<>vgNCVCv$3CkO>ZtNyHQRI*T11?M*GC_Vp_=b z7B!RPK$akqR6+4aNx0VRL2vo3f@2NyU%!_&)Qp3zPhmegD0Cad@k>Y_>nwh?qI5&$Ezawp^(=maLN!>@KkLE4QLoUP-g~Lr2lvO z|8C8;qoc=3Bj)GFh%dIbvz9>py8Y{sPi;rZ2hk$wVRu|}v=>>6hRgoroc`nEgQLsl zo!rxtRrt1NU(XnQz4jPAf>zrWy`!l<8J7}qnu;jA(mUr&v3Gm+NvIya_|sf>HNj1o z<-HzsM2f4`pV7w(G%X4b|D9hwG_!Z|o`pS>P62XlIdG=}EBNg+mM19k{Xm|J>gu)H zh-#+ZxF0A&E|o)?plr_r)Iyrr8AZiRTHj0O^mz{c3>5Geum96CbJY=wAye|jWD?da z5gajd2*#M$t#_YFLJZfdd{pAOByRK~&I^b)_G*_yekPT}HF&4o5PuBMCQmOJ3L6J$ zl9f!?Y(A2uee=~+K{c61ORVbD&>6q-i%!a_wYP69P+&?nSsVX8-5xudQ7w#H(2pYj zbQx56b75?I-0GM%X$suRqbPVAFHm^PHTe#DmcwThz}k!)3JR7~unzTP^A*7Wa>zUd z2=!;MGydy&C21;Wrv*Mc;Yf~5o_MqpTU#3r-LQvKjOA6+2xiNE@{W%U#uxK5g65Rw zn&Pk!&od40oTuiO4A4C95{8MmN$~XUxQBrf0#m(c|H`J(Y(N^Dl{g!aJWJ!6E zSe*_Bg1*?+`%1#zGP*J9BlxAVFM|Q=N=AxOu4n`i8$jetP&Y>-jvn&N=o#Mq-|NnO z@z1qOEDiA=BLd-7MLeqc9OZ^>ABXAFs2~+%i{&QmF)GLL#d7UB!YKx;l$?XKZ{>z- zTI<&m+(iQ_=*Lt05ILPZf*pwXs^|l&UGnx%>hnDL(v$Fgl#Ne_(@V-2y5tDKuf7 zzAHTbtIGi85Bu3{6SKh+#X&zrkr19ry5+ylz?E23)coi#M3-Xop73>TLM3n@Sy``$ z)TC3~!uit0inXP(fCW;6wd#-i&q#SC7r{Rtxx zi=J-{>)H*khhJ$61<5F!>6VF;y}hzoyxVk~t@id`Y)!wcP)}6fSok9*UMbS`4ScE~ zVaPFw<4yon__ONLPvUoZ#}M-YFTnY~DY%}o7#ZV@selNdm+D{O2BVJH!J3%kdR`BE z7j+EH$3IA`)wZJM(LDqI4ALlB{6HC9C5=Z7&R~yXX{J%KfyZkW!;T9bbl-1!VVj}d zSD=QOuz4}ktqeDY9k_Qeru7<_UTQ(;K0Ad^4uGlg!K&6aM;I}^4mPy6tTeJ?Y4c}l zNxS?F!6ENzWgoa4#?S=-o~$CkK6L&L_*^kln7;YeiaOu~3pmYJi|o%;RT%(bVB2#h zp6a!{l#@BiPp}$-lMM|G9sjY(qTUSr7iL*1fT3DuHSD@tKxQg=Slc}qv>#>%Ynyl) z8WlAs`1c}l)SfWlZc}OO>YTdKe(uv6`9z+5e)9LKIi!r_dGVyi9T|LKqSE zf?A(G7aWKdhd;xha>ARECdhF>;E~|hX61h?JbdxOzpRawT@qEPxRuJgQBQz4S@k9* zvQwn-Kro4#_}*JOLF`%wf#~c6j6c32s(R-+;Hj*so8aFlf4``mh=P(q%wT|ZLWD&J zof#=oJW?r`O+aSG+mH(N7W_$Xmg#M{x{tIm=IV)=I1k>{J73Vs$mf6bo#N%bKN>D- zPo2kcgR0417PNqwT8JtY;Hc#nU-kh`vctJ?n;E?2 zF-aLI*%synhXp__bn_$Q!_ExDHPY2o%FNx$M^_tbsc-ik)=T?5RXHF`q`qj)n$SV! zg;gA+g~kU=q!>VT0Ut=HlP8o_OT3G%x$Ni5 zpJR1r4D)1&x&{7FTcv3>wX~X?*NmlB1iKt%8kFtPYUy|$dx>g3ND_Tma_wwCnkrN! z?y2X!?AG{DsG0)Uk${~@l=>}e;&smXfeGym5O8ajmzS+(tIXGEasd}mfCJX^8Kg8| zS@W7I@D&8&;ptg5_<5)!uHSOTpKoMzR8j}Zi=_{|h2AOVBi8Q27j|kq>jyBd#_!H; zPgPT*Yw1*L%(=kFWqX1EzHLM|b$fdo@Z!)=~)a{bSqC!&%xr4et4m|)HaN&6TnA%>e5b{Rt>U$(tAc9-9JLs zdpZGb zqvWK>7Lu3!YY8Tnku{mP-hCqddXlunpa~sKovJZcVOoUwrqS^e*YlEaEn8wSp3)@k zq{J0W&7}6=_psOxl3BCTU=IvFTEU;@doEhXxZy2>NyR-NQ@sCo0 zR7eHVgR4SP@59T1y~iC&rM=dlkZ(M8|4@=6XNeF+uj5uWL$Q;Dyf^K!%JZDGj8Z#X zTzZc4B<5*4pBl|Q#`iV~wy_fGr2)}aUk4bb9vW2J_2YEO)*y~Uz&iMCb4z4x#OBe% zy|n8SUik2!avqE2EKi}ZTVpP_BhBJPq7SlwIiz`4K*9`X4SpTAh>FtI_I6fUVxq2w zfdpQtOlq>3-~q!aGgo`L-~~#;~MTsiR(7*TZobs(#1D`P(`do~KJo=9OkP+yFsz}ih$J;%z zkHQ3$0?nxKwZG78%zt?9?eXUxRZDF->R9XdgO@-3_~x<$ngS)Jv+>hK?favB#%5z; zbQ+2&*E$E&!s@WsXG-He?jw8AQafMMy*$2ZiurOZCE?tTsZJ%bn}S`J+BuZ%x;N+8 z*Li<@N|jLZ>XqWck9ziIWNqiJ#g0V?t{uiPlRj#X7(9hLuLE&tVarvmk?+c?q288f z)%Ivb#`MtX8Cej&PJH!ZWjKa&vf&Zcm}-n_4+3@NbS5bhs=A ze6vl#z0*!P2LnbrtS_NwCa>;X=EL@@U`(s>b6YYab_rjQ(#`L$0GMI@+H_NZi>R0G zvw8RD@g5@uA1gz)($`_q1uHp4>W@$o29VXBBg!?xiX1kuu_bZp68w0{JS0Bxdy_cU zD3eM*X%e{`t|!%daq70!ZcSPUC1U>b5F^ z(NdO}{oRs1YBYdzg|ELyaC;E5kX3VYFKK$BLwjKM>j^w+lwdxt7M&&1N&{1Ch8=v0 zdlH4xSCkN-e$5IVb~tc8K2oTw*^SX9Y4{5%z$S+$t-pj4PEv!XNIm~B(L7&BWwe5S z&TSeM5PMfk^ugZ6nEHTnqsNUrBBL#zFG5+o&jCSzVL6Nu2(i{&XM+2PPI`tAfj^d_ z`gsty!ebzJBerNOS{7V{kv!FyX+A|r4Jw^NVjvlI*ZCl!)a!Eeg$Ftl6}ng#0(7^d z_shu0GbvVUq2h-$kphasl&yJynL&Qnu1 z@j*mSOC5T?k=ZcoKOAe?y=1P|w^*%m@4^KRndeEA9u(Dus8vCL0dLS-t1r6j_7b!F zg}UH65dKlF+asVV_vBBHlyMf|C3@8JxpV4cN{Wv_QPV~72Vkj@?%cv~X{3QvzEbw| ziRT5f`vqj_aQc|K8r*Al@M*kW8ri3TijOpLDz3PO9?62^83zPHo5u?Ggm1^`gNNE?hbGIU=MTW$#9Bm z&A9$joqAj4zq%2qB+u@aYXfg8v%EK2JqKRjG%h)pTTt{xH&=XCM5PPd%+^Gm;=uL1 zSoj3%%VBytElKV^jM;x|0RgyjO(0PM+w)zaw5NumVW%FdvhN!o@RC#?;{Md2c`g<# zcE}972MuJ3Td=%utm^&T!1Cc8Qjn>}g-2yaVrs{S%Y%33qG0#4{+8sgUa#6ezL#2m zRIOJmM6alnYsVf}(DHSaiT|+467uU!Su`_wb+14x6d0vFe`|)`q3SD83 zj6b8uqlVQDC5gy`p=bG^6UQ zcS_fO2*)UTh^xt5b=@LYlMVUn1(0cKxz)TB5x0b;>d>qQ0oc_!D_3JabDOWmB2RhG ziqQ(?93o|EYtT@7LN=r`%Vmw25cRW4RW5SQv#y=JpfAs`x-G|yp;gt@)$}_jX#awV zBP`iv&>rGuQ<43aIXm0ire&y0^ayOZuR<0vnu>ve_hu-6*&P-C434MkWki4(FPy#{ z=(O{*va(O;4Bf%r=$at?^^8dZ?AZ* zN?{a$-53`KJ2{pdHPk}qzaUMF4j-LeN?M|0rrRA^ z(OBPoOzkg~fk(m6BuOr&Yp-`M4QfI6)qz}mmsJ^1hEQQn!Y7HX9%8HjMB-m#DQAaE zT^F-}%34>(xS6Sp0phy8`{5R94j%BL*zOcAj0^AR+C@=$&mTl#KWDu@j-@=yHv|v= zj20(3n)~kc;N4HdXCYohFsAL^V0;w0Kt2c8DRH$@yt&W2yS7w3CuY2BBF-}BJ)jh* zne2u&BI;pVxCM9z?gtU#y!xyQ-aNKdCSY)6`A3$c2GT;J57K;;WqjIx2Ek#=&)Sq` zC-a3QJ9+izs^oW-hBn?vC*Ms`*Uib~qb#|MsYh!e9r=D@C+TrP+xzp(z zSaY$sLy0-}pJc5WL%mAds*dFB87{2Oe9fn&RGYgRCtAGhj zXfR{4-uxWTBg>PCGM|5Pr{$l^QCdND0GQf_sZ{vl-?*HK+BI!n{oVXclV|}FEw#=7 zwoIi(mv1#X0Y}ZIYf;qD(1}CDiyOM_S=W_De4tOQvvF_ewLgs*{Qm0G;gXAzO|8Py zA8g`nw3At6A{V|Q+;t(@JkiA{f`Qr*d!8k%wE2J206?^%J;U-|*x~PI zX9hB{zZuzS7b^>}4l}$6Q0pNd`#?9YH8BvC`9NosP5V(>T}i}yGKnWt_M18EQ4y!D zk6O$nXpG%mN110&eqA($Kl`VhqOzrE0@+l&PU)S~7<wQsw;~U4V?YT< zdr=c@n}I1u%@gQK(6qjZyj4uH_0&|G7$m=ek$z>(G^k?dSD-Kb&gl5J%!Gp1>rL&^toXqw% zxB8)SkpHc2eE()C9`ug;6P6M4g=rOP`ei~aHDKqv6_=|+lNfllRe3cPPPLX87o#s%| z{<)_9$57TqCrlc8@l_(&%7>8;W50CLL>9Vq;6E^8y|;=;vt8v)uIk^~&^lo`Y*Oy#SD z%68Z{GRhrBur=N@PNcb$83LrCUcgLPmU^)g& zGlAgFd{h-&Q#j2nG5|w+!HulZ^8{nnts+MU5Xd#2D{b-~CJEI@Z@i=@0{u}P4 z+R@)*7#hAoQseta9$@J!Xnv3#V9%%l-el-0 zrF&>TW&t&!ix#yZms!2}U1Sr0$+$~u0hCy@@uAs@*#QC2cw4*P!h_UWf1w$q5c`zp za)>Wl+l`bSoMf`z~O`xaq^zKL5nxCZiWxi!*%DW)u=B~yLwS=WRPa;QjYzzx<-e*VX=_38JV{UuR#Moqw+nmV zbt6AfQ66zL7_h~vL4MSn;D>so6gt?6^y-m9%0>=#dU|*q#W%+GTVexpyTjvJ z(MISDf0q~F50jFR@SEmI@9GOp-HUO8`4j~gm!rFR>MKK?r>d&}_n~FAlEw&>21!C?Doqe#tR^8$ zTw#hI^Ka)+>ui@eD!sf&@Mu2rax7xri?>^xfoOn6HQCpfX@G%Dn6mn(S3Umc z-Sf|f!0I4&27TyX-BUT7RRcQ+wZ7Te*%{ztyjJRBuYqx8mz%1807NACCm6{xfBd<~ zM=LBToK91xdq_g@_^Y#BQEDLb`PyrL_R$XIDp4~Ir$!xc)O%`uv`X<6 z+y7olTJbF*?p?Y5G+@Iy6>AJpEZsBfvH=W3&kg}}GR4v!E(#zXJ^z2S|NjyE-v+?1 zcV79pG3Z59D~`&dMlr@_1E+}$M}Ono$MPGxvbv01-jhm{Mqj32Y1|og;fUZPMTN!k zqPJO5)&bng!aG_S(BZ|Bz21avLs+ufl)E^qlBJ(VlofN<%Q>IGE9of#x@JX4D-dx~ znN!apj=Glr`B1D|??>%<0-59Op-~vVNK?l?qp{D?$x?Sve7F2r8 zsWCSozINmj#Ecx$?!xYpLA4GabP4YOz**Jm73|tz@=>FO7-^H2o%z&aRcItCE zE>JAd0)W$*d}|hX>}kSsUnpv}|IckB)-{z}<9A$8ZTht}?I%P*zz1N6{wgIuu1T37j%)tgO4^eT~oY8hdLw zsI0B64+Q^R&0VI;fa>qHHVo#=?e?gsV$KDyrwkzVdZBl223Js29I$v9PH>eKt4c1S zWM}cqcByo4Q|`$D02gy?-(iz)Z*3KDod5uMX;&}I=(~GY;tY)=>}3VItSntAsXy09@O6QyU(57tA*{hQXgc-_Ni(ftF!-V-;lXZWYc$reJ(A@bonM!H<& zfu0vE8JPBXT|oBp?$+)uJ@Ch|TJ@Wm0q*&bHOI;pTW#SRB0*wK`RN**YcOzG1!A3k z&1W8p2HoExf(7#r8`lDFC7K z9^%wUR^-3q<^Cwna2JH0w@!ej6-}a(&(1CvaYC{@Ray0&CxnZ@2 z!F_FVPBB*jeBnB2@bwq3fYz+<*|Y8GuU3j04BHAmFq>C>J_9_kp)mw)%r7A1UdYelW4@l+9rxbUVZlZHN_)$9SHqMB)!CXq zH_+R^KU}YG-l%RZ*J|Ro(livJjb+qp?P?eWKmYvtU_-`rM&dB+jzo@d4TBiE(+oak z`ijvE)+?wiYI%(Rp~Ra{3Hl_#9~N~zs;zsOzLS8Lz-PY7<4&=`+-20f4B z_!GpdRgT(i-Nx*S647@rS>fm2i%a6>NIOWSt+q@DWH>YUe9n6jA;SrlX+ef28~yUd z#Rvbl45U6;T1mbzYMUcVI44|oOw^N<_*L*uO(znQkvzI^+~`s0bNXilYQXgmq3_)M zi&DUP=+ARJ95h~xEPQ-?^T(m^PO6fZQv>Zh8cV3hfU?IO*gPM!W~A0*zI^#&2-F$9 zJirgHwT+>xIqnY$-}ta&IdPyfsAA+*XUP7gp+Cw|nYdn>0wH_3!@} z%c{?P(?!*pK80vXDSd|tfn38$GVp^1tN$EzV#Wp|_##w+imm!uP?gUxBs^8nn$4{p znOTb3ly|nnfD-QgjjL^##%Y~HNxa~A-*#VRA*XVQxn^~lrG)Nki7qz0*LO!IPLC-1 zKgvJwM0D*@+#zIGazbVK1XovAZ5I7s(O09L?ibsSD6r(F`2U&K;hQMFL%uayai0|e zsspbB3uw(5!V=h%(`F9;Y5AVOS<%91aBa8e30}d!H*wv$6pkzOzUnI|(c29Knm#wFb%5tHyXSL|JrDSB z`QcEZpcCmtdkBFTA(iPt;x8cnNagpJA1n`;z!A|yaqNrMNM#?8xH6>iX#zK-0Lna3 z7KU)<1ZP1CbPLwvj+zmW$rh5g<*0l;FC;2EP9;hPLu!ZS@uMT$5v;K0vxV-gN&SCG z(MA#JQW#Qui;Z2GT!f^%&%v=PjS?=|mp;261YWa|Y0&Mftb69hqgKmNRV90OsOzAv zZdkJF=YRm9X9ppQHNymz9u627K&YaIR>8Fy%D)g(<9>qRX2(_=Yf}oJ%&f#Otdik7 zd5uURvV>$HmMj0OiSXl`GUOliF+@Qp&c%OVLkVo?sF0?(QCw38(-2LK;6fXrUby zghmXxXdi6%#&wC2kaKC?2*&{+1s|(~tWH}So7hcW2ylhK8*-0U8p{+vyAT?8{O1Z{ z_`~(@$wmdB3YjHb{ILm6K8cI&WloJiJNae;@DY)6Qk3OO-@e6WsVwvKkk#q zW2^!_>6ipdAWFUgfK37Jf0YqhSv8x^f4C4zy~vuTrngf9uj|y$@vG(8ivu?Ygi6!e zpC!9rj&^~cH;K|wm&YgJ_rLR*DO}p;$PeCTfBN}R%_1j3`qg!s$9T$hUq|Bk%5v3z zJB(V&+@Ie4&iv-Dp}*}q?7TXT7)y8!%}H$U@t$|Mxc*Ek>-c`|7|r>!a8C^L@9!?FqblLAvQq~f z>)ar}$B8=rWT|8#Vn}6PF4c3|xyd){OC{3`9tTCR@NU+wpb$-kt=M-KOAQNDWfY>A z&!T6@Z|Ir}Ns2E!5CJr)+XGw^==6QRFcYTe2`@4G>k^#c|Z7;8dvVFI+~*~ zR*$8`D=^W(&e`4akWvI(gW1fA79?g$IuZt~%`yn9v)dTzH7*b(+1~M!CKp-I6^-Zh zvf;+TznZRi3OOVXGECocwQCBnjyjC&Os>pAD)-pB)9_7IxU#BX2%*FVmWTL{mpkMzBf!8&C4iU40vphW1`c@uFQ9vP!_+M3Qg=vF7)# zYJ@=aqlO&8wFV_C=k{@Fvm4~%frDQI0i87hlm-URA(eZTm+--ZelqpW^dLXnHkM9w zM};j4P|K2Zrydo^kLyj$8f41~)H1a4pty8D-H?%OZS33>^ts9qe42f;>O|{oK3tPU zofdYduvPxJBO)bAIj|rndik0{m!`N8naK;zL36C$eTM-8s0_V*+3_SonAu5B0lZ*5 zTp4bIQ9Q8uTQ>v>SbgC>MSDOap-*lAdszOf?(K_VTo-SiVEJI~S`tHWapd^WGfLv- zBO1ArcLEQ9aAf^c3gGl7Bn*XfuG6f40SG7nz|5E^G;Y@9VybY8cRX8ZdNUuJKnsfQ ze+)Fz0{>i}@5^FI0L1xS!0T(#4yfJh$3Cr`)(8o9bPUu9Q zdlTF*t;J|>WZT2kI`43ur^_f~m*#NCT2429)^f=9zjtRLPS-BF=-!eOtna~N&AcC!UW>d`($~C3X}9^;A3CFJzb}jO-CeBG+boQjX+G`#xfRfKG^6KFbf7oY z>^^vHPy13u3@eeEwip!+$ivEA6zg{k5M%Hlep|P|XM$q!UQ0nZ7Z^b1ujM70#G@fx z9qH!fAJ;%AUJyxwGhhDI`FuNR*E24BFHY#)`1y?v^Q5z?+H6@4>RuMHOKYp(C33RX zHd^~<6j7iWf`Oy^UG&C#lb0rOvqD&ondayZF(^ax3h z{wicsuVE~Uil82Y2peDx-{GPep!GtmKcHOVq`nwOV>n5t`045@^-0+uqYsqqjZ;QF zkQh@84D-nL#Hc2t9F~1HUpPsJ8`pJWKecjfNQ3Q#%FW*%X>iz`gmjhlQRnFC;(ULB z-dIH$+RnR(fotV4rmIl!0vh%Q|I%{pI3h$kxN4<29xWTgr8~(_wfbvygjMaY@|W0c z;%`6fZ__X4j)o^5*u0VpYR0lUK?-9(8nLznGNhb znh%6CHPWx_J^m@d`HvR|mBzjaalrUPoW(QvgV6jR#%yR3FnJbe0C@gYqT+h64g%zh zIfDlQ0$3Fg$D&t3SBrGgn%Q<*9I(Y~v@p@u&0B3pJOu8Hr8(F9oi@1YkexpJ@`AH* zq5-5N-e~{u)Ylp~n;%e{;a>{EWjH7SJI045zpG1$!u<@k;ZdkIkPWX%dV;<)6H_A%CT0QOquHVpJ zT<|ipPG;(ga`A2~SR6a7XXzLl9VJl>{-ES!Gd0$K`3rUM#+ubzqE^@W6P-mky6(%2 z)F2E|q;lO?9Q1WvXvG*Q3z!&be5C{5Xa*0l#{gGy)wL+YC=*zLRZgw(y-tH~O@mFqM(;*l=pkF5%n`6^Ii3ON1X? z5C^!I5BpUY7c{oPA*#A7wh%kvJSA0htfnggbse^kc#q^lb2v1rLh(lW)g8pKe|*KS z(4~=Trz}$6CsLEfa@_qwaD5LhScD=*4)xF95#Za0mpSBW`RN1c3U*gQEV=9hB1zet zo-~jHWCkav&))f&_@nA&WB5uqb<~t zkL3SbobQZsQHPK%G#$V6fzrKqLjA;j9=h)hcNT$<2*(h$>I{N+f|{&Cn_p#;ybW6C zgpQ|9zJkuRuFXt_t~tz2@XWiO&&?md@>wT@W|4DDQzpiLAtdN0@LAKHp^&#}#Po*{ z2%hpYe!S#oOnezE9YUe7^_)6c-)Kgu(p7S9k{Lyn!KpU3U&@&VrTcB{J94#{jT#7{F9T%wO@g?jne>tDP`bFse-#Qi zZNGjaIVrS)TItK2^Ye=aC}b8y{A4zWjK7T+MTi zT`bhE4$Joyl%my>yT+}Fmj8GqEEv%L>lb9LU&WSK$nSo=ck;F7 zQ&$Su!+@I%DrtfE98|i8iv~WGx_BETr;Lta5q=|&=@BG{t>WgdS3{QFo#SOeCoQW6uV>pp+Bl+4uzP_!w)U{F(P zGMYsu-f`0m)Z%(DU(*h7R}szh5jLpnkX=7v4tj^zo>C&>dojCyLCnz+{6I3Ghgt^t z+<=XBsq`NyUeCP0{+bqxqcK3J@wG0zjlgCVhbTwP-E#AMf9?`Gh~ns4ct}zaRJGkFqAs{AvR29~JJ84*Q&Y?rlGr;M6hpkl$ph>K8+sed-Dy zzfE#}VYcaCe>77cPQ|_){!@89kX0E?kk1~;Es?*W(p&!KLB!43t9w=f7rxrMW-+Vt z>xZ|Ow^x28cOBp8SE7O#E=xii`OH|#MSua1jGaKpH6O4f{&MA0v)^Zw z4fs@aoeRW{L1iKTxh~fue}=}FOCyZ|Ob8Wjo^TS)mFACbJ53eIC;x0bb}hgFyz=z1 zHV83aG0uLSvp_p>J^wkYhU0O>w@coZOsUNP14w`QHE-x9$D+O0zpY-M@#V))L zJ45eS0wdW$;TECS!E@EZ%O+0FZk#LxL`O^TF;t*b$qAyhz0N?N)> zYG_d;h8jS+29Pe5lnx20A%p=&;Jd!>@BM#wEoRMHGt6D*-h0mToc-))Z>S=eV! zu*Pvc!aoAdwW){&yY_pvJtgGLI2qB#mQT z>i#6|coFiuqyER(J~APwvVorqfpx4{OE#4nQdr^2b~GxUFug5l$Lb9@P1N9*y6=15 z|9AW~^>)1}4ZtbAFZ<`{7DvCnEit-!e<~z};mcw*eu9%jQ_PF0GP(EAeH6X->__^M z+>L3LCdi~vCP8a2btvb(t8v4J+t)h#CzTk2p~v0+It?eFxcXAr&&U^z-bNM-&OgWa zLUTU3`&Vp12C=JUHu9xCh{kRloPIf^obk%xAcM$0UdC?dv zBIYsq%FA#wimFj#pKvq7Ur{g_^$%G5$ixQ|1~YQHYc~QOy!=`y*+-kUYx}AFw@OHJ zc$+E1V~#}P9L{)y)74)c_esQ1ISOK0uj$h&!}rxo!r`wypog>!hVffJeF{$V=D;WNjNci!50LEHX0OihRij6AY8(ohmcJ}mf6*kKC z@o@~aABmg-T<`s=czFGl=}7M+h%CyMu$O8Xc+d2;%_W%p)xi_Jbf$p>)}s^gcTcHX zzcI()p|=Sj!7G`q_|9wVOi@wq7KFc;D3g&YuoB(fkti0!?I^Q?>)2dpJPJAQdWCk; zKGqHA;t78R!vQ>+nfi+8?9EU{nGBVG3RN27!_8AjFi|@?poB4N5;DWNyi+FjxPTJu zKvIh5uLWUL-yc)vN@C=v5btY%?*A$6LU9@b9$Py+1z zKKt5@`~wwaCoL%cr%PR@s(+CWE1-w0ESx1%i)R!TNneL=e9lDNz-FX8%~H3N5R5ps z@Z2m)AFz19XtaBy15u$$Lwa{9@Z%4O*_O)JVxA-Njmy7QkCfhjq^J4cqg*iaDZ}E0 z+XTmsk8{dd+Z4j*W&|gA;vm;xzQ{r)hHDdJl9hKpL`ibIxv2GE(RLt`{kpki@OuG# z=J0yd_l=0=*5#tJzi8XR97C8Ms%Z4@@2o!^qp3|~9iVisAVn?bYNtaS3nQ7|^I=M& z^L5X2C~ltDZ&KH_lE_5a!4mG0*Hv5_9)jV#1ruP-u}%e7@l0Q?BkB2sx>QO#lCS`H z8%;x)Ku-pV>SrDR&>o~C+Gf>Ap8Q(1-g}VX*0twQ#Xaz13`d|K`^5CM_WJ&CADxC& zUE$u`H^NH;2q&?ck$!X1k!xAHKl#!}okT6m9esRr(Cxk?Xnex_wwioI<` zMbDv;32GcJHV9)b?V>xAkucsihXf0Kahi`+H~C4$;?f$+#tjOkO7n!p=*%NNV$nu+ zGss_XHQm0T7NGSH{nJN>g~kd714!?mK|1O0t9#Fu+|Pa+Qw9@PIH&1;Xv3v4%SajQ z^%o{OUuHjxB)S&Gaw^~J0?2#k+fs)5OCD%QcJO)t&l6~U6eYB7Kh=Ckvd89 zi)P4`(8Y#7baT>P?up#4HnKiUsqUM=D#VLd|3zGpTh)b?r{U=>%a$uZ8zFY(BkhfQ zfLVy$TWut*W8=AkHJ?k$9F4k&XNBRYsynopeMHZRM~&vdubIPQ+2R5WtVptqs76n| zE4=^g>WF1R%j2cQU%^eD!O(E!0 z(4I`SMs0eVX3bFoeyV&7Kvh1XbxYy9}9gatO6v$sNcv)sE$~ zsWOJLFy1^+dS2WSIF)^!kmtu3hU>og`1!#+Om0%-TYd+duYBpJgWJU;ZPu%tkTci( z=C_BQq`z@CqR#Jn84zW5#1#$exI(RKf%DNQsx|vpO)VYxOgx}f+bnlXtNbTq#(mH! z-L&SIUa~5jTWNgDrPiWvz4@`}Z<-On-8Im#02FehkRhML6yqKsnDBW%9 zAa`*LGl?5=ueb(BBOh^4c)7Imvz;_*ftbNn~K z754RA4}`A^4e1e5r9qHteD{(YY-@z^VRLKfH0YVJ6kDyoPXiSKLgizD2>14(Ei zp&+yAsb3bZ!dTSB!MnN0!o{xn+;uAWTdmDK`k2DLmZ7WL5=Dh%^1+RPy2`ae_ViJl0wBJ;pG$Ro%$Ux@j4k_Q#Bbl1oU)wt#Usnl7R4#5)va+XPG?gr<5*9f{Jg&JQYrL#%vzD71jjabGB*MtH|U17wQo<;7KPhpbVtj$;H3cZTG zN_#oInm#-n7jbpXrYx%>=t%OJ*!o|Zv4_Wn`a>~cwM6|uV@4Y2A?sqfu`SoViO=xN zDKm1J28Z&-THezLrzG{Ino&&of_r7m!lWKmLY z@Mu-$RjUHUpmgM2kMs!&JEr`Vty}x|b4DG|tsH}>(pZDp!;#ugtPn`S0p4@Q_S=2v z8LFt*p3_JvlyJV`h;Rut;N1le;R40j;^ep>EQPd|&hba`wn~JQY5%RDA-v^qy=DAR z&#&f+gY1ipv|lHQGAqcS_?gyR7~Hv-kswB5z6R2ZcGfSetY=Ka1Go5B{fv#56)B7<2O5mtnLTItdXhCYLRk^OI5bD>wsUl?pQHK{(t2w=qmnQbTytbF5723UcP6w`pS<-ts|hWiuyrk9-f5(+ zX{O!I%zvrePh3UWKl|t98D-_3rEN)Uew-2~B3NyTEZAwZ%kxmSe`y>hGu%*Y1nieU zP!aqUPwSQ1sDT3VaG9S77P6|EUOH?}`$?e>ct)zxgDm8q>GdNIJ73YZ$&Q756&xf; zRbKk(KerPEPYx7@(BG@{;QEaN=)+;v>3er`uRwQH;We0MmN=aI|MsU`Ty`!~`2H`K zHn}$?eTZ1J9>gLCBr5mKoGphe5lCcrS>k2 z@bQic_n*XviDy=p?!_6P9$SXO0r%HtM{dt?WlVSgAO2= z8aVVcuuFf{(uE{wYG`XRC!#&pqExTeWuxJ%+ff7ymkq0Fdy1zH1V_1~ifg?b~EYB)Z@_ zA_=nY^~dvV_R(^TukM43ViP~?wKZam^3jP*k!iiY3l#EOsehg*{NhuBi-L%ZcB5ZR zWdkF_zy(!v2t`plZ6F2qBrbqVb3&4$nO9<9n9UWz&Wa=9Mo4O`pOM;sk6x3_w>hUB zEgohngnKd-**=CoVNsmbA4GfcZCQ`4AX0lgY5z9PsmC@Eu^BY(whH=?RoXNaob2gu;P%*5xjbdR z!N|)^h>tP(7R7*2u?DUTb_#qCGa+y*_yG{mVG>Xw9lg^3MaQfqCWr|XLxo2m5E>dl zkf@m;hk0}oH5@B5Fgh7RQoI~>ksUAiY~z#MA?N3k&|8%sq$GS5dnq6Y zX6-NfTDdnwrC*Q5?e5lL9=E~}rEfC8IpyZ|K&!C5GV^0#zzBI2wsB1JMsb?J~izU*Vj>YGWsF8D3)G#VvN znM(nO>wZUn3^Z}K$GQ3>R{Qg!W=zQM$b4)Q?eBUgp=#9X{1Lr(e{TD{=I9ot`WLLj z6H-L3_yMl&=@z+=n;6W9E-xN?F^0J`u}qd4<9@5;p?`csmlgmc1O%BgSOaa}U0@*R zG^R(7#_nxf!_Vekn3b{&NMYrN$CXx~WN1F2dklTp$ee zSv0y%?n1aUQGt#LhYT{qSkIiY@6572{N`EiSqgNd@)3MSExsU`87|eglA|S7dy|6r z%d`kZ!BESMj)(n1pgG(4s%RJx0zANfFb_bJIN%j_Iau>h3jBIs(v8w|<{rwxS!hF* z^}u=(xgs7MZWPW4IZxDNowQpmTXhQ5$xHu=`@dB_FOAgM#H=M(Wbv)g&u_2M4EYxW zqV*IuK3eH~jc?qZqxKi{ao+w2O*rj45pFU+)Dze~lT*>yih+uh{$YwXe;Se;<*b>( z`Jct=?octB)SZP3VR_3$dt3I&gd?xGiSq+Nt=V8W4EctH!Q=tL;bjCdBtqXbyljZf zaQ)3YF%ubEyNU(-xKMN=k%#+Nyh1*E4vuW7+}9P-%m5N2V{hDjz(kpB&V)Kg1y&ZeG zB@z6P2qjF4Sh!o&X`eXjE(oLp@$uR9XEi+g^l2aEqiz1j$v8HVr{NaM2+W=sb^k_Y zf|RkrBXqdY`ynqK2mTV{m(PH9i0xmJwHMm=lvo2rP;I{3b^+tP8BnzBiya<7P=vH% zhQdfy2lsi@fD((*Tg#;CfHK@bJZpN-@+k1Q-yuiT_$ZD~fPiIkTuRu^k49>H{+zQm zs~G<4YV+(-NX8p2r7# zr-SeP(foNM<~T-o5V$zNUKHI)7~OWlxl?nlvxXz(j;``}_T9ZgS@hl6BGmiWM_2%9 zg`b@_n(<3RL3@**IOS<}!|_4fkG>n>{w_4S|`tk#+h(V-?9uZas; z{s2GwddguPySx}t=Qpc?G&e?1$S?Gd>@3Q_8wyuxvrxg!lL$JSIzT*u_Qj1&YUMLgZtIGQa*p zCIGa0>z2%cDQbV-gpXzAd!`m|740lHFmnj-AE^@zQwq#2c~tP!-8KV$D`j*gET09& ze*d3EJN4MeK3;qHChPQqe%c*TJyz||zMeDSH)*k`Ya zV>FZ$^aGo;z^5BNF=E_Bafrs&9mK2I${FDUzQ>$jHkpZJg9LlzrSKX2?`HhJ-}%2c zf1A_(AL@2Fe7sj_SUaQUI~uN=D<^#r%BNOgjCfE>U38)NJpJ2$Q;z>k<$o_e_fN2% z{`V@)Z;$yKF3bozmk5;M{=8p|L23MqJ+{P8{OMC3(pDXl{@*eF-|MkAG@brl7pj>m z4I8PeDq))g4_RsVL;VKYXsX3m3S%_^A6y&AGWiQa675eYvbT12YFAo3H(yPjjcn}c z6e`Nq0yel>ORaCu_cD{&G|(%3gqR!dtwBFhOS6V?pvj602y(>4@Om?B^O3MozU^vP@8MGLO}CaQtl9xUo7m zqjHZD$y&H04A;3k>I7Jr3-DLU2*7g3Zx-l4>;49gC`9DIP7nv#d81I(Mc|1qy8n!M z;zQqNvg&e+2-R}QvAWaUpoI}&1db=+Bza^9(^ON+9o>mWQ~?Oz!-ue zBkdhbVr_;71YFI%+zZ|cSefwT3tHtQOT?wnl$cEk>utfb0XO!}VGWJ6)qY946-eFs z1<=?Tu2!gj#sv^&JT`XNkT`2L$cVz7PL2u{dRa-G&Q|0!pb=sLxHg|dN>&z;$}jg0 z4+B=(e_B2AO=OjMoqc-hMJY=YOFJuy{Uor^Z*KcQCc*Rkfv9K^InW3$;Q<&gqGpU& z&^PuUB4RDgfhG-a@~vF#ewZ5VT1w%LRc`U2Cvr%#%oM8usN%BAzkvbWg_m7-Ovn4V z3pL^Cij#p~MCjcC^5!pFF}?2Z!IkothrJSgi5zAlnac3cQd_%&lGF zPB5juwRIPV|8VB=pw*(~0qHT+auaCKV#IB>>m49DQ2&cxO0_^e&p1!(KY+ej6yw@9 zDUy`(V2~alS)*N(_<+|wNr<&rx%cm%9s_iK&ei7;xrzZ^9LGcz**y=}a9ueh`?eQf zs}imS+4^bkvT6`ZJNMX6$#|TL0uP$XKTpmvpy02ewzb-~tz-Iuuv9XS01)u7_~iW9 z3i!qak^92Zjk_E8*BpG|!JA!&RdnsxX@LPnBz@Jm z_+;uMxcoo+(vmn@J`QWs$)s_hiSadah2K+^5A+wV&i3Ad+O+rdv8u64aaVD5Jgv=< z0jiX%Xv+A&(913x&P$173%_!@yaw+&zbW5&g=$)lr@-V?r{&e&RRrWnHgvk?Bk$x& zwbPcY);Qlsoqn>b4F9t1m?8N(^qySnMdMt&;jC~#`sW7sA2a=vkSw?EMV%j2XD7@U zQ7bgJw+;Kpq{SnRGHf(4GMZlEa=m&JZWi-q=}hlO$tU3ehG1z!(~vtcEVsavkLt}0 zn~C%SSKC)sjUR*9$K{JuG0U&ZO-uww9;~*&8cB=hcpBV4e-ye=R$pt%F>-i?D*jzv zV!t0ZjVo`D>csykA`381O8<6iK$JXA?|JjfwuTR9a|foW{3$N!WEI++ zy`Fuj6wk58J~l3is}##|lYv<6?JY$PZ#0$T;K}yiU?{asmN{EUcjM&nTy|F_$jxe`V;_sT|K!zo7quxSV5#tFw zZ7pd{aI`^8oY!WOjI=O6e*p6?sVg0|9)wT5kG@r393LQyG1|Y|B>25RmqtrMN?Js@ zx3#@}1Wb$&=?naMd>9CXDTlu;l;I4_S;O28!t`&bC(ml)T>d?~vXD+dd6iXm@T^0$ z*U^%xR6)$`=rgFEsNv$a0ztt#X%!B7V7t`fsWdt|YC|Ajv1evm$*;;FWac5Id&LEU z8lRW$Dz+T8?LW`X$jHb0%T<#^MF}j%PRBjy8wMDGHyPp+d5J9KJu8$b9A`3r@>ZnZ&w*H0}aT;q9mem)h~&TeQ&=NKEV93L#lv z2!gUFrw&?iVhO|EqH8s>Dkk= zFya*+Q9IJ+io%^6UY*RJN6Xj#U-PP!JtRD+OX-xUV`)dCGC9#WbKpLwtFBd5u&%+( zcO(Unn6&zI_eS11`i9fuT{{TOecTt5C%?=~-z-bbS7d2c2pc%0NL80eF#FqDhIM|r zXxQzEPP|E&pUzx*lDRc1BT{WrV;ymkx#PVrRjF8*H~0ME1-D#{>(n3Ut2T+G1v<@i z-NEBSLCh=pT840fSETz1E=SXuj4uITa{`&sfkmqROAmPtf4)6J+@#uN0Z}27s#EZg zIrh^IsPCsvV;fTwv=w%WySV3}AzU3bF_@@XZxR+eR1KS1+-D|r-WFT4+*oaV6iSHw zTM;k8_`GRcEIF|S6T;__4G*D{520uZKPrWLV4EZKiZg^>*&xAQseVggz?cbMZob9|q9r%qIzp*_kh)mv_8i3DOmK3GLFVx@QhjZ3}hlXp(z-P-1L06~H z2Dint4tgYR7pj|Ntk;@~F>On60Y~v5U?upqD?}IQzxoJdh6xDH6apR|9t>`Z+d1`X z-hmX(ReX#%7vL;805mQl_n=Ha`BmX-3=BnfE0%}h+z3v@sPy88X0gsdv~?G7qAt%? zZN*7JAYXiVu)KiXuvY`h0LK2pa3m#9ak5>$h7+yS?YHqYE~Un*{lZt9t1wmH1uQ2m zJr9i~7{~m0S=((Qpki`+{6Ncjwd%Qn+F4Cs$@oMzwp#m2l&je-cIA%Bcs%N8>Riic z0DS1z{?zMK+q2HUv=%UG#hu=DGq5n349%75pEOAjgwxN2?#+r64!k#4&$Z~LC$}Jf zKdU5yJzQ)zdMmmAhE6aP_P&WzDk|g&eyjydw_njpw1>>-G;C9RKhG*`>fHv+Z$1I0 zfodw{*`~$_ZL`0@@=$2{sma*u;qA%09o#NQckgFvj1>x1!QtiO!rL|3vyD76Yncg? z5mz_#8Mpl(T&afzvBIySNkg!?y=DnV3qZ*6_U`yV5@Fr8y{GH2lV`{?SgMS4w>ud= zl0axf6Ilo2np`$3$s<=KrOx>P=Pow+CFm`gc&W;E5w;O%)i#D(z0q+d*j_Q%+Okn{p~Rrc;F#Ne{02fzR|cA9&WKw@Y))SKc#9tZ$h6VIb35CnV(S9}K|^pSJW;jN6zx1Y@9u9~(<%G}9Ee{p;7?rqWaeV1q5(4FpP&2mJhU zcrOfr_)JV)8})DMiQ07iRfMp|zf{k&O%D;dzzLPyE3T6plH^kpP20-0^m;nn&$yV6 z4!&d2Cbc%{4!KeJ8o<-iA>ItNxkf8Zwu|S9>*PxEbE2U^>=3;RRbg7wJsDYajWnV*jh+P=&zRL7GT8r7;-LSrZ~FpN!-%R;OOXB zW+ysJsgcAYHHy9owO0`v1X2`N+A~6>7-7ZducMoqSpE&Bj6l#0*x?7Q7DWl;Y^+p= z+nz`W-DxDX_(A0LG9n`r%fHD)+(yhQ*zmtM;tccATCrbI;DZP-OIKZ*0bwycYgxyA zu4#_QT5a%mD${W?KtL8k~S@ucZa&j)csU9ivJ?AOv@{w@F5pVvr2__f!rCF5ARWA0+hLA2X5m(vG;GH=iI zp-oMaQQQMnutTV;K_`trK%df^`v4f>NgEa{71xICL>yZKW4S&Du|py;3d zXoEEgu41xiJ1amSN`P+4cdqVc|641Z)X)HLa z2S6Vq=Nj?NTF!Hj>hLx&cmU@U*a1Mrc1Nms9LhI3@ZLg4h{d1-&~T{4RvR*M=1|Q? z&|u~vbxz81x-EI<HuW(H zZ_zbYx_dPJJ@+>0J={COF|0QD9>LDA80#W>NeI+#Phbp1EP=K_^`8Wd4&}KmV*>h2 zCB*y+r8dK;C#IZ5xG1S0!qjQ2&_d0E>8*56Oxa5_&84eizq3z<|KkE&93d|rD;4bM zQdu87AG4)*4V|Jfa$t`>H25(r84+mCT<{c}JUF`-6P=udqf2l>HhTm*y|;!f+7dh? zjKqT6d@Vpl3~y7X;nq=EbW`;9#|@#vRN{w(;qn$jlY_(X1%+`lMmxLZW_iyOlr$-j zZnHnWt4$aU((e{|cWo4IY3mk2Kz?f$bKU63E+P{Pcgp-Kl?W%`AaqXwSla2@TLtg# ziBT%a2Th=FOh&VW14pB#7AO~kY6rYx*&;h#3#$*AWazUa6=R>GHT`iDqe5hfWIvab z{6f{ZX4Ju4Hg3=NW&$59hKRQQdQYRhm|&#q_7o@lQM&MwUcvDA_#xA^+12u?qPuiy zFee=Dm&mTrbnm$z(DiHuNLM5E*DBpA{(6w%Ql$|t?eK|_zj=yeA^j$cbbRFt+NIyds<(t&kpq_%=EliQ|AyyTRZP(8YE`%#*R2HL;5EZuk89r3p|8nmW&ZuEVw#YQ+T z=JVlPXuEwqkfDZKr!!CqGW`AOcjVQS*e6&Yf_$v}xiyqcSbQ>n88pae$H9sn+9Pdc z)6ykMsO-U-W1F~Wm$w~QM}Es>TVquEbv*nDjOI{Xi0$zQ)c}gT#~9nI)h@a;1o}YC zb)q97YEr&0xQjcv zR_<{^d_I#_OUA&jG)cqeAdQ+p%?0r&Bu=;ZA&P*@l|7<7cM()+$yj_bvN0kL%}z%8 z71y&q4QM(@h$<2Q#8kZ?!4IfTEBBg_GNAg(ShnQqBtegr3D6I+gn933cvm^x@u;oL zF5uBSw&=k05o#~4i=dD)czB{a4}U)m479Hf>3nK*MY?ErTJVL0iu!j{wFXMl$N{Hx ziI^;^8$Y*|$^<(iJOy`4W4CKO?t#ihkD`h$xtd<9+)0QBJE*?1ol>KG?*ZgS6|zcP zqY&K#TYA+IyR^}(eS@!McE>pfD9U{YeB*ZatPIiaHU~K-(Hn*{lK>C5>{lBrQ!T`M zOM5UwqNnr02dBYzK}~6iZVCLVVbG;+75lt{DgXjjs7PA*BmalJ1=J}Xba^~p_(J{} z0D(}BZBQGsOjZ%K7KEEGI9iB4SabuPb35MDm zhraRcLUF!xD~z!fEf5IM2OwE)z*@)}KgLcD((8sdI1-lrB$>^e=hjk3R$Yq?P!&JY#_r*a>}}6OXos?$%0lJbV8#e?{$kAShM{hW&vOau zi_r`h{4Lc*dnfDmc-UFK6}~pna!f18OR~w}rxqlp&8xe&>a?x3DOiYdMg-p04L?fe zXR61n3(ZnPz7uPhVM(H*AO`xk% zb2gl#0)A8XjTqhLL4-{n?g?Lb1i{#&cht&Mv5i_f;BZ{XITK_VJ8)oTg9WI|{O54x z&p!|TaA{_2^pot+HAS5>K;lgmano!f$*SKccvVB#-Y^pPab17$!|%QXxJ9o7rsr(e zXvg#SK`&5H@-13oaVm@2ZYlxHBTcMOm8Ou}N8r-fA@}@Vpi(9PYPP#FEww-G_7-!0 zfA7z{@_bw4Gr%Nig-$VI8G&%LJ9vO9fx!*)06(s7-$(Ia#@6IYgreZ1PI8ChA(G*Y?*77` zg|Ol&TS)Ld<3A2_sKB%kcb?4o+m~a=(5Bc95U5My14)g$#@H0EmNx_i*U=Z<-tCf(4n=@PuCa%o zM*nYCNEp6$G}ptSuE@ZF7#qK#C?LUGqJ5IWar1ob<$AzME`WxH1{C_;=hsUV9ssI9 zZ!f!QVWvH2ND7db-C#0%C^e&QIRO4M8xk)M5^xadwx0Rj(*W1}QAEwilR4vU3&1Mj zo6@hBT9D`)zo6Cbe>hdpDjM^zkR)ovEoA_lRhGeza&1`WrHj@&2FN;wv5##f>l$|g zcz{r;K#d7MG&D5yDhkXow6s*D2&@PxC@KnFXfh!&Ha5mXWoHATk<_~H={rQDFT1*f ztrjkV@5~H2?$hqeel21tA|hDoDUyqiBLW&HZv{bl=UlEB~)kI~L;A%4QJyx|j?4 zS*KK7YRAoNZ^WUGoy(;GS$@yVg*{x@-ZViol=^o{fBFrFQ6wH+5Q3nT_!CNm#_=?M%zYv#Yd&tB(P zu!QWRDen17JAfFV5FC=pvq?OEzfTxV~+YXd2FEwNHIp_3~^p)Y1@Ji#0nRqgFww7_Xa*Lo!9JhKEPnA-1t{?egP%SkdA4Gp^ARNKO1Si{KhTDoTSG1j!&&QaL# znM&U&YxnP?$D(5ol=w0}V)>T#Is<|Wwu`1+ujs;4BK#!ig)$`{IrV!CS>4Dgx z7GSFINX;Y}nwXd{S8^wPwh{ueOTou?DQ7QsvubK~0*XE>G~@p+g*%IwA=Uza_!s{< zT5k6MI*l<{-BmyYdeIw6j5{(i!qHpxIHl(^xdO+2-H2^4#ne$Hst-9m9q19rd^KT5A1{#uC(goc}^WW`Ik2ShszdTh) z{8y<3V&RmrkAO!B3X|QQPi<<~Tew-%x}Ce_>C?<0!l_MVx*b0ByJ9}Y$c0)iDZ@}W zIjaj*M99lzICFuthIwd&u_{dlzGl4a4MaT)jZALRWR*$&yxZ5`2;DqLBH-n|1N z)53K=wmb|>6bF&Sji}@di~dscv&mk|dfb$5%(NOE-a(}BR}6SBIE-|TPF?7zI);a_ zD0~a~fUDt=KBdshpg%0mcImZJ3=f68|JMIm`XIFft{~mltUhnIV?C~&%9==KkM&Q5 z@2OD_muQmoV&iQxM@4;qOKw!CL-^WgrkbNv>c1R_^_?V%KQF)n4@u1oU)pzYvBYb- zkJ;|%3xNg9b}t25ovd2l!sR2z=&)=e$#s_MM5X9wNo@V#Byogxy?>s$0P96qfWj&j zJpJ*AA?Hqj0#>uKkJ?^mxd?YfH0knmx~2oAALrfffD)43C6S-;U4C5v{P`Xotqs(A zOceU$sjwLLXQSz@RF4D74tk~+w6z(stXge1Df&5xQ(KzGL}h4PhS9jrsZQ~XJLAM~`B_n5GlsNuZ#`mH;lXTKtBzby`EwAo`hcp5ct2a$8Ng}wI{frZm#!Pmbs4{ZbkR{!;b+Nq++sf#5feN9 zMarFZW^W2_hd7Ts<(&|WyXb(ggjJJT_tO-ksN`)(w4YA7PyY}w^I)`# zT^_WPSB_IfV}XX zVy7NV17#6wHc(dJW*AGf5|hQ54^>(^_?JC(EBjgL3g^7cu|R1X<7hDG;WMx=by_mW zOQ2M!l`y>)f~65RR0#6wh*gZ(dKoghTzjusgV9e|N&T0hHbYQ&Y47n9)G`!#1@bEX zCz@;%8>=TEI!HEmheyp%1;~|%p3Z|&)FXAr)tR!B`NYU`gRPiNg)uQA?YQ#@6Y>W7 z2M!dTlibG{A#C#+V4$w~8uU)bjl4m|cxlMC}7{A}?HPd0o5ghcrqeXJ)OVvYE77 z*u$AT+n%#@+~2^2OaLq;RF5L>Gw?6G$usLoW56p5I+q!fFw;d$@|5W1x}bnSJv9Q~ zaYM}wKR!uR#&zDq3>fmaV@`g%SrGs}g*@gQt>cVZ6a8i=V>pvi&$Ky-vx?RuxQ*|m zeT`O})H0GZd+{Y-@}=SI$b4j^&i&kkau%)bwnoFJ-@a_tzUamXzn?=$w4Pf`Iqi(T zTolYSdG-4suJM+A#qyWbk%-O$C-~1~$I_;G!&(4CXwE~){dv^um#K2=*UbtAr885f-^uedM6I$H^YoBeBx28)3iZa8pA=he*{;@$?C7XnDUhQFN=qDKI+_WLJ| zP($x(Iw0u^C*C~`dy4$*W564E$rQ+Szz3pn8$Ijr6PrUEGx1{0%}$rcvYD8fweX8$ zS9+fGGrIo?4sBv}?|yDfKJxm-_mAq1L-@c%0ZIuk*XkWdll$n1BM>^F8bU9>y#y+a zb3jxoJ%97l5D+!h`w49Amgl`W-gOdHuJ=;o;~bX)VO7Cav}8OPpvxgdclUvGv#$$r zH@T7%qX8)h{d=ZM!$57RijPmvSk4+d8^3WhIosym(rf~secq^UVEle5pSZl-=W(@9 zUvNV80)wBMmB5h;aZT9B$MOTMFo%^@PE_mgxC3vFDpvMcK%wIBQs7bR&Wb{g+>TY3 zd!Tl=c=q4#1qO5lUmgzpn3dgGusb(O?kV9T0Az}tL$9_S_N$w-_V)HlsDmtaEMEn< zgq9dq;QRQT#|w|Mn1aCq0s^y9rS%>Yts;`st;}l;O}U$qaE%4;29 z{`asl==|1W`NOIsj#{(wcN*HgeCnQ=1x}^^`^!yq+2|{PxG?@w zI@-U>d|CFoeUxRHAWh&1Tx)g5n_l?y>3-IhK|dXd*Au|b4&+7bkraE7tW%>E)+cVY zvifpUE%Xk5f^llqic~99G%^MeH8}^ddUMvfM(6;qfgFmL9p3r!d#tMDS=Wd3occlvWnj&ymVHJU8Z) zbors}rjgT&sBFKp#(p{OAjF-6vtSyGbbd9mP)%2gxD7gr?EZL9(7ZpoyU9_DzT)O! zl2pLW%5Qu$F=0Gm{f=*ldR*@8ssp1e%iL)QZ=*ROlfjXHOb1Zx2)}cE>(t>qp?>hI z;%->RStgG(BrM|=!gjm_+x1Xu_`6o-6Y*S%hUW;+Y4=#h&jQsGQaB%<5+`A+LLSmh zK_N~HMenzy%7yBB%_q7n3C14!)_gzbZnB7!k-G*E=;-N1w?#;DSj1dEi_NAUXNl)G zlwj>CCG1)6Rt2s=kLBy{a?$drmg~=v!UJv%>ED8evF{kaMQ8kp)p_84ce#C*%In7{ z>xsz%nitggL7z}YHxvg?`k?Wn2#d&sZ4pG0+OqHb5``ar+(Rf@S(`bB%WrRZ~JIs>!2S8`t&7wU8IgG-Ua!I%-Zwgk~Ib)Chy4YB4GHj>TD1ObtP}!D+{A z2)___pSoBS)j6F6hZO0}KhdcneaOyZWZFA_O(T^zu@_czY-*e*1oi?x5cSNDx>6ECCu zAg%@)+l?kK1MA+z9g1}%MiKle zO*3~Ww_w#F@yoijtJivC&y?Gc`aMyr-fy==9r=khfOc?WQT8HOLs0nx>M41c9hiaK ze9sfM`*PsdB6@8IbWfOZ>45=@GqnXm18#Jy<`#~-7OoI$srcv35S&B`IR$$0brU}5jm zfQWc@Lhm!pb>F17w~8?V@1Q2T2M4&q(XAl_D@z$8dWK*&ODNs*^-^m3iHqq*;K#4@ zk;hct#gc=|s=e1fF2xl};H)+}pVH2xRBU+fS{?(-`B2#B^fFpgo$eI2`+>KnSEe*d zqb`6nmiVs)0xx}xEhF6aLfA;j%b5`Hn$6+TZ= z6mm02jcX6Ge14N`-6U_X6AE+BHuv_$6|WZPXnoPClO6b$ zOgbM%<=MVNZle4gQjzj|E6>fC*$*gsQygpZ+n}B~NC6yjV+^|}!a{B?;d(U`C520K z@2{Un`;Iex6}*X?V(hPO-Q6g`U>;;N^9XT-i}Wqq@=feMo;zxNPicr!G#ep!W7V7J zq90|EoLyY(=s(Afn}X^YxhT#oWSNwi-(_^I4I-ixcZfu8df~6nIQNSSH+_Y@eEFN8 zm#0kD>g!mwcz<*Z=hH*@@Fe!kSr<%&-tvSwwm|H)o2EfeVIr$yakou6fg5!EHa`^v zBa6c^()eBZZu5=)>PTVSwY$%GkXpLB62b2$i1-;EJHY^K7s2xLNnnCT?toq2PPJ0* zP)O&1c&dh^@be0W%%{;NcHn|73gJ50=7M;_4BP_RKyM_n1>&k26q1U(*sUl6kE@b9 z)JQUesPl5+q`U+txk0~kwA^dNj_=e1%xI%Iu6*}{ zM@{&YURt&Ag(bBGv5YDb^xM7Q*B2Y1LZhk9oot zGL%5^nt3(6;bAM(^D!v!V*Sq!Q^kA_*M9+zRoSv%79M_ekV~Qx2oS#1S>Z` z-4i1`#4ehs8{SoqIW-5XGA!Z7<;BIt@?7=Ua3{l<>BbV`J>SnS_AnAZVB6OE>HCIKVFD%$s|mq46~datF(9@aj#2$Y^0WagRY-dgm1 z-$(WBock~C#;LfseC;4qdBDr-dF2l-J9Ja==Aq1Hylk24bOfg3R`&e#GCL2u?mOA@rx$)4)s@uYv=#^ z2Iw*?s_}d)0FYr8Q#VP_^F05TV)q-xr7Ljt7fGsu49*Q_LQj7*|HsyVJhk_g1EeeA z4>I0m_gB)XX*xi^vPze2_9|SK&9@lU)m;Rw#9%Og-cZY-vX#tNzByi&X9?VgBDA%U z0=jCd!Y4_62FLdP{N8@AUaeT-rb>i5Z8hiIaZ?)z!UAQGTRhj(8*Q~-VG9`+`0ieR z#$8-xR-M)qolrz(cX0e*WtO?0KHP2A);)SfrX>NQqfC?FhU zQEK2xI`uECg(z2wf`r}O-9h?fZG&FfyXS0K`3WFvOwT zu^@Q@Bu0(m_}bRdlWFgX)E@VI|30IB>+gXw;ilve7a@jVFntmL-n{J*DO^wQh@UF~ z%Uept$Q)=pauJb4eSMFa+M#_+jZ0K$$LHeMAL~5dk{Ud^z%HlCC2(^e5nN_G-ZtRl z0Plm>iKQe6%et3B)F#c^4OzS86t%<#pq_kO47)?1gJ~QNT_o=~a=F1ZFidtcwcGNE zpuTy)r?-#2?g(XpF^1o+7d%oFy2+cR@eCNfKe(R>1ndcX`mXdvJZ-FsS{+bNh;D?t zFTB2>tjyIGIKF~+hct`fHCt<@m$l-|P=Z)4bpz2(>+U-s@w>s-W0Bf+czi;!-AUBp zK|`4&LIBg+r^e$w$V!=)&!s7E3s|Om>4swm3ZGCthDVlo`W$Uer^E$byJGIaTo{gB zFX)-|MT`gV=yehYeIHa*f2a%R zN7!Wo2(O8;v2lYPI?2w0UU8P7Q7w1Kw_sJc$uV&;hkf~*7xA&o_7UhobCJ@RT7L;a zUDq8Z7P2_3xnuzw)MJ5ns@-`_A&{8rZ{K2e5|*%J%b-PHF9DFaCg40nENK2r5>20P z<|lr+0LED#=N3SK>JrpB5SR-GLFBGvuDN1p7${!@2@G#v)%%=2;9AIx6d~zT~a?5h= zMj>i_B5~1CWZMYX!olASIQxyu=(YDyP7^**t|E#MRiFl^sUx#@3McGCoi-@Bioy*#^jG(wCJa2 zTkZtMDM+W@nlHD;0PkISAz-saqKkHuzIY0+XF0Y99fuh|AO`MU;H$<}7z9KDvLvKT zg|}}XUP7P28^2G;Um0WmrUy?SaPhm(l|OThqEh~*wuX>0k2lHrd{Yegjnu67|>L|nUbDQjYM3Fa9Q2CsrKZ6$4Yiw6^BVdgEiF4=2 z^Ec%6XqfjNdj@zd9PRiwpU~Lw1N#{J4A@LY#^HH5YeH?_oe^e zMLp-)8T^fJvnAjjr;}2IZIWm_A4U}TTi5+U-eTi|)<3jZxjq#=++0umjcknmCi!)m zm|)Di(WAX5Cwf8Uet`~QTX^^!byF(;S7Qp%ZTZk)YxOdEZN^sxE=7dv1QCuok!D9H zE#NT7Z-zrXfqFO(O$>i9Ymh;2^S0l}Wh~aZj(U0BfYsOP>5B(Y-q@j_nWn%XaUfZ( zLc_dD?5cOq(|m2rUjGm&?4Dr^KllxQm@`Lkjev`ibUWd;Ub)Y=RZM}jImZN2+I`h+ zboG|zXNT=^xUYGBtcBi@moCi?PC4b5Hu@^zXdwnOeQJeU4wHOe0K(nc&M zmNv#iK@adJk_u8we^LmBE0GnVn{|eth|^YeWZ_vOr>%((2$l?_HyRB zQ*K|eQk~`Nyc`Nib?HFn4!6UmSWd%Ai z6snLqYq#DMmL>ZGYFhab<<_i1p{6%nQ@H3sRNN!?1fCn#HG~L#1K%W2u9&*J&1q(; zR=m7CEc=0jcMmr(OZRyZO4hTgq# zkg}(Q8;5i;ji@f5H+HrgE#ic?3-7YJv?gv;Ld0D5?`xSB&{| z*OW%T{M}_>!XNy$-v#c)4WS|^E(C>s07(z)f-fO^qirj&wV{Xfq+(V=73Onlq0z?X%0WD&xTH=qE;WdwgzSRp z(Ot+uSQl7CqA6`_*t@B-b!8VLLecfzoHmA7F^i?3`K%h{mspn$DJwzM5%!Wb0F^n# zrRdNLLvQX5wZfdkQFB*U?EbKx*JMuPjD78oz*ouH6)IQ775?q}6-s3AocceA`<^2F zwVNyDM}eN;h=CpdeE|WhnL6*@R2e<_i+%0o{tC0Sg#~j`Dz>q8?;MR(zaJMBG4ULWa3iTr|Qc`6+a{}>~2PL^` zNiDzfwf9U|o4&pp`it!=A0?<026T1fTYlTkjKBBm=4FW9zlhNeFBMyFSAes=T9PCF zsyFu!umgRn2}Z9@Gkja zeFqm)L+=^c;6OrIpq+}EqGpS=DWea6#Fm3eFZqu3=eQB`vdIR{Z#-@BZ)#iWhw4f~ zbdWW@!}z=!xtzo*c?J3F9Lz#op%R*;1;Zb%!~7-nk&j?(&!S$EiW&C&1Dhe{%3F2u zKAa`q*Bf?dFH^K4#O19zgi0KlkFz~RDQirV@o?o{vHF#^7Jb2TGZZQuusoSogc%hd z!uyZ0U0%iZ#`u<>=?$X^(U4uf_)uZ4&P_77dsJgbW+`8gukhn@`Je%v16)ITLz5=f zSDt;0s^H$KHQc?SPpTIY0NuW-tG7r~$kjF2(6^xg2u@v%4TKcm&nqwie2=f`p1o^teV3ea_JDoY&E9cF2CAmi&<5QEnb zImwXrm_wD}>H8XA0*O?04iX?`?D68R-zDsFG>RgiDy7S#0 zwX}!T*?FJR9V>=)8#}(fGF-4%OZU9$+=#J)W${XcUcd=EnOc~Stp_{K$y4U2^{@GJ zCxyTIT^!86blAigz#Z1rfHA25I55k2y_qqEf_BoRB@Jnl@fak0lK2j6jd^{W)*)t4aY%WVC}Y^B4P- zeB&J|Qh4f`s8O-juyQEUAzJYQuLGAqOyLe!BKeUUbXjt6F|fl-pvQeSfb?%4n|j5i zzLxuI@L9U$jc4(0QmC%U%ZVM_#f{@1GSnl)wxy4DRQ=EB4~_b@hg0Y-9aORyHYE5l+AQ<5v+jwRGtw?;#Z^b913olVO8X#`+M!4+dL&`|D%|*BF zHK!ds;FkKIOB0}K%}`8s-XDCbI*=wym?-Njk?yy94U_~q&_;cKD7iTn2)Behkc$`Xi2dk6X zx>S<1`vWAd|K;U*&Ti?&>4Du6{TOIy>f04ntcvRDzSVgk{n9*Z@8A5K0ch}@e9lL(Q<%q+#Pp^z|3|-V~z!R3CshCxJHO3b# z+m)!P_lgqJ{1BPbeHXvCzwS3FsL`Fi0*Lm`W6w55whb)gttZ#16m59vsa}SEU}4w7 zaHzv{DNotu*xs>Vsbb+uip?lVc=4p5-OV1_(SvH!tJBo`#4|fb2U>h08#si{sC&b} zbTD18d#O?tYngbc|NDMIF&ix=LZ^aN-T*vD>7(TIpWAF51Y{NzwVMco3&W;qOwAa_ zD6!$!8FIF#t>&Aqe5sf8e97yq_A!_F^2M?_nHQh8@Cxh9#+ev8MN6UO8wPKcjoNB@ z%_yezuw9S+U^C&Dr_`;MC%2vtcb0Ab6DZ#i8H{*hmXFc>_uiPn%cXXXCZLC&%IEbw zotMaMn$xr=2MT_lyNL|A;uTNDMm3z)XKB85J54b3%pLO#=5Uu@n|U=)xyCy5D^&QZ zXmKFA!k?05HR1aA!N3yBKuFm&2~WYS%g#dtV}~&2)F;g@qBGt2Xn`By5dUr3rD+T6 zji^IX6nbn1-h3^ZLy6cdcWuP8{Q8zvtqk2B&dHV+(cBsxadkyhk86DcVY>6MY zM=2*2xxOa8`|ku}6=KbgIv6!gA3M=9H0&|OpXwQxWqq+S0sEB3fbwEFxXtlt0 z4#%EUFF_#XvYYJ^LG#ZZdA;HIu&W(4qdUmPwscR9-m9fozG)P`@8(B*KMQG^ACsMd zdYFfHDJo3NhP)aRonhr6Sx_8N9P^#a9V05C3YU^$LYnx!hN2!^>|lv=nHcpwr73G# zI$vlclZ+9qsrNR!WTEUgQ@PpcI{Aran)Vxj!1-t?&$on9#mN%IEX{>L^S6y9SUDHw z$~=MQth*A#9VZc=ap$sQWL|8s3|{O=9pfO`BTzK`O`gq$W6__euasr$lKp~d6Dex4HT z;cUoHGGx;d-)Y*nO1rXakmkFq1kx)eRXj7 z*RSm<lXM9%)DLTNZ2Dt6EURg}*Y|Gbf%4ir-H%yq)&R z35RcJYMfDoC!FlznY>^yfunIoGyVHy9TRnbu?WSeb7;RSPmoyUx0^S53_`mG6SW~J zcfLBC`Y(TfHiu*pygf?jakxv2>S7u5{qh{ndtMm>HdZblteCgo=?Mm6{qb$kGEVB| zjP8IWKPpI>@5osu`LQMy_cUtkgbRWvdl;ELg4c%+3l__@F+LmMimGK-I+I|v7<`#- zLDBN^lBJQ9s>PCTcc-qg z442P_9;IXMttG(sxNQF8#awVDuw}EA?(#r`WM5uL6JLGvO5O7Bm|ZOI z_InH$lQuDSE^Ft~BrROo@?LlmHPMXL@Vn3e7H9~}QnHtDcdbp>>E7~q#Te37_d72c z>x*E?$nB2?WESFvGd&ZMA@3v7H%dQe?}T2+V&~HAt+m*7XS1t?H&x=11Bxx$y zQuy<|6vT2#{h>jstglBb@Ud0ak>Vqtf!xn}!`bFRr$5Md)F&!oE-u28_T`iW;f(wX zsh%@mOdA92%euKhN)wqT>$}YNe#XGo&Mw8rtL)kEQTzVuz<1rGpfgK@;DRva+ZL+V zkvTV_?z;O)68MBG<+eeVX8iIuLy=bJEtVX7ef6yIcRmgc4wL&>P$iz`J%AT6@Xj6Q z7FK$eeBL8wv7}!(!re;bYw5n0tI54Sar)zi@L|4$fEwZ*R8yi8f+e39nv-xa8p^zO zIldXB9QCq15^<;VK%$Na z$Sy_UZOe1DX2w)yG9}k$rs$oDHlkw-dzz6q9lr!W!Vi!%`VstL2`3KWu%$h=&X;=z zbv8%+pYVg*w`N#kwWO-w$^EzRg`A^bUe&d!W#87MNm{~h{!Z!ZxckvHhTr&#gnZ~r zBhJrLJ(j6lc{ZCiKFHfC;h}!s#2m8+^1XblnXD5voBMULN>`Ca&ny{yRRho@_0*k zx(wS^2uz%~I4l#Z`n=dJu>L7kYJG!Cvo_v<{gZK!Z&1P4Fa1v{+kPR({4O{yw*}ZH?qI#^Ueeux7fI7N^PgW|zsx)*^xaxt z9`LQl^dIWWoDpc|ubOk5S6sOXsC_S<*BG7(%V%Q-&g>Wi`%DQ_hwmm@TwYcC0aO13 zSH}G2`fnS!AZlX5;8wu#i=zBjMjS%+st2N#y3r26APdJyCD4s$CD zQ!f-b)fqepDN8~K*9nZZSah~&TJ!nWWr^eHVrsF<7gmS|rwG1jKgAMXPW;(g;f84N zt$>|h@%Af$oj(ogg{?JqZ(Up&a&i<9myL=tXiSnAFI0@*bi1WN3f7M4K@W$`3>xqq zStOO<;SwH-c}Dx5Hja`uD68Z#ge4sMup0Jemn!wiB+GW8GU?W4AJ24SBjQJeRbQRX z^i&kxi@zHc>fVl=KKgH1x>nKB?>lIAW0oytal||-CjFj>pe|RZ#oqjxP<38AB7U{L zsX@R0-5M5k>>V(LEIsiQxw%AWFCamUTqu0}ruSD&z@%SqPyh-emnL;s1H%h4js+I8 zJV15jjQQ={oo4g~`p{N*{8xWsuZ~edmdxR~4>1yE zdB>`$kuGJjW4uSkGIj0YoN_N=d6(%HXz9!G>LnvpD$x+U2|nI^-c=n~0)E#{6Ye>*(#anWKaDRmChpF5kltqLPBX zYs|O*HKGQjTC!Lu*y;X+3>4~&hW2-4eGjvYYdsFmfT&`Bn(yZQ#g0h3rMxanktv_G zB6T!VbyytE93TWikeAip8*NdNmda62$yqBbrvlRp1vm{&<+O)kn$PNeTf3AV7E|xM z)m+H)P{n%BDF5rMK~s=wvS<1X6tiA_&uRRYxiB)$@ZJy?dpR7%^s?t3TuVK7Wf;|bAAvS|rp zGpX;_BVH*;(yWY;E0-kFm9`&nxlGh0kRCS(_u)6+4U7EShT3Ka06F5?v!?J!Y{X!9 zwFryO!NXoN6Q#x&ln#BF!n0wgpw_zJ0A%lthxZcfKVeMnK#t7yYdMau|N34ifu{$g zr0W|%NAnBndW&V@;da@hjZ!GKQW5W6Y)8(2CFb~S>TZw<{HVuARt;9%YMCi_xX6+= zhJWcNAjm#KoS22#qjg|BS<^U_VY<0qt}j8joL6EoN`$&gulzqOfFJ=_7wdA4);XXp zbTnzOlLh5hDD+V9VBi(!ZMx{z62pGRn7z^oc5#Gyqg40_+<>Mq6C?9`{E~zb5jVx? z9XhFA>fZgyi#;2oNx{X@;vFnDmH`1RKR^EkU@Av&$eU>A)3Z8$yK}Ztm2O|R(?MYW z?SddV(l@t z?APwL3c%b1Wq-)(D&PVl0MW53TcUxh*&X_GpSqoE!pXNfC^r}=8PsW-rx3~gr#>*mExQ(ynyD2ESf%_!gl2sd(uZdb&W^gZIMm9)CSSRXA>yfLbKQQ}tj zIQxT#i^LwqkfBj3q358-e7MP zIAgbamhdqTzA`EUjPeerf&4-x=fBOFXE*w*{e`+?sxo+NT^_BV*FwA7dLuG;5*)2= zZ|fIFrZ_b~YuC%dA71PaowhSE`lWSSCW2lI@clJA9jp{h3++XekDR`Lyr+76IO*iQ z5X!wj_l6qOs7Et~e=m6~Hx3h%n6gnh8I_R{AD0N026HRx7lIbkJLS6$6m|C@Tf|Q0 zqFPfShwzHz{p57~3)-guxoeTA<@eMqQg=UwuEK{S zkN^X-E<3XisDP|FkES{uylY|Tyem?+~)72mW_ zpX0ID`WDJ@W^RT-)upRs-{R%xzxY}$r+WoAH4gci_b1QbPEt}+uSTkLJrs^PUv|4)7!dQ|wuD1Gl0aAjnZkAy`+cPwhfs!SW~b z5$>s$+hg7+nW5Y-3@yKawv{h!=jO6@=SMz*c+9FEsO&gE8hjMn{D!P#yJZMEstyZC zsW*mO6VK8!F*V8oAx1%0HqTEedoZbgqP735xS;@p2?Lq+00WKIFjFSa_xu$}fDVWR zGk=XMf2OMUDnOEAeEk_fSD3<&ju!RV6bCE%j8y@8bFeLx4*wP}&lJ-M@LdKG3O4)z zm#L&?>Ss=`h_@*<*|^$|Ora*VUb$K6IFPF<5kFem`?VxNma>^1KM6`BZCPBMp1~ z9xo-WZ#o}+%s57x*o!|bgW+W5Jvh=SVrKzDr1lFm#KEPw*5+9nE|Ne4(XDQ0Fdpy1$v{PyD=@4xt2V( zcWDHh+1cv3aWSa^5CpNH@t#}w3^0OjiddrjfLHYc%mzM#uc(R)567(~yBoYfU31Wg?@Q;~9x-&nuH>YYO?ynnfFcI8Qh(>9IR5nBTNZYnQ}8)l z2LLd!D>YkRhctfXYI2waoV-kx^Y`IADFEGk!&rSDQ0CxzMF&1*WI!s%%qhU&x2@$} zWbSpD^-^L(hYEPC%dFR8WR2Ua%;-Yv44wyV+w~MyUpZip--1PW#2A*INY0cqA!6_KtTCpWVNhC=R*~BQ%8OSE#kN%_EE;19l?37bFqlV& zTZm-qSG3c;O^!b=?Uku(u}oEjV)qsM;c#G3}7Ay{)O*WARKR@Sqpq|rUba<>f$q- z@fEi_+m44%;PsDTavdTX5(oYligfK1@B>m)M43Dn*}*MFcw)qr+Qj!Q+dD4lr??|u zzL%E*d<+3s8EHtlD%=S}`5^WUo`mX|w5q{UwXd*FdoH>u*4OUZ>EnPnXY%0oxi z47&Sr4e<#uOA56;uRDhkn@y|J|N0B?@P1axcB?%k?g*Snx__KQJX|F3( zq3+Ak&xf_??LR{ZM7_-4mkB^8sE9O@g)KS^0qj!R65vsWT)*B))kqIw2MZm)ez!mi9_*vj8 z@*jW+0&IqoHECxI&s&8i#$*it8X1v$GDMV6^g^)Y-4ThdTHdoKdA3JHlMN`rjHMHK zc;v2laX~?5P0gttZt5{`4G9VH@r<|1CO>WV)m7ye6}3Z;Altb-VIRvNKmwD#RuIa5 zn*+=n51VW_t{Nz&Wjq0QfQ&eS$n-k6V{UcE@W6Ps6y)X`p0KpTIlb{f@p!BN>XooJ*k8_pysM|+kYmY=zUe`0d( zZbWqcKBr&&^WfPo``jtOHND#S99XD^mf8t*s2sO~l)_zo)zvBgPCBx(-U5`w&kDQ6 zlG$w4gk4a1t&wqv6O{tlWAatqy;AW?$M&+SVUajl}J)#>f9to-;w434_XTUI~f)h3I1UD{gtWo~xm9(G{H?+iIYrZpUBS)WGv$y&Vj zUV(afzwhjF+QZ4&jOIV7c7e@%v~d4-@$ACghpO05$LLo(nB=`$`KPsk7X7hz5Bjfi z+^=|_d?_e*ybLRBy4zF|tfzC3`S3zM+0IutWv~wbx2?hiPHWh~J;en2^Hg396diop zPe2Aw4PvNM`-sN%Dm5HVGFmz9P2$nVzRGD5dblwU!;!VMauZ4KK+LK|_oxZCZ!t!0 z!}O?wJc6o6PU8PSafJc#J%kw;I@pp8{s_VMU{#mK`#Fq7aX73?8Z$u>zT~R}>+q$l zI>4eTErQuW{>lMh#1l}Nuvw@lDdqd0_f3XQIU5mM?-ds|Lb87zwTh_ez9+uB{F3Ft zRCr^QY>;~p(z-9Xq5`@3nI}x-M0%TT6+I~(mVvHuE4Lnyi+R70H2(0KS{K%zwO3e# z!wWJRoTO$I$NH$;i>a&HM)QN9ZGgZH*1B+^>ac@ST*IyHGhlbIXe9SjtzV2a{(-F! z(dG=Hs$JX!yBD^sY&QtVwj($$^!Zq@2}s9qqnJ54?b}w=>DNB?+^ovQUl>s=)?O_+ zOAOgFl)98rluo^TCz(^xx_MUAbOzZK|Dg`AYAJiJeB5-IK zinD%9dMp?NC-D}4djtvyB#3IVAQIhWm+`RNS!nk=`JHe&AHq=v7=EV#;Jfq&aWKW* zQ7v`i#^=kQs)DbKp2?06fTY!HyP2#)GhOarvc_ZMJCN0PTkf4wehfy@;^4gsIO2oIh;x%j>s zsZq-^HfbGJ7}^*4WEt6Yt^lR_);9Yld+hv7(eLx~|HEn?J7SHfZV0kJCz(UnUQ>Y0 z2nY%~nU_8v9*4L-0q{?!?mI~LlITQs%5{XXalPQRH=FkojLL4^c@NnLM51edMbF3DYTH5=Ca4FOXUpzOv7ueo$;sH>NNA+{B zDXefd2CI=j8Tt;mA=H4(h!^klmS~3rND}majw2~9u35!IA(pkty>3YXz_}tcnX06) za7s9~yO5C+POlhkcDhs$d*_)cs+tBQwUJBZXe3jtbC6f3dF(>ZUw%U_2zvtCf`Uh* z<9r}suDh}&-mjBlENp2GlXXPx9GSvEP+Vtk4MW-0J6FuEWYv3KtMi87y$XXG$N8jt#{`` z`bP6oB>1gq?PRrcH5``S5+1LY4}c%^%V(}T*X7E2x8GRNZXY+5N|vwL{@bMZ>+1@VetnnwhhDKH4jfr_ z5(~%Z;4?AjkfkUPO*TUmZ)h7C`8`3pKdPhg5;XWQr_T)2(ji8xzp>g0=&N9g;T7IE zwn#;${I+qu8sEKprB6xrN(7)7J<)Ot1mBEjn^?Ufyu`i#!tx$^jX`ae%?$JcSN|a} zIb2t?`M5%ekfq{7F4_5wyhg1jO*<}i#rW@(sQ@gCWPDjgD|xULw^Gih8D$i}&IhgOJFk#6g@5ybL9|0Xm84VUN&!N< zDLcVrLPydDnparJ76hG<8~DDD_zjXG_GrPW%{3l>f)Cx6$x`X%HzT3)wm}!kE&&99 zz-I_lWzL9lb%Bf$CxX|dKeDKx;7p!Hq>6~LcfeBQ<&x(&(g20LRS_T*1b5OI26JiH z`uVW{$a3Kax8U_E@U06PY58Zv`k2$wK)EW+Dlfo@{-;|qc^kqG;t>rqKO~SL<}2#_ z5$w7C24LxbElh8PSuzRUpNO}hr5QJdJ%BAq(?IoLrxm}Ux@3?tlZBboyAZNaCH%VY z#^fO_z}uB67dOQ3okxc%^%HEtQfgtAOXO*}Fc=r3f%UIO+$Arh-gSL)dbXr!m(4ft zuS}L{c-I386^58p+JRk58Ylv`8}EW(2eb-E*~C&y0xxkEKY(1vARUF{pQQ6MKR4aW ztgNhTZ%3!SrVG*v&Y91wbDNG;`qdU4qV4&1mf=Sk|g> z(Q%x;Xh@bK0Odww03eOxh#P_DVS5H>M5gFU5c%X8Wu?D>Wh{fh!RVUIV4lL)@S|YB z_|N;a{~(Ry4S(P57vqsym;UEM3dla|+MxTZWlMXpgg^40bU(*UQ8sO_|0N*>n!BoI z3Saw5hkae<5Zx1kNsicQgByxkI7^PdWIuR4a~@tq2d)!$Pc{A*6xTs$t*EsR z?NR26WnRG7S-7kIlfPQh)ByIW`wE>TE&@8pd+Qznq6ijoTTYg;J%Q+qyxW;|l0nn7 zir%V>B*`EzZ~TKkyDxNOXlV8(Z~VE1CG$3%E7qGcPDOSTol;&y_J1(pLN#CuYT0-6 zN*4?vu2~q3oe~+d2ej3RYjIZvo)0H8unpxT?yAYp39IRzSk8&iKsDip+0GD1BSW!Nv77W19QT6K3MvPeP`|i^{Oc zNqEUiLIv7VJ<{ocmnVCZ$70=($%BOr;EKo9xQI*V|9SLo6nr``ld|f%Nq)8~9L_}&Pq1&>*O8dJF9IpN3%rRCaJEu+h2*gsU&!L5ShI8o2 z52T?PugR}j3*WoUEH2)ZT30O@1`U$t#5)aFZbo;z_O*WfwJ3OOq7eINJ`Iedre(`2 zaeM^nFt}tBnj>8JTIB$iudc5&wE2!gAkL@}5Z01~#G6%#Zc$qT%T4YJ&>#2G$2bJl z020{Q1rXxIRlcZPH&-(@p1vF_*D4(IH)EJ*x9VejLG|Cd@CuPUpP%!JMWPFoIHLWv z;SmW{2fanw4S=B#m*Mph*%o6g{l;XK!b-kR7h{@d8~eG6sPii!SD#Vj@SW6+Dkh7M zi3ukxG3k{Vlm9fG@wT4C3V2BRk6jF(o5m`_*X*u>0OT3$6yyk8j;}?9 z^n!=)>FmH$EwO3n(VZVvK>AD2#nixVbU#3%^OdVwvy47hnL(h6bJFolrB*Al`}qT zqXh*8@*Q<6{m`m7)Kn2>F_R}5uEb$-=*YJmDPIJ7RLg}IlNMAloT5025rcD51`NEhEAx6w&Ov#r3V0lN6m`>koRt4(O2Hh0Oy>R6L6%nS;t*F} zU5hfoZNp?z(S~eH;~Sq=Cx)DUY>B+Us}BuKd0NAFzV=oi=H_UWm7jw-GYuJAxbj@! z1BkIud-NW>!sN?iSTUj8v*AXR5=qXLH>kGfgEYFD>v#AvUzTzlRW&)o{oASrM)4I2 z6_}aCKc;jS2?e%t+^x6E)?Z>yD^YC0B!OuW!^}@$m*jN|>~~OI&55$B+=*&uDGEs# z4ceGAMD?47CZ9`#4nn3p+d^02tK~`T3olD+ETUe64N!%!lq7_D-LX$}Q^XoziUdyv zf0rsnz((4BnMILEo9lDf4ZfyRgpD+_$>$c>#;VcKj9>E=q->daV|efI+P2WL-(=V9 z8BDc-DHs|K9^kyuIKLG9yQFtl;CboG9pqZPwjMu zPawPZDe>AalMM*<>H5;bbfzF60H)d)C~9_vF>#i}_sJ;O+!A`GL(aB&q(=-8$*hnv zxkEV<3aQ7iD6)pBBWi zK_`QBhCW6Twv?ZBY55{46 zdkfM?nAX18+>G(r29hey{e4aNl7iK}CJK_S2dO!jlQ5D%0Z3{pa*c8ID~kD{m$NaT z6JG;P_gZgPU?Juf#T@$V_4|P=9LU3W)kXT-Ex&Dcdj$NY%S9nK83EzNMeG-!@-866 zpQ?-Ex>V^Eoy5ww*l|V-60aumEBt*ILM>w#a0RqDBViAGQ<=lZsW(ssD$o8RX2rqR zg%_;HvpxL8j0laTb%D|)=O6w->I%{oUcJ;Q)lJr)HCxI8KU?VWyp#W5^WZqjH3(n- zDQ8tsZ?LrgVUX1?wz~PFBScn%S@WB2_alL(mUz-d%I2qpjs4ou4j=LCtchgimBsf% z<-&w5y!m|b53JCQv|fEq1v&o^d2z~*)b6-yL&{<>0$oFap-BcK%~gdL77`yABRjDRxF@_ES$gK_Vm_(BXLc?USig4cVswpdi(Rke z*rC(>|F!id;86Z;8?asWP$6q$iL8-*tBfQ?V(e>_eI2rmT_{_~J_wbJHEZ@MWl0T@ zoiU7>>|-DM_v`<>&-=aq@Ax{ZLq}%D{N}!|<-E@8JfD!XYF5hQv>nyI*>B4JCNqzr zUO%<2P`FFe-#s~5NLj(`n>KK@AsvQsg-2KcIGY;;>Q09r<6icB??k`{kAzog?$T&R z(R3MmNl>qf!rFf-?|Fg?;CPdh%Ce6O(;R&~J5!_Riu@r{1v;yqbCZT(W{`(zE|r;S z)qH3X0)b?mL?nnM_Y84v&1*VmSpeH4$QU@;n_jOLvr-w6OMnasr*=+{) zVuL{1K8p(^O#6?&#+6H1w^W!c7X1QHKZ_KQG7kgco0o=X>vT0gDEr*VNZhQEI-|gI zdc)75IzK-2BuV>>edZLtxF_ifb%=_kGPHY)T4$t;7y4{%$S%LenRGEpb-u&?n#hNB zLvKoL`(2G${=Eys+kSi7?snU41H%RZu$dPBasV4GNpwb^CPnWB^S?sT#w-Sa5sQu~ z40habJD|>`{StYhMYHS)%ac%8K4W6GjQuBa(B%YqouLPZw(kyB6-~Z>|6a182z{op zsDf5OsaU~$Fzr_$f?!h<*Zmw6JUsB3DxM*G<8STk(Aore^3vL3FmCCLvOww41U4X&?0VyoODys2#Ip8dfrdR9w>3Uv@Tnte8PBGBRVxxGrN?!_`x z*5igLZZk;FQ&Zb!0f|F$4LxV)(T;X;h*QkQOjLkCMWSYMLRT<9E}x8A4lE)mp0tS? zYmulBWblXmLA0C_kWg5IK8#y?LA;HvA7*~+nZn}SDw=A~pdaJ5k=(E_9c%>kq(4k` zeD6+uclgz1f&X#=Xsmqo&)IWgPvq}IN5AOB!El{Znz0&(^Q!{qQ7x~ZB*!1+n9$A? zktS7~%3ay~j-Z?E^B!3P0g=!$n zXe_!F%(A+AQuu9UP*;=jO%cOjMsRf#5RoTt!NB=d5~+KdzMSIzN(cbpr3gN@`|6ei$!1q3$^H-7)l^9qBH#gZC+XDTJD8VjLHB&wjK+wf*ir;>FW9*Y614@^#T6`kUMT$ zLmrB2EHChrG{@+ghi;vUQ}qm(*|~#S@B%cfZc*W&BZNOG|J$(rsv$q`3?9zEj|9B&FnP zrYXMb~@Tx(6^I0O+h1TXO5*{*Nx4ujLwY7hCa(Wt}b`raMpp=~D_PQl@o`7C$ z_K%oXI{B#_Al>om=zYC^gwRBMQ2zB$a0kI`ZNr^A9+5FzkWk7U@%zKf@b72kl zj%&_N)Zd0_uFf|G4<8I7`%U`~59wGV#W@Bw6d1c?7`y&>%GTe~$RL>8#D-&HDpV>~ zUyQ4AgU#Nh65%S%bGC}b_a&1myAD@~9pWBID_s#Rb!%m57U$L%TolC#d@>UQZz~k` z4^9QjJJVdP9UDRo;Pjz@>1v0l2`H`yXjThKWOHFFqD1>Ov)5E86xP}M_2)QwwQ;Q= z_I<;}lS93qqKyI1-3r4K1}c=AM)+6)4_ET%atOw48yc1u5uC*H z#A-;-L#30WekPlHLWLsaBj$&v%-EoMjY=+s*1^W)Uotpd>lT{tx+EZ63Qhi=+v#s& zs~h@q>kdMSGqy=iJ+4VOV=lVH>;A}snhGO-{h=W1gt*(xy-1;`qY|0M)@ZHYhOkgA zn7kwO_*~!vXsyR6C9!k%bF6G4bBScJ=wxPv+Z~-V zgpUbx)FcQF;tOIu>-w3T+is0IjW^n}$BLNOKMvgESdj%(kgJtk0SrX3VmNfc+O7k| z7c=0uboR#5YK%;C+pp>a{ICIetP){UIU~KdNFBiOWAyr!F`t1-g^9=*+tTv#a)goZ z!4wVY5l7s~D)d(3Ye7s(l4+dB=+hnAgT)|*xt$bTbHFQM%JK>_)e2h+Td&Z0TP@nI z-10_in^`J;>6o!eG3|Qn^>N4h%iCM)pN`aWcJi2`{AnBWJMFHvZP6h{Z4^4_dxaJj z6bJjKzSpv)%56M7GWlp5&>txcT?mG$OV;lz*SN7xpnrY&8n_r`7}NWP?=d2fT%hCa zP&+yhc8~AYV>~d#o%!N%%qIQoMG8=3{G_h${l|*@2tv3K#HbW}_V$I1)CW)CopuK`Eh8XX4nK{5sU)Cc|XOJ@y^>*eanz_Mg+|#=0N;$1@c!Hu|e;- zGUf>--@w=4-nTUC=rVdXE3z_T$0ed~?~C!LjbCqdIg9tSi`zWDqNw$drm{!SN2$S$ zg+5X*kFp1~1dZ5Hw8#d6@eZNKG%2Tx#8EEL?Rr8P{m9&tzW!r&-gjh!>M&+$p2jQvfT z>b>!wk?}E(YNw1pRu1Rf7SBDu|3@rswbJC~6jW+$tGIIWY}l}(GQp&qBWekdYZQtj z-afht)WVz;6%GnrK&N$6(I!IccUK0u4cy)>QP~0gqyP}z&xKP`UO%UONPBrew&d;G z$8NBDaeZ46b#OU(B-}%G`pymL?){OSNRD}>u#Wa!^=I)s#VB3BohNg!cw>-y3`u$Q zjzCdiCky?zcnf&7bBig$JE^cheLz`}2OipHlB8DGDgtY7>So!#8ktX8-gb{gt90uo2S%3Y`lWM zAoopi(HZ|F9+}MZa>QD7F}t*QQp~iySWo^_vf)L93 z2GM}pr1d#BL*%(`l6Bk0@l&M66X9iLcCWLiq564H5pl&3oFnc6%;RjT2XW7B|DZ5U zPQ9U>mp#=N@qIucG73_wsu8hd46{C0TO06kOo&`ynxiz*?}cCR8KoQ0wXS{zn6n$} z;pa;`Z77k(xHqmLF$%L?dWyXKkC`Y7zNcv|GqqXVwh(j7j|ix6luLYq;cENQagXSy zv{pJ#sSba0#Q#xKCvu>e^Y&t3$^3Njul7jbAql;qq_LW)d?{5ngy%Z!R2ag( zG5b9q1-h*47c#uHAV#)9Z9$E5JE;eD&YOkb+5xC{){2Ii#^&$Coo)b#i(g#d}1bzl3O zwhmCVmo;4;{6kiBd%w?q6P0|2+n=2!W^ZPrER-@r2i^mL$dMcSHvzCzNN*uWjXFnf zP7y5zMrP_)q)j3gQXZ}rSE?;P-K*jZ%v4G14}RVGkx-KXCZe+vU5ygzr6EVul-Y-m_Ml%yL|_H_>y~o z9_%0!{Nm?8O3)|NqV2NIh;(XWd9tfUUMQ}tl(DlM_CD)KHt zodENJ&m8yf@||t!(%DNqQ*CcQ@evqs#c#8w@;`kf{#RIkj)-q zP5n7Yt^fFMu!?dI8XH&fZPyt%1{&{Vyy^>~=-9QIZ@36u-l1nzz6ot)P4&=zeG4je zA@%sqIP>*eFel*gDg}w|>W~sn7lr^*+xObH;g=xX3B7yT3s$Vkwg{iDY5e=hcw=B1 z1(B8FDZ~cm+eT=0?WV=0o{y0CJutI|b|>`0Ail}*?m2Y`1J(&s=;(#ix~}({SN96c zpik&}fJi@=AjI-zVB0_UAnCE(dD~@5MB}kL>pnwA$L9k36UzD|B<;8nw17ReN$ar4 z{zM37ednPSbd5cAN{@3uJuq)kxKBMNFf1xO`6vM;lAI~@CFH)d;%%rDnzmVk^>+q- zy*f9&5Gb#vX@mdPZJTk>MhLJ&*q-$kkrJb(?`8iTE$S_Uj8-GkDCV?Dd~xWkF^FupfU;2ta2*|i_qZCx%-M;j7Pt+=icuLxCB zgkMA+S;!!4)J#U5=6(g6JD+-I?x4M`C3+d@-0)fDrv2vgy z2Xq>eEG#V6gnmA-cQGK&)usWX;?uu06y=osHX!<_a+W(geQOYnO;HWJ(FHK z(PM3X{{m@Y@Cv0HicD!4R#pnyT!3u^zu2Mbt9{^usnjoD3(Kn30bH-;vkMD=e4zDy z{j2gGb&V#`nlP>4!_!Ho=Ne=6JV4^40+7jGgJw<2x}v>W<)e~-twaX_o%ZrNkXfKO!)6x~1^suF@nJs>$rOnYt{y|5DMr*KnRYd2Z zCwaipoj(~-8Hb-zIv7j|)0+Ivg4^`wgOXh9z2naEoQ+r2c7vx**rkwkf?oGcR+w~F z8MAnVp%mOzG>2Z)P4xjTX`vgwcb}5ZkRsz5zYdjC3y7z=de~7~$dRLGUu!0Z;|`Q0 zY~>_E&hQ_PuoQ+i$)3<0IeqK`c>Av?SW9e&Rth7vkk$ z0h$X^n~xG#J?**_Q zZH(K%Y^lzIS$&$tDKj1`ofzU^As7Cn+X)`_EG7G{>##NdftmF7DIJzr!$jm}-FF!c zD~K5gTusV)>P{0D8GiP;mS!ow&b6xN)RvJpOh@Lzf3TTVZCK~o)EQ#VyF>iCBAcqM z9MQ?nm^`N#w$Y%(ZbODK96{`T%{v>#HpMki2a#nfe7{i?-xeESR}qzxIDlCRbsC!F~~Tw-{nNq3hu6~D1Jq4}A+#xkNAvU%a8!&#%o)Fd?d^{MLC_UTR4 zV}hV=X!xc6Th=L^rdU%Lf1itLp~;X$s8bAb`cXB6hVmJ-f0$H}xC|9a ztqi{C1rI@?eQuLpHtv=5;OZRdsh8XI$|)U9aXCDFWn+;nk(OP12ckB+L2M`48o>6s zd+MeFxhKm5Z_D|C_YdT*$Np-Bjfk)+vv!`AY?v!&&9D0G#o|i?34?X0;Hr3cMk_(c zI=)aE06BI1df zf5)t0%vOAj{#U(k@$|e|Te*(|lkdXFt`j23dFv4_>!26|I*K}q@<)V-08bzP-DXzu8w`?pzdTMh4S9buYwa9I1aa+41b-nsnyg7Ls)%8f54rl8rqj30J#ad%gv@_HrzVkbdwnTDo% z`k+~Yn!92&cR$rId!PPWFwDGY+R0O*x0cIERXH~|%f=)z@ss*#Y?J0rgDP3E+OxWz z_4&e!#$XK5mHmRudm8h}p}MIPZYz)8HuqlIv!A-3`#4{1=k{c6m}-CNJU`zoTWZ_} zVGoXuzW7`jwG;~3G`0JH;>#>exwmo3!Xl!Gg8068d>+rBxF|ixA683gf}uU(^jt9g z!o6y6Sv-{Q!$sTsGJ+8C`I5I`I#U-_C)B8p6x0@Wx>XI6sjhs{6S86i3Rkv|lCGxk znfu(_9`PbF$3J8>tH#L(aL`=-ZbVwv4PkzPg{0*%?Gps@$65I(^-V_(&hGEgoY-uC z@kUg2>)a`Lp)~!)X&;fOIeJLmX*BXMEiruqlfuhR$cev8D|J4VslK5GpM~B_KU05p zKai)ArP>LX#Htq+^I4DKpP*y^3I&hkk7JBp-AGPKAP_uZ6Jx(}H|bm{8qbBTeMOj?eO&$@h%6Uaq0l=u!^a<%wmf z-B-nqcaTZ5GzdAj-aai~*zVLRIN7=yJ$kWWCy*BHM9nxHFvn026gqCq*EK4B;qE=H zM6Ew+nB^v2#nzmjJIVHltkxvgxb8>Wru9e>Vbaf_OVoeG~*;y;sC84%4nP8rm^QTJ>toi5-Q8ueDXe8eRnVNxOVEE_}{%WD$i5J717~ zBE2#Iw?D~3dqQd@v5`X*YNe=Crt*#yO%0EgS!&K_nwK+g!U|btjm)z>DPj{$$!^PT zoo1{Q9vtw?Z4CH{<6&9_1I**Fk&CSR?AWW#5NzMp&H0zcBc-36j=i1+`D60Wb=M}KY!;Cr zn#p*bNy`APbZB5l5$g2MP0eT|eD!Im1}K%PL{3Br(}t@Rdjm?z1{k?;55n~E+}78? zl3%V8)~~l3fYb}{CMd4UA)omY9Y_m&&=S5YOjQgP4s?+cv^4EDu9Q~{6*#qAzKwad zXWa18c<@a;UWuJ2pM^3{UQw|V6fWd#LJ&z*%O#>*6f`qFkq3BNc0AON8u+F(uDo~S z&$=Y5%Y%`Rfz`oju#Jc7*mfO`i|MF>Ipm>v_T9OGELem;ah8sx`3iIHI4QybD9^sf zG&gO8SFF#Uei#K3nyqE75W`JTC)T=f9o_SQoIZgyYQ1F;@-P1O)UFE8Rf$q$Y0D-p|x%c@17%B!gi3MJb#`T4@xAGcQ>tp?dL9+!KXr1CV< zxu0b#H4c5Et6*8hG(}zdMQ$Da^YG>Dn&3-q??1cV2T3*$%GD2cY+95KEDJMbTQU+P zjYlTt-tIvWG@o5a%eaTE%0@70DSK{3)Ka_hmc>m!>>4SgK&Z~$BlAgw#E%`=2sOl4 z@g!0>?{b}Ib|;&(PEClaL$Dc)yGw=XQj|+&jeDs~GQ*wmCIllROY<*M{9C3-z`N^$ zEURVwx<7Q5$@F=Jk({?arp?M@?m_mO8wScsPfzYGZ;bQsmnlgS=7gW2#r?UvA{gpq z<+LDz1iw6A5%^2K3!2@s=u%=q7*#(nFAM=4tX$_zu0-(cAeGu${pv! zS+y;jVsxk*r`KKi+sF3^4Z1Y6MtSQBoEr@1JqK!TXWc25ZL;rr6IF#DhxkyFtGRwNSKb#vN-c zppnp48@8!nm6}}m@nw+6;Lg?ns*C9 zwZMdy2ZKl6D>rA^<9jJlxtxFa#UafK>|O}!K!o{N1XvTXW-0Upc4SuInaYgom68j6 zF{{rE^k!b#ogLV(3}Z|L4S}m*>d$i1>Q>OexJH(2biZu)1muJ-;2+&UVSseQLoSWH zI8zPm=hD;s!u%XVdQ>o_4ffaVqol7i^(uCC=4X(KcIb#n#HNflY(6{#49P`Yfnsg8k9lW<+a&JrBXS*efByXGp454vP3w@&vm9sixUP>Z zi-l7Lm-wK`+)-kRecPr)w590th$s4#hIRlDfca}ZIq^ziPLuU6s^Ng7-U%DA#WOwA zWT>{nlAomAd2=EQcI4hjU@^@*8@_U6908?N_@-D|+gMc_$FiIFWyT0W8Z_%H`$-_@ z(FQr^sp6YA2}_=r!)-|$0qsT)>ndc=4D&@OEAK`3tp0Sp(Xps3-M=#^UbBAR>=Ct+ zv*m}yoTI6Uhxa(&=Vgtm_|n?jiAuh&;o}Qxa63GEhDCAF(E{4oJu3|aY6A$It2B`CshLcTJ?H`~FeQOHb77WWj1D78SU(7L?7gcP9g9PNT3#8)-Px!7{)1_?%|1_-FniAiJEr;j7mnN+c}I`e5e87l zMidrgM=TsZ{lN#m5gc)zUF7a~+nYC!ELkU@Fw@Vcu@}frmu6b`D(VI_LT(gYjqi;_ z<$kRbW!L_}0gCWrrDVNlWTN#c>trPW;{bBL)<^O#f=BYYP{$5b$9R+1tohT|X>8zj zt7-!T{i=M;@RL1lM@yJB6TkU!LA)B^4&h2`{(+bncHPy1TnWp|8KMLz3}_ zBKpV=E?~%Y71bh!HQ#atGXEZ6o%>kAku;Og+3|bR;i$P@=&NdapHNz`X$H>t_*p!o z;m8fhkR?p>FX`JG%nH7Q3F?^v8Ox>U^eC`?s?c*8Pys=H)qo5=z>yjNt5$OrIb{hG z&bZU?OqTvsvH_Iig|Y!_)2kaa)AAdO;|vi2V5-&vrfN@ba$Sbhnwr&TACXhs3VHYG zW0q(qNdwuKR|8AtZx7%??r3GVp2dW`a+|u?wmFn$NhauJEcI24KlM58k3c}KVK(c@ zMXzA}iGX(jG(1h|-otYHa;dwV6d{b}lP>qisCtgg^)eTi1W*UXq=ylQ^L5-1KDDy)N5>vz1KPI^U(UG|992Nt2^VNrxZ^UL&e#Z&viD@Go@0Y4)AU)u?MIn>|r?O z&7t#bwg)MnhW~6^(@UO9O(524 zOB25Fvlx>{1C7r3BN|Q?#-WPhv>RU+`Cz;UDu>FdH-vUKAHugG8Ab8bN^g}oWE_@i?j-njGjHi8|EJ^tp)So)vkONNjkmhhyL z1XS`j*E%|^c|Ds(x`QUHUD|E`Pfh+#?SU1?X}(B<9j2>)x~ilD_sbtmk2)Bx2uo(1 zl42O1H678Z%k+vf*x-L~TLt}hR{8gLN%?jl>vlD{?rsn7>|;U?5Qu*eXzg+D&4V|8 z!nkL>p-|xHz-PZ%{7Z!sAD%H6czk;JZ9lb;s5&Kgce0^L67JF&MvpwAB&}1BbYA4< zH=Xqi;qwf!30juR_N@tkZm-2oHu5L{!O>Sj~l0rj8>+&LAz0;`^`7tm%pV++ku61H7D~C6SsZfZ|q}YucM2 z%?|Hb&6~&ZW5zqR6rtESX+L#6DBnjtQBTWPt4R=FO$~M;S|)aS7M*cpshYabdQ-vM zQ}qyb7G^C0DJ37Hh>MZae~UNrkPU0(H-rDadb!x4Mdd4hrj=JQ%wM3FxQZ`OiZ3T z+=#sMKO7}{PW4YsKn;i^BHpi2;J0FwsZG!$+BV02&8Yh94aw5K%#ynzbu=<^$@r+J z>5L_3LgpAoY+KrBH~oe4^}Uj+U5GD^F`Ju0t7A_izSGbRr$qM5MsODzJ?>m~d*t4x z!c+Jw{)3nP-kS!EZP}k#CKxSg@mbeXr&&Y3FzSQ7$hj%fz9g3t{_z_zJs;2hkDq#R zdn%qzb1Zv1(3Vy9Rf$=;ah7VyHW3?@?JyhxmHV?9OsfPTA#+JT#D}l+1fH)kHts+H z<4^#q5^1(CN3ciC{uqrv4ry~={E9Ziq13uJw>JDUXei`K?$1|RbP2V7sU7f$>5y#8 z-n0|r5ld}Hhqli{1X9JbR_9LU?vg;J-w&-m4qg17HJ496p$5hH^moBY_;d~!jCF#a zGdjRbEpA{`P0;C(FfZp;+stHZr@pwngd0B)>v%kJh{ir!FdoM&2JXLKP({#GkL7J| z-02xohJAN$`lXl+j3v(6l1N9t)B$7w8ZhQ>XH)eiJ={5iWG3o&SyM-hN5Y(_U7E>@ zhlIJ}JQ%waFt*jW4MiL>WK(MC+DN!*Sk1GV!?T6oeelvTtCvL&JtnTS?hxI)e`x7d zH$CA0#WBlqup3o577N%79M3a@mIQ{*NH(2wW96X>h%q(1IfF7+-rB@UQ|VSt&xUoh za1DS|wd#KG1xitlZtQ*(I*OPw94W6Y)pjJ4kru0vgyhZVyK7V0e^R1P7Ovmd!uaL6 zpNF;Anei8WcUbtT&_Dc}9rq16v4~W_Z&mDNsck*Rzj?dq;l!uWB^ZJgL<=f!VLz(2 z&?oJ6gT_Rt-@XJjFf?lK_@7k58T+FIf#(%?+q4DT!DzRyJsM8S1e(|IFkBd4-vU;Ixn>ykKfP(T)801H=CmH}a48=;x1b@?6OmjozSDB#h(}VXG1wcH? z!+fw2Ul1^ zmQyf)TWsWeN2zfk70AK&KF;&l{ah5sH~GL_0@K_{vHaA>+7t$pugu@=qzU5_>5Rt* zRzI0!AzPys`gW0{XCw5>=psFJ^1ZUVXH#FIlBsiPSon^jL5q9s{5ZxReHQly0871N zB1(;X6@x$ATtn1ejR!X#3k$eh6>;^mq(TZ_*>ym9wi1fhKSW@Wh1$I zHgZ<$XW6sUABptY=14U%-nnk)WRc&;g_E><8~-gHPl}vg z&i_AG54bY=W2N-$lnDy=N{0t1o5UM|7 zF&R5AoG2_GY)bNhb{3NdCIdZjX3fd;+!c~>Qm$@-4#+M^0hQubLaUEFr* z{`yk(`Bg90$6o>;=n?2bhD`gG4u5F9LkClggP)mmKn%RfpySD3-vhdF*3(donC$OV zbNo2NI*{iaym>eXAc>~IJD6q-Ofy4dIHe}d{3!*d=S+CP{fz5?E+<4vYO)8=lW zM!Tu1!=l&~qJDw@9cNV=*Z^%u@V97RG5s2 zp+QdJ-`c=*oLP@iHHWS1l@6aW>l^*2ocizInOCjT&;YL>QzNTjL|lRpz#grGw)U4i zGSHT+%Y(M0f!N(GNbDwl2e8Z}dO4^Cq42!emg3zKnVr9#KWv7Jf2OklWrIgfJpvLB zPUpTpK68z%d~{^wIIWQtM+TU(#K5*2&E&oE^A{jKXf+mhS{|9d6V?HMdr%8k%^HTK zq>u(4>AX@voQP@UhKd2#n|^?~@V^~iY)0F`W_X<)UIIXn`_^*vAT9ro6Ym0#H9o9U zkIzw1$H!3sa4@*jU7M?uZlp*i=leRwCyo zQuILxQPF-;MW08X2R}r}yCq@m7HczebLCd_t_iIaMHtPIFEG-wrEogGxa``-IQ-6K z_^tJe@_tQ+?!eWe+86o`bgQ1rZ8;;UD=S34ou)=A+W8{nsA_1gM|(=Cy7T^{IO zLN6~WSj-zRw8wmSq^0U@bbw5kYvzoXo0q$7r=wQ z11WUuBA}^X3?%fVqfeTX(ZI}E`jZpy49v)=&PXJ^xe?#$@~?bwD_}5#@rB%m;rI@4 zFB|X=TPOi|-&?q6E9n0p)JbN76YGKanyKV>aN4fh*TdH^O3D2FV>VDe!x70yYhXGT z$mVUoyQvKS%@dV{YNnJfGN$jrxrM6%SG|3H!n6n4hg9+6kq4s`7b}&o*r&z;8WY{g_+E%z5emzXylre^a#Hv9?eD)XkfPpF-nRl0FY^Obr;zN> z@%u&QBh*WOfDCqw`?3Nrh;Rld_^;)mD=8zwz}#cf3piElP=t`pl4Chi^8f_1HZX=& z-eYK!!>xmO&-t6FRNm;F#LsB+n?U;tEWWSQT+4(@rRw&B4f|z)CfR;cy}s*>spRe1 z2v?nSy6NqQ1X4ifN!%KB<@C~)jWGbt+CbBzDR53tYhSVbWq}mPKKl9u>`8u+9r<_B z@aK{Wj8f>Qp_2Sv8zXRr;1#-k+CJ26YN1fahkK`zHo+pF#&SiwmFGhJ3MN@}Hx_i? zxLZPFM$c?7e+prnQU9i#)fB%s2K=665LTCdZkXMC;X26|=>I0eq~*LcZ6n;1_r-wb zDMAOK{+tFT>4?U1OYd)Ips;+;{Z0iFi`pk8g$<32w$yRXIB>alW;XmWM%)?{L!W_F znv7^tocds9(h#RbqI(l)7l4Ct4)HpC)#2&c0lEA|8}zkv<{et|%^9#))-HdR?w zg*`uh#(8C=eC#_J5a`?2LR+r!t)TrbG+DB1Q1LzKO*fa{yFNM8AIgmkLzg}T6 zLp6R;*ZuzVzTaW@pi{s_`;aIh2FJaX98?Q;MEp1Uy2lh?oot4_zF$22JY*p*uFtJ* zw3VGiA8wHrQ`uj82Hx=_SySY<_b!H z+t|Xp8EXK{)~dff6$`-CYcCw#8NXY+M0nEJ{7Lrs|GfD+@a7>9%C4RkrR2_~?v0nw zbK3B_?pl-gjcyh1yOT&aSG0hjD*QIsX=w}$DkRX4DD(>d>{ODtYm?P3@x0hEn4K_< zd9(V__tLYrSz#TlYXBJxXkxKA4a5mkk0p$rz5_!*DqDVgEMPFOJ2Biix%@19JuUrD zNs7kgIWy(w#W`>4S>$ya&)~zZhUCP5qZ-Wxdt$lPT*I}Wl{rAhvZ7@q(^v!-;ZM(% zlX@%jQk<2pEYR(>7*+x7SWPlUYl;47!e?G;@lw_@zKY~lD`e^f9bq`)U!z8-o1OYCcv(fvYaxGY>KRj;K(ch;YVEo;W|2UEiHA)1w$D|RUhB` z{;vuyoCgFGR{9@=xu;6Wdn>&(!;9M`pr*cB6NU1mmKaWyCQQ?l)>&(16VR&SNch+s zLni+sl6&|b=9y5r$l+w#SM$gJ%7@)!NQ}z$v`_t^Z|~;R4uR=z$4V7>1_=AnvN^&} zdiU;_{W7>NjOFZLBFYk*nB8TsuAPysuqS)?uMopp~>DxU0MnlDGH-~70(10>q{IR^x9Xt)A#UbnF#d5486f#LcX zoA%)L!SQj@)tcZJY^ts4t%iIDZgR0yuyzQLaJp5#RBu%#%IZP|L|r&eDU}Fs$vV5a zaRwDAR7=zK;qydH3!>uZk5!t>U21k(Fzd>a<$&|7%C}*Mlnjxjz5|jt{y^H^i;!A_ z?6oV=pBiTea`(&wZDCL$$LIe#kJt_Qw{`N@v3E3pl1pgy^}HES;;9P+k#qa`T6)|c zfx4oqfZ)2<1rNs0K5b@DjKN#&1>^&_%YPeDftv7awYH)n`>-_zC2@%X&qIHqCg$6o z$1I<=0n3xS{=#)>q3{u~!gZ~ZFm&A9Q~Lh>h7sZx4chR{&ooiAS_DX&BMJ5Ud>v-T z{`M<9U{KWLbLQRBMKXx2bil+I9c$`~kA5N=(S!xCD<<|+<9TrzT7%lAb7?`QgV8}O z*JFg;ab$Fn<=gkIsSsI%DSac5)~sLI{*hKSTFfV6#q;&Uo64uI{wsTw5EhMTfZjCo zHL~`|u1JO04W(p`#|El|7U74%z#CZ%rhet_iO2Sz9|?EN4Pep~-DC`-z=M8SZ^p*K z0Y4Y>Et*X^Gx<@LgdB8%9L7t#a_w)=Mn!wuxosS7ZYz$!b59P~j7#D_Qb$JZbddGF8xfeci@Rl9P?Q~ zMKT#bd%<-9smk=>3~2-0D5mO%D|H-xcHI3`uu!&llm}9vso+O6e$E5M^)D(Akqjsk zBJ;H!vr$!Kh|E66NhMw+e2SGmi8AlA&(W=-RaL?X?vY#;~1NY?YNx=&y_JaHb*uC6L<;Yq>#W}Wv(M}ZcU#=eo{5*a~i#n(1GdW+tG2F@OSO;eO=+Z=LQL>(4$`ENT}-dghpZ)@|0iQ5B#$ zIyB_I6_}&R@|EHX#C{)gr9P8h#RQyXHG@l)D$>(x11s2%Wr9iL+EPvtKMW3H|1p)0Szz+!H(&%WPc%0XM z|Er4OIbkkNL$K{^VLguU^_(%gTl>!u{kXC|D#j&2n2rQ<(Hloz^It$abhp<-5F#Hz zF$=hRZ5{1!rJvnF9{}xHyyt(XDE}n1ME#)&$e+J!s7uI0YHy|*F`^Y%GJOpsi`=4b z_|jpTiy)iBY)dqI{umEVjVv9*dJACf%{0!c#Ac=_(dvSZAjhk!?mlpFaZ#p`4%!L^ z>IijTCX;zpcR@}+MxPX2`1qjPpH=w*jJ;%uPF)r^6i6m5UT>7`i6^7`Mzu>5Mz#N| z`ljDus(tOd=rh-0USzJsFCXG4h4oT}Kl>o`RPw`A0Aq3uIVGQJ0VHC`#VbC{KWBhX zO8a4sZ$o#<%s>Y{O1hgL0+y2mW)*;5LjkyKf!< zIH)!^zJkUbg^DA4rnPz=hg(o`Gy<64uyTOscwuN{DH4v4I81YAWlaSyhRvMAl;2}Y}h;VrDCf_yyo@0 zAdz8_KZo#F3iV--Aw? zQ5;GJ{DSC-o`#AFiE2tAP*_c@7K?t(imZ_ab^yrMnNSc1B?;3;feu^mWAIDJR@!l@ z+s`w+7La<$Ghq`s!eBkQxdbSi=auT`2lxK@Q36IJuo;+RYaxZ4h(SS{tCm(*K547t z75kOt)~{q7jZL=u*-Ae1IMDs~)IQ!}Szms%%8hOYG`-xrz~4mRld2}!DDCsd%D^gA z$lT2OR|_~?Tej}Tv*T8<^oLvF0O>aXuOaMz4p=Xd>r-GDlZQ?z+!W>It!We8t5Yg0 zc%)7LHncI{vGi7q+h8+E<6<_l^m{*GvpJGmYHsi!izDf+c7H9nEj2F;x`M%&oK-C#&N2O72Eo38m(cU6Cd?sKq4{T=em(>ujP%|HaFyf4e-nZx&|C)AJN*(QL&&Isy9ce3@#^N=ynh+SERH#29#Xt^#zd z=~H886A+&4LBh4Brrv>)KQ=b@GB9c^te3-nCievpa&<Y=6c`iPip&RspTQwITNhp7wWOlG`h0uYCYLJrb*NwN#?Tsu^*0G9o$rH#XVYddX( z&qi^4JWej+qhP5Va=?!YKk^5MR1{6if|XIi{p&O7GV8t_aQT4};eZmP z&1-;e{geE3HNxkJTNi}3FjO$hAb>X-KZ1kPG{ZU^hyYO}POoh&#fJ+Y%0SVOk^&6J z^&@mPb - ESP32-C3-DevKitC-02 <../hw-reference/esp32c3/user-guide-devkitc-02> + ESP32-C3-DevKitM-1 + ESP32-C3-DevKitC-02 .. only:: esp32s3 diff --git a/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst b/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst deleted file mode 100644 index 857ae0bd6cc..00000000000 --- a/docs/en/hw-reference/esp32c3/user-guide-devkitc-02.rst +++ /dev/null @@ -1,236 +0,0 @@ -=================== -ESP32-C3-DevKitC-02 -=================== - -:link_to_translation:`zh_CN:[中文]` - -This user guide will help you get started with ESP32-C3-DevKitC-02 and will also provide more in-depth information. - -ESP32-C3-DevKitC-02 is an entry-level development board based on `ESP32-C3-WROOM-02 `_, a general-purpose module with 4 MB SPI flash. This board integrates complete Wi-Fi and Bluetooth® Low Energy functions. - -Most of the I/O pins are broken out to the pin headers on both sides for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-C3-DevKitC-02 on a breadboard. - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-isometric.png - :align: center - :alt: ESP32-C3-DevKitC-02 - :figclass: align-center - - ESP32-C3-DevKitC-02 - -The document consists of the following major sections: - -- `Getting Started`_: Overview of ESP32-C3-DevKitC-02 and hardware/software setup instructions to get started. -- `Hardware Reference`_: More detailed information about the ESP32-C3-DevKitC-02's hardware. -- `Hardware Revision Details`_: Revision history, known issues, and links to user guides for previous versions (if any) of ESP32-C3-DevKitC-02. -- `Related Documents`_: Links to related documentation. - - -Getting Started -=============== - -This section provides a brief introduction of ESP32-C3-DevKitC-02, instructions on how to do the initial hardware setup and how to flash firmware onto it. - - -Description of Components -------------------------- - -.. _user-guide-c3-devkitc-02-v1-board-front: - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-annotated-photo.png - :align: center - :alt: ESP32-C3-DevKitC-02 - front - :figclass: align-center - - ESP32-C3-DevKitC-02 - front - -The key components of the board are described in a counter-clockwise direction. - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - Key Component - - Description - * - ESP32-C3-WROOM-02 - - ESP32-C3-WROOM-02 from Espressif is a powerful and general-purpose module that offers Wi-Fi and Bluetooth Low Energy coexistence. It has a PCB antenna and a 4 MB SPI flash. - * - 5 V to 3.3 V LDO - - Power regulator that converts a 5 V supply into a 3.3 V output. - * - 5 V Power On LED - - Turns on when the USB power is connected to the board. - * - Pin Headers - - All available GPIO pins (except for the SPI bus for flash) are broken out to the pin headers on the board. For details, please see :ref:`user-guide-c3-devkitc-02-v1-header-blocks`. - * - Boot Button - - Download button. Holding down **Boot** and then pressing **Reset** initiates Firmware Download mode for downloading firmware through the serial port. - * - Micro-USB Port - - USB interface. Power supply for the board as well as the communication interface between a computer and the ESP32-C3 chip. - * - Reset Button - - Press this button to restart the system. - * - USB-to-UART Bridge - - Single USB-to-UART bridge chip provides transfer rates up to 3 Mbps. - * - RGB LED - - Addressable RGB LED, driven by GPIO8. - -Start Application Development ------------------------------ - -Before powering up your ESP32-C3-DevKitC-02, please make sure that it is in good condition with no obvious signs of damage. - - -Required Hardware -^^^^^^^^^^^^^^^^^ - -- ESP32-C3-DevKitC-02 -- USB 2.0 cable (Standard-A to Micro-B) -- Computer running Windows, Linux, or macOS - -.. note:: - - Be sure to use an appropriate USB cable. Some cables are for charging only and do not provide the needed data lines nor work for programming the boards. - - -Software Setup -^^^^^^^^^^^^^^ - -Please proceed to :doc:`../../get-started/index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an application example into your ESP32-C3-DevKitC-02. - - -Contents and Packaging ----------------------- - -Retail Orders -^^^^^^^^^^^^^ - -If you order a few samples, each ESP32-C3-DevKitC-02 comes in an individual package in either antistatic bag or any packaging depending on your retailer. - -For retail orders, please go to https://www.espressif.com/en/contact-us/get-samples. - -Wholesale Orders -^^^^^^^^^^^^^^^^ - -If you order in bulk, the boards come in large cardboard boxes. - -For wholesale orders, please go to https://www.espressif.com/en/contact-us/sales-questions. - - -Hardware Reference -================== - -Block Diagram -------------- - -The block diagram below shows the components of ESP32-C3-DevKitC-02 and their interconnections. - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-block-diags.png - :align: center - :scale: 70% - :alt: ESP32-C3-DevKitC-02 (click to enlarge) - :figclass: align-center - - ESP32-C3-DevKitC-02 (click to enlarge) - - -Power Supply Options -^^^^^^^^^^^^^^^^^^^^ - -There are three mutually exclusive ways to provide power to the board: - -- Micro-USB Port, default power supply -- 5V and GND pin headers -- 3V3 and GND pin headers - -It is recommended to use the first option: Micro-USB Port. - - -.. _user-guide-c3-devkitc-02-v1-header-blocks: - -Header Block ------------- - -The two tables below provide the **Name** and **Function** of the pin headers on both sides of the board (J1 and J3). The pin header names are shown in :ref:`user-guide-c3-devkitc-02-v1-board-front`. The numbering is the same as in the `ESP32-C3-DevKitC-02 Schematic`_ (PDF). - - -J1 -^^^ - -=== ==== ========== =================================== -No. Name Type [1]_ Function -=== ==== ========== =================================== -1 G G Ground -2 3V3 P 3.3 V power supply -3 3V3 P 3.3 V power supply -4 RST I CHIP_PU -5 G G Ground -6 4 I/O/T GPIO4, ADC1_CH4, FSPIHD, MTMS -7 5 I/O/T GPIO5, ADC2_CH0, FSPIWP, MTDI -8 6 I/O/T GPIO6, FSPICLK, MTCK -9 7 I/O/T GPIO7, FSPID, MTDO -10 G G Ground -11 8 I/O/T GPIO8 [2]_, RGB LED -12 9 I/O/T GPIO9 [2]_ -13 5V P 5 V power supply -14 5V P 5 V power supply -15 G G Ground -=== ==== ========== =================================== - - -J3 -^^^ - -=== ==== ========== ==================================== -No. Name Type [1]_ Function -=== ==== ========== ==================================== -1 G G Ground -2 0 I/O/T GPIO0, ADC1_CH0, XTAL_32K_P -3 1 I/O/T GPIO1, ADC1_CH1, XTAL_32K_N -4 2 I/O/T GPIO2 [2]_, ADC1_CH2, FSPIQ -5 3 I/O/T GPIO3, ADC1_CH3 -6 G G Ground -7 10 I/O/T GPIO10, FSPICS0 -8 G G Ground -9 RX I/O/T GPIO20, U0RXD -10 TX I/O/T GPIO21, U0TXD -11 G G Ground -12 18 I/O/T GPIO18, USB_D- -13 19 I/O/T GPIO19, USB_D+ -14 G G Ground -15 G G Ground -=== ==== ========== ==================================== - -.. [1] P: Power supply; I: Input; O: Output; T: High impedance. -.. [2] GPIO2, GPIO8, and GPIO9 are strapping pins of the ESP32-C3 chip. These pins are used to control several chip functions depending on binary voltage values applied to the pins during chip power-up or system reset. For description and application of the strapping pins, please refer to Section Strapping Pins in `ESP32-C3 Datasheet`_. - - -Pin Layout -^^^^^^^^^^ - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-C3-DevKitC-02 (click to enlarge) - :figclass: align-center - - ESP32-C3-DevKitC-02 Pin Layout (click to enlarge) - - -Hardware Revision Details -========================= - -No previous versions available. - - -Related Documents -================= - -* `Build Secure and Cost-effective Connected Devices with ESP32-C3 `_ -* `ESP32-C3 Datasheet`_ (PDF) -* `ESP32-C3-WROOM-02 Datasheet`_ (PDF) -* `ESP32-C3-DevKitC-02 Schematic`_ (PDF) -* `ESP32-C3-DevKitC-02 PCB Layout `_ (PDF) -* `ESP32-C3-DevKitC-02 Dimensions `_ (PDF) -* `ESP32-C3-DevKitC-02 Dimensions source file `_ (DXF) - You can view it with `Autodesk Viewer `_ online - -For further design documentation for the board, please contact us at `sales@espressif.com `_. - -.. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _ESP32-C3-WROOM-02 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3-wroom-02_datasheet_en.pdf -.. _ESP32-C3-DevKitC-02 Schematic: https://dl.espressif.com/dl/schematics/SCH_ESP32-C3-DEVKITC-02_V1_1_20210126A.pdf diff --git a/docs/en/hw-reference/esp32c3/user-guide-devkitm-1.rst b/docs/en/hw-reference/esp32c3/user-guide-devkitm-1.rst deleted file mode 100644 index 2e9cb14e42c..00000000000 --- a/docs/en/hw-reference/esp32c3/user-guide-devkitm-1.rst +++ /dev/null @@ -1,240 +0,0 @@ -================== -ESP32-C3-DevKitM-1 -================== - -:link_to_translation:`zh_CN:[中文]` - -This user guide will help you get started with ESP32-C3-DevKitM-1 and will also provide more in-depth information. - -ESP32-C3-DevKitM-1 is an entry-level development board based on `ESP32-C3-MINI-1 `_, a module named for its small size. This board integrates complete Wi-Fi and Bluetooth® Low Energy functions. - -Most of the I/O pins on the ESP32-C3-MINI-1 module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-C3-DevKitM-1 on a breadboard. - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-isometric.png - :align: center - :alt: ESP32-C3-DevKitM-1 - :figclass: align-center - - ESP32-C3-DevKitM-1 - -The document consists of the following major sections: - -- `Getting Started`_: Overview of ESP32-C3-DevKitM-1 and hardware/software setup instructions to get started. -- `Hardware Reference`_: More detailed information about the ESP32-C3-DevKitM-1's hardware. -- `Hardware Revision Details`_: Revision history, known issues, and links to user guides for previous versions (if any) of ESP32-C3-DevKitM-1. -- `Related Documents`_: Links to related documentation. - - -Getting Started -=============== - -This section provides a brief introduction of ESP32-C3-DevKitM-1, instructions on how to do the initial hardware setup and how to flash firmware onto it. - - -Description of Components -------------------------- - -.. _user-guide-c3-devkitm-1-v1-board-front: - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-annotated-photo.png - :align: center - :alt: ESP32-C3-DevKitM-1 - front - :figclass: align-center - - ESP32-C3-DevKitM-1 - front - -The key components of the board are described in a counter-clockwise direction. - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - Key Component - - Description - * - ESP32-C3-MINI-1 - - ESP32-C3-MINI-1 is a general-purpose Wi-Fi and Bluetooth Low Energy combo module that comes with a PCB antenna. At the core of this module is `ESP32-C3FN4 `_, a chip that has an embedded flash of 4 MB. Since flash is packaged in the ESP32-C3FN4 chip, rather than integrated into the module, ESP32-C3-MINI-1 has a smaller package size. - * - 5 V to 3.3 V LDO - - Power regulator that converts a 5 V supply into a 3.3 V output. - * - 5 V Power On LED - - Turns on when the USB power is connected to the board. - * - Pin Headers - - All available GPIO pins (except for the SPI bus for flash) are broken out to the pin headers on the board. For details, please see :ref:`user-guide-c3-devkitm-1-v1-header-blocks`. - * - Boot Button - - Download button. Holding down **Boot** and then pressing **Reset** initiates Firmware Download mode for downloading firmware through the serial port. - * - Micro-USB Port - - USB interface. Power supply for the board as well as the communication interface between a computer and the ESP32-C3FN4 chip. - * - Reset Button - - Press this button to restart the system. - * - USB-to-UART Bridge - - Single USB-UART bridge chip provides transfer rates up to 3 Mbps. - * - RGB LED - - Addressable RGB LED, driven by GPIO8. - - -Start Application Development ------------------------------ - -Before powering up your ESP32-C3-DevKitM-1, please make sure that it is in good condition with no obvious signs of damage. - - -Required Hardware -^^^^^^^^^^^^^^^^^ - -- ESP32-C3-DevKitM-1 -- USB 2.0 cable (Standard-A to Micro-B) -- Computer running Windows, Linux, or macOS - -.. note:: - - Be sure to use an appropriate USB cable. Some cables are for charging only and do not provide the needed data lines nor work for programming the boards. - - -Software Setup -^^^^^^^^^^^^^^ - -Please proceed to :doc:`../../get-started/index`, where Section :ref:`get-started-step-by-step` will quickly help you set up the development environment and then flash an application example onto your ESP32-C3-DevKitM-1. - - -Contents and Packaging ----------------------- - -Retail Orders -^^^^^^^^^^^^^ - -If you order one or several samples, each ESP32-C3-DevKitM-1 comes in an individual package in either antistatic bag or any packaging depending on your retailer. - -For retail orders, please go to https://www.espressif.com/en/contact-us/get-samples. - - -Wholesale Orders -^^^^^^^^^^^^^^^^ - -If you order in bulk, the boards come in large cardboard boxes. - -For wholesale orders, please go to https://www.espressif.com/en/contact-us/sales-questions. - - -Hardware Reference -================== - -Block Diagram -------------- - -The block diagram below shows the components of ESP32-C3-DevKitM-1 and their interconnections. - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-block-diagram.png - :align: center - :scale: 70% - :alt: ESP32-C3-DevKitM-1 (click to enlarge) - :figclass: align-center - - ESP32-C3-DevKitM-1 (click to enlarge) - - -Power Supply Options -^^^^^^^^^^^^^^^^^^^^ - -There are three mutually exclusive ways to provide power to the board: - -- Micro-USB Port, default power supply -- 5V and GND pin headers -- 3V3 and GND pin headers - -It is recommended to use the first option: Micro-USB Port. - - -.. _user-guide-c3-devkitm-1-v1-header-blocks: - -Header Block ------------- - -The two tables below provide the **Name** and **Function** of the pin headers on both sides of the board (J1 and J3). The pin header names are shown in :ref:`user-guide-c3-devkitm-1-v1-board-front`. The numbering is the same as in the `ESP32-C3-DevKitM-1 Schematic`_ (PDF). - - -J1 -^^^ - -=== ==== ========== =================================== -No. Name Type [1]_ Function -=== ==== ========== =================================== -1 GND G Ground -2 3V3 P 3.3 V power supply -3 3V3 P 3.3 V power supply -4 IO2 I/O/T GPIO2 [2]_, ADC1_CH2, FSPIQ -5 IO3 I/O/T GPIO3, ADC1_CH3 -6 GND G Ground -7 RST I CHIP_PU -8 GND G Ground -9 IO0 I/O/T GPIO0, ADC1_CH0, XTAL_32K_P -10 IO1 I/O/T GPIO1, ADC1_CH1, XTAL_32K_N -11 IO10 I/O/T GPIO10, FSPICS0 -12 GND G Ground -13 5V P 5 V power supply -14 5V P 5 V power supply -15 GND G Ground -=== ==== ========== =================================== - - -J3 -^^^ - -=== ==== ========== ==================================== -No. Name Type [1]_ Function -=== ==== ========== ==================================== -1 GND G Ground -2 TX I/O/T GPIO21, U0TXD -3 RX I/O/T GPIO20, U0RXD -4 GND G Ground -5 IO9 I/O/T GPIO9 [2]_ -6 IO8 I/O/T GPIO8 [2]_, RGB LED -7 GND G Ground -8 IO7 I/O/T GPIO7, FSPID, MTDO -9 IO6 I/O/T GPIO6, FSPICLK, MTCK -10 IO5 I/O/T GPIO5, ADC2_CH0, FSPIWP, MTDI -11 IO4 I/O/T GPIO4, ADC1_CH4, FSPIHD, MTMS -12 GND G Ground -13 IO18 I/O/T GPIO18, USB_D- -14 IO19 I/O/T GPIO19, USB_D+ -15 GND G Ground -=== ==== ========== ==================================== - -.. [1] P: Power supply; I: Input; O: Output; T: High impedance. -.. [2] GPIO2, GPIO8, and GPIO9 are strapping pins of the ESP32-C3FN4 chip. These pins are used to control several chip functions depending on binary voltage values applied to the pins during chip power-up or system reset. For description and application of the strapping pins, please refer to Section Strapping Pins in `ESP32-C3 Datasheet`_. - - -Pin Layout -^^^^^^^^^^ - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-C3-DevKitM-1 (click to enlarge) - - ESP32-C3-DevKitM-1 Pin Layout (click to enlarge) - - -Hardware Revision Details -========================= - -No previous versions available. - - -Related Documents -================= - -* `Build Secure and Cost-effective Connected Devices with ESP32-C3 `_ -* `ESP32-C3 Datasheet`_ (PDF) -* `ESP32-C3-MINI-1 Datasheet`_ (PDF) -* `ESP32-C3-DevKitM-1 Schematic`_ (PDF) -* `ESP32-C3-DevKitM-1 PCB Layout`_ (PDF) -* `ESP32-C3-DevKitM-1 Dimensions`_ (PDF) -* `ESP32-C3-DevKitM-1 Dimensions source file`_ (DXF) - You can view it with `Autodesk Viewer `_ online - -For further design documentation for the board, please contact us at `sales@espressif.com `_. - -.. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf -.. _ESP32-C3-MINI-1 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf -.. _ESP32-C3-DevKitM-1 Schematic: https://dl.espressif.com/dl/schematics/SCH_ESP32-C3-DEVKITM-1_V1_20200915A.pdf -.. _ESP32-C3-DevKitM-1 PCB Layout: https://dl.espressif.com/dl/schematics/PCB_ESP32-C3-DEVKITM-1_V1_20200915AA.pdf -.. _ESP32-C3-DevKitM-1 Dimensions: https://dl.espressif.com/dl/schematics/DIMENSION_ESP32-C3-DEVKITM-1_V1_20200915AA.pdf -.. _ESP32-C3-DevKitM-1 Dimensions source file: https://dl.espressif.com/dl/schematics/DIMENSION_ESP32-C3-DEVKITM-1_V1_20200915AA.dxf diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index d651c66a7e9..c731f67f7e8 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -131,8 +131,8 @@ .. toctree:: :maxdepth: 1 - ESP32-C3-DevKitM-1 <../hw-reference/esp32c3/user-guide-devkitm-1> - ESP32-C3-DevKitC-02 <../hw-reference/esp32c3/user-guide-devkitc-02> + ESP32-C3-DevKitC-02 + ESP32-C3-DevKitM-1 .. only:: esp32s3 diff --git a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst deleted file mode 100644 index c3388cb74b8..00000000000 --- a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitc-02.rst +++ /dev/null @@ -1,237 +0,0 @@ -=================== -ESP32-C3-DevKitC-02 -=================== - -:link_to_translation:`en: [English]` - -本指南将帮助你快速上手 ESP32-C3-DevKitC-02,并提供该款开发板的详细信息。 - -ESP32-C3-DevKitC-02 是一款入门级开发板,使用配置 4 MB SPI flash 的通用型模组 `ESP32-C3-WROOM-02 `_。该款开发板具备完整的 Wi-Fi 和低功耗蓝牙功能。 - -板上模组大部分管脚均已引出至两侧排针,开发人员可根据实际需求,轻松通过跳线连接多种外围设备,同时也可将开发板插在面包板上使用。 - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-isometric.png - :align: center - :alt: ESP32-C3-DevKitC-02 - :figclass: align-center - - ESP32-C3-DevKitC-02 - -本指南包括如下内容: - -- `入门指南`_:简要介绍了 ESP32-C3-DevKitC-02 和硬件、软件设置指南。 -- `硬件参考`_:详细介绍了 ESP32-C3-DevKitC-02 的硬件。 -- `硬件版本`_:介绍硬件历史版本和已知问题,并提供链接至历史版本开发板的入门指南(如有)。 -- `相关文档`_:列出了相关文档的链接。 - - -入门指南 -======== - -本小节将简要介绍 ESP32-C3-DevKitC-02,说明如何在 ESP32-C3-DevKitC-02 上烧录固件及相关准备工作。 - - -组件介绍 --------- - -.. _user-guide-c3-devkitc-02-v1-board-front: - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-annotated-photo.png - :align: center - :alt: ESP32-C3-DevKitC-02 - 正面 - :figclass: align-center - - ESP32-C3-DevKitC-02 - 正面 - -以下按照逆时针的顺序依次介绍开发板上的主要组件。 - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - 主要组件 - - 介绍 - * - ESP32-C3-WROOM-02 - - ESP32-C3-WROOM-02 是乐鑫推出的一款通用型 Wi-Fi 和低功耗蓝牙双模模组,功能强大。该模组采用 PCB 板载天线,配置了 4 MB SPI flash。 - * - 5 V to 3.3 V LDO(5 V 转 3.3 V LDO) - - 电源转换器,输入 5 V,输出 3.3 V。 - * - 5 V Power On LED(5 V 电源指示灯) - - 开发板连接 USB 电源后,该指示灯亮起。 - * - Pin Headers(排针) - - 所有可用 GPIO 管脚(除 Flash 的 SPI 总线)均已引出至开发板的排针。请查看 :ref:`user-guide-c3-devkitc-02-v1-header-blocks` 获取更多信息。 - * - Boot Button(Boot 键) - - 下载按键。按住 **Boot** 键的同时按一下 **Reset** 键进入“固件下载”模式,通过串口下载固件。 - * - Micro-USB Port(Micro-USB 接口) - - USB 接口。可用作开发板的供电电源或 PC 和 ESP32-C3 芯片的通信接口。 - * - Reset Button(Reset 键) - - 复位按键。 - * - USB-to-UART Bridge(USB 至 UART 桥接器) - - 单芯片 USB 至 UART 桥接器,可提供高达 3 Mbps 的传输速率。 - * - RGB LED - - 可寻址 RGB 发光二极管,由 GPIO8 驱动。 - - -开始开发应用 ------------- - -通电前,请确保 ESP32-C3-DevKitC-02 完好无损。 - - -必备硬件 -^^^^^^^^ - -- ESP32-C3-DevKitC-02 -- USB 2.0 数据线(标准 A 型转 Micro-B 型) -- 电脑(Windows、Linux 或 macOS) - -.. 注解:: - - 请确保使用适当的 USB 数据线。部分数据线仅可用于充电,无法用于数据传输和编程。 - - -软件设置 -^^^^^^^^ - -请前往 :doc:`../../get-started/index`,在 :ref:`get-started-step-by-step` 小节查看如何快速设置开发环境,将应用程序烧录至 ESP32-C3-DevKitC-02。 - - -内含组件和包装 --------------- - -零售订单 -^^^^^^^^ - -如购买样品,每个 ESP32-C3-DevKitC-02 开发板将以防静电袋或零售商选择的其他方式包装。 - -零售订单请前往 https://www.espressif.com/zh-hans/company/contact/buy-a-sample。 - - -批量订单 -^^^^^^^^ - -如批量购买,ESP32-C3-DevKitC-02 开发板将以大纸板箱包装。 - -批量订单请前往 https://www.espressif.com/zh-hans/contact-us/sales-questions。 - - -硬件参考 -======== - -功能框图 --------- - -ESP32-C3-DevKitC-02 的主要组件和连接方式如下图所示。 - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-block-diags.png - :align: center - :scale: 70% - :alt: ESP32-C3-DevKitC-02(点击放大) - :figclass: align-center - - ESP32-C3-DevKitC-02(点击放大) - - -电源选项 -^^^^^^^^ - -以下任一供电方式均可为 ESP32-C3-DevKitC-02 供电: - -- Micro-USB 接口供电(默认) -- 5V 和 GND 排针供电 -- 3V3 和 GND 排针供电 - -建议选择第一种供电方式:Micro-USB 接口供电。 - - -.. _user-guide-c3-devkitc-02-v1-header-blocks: - -排针 ----- - -下表列出了开发板两侧排针(J1 和 J3)的 **名称** 和 **功能**,排针的名称如图 :ref:`user-guide-c3-devkitc-02-v1-board-front` 所示,排针的序号与 `ESP32-C3-DevKitC-02 原理图`_ (PDF) 一致。 - - -J1 -^^^ - -==== ==== ========== ================================ -序号 名称 类型 [1]_ 功能 -==== ==== ========== ================================ -1 G G 接地 -2 3V3 P 3.3 V 电源 -3 3V3 P 3.3 V 电源 -4 RST I CHIP_PU -5 G G 接地 -6 4 I/O/T GPIO4, ADC1_CH4, FSPIHD, MTMS -7 5 I/O/T GPIO5, ADC2_CH0, FSPIWP, MTDI -8 6 I/O/T GPIO6, FSPICLK, MTCK -9 7 I/O/T GPIO7, FSPID, MTDO -10 G G 接地 -11 8 I/O/T GPIO8 [2]_, RGB LED -12 9 I/O/T GPIO9 [2]_ -13 5V P 5 V 电源 -14 5V P 5 V 电源 -15 G G 接地 -==== ==== ========== ================================ - - -J3 -^^^ - -==== ==== ========== ================================ -序号 名称 类型 [1]_ 功能 -==== ==== ========== ================================ -1 G G 接地 -2 0 I/O/T GPIO0, ADC1_CH0, XTAL_32K_P -3 1 I/O/T GPIO1, ADC1_CH1, XTAL_32K_N -4 2 I/O/T GPIO2 [2]_, ADC1_CH2, FSPIQ -5 3 I/O/T GPIO3, ADC1_CH3 -6 G G 接地 -7 10 I/O/T GPIO10, FSPICS0 -8 G G 接地 -9 RX I/O/T GPIO20, U0RXD -10 TX I/O/T GPIO21, U0TXD -11 G G 接地 -12 18 I/O/T GPIO18, USB_D- -13 19 I/O/T GPIO19, USB_D+ -14 G G 接地 -15 G G 接地 -==== ==== ========== ================================ - -.. [1] P:电源;I:输入;O:输出;T:可设置为高阻。 -.. [2] GPIO2、GPIO8、GPIO9 为 ESP32-C3 芯片的 Strapping 管脚。在芯片上电和系统复位过程中,Strapping 管脚根据管脚的二进制电压值控制芯片功能。Strapping 管脚的具体描述和应用,请参考 `ESP32-C3 技术规格书`_ 的 Strapping 管脚章节。 - -管脚布局 -^^^^^^^^ - -.. figure:: ../../../_static/esp32-c3-devkitc-02-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-C3-DevKitC-02 管脚布局(点击放大) - :figclass: align-center - - ESP32-C3-DevKitC-02 管脚布局(点击放大) - - -硬件版本 -========== - -该开发板为最新硬件,尚未有历史版本。 - - -相关文档 -======== - -* `使用 ESP32-C3 构建安全高性价比的互联设备 `_ -* `ESP32-C3 技术规格书`_ (PDF) -* `ESP32-C3-WROOM-02 规格书`_ (PDF) -* `ESP32-C3-DevKitC-02 原理图`_ (PDF) -* `ESP32-C3-DevKitC-02 PCB 布局图 `_ (PDF) -* `ESP32-C3-DevKitC-02 尺寸图 `_ (PDF) -* `ESP32-C3-DevKitC-02 尺寸图源文件 `_ (DXF) - 可使用 `Autodesk Viewer `_ 查看 - -有关本开发板的更多设计文档,请联系我们的商务部门 `sales@espressif.com `_。 - -.. _ESP32-C3 技术规格书: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_cn.pdf -.. _ESP32-C3-WROOM-02 规格书: https://www.espressif.com/sites/default/files/documentation/esp32-c3-wroom-02_datasheet_cn.pdf -.. _ESP32-C3-DevKitC-02 原理图: https://dl.espressif.com/dl/schematics/SCH_ESP32-C3-DEVKITC-02_V1_1_20210126A.pdf diff --git a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst b/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst deleted file mode 100644 index 76f4c71f152..00000000000 --- a/docs/zh_CN/hw-reference/esp32c3/user-guide-devkitm-1.rst +++ /dev/null @@ -1,240 +0,0 @@ -================== -ESP32-C3-DevKitM-1 -================== - -:link_to_translation:`en: [English]` - -本指南将帮助你快速上手 ESP32-C3-DevKitM-1,并提供该款开发板的详细信息。 - -ESP32-C3-DevKitM-1 是一款入门级开发板,使用以尺寸小而得名的 `ESP32-C3-MINI-1 `_ 模组。该款开发板具备完整的 Wi-Fi 和低功耗蓝牙功能。 - -板上模组大部分管脚均已引出至两侧排针,开发人员可根据实际需求,轻松通过跳线连接多种外围设备,同时也可将开发板插在面包板上使用。 - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-isometric.png - :align: center - :alt: ESP32-C3-DevKitM-1 - :figclass: align-center - - ESP32-C3-DevKitM-1 - -本指南包括如下内容: - -- `入门指南`_:简要介绍了 ESP32-C3-DevKitM-1 和硬件、软件设置指南。 -- `硬件参考`_:详细介绍了 ESP32-C3-DevKitM-1 的硬件。 -- `硬件版本`_:介绍硬件历史版本和已知问题,并提供链接至历史版本开发板的入门指南(如有)。 -- `相关文档`_:列出了相关文档的链接。 - - -入门指南 -======== - -本小节将简要介绍 ESP32-C3-DevKitM-1,说明如何在 ESP32-C3-DevKitM-1 上烧录固件及相关准备工作。 - - -组件介绍 --------- - -.. _user-guide-c3-devkitm-1-v1-board-front: - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-annotated-photo.png - :align: center - :alt: ESP32-C3-DevKitM-1 - 正面 - :figclass: align-center - - ESP32-C3-DevKitM-1 - 正面 - -以下按照逆时针的顺序依次介绍开发板上的主要组件。 - -.. list-table:: - :widths: 30 70 - :header-rows: 1 - - * - 主要组件 - - 介绍 - * - ESP32-C3-MINI-1 - - ESP32-C3-MINI-1 是一款通用型 Wi-Fi 和低功耗蓝牙双模模组,采用 PCB 板载天线。该款模组集成配置 4 MB 嵌入式 flash 的 `ESP32-C3FN4 `_ 芯片。由于 flash 直接封装在芯片中,ESP32-C3-MINI-1 模组具有更小的封装尺寸。 - * - 5 V to 3.3 V LDO(5 V 转 3.3 V LDO) - - 电源转换器,输入 5 V,输出 3.3 V。 - * - 5 V Power On LED(5 V 电源指示灯) - - 开发板连接 USB 电源后,该指示灯亮起。 - * - Pin Headers(排针) - - 所有可用 GPIO 管脚(除 flash 的 SPI 总线)均已引出至开发板的排针。请查看 :ref:`user-guide-c3-devkitm-1-v1-header-blocks` 获取更多信息。 - * - Boot Button(Boot 键) - - 下载按键。按住 **Boot** 键的同时按一下 **Reset** 键进入“固件下载”模式,通过串口下载固件。 - * - Micro-USB Port(Micro-USB 接口) - - USB 接口。可用作开发板的供电电源或 PC 和 ESP32-C3FN4 芯片的通信接口。 - * - Reset Button(Reset 键) - - 复位按键。 - * - USB-to-UART Bridge(USB 至 UART 桥接器) - - 单芯片 USB 至 UART 桥接器,可提供高达 3 Mbps 的传输速率。 - * - RGB LED - - 可寻址 RGB 发光二极管,由 GPIO8 驱动。 - - -开始开发应用 ------------- - -通电前,请确保 ESP32-C3-DevKitM-1 完好无损。 - - -必备硬件 -^^^^^^^^ - -- ESP32-C3-DevKitM-1 -- USB 2.0 数据线(标准 A 型转 Micro-B 型) -- 电脑(Windows、Linux 或 macOS) - -.. 注解:: - - 请确保使用适当的 USB 数据线。部分数据线仅可用于充电,无法用于数据传输和编程。 - - -软件设置 -^^^^^^^^ - -请前往 :doc:`../../get-started/index`,在 :ref:`get-started-step-by-step` 小节查看如何快速设置开发环境,将应用程序烧录至 ESP32-C3-DevKitM-1。 - - -内含组件和包装 --------------- - -零售订单 -^^^^^^^^ - -如购买样品,每个 ESP32-C3-DevKitM-1 开发板将以防静电袋或零售商选择的其他方式包装。 - -零售订单请前往 https://www.espressif.com/zh-hans/company/contact/buy-a-sample。 - - -批量订单 -^^^^^^^^ - -如批量购买,ESP32-C3-DevKitM-1 开发板将以大纸板箱包装。 - -批量订单请前往 https://www.espressif.com/zh-hans/contact-us/sales-questions。 - - -硬件参考 -======== - -功能框图 --------- - -ESP32-C3-DevKitM-1 的主要组件和连接方式如下图所示。 - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-block-diagram.png - :align: center - :scale: 70% - :alt: ESP32-C3-DevKitM-1 (点击放大) - :figclass: align-center - - ESP32-C3-DevKitM-1 (点击放大) - - -电源选项 -^^^^^^^^ - -以下任一供电方式均可为 ESP32-C3-DevKitM-1 供电: - -- Micro-USB 接口供电(默认) -- 5V 和 GND 排针供电 -- 3V3 和 GND 排针供电 - -建议选择第一种供电方式:Micro-USB 接口供电。 - - -.. _user-guide-c3-devkitm-1-v1-header-blocks: - -排针 ----- - -下表列出了开发板两侧排针(J1 和 J3)的 **名称** 和 **功能**,排针的名称如图 :ref:`user-guide-c3-devkitm-1-v1-board-front` 所示,排针的序号与 `ESP32-C3-DevKitM-1 原理图`_ (PDF) 一致。 - - -J1 -^^^ - -==== ==== ========== ================================ -序号 名称 类型 [1]_ 功能 -==== ==== ========== ================================ -1 GND G 接地 -2 3V3 P 3.3 V 电源 -3 3V3 P 3.3 V 电源 -4 IO2 I/O/T GPIO2 [2]_ , ADC1_CH2, FSPIQ -5 IO3 I/O/T GPIO3, ADC1_CH3 -6 GND G 接地 -7 RST I CHIP_PU -8 GND G 接地 -9 IO0 I/O/T GPIO0, ADC1_CH0, XTAL_32K_P -10 IO1 I/O/T GPIO1, ADC1_CH1, XTAL_32K_N -11 IO10 I/O/T GPIO10, FSPICS0 -12 GND G 接地 -13 5V P 5 V 电源 -14 5V P 5 V 电源 -15 GND G 接地 -==== ==== ========== ================================ - - -J3 -^^^ - -==== ==== ========== ================================ -序号 名称 类型 [1]_ 功能 -==== ==== ========== ================================ -1 GND G 接地 -2 TX I/O/T GPIO21, U0TXD -3 RX I/O/T GPIO20, U0RXD -4 GND G 接地 -5 IO9 I/O/T GPIO9 [2]_ -6 IO8 I/O/T GPIO8 [2]_, RGB LED -7 GND G 接地 -8 IO7 I/O/T GPIO7, FSPID, MTDO -9 IO6 I/O/T GPIO6, FSPICLK, MTCK -10 IO5 I/O/T GPIO5, ADC2_CH0, FSPIWP, MTDI -11 IO4 I/O/T GPIO4, ADC1_CH4, FSPIHD, MTMS -12 GND G 接地 -13 IO18 I/O/T GPIO18, USB_D- -14 IO19 I/O/T GPIO19, USB_D+ -15 GND G 接地 -==== ==== ========== ================================ - -.. [1] P:电源;I:输入;O:输出;T:可设置为高阻。 -.. [2] GPIO2、GPIO8、GPIO9 为 ESP32-C3FN4 芯片的 Strapping 管脚。在芯片上电和系统复位过程中,Strapping 管脚根据管脚的二进制电压值控制芯片功能。Strapping 管脚的具体描述和应用,请参考 `ESP32-C3 技术规格书`_ 的 Strapping 管脚章节。 - - -管脚布局 -^^^^^^^^ - -.. figure:: ../../../_static/esp32-c3-devkitm-1-v1-pinout.png - :align: center - :scale: 45% - :alt: ESP32-C3-DevKitM-1 管脚布局(点击放大) - - ESP32-C3-DevKitM-1 管脚布局(点击放大) - - -硬件版本 -========== - -该开发板为最新硬件,尚未有历史版本。 - - -相关文档 -======== - -* `使用 ESP32-C3 构建安全高性价比的互联设备 `_ -* `ESP32-C3 技术规格书`_ (PDF) -* `ESP32-C3-MINI-1 规格书`_ (PDF) -* `ESP32-C3-DevKitM-1 原理图`_ (PDF) -* `ESP32-C3-DevKitM-1 PCB 布局图 `_ (PDF) -* `ESP32-C3-DevKitM-1 尺寸图 `_ (PDF) -* `ESP32-C3-DevKitM-1 尺寸图源文件 `_ (DXF) - 可使用 `Autodesk Viewer `_ 查看 - -有关本开发板的更多设计文档,请联系我们的商务部门 `sales@espressif.com `_。 - -.. _ESP32-C3 技术规格书: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_cn.pdf -.. _ESP32-C3-MINI-1 规格书: https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_cn.pdf -.. _ESP32-C3-DevKitM-1 原理图: https://dl.espressif.com/dl/schematics/SCH_ESP32-C3-DEVKITM-1_V1_20200915A.pdf -.. _ESP32-C3-DevKitM-1 PCB 布局图: https://dl.espressif.com/dl/schematics/PCB_ESP32-C3-DEVKITM-1_V1_20200915AA.pdf -.. _ESP32-C3-DevKitM-1 尺寸图: https://dl.espressif.com/dl/schematics/DIMENSION_ESP32-C3-DEVKITM-1_V1_20200915AA.pdf -.. _ESP32-C3-DevKitM-1 尺寸图源文件: https://dl.espressif.com/dl/schematics/DIMENSION_ESP32-C3-DEVKITM-1_V1_20200915AA.dxf From 90149f6ffdb4830e3108fe8235fd059b9a9794f5 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Thu, 20 Jun 2024 11:20:07 +0200 Subject: [PATCH 334/548] fix(usb/host): Decode error flags in ISOC transfers --- components/usb/hcd_dwc.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 24108d33f69..3cf55bea261 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -2522,13 +2522,28 @@ static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) int desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, desc_idx, &rem_len, &desc_status); usb_dwc_hal_xfer_desc_clear(buffer->xfer_desc_list, desc_idx); - assert(rem_len == 0 || is_in); - assert(desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS || desc_status == USB_DWC_HAL_XFER_DESC_STS_NOT_EXECUTED); + switch (desc_status) { + case USB_DWC_HAL_XFER_DESC_STS_SUCCESS: + transfer->isoc_packet_desc[pkt_idx].status = USB_TRANSFER_STATUS_COMPLETED; + break; + case USB_DWC_HAL_XFER_DESC_STS_NOT_EXECUTED: + transfer->isoc_packet_desc[pkt_idx].status = USB_TRANSFER_STATUS_SKIPPED; + break; + case USB_DWC_HAL_XFER_DESC_STS_PKTERR: + transfer->isoc_packet_desc[pkt_idx].status = USB_TRANSFER_STATUS_ERROR; + break; + case USB_DWC_HAL_XFER_DESC_STS_BUFFER_ERR: + transfer->isoc_packet_desc[pkt_idx].status = USB_TRANSFER_STATUS_ERROR; + break; + default: + assert(false); + break; + } + assert(rem_len <= transfer->isoc_packet_desc[pkt_idx].num_bytes); // Check for DMA errata // Update ISO packet actual length and status transfer->isoc_packet_desc[pkt_idx].actual_num_bytes = transfer->isoc_packet_desc[pkt_idx].num_bytes - rem_len; total_actual_num_bytes += transfer->isoc_packet_desc[pkt_idx].actual_num_bytes; - transfer->isoc_packet_desc[pkt_idx].status = (desc_status == USB_DWC_HAL_XFER_DESC_STS_NOT_EXECUTED) ? USB_TRANSFER_STATUS_SKIPPED : USB_TRANSFER_STATUS_COMPLETED; // A descriptor is also allocated for unscheduled frames. We need to skip over them desc_idx += buffer->flags.isoc.interval; if (desc_idx >= XFER_LIST_LEN_INTR) { From a56a4b8980db6cc8d427c4d5d64e8343478ad814 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Fri, 21 Jun 2024 15:32:29 +0530 Subject: [PATCH 335/548] fix(soc): Disable key manager and ECDSA peripheral support for esp32p4 The support is disabled only for ECO1 and below --- components/soc/esp32p4/include/soc/Kconfig.soc_caps.in | 4 ++-- components/soc/esp32p4/include/soc/soc_caps.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index bd69a4b750f..6a3444eb7d1 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -189,11 +189,11 @@ config SOC_ECC_EXTENDED_MODES_SUPPORTED config SOC_ECDSA_SUPPORTED bool - default y + default n config SOC_KEY_MANAGER_SUPPORTED bool - default y + default n config SOC_FLASH_ENC_SUPPORTED bool diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 3072daf2ee9..928e7bde687 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -64,8 +64,8 @@ #define SOC_DIG_SIGN_SUPPORTED 1 #define SOC_ECC_SUPPORTED 1 #define SOC_ECC_EXTENDED_MODES_SUPPORTED 1 -#define SOC_ECDSA_SUPPORTED 1 -#define SOC_KEY_MANAGER_SUPPORTED 1 +#define SOC_ECDSA_SUPPORTED 0 +#define SOC_KEY_MANAGER_SUPPORTED 0 #define SOC_FLASH_ENC_SUPPORTED 1 #define SOC_SECURE_BOOT_SUPPORTED 1 #define SOC_BOD_SUPPORTED 1 From cd627d6453e69c22b348a8f827fbc94b0f2a149d Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 28 May 2024 17:52:36 +0800 Subject: [PATCH 336/548] feat(ble_mesh): add cas operation for bt_mesh_atomic_val_t --- components/bt/esp_ble_mesh/common/atomic.c | 19 ++++++++++++- .../esp_ble_mesh/common/include/mesh/atomic.h | 27 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/components/bt/esp_ble_mesh/common/atomic.c b/components/bt/esp_ble_mesh/common/atomic.c index 723ce7e3ac1..40f163ab451 100644 --- a/components/bt/esp_ble_mesh/common/atomic.c +++ b/components/bt/esp_ble_mesh/common/atomic.c @@ -13,7 +13,7 @@ /* * SPDX-FileCopyrightText: 2016 Intel Corporation * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -170,4 +170,21 @@ bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target) return ret; } +bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +{ + bt_mesh_atomic_val_t ret = 0; + + bt_mesh_atomic_lock(); + + ret = *target; + if (*target == excepted) { + *target = new_val; + bt_mesh_atomic_unlock(); + return true; + } + + bt_mesh_atomic_unlock(); + return false; +} + #endif /* #ifndef CONFIG_ATOMIC_OPERATIONS_BUILTIN */ diff --git a/components/bt/esp_ble_mesh/common/include/mesh/atomic.h b/components/bt/esp_ble_mesh/common/include/mesh/atomic.h index f72834369fc..c6ef0fc5ae0 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/atomic.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/atomic.h @@ -147,6 +147,33 @@ static inline bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value); #endif +/** + * @brief Atomic CAS operation. + * + * This compares the contents of @a *target + * with the contents of @a excepted. If equal, + * the operation is a read-modify-write operation + * that writes @a new_val into @a *target and return true. + * If they are not equal, the operation is a read + * and return false. + * + * @param target Address of atomic variable. + * @param excepted Value of excepted. + * @param new_val Write value if compare sunncess. + * + * @return + * - true: write operation succeeded. + * - false: write operation failed. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +{ + return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} +#else +extern bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val); +#endif + /** * @cond INTERNAL_HIDDEN */ From 9b6b8ac41b53544ec7c44f52e66850860293ba8b Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 28 May 2024 18:02:46 +0800 Subject: [PATCH 337/548] fix(ble_mesh): ensure the operation of adv busy is thread-safe --- components/bt/esp_ble_mesh/common/atomic.c | 5 +---- .../esp_ble_mesh/common/include/mesh/atomic.h | 10 +++++----- components/bt/esp_ble_mesh/core/adv.c | 18 +++++++++--------- components/bt/esp_ble_mesh/core/adv.h | 8 ++++++-- components/bt/esp_ble_mesh/core/friend.c | 2 +- components/bt/esp_ble_mesh/core/prov_common.c | 4 ++-- components/bt/esp_ble_mesh/core/transport.c | 14 +++++++++++--- .../bt/esp_ble_mesh/core/transport.enh.c | 6 +++--- 8 files changed, 38 insertions(+), 29 deletions(-) diff --git a/components/bt/esp_ble_mesh/common/atomic.c b/components/bt/esp_ble_mesh/common/atomic.c index 40f163ab451..9c856cc3372 100644 --- a/components/bt/esp_ble_mesh/common/atomic.c +++ b/components/bt/esp_ble_mesh/common/atomic.c @@ -170,13 +170,10 @@ bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target) return ret; } -bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) { - bt_mesh_atomic_val_t ret = 0; - bt_mesh_atomic_lock(); - ret = *target; if (*target == excepted) { *target = new_val; bt_mesh_atomic_unlock(); diff --git a/components/bt/esp_ble_mesh/common/include/mesh/atomic.h b/components/bt/esp_ble_mesh/common/include/mesh/atomic.h index c6ef0fc5ae0..b284974363a 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/atomic.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/atomic.h @@ -159,19 +159,19 @@ extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh * * @param target Address of atomic variable. * @param excepted Value of excepted. - * @param new_val Write value if compare sunncess. + * @param new_val Write if target value is equal to expected one. * * @return - * - true: write operation succeeded. - * - false: write operation failed. + * - true: Target value updated. + * - false: Target value not updated. */ #ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN -static inline bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +static inline bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) { return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } #else -extern bool bt_mesh_atomic_campare_and_set(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val); +extern bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val); #endif /** diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index dbbda0ab147..79932a05829 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -335,8 +335,7 @@ static void adv_thread(void *p) } /* busy == 0 means this was canceled */ - if (BLE_MESH_ADV(*buf)->busy) { - BLE_MESH_ADV(*buf)->busy = 0U; + if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(*buf), 1, 0)) { #if !CONFIG_BLE_MESH_RELAY_ADV_BUF if (adv_send(*buf)) { BT_WARN("Failed to send adv packet"); @@ -449,7 +448,7 @@ static void bt_mesh_unref_buf(bt_mesh_msg_t *msg) if (msg->arg) { buf = (struct net_buf *)msg->arg; - BLE_MESH_ADV(buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); if (buf->ref > 1U) { buf->ref = 1U; } @@ -490,7 +489,7 @@ void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); BLE_MESH_ADV(buf)->xmit = xmit; bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); @@ -589,7 +588,7 @@ void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); BLE_MESH_ADV(buf)->xmit = xmit; msg.arg = (void *)net_buf_ref(buf); @@ -753,7 +752,7 @@ static void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_ BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); @@ -772,7 +771,7 @@ static void ble_adv_tx_reset(struct ble_adv_tx *tx, bool unref) } bt_mesh_atomic_set(tx->flags, 0); memset(&tx->param, 0, sizeof(tx->param)); - BLE_MESH_ADV(tx->buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0); if (unref) { net_buf_unref(tx->buf); } @@ -961,7 +960,8 @@ int bt_mesh_stop_ble_advertising(uint8_t index) /* busy 1, ref 1; busy 1, ref 2; * busy 0, ref 0; busy 0, ref 1; */ - if (BLE_MESH_ADV(tx->buf)->busy == 1U && + + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)) && tx->buf->ref == 1U) { unref = false; } diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index ab37ec3cda8..33224d78b11 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -10,6 +10,7 @@ #ifndef _ADV_H_ #define _ADV_H_ +#include "mesh/atomic.h" #include "mesh/access.h" #include "mesh/adapter.h" @@ -24,6 +25,7 @@ extern "C" { #define BLE_MESH_ADV_USER_DATA_SIZE 4 #define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +#define BLE_MESH_ADV_BUSY(buf) (BLE_MESH_ADV(buf)->busy) uint16_t bt_mesh_pdu_duration(uint8_t xmit); @@ -48,8 +50,10 @@ struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; void *cb_data; - uint8_t type:3, - busy:1; + uint8_t type:3; + + bt_mesh_atomic_t busy; + uint8_t xmit; }; diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index fca3cf1358a..b1a298d5a97 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -183,7 +183,7 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) /* Cancel the sending if necessary */ if (frnd->pending_buf) { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL); - BLE_MESH_ADV(frnd->last)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(frnd->last), 0); } else { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL); } diff --git a/components/bt/esp_ble_mesh/core/prov_common.c b/components/bt/esp_ble_mesh/core/prov_common.c index 655c4712f24..bc75b447d25 100644 --- a/components/bt/esp_ble_mesh/core/prov_common.c +++ b/components/bt/esp_ble_mesh/core/prov_common.c @@ -359,7 +359,7 @@ static void free_segments(struct bt_mesh_prov_link *link) link->tx.buf[i] = NULL; bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); /* Mark as canceled */ - BLE_MESH_ADV(buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); net_buf_unref(buf); } } @@ -474,7 +474,7 @@ static void prov_retransmit(struct k_work *work) break; } - if (BLE_MESH_ADV(buf)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(buf))) { continue; } diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 64ac566aced..70589706dae 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -310,7 +310,15 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL); - BLE_MESH_ADV(tx->seg[seg_idx])->busy = 0U; + /** + * When cancelling a segment that is still in the adv sending queue, `tx->seg_pending` + * must else be decremented by one. More detailed information + * can be found in BLEMESH24-26. + */ + if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 1, 0)) { + tx->seg_pending--; + } + net_buf_unref(tx->seg[seg_idx]); tx->seg[seg_idx] = NULL; tx->nack_count--; @@ -443,7 +451,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) continue; } - if (BLE_MESH_ADV(seg)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { BT_DBG("Skipping segment that's still advertising"); continue; } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 6ef6c0a55db..a4a5130e215 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -350,7 +350,7 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) */ bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 4U, BLE_MESH_BUF_REF_SMALL); - BLE_MESH_ADV(tx->seg[seg_idx])->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 0); net_buf_unref(tx->seg[seg_idx]); tx->seg[seg_idx] = NULL; @@ -498,7 +498,7 @@ static bool send_next_segment(struct seg_tx *tx, int *result) /* The segment may have already been transmitted, for example, the * Segment Retransmission timer is expired earlier. */ - if (BLE_MESH_ADV(seg)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { return false; } @@ -768,7 +768,7 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) * A is still going to be retransmitted, but at this moment we could * find that the "busy" flag of Segment A is 1. */ - if (BLE_MESH_ADV(seg)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { return false; } From a83b39f96c65ec54e973651a04737d0ecdc77dab Mon Sep 17 00:00:00 2001 From: yinqingzhao Date: Fri, 21 Jun 2024 11:36:19 +0800 Subject: [PATCH 338/548] docs(wifi):update TWT docs --- docs/_static/itwt_10s_current.png | Bin 0 -> 107886 bytes docs/_static/itwt_30s_current.png | Bin 0 -> 69190 bytes docs/_static/itwt_setup.png | Bin 0 -> 48712 bytes docs/_static/itwt_suspend.png | Bin 0 -> 43566 bytes docs/_static/itwt_teardown.png | Bin 0 -> 38537 bytes docs/zh_CN/api-guides/low-power-mode.rst | 290 +++++++++++++++++++++++ 6 files changed, 290 insertions(+) create mode 100644 docs/_static/itwt_10s_current.png create mode 100644 docs/_static/itwt_30s_current.png create mode 100644 docs/_static/itwt_setup.png create mode 100644 docs/_static/itwt_suspend.png create mode 100644 docs/_static/itwt_teardown.png diff --git a/docs/_static/itwt_10s_current.png b/docs/_static/itwt_10s_current.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd315c042e4113523752e3dc1e955d64283c81f GIT binary patch literal 107886 zcmY(qbzD@>`vm-H5b+h_q4)yCAT@(w!?QjewL$i3ls5ON!FX!V;28 zH*)v${oVV=-SgTx=ggcrGf&Jj&ph)!aYhE($6sAm9-I5E=;pTw}9B{{jF$VgSI79RMJo1pqLD z^L`qGumukso@#3V?*BVJwUwt~bBMt@FT4Q&ir)YJI2l3|tk_J#_qxwC3Ac!t2oz+& zk{oZaSyYbp2EPB-9o*m8`~Q9}krd*!*wz5L8meZ{`Mo>m?>rX1Y_Y-i<1M-8*T)pk z3DTpQ$UlWW`1xl^rD5=qKuYoSfKjn5O=-5wQ|{4;fZ|N45}Buyt$fERYXhb z`(YkZZ*llzj-NM;oL!V%FjHf+%@LQ&Yk&2oRuROjm)D^%%ZyDqiv&>2x7e_$@?u)}(cJ2%>zEsc`)Je1?3+ z12+APmFBVeVO>vwluP4q0T6ixN;ds|&hpZCz0`gnq^BY(8WOFWKr8#ZJLSR4-<@Hu zMHWKjPhMN)D^QRFv&_q;w*N~TU&aDH3|Dg$+U~b-M6crJCX$hnS^X9>v^21@`$Q-; zl4d+atY77gEDFP$82T=s|9@%3L-gT}N<<_*n$jv_;`_Y4Xn&eg^>@4U?<`@Nv&^N4 zO}c^-DMKyYDr%RwheFq4^S$HUX|9b7-w&OvVoa+Z+F50rmu0w?Qkx%sE(W-0W_bU8 zZcnfEx5rq%{a3>kA6r|Z`oa)EkyBwRSYx2xv8Pwkp{2Vk7CPrc>pSm|zW2*3 zyrFaNXPo^IvDCYY?CI5B{*8dLjOAe0^aM> zh##C2JGb?Fy>&aqx)-0`jeM665mpfY`qO1xk%-m(B2j<$(BzNR;Wl&y;~!^?Hc18xwC}VybzGXf-_b zv891njPW;YjfbUqzpKpo{?|qrmYMk!Wj?ZvEMZuoesFon5cuIQik$T@`dPq(oA;9c z<8#l@L^7PCezu5GUnt1RbyZGJ?!Tw2eX%OF{hwN5*(sD{XEmzYxH4$8sLr~gD!oL~UUIW(#5Gp+N;lbeMFb@pd18g+b0O?+c4%J@Mjvn#lJSlfyqsR+m&|FckRao!i%|vuBxKe;@DmPWQr{ zkk7N)M-6@-C;Xq@W}CBgeb0#?0<@yK@FM)sbGg+w+iX`O8Ye!@e!U)tC2o%4=&&i+3V&BcMYjHU$Zs7pe7LceJpa zb9ANYjgdQlMeS1O#j;$?&|P>@$Xg&^A&gkN*zd?T_~b@sUoo*q0l7-9Ax>Sh+GFTp z?{yIj`YsyPz@FbzU9|;iK_O2>J3<%vLL!y#otR?`l%gZjIEif7Yg+I4WCIoOUaZ!i z{6#}ARe&UXsO7#32rqlLY592sUd-{aPwUmei*#O`v>P}&&as6<2v?%%7pfaK2Fa#C zK~1x>{qnLu*V)JeeE5@Ka>s{gnTaiUM?gOYA0Q38j9}+z#u)FhU#O$Po?_bK8oaAe zP?__Gfk4WGc%0VI7RD7Mj5`d;Hcy~y{-NzcVENx6jbPF>MqnGqHiW^c*4w-AD29~~2Q6yEEe zYGCKw&F=eC3Fxk*Q@UGi0(;cNPQZcveHY8!a|s{ot&Z#ypQ0xaWN(~lVtXIeLGOT> z-cxVj)>QEJL!Ql*JIB12A0W2_B6ObtG?tx|qNNZ!Z8GnsO`|s3(|CgeH7+VG&~j%K zyvD(Go2}+mTXd_~1KXnq?f2)*i`I|Pou3Ii&R&Lu24+i?`C-(==wh;3qIRFYP9#{m zJVjsBt~@;T9^bF}I`JODHKjkQJa%EjNI+4%n~Q8A9KwQMnh|8}yOv4Tue0KQ6K zy5T|?D<;pjw`WW-$&Q1}bz8XoqRR&e@}WVn&U{cMLQ-N>MDkVb9F&vy!RVJE*N@Fg z2*FN*@t3_!O4kR44mNtLmo*&IZZ^GYszAk`jEu`y6e5qMz-yO%nZi})m75^*ymqZGf(U^coZpF;xLP&lRxq<)S!Gp(I0(@fCzaGXsp!m=9z5jnx z-^3ogP&3ihFtANcgI@t%%m zoxC442KJs{G~g5Ni_A{{ZYbE6%vl)`t*0K&qx*rLz@!AH(xxv1zS2|fJ^TSj>Wjbi zPcTJxG<#tAZ8O9hrxi*1@e^wLiW0(ywC7^$K3=1lwwTb_Q;Ic3va5}ZsjpcR5kwFX z(tZ8vWIQBV{8>Xxkr{bCL=t}mH2;F@JEFgO7=Z+@^+JGwfBE0=6@MVv)%iGV`NCTL z{TtC+7{#_ewUE#-k+vf^Fo-C!AGJ0#upU29%Gh;dn#Jtx2vJNhQA&WlQsMbq&znVt z*A?xjIF4K9bNGof1x|zUP;uWAtL~|6WcMBxz|g-ZaY=e;^^0Hoo9<;-qMN-ON8O zQbtuXT?rzwDAaMYu_*nYP}1Uot_`meVUtu`@#Nen<}!-%afF`b%J)oMW3V^SZpw z|4nV!8IB@h+N0|`1z(oA<7pr}KQ3VF7=3zT+j&GxjA^g!#MIc!kple>IX_}gF1eY0)%rj0o6eaT8Q_eP|Us`H8Ux9M|#8>g{oCcH09V> zmrOgWKGQ(osh zBajFCtJ-`12z+)Mc(|_^#f?l3Gu-RmM;MCLyDLZPJs9@KiGj0e+T^LMp7S+NGxhu- zWY_roH@fymat3V9Bu4&>;ybOF-jDsJY2$CD)LGT}3C7HlCmRp_D9tUs&I zH~u5<@;{CJ&q^2F-+bRx0DPPllTL}WuI<^S{A6RCWnj>a+&KIbQ^+BTST&As z_6ekJj3%>r?+EjiQ4?WK6}Erpin9@otD+^+Mq&FF_dx5x)|hSgQj}(F5&l{*fs9B{ zd|=g8Qtf(xI`Q6IcDPw}k<~A5(^QUWiRNHuVjq9gR+C!Pa<>Fs0dn?I_z@CR@l;}{ zj|Nu6ksgiTGy~V-rOdui5wxJvy=6A+T7bf3Ri{g+6mpJkXl|(^F?R$9`;w^kp6t#hWg9PirF%v)r!k3NX@P*qR-me<*-Lg^A~oJpJa|69iV zZ!zPp+Lueb->$HGaYLP?bu-?S(lg?+Axjabfm_V)yA<<^2p^XyrYG}cFJ{_^KhjRj z#kKJ6w_rS1>fn0+J*E7SkD5gGB18F`@ACx7=ns0O6#)Y73NP_-aT1e~&L(4CWfc_s zNOBep(%08lp~Bzs$9C?rfJ`}Iy?jP zN`%p*ap534KiH7#Ug_%{&rqNuY1oH`4Evv|yK_*@dOd!2LM*(`mhofp zbKm9VrIu1@b~#J==R3;d(*mm#&Q~EfNd}Jk1_m^*3az@*;;ZahL>-_7EBxloclP?D z2PzUQ;hi$%Ll7WrRo3@lK541t4Ky8Rb$8E>)fVe2ZxZOu|Z_4?o4x3|Rvu;EP_q{Ed#tj=VQanJV2SM&my}GZ3-RvhY=Olhxv1XXdJ>FH zE6FA=e6xoT_ERO`|IoMU+DGO%gl8T$lu1tb55m|g>JklVmE`4fq%E7=I@p8Qjf~!_f_r|%L>e%0| z@%chu@)JV{5Do^#eem0TkcrleEP>#+IY`=GhG*p!^g$iSijy=A;M!-Lgdar{HH2H= z83f*P_Li)UUT#3~xy2*#*s@*>2V}c@G~Kjg5M}T*V(809QpkkZM>L0ssGA>KC~_?- z@|$N@?K62O-xkb8mo!?6Ii|d?0*FxqWrxo20`fxbq~abnG{i>3Sg$^MJ5NT>-Ul$G4T{HJ#Ld@J&Ymh`O*9o;^GQEp4nk5+JSn>pa%l~M z+Gy~ICueW#M#4NyA@ihknt#@VDLibcj$E7^;kbajzp8Ft4<^zCps#MD+wf9k`@?NI z%RVN&9V`zg{R0ICH#K*~FlyiDkm_feO_W&1*WCE)8K=KV)-$m4^=08K zWCe+G0iW9Yz9F$MgrxKgA<8y(unQl!_Uf99p=d?mKuJZQbK1K3Iu0HbGLzN z^^w2wJm#g@5>)7*&8`3O#DR->X@K@_llbjuWj+Ecq$rtbtN-*5zTN+Y8t$=`*|2xTt7Fbz2Iz*I%Fs7`gt;W}bbuVABe6L8sF$#+IiZzI_=edl^pM%cUBM&V~GR zWT*$*EwtC#f?fu(0~73p|1OO8vl`gV94OApDMW>8NB%u`gatfEtK5goi(>7?g=ftj zQ0DgE$)?;Jb6 z@n!VgpO1s~cC310N3qMSvm0FSe@m97HgBW}Ow_N#=&5j(SX+{cb1($=yY97v>b`NQ%q^RjFHL zuST|x`WX#Z=P8vnR{tGVF7X}RrcrXriAOByijF5y6$I_jg|FgM?CU!mErSG;{w<`V zWh2!%=|~8`H2}7MBkq^oPqo2!ZH7jzV^bRmsM(3a9>#)Mc*~5Zn$BJi=@=-{$%`b= zx!W?&R%J@9X8-NZ5tJjIYiLUT(K%ZWJa~T?T)Ws?J#~A>0D8j?rK|1uC%BmXvbn{) zr_$NBtLUNbo93B|9U$PX)1AEIEJ&Mb)L0CT*T+xs# zA?TV45qn`9MK+pB@1S4E_8LSpF1X1s@!>Joya1mD7xnsyzX}+A$SsOW5><}dXmGAK ze}@ede`LQg0L9h9{<%7N*!FqV;C@t&cD4;*4jZCjm?mL8-@C}~#S($JB3H7=+W(kDm2AOGKT(Et%ezKqA=Ai)S>bK43H|O^9!Xo`xOD;T!tEKCL+r$6YM<2R#Rj|wBdF2 zkL66zCU}R+!?raN_6%1Rr+zyEdL4((%F62N$|gECp@J(1v!H1wWWUKIyIXA89gWux zo3?0gEOLU5)))`xkmsoDtEc==oI+_o%=OmH z_OW*HAOP<6i0}qBnlRz^s(Ykp0($qfFiIha(Ys0x00b4$vH2ep?*R>0!w4xkLoQgn zQdtAp0!V5*PB}b+0tlk4?oTRxR~Ys8I!_8i@c8@?;Qevn7rm3Rv1La%dJ?at-tpd^ zC*5bHnoi97FI|CBJ*%JR=-GE=aYs{Qy491b4`W-@2K)Wawt;xsNM7rf07f4I6aghg z9+U=2vDaCnPU-Nq{ek@^9h=;T-q{fxeZ)y~L+Zkh^OtQuzCf%*J{A!v*@T*x{2H#y&$qe{{sk58m(-zQ1aEnh49ivv?LHT9dx;ILt)A(Fvjjo#UhK1L?a#O#;6c z4PQ$z;O<{NT3rO~S_UM9-JY7`f>HWbyq9 zdw0ixVMvU&Vn_1(A7tX7u#fGRynE!&v15dprpQ>c0L}R`V%FP5IW>joOSa}f7u{{+ z^Srk9#I_bBWPgY2T=9~lznM%40mh4KqqKj*gN-eDXBje*d!kZ7!*89bjh33BCO365 zS$&wGyJz}&P>LI0j0*QR+P*%y%SaZbfSXs=uSUZCVjyA+T}ufossU>+@(iLoZC_vl zxOKi{Y+a3pgo{IWUaac{9|B{3PvYz)3C8X(#Vt5@L{;_iw_kRPPnM9x`;D!R8j?ac zghU-IE?-%XUO4krOcfo|E!y;UiwHk{{pk?2*d@z0D-)I@OJHkH5pq3UE_*gNQx~F5 z^3+dsb$tIN6onAA1F`f^^}RI&j@(9X<@#MXs^TOhFo$lfQj~+83~_xh21L6SM@fD) z=pzdoCO|_N@{4qGr44SF&foie*#Bi>hQna1$Ts97Ob-htH_rj z$J(9A+DF-hzUVh^*!YqUy7wpcNDbSHbB0V$HBmKNDUYK#h=6KGFGjSWy==1a zQ%_eqW1h0LUT3Egxg=o3)K`He}MRfT+C z&1(K(4dki3n-WDhheN=OO>E!mbw$Xe#8dto`a>Y$@39xXL)UA9m`uNYh!=w11hR+0+52g=omX4FN2-@6 zs~XgP8e*Atm$T-tbGb9pSJgRdC7FP}{8 zPu&sXPX6tU!5OKb_8GgUShz_5eO`Ci7IaU^i!5oXWnjd%=j_UVBrlk`rEJZTQmgL$ zU5q7DAe~`SOsB0?eJP;g-^){Nl@0#aeys z@5C(oY1c!Ywb?(4&E5yk*1wpfRgpiL@;Zw_8d=(et;~Sr+O~dEPiA5`nqah^wl9$D zm5g)NiuVQ0B3J>(Y=P+{t@&ZVecpRq1s!!Fin3qiX!st02bqDOvq7H0j83a&s| zFQ%FRVgll<*&r&*_DIj*=Gbyuf3}viV3?Pv=T(;<^GVR%uoq#1|nJQAOBGt&{0E>W33n)wS@IYJCw_d zXFCFM{c2xn+r3ftj7ZFi?H8r0#8=hh(D{B22ZIu|)nUFQt zNU3JeeBzIz4c}9h{z!=Qrt0M|C=4bV-s(uoP#ZnX+cBSsezp`0HP(J)i#rB6)JE33 zgJN@Kw(8Mcrm-9`Ue8>Wm^W)sqi_+_ku#g->{hqK4>!cKg=0EvqA0w9ni?E0@0BLU zF*dWz1I|5nR76vI)bP{S;C})j#f`4Okblo6*CQn@Gv_gN*P~;M zbwwR7O2)XYUqpqRim`p+|7hY#>jPQ>3v)DIsV4UpEZy4Q9@Mp|@PmBk{JF1Rndx9L2V zhE=uh<%Yhs9vS-VGX!6D5jY8*Z5B%N06Z=gJLh-gzh(QF^#b~Pf}JcTD%Pj#vMxBp z`xhJxGs?{bP>VMh)VW*H)%`d8N=|Mj63&hvktU_FrDrtVY!ntE)*3GoxwdOi=f^** z|9yPToaDv8-f=;3P&)j9p7|S(YAPLmgsPLpN8=j0`g8$qX#^u2xDxTQFgV`&InG#@ zd9Gl5cvKZTy2o&fV{laY;|}?u8UUskqhA!-*GGTpAOJd@d@7qof(p|vM5a+5gb&OO zHx#_;RKNr!HmVVP`?}avNtzPND)jW}!0QHney+t*;m@h_=P6*Iv>9gGX|6fvfE7`v&uUB6k9;p2P~FD(w!E^1B}B1)wQ_GL?DsCyTTW(agxrWB}QpaPSo1M6)Z#@ zIr$vlU_`zyUeft_*dWiYq)bc|jI8poT&)wPWNyR(XlABlcSK8W)qeWymEkmSCgJg_ zEpdY;X8VLd@ErY_=z9gpUbm+M1{ldqZMxzycsKDcRGBVYss z_+qSE;In?3=?30B*uSTj$F!2oJ~HkLu>v6aRHJ{FjM=FTa3T4?JF`lQ z2pIKM4({qd$5G#Z4FS8jO08g8pGxNPZ#?R5ll9 zotcuhs2@h=AMCF5GCjv_>Er%V0Uem`YpFFS$^b*a? zlw=L0Yx!5{%y_s==v;5}6_3?luj{nSbaqt~HD0aB-x_MflXyGNBG@Nv?yVxVR*xOk zLg=A6N^p>pcgWaG>w$OD=-SalAY^}$?*eVoKXu}qViBH|NYvcYoESa&B;$)F?E245 zGon?l+(|cF^am*%nA?}(y=CkM2REqpxex^j2X8M@08 z#3`mMFZ5?QQ`mwy%2BF<9nVufLIPsgTi}XOTkMKtg)U=_->(fz()+V-0?ppensxR5 zL(ArTMVCDF`wf5x*gt%Mp}6gZw?`A(l4m=NniqJL#J5-|b@k;w%>nVMnrk#$i-2y| zSfOarF-Kot+yX0#IT$nIJxja-QSHKVP~mum-N87r8FurJ?YTMPC(1YQ@N(F;>!Ynd z1DcbXV61{4gHeNj{*cIWZ?>V*(qf4o4No?n=#-ext>oqWOnZFH`7?*D zRnsi`8Sqg*4F?fQ-})qB)U7PsO#nVMCEZKPEG$~Xnf|4RJL7OQiuaO6dM{5dPTSyN zp903VcTo?I&mg}Saj~rR!%V%lN#nuEYes@8FXlW^fXrCWzITbuV^n{s_Xj$P-Iagp zuz^7Ej<;=p{hb1;;2dpuzuTcL52LXSSSJ!$4kqmrDR}T#v+7zh8Es_U9+nWrpGwFU ziQJ9mZ{Zx0UjHJoXd@&0Cn8k4TMyBsjq?-z^GbxaGQF!WfnYDhNhZ}s8JZlkvZaPF zicpr1Glc_@OD7n|;I>)mu>vW6y$147EeQFR=q4Dt2T-%IJxOjs5*PrHBO17>V%zf*r4r3?crrK9pV(qLX%6K0+!cT5EX8b>!;QqVp`1jy|B=Bfxf^fA1 z#yY2W&;HVt`Wxiq=jJDHpm8Tn&bNoVnGkHrMV%KM-wR^%3BAF%YzJ6e;m9Q@NS(;*F`Y$YFh4 zfkC;jokYlFb=K1&KOp>T{KFjU`^X&4jDPfQkMFy)_LYy7EC>* zLf)1GSs?@}hAdKfLvzoq2dky8yf5~NDe9eQgcyTEl`oey^PuONdvhthYGpUt(?3@Q zhmSLPe`MM8XN=s*byp_f!nf}TIhSCJ_vcFs(BpMB2(Tj_FvSL zLars@cCfcJrbW7mgQS=1i}WMTdve5eqh$cMC@GQPoUm@;fPMiljrSq~->dX%hbuP!f{55kg z$bRvWKQT?fb13Z=sf#Ob*5Q&fufMADeP(UtC>H2GkT++ zQ4I;eT$clo+$?Y|Nk58^V_&9Pw#Ar08_M>pm48A?j}y__HVW~F<=&P8JA75auRL9| z1>+MJEJVZ61ifpHmWbd7AvZ*59@0kJ5Vkeij&nj0#cz%?q|k6S6yS1vxD;)^up zyBA=A{XVqqEm=R3Cy_l%&DydXDZ|sbg@aYo3o!q}p=GJa*v-}R8V2zGkdHnvfDHYI zAD2=&xlNLj4l8PJ>4+FMr6lae>!S7Fb5J#bHAel*I(Wm2dP2KUO^_i1^M`n^@R;-E zxx-j5)7pWySX&^=zq6Ok4Zb)&t|vM5$_U*av$^#z{1OaXH9f33-95ArD7riay8~ub zm;6>ZS@~Y{9*41t_Hxge!f|h6m;d$Gg{zdkn<6=g`C#>$o)R1_nx`VQjZB*`){hYy zfTSHhF6`^LT7C_>%^tJ6cn=i1@?S%$RCi`7>Xk$*%+vx%KHN2|AOoqu*OG-j1rX-c zztK9On$WD`L!_5n40ky@P7@4* z))l0&r0<#UFr{PO?t3`^pvoM-+<%JU{)uKPP=c^*#}mfIk{-3`@+|H)zdx7o5N0Gp z5&|HsIE}c(o%FG*y+^V&E7pCBjY33him@)85mAU?D!+ZChG6`#UrPv`xnV^<|8iS+ zhPF*F8a_>p1&aI|_t{elpec=#yEL6RYQFW6k4qyAQ{E4l54n(|S~E5zd2&GVnr zLxJMb3Q16@@z5#wPB*!=)jH(uy}InfYWvn;Ld;j6kiPMU z7Hlc&JdaGpFPn)q7~N*uxRV3@JiAV2IYBV_=PHBM920)Kc|Yv#<@<8yIYE2XO77pD$|DM>+PEXctX~^AC-+#)Y`nD z+g&iVkq}hoQF%Faf`+)XVzSi|JWd7g!eeB0{fG~xCq#8J+}y~4o^00z&Td5+R!SSv zE)3IAwPLq1Rbj%>gOzkVypieU;X;1XAMy%Rxe7W*G=Sbs9;M)n+ ztaZk^)Q0lQayJx|F*VIpN5heSOy6PZRgYOWylUovBRx+|kUB~>yL)F|en;UEc7k)weT3>mKRSj14YkkkTmJ}$EMNFb{J|H zx!AQ&-mi@@fI+t@_+|aHI+rIpi!YF~y}~5!RnW_g8F7IzbWjM*stJR;2@%q;0KlH# zKfg%GZ`Nd^a>`oF7du#~+l$uKfA)w&$DXGbcgHd2Xb0VLG)Tzq_$Gja{$9BKaJ;Aa zYA{CU*9eE-#v{Ea>yxAY{aqX6_HJ%8M^F+|T8Pu7Z2t!wWq%q`Wl)$Trd*uf8%-E; zntNHp<2aL2UMJcb9raZa9#Um3XQKgwkyL5`|7Ghgiu|neei9#*$Xa-F+rYmpo1o)H z<6bK4)-AH9cnL7!q)3n%d{Q+X79m5`Gct*v%Bf7_$k|*@sbqVf zlN6wo^f$Q#y4r`VKiy{LaW1PbXbU$fJgE5VhQd$e2TZlNSo;tjl3I0T_iH+H01W?{2iL4T9h$~2jSprATBpYcP8+rGXuJ9xG z6#478vd``W@{u zc2L^CB~-fjYXkENB7nEwmO%M!x^A4qb^5rP8{RG{WauKI9d-4Skm8%!8hbVbrfHCo zSO1iP@AmvSdoNHY<<5tH0x_uEm71=NxV3CX_P(hE8JYNycXy=`HV(7cG3Mq=PAO&ks*6P@`&7JrBoqaDi)R7easWJ0JBL*`|7H3X16KnPEA{r5s0Q~ zhWgnv&ZckSy^}on1{#)MR|AZ@xC`$j*a}jQy0Qrp`HHb?6fLuhdckN-L#nh1(^zC$ zR)M}+1tAsv(*Yrz&s<9QX#$@y)?F9NZISVx?YuCqAgP7UrRT@;@pYc}VIl7^=fE!+ zT+`+=#=;Es?cd^Ih)7rszyS3@$V{ApRo!=$VKY+#i(PP8XMpVYKTLOPTcNMNF`e1b zR*6SQe=U7V6d7UJ;!Xe2^Ks`sWl5@G#7QI-@y~kjK5osTP3MpsLsz{xc!M5xI><}s zzC=I$^NuKX1R*ZRtj$}fU23IK!=;{1(j0Wd#$y41J&y3+5^;d|6Y%P47=2xvF#P3+ zNT76oU-BBw%`qj<6$iOQ$m>m!jBf++Q+n3&7c4~wi3qK;T3{4@=2b*7iUV86D15fk z5f+I)H>7w#V|jcMJk*Rewyb~k`4|4o;Q=R7DgwKI=Z~G-foj1xG9m?i`58bua41)a z)nm@K0!?-EfKB_)nl}k&m-$^i* zWU$9cq+6ogGck;NJE~aHzQ$%{=@n-V7n=xi+kTC(*vaaUjFD&sKP9kkJrrPI_-K@_ z5g7#Zu)U&d`Y8G1t>t%i9AjCTvNDAni_eZ2{Xc)*`qcT z_JoiKG&Cpmjo=tge@4@T6&Wau$ONKHa>X@N3W}fFM04`aC2czqA*`u499Xhph%3tk zGi}a7)ppCqM7}|76*?lFWWJ*Ggo??kfz5c7KZgZBcMg!yR`ip#$lCILuB8xOeJo`{ zlL-2HDI=*R^KRf-^^?&z4WkYlP#Tl^P`9@5x9wyFrdVxC(MiIa0u7bodaSgD=|AhV z{2diIBf2_$%fiF@Cndb+e}Zf3dEXVw+9Gzw?Wn-I2&KcRBJw&Wpt`{kGJJoKGuoV z2)AtaA)fINeTN|0BOH6ojw6tX#ZFOEwipSge;9K%MuS|;^iZ!v=uQYi8I6X7*X9># zV5?%i*DOl^{+g}_-d0d-D}0%Phw6asVO+@pm9cuIp>K7=wFOqs^9cqHI2QGo8Gq&X zM=0Nn`}uh;2ux zyWdPsxr;18k`=+O`}Plr+r~e`7L4~5S61we@xZ3BAcK*|VFmp(#M700Sp{%50{Rsk zK>jpA2pm%a79z;IS?7`{wOUy=uDJ``|4;S!`yFl88wlt~<;-4FXY7$|T1XrcgjZCr zbn!9P+6UVcwAV95TCq4QU(vnDPxHCEC5rt_gq;zJ3&x}`DoW+?CsTgWa|(qD%NUKk zuKWHy(mF|fmK%NDm(bi~t|DU*^v2Qhj!388Ov^<$uI{B)yS0``8XlDG>g@w*-3N5c zjb7Bd2of&G;Pr_Y{2;iVQpDNfIlSY{v7`8|S&ctaP3P?=BSG$uqhVXJ>)+-!^Ne{W z1qnVk5J-J4qj#T@kk}@3djhj0n8kK%fw9X;;&+~DDX!jgW|PKPH3W%@YKgh#lZNQh zzyvC8;^uW+5!+ij_p71I-1NKo`$~446eqU9I38@AJR^X7PR)DebM4p>V*O8vR!NamXD9sWg8Unj6+*aQqJSuJd*SuI+ayEC z-8n8c0CtEUUQvcwUE9blOZc)h592m?`udVvTmu9oDHV)I2=f@Ilzza&B-jc6?O&>5 z1iOpFjb>xiL@1*ejf9+@97nuj$DsxV^U&Ixk?@*T`8$#NfK3RZ1gYTgB4f*51gV8_ z>%FmxrpG7C5zbuh`$O*keg4;aa!z?I82bbp-@b$?ef|2CEJsiK5ClIuf_$y1DYj`U z|KRvwzGZ0@%oNVSk^kf3(qG1JvE&cG(+jO9PyhW%Q3aJ9cpDcSj~D}_$U;7_d0KH zK`i9%9@b~3y9Y}xklpF(WXIoj7_cl^)53nNY~%R-9X=8=TklACu-x`Es30dROXW$f zCgQ8@`(jQlx#Wlyj5Y^V=kc)@=AkcBxkWV)Y47DlTWVLn>8);PTEh68qRz{NIS zF|{WLnXjI9ks<-S+Be=$v~OBSa*{yQV;XWJvLRS>jzc}u=GGQre;EEwgO2} z()VD&SzUHuN5#^|GOk7a+dDg7cz3;(8xIx{w0@Z7C8)Nya@R$ppPJ=!WBREJ`xiv2 zRQf@UA2q73;Zq#@6C;;AIU~p76XhI4z3&27=iLi;K7s?cCkFWPQ^S}GK0n!iVvrQ9 zeog>W=!FDZD#;3_c{+o~32LZo~~o)`=ypbsdMuEF|4M`CMimw<(=nW@QK7 z4Vf;D(3VKgljQCw3fP_HJ#h>%DR{G)p2MfpeD1ztIFvS7rWNE%+w*4Hw848wufVNv zUewxeXC?8j+UBNlmu}Ez+T}K>mXcD;u<~6J^h-{_)x2A+b;}^F`LR@kR@x?8l~;(2 zuL&BluuIDwn9`|V!1ZqTvwLOmx`3qkltCI1K;$E1a7eF-*GqDOm&+J#BDI*74HED@ z_i|V$yG<=)V@|y~eprWXoU~hI=$8M$HwVkccMrmG=TOF6swir*e&Z@g#f(Csr4b|Z zi%jzU(Gy?}rc)-M@L5_F&)~ZoW9i5q&cjxKt{3&(_g94hKTOik&n@JbAX8j)@rxH} zF4`snH2QtRpQ6hSceU;g^rZxpIklqjxcP5C{T=EO>#`H#8vqMy{!jNWe}NUd$o(0 zwD$(tgS7LYM&_PsqNs2%!kVFPd-_QCxY9qD<)(xEs_@mar?S42^3 zu^K<-P2qU1O42=3iG?6GneZ-tF6z{?bkGH9c&Jv%g>*oJAw`i9Zc=opRdvnP$^Mgl zB%9Aoz|S+x_mIsKe`>M^#+=Z=H0Jw+Vx9NLZFA+21H7C-GdNNm_IT-b$HQ|bpU3*_ zmW8aJIxd~)nx{p{!_BQQ@H=qi>mMxFGvd`?k2Tjq#&aUFmF|MsZ~p-%@f!0l?$*Vp z;&#n*Q@zRYaSsCq*Ct)|jpedljRB4o-FQqS7fr3|wdrv>F_ey5zhcM~#3_9u5LasM zZBItIGujwQrtquA)F0Z0&Fn@X(W+uDw?r;CN(#FkO)rezVfPYh(BJ)1{R?_#XPLsg z7Bl;dFdhv*nHO#o-v5wUeRd3U#8XQv<<1CXV*;Z z?1adqrJ3I~b)WK2`h!^9#~GeK&-JL`3m`~#lE7(F(5zs8*X+Sy`n-Apv9s{W)aLEG zk9tWF=wcV!in;ar%9Vk#bh+f60_Lta z(gl3gjQW6VLz$bsJU*(VP=mpU?CKTYJ6oa^S? zOe(sGWlii?W$eDOuWqo_y{K5g4qkU}_`Iv~RHR%XR%})sPtfVYWi)a4xBrNXaWCH# zNX>KSyf9qoo17M(lqJWP$T|BuF|XZ@S+ohAy4W?pX}YKy+lm_A@Q5?z&fU4Ip00gU zTRN~;_}@n%yix=c=fV3va6#PvhpqR3YHDk@h67Tht5oSK3J3~Fl@3Z(g9ru;NEhk7 z_o5(OY0^62na}t^w7h<@VxK6cl_hqLlFlAR`%X&uQlg0=X@09 zo5OlO9v^ZlE>OJgpimmtVF3%9e0JRLOcmVGsDW24(@!k(ozXzs3u>oGiKjr^dM~vd zi)CHit9M|-Z5VVpE*6rNa9`Yyve~YYK$^SF7iShCHy}UiC#R*ue0Ym>*!IrQhI{Kp zOz+@SLB+5}kE5#KcX%!VxwYM)G*c)U`^1C>qrBO3TaXx9lVX zN@o9wD*h$%T(JMrarVjeJb#%+S-Y?`u-$2m;Mh*NK9u*;S7SXy}o*X!mb@iU8 zmOAdC2l4xcKy8ke)z$CG3Sg>Yv-JlF{k0lfy3uY1P>Ea zO_QFMRzj+O7v8<9(O5(4xsNR8!(45_yLVY@a2|2P-DG**A?aR4o?zGMX6QP)X5-2WQ4-TruanS%obRjZ zUmVLEqIDjl31#{j9VaJpX3hAj4f^!3P%BJnw z*W86HUfkMl{+`4WrqRWVDd&r!Ior44y>sMzc`Qy!T(l`wrghKfD#j+_cg|4nQq#-N z_2_{

;$Px2bQ>y^}V85o@!+7l@}q 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 F{|{B5pgjNp diff --git a/docs/_static/esp32-c3-devkitc-02-v1-isometric.png b/docs/_static/esp32-c3-devkitc-02-v1-isometric.png deleted file mode 100644 index 24636265821fc4352e61806e66bd47399cc4b047..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244132 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