[Telink] Add Telink factory data & Update every image to 0.6.06 (#23502)

* [Telink] Add Factory Data functionality

* [Telink] Add CHIP license attribution

* [Telink]: Update every image to 0.6.06
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 6847480..b5da6c1 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -17,7 +17,7 @@
     "build": {
         "dockerfile": "Dockerfile",
         "args": {
-            "BUILD_VERSION": "0.6.03"
+            "BUILD_VERSION": "0.6.06"
         }
     },
     "remoteUser": "vscode",
diff --git a/.github/workflows/bloat_check.yaml b/.github/workflows/bloat_check.yaml
index 4849a8d..78f5612 100644
--- a/.github/workflows/bloat_check.yaml
+++ b/.github/workflows/bloat_check.yaml
@@ -30,7 +30,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
 
         steps:
             - uses: Wandalen/wretry.action@v1.0.15
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 750506b..19f1b96 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -32,7 +32,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
@@ -133,7 +133,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
@@ -287,7 +287,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
             options: --sysctl "net.ipv6.conf.all.disable_ipv6=0
diff --git a/.github/workflows/chef.yaml b/.github/workflows/chef.yaml
index 9484e01..a473a39 100644
--- a/.github/workflows/chef.yaml
+++ b/.github/workflows/chef.yaml
@@ -29,7 +29,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             options: --user root
 
         steps:
@@ -57,7 +57,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-esp32:0.6.05
+            image: connectedhomeip/chip-build-esp32:0.6.06
             options: --user root
 
         steps:
@@ -85,7 +85,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-nrf-platform:0.6.05
+            image: connectedhomeip/chip-build-nrf-platform:0.6.06
             options: --user root
 
         steps:
diff --git a/.github/workflows/cirque.yaml b/.github/workflows/cirque.yaml
index 78d5012..c91c437 100644
--- a/.github/workflows/cirque.yaml
+++ b/.github/workflows/cirque.yaml
@@ -29,7 +29,7 @@
         timeout-minutes: 90
 
         env:
-            DOCKER_RUN_VERSION: 0.6.05
+            DOCKER_RUN_VERSION: 0.6.06
             GITHUB_CACHE_PATH: /tmp/cirque-cache/
 
         runs-on: ubuntu-latest
@@ -38,7 +38,7 @@
         # need to run with privilege, which isn't supported by job.XXX.contaner
         #  https://github.com/actions/container-action/issues/2
         #         container:
-        #             image: connectedhomeip/chip-build-cirque:0.6.05
+        #             image: connectedhomeip/chip-build-cirque:0.6.06
         #             volumes:
         #                 - "/tmp:/tmp"
         #                 - "/dev/pts:/dev/pts"
diff --git a/.github/workflows/doxygen.yaml b/.github/workflows/doxygen.yaml
index 0751549..1d33bd9 100644
--- a/.github/workflows/doxygen.yaml
+++ b/.github/workflows/doxygen.yaml
@@ -82,7 +82,7 @@
 
         runs-on: ubuntu-20.04
         container:
-            image: connectedhomeip/chip-build-doxygen:0.6.05
+            image: connectedhomeip/chip-build-doxygen:0.6.06
 
         if: github.actor != 'restyled-io[bot]'
 
diff --git a/.github/workflows/examples-ameba.yaml b/.github/workflows/examples-ameba.yaml
index 0f22ae0..50506da 100644
--- a/.github/workflows/examples-ameba.yaml
+++ b/.github/workflows/examples-ameba.yaml
@@ -32,7 +32,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-ameba:0.6.05
+            image: connectedhomeip/chip-build-ameba:0.6.06
             options: --user root
 
         steps:
diff --git a/.github/workflows/examples-cc13x2x7_26x2x7.yaml b/.github/workflows/examples-cc13x2x7_26x2x7.yaml
index 26a3548..78e06bb 100644
--- a/.github/workflows/examples-cc13x2x7_26x2x7.yaml
+++ b/.github/workflows/examples-cc13x2x7_26x2x7.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-ti:0.6.05
+            image: connectedhomeip/chip-build-ti:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml
index 5bf7067..ace5165 100644
--- a/.github/workflows/examples-efr32.yaml
+++ b/.github/workflows/examples-efr32.yaml
@@ -35,7 +35,7 @@
     if: github.actor != 'restyled-io[bot]'
 
     container:
-      image: connectedhomeip/chip-build-efr32:0.6.05
+      image: connectedhomeip/chip-build-efr32:0.6.06
       volumes:
         - "/tmp/bloat_reports:/tmp/bloat_reports"
     steps:
diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml
index 0da3c73..4fa36a4 100644
--- a/.github/workflows/examples-esp32.yaml
+++ b/.github/workflows/examples-esp32.yaml
@@ -31,7 +31,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-esp32:0.6.05
+            image: connectedhomeip/chip-build-esp32:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
@@ -119,7 +119,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-esp32:0.6.05
+            image: connectedhomeip/chip-build-esp32:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-infineon.yaml b/.github/workflows/examples-infineon.yaml
index 3bd67ff..0cf077b 100644
--- a/.github/workflows/examples-infineon.yaml
+++ b/.github/workflows/examples-infineon.yaml
@@ -32,7 +32,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-infineon:0.6.05
+            image: connectedhomeip/chip-build-infineon:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-k32w.yaml b/.github/workflows/examples-k32w.yaml
index f62da3a..ce7088d 100644
--- a/.github/workflows/examples-k32w.yaml
+++ b/.github/workflows/examples-k32w.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-k32w:0.6.05
+            image: connectedhomeip/chip-build-k32w:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-linux-arm.yaml b/.github/workflows/examples-linux-arm.yaml
index 51fae3f..c38d838 100644
--- a/.github/workflows/examples-linux-arm.yaml
+++ b/.github/workflows/examples-linux-arm.yaml
@@ -31,7 +31,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-crosscompile:0.6.05
+            image: connectedhomeip/chip-build-crosscompile:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-linux-imx.yaml b/.github/workflows/examples-linux-imx.yaml
index 81d8d60..1c17f0b 100644
--- a/.github/workflows/examples-linux-imx.yaml
+++ b/.github/workflows/examples-linux-imx.yaml
@@ -31,7 +31,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-imx:0.6.05
+            image: connectedhomeip/chip-build-imx:0.6.06
 
         steps:
             - uses: Wandalen/wretry.action@v1.0.15
diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml
index 38438ec..77fe6ce 100644
--- a/.github/workflows/examples-linux-standalone.yaml
+++ b/.github/workflows/examples-linux-standalone.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-mbed.yaml b/.github/workflows/examples-mbed.yaml
index f7a69bd..1e38a7f 100644
--- a/.github/workflows/examples-mbed.yaml
+++ b/.github/workflows/examples-mbed.yaml
@@ -37,7 +37,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-mbed-os:0.6.05
+            image: connectedhomeip/chip-build-mbed-os:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-mw320.yaml b/.github/workflows/examples-mw320.yaml
index 93c2327..9f54ec8 100755
--- a/.github/workflows/examples-mw320.yaml
+++ b/.github/workflows/examples-mw320.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-nrfconnect.yaml b/.github/workflows/examples-nrfconnect.yaml
index c6b729f..f46b3e8 100644
--- a/.github/workflows/examples-nrfconnect.yaml
+++ b/.github/workflows/examples-nrfconnect.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-nrf-platform:0.6.05
+            image: connectedhomeip/chip-build-nrf-platform:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-qpg.yaml b/.github/workflows/examples-qpg.yaml
index 56656a6..86db7a3 100644
--- a/.github/workflows/examples-qpg.yaml
+++ b/.github/workflows/examples-qpg.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
         steps:
diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml
index e20c269..366cf08 100644
--- a/.github/workflows/examples-telink.yaml
+++ b/.github/workflows/examples-telink.yaml
@@ -32,7 +32,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-telink:0.6.05
+            image: connectedhomeip/chip-build-telink:0.6.06
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
 
diff --git a/.github/workflows/examples-tizen.yaml b/.github/workflows/examples-tizen.yaml
index 47c9e88..c2c3967 100644
--- a/.github/workflows/examples-tizen.yaml
+++ b/.github/workflows/examples-tizen.yaml
@@ -32,7 +32,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-tizen:0.6.05
+            image: connectedhomeip/chip-build-tizen:0.6.06
             options: --user root
             volumes:
                 - "/tmp/bloat_reports:/tmp/bloat_reports"
diff --git a/.github/workflows/full-android.yaml b/.github/workflows/full-android.yaml
index 176f2ac..b3c961e 100644
--- a/.github/workflows/full-android.yaml
+++ b/.github/workflows/full-android.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-android:0.6.05
+            image: connectedhomeip/chip-build-android:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/fuzzing-build.yaml b/.github/workflows/fuzzing-build.yaml
index b9267d9..6caf55c 100644
--- a/.github/workflows/fuzzing-build.yaml
+++ b/.github/workflows/fuzzing-build.yaml
@@ -31,7 +31,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 2b4fe4a..6bb491f 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -28,7 +28,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
 
         steps:
             - uses: Wandalen/wretry.action@v1.0.15
diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml
index eb08379..ab7eb29 100644
--- a/.github/workflows/qemu.yaml
+++ b/.github/workflows/qemu.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-esp32-qemu:0.6.05
+            image: connectedhomeip/chip-build-esp32-qemu:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml
index 6bc9aba..f2124e8 100644
--- a/.github/workflows/release_artifacts.yaml
+++ b/.github/workflows/release_artifacts.yaml
@@ -29,7 +29,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build-esp32:0.6.05
+            image: connectedhomeip/chip-build-esp32:0.6.06
 
         steps:
             - uses: Wandalen/wretry.action@v1.0.15
@@ -75,7 +75,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build-efr32:0.6.05
+            image: connectedhomeip/chip-build-efr32:0.6.06
         steps:
             - uses: Wandalen/wretry.action@v1.0.15
               name: Checkout
diff --git a/.github/workflows/smoketest-android.yaml b/.github/workflows/smoketest-android.yaml
index af5c8c7..7065d26 100644
--- a/.github/workflows/smoketest-android.yaml
+++ b/.github/workflows/smoketest-android.yaml
@@ -34,7 +34,7 @@
         if: github.actor != 'restyled-io[bot]'
 
         container:
-            image: connectedhomeip/chip-build-android:0.6.05
+            image: connectedhomeip/chip-build-android:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
 
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 0e88bb5..b6c4ab7 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -44,7 +44,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
                 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1"
 
@@ -347,7 +347,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0
                 net.ipv4.conf.all.forwarding=0 net.ipv6.conf.all.forwarding=0"
 
diff --git a/.github/workflows/unit_integration_test.yaml b/.github/workflows/unit_integration_test.yaml
index c2875c4..4be02d8 100644
--- a/.github/workflows/unit_integration_test.yaml
+++ b/.github/workflows/unit_integration_test.yaml
@@ -37,7 +37,7 @@
         runs-on: ubuntu-latest
 
         container:
-            image: connectedhomeip/chip-build:0.6.05
+            image: connectedhomeip/chip-build:0.6.06
             volumes:
                 - "/tmp/log_output:/tmp/test_logs"
             options: --privileged --sysctl "net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1"
diff --git a/.github/workflows/zap_regeneration.yaml b/.github/workflows/zap_regeneration.yaml
index 9f76f04..19e44cb 100644
--- a/.github/workflows/zap_regeneration.yaml
+++ b/.github/workflows/zap_regeneration.yaml
@@ -28,7 +28,7 @@
 
         runs-on: ubuntu-20.04
         container:
-            image: connectedhomeip/chip-build-zap:0.6.05
+            image: connectedhomeip/chip-build-zap:0.6.06
         defaults:
             run:
                 shell: sh
diff --git a/.github/workflows/zap_templates.yaml b/.github/workflows/zap_templates.yaml
index 0a16f8e..03aafce 100644
--- a/.github/workflows/zap_templates.yaml
+++ b/.github/workflows/zap_templates.yaml
@@ -29,7 +29,7 @@
 
         runs-on: ubuntu-20.04
         container:
-            image: connectedhomeip/chip-build-zap:0.6.05
+            image: connectedhomeip/chip-build-zap:0.6.06
         defaults:
             run:
                 shell: sh
diff --git a/config/telink/chip-module/CMakeLists.txt b/config/telink/chip-module/CMakeLists.txt
index f6d9321..6ef6ac2 100644
--- a/config/telink/chip-module/CMakeLists.txt
+++ b/config/telink/chip-module/CMakeLists.txt
@@ -28,6 +28,7 @@
 include(ExternalProject)
 include(../../zephyr/ota-image.cmake)
 include(../../zephyr/zephyr-util.cmake)
+include(generate_factory_data.cmake)
 
 # ==============================================================================
 # Declare configuration variables and define constants
@@ -45,7 +46,7 @@
 # CHIP libraries that the application should be linked with
 list(APPEND CHIP_LIBRARIES)
 
-# GN meta-build system arguments in the form of 'key1 = value1\nkey2 = value2...' string
+# GN meta-build system arguments passed to the make_gn_args.py script
 string(APPEND CHIP_GN_ARGS)
 
 # C/C++ compiler flags which should not be forwarded to CHIP
@@ -67,28 +68,27 @@
 # ==============================================================================
 
 macro(chip_gn_arg_import FILE)
-    string(APPEND CHIP_GN_ARGS "import(\"${FILE}\")\n")
+    string(APPEND CHIP_GN_ARGS "--module\n${FILE}\n")
 endmacro()
 
 macro(chip_gn_arg_string ARG STRING)
-    string(APPEND CHIP_GN_ARGS "${ARG} = \"${STRING}\"\n")
+    string(APPEND CHIP_GN_ARGS "--arg-string\n${ARG}\n${STRING}\n")
 endmacro()
 
-macro(chip_gn_arg_bool ARG BOOLEAN)
-    if (${BOOLEAN})
-        string(APPEND CHIP_GN_ARGS "${ARG} = true\n")
+macro(chip_gn_arg_bool ARG)
+    if (${ARGN})
+        string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\ntrue\n")
     else()
-        string(APPEND CHIP_GN_ARGS "${ARG} = false\n")
+        string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\nfalse\n")
     endif()
 endmacro()
 
 macro(chip_gn_arg_cflags ARG CFLAGS)
-    set(CFLAG_EXCLUDES "[")
-    foreach(cflag ${CHIP_CFLAG_EXCLUDES})
-        string(APPEND CFLAG_EXCLUDES "\"${cflag}\", ")
-    endforeach()
-    string(APPEND CFLAG_EXCLUDES "]")
-    string(APPEND CHIP_GN_ARGS "${ARG} = filter_exclude(string_split(\"${CFLAGS}\"), ${CFLAG_EXCLUDES})\n")
+    string(APPEND CHIP_GN_ARGS "--arg-cflags\n${ARG}\n${CFLAGS}\n")
+endmacro()
+
+macro(chip_gn_arg ARG VALUE)
+    string(APPEND CHIP_GN_ARGS "--arg\n${ARG}\n${VALUE}\n")
 endmacro()
 
 # ==============================================================================
@@ -197,8 +197,6 @@
 chip_gn_arg_string("zephyr_ar"                              ${CMAKE_AR})
 chip_gn_arg_string("zephyr_cc"                              ${CMAKE_C_COMPILER})
 chip_gn_arg_string("zephyr_cxx"                             ${CMAKE_CXX_COMPILER})
-chip_gn_arg_string("chip_project_config_include"            "${CHIP_PROJECT_CONFIG}")
-chip_gn_arg_string("chip_system_project_config_include"     "${CHIP_PROJECT_CONFIG}")
 chip_gn_arg_bool  ("is_debug"                               CONFIG_DEBUG)
 chip_gn_arg_bool  ("chip_enable_openthread"                 CONFIG_NET_L2_OPENTHREAD)
 chip_gn_arg_bool  ("chip_openthread_ftd"                    CONFIG_OPENTHREAD_FTD)
@@ -208,16 +206,32 @@
 chip_gn_arg_bool  ("chip_inet_config_enable_tcp_endpoint"   CONFIG_CHIP_BUILD_TESTS)
 chip_gn_arg_bool  ("chip_build_libshell"                    CONFIG_CHIP_LIB_SHELL)
 
+if (CONFIG_CHIP_FACTORY_DATA)
+    chip_gn_arg_bool  ("chip_use_transitional_commissionable_data_provider"  "false")
+    chip_gn_arg_bool  ("chip_enable_factory_data"                            "true")
+elseif (CONFIG_CHIP_FACTORY_DATA_CUSTOM_BACKEND)
+    chip_gn_arg_bool  ("chip_use_transitional_commissionable_data_provider"  "false")
+endif()
+
+if (CONFIG_CHIP_ROTATING_DEVICE_ID)
+    chip_gn_arg_bool("chip_enable_rotating_device_id"          "true")
+    chip_gn_arg_bool("chip_enable_additional_data_advertising" "true")
+endif()
+
 if (CONFIG_CHIP_ENABLE_DNSSD_SRP)
     chip_gn_arg_string("chip_mdns" "platform")
 endif()
 
+if (CHIP_PROJECT_CONFIG)
+    chip_gn_arg_string("chip_project_config_include"        ${CHIP_PROJECT_CONFIG})
+    chip_gn_arg_string("chip_system_project_config_include" ${CHIP_PROJECT_CONFIG})
+endif()
 if (CONFIG_CHIP_EXAMPLE_DEVICE_INFO_PROVIDER)
     chip_gn_arg_bool("chip_build_example_providers" "true")
     list(APPEND CHIP_LIBRARIES -lMatterDeviceInfoProviderExample)
 endif()
 
-file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/args.gn CONTENT ${CHIP_GN_ARGS})
+file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/args.tmp" CONTENT ${CHIP_GN_ARGS})
 
 # ==============================================================================
 # Define 'chip-gn' target that builds CHIP library(ies) with GN build system
@@ -227,13 +241,17 @@
     PREFIX                  ${CMAKE_CURRENT_BINARY_DIR}
     SOURCE_DIR              ${CHIP_ROOT}
     BINARY_DIR              ${CMAKE_CURRENT_BINARY_DIR}
-    CONFIGURE_COMMAND       ${GN_EXECUTABLE}
+    CONFIGURE_COMMAND       ""
+    BUILD_COMMAND           ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/make_gn_args.py
+                                @args.tmp > args.gn &&
+                            ${GN_EXECUTABLE}
                                 --root=${CHIP_ROOT}
                                 --root-target=${GN_ROOT_TARGET}
                                 --dotfile=${GN_ROOT_TARGET}/.gn
                                 --script-executable=${Python3_EXECUTABLE}
-                                gen --check --fail-on-unused-args ${CMAKE_CURRENT_BINARY_DIR}
-    BUILD_COMMAND           ninja
+                                --export-compile-commands
+                                gen --check --fail-on-unused-args . &&
+                            ninja
     INSTALL_COMMAND         ""
     BUILD_BYPRODUCTS        ${CHIP_LIBRARIES}
     BUILD_ALWAYS            TRUE
@@ -288,11 +306,11 @@
         west sign -t imgtool -p ${ZEPHYR_BASE}/../bootloader/mcuboot/scripts/imgtool.py -d ${PROJECT_BINARY_DIR}/.. -- --key ${ZEPHYR_BASE}/../bootloader/mcuboot/root-rsa-2048.pem
     )
 
-    add_custom_target(final_bin ALL
+    add_custom_target(merge_mcuboot ALL
         COMMAND
-        dd if=${PROJECT_BINARY_DIR}/../modules/chip-module/build_mcuboot/zephyr/zephyr.bin of=${PROJECT_BINARY_DIR}/zephyr_final.bin
+        dd if=${PROJECT_BINARY_DIR}/../modules/chip-module/build_mcuboot/zephyr/zephyr.bin of=${PROJECT_BINARY_DIR}/zephyr.bin
         COMMAND
-        dd if=${PROJECT_BINARY_DIR}/zephyr.signed.bin of=${PROJECT_BINARY_DIR}/zephyr_final.bin bs=1024 seek=64
+        dd if=${PROJECT_BINARY_DIR}/zephyr.signed.bin of=${PROJECT_BINARY_DIR}/zephyr.bin bs=1024 seek=64
     )
 
     chip_ota_image(chip-ota-image
@@ -301,8 +319,28 @@
     )
 
     add_dependencies(west_sign ${ZEPHYR_FINAL_EXECUTABLE})
-    add_dependencies(final_bin west_sign)
+    add_dependencies(merge_mcuboot west_sign)
     add_dependencies(chip-ota-image west_sign)
 endif()
 
+if (CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE)
+    add_custom_target(merge_factory_data ALL
+        COMMAND
+        dd if=${PROJECT_BINARY_DIR}/factory_data.bin of=${PROJECT_BINARY_DIR}/zephyr.bin bs=1024 seek=976
+    )
+if (CONFIG_CHIP_OTA_IMAGE_BUILD)
+    add_dependencies(merge_factory_data merge_mcuboot)
+else()
+    add_dependencies(merge_factory_data ${ZEPHYR_FINAL_EXECUTABLE})
+endif()
+endif()
+
+# ==============================================================================
+# Define 'factory_data' target for generating a factory data partition
+# ==============================================================================
+
+if (CONFIG_CHIP_FACTORY_DATA_BUILD)
+    telink_generate_factory_data()
+endif()
+
 endif() # CONFIG_CHIP
diff --git a/config/telink/chip-module/Kconfig b/config/telink/chip-module/Kconfig
index e02dee9..366c43d 100644
--- a/config/telink/chip-module/Kconfig
+++ b/config/telink/chip-module/Kconfig
@@ -59,4 +59,210 @@
 # Enable getting reboot reasons information
 config HWINFO
     bool
-    default y
\ No newline at end of file
+    default y
+
+config CHIP_FACTORY_DATA
+	bool "Enable Factory Data support"
+	select ZCBOR
+	help
+	  Enables support for reading factory data from flash memory partition.
+	  It requires factory_data partition to exist.
+
+config CHIP_FACTORY_DATA_CUSTOM_BACKEND
+	bool "Enable Factory Data custom backend"
+	depends on !CHIP_FACTORY_DATA
+	help
+	  Enables user custom factory data implementation. It cannot be used
+	  with the CHIP_FACTORY_DATA that enabled default Telink factory data
+	  implementation.
+
+config CHIP_FACTORY_DATA_BUILD
+	bool "Enable Factory Data build"
+	default n
+	help
+	  Enables generation of factory data during the building.
+	  It requires factory_data partition to exist.
+	  As a result a new output file factory_data.bin will be created.
+
+config CHIP_FACTORY_DATA_VERSION
+	int
+	default 1
+	help
+	  The Factory data version contains a current version of a factory data 
+	  parameter set that the user cannot change. 
+	  After moving to the next version of the factory data set, change the default value. 
+	  This config is used to validate the version of a factory data set on a device-side 
+	  with the version of factory data saved in the Flash memory.
+
+if CHIP_FACTORY_DATA_BUILD
+
+# Factory data definitions
+config CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE
+	bool "Enable merging generated factory data with the build target .bin file"
+	default y
+	help
+	  Enables merging generated factory data with the build target zephyr.bin file.
+	  As a result, output file zephyr.bin will consist of all partitions including 
+	  factory data.
+
+# Use default certificates without generating or providing them
+config CHIP_FACTORY_DATA_USE_DEFAULT_CERTS
+	bool "Use default certificates located in Matter repository"
+	default y
+	help
+	  Pre-generated certificates can be used for development purpose.
+	  This config includes default pre-generated certificates 
+	  which are located in credentials/development/attestation/ directory 
+	  instead of generating new ones.
+	  If this config is set to `n` new certificates will be generated.
+
+# Configs for SPAKE2 generation
+config CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER
+	bool "Enable spake2 verifier generation"
+	help
+	  Enables generation of spake2 verifier according to 
+	  given iteration counter, salt and passcode.
+	  To generate Spake2 verifier a spake2p executable must be available 
+	  from system variables environment.
+
+config CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID
+	bool "Enable generation of a new Rotating device id unique id"
+	default y
+	help
+	  Enables generation of a new Rotating device id unique id.
+
+endif #CHIP_FACTORY_DATA_BUILD
+
+# Factory data parameters
+config CHIP_DEVICE_SERIAL_NUMBER
+	string "Serial number of device"
+	default "11223344556677889900"
+	help
+	  A serial number parameter defines an unique number of manufactured device.
+	  Maximum length of serial number is 32 characters.
+
+config CHIP_DEVICE_VENDOR_NAME
+	string "Human-readable vendor name"
+	default "Telink Semiconductor"
+	help
+	  A human-readable vendor name which provides a simple string 
+	  containing identification of device's vendor for the Content APP.
+	  This information should be included in the Matter Basic Cluster.
+
+config CHIP_DEVICE_PRODUCT_NAME
+	string "Human-readable product name"
+	default "not-specified"
+	help
+	  A human-readable product name which provides a simple string 
+	  containing identification of the product for the Content APP.
+
+config CHIP_DEVICE_MANUFACTURING_DATE
+	string "Manufacturing date in ISO 8601"
+	default "2022-01-01"
+	help
+	  A manufacturing date specifies the date that the device was manufactured.
+	  The format used for providing a manufacturing date is ISO 8601 e.g. YYYY-MM-DD.
+	
+config CHIP_DEVICE_HARDWARE_VERSION
+	int "Integer representation of hardware version"
+	default 0
+	help
+	  A hardware version number specifies the version number
+	  of the hardware of the device. The meaning of its value, 
+	  and the versioning scheme, are vendor defined.
+
+config CHIP_DEVICE_HARDWARE_VERSION_STRING
+	string "user-friendly string representation of hardware version"
+	default "prerelease"
+	help
+	  A hardware version string parameter specifies the version
+	  of the hardware of the device as a more user-friendly value
+	  than that represented by the hardware version integer value.
+	  The meaning of its value, and the versioning scheme, are
+	  vendor defined.
+
+config CHIP_DEVICE_DISCRIMINATOR
+	hex "Device pairing discriminator"
+	default 0xF00
+	help
+	  A 12-bit value matching the field of the same name in
+	  the setup code. Discriminator is used during
+	  a discovery process.
+
+config CHIP_DEVICE_SPAKE2_PASSCODE 
+	int "Spake2+ passcode"
+	default 20202021
+	range 1 99999998
+	help
+	  A pairing passcode is a 27-bit unsigned integer which serves
+	  as a proof of possession during commissioning. 
+	  Its value shall be restricted to the values 0x0000001 to 0x5F5E0FE
+	  (00000001 to 99999998 in decimal), excluding the invalid Passcode values:
+	  - 00000000, 11111111, 22222222, 33333333, 44444444, 55555555, 
+	  66666666, 77777777, 88888888, 99999999, 12345678, 87654321.
+
+config CHIP_DEVICE_SPAKE2_IT
+	int "Spake2+ iteration count"
+	default 1000
+	help
+	  The Spake2 iteration count is associated with the ephemeral
+	  PAKE passcode verifier to be used for the commissioning.
+	  The iteration count is used as a crypto parameter to process
+	  spake2 verifier.
+
+config CHIP_DEVICE_SPAKE2_SALT
+	string "Spake2+ salt in string format"
+	default "U1BBS0UyUCBLZXkgU2FsdA=="
+	help
+	  The spake2 salt is random data that is used as an additional input 
+	  to a one-way function that “hashes” data. 
+	  A new salt should be randomly generated for each password.
+	  The minimum length of spake2 salt is 16 Bytes.
+	  The maximum length of spake2 salt is 32 Bytes.
+
+config CHIP_DEVICE_SPAKE2_TEST_VERIFIER
+	string "Testing spake2+ verifier"
+	default "uWFwqugDNGiEck/po7KHwwMwwqZgN10XuyBajPGuyzUEV/iree4lOrao5GuwnlQ65CJzbeUB49s31EH+NEkg0JVI5MGCQGMMT/SRPFNRODm3wH/MBiehuFc6FJ/NH6Rmzw=="
+	help
+	  The spake 2 verifier generated using default SPAKE2 salt, 
+	  iteration count and passcode. This value can be used for development
+	  or testing purposes.
+	  Generated with: 
+	  spake2p gen-verifier -o - -i 1000 -s "U1BBS0UyUCBLZXkgU2FsdA==" -p 20202021
+
+config CHIP_DEVICE_ROTATING_DEVICE_UID
+	string  "A rotating device id unique id"
+	default "91a9c12a7c80700a31ddcfa7fce63e44"
+	help
+	  A device rotating id unique id which will be generated if
+	  this config is not set in prj.conf file.
+
+config CHIP_DEVICE_ENABLE_KEY
+	string "Enable Key for triggering test actions on device"
+	default "00112233445566778899AABBCCDDEEFF"
+	help
+	  The Enable Key is a 128-bit value that triggers test action 
+	  while invoking the TestEventTrigger Command. 
+	  Pattern: "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+	  This value is used during Certification Tests,
+	  and should not be present on production devices.
+
+config CHIP_CERTIFICATION_DECLARATION_STORAGE
+	bool "Enable storing Certification Declaration"
+	depends on CHIP_FACTORY_DATA
+	help
+	  Enables storing Certification Declaration in Zephyr settings
+	  instead of using hardcoded value from firmware. It also adds
+	  support for including new Certification Declaration into a firmware
+	  update image package sent via OTA Software Update.
+
+if CHIP_CERTIFICATION_DECLARATION_STORAGE
+
+config CHIP_CERTIFiCATION_DECLARATION_OTA_IMAGE_ID
+	int "Certification declaration OTA image id"
+	default 205 #0xcd
+	help
+	  The image id of Certification Declaration image
+	  for sending it via OTA Software Update purposes.
+
+endif
diff --git a/config/telink/chip-module/generate_factory_data.cmake b/config/telink/chip-module/generate_factory_data.cmake
new file mode 100644
index 0000000..ff9514e
--- /dev/null
+++ b/config/telink/chip-module/generate_factory_data.cmake
@@ -0,0 +1,194 @@
+#
+#   Copyright (c) 2022 Project CHIP Authors
+#
+#   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.
+#
+
+
+# Create a JSON file based on factory data given via kConfigs.
+#
+# This function creates a list of arguments for external script and then run it to write a JSON file.
+# Created JSON file can be checked using JSON SCHEMA file if it is provided.
+#
+# This script can be manipulated using following kConfigs:
+# - To merge generated factory data with final zephyr.hex file set kConfig CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=y
+# - To use default certification paths set CONFIG_CHIP_FACTORY_DATA_USE_DEFAULTS_CERTS_PATH=y 
+# 
+# During generation process a some file will be created in zephyr's build directory:
+# - <factory_data_target>.json a file containing all factory data written in JSON format.
+#
+# [Args]:
+#   factory_data_target - a name for target to generate factory_data.
+#   script_path         - a path to script that makes a JSON factory data file from given arguments.
+#   schema_path         - a path to JSON schema file which can be used to verify generated factory data JSON file.
+#                         This argument is optional, if you don't want to verify the JSON file put it empty "".
+#   output_path         - a path to output directory, where created JSON file will be stored.
+function(telink_create_factory_data_json factory_data_target script_path schema_path output_path)
+
+# set script args for future purpose
+set(script_args)
+## generate all script arguments
+string(APPEND script_args "--sn \"${CONFIG_CHIP_DEVICE_SERIAL_NUMBER}\"\n")
+string(APPEND script_args "--date \"${CONFIG_CHIP_DEVICE_MANUFACTURING_DATE}\"\n")
+string(APPEND script_args "--vendor_id ${CONFIG_CHIP_DEVICE_VENDOR_ID}\n")
+string(APPEND script_args "--product_id ${CONFIG_CHIP_DEVICE_PRODUCT_ID}\n")
+string(APPEND script_args "--vendor_name \"${CONFIG_CHIP_DEVICE_VENDOR_NAME}\"\n")
+string(APPEND script_args "--product_name \"${CONFIG_CHIP_DEVICE_PRODUCT_NAME}\"\n")
+string(APPEND script_args "--hw_ver ${CONFIG_CHIP_DEVICE_HARDWARE_VERSION}\n")
+string(APPEND script_args "--hw_ver_str \"${CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING}\"\n")
+
+# check if Rotating Device Id Unique Id should be generated
+if(NOT CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID)
+    if(NOT DEFINED CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID)
+        message(FATAL_ERROR "CHIP_DEVICE_ROTATING_DEVICE_UID was not provided. To generate it use CONFIG_CHIP_DEVICE_GENERATE_ROTATING_DEVICE_UID=y")
+    else()
+        string(APPEND script_args "--rd_uid \"${CONFIG_CHIP_DEVICE_ROTATING_DEVICE_UID}\"\n")
+    endif()
+else()
+    string(APPEND script_args "--generate_rd_uid\n")
+endif()
+
+# for development purpose user can use default certs instead of generating or providing them
+if(CONFIG_CHIP_FACTORY_DATA_USE_DEFAULT_CERTS)
+    # convert decimal PID to its hexadecimal representation to find out certification files in repository
+    math(EXPR LOCAL_PID "${CONFIG_CHIP_DEVICE_PRODUCT_ID}" OUTPUT_FORMAT HEXADECIMAL)
+    string(SUBSTRING ${LOCAL_PID} 2 -1 raw_pid)
+    # all certs are located in ${CHIP_ROOT}/credentials/development/attestation
+    # it can be used during development without need to generate new certifications
+    string(APPEND script_args "--dac_cert \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid}-Cert.der\"\n")
+    string(APPEND script_args "--dac_key \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-DAC-${raw_pid}-Key.der\"\n")
+    string(APPEND script_args "--pai_cert \"${CHIP_ROOT}/credentials/development/attestation/Matter-Development-PAI-noPID-Cert.der\"\n")
+else()
+    find_program(chip_cert_exe NAMES chip-cert REQUIRED)
+    string(APPEND script_args "--gen_cd\n")
+    string(APPEND script_args "--chip_cert_path ${chip_cert_exe}\n")
+endif()
+
+# add Password-Authenticated Key Exchange parameters
+string(APPEND script_args "--spake2_it \"${CONFIG_CHIP_DEVICE_SPAKE2_IT}\"\n")
+string(APPEND script_args "--spake2_salt \"${CONFIG_CHIP_DEVICE_SPAKE2_SALT}\"\n")
+string(APPEND script_args "--discriminator ${CONFIG_CHIP_DEVICE_DISCRIMINATOR}\n")
+string(APPEND script_args "--passcode ${CONFIG_CHIP_DEVICE_SPAKE2_PASSCODE}\n")
+string(APPEND script_args "--overwrite\n")
+
+# check if spake2 verifier should be generated using script
+if(CONFIG_CHIP_FACTORY_DATA_GENERATE_SPAKE2_VERIFIER)
+    # request script to generate a new spake2_verifier
+    # by adding an argument to script_args
+    find_program(spake_exe NAMES spake2p REQUIRED)
+    string(APPEND script_args "--spake2p_path ${spake_exe}\n")   
+else()
+    # Spake2 verifier should be provided using kConfig
+    string(APPEND script_args "--spake2_verifier \"${CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER}\"\n")
+endif()
+
+if(CONFIG_CHIP_DEVICE_ENABLE_KEY)
+# Add optional EnableKey that triggers user-specific action.
+string(APPEND script_args "--enable_key \"${CONFIG_CHIP_DEVICE_ENABLE_KEY}\"\n")
+endif()
+
+# Set output JSON file and path to SCHEMA file to validate generated factory data
+set(factory_data_json ${output_path}/${factory_data_target}.json)
+string(APPEND script_args "-o \"${factory_data_json}\"\n")
+string(APPEND script_args "-s \"${schema_path}\"\n")
+
+# execute first script to create a JSON file
+separate_arguments(separated_script_args NATIVE_COMMAND ${script_args})
+add_custom_command(
+    OUTPUT ${factory_data_json}
+    DEPENDS ${FACTORY_DATA_SCRIPT_PATH}
+    COMMAND ${Python3_EXECUTABLE} ${FACTORY_DATA_SCRIPT_PATH} ${separated_script_args}
+    COMMENT "Generating new Factory Data..."
+    )
+add_custom_target(${factory_data_target} ALL
+    DEPENDS ${factory_data_json}
+    )
+
+endfunction()
+
+
+# Create a .hex file with factory data in CBOR format.
+#
+# This function creates a .hex and .cbor files from given JSON factory data file.
+#
+# 
+# During generation process some files will be created in zephyr's build directory:
+# - <factory_data_target>.hex a file containing all factory data in CBOR format.
+# - <factory_data_target>.bin a binary file containing all raw factory data in CBOR format.
+# - <factory_data_target>.cbor a file containing all factory data in CBOR format.
+#
+# [Args]:
+#   factory_data_hex_target - a name for target to generate factory data HEX file.
+#   factory_data_target     - a name for target to generate factory data JSON file.
+#   script_path             - a path to script that makes a factory data .hex file from given arguments.
+#   output_path             - a path to output directory, where created JSON file will be stored.
+function(telink_create_factory_data_hex_file factory_data_hex_target factory_data_target script_path output_path)
+
+# Pass the argument list via file
+set(cbor_script_args "-i ${output_path}/${factory_data_target}.json\n")
+string(APPEND cbor_script_args "-o ${output_path}/${factory_data_target}\n")
+# get partition address and offset from partition manager during compilation
+string(APPEND cbor_script_args "--offset 0xf4000\n")
+string(APPEND cbor_script_args "--size 0x1000\n")
+string(APPEND cbor_script_args "-r\n")
+
+# execute second script to create a hex file containing factory data in cbor format
+separate_arguments(separated_cbor_script_args NATIVE_COMMAND ${cbor_script_args})
+set(factory_data_hex ${output_path}/${factory_data_target}.hex)
+
+add_custom_command(OUTPUT ${factory_data_hex}
+    COMMAND ${Python3_EXECUTABLE} ${script_path} ${separated_cbor_script_args}
+    COMMENT "Generating factory data HEX file..."
+    DEPENDS ${factory_data_target} ${script_path}
+    )
+add_custom_target(${factory_data_hex_target} ALL
+    DEPENDS ${factory_data_hex}
+    )
+
+endfunction()
+
+# Generate factory data partition using given args
+#
+# 
+# During generation process a some file will be created in zephyr's build directory:
+# - merged.hex a file containing firmware and factory data merged to single file
+# - factory_data.hex a file containing only a factory data partition including proper offset
+#
+function(telink_generate_factory_data)
+
+find_package(Python REQUIRED)
+
+# CHIP_ROOT must be provided as a reference set all localization of scripts
+if(NOT CHIP_ROOT)
+message(FATAL_ERROR "CHIP_ROOT variable is not set, please add it to CMakeLists.txt file")
+endif()
+
+# Localize all scripts needed to generate factory data partition
+set(FACTORY_DATA_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/telink/generate_telink_chip_factory_data.py)
+set(GENERATE_CBOR_SCRIPT_PATH ${CHIP_ROOT}/scripts/tools/telink/telink_generate_partition.py)
+set(FACTORY_DATA_SCHEMA_PATH ${CHIP_ROOT}/scripts/tools/telink/telink_factory_data.schema)
+set(OUTPUT_FILE_PATH ${APPLICATION_BINARY_DIR}/zephyr)
+
+# create a JSON file with all factory data
+telink_create_factory_data_json(factory_data
+                                    ${FACTORY_DATA_SCRIPT_PATH} 
+                                    ${FACTORY_DATA_SCHEMA_PATH} 
+                                    ${OUTPUT_FILE_PATH})
+
+# create a .hex file with factory data in CBOR format based on the JSON file created previously 
+telink_create_factory_data_hex_file(factory_data_hex
+                                        factory_data
+                                        ${GENERATE_CBOR_SCRIPT_PATH} 
+                                        ${OUTPUT_FILE_PATH})
+
+endfunction()
diff --git a/config/telink/chip-module/make_gn_args.py b/config/telink/chip-module/make_gn_args.py
new file mode 100755
index 0000000..f30cd45
--- /dev/null
+++ b/config/telink/chip-module/make_gn_args.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+
+#
+#    Copyright (c) 2021 Project CHIP Authors
+#    All rights reserved.
+#
+#    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.
+#
+
+import argparse
+import re
+import sys
+
+GN_SPECIAL_CHARACTERS = r'(["$\\])'
+GN_CFLAG_EXCLUDES = [
+    '-fno-asynchronous-unwind-tables',
+    '-fno-common',
+    '-fno-defer-pop',
+    '-fno-reorder-functions',
+    '-ffunction-sections',
+    '-fdata-sections',
+    '-g*',
+    '-O*',
+    '-W*',
+]
+
+
+def escape_strings(gn_args):
+    return [[key, re.sub(GN_SPECIAL_CHARACTERS, r'\\\1', value)] for key, value in gn_args]
+
+
+def write_gn_args(args):
+    if args.module:
+        sys.stdout.write('import("{}")\n'.format(args.module))
+
+    for key, value in args.arg:
+        sys.stdout.write('{} = {}\n'.format(key, value))
+
+    for key, value in args.arg_string:
+        sys.stdout.write('{} = "{}"\n'.format(key, value))
+
+    cflag_excludes = ', '.join(['"{}"'.format(exclude)
+                               for exclude in GN_CFLAG_EXCLUDES])
+
+    for key, value in args.arg_cflags:
+        sys.stdout.write('{} = filter_exclude(string_split("{}"), [{}])\n'.format(
+            key, value, cflag_excludes))
+
+
+def main():
+    parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+    parser.add_argument('--module', action='store')
+    parser.add_argument('--arg', action='append', nargs=2, default=[])
+    parser.add_argument('--arg-string', action='append', nargs=2, default=[])
+    parser.add_argument('--arg-cflags', action='append', nargs=2, default=[])
+    args = parser.parse_args()
+    args.arg_string = escape_strings(args.arg_string)
+    args.arg_cflags = escape_strings(args.arg_cflags)
+    write_gn_args(args)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay b/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay
deleted file mode 100644
index 613584d..0000000
--- a/examples/light-switch-app/telink/boards/tlsr9518adk80d.overlay
+++ /dev/null
@@ -1,35 +0,0 @@
-&flash {
-    /delete-node/ partitions;
-};
-
-&flash {
-	reg = <0x20000000 0x100000>;
-
-	partitions {
-		compatible = "fixed-partitions";
-		#address-cells = <1>;
-		#size-cells = <1>;
-
-		boot_partition: partition@0 {
-			label = "mcuboot";
-			reg = <0x00000000 0x10000>;
-		};
-		slot0_partition: partition@10000 {
-			label = "image-0";
-			reg = <0x10000 0x70000>;
-		};
-		slot1_partition: partition@80000 {
-			label = "image-1";
-			reg = <0x80000 0x70000>;
-		};
-		scratch_partition: partition@f0000 {
-			label = "image-scratch";
-			reg = <0xf0000 0x4000>;
-		};
-		storage_partition: partition@f4000 {
-			label = "storage";
-			reg = <0xf4000 0x0000b000>;
-		/* region <0xff000 0x1000> is reserved for Telink B91 SDK's data */
-		};
-	};
-};
diff --git a/examples/light-switch-app/telink/include/AppTask.h b/examples/light-switch-app/telink/include/AppTask.h
index 7fd67ff..6cf0a33 100755
--- a/examples/light-switch-app/telink/include/AppTask.h
+++ b/examples/light-switch-app/telink/include/AppTask.h
@@ -24,6 +24,10 @@
 
 #include <platform/CHIPDeviceLayer.h>
 
+#if CONFIG_CHIP_FACTORY_DATA
+#include <platform/telink/FactoryDataProvider.h>
+#endif
+
 #include <cstdint>
 
 struct k_timer;
@@ -48,7 +52,6 @@
 
 private:
     friend AppTask & GetAppTask(void);
-
     CHIP_ERROR Init();
 
     static void ActionInitiated(AppTask::Action_t aAction, int32_t aActor);
@@ -74,6 +77,11 @@
     static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
 
     static AppTask sAppTask;
+
+#if CONFIG_CHIP_FACTORY_DATA
+    // chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::InternalFlashFactoryData> mFactoryDataProvider;
+    chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::ExternalFlashFactoryData> mFactoryDataProvider;
+#endif
 };
 
 inline AppTask & GetAppTask(void)
diff --git a/examples/light-switch-app/telink/prj.conf b/examples/light-switch-app/telink/prj.conf
index 05b92e9..1366c5f 100755
--- a/examples/light-switch-app/telink/prj.conf
+++ b/examples/light-switch-app/telink/prj.conf
@@ -54,4 +54,8 @@
 CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y
 
 # CHIP shell
-CONFIG_CHIP_LIB_SHELL=n
\ No newline at end of file
+CONFIG_CHIP_LIB_SHELL=n
+
+# Disable factory data support. 
+CONFIG_CHIP_FACTORY_DATA=n
+CONFIG_CHIP_FACTORY_DATA_BUILD=n
\ No newline at end of file
diff --git a/examples/light-switch-app/telink/src/AppTask.cpp b/examples/light-switch-app/telink/src/AppTask.cpp
index e8d3d00..7e1c792 100644
--- a/examples/light-switch-app/telink/src/AppTask.cpp
+++ b/examples/light-switch-app/telink/src/AppTask.cpp
@@ -23,27 +23,19 @@
 #include "ButtonManager.h"
 #include "LEDWidget.h"
 #include "binding-handler.h"
-#include <app/server/OnboardingCodesUtil.h>
-#include <app/server/Server.h>
-
-#include <DeviceInfoProviderImpl.h>
 
 #include "ThreadUtil.h"
 
+#include <DeviceInfoProviderImpl.h>
 #include <app-common/zap-generated/attribute-id.h>
 #include <app-common/zap-generated/attribute-type.h>
 #include <app-common/zap-generated/cluster-id.h>
 #include <app/clusters/identify-server/identify-server.h>
-#include <app/util/attribute-storage.h>
-
+#include <app/server/OnboardingCodesUtil.h>
+#include <app/server/Server.h>
 #include <credentials/DeviceAttestationCredsProvider.h>
 #include <credentials/examples/DeviceAttestationCredsExample.h>
-
-#include <platform/CHIPDeviceLayer.h>
-
 #include <lib/support/ErrorStr.h>
-#include <setup_payload/QRCodeSetupPayloadGenerator.h>
-#include <setup_payload/SetupPayload.h>
 #include <system/SystemClock.h>
 
 #if CONFIG_CHIP_OTA_REQUESTOR
@@ -57,12 +49,22 @@
 
 LOG_MODULE_DECLARE(app);
 
+using namespace ::chip;
+using namespace ::chip::app;
+using namespace ::chip::Credentials;
+using namespace ::chip::DeviceLayer;
+
 namespace {
 
 constexpr int kAppEventQueueSize      = 10;
 constexpr uint8_t kButtonPushEvent    = 1;
 constexpr uint8_t kButtonReleaseEvent = 0;
 
+// NOTE! This key is for test/certification only and should not be available in production devices!
+// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data.
+uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                                                                                   0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+
 K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent));
 
 LEDWidget sStatusLED;
@@ -112,15 +114,11 @@
 
 } // namespace
 
-using namespace ::chip::Credentials;
-using namespace ::chip::DeviceLayer;
-using namespace ::chip::DeviceLayer::Internal;
-
 AppTask AppTask::sAppTask;
 
 CHIP_ERROR AppTask::Init()
 {
-    CHIP_ERROR ret;
+    CHIP_ERROR err;
 
     LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION,
             CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING);
@@ -133,15 +131,30 @@
 
     InitButtons();
 
-    // Init ZCL Data Model and start server
-    static chip::CommonCaseDeviceServerInitParams initParams;
-    (void) initParams.InitializeStaticResourcesBeforeServerInit();
-    chip::Server::GetInstance().Init(initParams);
-
-    // Initialize device attestation config
+    // Initialize CHIP server
+#if CONFIG_CHIP_FACTORY_DATA
+    ReturnErrorOnFailure(mFactoryDataProvider.Init());
+    SetDeviceInstanceInfoProvider(&mFactoryDataProvider);
+    SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider);
+    SetCommissionableDataProvider(&mFactoryDataProvider);
+    // Read EnableKey from the factory data.
+    MutableByteSpan enableKey(sTestEventTriggerEnableKey);
+    err = mFactoryDataProvider.GetEnableKey(enableKey);
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger");
+        memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey));
+    }
+#else
     SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());
+#endif
 
-    gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage());
+    static CommonCaseDeviceServerInitParams initParams;
+    // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) };
+    (void) initParams.InitializeStaticResourcesBeforeServerInit();
+    // initParams.testEventTriggerDelegate = &testEventTriggerDelegate;
+    ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams));
+    gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage());
     chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
 
 #if CONFIG_CHIP_OTA_REQUESTOR
@@ -151,11 +164,11 @@
     ConfigurationMgr().LogDeviceConfig();
 
     // Configure Bindings
-    ret = InitBindingHandler();
-    if (ret != CHIP_NO_ERROR)
+    err = InitBindingHandler();
+    if (err != CHIP_NO_ERROR)
     {
         LOG_ERR("InitBindingHandler() failed");
-        return ret;
+        return err;
     }
 
     PrintOnboardingCodes(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE));
@@ -165,14 +178,13 @@
     // between the main and the CHIP threads.
     PlatformMgr().AddEventHandler(ChipEventHandler, 0);
 
-    ret = ConnectivityMgr().SetBLEDeviceName("TelinkSwitch");
-    if (ret != CHIP_NO_ERROR)
+    err = ConnectivityMgr().SetBLEDeviceName("TelinkSwitch");
+    if (err != CHIP_NO_ERROR)
     {
         LOG_ERR("Fail to set BLE device name");
-        return ret;
     }
 
-    return CHIP_NO_ERROR;
+    return err;
 }
 
 CHIP_ERROR AppTask::StartApp()
@@ -255,7 +267,7 @@
     if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned())
     {
         // Switch context from BLE to Thread
-        BLEManagerImpl sInstance;
+        Internal::BLEManagerImpl sInstance;
         sInstance.SwitchToIeee802154();
         StartDefaultThreadNetwork();
         LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration.");
diff --git a/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay b/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay
deleted file mode 100644
index 613584d..0000000
--- a/examples/lighting-app/telink/boards/tlsr9518adk80d.overlay
+++ /dev/null
@@ -1,35 +0,0 @@
-&flash {
-    /delete-node/ partitions;
-};
-
-&flash {
-	reg = <0x20000000 0x100000>;
-
-	partitions {
-		compatible = "fixed-partitions";
-		#address-cells = <1>;
-		#size-cells = <1>;
-
-		boot_partition: partition@0 {
-			label = "mcuboot";
-			reg = <0x00000000 0x10000>;
-		};
-		slot0_partition: partition@10000 {
-			label = "image-0";
-			reg = <0x10000 0x70000>;
-		};
-		slot1_partition: partition@80000 {
-			label = "image-1";
-			reg = <0x80000 0x70000>;
-		};
-		scratch_partition: partition@f0000 {
-			label = "image-scratch";
-			reg = <0xf0000 0x4000>;
-		};
-		storage_partition: partition@f4000 {
-			label = "storage";
-			reg = <0xf4000 0x0000b000>;
-		/* region <0xff000 0x1000> is reserved for Telink B91 SDK's data */
-		};
-	};
-};
diff --git a/examples/lighting-app/telink/include/AppTask.h b/examples/lighting-app/telink/include/AppTask.h
index d926c52..0b1b588 100644
--- a/examples/lighting-app/telink/include/AppTask.h
+++ b/examples/lighting-app/telink/include/AppTask.h
@@ -1,6 +1,6 @@
 /*
  *
- *    Copyright (c) 2021 Project CHIP Authors
+ *    Copyright (c) 2022 Project CHIP Authors
  *    All rights reserved.
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +23,10 @@
 
 #include <platform/CHIPDeviceLayer.h>
 
+#if CONFIG_CHIP_FACTORY_DATA
+#include <platform/telink/FactoryDataProvider.h>
+#endif
+
 #include <cstdint>
 
 struct k_timer;
@@ -38,7 +42,6 @@
 
 private:
     friend AppTask & GetAppTask(void);
-
     CHIP_ERROR Init();
 
     static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor);
@@ -64,6 +67,11 @@
     static void ThreadProvisioningHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg);
 
     static AppTask sAppTask;
+
+#if CONFIG_CHIP_FACTORY_DATA
+    // chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::InternalFlashFactoryData> mFactoryDataProvider;
+    chip::DeviceLayer::FactoryDataProvider<chip::DeviceLayer::ExternalFlashFactoryData> mFactoryDataProvider;
+#endif
 };
 
 inline AppTask & GetAppTask(void)
diff --git a/examples/lighting-app/telink/prj.conf b/examples/lighting-app/telink/prj.conf
index 3e94168..3de670d 100644
--- a/examples/lighting-app/telink/prj.conf
+++ b/examples/lighting-app/telink/prj.conf
@@ -54,4 +54,8 @@
 CONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=y
 
 # CHIP shell
-CONFIG_CHIP_LIB_SHELL=n
\ No newline at end of file
+CONFIG_CHIP_LIB_SHELL=n
+
+# Disable factory data support. 
+CONFIG_CHIP_FACTORY_DATA=n
+CONFIG_CHIP_FACTORY_DATA_BUILD=n
\ No newline at end of file
diff --git a/examples/lighting-app/telink/src/AppTask.cpp b/examples/lighting-app/telink/src/AppTask.cpp
index fd9eabc..00db77c 100644
--- a/examples/lighting-app/telink/src/AppTask.cpp
+++ b/examples/lighting-app/telink/src/AppTask.cpp
@@ -23,28 +23,20 @@
 #include "ButtonManager.h"
 #include "LEDWidget.h"
 #include "LightingManager.h"
-#include <app/server/OnboardingCodesUtil.h>
-#include <app/server/Server.h>
-
-#include <DeviceInfoProviderImpl.h>
 
 #include "ThreadUtil.h"
 
+#include <DeviceInfoProviderImpl.h>
 #include <app-common/zap-generated/attribute-id.h>
 #include <app-common/zap-generated/attribute-type.h>
 #include <app-common/zap-generated/attributes/Accessors.h>
 #include <app-common/zap-generated/cluster-id.h>
 #include <app/clusters/identify-server/identify-server.h>
-#include <app/util/attribute-storage.h>
-
+#include <app/server/OnboardingCodesUtil.h>
+#include <app/server/Server.h>
 #include <credentials/DeviceAttestationCredsProvider.h>
 #include <credentials/examples/DeviceAttestationCredsExample.h>
-
-#include <platform/CHIPDeviceLayer.h>
-
 #include <lib/support/ErrorStr.h>
-#include <setup_payload/QRCodeSetupPayloadGenerator.h>
-#include <setup_payload/SetupPayload.h>
 #include <system/SystemClock.h>
 
 #if CONFIG_CHIP_OTA_REQUESTOR
@@ -58,6 +50,11 @@
 
 LOG_MODULE_DECLARE(app);
 
+using namespace ::chip;
+using namespace ::chip::app;
+using namespace ::chip::Credentials;
+using namespace ::chip::DeviceLayer;
+
 namespace {
 
 constexpr int kAppEventQueueSize      = 10;
@@ -66,6 +63,11 @@
 constexpr uint8_t kDefaultMinLevel    = 0;
 constexpr uint8_t kDefaultMaxLevel    = 254;
 
+// NOTE! This key is for test/certification only and should not be available in production devices!
+// If CONFIG_CHIP_FACTORY_DATA is enabled, this value is read from the factory data.
+uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                                                                                   0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+
 K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent));
 
 LEDWidget sStatusLED;
@@ -115,18 +117,10 @@
 
 } // namespace
 
-using namespace ::chip;
-using namespace ::chip::app;
-using namespace ::chip::Credentials;
-using namespace ::chip::DeviceLayer;
-using namespace ::chip::DeviceLayer::Internal;
-
 AppTask AppTask::sAppTask;
 
 CHIP_ERROR AppTask::Init()
 {
-    CHIP_ERROR ret;
-
     LOG_INF("Current Software Version: %u, %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION,
             CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING);
 
@@ -145,23 +139,39 @@
     uint8_t maxLightLevel = kDefaultMaxLevel;
     Clusters::LevelControl::Attributes::MaxLevel::Get(1, &maxLightLevel);
 
-    ret = LightingMgr().Init(LIGHTING_PWM_DEVICE, LIGHTING_PWM_CHANNEL, minLightLevel, maxLightLevel, maxLightLevel);
-    if (ret != CHIP_NO_ERROR)
+    CHIP_ERROR err = LightingMgr().Init(LIGHTING_PWM_DEVICE, LIGHTING_PWM_CHANNEL, minLightLevel, maxLightLevel, maxLightLevel);
+    if (err != CHIP_NO_ERROR)
     {
         LOG_ERR("Failed to int lighting manager");
-        return ret;
+        return err;
     }
     LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted);
 
-    // Init ZCL Data Model and start server
-    static chip::CommonCaseDeviceServerInitParams initParams;
-    (void) initParams.InitializeStaticResourcesBeforeServerInit();
-    chip::Server::GetInstance().Init(initParams);
-
-    // Initialize device attestation config
+    // Initialize CHIP server
+#if CONFIG_CHIP_FACTORY_DATA
+    ReturnErrorOnFailure(mFactoryDataProvider.Init());
+    SetDeviceInstanceInfoProvider(&mFactoryDataProvider);
+    SetDeviceAttestationCredentialsProvider(&mFactoryDataProvider);
+    SetCommissionableDataProvider(&mFactoryDataProvider);
+    // Read EnableKey from the factory data.
+    MutableByteSpan enableKey(sTestEventTriggerEnableKey);
+    err = mFactoryDataProvider.GetEnableKey(enableKey);
+    if (err != CHIP_NO_ERROR)
+    {
+        LOG_ERR("mFactoryDataProvider.GetEnableKey() failed. Could not delegate a test event trigger");
+        memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey));
+    }
+#else
     SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());
+#endif
 
-    gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage());
+    static CommonCaseDeviceServerInitParams initParams;
+    // static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) };
+    (void) initParams.InitializeStaticResourcesBeforeServerInit();
+    // initParams.testEventTriggerDelegate = &testEventTriggerDelegate;
+    ReturnErrorOnFailure(chip::Server::GetInstance().Init(initParams));
+
+    gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage());
     chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
 
 #if CONFIG_CHIP_OTA_REQUESTOR
@@ -176,14 +186,13 @@
     // between the main and the CHIP threads.
     PlatformMgr().AddEventHandler(ChipEventHandler, 0);
 
-    ret = ConnectivityMgr().SetBLEDeviceName("TelinkLight");
-    if (ret != CHIP_NO_ERROR)
+    err = ConnectivityMgr().SetBLEDeviceName("TelinkLight");
+    if (err != CHIP_NO_ERROR)
     {
         LOG_ERR("Fail to set BLE device name");
-        return ret;
     }
 
-    return CHIP_NO_ERROR;
+    return err;
 }
 
 CHIP_ERROR AppTask::StartApp()
@@ -274,7 +283,7 @@
     if (!chip::DeviceLayer::ConnectivityMgr().IsThreadProvisioned())
     {
         // Switch context from BLE to Thread
-        BLEManagerImpl sInstance;
+        Internal::BLEManagerImpl sInstance;
         sInstance.SwitchToIeee802154();
         StartDefaultThreadNetwork();
         LOG_INF("Device is not commissioned to a Thread network. Starting with the default configuration.");
diff --git a/integrations/cloudbuild/build-all.yaml b/integrations/cloudbuild/build-all.yaml
index 17c343b..e0dbcfa 100644
--- a/integrations/cloudbuild/build-all.yaml
+++ b/integrations/cloudbuild/build-all.yaml
@@ -6,7 +6,7 @@
           - "--init"
           - "--recursive"
       id: Submodules
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
@@ -21,7 +21,7 @@
             path: /pwenv
       timeout: 900s
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
diff --git a/integrations/cloudbuild/chef.yaml b/integrations/cloudbuild/chef.yaml
index d8cf8c8..7abdf02 100644
--- a/integrations/cloudbuild/chef.yaml
+++ b/integrations/cloudbuild/chef.yaml
@@ -1,5 +1,5 @@
 steps:
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
@@ -12,7 +12,7 @@
             path: /pwenv
       timeout: 2700s
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
@@ -26,7 +26,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml
index 23cec5d..a5d4915 100644
--- a/integrations/cloudbuild/smoke-test.yaml
+++ b/integrations/cloudbuild/smoke-test.yaml
@@ -1,5 +1,5 @@
 steps:
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       entrypoint: "bash"
       args:
           - "-c"
@@ -7,7 +7,7 @@
               git config --global --add safe.directory "*"
               git submodule update --init --recursive
       id: Submodules
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
       args:
@@ -22,7 +22,7 @@
             path: /pwenv
       timeout: 900s
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       id: ESP32
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -41,7 +41,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       id: NRFConnect
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -62,7 +62,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       id: EFR32
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -84,7 +84,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       id: Linux
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
@@ -142,7 +142,7 @@
           - name: pwenv
             path: /pwenv
 
-    - name: "connectedhomeip/chip-build-vscode:0.6.05"
+    - name: "connectedhomeip/chip-build-vscode:0.6.06"
       id: Android
       env:
           - PW_ENVIRONMENT_ROOT=/pwenv
diff --git a/scripts/tools/telink/generate_telink_chip_factory_data.py b/scripts/tools/telink/generate_telink_chip_factory_data.py
new file mode 100644
index 0000000..2ec9b88
--- /dev/null
+++ b/scripts/tools/telink/generate_telink_chip_factory_data.py
@@ -0,0 +1,492 @@
+#!/usr/bin/env python3
+#
+#    Copyright (c) 2022 Project CHIP Authors
+#
+#    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.
+#
+
+from os.path import exists
+import os
+import sys
+import json
+import jsonschema
+import secrets
+import argparse
+import subprocess
+import logging as log
+import base64
+from collections import namedtuple
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives.serialization import load_der_private_key
+
+# A user can not change the factory data version and must be coherent with
+# the factory data version set in the Telink platform Kconfig file (CHIP_FACTORY_DATA_VERSION).
+FACTORY_DATA_VERSION = 1
+
+MATTER_ROOT = os.path.dirname(os.path.realpath(__file__))[:-len("/scripts/tools/telink")]
+HEX_PREFIX = "hex:"
+PUB_KEY_PREFIX = b'\x04'
+INVALID_PASSCODES = [00000000, 11111111, 22222222, 33333333, 44444444,
+                     55555555, 66666666, 77777777, 88888888, 99999999, 12345678, 87654321]
+
+
+def get_raw_private_key_der(der_file: str, password: str):
+    """ Split given der file to get separated key pair consisting of public and private keys.
+
+    Args:
+        der_file (str): Path to .der file containing public and private keys
+        password (str): Password to decrypt Keys. It can be None, and then KEY is not encrypted.
+
+    Returns:
+        hex string: return a hex string containing extracted and decrypted private KEY from given .der file.
+    """
+    try:
+        with open(der_file, 'rb') as file:
+            key_data = file.read()
+            if password is None:
+                log.warning("KEY password has not been provided. It means that DAC key is not encrypted.")
+            keys = load_der_private_key(key_data, password, backend=default_backend())
+            private_key = keys.private_numbers().private_value.to_bytes(32, byteorder='big')
+
+            return private_key
+
+    except IOError or ValueError:
+        return None
+
+
+def gen_test_certs(chip_cert_exe: str,
+                   output: str,
+                   vendor_id: int,
+                   product_id: int,
+                   device_name: str,
+                   generate_cd: bool = False,
+                   cd_type: int = 1,
+                   paa_cert_path: str = None,
+                   paa_key_path: str = None):
+    """
+    Generate Matter certificates according to given Vendor ID and Product ID using the chip-cert executable.
+    To use own Product Attestation Authority certificate provide paa_cert_path and paa_key_path arguments.
+    Without providing these arguments a PAA certificate will be get from /credentials/test/attestation directory
+    in the Matter repository.
+
+    Args:
+        chip_cert_exe (str): path to chip-cert executable
+        output (str): output path to store a newly generated certificates (CD, DAC, PAI)
+        vendor_id (int): an identification number specific to Vendor
+        product_id (int): an identification number specific to Product
+        device_name (str): human-readable device name
+        generate_cd (bool, optional): Generate Certificate Declaration and store it in thee output directory. Defaults to False.
+        paa_cert_path (str, optional): provide PAA certification path. Defaults to None - a path will be set to /credentials/test/attestation directory.
+        paa_key_path (str, optional): provide PAA key path. Defaults to None - a path will be set to /credentials/test/attestation directory.
+
+    Returns:
+        dictionary: ["PAI_CERT": (str)<path to PAI cert .der file>, 
+                     "DAC_CERT": (str)<path to DAC cert .der file>,
+                     "DAC_KEY": (str)<path to DAC key .der file>]
+    """
+
+    CD_PATH = MATTER_ROOT + "/credentials/test/certification-declaration/Chip-Test-CD-Signing-Cert.pem"
+    CD_KEY_PATH = MATTER_ROOT + "/credentials/test/certification-declaration/Chip-Test-CD-Signing-Key.pem"
+    PAA_PATH = paa_cert_path if paa_cert_path != None else MATTER_ROOT + "/credentials/test/attestation/Chip-Test-PAA-NoVID-Cert.pem"
+    PAA_KEY_PATH = paa_key_path if paa_key_path != None else MATTER_ROOT + "/credentials/test/attestation/Chip-Test-PAA-NoVID-Key.pem"
+
+    attestation_certs = namedtuple("attestation_certs", ["dac_cert", "dac_key", "pai_cert"])
+
+    log.info("Generating new certificates using chip-cert...")
+
+    if generate_cd:
+        # generate Certification Declaration
+        cmd = [chip_cert_exe, "gen-cd",
+               "--key", CD_KEY_PATH,
+               "--cert", CD_PATH,
+               "--out", output + "/CD.der",
+               "--format-version",  "1",
+               "--vendor-id",  hex(vendor_id),
+               "--product-id",  hex(product_id),
+               "--device-type-id", "0",
+               "--certificate-id", "FFFFFFFFFFFFFFFFFFF",
+               "--security-level",  "0",
+               "--security-info",  "0",
+               "--certification-type",  str(cd_type),
+               "--version-number", "0xFFFF",
+               ]
+        subprocess.run(cmd)
+
+    new_certificates = {"PAI_CERT": output + "/PAI_cert",
+                        "PAI_KEY": output + "/PAI_key",
+                        "DAC_CERT": output + "/DAC_cert",
+                        "DAC_KEY": output + "/DAC_key"
+                        }
+
+    # generate PAI
+    cmd = [chip_cert_exe, "gen-att-cert",
+           "-t", "i",
+           "-c", device_name,
+           "-V", hex(vendor_id),
+           "-C", PAA_PATH,
+           "-K", PAA_KEY_PATH,
+           "-o", new_certificates["PAI_CERT"] + ".pem",
+           "-O", new_certificates["PAI_KEY"] + ".pem",
+           "-l", str(10000),
+           ]
+    subprocess.run(cmd)
+
+    # generate DAC
+    cmd = [chip_cert_exe, "gen-att-cert",
+           "-t", "d",
+           "-c", device_name,
+           "-V", hex(vendor_id),
+           "-P", hex(product_id),
+           "-C", new_certificates["PAI_CERT"] + ".pem",
+           "-K", new_certificates["PAI_KEY"] + ".pem",
+           "-o", new_certificates["DAC_CERT"] + ".pem",
+           "-O", new_certificates["DAC_KEY"] + ".pem",
+           "-l", str(10000),
+           ]
+    subprocess.run(cmd)
+
+    # convert to .der files
+    for cert_k, cert_v in new_certificates.items():
+        action_type = "convert-cert" if cert_k.find("CERT") != -1 else "convert-key"
+        log.info(cert_v + ".der")
+        cmd = [chip_cert_exe, action_type,
+               cert_v + ".pem",
+               cert_v + ".der",
+               "--x509-der",
+               ]
+        subprocess.run(cmd)
+
+    return attestation_certs(new_certificates["DAC_CERT"] + ".der",
+                             new_certificates["DAC_KEY"] + ".der",
+                             new_certificates["PAI_CERT"] + ".der")
+
+
+def gen_spake2p_params(spake2p_path: str, passcode: int, it: int, salt: bytes) -> dict:
+    """ Generate Spake2+ params using external spake2p tool
+
+    Args:
+        spake2p_path (str): path to spake2p executable
+        passcode (int): Pairing passcode using in Spake2+
+        it (int): Iteration counter for Spake2+ verifier generation
+        salt (str): Salt used to generate Spake2+ verifier
+
+    Returns:
+        dict: dictionary containing passcode, it, salt, and generated Verifier
+    """
+
+    cmd = [
+        spake2p_path, 'gen-verifier',
+        '--iteration-count', str(it),
+        '--salt', base64.b64encode(salt),
+        '--pin-code', str(passcode),
+        '--out', '-',
+    ]
+    output = subprocess.check_output(cmd)
+    output = output.decode('utf-8').splitlines()
+    return dict(zip(output[0].split(','), output[1].split(',')))
+
+
+class FactoryDataGenerator:
+    """
+    Class to generate factory data from given arguments and generate a JSON file
+
+    """
+
+    def __init__(self, arguments) -> None:
+        """
+        Args:
+            arguments (any):All input arguments parsed using ArgParse
+        """
+        self._args = arguments
+        self._factory_data = list()
+        self._user_data = dict()
+
+        try:
+            self._validate_args()
+        except AssertionError as e:
+            log.error(e)
+            sys.exit(-1)
+
+    def _validate_args(self):
+        if self._args.user:
+            try:
+                self._user_data = json.loads(self._args.user)
+            except json.decoder.JSONDecodeError as e:
+                raise AssertionError("Provided wrong user data, this is not a JSON format! {}".format(e))
+        assert (self._args.spake2_verifier or (self._args.passcode and self._args.spake2p_path)), \
+            "Cannot find Spake2+ verifier, to generate a new one please provide passcode (--passcode) and path to spake2p tool (--spake2p_path)"
+        assert (self._args.chip_cert_path or (self._args.dac_cert and self._args.pai_cert and self._args.dac_key)), \
+            "Cannot find paths to DAC or PAI certificates .der files. To generate a new ones please provide a path to chip-cert executable (--chip_cert_path)"
+        assert self._args.output.endswith(".json"), \
+            "Output path doesn't contain .json file path. ({})".format(self._args.output)
+        assert not (self._args.passcode in INVALID_PASSCODES), \
+            "Provided invalid passcode!"
+
+    def generate_json(self):
+        """
+        This function generates JSON data, .json file and validates it.
+
+        To validate generated JSON data a scheme must be provided within script's arguments.
+
+        - In the first part, if the rotating device id unique id has been not provided
+          as an argument, it will be created.
+        - If user-provided passcode and Spake2+ verifier have been not provided
+          as an argument, it will be created using an external script
+        - Passcode is not stored in JSON by default. To store it for debugging purposes, add --include_passcode argument.
+        - Validating output JSON is not mandatory, but highly recommended.
+
+        """
+        # generate missing data if needed
+        if not self._args.rd_uid:
+            if self._args.generate_rd_uid:
+                rd_uid = self._generate_rotating_device_uid()
+            else:
+                # rotating device ID unique ID was not provided, so do not store it in factory data.
+                rd_uid = None
+        else:
+            rd_uid = HEX_PREFIX + self._args.rd_uid
+
+        if not self._args.spake2_verifier:
+            spake_2_verifier = self._generate_spake2_verifier()
+        else:
+            spake_2_verifier = self._args.spake2_verifier
+
+        # convert salt to bytestring to be coherent with Spake2+ verifier type
+        spake_2_salt = self._args.spake2_salt
+
+        if self._args.chip_cert_path:
+            certs = gen_test_certs(self._args.chip_cert_path,
+                                   self._args.output[:self._args.output.rfind("/")],
+                                   self._args.vendor_id,
+                                   self._args.product_id,
+                                   self._args.vendor_name + "_" + self._args.product_name,
+                                   self._args.gen_cd,
+                                   self._args.cd_type,
+                                   self._args.paa_cert,
+                                   self._args.paa_key)
+            dac_cert = certs.dac_cert
+            pai_cert = certs.pai_cert
+            dac_key = certs.dac_key
+        else:
+            dac_cert = self._args.dac_cert
+            dac_key = self._args.dac_key
+            pai_cert = self._args.pai_cert
+
+        # try to read DAC public and private keys
+        dac_priv_key = get_raw_private_key_der(dac_key, self._args.dac_key_password)
+        if dac_priv_key is None:
+            log.error("Cannot read DAC keys from : {}".format(dac_key))
+            sys.exit(-1)
+
+        try:
+            json_file = open(self._args.output, "w+")
+        except FileNotFoundError:
+            print("Cannot create JSON file in this location: {}".format(self._args.output))
+            sys.exit(-1)
+        with json_file:
+            # serialize data
+            self._add_entry("version", FACTORY_DATA_VERSION)
+            self._add_entry("sn", self._args.sn)
+            self._add_entry("vendor_id", self._args.vendor_id)
+            self._add_entry("product_id", self._args.product_id)
+            self._add_entry("vendor_name", self._args.vendor_name)
+            self._add_entry("product_name", self._args.product_name)
+            self._add_entry("date", self._args.date)
+            self._add_entry("hw_ver", self._args.hw_ver)
+            self._add_entry("hw_ver_str", self._args.hw_ver_str)
+            self._add_entry("dac_cert", self._process_der(dac_cert))
+            self._add_entry("dac_key", dac_priv_key)
+            self._add_entry("pai_cert", self._process_der(pai_cert))
+            if self._args.include_passcode:
+                self._add_entry("passcode", self._args.passcode)
+            self._add_entry("spake2_it", self._args.spake2_it)
+            self._add_entry("spake2_salt", spake_2_salt)
+            self._add_entry("spake2_verifier", spake_2_verifier)
+            self._add_entry("discriminator", self._args.discriminator)
+            if rd_uid:
+                self._add_entry("rd_uid", rd_uid)
+            if self._args.enable_key:
+                self._add_entry("enable_key", HEX_PREFIX + self._args.enable_key)
+            if self._args.user:
+                self._add_entry("user", self._args.user)
+
+            factory_data_dict = dict(self._factory_data)
+
+            json_object = json.dumps(factory_data_dict)
+            is_json_valid = True
+
+            if self._args.schema:
+                is_json_valid = self._validate_output_json(json_object)
+            else:
+                log.warning("JSON Schema file has not been provided, the output file can be wrong. Be aware of that.")
+            try:
+                if is_json_valid:
+                    json_file.write(json_object)
+            except IOError as e:
+                log.error("Cannot save output file into directory: {}".format(self._args.output))
+
+    def _add_entry(self, name: str, value: any):
+        """ Add single entry to list of tuples ("key", "value") """
+        if(isinstance(value, bytes) or isinstance(value, bytearray)):
+            value = HEX_PREFIX + value.hex()
+        if value or (isinstance(value, int) and value == 0):
+            log.debug("Adding entry '{}' with size {} and type {}".format(name, sys.getsizeof(value), type(value)))
+            self._factory_data.append((name, value))
+
+    def _generate_spake2_verifier(self):
+        """ If verifier has not been provided in arguments list it should be generated via external script """
+        spake2_params = gen_spake2p_params(self._args.spake2p_path, self._args.passcode,
+                                           self._args.spake2_it, self._args.spake2_salt)
+        return base64.b64decode(spake2_params["Verifier"])
+
+    def _generate_rotating_device_uid(self):
+        """ If rotating device unique ID has not been provided it should be generated """
+        log.warning("Cannot find rotating device UID in provided arguments list. A new one will be generated.")
+        rdu = secrets.token_bytes(16)
+        log.info("\n\nThe new rotate device UID: {}\n".format(rdu.hex()))
+        return rdu
+
+    def _validate_output_json(self, output_json: str):
+        """
+        Validate output JSON data with provided .scheme file
+        This function will raise error if JSON does not match schema.
+
+        """
+        try:
+            with open(self._args.schema) as schema_file:
+                log.info("Validating JSON with schema...")
+                schema = json.loads(schema_file.read())
+                validator = jsonschema.Draft202012Validator(schema=schema)
+                validator.validate(instance=json.loads(output_json))
+        except IOError as e:
+            log.error("Provided JSON schema file is wrong: {}".format(self._args.schema))
+            return False
+        else:
+            log.info("Validate OK")
+            return True
+
+    def _process_der(self, path: str):
+        log.debug("Processing der file...")
+        try:
+            with open(path, 'rb') as f:
+                data = f.read()
+                return data
+        except IOError as e:
+            log.error(e)
+            raise e
+
+
+def main():
+    parser = argparse.ArgumentParser(description="Telink Factory Data NVS generator tool")
+
+    def allow_any_int(i): return int(i, 0)
+    def base64_str(s): return base64.b64decode(s)
+
+    mandatory_arguments = parser.add_argument_group("Mandatory keys", "These arguments must be provided to generate JSON file")
+    optional_arguments = parser.add_argument_group(
+        "Optional keys", "These arguments are optional and they depend on the user-purpose")
+    parser.add_argument("-s", "--schema", type=str,
+                        help="JSON schema file to validate JSON output data")
+    parser.add_argument("-o", "--output", type=str, required=True,
+                        help="Output path to store .json file, e.g. my_dir/output.json")
+    parser.add_argument("-v", "--verbose", action="store_true",
+                        help="Run this script with DEBUG logging level")
+    parser.add_argument("--include_passcode", action="store_true",
+                        help="Include passcode in factory data. By default, it is used only for generating Spake2+ verifier.")
+    parser.add_argument("--overwrite", action="store_true",
+                        help="If output JSON file exist this argument allows to generate new factory data and overwrite it.")
+    # Json known-keys values
+    # mandatory keys
+    mandatory_arguments.add_argument("--sn", type=str, required=True,
+                                     help="[ascii string] Serial number of a device which can be used to identify \
+	                                        the serial number field in the Matter certificate structure. \
+	                                        Maximum length of serial number is 20 bytes. \
+	                                        Strings longer than 20 bytes will be declined in script")
+    mandatory_arguments.add_argument("--vendor_id", type=allow_any_int,
+                                     help="[int | hex int] Provide Vendor Identification Number")
+    mandatory_arguments.add_argument("--product_id", type=allow_any_int,
+                                     help="[int | hex int] Provide Product Identification Number")
+    mandatory_arguments.add_argument("--vendor_name", type=str,
+                                     help="[string] provide human-readable vendor name")
+    mandatory_arguments.add_argument("--product_name", type=str,
+                                     help="[string] provide human-readable product name")
+    mandatory_arguments.add_argument("--date", type=str, required=True,
+                                     help="[ascii string] Provide manufacturing date \
+                                            A manufacturing date specifies the date that the Node was manufactured. \
+	                                        Used format for providing a manufacturing date is ISO 8601 e.g. YYYY-MM-DD.")
+    mandatory_arguments.add_argument("--hw_ver", type=allow_any_int, required=True,
+                                     help="[int | hex int] Provide hardware version in int format.")
+    mandatory_arguments.add_argument("--hw_ver_str", type=str, required=True,
+                                     help="[ascii string] Provide hardware version in string format.")
+    mandatory_arguments.add_argument("--spake2_it", type=allow_any_int, required=True,
+                                     help="[int | hex int] Provide Spake2+ iteration count.")
+    mandatory_arguments.add_argument("--spake2_salt", type=base64_str, required=True,
+                                     help="[base64 string] Provide Spake2+ salt.")
+    mandatory_arguments.add_argument("--discriminator", type=allow_any_int, required=True,
+                                     help="[int] Provide BLE pairing discriminator. \
+                                     A 12-bit value matching the field of the same name in \
+                                     the setup code. Discriminator is used during a discovery process.")
+
+    # optional keys
+    optional_arguments.add_argument("--chip_cert_path", type=str,
+                                    help="Generate DAC and PAI certificates instead giving a path to .der files. This option requires a path to chip-cert executable."
+                                    "By default You can find spake2p in connectedhomeip/src/tools/chip-cert directory and build it there.")
+    optional_arguments.add_argument("--dac_cert", type=str,
+                                    help="[.der] Provide the path to .der file containing DAC certificate.")
+    optional_arguments.add_argument("--dac_key", type=str,
+                                    help="[.der] Provide the path to .der file containing DAC keys.")
+    optional_arguments.add_argument("--generate_rd_uid", action="store_true",
+                                    help="Generate a new rotating device unique ID, print it out to console output and store it in factory data.")
+    optional_arguments.add_argument("--dac_key_password", type=str,
+                                    help="Provide a password to decode dac key. If dac key is not encrypted do not provide this argument.")
+    optional_arguments.add_argument("--pai_cert", type=str,
+                                    help="[.der] Provide the path to .der file containing PAI certificate.")
+    optional_arguments.add_argument("--rd_uid", type=str,
+                                    help="[hex string] [128-bit hex-encoded] Provide the rotating device unique ID. If this argument is not provided a new rotating device id unique id will be generated.")
+    optional_arguments.add_argument("--passcode", type=allow_any_int,
+                                    help="[int | hex] Default PASE session passcode. (This is mandatory to generate Spake2+ verifier).")
+    optional_arguments.add_argument("--spake2p_path", type=str,
+                                    help="[string] Provide a path to spake2p. By default You can find spake2p in connectedhomeip/src/tools/spake2p directory and build it there.")
+    optional_arguments.add_argument("--spake2_verifier", type=base64_str,
+                                    help="[base64 string] Provide Spake2+ verifier without generating it.")
+    optional_arguments.add_argument("--enable_key", type=str,
+                                    help="[hex string] [128-bit hex-encoded] The Enable Key is a 128-bit value that triggers manufacturer-specific action while invoking the TestEventTrigger Command."
+                                    "This value is used during Certification Tests, and should not be present on production devices.")
+    optional_arguments.add_argument("--user", type=str,
+                                    help="[string] Provide additional user-specific keys in JSON format: {'name_1': 'value_1', 'name_2': 'value_2', ... 'name_n', 'value_n'}.")
+    optional_arguments.add_argument("--gen_cd", action="store_true", default=False,
+                                    help="Generate a new Certificate Declaration in .der format according to used Vendor ID and Product ID. This certificate will not be included to the factory data.")
+    optional_arguments.add_argument("--cd_type", type=int, default=1,
+                                    help="[int] Type of generated Certification Declaration: 0 - development, 1 - provisional, 2 - official")
+    optional_arguments.add_argument("--paa_cert", type=str,
+                                    help="Provide a path to the Product Attestation Authority (PAA) certificate to generate the PAI certificate. Without providing it, a testing PAA stored in the Matter repository will be used.")
+    optional_arguments.add_argument("--paa_key", type=str,
+                                    help="Provide a path to the Product Attestation Authority (PAA) key to generate the PAI certificate. Without providing it, a testing PAA key stored in the Matter repository will be used.")
+    args = parser.parse_args()
+
+    if args.verbose:
+        log.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', level=log.DEBUG)
+    else:
+        log.basicConfig(format='[%(levelname)s] %(message)s', level=log.INFO)
+
+    # check if json file already exist
+    if(exists(args.output) and not args.overwrite):
+        log.error("Output file: {} already exist, to create a new one add argument '--overwrite'. By default overwriting is disabled".format(args.output))
+        return
+
+    generator = FactoryDataGenerator(args)
+    generator.generate_json()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/tools/telink/telink_factory_data.schema b/scripts/tools/telink/telink_factory_data.schema
new file mode 100644
index 0000000..16ffcc6
--- /dev/null
+++ b/scripts/tools/telink/telink_factory_data.schema
@@ -0,0 +1,147 @@
+{
+    "$id": "Telink_Factory_Data_schema",
+    "$schema": "https://json-schema.org/draft/2020-12/schema",
+    "description": "A representation of all factory data used in Matter's Telink device",
+    "type": "object",
+    "required": [
+        "version",
+        "sn",
+        "vendor_id",
+        "product_id",
+        "vendor_name",
+        "product_name",
+        "date",
+        "hw_ver",
+        "hw_ver_str",
+        "dac_cert",
+        "dac_key",
+        "pai_cert",
+        "spake2_it",
+        "spake2_salt",
+        "spake2_verifier",
+        "discriminator"
+    ],
+    "properties": {
+        "version": {
+            "description": "Current version of the factory data set",
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 255
+        },
+        "sn": {
+            "description": "Serial number of device",
+            "type": "string",
+            "maxLength": 32
+        },
+        "vendor_id": {
+            "description": "Vendor Identifier",
+            "type": "integer",
+            "minimum": 0,
+            "maximum":  65524
+        },
+        "product_id": {
+            "description": "Product Identifier",
+            "type": "integer",
+            "minimum": 1, 
+            "maximum":  65535
+        },
+        "vendor_name": {
+            "description": "human-readable vendor name",
+            "type": "string",
+            "maxLength": 32
+        },
+        "product_name": {
+            "description": "human-readable product name",
+            "type": "string",
+            "maxLength": 32
+        },
+        "date": {
+            "description": "Manufacturing date according to ISO 8601 in notation YYYY-MM-DD",
+            "type": "string",
+            "format": "date"
+        },
+        "hw_ver": {
+            "description": "Hardware version - integer",
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 65536
+        },
+        "hw_ver_str": {
+            "description": "A string representation of hardware version",
+            "type": "string",
+            "minLength": 1,
+            "maxLength": 64
+        },
+        "rd_uid": {
+            "description": "A randomly-generated 128-bit or longer octet string. Length has been expanded with 'hex:' prefix",
+            "type": "string",
+            "pattern:": "^hex:{1}",
+            "minLength": 20,
+            "minLength": 5,
+            "maxLength": 36
+        },
+        "dac_cert": {
+            "description": "DAC certificate in hex-string format",
+            "type": "string",
+            "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}",
+            "minLength": 5,
+            "maxLength": 1204
+        },
+        "dac_key": {
+            "description": "DAC Private Key in hex-string format",
+            "type": "string",
+            "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}",
+            "minLength": 68,
+            "maxLength": 68
+        },
+        "pai_cert": {
+            "description": "PAI certificate in hex-string format",
+            "type": "string",
+            "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}",
+            "minLength": 5,
+            "maxLength": 1204
+        },
+        "passcode": {
+            "description": "A default PASE session passcode",
+            "type": "integer",
+            "minimum": 1,
+            "maximum": 99999998
+        },
+        "spake2_it": {
+            "description": "An Iteration counter for the Symmetric Password-Authenticated Key Exchange",
+            "type": "integer",
+            "minimum": 1000,
+            "maximum": 100000
+        },
+        "spake2_salt": {
+            "description": "A key-derivation function for the Symmetric Password-Authenticated Key Exchange.",
+            "type": "string",
+            "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}",
+            "minLength": 36,
+            "maxLength": 68
+        },
+        "spake2_verifier": {
+            "description": "A verifier for the Symmetric Password-Authenticated Key Exchange",
+            "type": "string",
+            "pattern:": "^hex:{1}([0-9A-Fa-f]){2,}",
+            "minLength": 97
+        },
+        "discriminator": {
+            "description": "The Discriminator value helps to further identify potential devices during the setup process.",
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 4095
+        },
+        "enable_key": {
+            "description": "The Enable Key is a 128-bit value that triggers manufacturer-specific action while invoking the TestEventTrigger Command",
+            "type": "string",
+            "pattern": "^hex:{1}([0-9A-Fa-f]){32}",
+            "minLength": 36, 
+            "maxLength": 36
+        },
+        "user": {
+            "description": "A user-specific additional data which should be added to factory data. This should be a Json format.",
+            "type": "object"
+        }
+    }
+}
\ No newline at end of file
diff --git a/scripts/tools/telink/telink_generate_partition.py b/scripts/tools/telink/telink_generate_partition.py
new file mode 100644
index 0000000..ddd3b63
--- /dev/null
+++ b/scripts/tools/telink/telink_generate_partition.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+#
+#    Copyright (c) 2022 Project CHIP Authors
+#
+#    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.
+#
+
+import codecs
+import sys
+from intelhex import IntelHex
+import argparse
+import json
+import logging as log
+import cbor2 as cbor
+
+HEX_PREFIX = "hex:"
+
+
+class PartitionCreator:
+    """
+    Class to create telink partition containing FactoryData
+
+    :param offset: This is a partition offset where data will be stored in device's flash memory
+    :param length: This is a maximum partition size
+    :param input: This is a path to input JSON file
+    :param output: This is a path to output directory
+
+    """
+
+    def __init__(self, offset: int, length: int, input: str, output: str) -> None:
+        self._ih = IntelHex()
+        self._length = length
+        self._offset = offset
+        self._data_ready = False
+        self._output = output
+        self._input = input
+        try:
+            self.__data_to_save = self._convert_to_dict(self._load_json())
+        except IOError:
+            sys.exit(-1)
+
+    def generate_cbor(self):
+        """
+        Generates .cbor file using cbor2 library.
+        It generate a CBORTag 55799 which is user-specific tag
+
+        """
+        if self.__data_to_save:
+            # prepare raw data from Json
+            cbor_data = cbor.dumps(self.__data_to_save)
+            return cbor_data
+
+    def create_hex(self, data: bytes):
+        """
+        Creates .hex file from CBOR.
+        This file can be write directly to device.
+
+        """
+        if len(data) > self._length:
+            raise ValueError("generated CBOR file exceeds declared maximum partition size! {} > {}".format(len(data), self._length))
+        self._ih.putsz(self._offset, data)
+        self._ih.write_hex_file(self._output + ".hex", True)
+        self._data_ready = True
+        return True
+
+    def create_bin(self):
+        """
+        Creates raw binary data of created previously .hex file
+
+        """
+        if not self._data_ready:
+            log.error("Please create hex file first!")
+            return False
+        self._ih.tobinfile(self._output + ".bin")
+        return True
+
+    @staticmethod
+    def _convert_to_dict(data):
+        """
+        Converts a list containing tuples ("key_name", "key_value") to a dictionary
+
+        If "key_value" of data entry is a string-type variable and contains a HEX_PREFIX algorithm decodes it 
+        to hex format to be sure that a cbor file will contain proper bytes.
+
+        If "key_value" of data entry is a dictionary, algorithm appends it to the created dictionary.
+        """
+        output_dict = dict()
+        for entry in data:
+            if not isinstance(entry, dict):
+                log.debug("Processing entry {}".format(entry))
+                if isinstance(data[entry], str) and data[entry].startswith(HEX_PREFIX):
+                    output_dict[entry] = codecs.decode(data[entry][len(HEX_PREFIX):], "hex")
+                elif isinstance(data[entry], str):
+                    output_dict[entry] = data[entry].encode("utf-8")
+                else:
+                    output_dict[entry] = data[entry]
+            else:
+                output_dict[entry] = entry
+        return output_dict
+
+    def _load_json(self):
+        """
+        Loads file containing a JSON data and converts it to JSON format
+
+        :raises IOError: if provided JSON file can not be read out.
+        """
+        try:
+            with open(self._input, "rb") as json_file:
+                return json.loads(json_file.read())
+        except IOError as e:
+            log.error("Can not read Json file {}".format(self._input))
+            raise e
+
+
+def print_flashing_help():
+    print("\nTo flash the generated hex/bin containing factory data, use BDT tool")
+
+
+def main():
+
+    def allow_any_int(i): return int(i, 0)
+
+    parser = argparse.ArgumentParser(description="Telink Factory Data NVS partition generator tool")
+    parser.add_argument("-i", "--input", type=str, required=True,
+                        help="Path to input .json file")
+    parser.add_argument("-o", "--output", type=str, required=True,
+                        help="Prefix for output file paths, e.g. setting dir/output causes creation of the following files: dir/output.hex, and dir/output.bin")
+    parser.add_argument("--offset", type=allow_any_int, required=True,
+                        help="Partition offset - an address in device's NVM memory, where factory data will be stored")
+    parser.add_argument("--size", type=allow_any_int, required=True,
+                        help="The maximum partition size")
+    parser.add_argument("-v", "--verbose", action="store_true",
+                        help="Run this script with DEBUG logging level")
+    parser.add_argument("-r", "--raw", action="store_true",
+                        help="Do not print flashing help and other logs, only generate a .hex file. It can be useful when the script is used by other script.")
+    args = parser.parse_args()
+
+    if args.verbose:
+        log.basicConfig(format='[%(asctime)s][%(levelname)s] %(message)s', level=log.DEBUG)
+    elif args.raw:
+        log.basicConfig(format='%(message)s', level=log.ERROR)
+    else:
+        log.basicConfig(format='[%(asctime)s] %(message)s', level=log.INFO)
+
+    partition_creator = PartitionCreator(args.offset, args.size, args.input, args.output)
+    cbor_data = partition_creator.generate_cbor()
+    try:
+        if not args.raw:
+            print("Generating .hex file: {}.hex with offset: {} and size: {}".format(args.output, hex(args.offset), hex(args.size)))
+        if partition_creator.create_hex(cbor_data) and partition_creator.create_bin():
+            if not args.raw:
+                print_flashing_help()
+    except ValueError as e:
+        log.error(e)
+        sys.exit(-1)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/src/platform/telink/BUILD.gn b/src/platform/telink/BUILD.gn
index d5644b0..b13a9d1 100644
--- a/src/platform/telink/BUILD.gn
+++ b/src/platform/telink/BUILD.gn
@@ -16,6 +16,7 @@
 import("//build_overrides/telink.gni")
 
 import("${chip_root}/src/platform/device.gni")
+import("${chip_root}/src/platform/telink/args.gni")
 
 assert(chip_device_platform == "telink")
 
@@ -48,11 +49,26 @@
 
   deps = []
 
+  public = [
+    "${chip_root}/src/credentials/CHIPCert.h",
+    "${chip_root}/src/credentials/CertificationDeclaration.h",
+    "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h",
+  ]
+
   public_deps = [
     "${chip_root}/src/platform:platform_base",
     "${telink_sdk_build_root}",
   ]
 
+  if (chip_enable_factory_data) {
+    sources += [
+      "FactoryDataParser.c",
+      "FactoryDataParser.h",
+      "FactoryDataProvider.cpp",
+      "FactoryDataProvider.h",
+    ]
+  }
+
   if (chip_enable_openthread) {
     sources += [
       "../OpenThread/OpenThreadUtils.cpp",
diff --git a/src/platform/telink/CHIPDevicePlatformConfig.h b/src/platform/telink/CHIPDevicePlatformConfig.h
index 8241a10..4f45252 100644
--- a/src/platform/telink/CHIPDevicePlatformConfig.h
+++ b/src/platform/telink/CHIPDevicePlatformConfig.h
@@ -1,6 +1,6 @@
 /*
  *
- *    Copyright (c) 2021 Project CHIP Authors
+ *    Copyright (c) 2022 Project CHIP Authors
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -27,6 +27,42 @@
 
 // ==================== Platform Adaptations ====================
 
+#ifndef CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER
+#define CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER CONFIG_CHIP_DEVICE_SERIAL_NUMBER
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE
+#define CHIP_DEVICE_CONFIG_TEST_MANUFACTURING_DATE CONFIG_CHIP_DEVICE_MANUFACTURING_DATE
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION
+#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION CONFIG_CHIP_DEVICE_HARDWARE_VERSION
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE CONFIG_CHIP_DEVICE_PAIRING_PASSCODE
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR
+#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR CONFIG_CHIP_DEVICE_DISCRIMINATOR
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING
+#define CHIP_DEVICE_CONFIG_DEFAULT_DEVICE_HARDWARE_VERSION_STRING CONFIG_CHIP_DEVICE_HARDWARE_VERSION_STRING
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT
+#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT CONFIG_CHIP_DEVICE_SPAKE2_IT
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT
+#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT CONFIG_CHIP_DEVICE_SPAKE2_SALT
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER
+#define CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER CONFIG_CHIP_DEVICE_SPAKE2_TEST_VERIFIER
+#endif
+
 #ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID
 #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID CONFIG_CHIP_DEVICE_VENDOR_ID
 #endif
@@ -35,8 +71,12 @@
 #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID CONFIG_CHIP_DEVICE_PRODUCT_ID
 #endif
 
-#ifdef CONFIG_CHIP_DEVICE_TYPE
-#define CHIP_DEVICE_CONFIG_DEVICE_TYPE CONFIG_CHIP_DEVICE_TYPE
+#ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME
+#define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME CONFIG_CHIP_DEVICE_VENDOR_NAME
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME
+#define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_NAME CONFIG_CHIP_DEVICE_PRODUCT_NAME
 #endif
 
 #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION
@@ -80,6 +120,58 @@
 #endif // !defined(CONFIG_CHIP_MALLOC_SYS_HEAP) && defined(CONFIG_NEWLIB_LIBC)
 #endif // CHIP_DEVICE_CONFIG_HEAP_STATISTICS_MALLINFO
 
+#ifndef CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION
+//-> format_version = 1
+//-> vendor_id = 0xFFF1
+//-> product_id_array = [ 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, 0x8005, 0x8006, 0x8007, 0x8008, 0x8009, 0x800A, 0x800B,
+// 0x800C, 0x800D, 0x800E, 0x800F, 0x8010, 0x8011, 0x8012, 0x8013, 0x8014, 0x8015, 0x8016, 0x8017, 0x8018, 0x8019, 0x801A,
+// 0x801B, 0x801C, 0x801D, 0x801E, 0x801F, 0x8020, 0x8021, 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x8027, 0x8028, 0x8029,
+// 0x802A, 0x802B, 0x802C, 0x802D, 0x802E, 0x802F, 0x8030, 0x8031, 0x8032, 0x8033, 0x8034, 0x8035, 0x8036, 0x8037, 0x8038,
+// 0x8039, 0x803A, 0x803B, 0x803C, 0x803D, 0x803E, 0x803F, 0x8040, 0x8041, 0x8042, 0x8043, 0x8044, 0x8045, 0x8046, 0x8047,
+// 0x8048, 0x8049, 0x804A, 0x804B, 0x804C, 0x804D, 0x804E, 0x804F, 0x8050, 0x8051, 0x8052, 0x8053, 0x8054, 0x8055, 0x8056,
+// 0x8057, 0x8058, 0x8059, 0x805A, 0x805B, 0x805C, 0x805D, 0x805E, 0x805F, 0x8060, 0x8061, 0x8062, 0x8063 ]
+//-> device_type_id = 0x0016
+//-> certificate_id = "ZIG20142ZB330003-24"
+//-> security_level = 0
+//-> security_information = 0
+//-> version_number = 0x2694
+//-> certification_type = 0
+//-> dac_origin_vendor_id is not present
+//-> dac_origin_product_id is not present
+#define CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION                                                                               \
+    {                                                                                                                              \
+        0x30, 0x82, 0x02, 0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x0a, 0x30,    \
+            0x82, 0x02, 0x06, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,      \
+            0x02, 0x01, 0x30, 0x82, 0x01, 0x71, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82,      \
+            0x01, 0x62, 0x04, 0x82, 0x01, 0x5e, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf1, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80,      \
+            0x05, 0x01, 0x80, 0x05, 0x02, 0x80, 0x05, 0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05,      \
+            0x07, 0x80, 0x05, 0x08, 0x80, 0x05, 0x09, 0x80, 0x05, 0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d,      \
+            0x80, 0x05, 0x0e, 0x80, 0x05, 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05, 0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80,      \
+            0x05, 0x14, 0x80, 0x05, 0x15, 0x80, 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05, 0x18, 0x80, 0x05, 0x19, 0x80, 0x05,      \
+            0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05, 0x1f, 0x80, 0x05, 0x20,      \
+            0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05, 0x26, 0x80,      \
+            0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05,      \
+            0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33,      \
+            0x80, 0x05, 0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80,      \
+            0x05, 0x3a, 0x80, 0x05, 0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05,      \
+            0x40, 0x80, 0x05, 0x41, 0x80, 0x05, 0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, 0x80, 0x05, 0x45, 0x80, 0x05, 0x46,      \
+            0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05, 0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, 0x4b, 0x80, 0x05, 0x4c, 0x80,      \
+            0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05, 0x50, 0x80, 0x05, 0x51, 0x80, 0x05, 0x52, 0x80, 0x05,      \
+            0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05, 0x57, 0x80, 0x05, 0x58, 0x80, 0x05, 0x59,      \
+            0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05, 0x5e, 0x80, 0x05, 0x5f, 0x80,      \
+            0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16, 0x2c, 0x04, 0x13,      \
+            0x5a, 0x49, 0x47, 0x32, 0x30, 0x31, 0x34, 0x32, 0x5a, 0x42, 0x33, 0x33, 0x30, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x34,      \
+            0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x25, 0x07, 0x94, 0x26, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7d, 0x30, 0x7b, 0x02,      \
+            0x01, 0x03, 0x80, 0x14, 0x62, 0xfa, 0x82, 0x33, 0x59, 0xac, 0xfa, 0xa9, 0x96, 0x3e, 0x1c, 0xfa, 0x14, 0x0a, 0xdd,      \
+            0xf5, 0x04, 0xf3, 0x71, 0x60, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30,      \
+            0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x24, 0xe5,      \
+            0xd1, 0xf4, 0x7a, 0x7d, 0x7b, 0x0d, 0x20, 0x6a, 0x26, 0xef, 0x69, 0x9b, 0x7c, 0x97, 0x57, 0xb7, 0x2d, 0x46, 0x90,      \
+            0x89, 0xde, 0x31, 0x92, 0xe6, 0x78, 0xc7, 0x45, 0xe7, 0xf6, 0x0c, 0x02, 0x21, 0x00, 0xf8, 0xaa, 0x2f, 0xa7, 0x11,      \
+            0xfc, 0xb7, 0x9b, 0x97, 0xe3, 0x97, 0xce, 0xda, 0x66, 0x7b, 0xae, 0x46, 0x4e, 0x2b, 0xd3, 0xff, 0xdf, 0xc3, 0xcc,      \
+            0xed, 0x7a, 0xa8, 0xca, 0x5f, 0x4c, 0x1a, 0x7c                                                                         \
+    }
+#endif
+
 // ========== Platform-specific Configuration Overrides =========
 
 #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY
@@ -111,3 +203,11 @@
 #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_COMMISSIONABLE_DISCOVERY 1
 #endif // CONFIG_CHIP_ENABLE_DNS_CLIENT
 #endif // CONFIG_CHIP_ENABLE_DNSSD_SRP
+
+#ifdef CONFIG_CHIP_DEVICE_TYPE
+#define CHIP_DEVICE_CONFIG_DEVICE_TYPE CONFIG_CHIP_DEVICE_TYPE
+#endif // CONFIG_CHIP_DEVICE_TYPE
+
+#ifdef CONFIG_CHIP_EXTENDED_DISCOVERY
+#define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1
+#endif // CONFIG_CHIP_EXTENDED_DISCOVERY
diff --git a/src/platform/telink/FactoryDataParser.c b/src/platform/telink/FactoryDataParser.c
new file mode 100644
index 0000000..e89cf3b
--- /dev/null
+++ b/src/platform/telink/FactoryDataParser.c
@@ -0,0 +1,167 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    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.
+ */
+
+#include "FactoryDataParser.h"
+
+#include <zcbor_decode.h>
+#include <zephyr/logging/log.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#define MAX_FACTORY_DATA_NESTING_LEVEL 3
+
+LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL);
+
+static inline bool uint16_decode(zcbor_state_t * states, uint16_t * value)
+{
+    uint32_t u32;
+
+    if (zcbor_uint32_decode(states, &u32))
+    {
+        *value = (uint16_t) u32;
+        return true;
+    }
+
+    return false;
+}
+
+bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData)
+{
+    memset(factoryData, 0, sizeof(*factoryData));
+    ZCBOR_STATE_D(states, MAX_FACTORY_DATA_NESTING_LEVEL, buffer, bufferSize, 1);
+
+    bool res = zcbor_map_start_decode(states);
+    struct zcbor_string currentString;
+
+    while (res)
+    {
+        res = zcbor_tstr_decode(states, &currentString);
+
+        if (!res)
+        {
+            res = true;
+            break;
+        }
+
+        if (strncmp("version", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && uint16_decode(states, &factoryData->version);
+        }
+        else if (strncmp("hw_ver", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res                       = res && uint16_decode(states, &factoryData->hw_ver);
+            factoryData->hwVerPresent = res;
+        }
+        else if (strncmp("spake2_it", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_uint32_decode(states, &factoryData->spake2_it);
+        }
+        else if (strncmp("vendor_id", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res                          = res && uint16_decode(states, &factoryData->vendor_id);
+            factoryData->vendorIdPresent = res;
+        }
+        else if (strncmp("product_id", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res                           = res && uint16_decode(states, &factoryData->product_id);
+            factoryData->productIdPresent = res;
+        }
+        else if (strncmp("discriminator", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res                               = res && uint16_decode(states, &factoryData->discriminator);
+            factoryData->discriminatorPresent = res;
+        }
+        else if (strncmp("passcode", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_uint32_decode(states, &factoryData->passcode);
+        }
+        else if (strncmp("sn", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->sn);
+        }
+        else if (strncmp("date", (const char *) currentString.value, currentString.len) == 0)
+        {
+            // Date format is YYYY-MM-DD, so format needs to be validated and string parse to integer parts.
+            struct zcbor_string date;
+            res = res && zcbor_bstr_decode(states, &date);
+            if (date.len == 10 && isdigit(date.value[0]) && isdigit(date.value[1]) && isdigit(date.value[2]) &&
+                isdigit(date.value[3]) && date.value[4] == '-' && isdigit(date.value[5]) && isdigit(date.value[6]) &&
+                date.value[7] == '-' && isdigit(date.value[8]) && isdigit(date.value[9]))
+            {
+                factoryData->date_year =
+                    1000 * (date.value[0] - '0') + 100 * (date.value[1] - '0') + 10 * (date.value[2] - '0') + date.value[3] - '0';
+                factoryData->date_month = 10 * (date.value[5] - '0') + date.value[6] - '0';
+                factoryData->date_day   = 10 * (date.value[8] - '0') + date.value[9] - '0';
+            }
+            else
+            {
+                LOG_ERR("Parsing error - wrong date format");
+            }
+        }
+        else if (strncmp("hw_ver_str", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->hw_ver_str);
+        }
+        else if (strncmp("rd_uid", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->rd_uid);
+        }
+        else if (strncmp("dac_cert", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_cert);
+        }
+        else if (strncmp("dac_key", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->dac_priv_key);
+        }
+        else if (strncmp("pai_cert", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->pai_cert);
+        }
+        else if (strncmp("spake2_salt", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_salt);
+        }
+        else if (strncmp("spake2_verifier", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->spake2_verifier);
+        }
+        else if (strncmp("vendor_name", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->vendor_name);
+        }
+        else if (strncmp("product_name", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->product_name);
+        }
+        else if (strncmp("enable_key", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->enable_key);
+        }
+        else if (strncmp("user", (const char *) currentString.value, currentString.len) == 0)
+        {
+            res = res && zcbor_bstr_decode(states, (struct zcbor_string *) &factoryData->user);
+        }
+        else
+        {
+            res = res && zcbor_any_skip(states, NULL);
+        }
+    }
+
+    return res && zcbor_list_map_end_force_decode(states);
+}
diff --git a/src/platform/telink/FactoryDataParser.h b/src/platform/telink/FactoryDataParser.h
new file mode 100644
index 0000000..156010a
--- /dev/null
+++ b/src/platform/telink/FactoryDataParser.h
@@ -0,0 +1,78 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct FactoryDataString
+{
+    void * data;
+    size_t len;
+};
+
+struct FactoryData
+{
+    uint16_t version;
+    struct FactoryDataString sn;
+    uint16_t date_year;
+    uint8_t date_month;
+    uint8_t date_day;
+    uint16_t vendor_id;
+    uint16_t product_id;
+    struct FactoryDataString vendor_name;
+    struct FactoryDataString product_name;
+    uint16_t hw_ver;
+    struct FactoryDataString hw_ver_str;
+    struct FactoryDataString rd_uid;
+    struct FactoryDataString dac_cert;
+    struct FactoryDataString dac_priv_key;
+    struct FactoryDataString pai_cert;
+    uint32_t spake2_it;
+    struct FactoryDataString spake2_salt;
+    struct FactoryDataString spake2_verifier;
+    uint16_t discriminator;
+    uint32_t passcode;
+    struct FactoryDataString enable_key;
+    struct FactoryDataString user;
+
+    bool vendorIdPresent;
+    bool productIdPresent;
+    bool hwVerPresent;
+    bool discriminatorPresent;
+};
+
+/**
+ * @brief Parses raw factory data into the factory data structure.
+ *
+ * @param[in] buffer Buffer containing raw factory data.
+ * @param[in] bufferSize Size of factory data.
+ * @param[out] factoryData address of object to be filled with parsed factory data.
+ *
+ * @returns true on success, false otherwise.
+ */
+bool ParseFactoryData(uint8_t * buffer, uint16_t bufferSize, struct FactoryData * factoryData);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/platform/telink/FactoryDataProvider.cpp b/src/platform/telink/FactoryDataProvider.cpp
new file mode 100644
index 0000000..3859227
--- /dev/null
+++ b/src/platform/telink/FactoryDataProvider.cpp
@@ -0,0 +1,341 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    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.
+ */
+
+#include "FactoryDataProvider.h"
+#include "CHIPDevicePlatformConfig.h"
+#include <crypto/CHIPCryptoPAL.h>
+
+#if CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE
+#include <credentials/CertificationDeclaration.h>
+#include <platform/Zephyr/ZephyrConfig.h>
+#endif
+
+#include <zephyr/logging/log.h>
+
+namespace chip {
+namespace {
+
+CHIP_ERROR LoadKeypairFromRaw(ByteSpan privateKey, ByteSpan publicKey, Crypto::P256Keypair & keypair)
+{
+    Crypto::P256SerializedKeypair serializedKeypair;
+    ReturnErrorOnFailure(serializedKeypair.SetLength(privateKey.size() + publicKey.size()));
+    memcpy(serializedKeypair.Bytes(), publicKey.data(), publicKey.size());
+    memcpy(serializedKeypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size());
+    return keypair.Deserialize(serializedKeypair);
+}
+} // namespace
+
+namespace DeviceLayer {
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::Init()
+{
+    uint8_t * factoryData = nullptr;
+    size_t factoryDataSize;
+
+    CHIP_ERROR error = mFlashFactoryData.ProtectFactoryDataPartitionAgainstWrite();
+
+    // Protection against write for external storage is not supported.
+    if (error == CHIP_ERROR_NOT_IMPLEMENTED)
+    {
+        ChipLogProgress(DeviceLayer, "The device does not support hardware protection against write.");
+        error = CHIP_NO_ERROR;
+    }
+    else if (error != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Failed to protect the factory data partition.");
+        return error;
+    }
+
+    error = mFlashFactoryData.GetFactoryDataPartition(factoryData, factoryDataSize);
+
+    if (error != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Failed to read factory data partition");
+        return error;
+    }
+
+    if (!ParseFactoryData(factoryData, factoryDataSize, &mFactoryData))
+    {
+        ChipLogError(DeviceLayer, "Failed to parse factory data");
+        return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
+    }
+
+    // Check if factory data version is correct
+    if (mFactoryData.version != CONFIG_CHIP_FACTORY_DATA_VERSION)
+    {
+        ChipLogError(DeviceLayer, "Factory data version mismatch. Flash version: %d vs code version: %d", mFactoryData.version,
+                     CONFIG_CHIP_FACTORY_DATA_VERSION);
+        return CHIP_ERROR_VERSION_MISMATCH;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetCertificationDeclaration(MutableByteSpan & outBuffer)
+{
+#if CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE
+    size_t cdLen = 0;
+
+    if (Internal::ZephyrConfig::ReadConfigValueBin(Internal::ZephyrConfig::kConfigKey_CertificationDeclaration,
+                                                   reinterpret_cast<uint8_t *>(outBuffer.data()), outBuffer.size(),
+                                                   cdLen) == CHIP_NO_ERROR)
+    {
+        outBuffer.reduce_size(cdLen);
+        return CHIP_NO_ERROR;
+    }
+#endif
+    constexpr uint8_t kCdForAllExamples[] = CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION;
+
+    return CopySpanToMutableSpan(ByteSpan{ kCdForAllExamples }, outBuffer);
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer)
+{
+    out_firmware_info_buffer.reduce_size(0);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetDeviceAttestationCert(MutableByteSpan & outBuffer)
+{
+    ReturnErrorCodeIf(outBuffer.size() < mFactoryData.dac_cert.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.dac_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(outBuffer.data(), mFactoryData.dac_cert.data, mFactoryData.dac_cert.len);
+
+    outBuffer.reduce_size(mFactoryData.dac_cert.len);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer)
+{
+    ReturnErrorCodeIf(outBuffer.size() < mFactoryData.pai_cert.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.pai_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(outBuffer.data(), mFactoryData.pai_cert.data, mFactoryData.pai_cert.len);
+
+    outBuffer.reduce_size(mFactoryData.pai_cert.len);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::SignWithDeviceAttestationKey(const ByteSpan & messageToSign,
+                                                                               MutableByteSpan & outSignBuffer)
+{
+    Crypto::P256ECDSASignature signature;
+    Crypto::P256Keypair keypair;
+
+    VerifyOrReturnError(outSignBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.dac_cert.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    ReturnErrorCodeIf(!mFactoryData.dac_priv_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    // Extract public key from DAC cert.
+    ByteSpan dacCertSpan{ reinterpret_cast<uint8_t *>(mFactoryData.dac_cert.data), mFactoryData.dac_cert.len };
+    chip::Crypto::P256PublicKey dacPublicKey;
+
+    ReturnErrorOnFailure(chip::Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey));
+    ReturnErrorOnFailure(
+        LoadKeypairFromRaw(ByteSpan(reinterpret_cast<uint8_t *>(mFactoryData.dac_priv_key.data), mFactoryData.dac_priv_key.len),
+                           ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair));
+    ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature));
+
+    return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer);
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSetupDiscriminator(uint16_t & setupDiscriminator)
+{
+    VerifyOrReturnError(mFactoryData.discriminatorPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    setupDiscriminator = mFactoryData.discriminator;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::SetSetupDiscriminator(uint16_t setupDiscriminator)
+{
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSpake2pIterationCount(uint32_t & iterationCount)
+{
+    ReturnErrorCodeIf(mFactoryData.spake2_it == 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    iterationCount = mFactoryData.spake2_it;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSpake2pSalt(MutableByteSpan & saltBuf)
+{
+    ReturnErrorCodeIf(saltBuf.size() < mFactoryData.spake2_salt.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.spake2_salt.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(saltBuf.data(), mFactoryData.spake2_salt.data, mFactoryData.spake2_salt.len);
+
+    saltBuf.reduce_size(mFactoryData.spake2_salt.len);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen)
+{
+    ReturnErrorCodeIf(verifierBuf.size() < mFactoryData.spake2_verifier.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.spake2_verifier.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(verifierBuf.data(), mFactoryData.spake2_verifier.data, mFactoryData.spake2_verifier.len);
+
+    verifierLen = mFactoryData.spake2_verifier.len;
+
+    verifierBuf.reduce_size(verifierLen);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSetupPasscode(uint32_t & setupPasscode)
+{
+    ReturnErrorCodeIf(mFactoryData.passcode == 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    setupPasscode = mFactoryData.passcode;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::SetSetupPasscode(uint32_t setupPasscode)
+{
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetVendorName(char * buf, size_t bufSize)
+{
+    ReturnErrorCodeIf(bufSize < mFactoryData.vendor_name.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.vendor_name.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(buf, mFactoryData.vendor_name.data, mFactoryData.vendor_name.len);
+    buf[mFactoryData.vendor_name.len] = 0;
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetVendorId(uint16_t & vendorId)
+{
+    VerifyOrReturnError(mFactoryData.vendorIdPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    vendorId = mFactoryData.vendor_id;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductName(char * buf, size_t bufSize)
+{
+    ReturnErrorCodeIf(bufSize < mFactoryData.product_name.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.product_name.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(buf, mFactoryData.product_name.data, mFactoryData.product_name.len);
+    buf[mFactoryData.product_name.len] = 0;
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetProductId(uint16_t & productId)
+{
+    VerifyOrReturnError(mFactoryData.productIdPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    productId = mFactoryData.product_id;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetSerialNumber(char * buf, size_t bufSize)
+{
+    ReturnErrorCodeIf(bufSize < mFactoryData.sn.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.sn.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(buf, mFactoryData.sn.data, mFactoryData.sn.len);
+    buf[mFactoryData.sn.len] = 0;
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day)
+{
+    VerifyOrReturnError(mFactoryData.date_year != 0, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    year  = mFactoryData.date_year;
+    month = mFactoryData.date_month;
+    day   = mFactoryData.date_day;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetHardwareVersion(uint16_t & hardwareVersion)
+{
+    VerifyOrReturnError(mFactoryData.hwVerPresent, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    hardwareVersion = mFactoryData.hw_ver;
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetHardwareVersionString(char * buf, size_t bufSize)
+{
+    ReturnErrorCodeIf(bufSize < mFactoryData.hw_ver_str.len + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.hw_ver_str.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(buf, mFactoryData.hw_ver_str.data, mFactoryData.hw_ver_str.len);
+    buf[mFactoryData.hw_ver_str.len] = 0;
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan)
+{
+    ReturnErrorCodeIf(uniqueIdSpan.size() < mFactoryData.rd_uid.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+    ReturnErrorCodeIf(!mFactoryData.rd_uid.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+
+    memcpy(uniqueIdSpan.data(), mFactoryData.rd_uid.data, mFactoryData.rd_uid.len);
+
+    return CHIP_NO_ERROR;
+}
+
+template <class FlashFactoryData>
+CHIP_ERROR FactoryDataProvider<FlashFactoryData>::GetEnableKey(MutableByteSpan & enableKey)
+{
+    ReturnErrorCodeIf(!mFactoryData.enable_key.data, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    ReturnErrorCodeIf(enableKey.size() < mFactoryData.enable_key.len, CHIP_ERROR_BUFFER_TOO_SMALL);
+
+    memcpy(enableKey.data(), mFactoryData.enable_key.data, mFactoryData.enable_key.len);
+
+    enableKey.reduce_size(mFactoryData.enable_key.len);
+
+    return CHIP_NO_ERROR;
+}
+
+// Fully instantiate the template class in whatever compilation unit includes this file.
+// template class FactoryDataProvider<InternalFlashFactoryData>;
+template class FactoryDataProvider<ExternalFlashFactoryData>;
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/telink/FactoryDataProvider.h b/src/platform/telink/FactoryDataProvider.h
new file mode 100644
index 0000000..79d34a6
--- /dev/null
+++ b/src/platform/telink/FactoryDataProvider.h
@@ -0,0 +1,117 @@
+/*
+ *
+ *    Copyright (c) 2022 Project CHIP Authors
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <credentials/DeviceAttestationCredsProvider.h>
+#include <platform/CommissionableDataProvider.h>
+#include <platform/DeviceInstanceInfoProvider.h>
+
+#include <system/SystemError.h>
+#include <zephyr/drivers/flash.h>
+#include <zephyr/storage/flash_map.h>
+
+#include "FactoryDataParser.h"
+
+namespace chip {
+namespace DeviceLayer {
+
+struct InternalFlashFactoryData
+{
+    CHIP_ERROR GetFactoryDataPartition(uint8_t *& data, size_t & dataSize)
+    {
+        data     = reinterpret_cast<uint8_t *>(FLASH_AREA_OFFSET(factory_data));
+        dataSize = FLASH_AREA_SIZE(factory_data);
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR ProtectFactoryDataPartitionAgainstWrite() { return CHIP_ERROR_NOT_IMPLEMENTED; }
+};
+
+struct ExternalFlashFactoryData
+{
+    CHIP_ERROR GetFactoryDataPartition(uint8_t *& data, size_t & dataSize)
+    {
+        int ret = flash_read(mFlashDevice, FLASH_AREA_OFFSET(factory_data), mFactoryDataBuffer, FLASH_AREA_SIZE(factory_data));
+
+        if (ret != 0)
+        {
+            return CHIP_ERROR_READ_FAILED;
+        }
+
+        data     = mFactoryDataBuffer;
+        dataSize = FLASH_AREA_SIZE(factory_data);
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR ProtectFactoryDataPartitionAgainstWrite() { return CHIP_ERROR_NOT_IMPLEMENTED; }
+
+    const struct device * mFlashDevice = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller));
+    uint8_t mFactoryDataBuffer[FLASH_AREA_SIZE(factory_data)];
+};
+
+template <class FlashFactoryData>
+class FactoryDataProvider : public chip::Credentials::DeviceAttestationCredentialsProvider,
+                            public CommissionableDataProvider,
+                            public DeviceInstanceInfoProvider
+{
+public:
+    CHIP_ERROR Init();
+
+    // ===== Members functions that implement the DeviceAttestationCredentialsProvider
+    CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & outBuffer) override;
+    CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override;
+    CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & outBuffer) override;
+    CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) override;
+    CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override;
+
+    // ===== Members functions that implement the CommissionableDataProvider
+    CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override;
+    CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override;
+    CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override;
+    CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override;
+    CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) override;
+    CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override;
+    CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override;
+
+    // ===== Members functions that implement the DeviceInstanceInfoProvider
+    CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override;
+    CHIP_ERROR GetVendorId(uint16_t & vendorId) override;
+    CHIP_ERROR GetProductName(char * buf, size_t bufSize) override;
+    CHIP_ERROR GetProductId(uint16_t & productId) override;
+    CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override;
+    CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override;
+    CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override;
+    CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override;
+    CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override;
+
+    // ===== Members functions that are platform-specific
+    CHIP_ERROR GetEnableKey(MutableByteSpan & enableKey);
+
+private:
+    static constexpr uint16_t kFactoryDataPartitionSize    = FLASH_AREA_SIZE(factory_data);
+    static constexpr uint32_t kFactoryDataPartitionAddress = FLASH_AREA_OFFSET(factory_data);
+    static constexpr uint8_t kDACPrivateKeyLength          = 32;
+    static constexpr uint8_t kDACPublicKeyLength           = 65;
+
+    struct FactoryData mFactoryData;
+    FlashFactoryData mFlashFactoryData;
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/telink/args.gni b/src/platform/telink/args.gni
index 1ff86d0..a830708 100644
--- a/src/platform/telink/args.gni
+++ b/src/platform/telink/args.gni
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Project CHIP Authors
+# Copyright (c) 2022 Project CHIP Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,3 +15,8 @@
 chip_device_platform = "telink"
 
 chip_inet_config_enable_ipv4 = false
+
+declare_args() {
+  # Enable factory data support
+  chip_enable_factory_data = false
+}
diff --git a/src/platform/telink/telink-mbedtls-config.h b/src/platform/telink/telink-mbedtls-config.h
index d0de1d1..0a37b4a 100644
--- a/src/platform/telink/telink-mbedtls-config.h
+++ b/src/platform/telink/telink-mbedtls-config.h
@@ -1,20 +1,25 @@
-/******************************************************************************
- * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
- * All rights reserved.
+/*
  *
- * 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
+ *    Copyright (c) 2022 Project CHIP Authors
  *
- *   http://www.apache.org/licenses/LICENSE-2.0
+ *    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
  *
- * 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.
+ *        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.
+ */
+
+/**
+ *    @file
+ *          Telink mbedtls configuration file.
+ *
+ */
 
 #ifndef MBEDTLS_TSLR9_CONF_H
 #define MBEDTLS_TSLR9_CONF_H