From 4dbf0af92d164dd23618f8585c6c52152a12055a Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 24 Jul 2024 14:20:04 +0200 Subject: [PATCH 01/18] west.yml: Update hal_ti Sync with simplelink_lpf3 support for cc23x0r5 SoC. Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 0c17ee71197d0..8f20001e358f4 100644 --- a/west.yml +++ b/west.yml @@ -253,7 +253,7 @@ manifest: groups: - hal - name: hal_ti - revision: 2e7b95ad079e9f636884eedc6853e6ad98b85f65 + revision: 258652a3ac5d7df68ba8df20e4705c3bd98ede38 path: modules/hal/ti groups: - hal From 0c87aae2695b032efde226bec3f3f3adc694648c Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 24 Jul 2024 14:35:36 +0200 Subject: [PATCH 02/18] modules: simplelink: Add support for cc23x0 SoC Product URL: https://www.ti.com/product/CC2340R5 Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- modules/Kconfig.simplelink | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/Kconfig.simplelink b/modules/Kconfig.simplelink index 13b26b1ca1a48..3a1cea8ebb3e3 100644 --- a/modules/Kconfig.simplelink +++ b/modules/Kconfig.simplelink @@ -32,3 +32,8 @@ config HAS_CC13X2_CC26X2_SDK config HAS_CC13X2X7_CC26X2X7_SDK bool + +# CC23X0 SDK HAL configuration + +config HAS_CC23X0_SDK + bool From e47d9b1be53395f40c849c103a4fe331874f5ec3 Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:27:17 +0200 Subject: [PATCH 03/18] soc: ti: Add support for new SoC cc23x0 Datasheet: https://www.ti.com/lit/ds/symlink/cc2340r5.pdf TRM: https://www.ti.com/lit/ug/swcu193/swcu193.pdf Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc2340r5.dtsi | 15 ++++ dts/arm/ti/cc23x0.dtsi | 41 +++++++++++ soc/ti/simplelink/Kconfig | 6 ++ soc/ti/simplelink/cc23x0/CMakeLists.txt | 12 ++++ soc/ti/simplelink/cc23x0/Kconfig | 49 +++++++++++++ soc/ti/simplelink/cc23x0/Kconfig.defconfig | 19 +++++ soc/ti/simplelink/cc23x0/Kconfig.soc | 22 ++++++ soc/ti/simplelink/cc23x0/ccfg.c | 80 ++++++++++++++++++++++ soc/ti/simplelink/cc23x0/ccfg.ld | 23 +++++++ soc/ti/simplelink/cc23x0/linker.ld | 8 +++ soc/ti/simplelink/cc23x0/soc.c | 14 ++++ soc/ti/simplelink/cc23x0/soc.h | 13 ++++ soc/ti/simplelink/soc.yml | 3 + 13 files changed, 305 insertions(+) create mode 100644 dts/arm/ti/cc2340r5.dtsi create mode 100644 dts/arm/ti/cc23x0.dtsi create mode 100644 soc/ti/simplelink/cc23x0/CMakeLists.txt create mode 100644 soc/ti/simplelink/cc23x0/Kconfig create mode 100644 soc/ti/simplelink/cc23x0/Kconfig.defconfig create mode 100644 soc/ti/simplelink/cc23x0/Kconfig.soc create mode 100644 soc/ti/simplelink/cc23x0/ccfg.c create mode 100644 soc/ti/simplelink/cc23x0/ccfg.ld create mode 100644 soc/ti/simplelink/cc23x0/linker.ld create mode 100644 soc/ti/simplelink/cc23x0/soc.c create mode 100644 soc/ti/simplelink/cc23x0/soc.h diff --git a/dts/arm/ti/cc2340r5.dtsi b/dts/arm/ti/cc2340r5.dtsi new file mode 100644 index 0000000000000..031022f3129e1 --- /dev/null +++ b/dts/arm/ti/cc2340r5.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(36)>; + }; +}; diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi new file mode 100644 index 0000000000000..5ec7223c10f19 --- /dev/null +++ b/dts/arm/ti/cc23x0.dtsi @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m0+"; + clock-frequency = ; + reg = <0>; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = ; + #clock-cells = <0>; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <2>; /* Interrupt levels are 0-192 in steps of 64 */ +}; + +&systick { + status = "disabled"; +}; diff --git a/soc/ti/simplelink/Kconfig b/soc/ti/simplelink/Kconfig index af4cd5f74333e..e4e57d9a9dd7d 100644 --- a/soc/ti/simplelink/Kconfig +++ b/soc/ti/simplelink/Kconfig @@ -12,4 +12,10 @@ config HAS_TI_CCFG Selected when CCFG (Customer Configuration) registers appear at the end of flash +config TI_SIMPLELINK_DYNAMIC_DPL_OBJECTS + bool + help + Turn on dynamic memory allocation for DPL objects. Reserves + extra memory for this. + endif # SOC_FAMILY_TI_SIMPLELINK diff --git a/soc/ti/simplelink/cc23x0/CMakeLists.txt b/soc/ti/simplelink/cc23x0/CMakeLists.txt new file mode 100644 index 0000000000000..b8e02adbd58e8 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) +zephyr_sources(ccfg.c) +zephyr_include_directories(.) + +zephyr_linker_sources_ifdef(CONFIG_HAS_TI_CCFG SECTIONS ccfg.ld) + +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/ti/simplelink/cc23x0/Kconfig b/soc/ti/simplelink/cc23x0/Kconfig new file mode 100644 index 0000000000000..fa1c2c45af3e3 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/Kconfig @@ -0,0 +1,49 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_CC23X0 + select ARM + select CPU_CORTEX_M0PLUS + select CPU_CORTEX_M_HAS_VTOR + select SOC_RESET_HOOK + select TICKLESS_KERNEL + select DYNAMIC_INTERRUPTS + select HAS_CC23X0_SDK + select HAS_TI_CCFG + select TI_SIMPLELINK_DYNAMIC_DPL_OBJECTS + select EVENTS + select DYNAMIC_THREAD + select DYNAMIC_THREAD_ALLOC + select THREAD_STACK_INFO + select BUILD_OUTPUT_HEX + select BUILD_NO_GAP_FILL + +menu "Bootloader Configuration" +depends on SOC_SERIES_CC23X0 + +choice CC23X0_BLDR_VTOR_TYPE + prompt "Pointer to user bootloader vector table" + default CC23X0_BLDR_VTOR_TYPE_UNDEF + +config CC23X0_BLDR_VTOR_TYPE_UNDEF + bool "ROM serial bootloader" + +config CC23X0_BLDR_VTOR_TYPE_FORBID + bool "No bootloader invoked" + +config CC23X0_BLDR_VTOR_TYPE_USE_FCFG + bool "Use factory configuration" + +config CC23X0_BLDR_VTOR_TYPE_FLASH + bool "Use valid main flash address" + +endchoice # CC23X0_BLDR_VTOR_TYPE + +config CC23X0_BLDR_ENABLED + bool "Bootloader commands" + help + If n, bootloader ignores all commands. + +endmenu # "Bootloader Configuration" diff --git a/soc/ti/simplelink/cc23x0/Kconfig.defconfig b/soc/ti/simplelink/cc23x0/Kconfig.defconfig new file mode 100644 index 0000000000000..442c9b09c9e07 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/Kconfig.defconfig @@ -0,0 +1,19 @@ +# Texas Instruments SimpleLink CC23X0 + +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_CC23X0 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +config SYS_CLOCK_TICKS_PER_SEC + default 1000 + +config NUM_IRQS + default 19 + +endif diff --git a/soc/ti/simplelink/cc23x0/Kconfig.soc b/soc/ti/simplelink/cc23x0/Kconfig.soc new file mode 100644 index 0000000000000..6817c069f9399 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/Kconfig.soc @@ -0,0 +1,22 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_CC23X0 + bool + select SOC_FAMILY_TI_SIMPLELINK + help + Enable support for TI SimpleLink CC23X0 series SOCs. + +config SOC_CC2340R5 + bool + select SOC_SERIES_CC23X0 + help + CC2340R5 + +config SOC_SERIES + default "cc23x0" if SOC_SERIES_CC23X0 + +config SOC + default "cc2340r5" if SOC_CC2340R5 diff --git a/soc/ti/simplelink/cc23x0/ccfg.c b/soc/ti/simplelink/cc23x0/ccfg.c new file mode 100644 index 0000000000000..08031e40adc0a --- /dev/null +++ b/soc/ti/simplelink/cc23x0/ccfg.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#define CC23_CCFG_FLASH DT_INST(0, ti_cc23x0_ccfg_flash) +#define CC23_CCFG_FLASH_PROP(prop) DT_PROP(CC23_CCFG_FLASH, prop) + +#define CC23_TO_PERM_VAL(en) ((en) ? CCFG_PERMISSION_ALLOW : CCFG_PERMISSION_FORBID) + +#if CONFIG_CC23X0_BLDR_VTOR_TYPE_UNDEF +#define CC23X0_BLDR_VTOR 0xffffffff +#elif CONFIG_CC23X0_BLDR_VTOR_TYPE_FORBID +#define CC23X0_BLDR_VTOR 0xfffffffc +#elif CONFIG_CC23X0_BLDR_VTOR_TYPE_USE_FCFG +#define CC23X0_BLDR_VTOR 0xfffffff0 +#else +#define CC23X0_BLDR_VTOR CC23_CCFG_FLASH_PROP(ti_bldr_vtor_flash) +#endif + +#define CC23X0_P_APP_VTOR DT_REG_ADDR(DT_CHOSEN(zephyr_code_partition)) + +#if CC23_CCFG_FLASH_PROP(ti_chip_erase) == 0 +#warning ti,chip-erase property is NOT PRESENT in your device tree, \ + flashing this firmware will LOCK YOUR DEVICE. +#endif + +/* Default CCFG */ +const ccfg_t ccfg __attribute__((section(".ti_ccfg"))) __attribute__((used)) = { + .bootCfg.pBldrVtor = (void *)CC23X0_BLDR_VTOR, + .bootCfg.bldrParam.serialRomBldrParamStruct.bldrEnabled = + IS_ENABLED(CONFIG_CC23X0_BLDR_ENABLED), + .bootCfg.bldrParam.serialRomBldrParamStruct.serialIoCfgIndex = + CC23_CCFG_FLASH_PROP(ti_serial_io_cfg_index), + .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerEnabled = + CC23_CCFG_FLASH_PROP(ti_pin_trigger), + .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerDio = + CC23_CCFG_FLASH_PROP(ti_pin_trigger_dio), + .bootCfg.bldrParam.serialRomBldrParamStruct.pinTriggerLevel = + CC23_CCFG_FLASH_PROP(ti_pin_trigger_level_hi), + .bootCfg.pAppVtor = (void *)CC23X0_P_APP_VTOR, + + .hwOpts = {0xffffffff, 0xffffffff}, + + .permissions.allowDebugPort = CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_debug_port)), + .permissions.allowEnergyTrace = CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_energy_trace)), + .permissions.allowFlashVerify = CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_flash_verify)), + .permissions.allowFlashProgram = CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_flash_program)), + .permissions.allowChipErase = CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_chip_erase)), + .permissions.allowToolsClientMode = CCFG_PERMISSION_ALLOW, + .permissions.allowReturnToFactory = + CC23_TO_PERM_VAL(CC23_CCFG_FLASH_PROP(ti_ret_to_factory)), + .permissions.allowFakeStby = CCFG_PERMISSION_ALLOW, + + .misc.saciTimeoutOverride = 0, + .misc.saciTimeoutExp = XCFG_MISC_SACITOEXP_8SEC, + + .flashProt.writeEraseProt.mainSectors0_31 = CC23_CCFG_FLASH_PROP(ti_wr_er_prot_sect0_31), + .flashProt.writeEraseProt.mainSectors32_255 = + CC23_CCFG_FLASH_PROP(ti_wr_er_prot_sect32_255), + .flashProt.writeEraseProt.ccfgSector = CC23_CCFG_FLASH_PROP(ti_wr_er_prot_ccfg_sect), + .flashProt.writeEraseProt.fcfgSector = CC23_CCFG_FLASH_PROP(ti_wr_er_prot_fcfg_sect), + .flashProt.writeEraseProt.engrSector = CC23_CCFG_FLASH_PROP(ti_wr_er_prot_engr_sect), + + .flashProt.res = 0xffffffff, + + .flashProt.chipEraseRetain.mainSectors0_31 = + CC23_CCFG_FLASH_PROP(ti_chip_er_retain_sect0_31), + .flashProt.chipEraseRetain.mainSectors32_255 = + CC23_CCFG_FLASH_PROP(ti_chip_er_retain_sect32_255), + + .debugCfg.authorization = CCFG_DBGAUTH_DBGOPEN, + .debugCfg.allowBldr = CCFG_DBGBLDR_ALLOW, +}; diff --git a/soc/ti/simplelink/cc23x0/ccfg.ld b/soc/ti/simplelink/cc23x0/ccfg.ld new file mode 100644 index 0000000000000..a9baf05dcf46d --- /dev/null +++ b/soc/ti/simplelink/cc23x0/ccfg.ld @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +GROUP_START(FLASH_CCFG) + +CRC_CCFG_BOOT_CFG_begin = 0x4e020000; +CRC_CCFG_BOOT_CFG_end = 0x4e02000B; +CRC_CCFG_begin = 0x4E020010; +CRC_CCFG_end = 0x4E02074B; +CRC_CCFG_DEBUG_begin = 0x4E0207D0; +CRC_CCFG_DEBUG_end = 0x4E0207FB; +CRC_CCFG_USER_RECORD_begin = 0x4E020750; +CRC_CCFG_USER_RECORD_end = 0x4E0207CB; +SECTION_PROLOGUE(.ti_ccfg,,) +{ + KEEP(*(_TI_CCFG_SECTION_NAME)) +} GROUP_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_NODELABEL(ti_ccfg_partition))) + +GROUP_END(FLASH_CCFG) diff --git a/soc/ti/simplelink/cc23x0/linker.ld b/soc/ti/simplelink/cc23x0/linker.ld new file mode 100644 index 0000000000000..448cc70c043d1 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/linker.ld @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/soc/ti/simplelink/cc23x0/soc.c b/soc/ti/simplelink/cc23x0/soc.c new file mode 100644 index 0000000000000..cddae58b4e05d --- /dev/null +++ b/soc/ti/simplelink/cc23x0/soc.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +void soc_reset_hook(void) +{ + /* Perform necessary trim of the device. */ + SetupTrimDevice(); +} diff --git a/soc/ti/simplelink/cc23x0/soc.h b/soc/ti/simplelink/cc23x0/soc.h new file mode 100644 index 0000000000000..968cbc99d9c54 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/soc.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TI_SIMPLELINK_CC23X0_SOC_H_ +#define TI_SIMPLELINK_CC23X0_SOC_H_ + +#include "cmsis/cc23x0r5.h" + +#endif /* TI_SIMPLELINK_CC23X0_SOC_H_ */ diff --git a/soc/ti/simplelink/soc.yml b/soc/ti/simplelink/soc.yml index 2dbf91f315e6f..bbf1ef19de4b5 100644 --- a/soc/ti/simplelink/soc.yml +++ b/soc/ti/simplelink/soc.yml @@ -13,6 +13,9 @@ family: - name: cc1352r7 - name: cc2652p7 - name: cc2652r7 + - name: cc23x0 + socs: + - name: cc2340r5 - name: cc32xx socs: - name: cc3220sf From e6ae8922b5f9416955e4e41eaa6c0041921aa2a0 Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:31:47 +0200 Subject: [PATCH 04/18] boards: ti: Add support for new board lp_em_cc2340r5 Product URL: https://www.ti.com/tool/LP-EM-CC2340R5 Quick Start Guide: https://www.ti.com/lit/ml/swru588a/swru588a.pdf Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- .../ti/lp_em_cc2340r5/Kconfig.lp_em_cc2340r5 | 7 + boards/ti/lp_em_cc2340r5/board.yml | 5 + .../lp_em_cc2340r5/boosterpack_connector.dtsi | 39 ++++++ .../doc/img/lp_em_cc2340r5.webp | Bin 0 -> 55752 bytes boards/ti/lp_em_cc2340r5/doc/index.rst | 128 ++++++++++++++++++ boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 19 +++ boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml | 14 ++ .../lp_em_cc2340r5/lp_em_cc2340r5_defconfig | 10 ++ 8 files changed, 222 insertions(+) create mode 100644 boards/ti/lp_em_cc2340r5/Kconfig.lp_em_cc2340r5 create mode 100644 boards/ti/lp_em_cc2340r5/board.yml create mode 100644 boards/ti/lp_em_cc2340r5/boosterpack_connector.dtsi create mode 100644 boards/ti/lp_em_cc2340r5/doc/img/lp_em_cc2340r5.webp create mode 100644 boards/ti/lp_em_cc2340r5/doc/index.rst create mode 100644 boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts create mode 100644 boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml create mode 100644 boards/ti/lp_em_cc2340r5/lp_em_cc2340r5_defconfig diff --git a/boards/ti/lp_em_cc2340r5/Kconfig.lp_em_cc2340r5 b/boards/ti/lp_em_cc2340r5/Kconfig.lp_em_cc2340r5 new file mode 100644 index 0000000000000..fbc90c7ebc8ae --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/Kconfig.lp_em_cc2340r5 @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_LP_EM_CC2340R5 + select SOC_CC2340R5 diff --git a/boards/ti/lp_em_cc2340r5/board.yml b/boards/ti/lp_em_cc2340r5/board.yml new file mode 100644 index 0000000000000..8f51f66196184 --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/board.yml @@ -0,0 +1,5 @@ +board: + name: lp_em_cc2340r5 + vendor: ti + socs: + - name: cc2340r5 diff --git a/boards/ti/lp_em_cc2340r5/boosterpack_connector.dtsi b/boards/ti/lp_em_cc2340r5/boosterpack_connector.dtsi new file mode 100644 index 0000000000000..f330b8c1e8233 --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/boosterpack_connector.dtsi @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + boosterpack_header: connector { + compatible = "ti,boosterpack-header"; + #gpio-cells = <2>; + gpio-map = <3 0 &gpio0 22 0>, + <4 0 &gpio0 20 0>, + <7 0 &gpio0 18 0>, + <8 0 &gpio0 3 0>, + <9 0 &gpio0 24 0>, + <10 0 &gpio0 0 0>, + + <12 0 &gpio0 9 0>, + <13 0 &gpio0 10 0>, + <14 0 &gpio0 12 0>, + <15 0 &gpio0 13 0>, + <17 0 &gpio0 19 0>, + <18 0 &gpio0 11 0>, + + <23 0 &gpio0 23 0>, + <24 0 &gpio0 25 0>, + <25 0 &gpio0 1 0>, + <26 0 &gpio0 2 0>, + <27 0 &gpio0 5 0>, + <28 0 &gpio0 7 0>, + + <36 0 &gpio0 8 0>, + <37 0 &gpio0 21 0>, + <38 0 &gpio0 6 0>, + <39 0 &gpio0 14 0>, + <40 0 &gpio0 15 0>; + }; +}; diff --git a/boards/ti/lp_em_cc2340r5/doc/img/lp_em_cc2340r5.webp b/boards/ti/lp_em_cc2340r5/doc/img/lp_em_cc2340r5.webp new file mode 100644 index 0000000000000000000000000000000000000000..df225cf6154efb468d7bfead34e25446adfb7c1a GIT binary patch literal 55752 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 literal 0 HcmV?d00001 diff --git a/boards/ti/lp_em_cc2340r5/doc/index.rst b/boards/ti/lp_em_cc2340r5/doc/index.rst new file mode 100644 index 0000000000000..c392862ac53e2 --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/doc/index.rst @@ -0,0 +1,128 @@ +.. _lp_em_cc2340r5: + +TI CC2340R5 Launchpad +##################### + +Overview +******** + +The Texas Instruments CC2340R5 LaunchPad |trade| (LP_EM_CC2340R5) is a +development kit for the SimpleLink |trade| multi-Standard CC2340R5 wireless MCU. + +See the `TI CC2340R5 LaunchPad Product Page`_ for details. + +.. figure:: img/lp_em_cc2340r5.webp + :align: center + :alt: TI CC2340R5 Launchpad + + Texas Instruments CC2340R5 LaunchPad |trade| + +Hardware +******** + +The CC2340R5 LaunchPad |trade| development kit features the CC2340R5 wireless MCU. +The board is equipped with two LEDs, two push buttons and BoosterPack connectors +for expansion. + +The CC2340R5 wireless MCU has a 48 MHz Arm |reg| Cortex |reg|-M0+ SoC and an +integrated 2.4 GHz transceiver supporting multiple protocols including Bluetooth +|reg| Low Energy and IEEE |reg| 802.15.4. + +See the `TI CC2340R5 Product Page`_ for additional details. + +Supported Features +================== + +The ``lp_em_cc2340r5`` board supports the following hardware features: + ++-----------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++===========+============+======================+ +| NVIC | on-chip | arch/arm | ++-----------+------------+----------------------+ +| GPIO | on-chip | gpio | ++-----------+------------+----------------------+ +| PINMUX | on-chip | pinmux | ++-----------+------------+----------------------+ +| UART | on-chip | serial port | ++-----------+------------+----------------------+ +| SYSTIM | on-chip | system timer | ++-----------+------------+----------------------+ +| FLASH | on-chip | flash memory | ++-----------+------------+----------------------+ + +Other hardware features have not been enabled yet for this board. + +Connections and IOs +=================== + +All I/O signals are accessible from the BoosterPack connectors. Pin function +aligns with the LaunchPad standard. + ++-------+-----------+---------------------+ +| Pin | Function | Usage | ++=======+===========+=====================+ +| DIO0 | GPIO | | ++-------+-----------+---------------------+ +| DIO1 | ANALOG_IO | A4 | ++-------+-----------+---------------------+ +| DIO2 | ANALOG_IO | A3 | ++-------+-----------+---------------------+ +| DIO5 | ANALOG_IO | A5 | ++-------+-----------+---------------------+ +| DIO6 | SPI_CSN | SPI CS | ++-------+-----------+---------------------+ +| DIO7 | ANALOG_IO | A0 | ++-------+-----------+---------------------+ +| DIO8 | GPIO | | ++-------+-----------+---------------------+ +| DIO9 | GPIO | Button 2 | ++-------+-----------+---------------------+ +| DIO10 | GPIO | Button 1 | ++-------+-----------+---------------------+ +| DIO11 | SPI_CSN | SPI CS | ++-------+-----------+---------------------+ +| DIO12 | SPI_POCI | SPI POCI | ++-------+-----------+---------------------+ +| DIO13 | SPI_PICO | SPI_PICO | ++-------+-----------+---------------------+ +| DIO14 | GPIO | Red LED | ++-------+-----------+---------------------+ +| DIO15 | GPIO | Green LED | ++-------+-----------+---------------------+ +| DIO18 | SPI_CLK | SPI CLK | ++-------+-----------+---------------------+ +| DIO19 | GPIO | | ++-------+-----------+---------------------+ +| DIO20 | UART0_TX | UART TX | ++-------+-----------+---------------------+ +| DIO21 | GPIO | | ++-------+-----------+---------------------+ +| DIO22 | UART0_RX | UART RX | ++-------+-----------+---------------------+ +| DIO23 | ANALOG_IO | A8 | ++-------+-----------+---------------------+ +| DIO24 | ANALOG_IO | A7 | ++-------+-----------+---------------------+ + +Programming and Debugging +************************* + +The LP_EM_CC2340R5 requires an external debug probe such as the LP-XDS110 or +LP-XDS110ET. + +Currently there is no debug support in Zephyr for the LP_EM_CC2340R5, and the +built binaries for this target must be flashed/debugged using either Uniflash +or Code Composer Studio. + +References +********** + +CC2340R5 LaunchPad Quick Start Guide: + https://www.ti.com/lit/pdf/swru588 + +.. _TI CC2340R5 LaunchPad Product Page: + https://www.ti.com/tool/LP-EM-CC2340R5 + +.. _TI CC2340R5 Product Page: + https://www.ti.com/product/CC2340R5 diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts new file mode 100644 index 0000000000000..f5b36af5a766e --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "LP_EM_CC2340R5"; + compatible = "ti,lp_em_cc2340r5"; + + chosen { + zephyr,sram = &sram0; + }; +}; diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml new file mode 100644 index 0000000000000..705f3cdef20a7 --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.yaml @@ -0,0 +1,14 @@ +identifier: lp_em_cc2340r5 +name: TI SimpleLink CC2340R5 LaunchPad +type: mcu +arch: arm +ram: 80 +flash: 512 +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - gpio + - uart +vendor: ti diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5_defconfig b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5_defconfig new file mode 100644 index 0000000000000..7f9b629c25f38 --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5_defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_GPIO=y +CONFIG_SERIAL=y + +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y From bb8d92a93126e469135a851b7f56b22c93f30b5d Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 15:03:14 +0200 Subject: [PATCH 05/18] drivers: flash: Add support for cc23x0 flash Add support for flash to cc23x0 SoC. The driver interacts with VIMS (Versatile Instruction Memory System) internal bus standing before NVM. Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/flash/CMakeLists.txt | 1 + drivers/flash/Kconfig | 1 + drivers/flash/Kconfig.cc23x0 | 14 + drivers/flash/soc_flash_cc23x0.c | 239 ++++++++++++++++++ .../ti,cc23x0-flash-controller.yaml | 5 + 5 files changed, 260 insertions(+) create mode 100644 drivers/flash/Kconfig.cc23x0 create mode 100644 drivers/flash/soc_flash_cc23x0.c create mode 100644 dts/bindings/flash_controller/ti,cc23x0-flash-controller.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index b8b345bb6d96e..50f6498c3a7b9 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_STM32_XSPI flash_stm32_xspi.c) zephyr_library_sources_ifdef(CONFIG_INFINEON_CAT1_QSPI_FLASH flash_ifx_cat1_qspi.c) zephyr_library_sources_ifdef(CONFIG_NORDIC_QSPI_NOR nrf_qspi_nor.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC13XX_CC26XX soc_flash_cc13xx_cc26xx.c) +zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_CC23X0 soc_flash_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ESP32 flash_esp32.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_GECKO flash_gecko.c) zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_ITE_IT8XXX2 flash_ite_it8xxx2.c) diff --git a/drivers/flash/Kconfig b/drivers/flash/Kconfig index bc9f6e69d7e35..edfa81224dc39 100644 --- a/drivers/flash/Kconfig +++ b/drivers/flash/Kconfig @@ -171,6 +171,7 @@ source "drivers/flash/Kconfig.b91" source "drivers/flash/Kconfig.cadence_nand" source "drivers/flash/Kconfig.cadence_qspi_nor" source "drivers/flash/Kconfig.cc13xx_cc26xx" +source "drivers/flash/Kconfig.cc23x0" source "drivers/flash/Kconfig.esp32" source "drivers/flash/Kconfig.gd32" source "drivers/flash/Kconfig.gecko" diff --git a/drivers/flash/Kconfig.cc23x0 b/drivers/flash/Kconfig.cc23x0 new file mode 100644 index 0000000000000..0a71900914422 --- /dev/null +++ b/drivers/flash/Kconfig.cc23x0 @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FLASH_CC23X0 + bool "TI SimpleLink CC23x0 flash controller driver" + default y + depends on DT_HAS_TI_CC23X0_FLASH_CONTROLLER_ENABLED + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_DRIVER_ENABLED + select MPU_ALLOW_FLASH_WRITE if ARM_MPU + help + Enables TI SimpleLink CC23x0 flash controller driver. diff --git a/drivers/flash/soc_flash_cc23x0.c b/drivers/flash/soc_flash_cc23x0.c new file mode 100644 index 0000000000000..a3e686fda6b15 --- /dev/null +++ b/drivers/flash/soc_flash_cc23x0.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define DT_DRV_COMPAT ti_cc23x0_flash_controller +#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash) + +#define FLASH_ADDR DT_REG_ADDR(SOC_NV_FLASH_NODE) +#define FLASH_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE) +#define FLASH_ERASE_SIZE DT_PROP(SOC_NV_FLASH_NODE, erase_block_size) +#define FLASH_WRITE_SIZE DT_PROP(SOC_NV_FLASH_NODE, write_block_size) + +struct flash_cc23x0_data { + struct k_sem mutex; +}; + +static const struct flash_parameters flash_cc23x0_parameters = { + .write_block_size = FLASH_WRITE_SIZE, + .erase_value = 0xff, +}; + +static int flash_cc23x0_init(const struct device *dev) +{ + struct flash_cc23x0_data *data = dev->data; + + k_sem_init(&data->mutex, 1, 1); + + return 0; +} + +static void flash_cc23x0_cache_restore(uint32_t vims_mode) +{ + while (VIMSModeGet(VIMS_BASE) == VIMS_MODE_CHANGING) { + ; + } + + /* Restore VIMS mode and line buffers */ + if (vims_mode != VIMS_MODE_DISABLED) { + VIMSModeSafeSet(VIMS_BASE, vims_mode, true); + } + + VIMSLineBufEnable(VIMS_BASE); +} + +static uint32_t flash_cc23x0_cache_disable(void) +{ + uint32_t vims_mode; + + /* VIMS and both line buffers should be off during flash update */ + VIMSLineBufDisable(VIMS_BASE); + + while (VIMSModeGet(VIMS_BASE) == VIMS_MODE_CHANGING) { + ; + } + + /* Save current VIMS mode for restoring it later */ + vims_mode = VIMSModeGet(VIMS_BASE); + if (vims_mode != VIMS_MODE_DISABLED) { + VIMSModeSafeSet(VIMS_BASE, VIMS_MODE_DISABLED, true); + } + + return vims_mode; +} + +static int flash_cc23x0_erase(const struct device *dev, off_t offs, size_t size) +{ + struct flash_cc23x0_data *data = dev->data; + uint32_t vims_mode; + unsigned int key; + int i; + int rc = 0; + size_t cnt; + + if (!size) { + return 0; + } + + /* Offset and length should be multiple of erase size */ + if (((offs % FLASH_ERASE_SIZE) != 0) || ((size % FLASH_ERASE_SIZE) != 0)) { + return -EINVAL; + } + + if (k_sem_take(&data->mutex, K_FOREVER)) { + return -EACCES; + } + + vims_mode = flash_cc23x0_cache_disable(); + /* + * Disable all interrupts to prevent flash read, from TI's TRF: + * + * During a FLASH memory write or erase operation, the FLASH memory + * must not be read. + */ + key = irq_lock(); + + /* Erase sector/page one by one, break out in case of an error */ + cnt = size / FLASH_ERASE_SIZE; + for (i = 0; i < cnt; i++, offs += FLASH_ERASE_SIZE) { + while (FlashCheckFsmForReady() != FAPI_STATUS_FSM_READY) { + ; + } + + rc = FlashEraseSector(offs); + if (rc != FAPI_STATUS_SUCCESS) { + rc = -EIO; + break; + } + } + + irq_unlock(key); + + flash_cc23x0_cache_restore(vims_mode); + + k_sem_give(&data->mutex); + return rc; +} + +static int flash_cc23x0_write(const struct device *dev, off_t offs, const void *data, size_t size) +{ + struct flash_cc23x0_data *flash_data = dev->data; + uint32_t vims_mode; + unsigned int key; + int rc = 0; + + if (!size) { + return 0; + } + + if (offs < 0 || size < 1) { + return -EINVAL; + } + + if (offs + size > FLASH_SIZE) { + return -EINVAL; + } + + /* + * From TI's HAL 'driverlib/flash.h': + * + * The pui8DataBuffer pointer can not point to flash. + */ + if ((data >= (void *)FLASH_ADDR) && (data <= (void *)(FLASH_ADDR + FLASH_SIZE))) { + return -EINVAL; + } + + if (k_sem_take(&flash_data->mutex, K_FOREVER)) { + return -EACCES; + } + + vims_mode = flash_cc23x0_cache_disable(); + + key = irq_lock(); + + while (FlashCheckFsmForReady() != FAPI_STATUS_FSM_READY) { + ; + } + + rc = FlashProgram((uint8_t *)data, offs, size); + if (rc != FAPI_STATUS_SUCCESS) { + rc = -EIO; + } + + irq_unlock(key); + + flash_cc23x0_cache_restore(vims_mode); + + k_sem_give(&flash_data->mutex); + + return rc; +} + +static int flash_cc23x0_read(const struct device *dev, off_t offs, void *data, size_t size) +{ + ARG_UNUSED(dev); + + if (!size) { + return 0; + } + + if (offs < 0 || size < 1) { + return -EINVAL; + } + + if (offs + size > FLASH_SIZE) { + return -EINVAL; + } + + memcpy(data, (void *)offs, size); + + return 0; +} + +static const struct flash_parameters *flash_cc23x0_get_parameters(const struct device *dev) +{ + ARG_UNUSED(dev); + + return &flash_cc23x0_parameters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static const struct flash_pages_layout dev_layout = { + .pages_count = FLASH_SIZE / FLASH_ERASE_SIZE, + .pages_size = FLASH_ERASE_SIZE, +}; + +static void flash_cc23x0_layout(const struct device *dev, const struct flash_pages_layout **layout, + size_t *layout_size) +{ + *layout = &dev_layout; + *layout_size = 1; +} +#endif /* CONFIG_FLASH_PAGE_LAYOUT */ + +static const struct flash_driver_api flash_cc23x0_api = { + .erase = flash_cc23x0_erase, + .write = flash_cc23x0_write, + .read = flash_cc23x0_read, + .get_parameters = flash_cc23x0_get_parameters, +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_cc23x0_layout, +#endif +}; + +static struct flash_cc23x0_data cc23x0_flash_data; + +DEVICE_DT_INST_DEFINE(0, flash_cc23x0_init, NULL, &cc23x0_flash_data, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &flash_cc23x0_api); diff --git a/dts/bindings/flash_controller/ti,cc23x0-flash-controller.yaml b/dts/bindings/flash_controller/ti,cc23x0-flash-controller.yaml new file mode 100644 index 0000000000000..538e75aa16d89 --- /dev/null +++ b/dts/bindings/flash_controller/ti,cc23x0-flash-controller.yaml @@ -0,0 +1,5 @@ +description: Texas Instruments CC23X0 flash controller + +compatible: "ti,cc23x0-flash-controller" + +include: flash-controller.yaml From 2cb6357840f1729b3afd42221cdd49672f093971 Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 16 Oct 2024 15:51:23 +0200 Subject: [PATCH 06/18] dts: bindings: mtd: Add support for cc23x0 flash CCFG sector This region is used for customer configuration options. Signed-off-by: Julien Panis --- dts/bindings/mtd/ti,cc23x0-ccfg-flash.yaml | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 dts/bindings/mtd/ti,cc23x0-ccfg-flash.yaml diff --git a/dts/bindings/mtd/ti,cc23x0-ccfg-flash.yaml b/dts/bindings/mtd/ti,cc23x0-ccfg-flash.yaml new file mode 100644 index 0000000000000..0786ec7c478cd --- /dev/null +++ b/dts/bindings/mtd/ti,cc23x0-ccfg-flash.yaml @@ -0,0 +1,161 @@ +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: | + This binding describes the TI CC23X0 flash CCFG (custom configuration) + area content. + + Notes: + The flash CCFG sector node (e.g. flash1) should have both + "ti,cc23x0-ccfg-flash" and the "soc-nv-flash" compatibles. + The latter is used from mcuboot and other modules to identify + the flash area. + +compatible: "ti,cc23x0-ccfg-flash" + +include: soc-nv-flash.yaml + +properties: + ti,bldr-vtor-flash: + type: int + description: | + Bootloader entry point when a boot from flash is selected. + Valid range: 0 - 0x0effffff + Default is 0, which is the standard initial configuration. + default: 0 + + ti,serial-io-cfg-index: + type: int + description: | + Index of which I/O mapping to use for UART/SPI. + Valid range: 0 - 2 + Default is 0, which is the standard initial configuration. Other values can be + used depending on I/O availability. + default: 0 + + ti,pin-trigger: + type: boolean + description: | + If not present, then bootloader unconditionally triggers. + Else normal pin trigger check is performed. + + ti,pin-trigger-dio: + type: int + description: | + Index of DIO pin to use for pin trigger check. + Valid range: 0 - 25 + Default is 0, which is the standard initial configuration. Other values can be + used depending on DIO availability. + default: 0 + + ti,pin-trigger-level-hi: + type: boolean + description: | + If not present, then the level on trigger pin that triggers bootloader is low. + Else level that triggers bootloader is high. + + ti,debug-port: + type: boolean + description: | + If not present, then the SWD port is disabled altogether at a certain point in boot + before invoking either bootloader or application. + + ti,energy-trace: + type: boolean + description: | + Allows using EnergyTrace power analyzer tool. + EnergyTrace software is an energy-based code analysis tool that measures + and displays the energy profile of an application and helps optimize it for + ultra-low-power consumption. + + ti,flash-verify: + type: boolean + description: | + Determines whether flash verifying SACI commands are allowed. These commands only check + integrity against a provided CRC32 value, never return any flash contents. Flash verify + commands are always allowed after a chip erase and until the first reset after the CCFG + sector has been programmed. + + ti,flash-program: + type: boolean + description: | + Determines whether flash programming SACI commands are allowed. + Reset to allowed after a chip erase. + + ti,chip-erase: + type: boolean + description: | + Determines whether chip erasing SACI commands are allowed. + + ti,ret-to-factory: + type: boolean + description: | + Allows return-to-factory procedure by SACI. + To do full failure analysis including flash, a return to factory procedure is supported. + + ti,wr-er-prot-sect0-31: + type: int + description: | + Bitmask for write/erase protection of individual sectors in sector range [0, 31]. + Controls whether flash programming is allowed through SACI. The same mechanism + controls whether the application is allowed to program these sectors. + 0 = protected. + Valid range: 0 - 0xffffffff + Default is 0xffffffff to allow programming these sectors. + default: 0xffffffff + + ti,wr-er-prot-sect32-255: + type: int + description: | + Bitmask for write/erase protection of groups of 8 sectors, in sector range [32, 255]. + Bit i protects sectors [32 + 8i, 39 + 8i]. + 0 = protected. + Valid range: 0 - 0xffffffff + Default is 0xffffffff to allow programming these sectors. + default: 0xffffffff + + ti,wr-er-prot-ccfg-sect: + type: int + description: | + Bitmask for write/erase protection of CCFG sectors. + Valid range: 0 - 0xffffffff + Default is 0 to prevent from mistakenly programming these sectors. + default: 0 + + ti,wr-er-prot-fcfg-sect: + type: int + description: | + Bitmask for write/erase protection of FCFG sectors. + Valid range: 0 - 0xffffffff + Default is 0 to prevent from mistakenly programming these sectors. + default: 0 + + ti,wr-er-prot-engr-sect: + type: int + description: | + Bitmask for write/erase protection of ENGR sectors. + Valid range: 0 - 0xffffffff + Default is 0 to prevent from mistakenly programming these sectors. + default: 0 + + ti,chip-er-retain-sect0-31: + type: int + description: | + Bitmask for chip erase protection of individual sectors in sector range [0, 31]. + Controls whether a chip erase affects a sector or not. The mechanism is intended + to allow flash sectors devoted to logging or runtime state/configuration to survive + the chip erase during a FW update. + 0 = protected. + Valid range: 0 - 0xffffffff + Default is 0 to prevent from mistakenly programming these sectors. + default: 0 + + ti,chip-er-retain-sect32-255: + type: int + description: | + Bitmask for chip erase protection of groups of 8 sectors, in sector range [32, 255]. + Bit i protects sectors [32 + 8i, 39 + 8i]. + 0 = protected. + Valid range: 0 - 0xffffffff + Default is 0 to prevent from mistakenly programming these sectors. + default: 0 From 7040752b406c19cdacaba85f08d17f185ad674a5 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:23:26 +0200 Subject: [PATCH 07/18] dts: arm: ti: cc23x0: Add flash support Add support for flash to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc2340r5.dtsi | 44 ++++++++++++++++++++++++++++++++++++++++ dts/arm/ti/cc23x0.dtsi | 27 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/dts/arm/ti/cc2340r5.dtsi b/dts/arm/ti/cc2340r5.dtsi index 031022f3129e1..c275b2e1de8a9 100644 --- a/dts/arm/ti/cc2340r5.dtsi +++ b/dts/arm/ti/cc2340r5.dtsi @@ -13,3 +13,47 @@ reg = <0x20000000 DT_SIZE_K(36)>; }; }; + +/* Main flash */ +&flash0 { + reg = <0x0 DT_SIZE_K(512)>; + #address-cells = <1>; + #size-cells = <1>; + + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x0 DT_SIZE_K(512)>; + }; +}; + +/* CCFG */ +&flash1 { + reg = <0x4e020000 DT_SIZE_K(2)>; + ti,bldr-vtor-flash = <0>; + ti,serial-io-cfg-index = <0>; + ti,debug-port; + ti,energy-trace; + ti,flash-verify; + ti,flash-program; + ti,chip-erase; + ti,ret-to-factory; + ti,wr-er-prot-sect0-31 = <0xffffffff>; + ti,wr-er-prot-sect32-255 = <0xffffffff>; + ti,wr-er-prot-ccfg-sect = <0>; + ti,wr-er-prot-fcfg-sect = <0>; + ti,wr-er-prot-engr-sect = <0>; + ti,chip-er-retain-sect0-31 = <0>; + ti,chip-er-retain-sect32-255 = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + ti_ccfg_partition: partition@4e020000 { + compatible = "zephyr,memory-region"; + reg = <0x4e020000 0x800>; + zephyr,memory-region = "FLASH_CCFG"; + }; + }; +}; diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index 5ec7223c10f19..e2d93bdb29ee7 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -9,6 +9,10 @@ #include / { + chosen { + zephyr,flash-controller = &flash_controller; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -30,6 +34,29 @@ clock-frequency = ; #clock-cells = <0>; }; + + soc { + flash_controller: flash-controller@40021000 { + compatible = "ti,cc23x0-flash-controller"; + reg = <0x40021000 0x408>; + #address-cells = <1>; + #size-cells = <1>; + + /* Main flash sector */ + flash0: flash@0 { + compatible = "soc-nv-flash"; + erase-block-size = ; + write-block-size = <0x10>; + }; + + /* CCFG flash sector */ + flash1: flash@4e020000 { + compatible = "ti,cc23x0-ccfg-flash", "soc-nv-flash"; + erase-block-size = ; + write-block-size = <0x10>; + }; + }; + }; }; &nvic { From 8cf5e8f746ca265a2c15a932386f8724111bc090 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:23:38 +0200 Subject: [PATCH 08/18] boards: ti: lp_em_cc2340r5: Add flash support Describe system flash setting. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index f5b36af5a766e..2a75adaba0b01 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -15,5 +15,7 @@ chosen { zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; }; }; From db1cfcc8b3b9f54373eb3c10372791e1b997317b Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:45:52 +0200 Subject: [PATCH 09/18] drivers: pinctrl: Add support for cc23x0 pinctrl Add support for pinctrl to cc23x0 SoC. Like for other TI SoCs, a node approach is implemented (no grouping approach). Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/pinctrl/CMakeLists.txt | 1 + drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Kconfig.cc23x0 | 11 + drivers/pinctrl/pinctrl_cc23x0.c | 36 +++ dts/bindings/pinctrl/ti,cc23x0-pinctrl.yaml | 62 +++++ .../dt-bindings/pinctrl/cc23x0-pinctrl.h | 227 ++++++++++++++++++ soc/ti/simplelink/cc23x0/pinctrl_soc.h | 59 +++++ 7 files changed, 397 insertions(+) create mode 100644 drivers/pinctrl/Kconfig.cc23x0 create mode 100644 drivers/pinctrl/pinctrl_cc23x0.c create mode 100644 dts/bindings/pinctrl/ti,cc23x0-pinctrl.yaml create mode 100644 include/zephyr/dt-bindings/pinctrl/cc23x0-pinctrl.h create mode 100644 soc/ti/simplelink/cc23x0/pinctrl_soc.h diff --git a/drivers/pinctrl/CMakeLists.txt b/drivers/pinctrl/CMakeLists.txt index e56922d083ebe..ee17efc789fb1 100644 --- a/drivers/pinctrl/CMakeLists.txt +++ b/drivers/pinctrl/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_PINCTRL_IMX pinctrl_imx.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_SIFIVE pinctrl_sifive.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_NXP_IOCON pinctrl_lpc_iocon.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_CC13XX_CC26XX pinctrl_cc13xx_cc26xx.c) +zephyr_library_sources_ifdef(CONFIG_PINCTRL_CC23X0 pinctrl_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_ESP32 pinctrl_esp32.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_RV32M1 pinctrl_rv32m1.c) zephyr_library_sources_ifdef(CONFIG_PINCTRL_INFINEON_CAT1 pinctrl_ifx_cat1.c) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 299372eea7f6b..44bd890564355 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -50,6 +50,7 @@ source "drivers/pinctrl/Kconfig.imx" source "drivers/pinctrl/Kconfig.sifive" source "drivers/pinctrl/Kconfig.lpc_iocon" source "drivers/pinctrl/Kconfig.cc13xx_cc26xx" +source "drivers/pinctrl/Kconfig.cc23x0" source "drivers/pinctrl/Kconfig.esp32" source "drivers/pinctrl/Kconfig.rv32m1" source "drivers/pinctrl/Kconfig.ifx_cat1" diff --git a/drivers/pinctrl/Kconfig.cc23x0 b/drivers/pinctrl/Kconfig.cc23x0 new file mode 100644 index 0000000000000..f10e2215aa05e --- /dev/null +++ b/drivers/pinctrl/Kconfig.cc23x0 @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config PINCTRL_CC23X0 + bool "TI SimpleLink CC23X0 pinctrl driver" + default y + depends on DT_HAS_TI_CC23X0_PINCTRL_ENABLED + help + Enable the TI SimpleLink CC23X0 pinctrl driver diff --git a/drivers/pinctrl/pinctrl_cc23x0.c b/drivers/pinctrl/pinctrl_cc23x0.c new file mode 100644 index 0000000000000..41ce0be662e97 --- /dev/null +++ b/drivers/pinctrl/pinctrl_cc23x0.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_pinctrl + +#include + +#include + +#define IOC_BASE_REG DT_REG_ADDR(DT_NODELABEL(pinctrl)) +#define IOC_BASE_PIN_REG 0x00000100 +#define IOC_ADDR(index) (IOC_BASE_REG + IOC_BASE_PIN_REG + (sizeof(uint32_t) * (index))) + +static int pinctrl_cc23x0_set(uint32_t pin, uint32_t func, uint32_t mode) +{ + uint32_t iocfg_reg = IOC_ADDR(pin); + + HWREG(iocfg_reg) = mode | func; + + return 0; +} + +int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) +{ + ARG_UNUSED(reg); + + for (uint8_t i = 0U; i < pin_cnt; i++) { + pinctrl_cc23x0_set(pins[i].pin, pins[i].iofunc, pins[i].iomode); + } + + return 0; +} diff --git a/dts/bindings/pinctrl/ti,cc23x0-pinctrl.yaml b/dts/bindings/pinctrl/ti,cc23x0-pinctrl.yaml new file mode 100644 index 0000000000000..9f3b17221b7ca --- /dev/null +++ b/dts/bindings/pinctrl/ti,cc23x0-pinctrl.yaml @@ -0,0 +1,62 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: | + TI SimpleLink CC23X0 pinctrl node. + + Device pin configuration should be placed in the child nodes of this node. + Populate the 'pinmux' field with a pair consisting of a pin number and its IO + functions. + + The node has the 'pinctrl' node label set in your SoC's devicetree, + so you can modify it like this: + + &pinctrl { + /* your modifications go here */ + }; + + All device pin configurations should be placed in child nodes of the + 'pinctrl' node, as in the i2c0 example shown at the end. + + Here is a list of + supported standard pin properties: + + - bias-disable: Disable pull-up/down. + - bias-pull-down: Enable pull-down resistor. + - bias-pull-up: Enable pull-up resistor. + - drive-open-drain: Output driver is open-drain. + - drive-open-source: Output driver is open-source. + - input-enable: enable input. + - input-schmitt-enable: enable input schmitt circuit. + +compatible: "ti,cc23x0-pinctrl" + +include: base.yaml + +properties: + reg: + required: true + +child-binding: + description: | + This binding gives a base representation of the CC23X0 + pins configuration. + + include: + - name: pincfg-node.yaml + property-allowlist: + - bias-disable + - bias-pull-down + - bias-pull-up + - drive-open-drain + - drive-open-source + - input-enable + - input-schmitt-enable + + properties: + pinmux: + required: true + type: array + description: | + CC23X0 pin's configuration (IO pin, IO function). diff --git a/include/zephyr/dt-bindings/pinctrl/cc23x0-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/cc23x0-pinctrl.h new file mode 100644 index 0000000000000..1c365965c9df5 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/cc23x0-pinctrl.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CC23X0_PINCTRL_COMMON_H_ +#define CC23X0_PINCTRL_COMMON_H_ + +/* + * The whole TI CC23X0 pin configuration information is encoded in a 32-bit + * bitfield organized as follow: + * + * - 31: Reserved + * - 30: Input hysteresis + * - 29: Input capability of IO + * - 28..27: Reserved + * - 26..24: IO mode + * - 23..22: Reserved + * - 21..20: Wakeup configuration from shutdown + * - 19: Reserved + * - 18: Wakeup capability from standby + * - 17..16: Edge detection configuration + * - 15: Reserved + * - 14..13: Pull control + * - 12..3: Reserved + * - 2..0: Function configuration + */ + +/* TI CC23X0 function configuration */ + +#define IOC_PORTCFG_BASE 0U +#define IOC_PORTCFG_PFUNC1 1U +#define IOC_PORTCFG_PFUNC2 2U +#define IOC_PORTCFG_PFUNC3 3U +#define IOC_PORTCFG_PFUNC4 4U +#define IOC_PORTCFG_PFUNC5 5U +#define IOC_PORTCFG_ANA 6U +#define IOC_PORTCFG_DTB 7U + +/* TI CC23X0 peripheral pin mapping */ + +#define DIO0_GPIO0 IOC_PORTCFG_BASE +#define DIO0_SPI0_CSN IOC_PORTCFG_PFUNC1 +#define DIO0_I2C0_SDA IOC_PORTCFG_PFUNC2 +#define DIO0_T3_C2 IOC_PORTCFG_PFUNC3 +#define DIO0_ADC5 IOC_PORTCFG_ANA + +#define DIO1_GPIO1 IOC_PORTCFG_BASE +#define DIO1_T3_C1 IOC_PORTCFG_PFUNC1 +#define DIO1_LRFD7 IOC_PORTCFG_PFUNC2 +#define DIO1_T1_F IOC_PORTCFG_PFUNC3 +#define DIO1_UART0_RTS IOC_PORTCFG_PFUNC4 +#define DIO1_ADC4 IOC_PORTCFG_ANA +#define DIO1_DTB2 IOC_PORTCFG_DTB + +#define DIO2_GPIO2 IOC_PORTCFG_BASE +#define DIO2_T0_PE IOC_PORTCFG_PFUNC1 +#define DIO2_T2_C1N IOC_PORTCFG_PFUNC2 +#define DIO2_UART0_CTS IOC_PORTCFG_PFUNC3 +#define DIO2_ADC3 IOC_PORTCFG_ANA + +#define DIO3_GPIO3 IOC_PORTCFG_BASE +#define DIO3_LFCI IOC_PORTCFG_PFUNC1 +#define DIO3_T0_C1N IOC_PORTCFG_PFUNC2 +#define DIO3_LRFD0 IOC_PORTCFG_PFUNC3 +#define DIO3_T3_C1 IOC_PORTCFG_PFUNC4 +#define DIO3_T1_C2 IOC_PORTCFG_PFUNC5 +#define DIO3_LFXT_P IOC_PORTCFG_ANA +#define DIO3_DTB7 IOC_PORTCFG_DTB + +#define DIO4_GPIO4 IOC_PORTCFG_BASE +#define DIO4_T0_C2N IOC_PORTCFG_PFUNC1 +#define DIO4_UART0_TXD IOC_PORTCFG_PFUNC2 +#define DIO4_LRFD1 IOC_PORTCFG_PFUNC3 +#define DIO4_SPI0_MOSI IOC_PORTCFG_PFUNC4 +#define DIO4_T0_C2 IOC_PORTCFG_PFUNC5 +#define DIO4_LFXT_N IOC_PORTCFG_ANA +#define DIO4_DTB8 IOC_PORTCFG_DTB + +#define DIO5_GPIO5 IOC_PORTCFG_BASE +#define DIO5_T2_C2 IOC_PORTCFG_PFUNC1 +#define DIO5_LRFD6 IOC_PORTCFG_PFUNC3 +#define DIO5_ADC2 IOC_PORTCFG_ANA + +#define DIO6_GPIO6 IOC_PORTCFG_BASE +#define DIO6_SPI0_CSN IOC_PORTCFG_PFUNC1 +#define DIO6_I2C0_SCL IOC_PORTCFG_PFUNC2 +#define DIO6_T1_C2 IOC_PORTCFG_PFUNC3 +#define DIO6_LRFD2 IOC_PORTCFG_PFUNC4 +#define DIO6_UART0_TXD IOC_PORTCFG_PFUNC5 +#define DIO6_ADC1_AREFP IOC_PORTCFG_ANA +#define DIO6_DTB6 IOC_PORTCFG_DTB + +#define DIO7_GPIO7 IOC_PORTCFG_BASE +#define DIO7_T3_C1 IOC_PORTCFG_PFUNC1 +#define DIO7_LRFD4 IOC_PORTCFG_PFUNC3 +#define DIO7_ADC0_AREFM IOC_PORTCFG_ANA + +#define DIO8_GPIO8 IOC_PORTCFG_BASE +#define DIO8_SPI0_SCLK IOC_PORTCFG_PFUNC1 +#define DIO8_UART0_RTS IOC_PORTCFG_PFUNC2 +#define DIO8_T1_C0N IOC_PORTCFG_PFUNC3 +#define DIO8_I2C0_SDA IOC_PORTCFG_PFUNC4 +#define DIO8_T0_C0N IOC_PORTCFG_PFUNC5 +#define DIO8_DTB3 IOC_PORTCFG_DTB + +#define DIO9_GPIO9 IOC_PORTCFG_BASE +#define DIO9_T3_C0 IOC_PORTCFG_PFUNC1 +#define DIO9_LRFD3 IOC_PORTCFG_PFUNC3 + +#define DIO10_GPIO10 IOC_PORTCFG_BASE +#define DIO10_LPC0 IOC_PORTCFG_PFUNC1 +#define DIO10_T2_PE IOC_PORTCFG_PFUNC2 +#define DIO10_T3_C0N IOC_PORTCFG_PFUNC3 + +#define DIO11_GPIO11 IOC_PORTCFG_BASE +#define DIO11_SPI0_CSN IOC_PORTCFG_PFUNC1 +#define DIO11_T1_C2N IOC_PORTCFG_PFUNC2 +#define DIO11_T0_C0 IOC_PORTCFG_PFUNC3 +#define DIO11_LRFD0 IOC_PORTCFG_PFUNC4 +#define DIO11_SPI0_MISO IOC_PORTCFG_PFUNC5 +#define DIO11_DTB9 IOC_PORTCFG_DTB + +#define DIO12_GPIO12 IOC_PORTCFG_BASE +#define DIO12_SPI0_MISO IOC_PORTCFG_PFUNC1 +#define DIO12_SPI0_MOSI IOC_PORTCFG_PFUNC2 +#define DIO12_UART0_RXD IOC_PORTCFG_PFUNC3 +#define DIO12_T1_C1 IOC_PORTCFG_PFUNC4 +#define DIO12_I2C0_SDA IOC_PORTCFG_PFUNC5 +#define DIO12_DTB13 IOC_PORTCFG_DTB + +#define DIO13_GPIO13 IOC_PORTCFG_BASE +#define DIO13_SPI0_MISO IOC_PORTCFG_PFUNC1 +#define DIO13_SPI0_MOSI IOC_PORTCFG_PFUNC2 +#define DIO13_UART0_TXD IOC_PORTCFG_PFUNC3 +#define DIO13_T0_C0N IOC_PORTCFG_PFUNC4 +#define DIO13_T1_F IOC_PORTCFG_PFUNC5 +#define DIO13_DTB4 IOC_PORTCFG_DTB + +#define DIO14_GPIO14 IOC_PORTCFG_BASE +#define DIO14_T3_C2 IOC_PORTCFG_PFUNC1 +#define DIO14_T1_C2N IOC_PORTCFG_PFUNC2 +#define DIO14_LRFD5 IOC_PORTCFG_PFUNC3 +#define DIO14_T1_F IOC_PORTCFG_PFUNC4 + +#define DIO15_GPIO15 IOC_PORTCFG_BASE +#define DIO15_UART0_RXD IOC_PORTCFG_PFUNC1 +#define DIO15_T2_C0N IOC_PORTCFG_PFUNC2 +#define DIO15_CKMIN IOC_PORTCFG_PFUNC3 + +#define DIO16_GPIO16 IOC_PORTCFG_BASE +#define DIO16_SPI0_MOSI IOC_PORTCFG_PFUNC1 +#define DIO16_UART0_RXD IOC_PORTCFG_PFUNC2 +#define DIO16_I2C0_SDA IOC_PORTCFG_PFUNC3 +#define DIO16_T1_C2 IOC_PORTCFG_PFUNC4 +#define DIO16_T1_C0N IOC_PORTCFG_PFUNC5 +#define DIO16_DTB10 IOC_PORTCFG_DTB + +#define DIO17_GPIO17 IOC_PORTCFG_BASE +#define DIO17_SPI0_SCLK IOC_PORTCFG_PFUNC1 +#define DIO17_UART0_TXD IOC_PORTCFG_PFUNC2 +#define DIO17_I2C0_SCL IOC_PORTCFG_PFUNC3 +#define DIO17_T1_C1N IOC_PORTCFG_PFUNC4 +#define DIO17_T0_C2 IOC_PORTCFG_PFUNC5 +#define DIO17_DTB11 IOC_PORTCFG_DTB + +#define DIO18_GPIO18 IOC_PORTCFG_BASE +#define DIO18_T3_C0 IOC_PORTCFG_PFUNC1 +#define DIO18_LPC0 IOC_PORTCFG_PFUNC2 +#define DIO18_UART0_TXD IOC_PORTCFG_PFUNC3 +#define DIO18_SPI0_SCLK IOC_PORTCFG_PFUNC4 +#define DIO18_DTB12 IOC_PORTCFG_DTB + +#define DIO19_GPIO19 IOC_PORTCFG_BASE +#define DIO19_T3_C1 IOC_PORTCFG_PFUNC1 +#define DIO19_T2_PE IOC_PORTCFG_PFUNC2 +#define DIO19_SPI0_MOSI IOC_PORTCFG_PFUNC4 +#define DIO19_DTB0 IOC_PORTCFG_DTB + +#define DIO20_GPIO20 IOC_PORTCFG_BASE +#define DIO20_LPC0 IOC_PORTCFG_PFUNC1 +#define DIO20_UART0_TXD IOC_PORTCFG_PFUNC2 +#define DIO20_UART0_RXD IOC_PORTCFG_PFUNC3 +#define DIO20_T1_C0 IOC_PORTCFG_PFUNC4 +#define DIO20_SPI0_MISO IOC_PORTCFG_PFUNC5 +#define DIO20_ADC11 IOC_PORTCFG_ANA +#define DIO20_DTB14 IOC_PORTCFG_DTB + +#define DIO21_GPIO21 IOC_PORTCFG_BASE +#define DIO21_UART0_CTS IOC_PORTCFG_PFUNC1 +#define DIO21_T1_C1N IOC_PORTCFG_PFUNC2 +#define DIO21_T0_C1 IOC_PORTCFG_PFUNC3 +#define DIO21_SPI0_MISO IOC_PORTCFG_PFUNC4 +#define DIO21_LRFD1 IOC_PORTCFG_PFUNC5 +#define DIO21_ADC10_LPCP IOC_PORTCFG_ANA +#define DIO21_DTB15 IOC_PORTCFG_DTB + +#define DIO22_GPIO22 IOC_PORTCFG_BASE +#define DIO22_T2_C0 IOC_PORTCFG_PFUNC1 +#define DIO22_UART0_RXD IOC_PORTCFG_PFUNC2 +#define DIO22_T3_C1N IOC_PORTCFG_PFUNC3 +#define DIO22_ADC9 IOC_PORTCFG_ANA +#define DIO22_DTB1 IOC_PORTCFG_DTB + +#define DIO23_GPIO23 IOC_PORTCFG_BASE +#define DIO23_T2_C1 IOC_PORTCFG_PFUNC1 +#define DIO23_T3_C2N IOC_PORTCFG_PFUNC3 +#define DIO23_ADC8_LPCP_LPCM IOC_PORTCFG_ANA + +#define DIO24_GPIO24 IOC_PORTCFG_BASE +#define DIO24_SPI0_SCLK IOC_PORTCFG_PFUNC1 +#define DIO24_T1_C0 IOC_PORTCFG_PFUNC2 +#define DIO24_T3_C0 IOC_PORTCFG_PFUNC3 +#define DIO24_T0_PE IOC_PORTCFG_PFUNC4 +#define DIO24_I2C0_SCL IOC_PORTCFG_PFUNC5 +#define DIO24_ADC7_LPCP_LPCM IOC_PORTCFG_ANA +#define DIO24_DTB5 IOC_PORTCFG_DTB + +#define DIO25_GPIO25 IOC_PORTCFG_BASE +#define DIO25_SPI0_MISO IOC_PORTCFG_PFUNC1 +#define DIO25_I2C0_SCL IOC_PORTCFG_PFUNC2 +#define DIO25_T2_C2N IOC_PORTCFG_PFUNC3 +#define DIO25_ADC6 IOC_PORTCFG_ANA + +#endif /* CC23X0_PINCTRL_COMMON_H_ */ diff --git a/soc/ti/simplelink/cc23x0/pinctrl_soc.h b/soc/ti/simplelink/cc23x0/pinctrl_soc.h new file mode 100644 index 0000000000000..4c2c6fefd1605 --- /dev/null +++ b/soc/ti/simplelink/cc23x0/pinctrl_soc.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TI_SIMPLELINK_CC23X0_SOC_PINCTRL_H_ +#define TI_SIMPLELINK_CC23X0_SOC_PINCTRL_H_ + +#include + +/* IO enabling/disabling */ +#define IOC_INPUT_ENABLE BIT(29) +#define IOC_INPUT_DISABLE 0U +#define IOC_HYST_ENABLE BIT(30) +#define IOC_HYST_DISABLE 0U + +/* IO modes */ +#define IOC_IOMODE_NORMAL 0U +#define IOC_IOMODE_INV BIT(24) +#define IOC_IOMODE_OPEN_DRAIN_NORMAL BIT(25) +#define IOC_IOMODE_OPEN_DRAIN_INV GENMASK(25, 24) +#define IOC_IOMODE_OPEN_SRC_NORMAL BIT(26) +#define IOC_IOMODE_OPEN_SRC_INV (BIT(26) | BIT(24)) + +/* IO pull */ +#define IOC_NO_IOPULL 0U +#define IOC_IOPULL_UP BIT(14) +#define IOC_IOPULL_DOWN BIT(13) + +typedef struct pinctrl_soc_pin { + uint32_t pin; + uint32_t iofunc; + uint32_t iomode; +} pinctrl_soc_pin_t; + +/* Convert DT flags to SoC flags */ +#define CC23X0_PIN_FLAGS(node_id) \ + (DT_PROP(node_id, bias_pull_up) * IOC_IOPULL_UP | \ + DT_PROP(node_id, bias_pull_down) * IOC_IOPULL_DOWN | \ + DT_PROP(node_id, bias_disable) * IOC_NO_IOPULL | \ + DT_PROP(node_id, drive_open_drain) * IOC_IOMODE_OPEN_DRAIN_NORMAL | \ + DT_PROP(node_id, drive_open_source) * IOC_IOMODE_OPEN_SRC_NORMAL | \ + DT_PROP(node_id, input_enable) * IOC_INPUT_ENABLE | \ + DT_PROP(node_id, input_schmitt_enable) * IOC_HYST_ENABLE) + +#define CC23X0_DT_PIN(node_id) \ + {.pin = DT_PROP_BY_IDX(node_id, pinmux, 0), \ + .iofunc = DT_PROP_BY_IDX(node_id, pinmux, 1), \ + .iomode = CC23X0_PIN_FLAGS(node_id)}, + +#define Z_PINCTRL_STATE_PIN_INIT(node_id, prop, idx) \ + CC23X0_DT_PIN(DT_PROP_BY_IDX(node_id, prop, idx)) + +#define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \ + {DT_FOREACH_PROP_ELEM(node_id, prop, Z_PINCTRL_STATE_PIN_INIT)} + +#endif /* TI_SIMPLELINK_CC23X0_SOC_PINCTRL_H_ */ From d9639c2ad30b2422c677f7190dd2f7ad4a413d13 Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Wed, 24 Jul 2024 16:25:08 +0200 Subject: [PATCH 10/18] dts: arm: ti: cc23x0: Add pinctrl support Add support for pinctrl to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc23x0.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index e2d93bdb29ee7..aa54498885331 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -56,6 +56,11 @@ write-block-size = <0x10>; }; }; + + pinctrl: pinctrl@40003000 { + compatible = "ti,cc23x0-pinctrl"; + reg = <0x40003000 0xc14>; + }; }; }; From 8fc80b0471c2c28166dbe82be0418a1fc3000833 Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:47:47 +0200 Subject: [PATCH 11/18] drivers: timer: Add support for cc23x0 systim Add support for systim to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/timer/CMakeLists.txt | 1 + drivers/timer/Kconfig | 1 + drivers/timer/Kconfig.cc23x0_systim | 13 ++ drivers/timer/cc23x0_systim_timer.c | 154 ++++++++++++++++++++++++ dts/bindings/timer/ti,cc23x0-timer.yaml | 15 +++ 5 files changed, 184 insertions(+) create mode 100644 drivers/timer/Kconfig.cc23x0_systim create mode 100644 drivers/timer/cc23x0_systim_timer.c create mode 100644 dts/bindings/timer/ti,cc23x0-timer.yaml diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 51b0e552f4a41..9a6b2697e988c 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_ARCV2_TIMER arcv2_timer0.c) zephyr_library_sources_ifdef(CONFIG_ARM_ARCH_TIMER arm_arch_timer.c) zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_timer.c) zephyr_library_sources_ifdef(CONFIG_CC13XX_CC26XX_RTC_TIMER cc13xx_cc26xx_rtc_timer.c) +zephyr_library_sources_ifdef(CONFIG_CC23X0_SYSTIM_TIMER cc23x0_systim_timer.c) zephyr_library_sources_ifdef(CONFIG_CH32V00X_SYSTICK wch_systick_ch32v00x.c) zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c) zephyr_library_sources_ifdef(CONFIG_ESP32_SYS_TIMER esp32_sys_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index f017589a60e18..839dec71fa26b 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -70,6 +70,7 @@ source "drivers/timer/Kconfig.arcv2" source "drivers/timer/Kconfig.arm_arch" source "drivers/timer/Kconfig.cavs" source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc" +source "drivers/timer/Kconfig.cc23x0_systim" source "drivers/timer/Kconfig.wch_ch32v00x" source "drivers/timer/Kconfig.cortex_m_systick" source "drivers/timer/Kconfig.esp32" diff --git a/drivers/timer/Kconfig.cc23x0_systim b/drivers/timer/Kconfig.cc23x0_systim new file mode 100644 index 0000000000000..41db73e6d52c6 --- /dev/null +++ b/drivers/timer/Kconfig.cc23x0_systim @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config CC23X0_SYSTIM_TIMER + bool "TI SimpleLink CC23X0 system clock timer" + default y + depends on HAS_CC23X0_SDK + select TICKLESS_CAPABLE + help + This module provides the "system clock driver" interfaces + for the TI Simplelink CC23X0 devices. diff --git a/drivers/timer/cc23x0_systim_timer.c b/drivers/timer/cc23x0_systim_timer.c new file mode 100644 index 0000000000000..1bc264ba179b2 --- /dev/null +++ b/drivers/timer/cc23x0_systim_timer.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_systim_timer + +/* + * TI SimpleLink CC23X0 timer driver based on SYSTIM + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Kernel tick period in microseconds (same timebase as systim) */ +#define TICK_PERIOD_MICRO_SEC (1000000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +/* + * Max number of systim ticks into the future + * + * Under the hood, the kernel timer uses the SysTimer whose events trigger + * immediately if the compare value is less than 2^22 systimer ticks in the past + * (4.194sec at 1us resolution). Therefore, the max number of SysTimer ticks you + * can schedule into the future is 2^32 - 2^22 - 1 ticks (~= 4290 sec at 1us + * resolution). + */ +#define SYSTIM_TIMEOUT_MAX 0xFFBFFFFFU + +/* Set systim interrupt to lowest priority */ +#define SYSTIM_ISR_PRIORITY 3U + +/* Keep track of systim counter at previous announcement to the kernel */ +static uint32_t last_systim_count; + +static void systim_isr(const void *arg); +static int sys_clock_driver_init(void); + +/* + * Set system clock timeout. + */ +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + + /* If timeout is necessary */ + if (ticks != K_TICKS_FOREVER) { + /* Get current value as early as possible */ + uint32_t now_tick = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); + uint32_t timeout = ticks * TICK_PERIOD_MICRO_SEC; + + if (timeout > SYSTIM_TIMEOUT_MAX) { + timeout = SYSTIM_TIMEOUT_MAX; + } + /* This should wrap around */ + HWREG(SYSTIM_BASE + SYSTIM_O_CH0CC) = now_tick + timeout; + } +} + +uint32_t sys_clock_elapsed(void) +{ + /* Get current value as early as possible */ + uint32_t current_systim_count = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); + uint32_t elapsed_systim; + + if (current_systim_count >= last_systim_count) { + elapsed_systim = current_systim_count - last_systim_count; + } else { + elapsed_systim = (UINT32_MAX - last_systim_count) + current_systim_count; + } + + int32_t elapsed_ticks = elapsed_systim / TICK_PERIOD_MICRO_SEC; + + return elapsed_ticks; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); +} + +void systim_isr(const void *arg) +{ + /* Get current value as early as possible */ + uint32_t current_systim_count = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); + uint32_t elapsed_systim; + + if (current_systim_count >= last_systim_count) { + elapsed_systim = current_systim_count - last_systim_count; + } else { + elapsed_systim = (UINT32_MAX - last_systim_count) + current_systim_count; + } + + int32_t elapsed_ticks = elapsed_systim / TICK_PERIOD_MICRO_SEC; + + sys_clock_announce(elapsed_ticks); + + last_systim_count = current_systim_count; + + /* Do not re-arm systim. Zephyr will do so through sys_clock_set_timeout */ +} + +static int sys_clock_driver_init(void) +{ + uint32_t now_tick; + + /* Get current value as early as possible */ + now_tick = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); + last_systim_count = now_tick; + + /* Clear any pending interrupts on SysTimer channel 0 */ + HWREG(SYSTIM_BASE + SYSTIM_O_ICLR) = SYSTIM_ICLR_EV0_CLR; + + /* + * Configure SysTimer channel 0 to compare mode with timer + * resolution of 1 us. + */ + HWREG(SYSTIM_BASE + SYSTIM_O_CH0CFG) = 0; + + /* Make SysTimer halt on CPU debug halt */ + HWREG(SYSTIM_BASE + SYSTIM_O_EMU) = SYSTIM_EMU_HALT_STOP; + + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) = EVTSVT_CPUIRQ16SEL_PUBID_SYSTIM0; + + /* + * Set IMASK for channel 0. IMASK is used by the power driver to know + * which systimer channels are active. + */ + HWREG(SYSTIM_BASE + SYSTIM_O_IMSET) = SYSTIM_IMSET_EV0_SET; + + /* This should wrap around and set a maximum timeout */ + HWREG(SYSTIM_BASE + SYSTIM_O_CH0CC) = now_tick + SYSTIM_TIMEOUT_MAX; + + /* Take configurable interrupt IRQ16 for systimer */ + IRQ_CONNECT(CPUIRQ16_IRQn, SYSTIM_ISR_PRIORITY, systim_isr, 0, 0); + irq_enable(CPUIRQ16_IRQn); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/bindings/timer/ti,cc23x0-timer.yaml b/dts/bindings/timer/ti,cc23x0-timer.yaml new file mode 100644 index 0000000000000..94b70e1a145ec --- /dev/null +++ b/dts/bindings/timer/ti,cc23x0-timer.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Baylibre SAS +# SPDX-License-Identifier: Apache-2.0 + +description: TI SimpleLink CC23x0 Timer Node + +compatible: "ti,cc23x0-systim-timer" + +include: base.yaml + +properties: + reg: + required: true + + interrupts: + required: true From 524298a5df83110cba0c9dabdbb22aee64e1b40d Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:49:11 +0200 Subject: [PATCH 12/18] drivers: gpio: Add support for cc23x0 GPIO Add support for GPIO to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/gpio/CMakeLists.txt | 1 + drivers/gpio/Kconfig | 1 + drivers/gpio/Kconfig.cc23x0 | 11 + drivers/gpio/gpio_cc23x0.c | 281 ++++++++++++++++++++++++++ dts/bindings/gpio/ti,cc23x0-gpio.yaml | 24 +++ 5 files changed, 318 insertions(+) create mode 100644 drivers/gpio/Kconfig.cc23x0 create mode 100644 drivers/gpio/gpio_cc23x0.c create mode 100644 dts/bindings/gpio/ti,cc23x0-gpio.yaml diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 1cfc120ff28cd..9ab88460ba550 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_BCM2711 gpio_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BD8LB600FS gpio_bd8lb600fs.c) zephyr_library_sources_ifdef(CONFIG_GPIO_BRCMSTB gpio_brcmstb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC13XX_CC26XX gpio_cc13xx_cc26xx.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_CC23X0 gpio_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CC32XX gpio_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CMSDK_AHB gpio_cmsdk_ahb.c) zephyr_library_sources_ifdef(CONFIG_GPIO_CY8C95XX gpio_cy8c95xx.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 668691de9276d..66e7a0641512e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -107,6 +107,7 @@ source "drivers/gpio/Kconfig.bcm2711" source "drivers/gpio/Kconfig.bd8lb600fs" source "drivers/gpio/Kconfig.brcmstb" source "drivers/gpio/Kconfig.cc13xx_cc26xx" +source "drivers/gpio/Kconfig.cc23x0" source "drivers/gpio/Kconfig.cc32xx" source "drivers/gpio/Kconfig.cmsdk_ahb" source "drivers/gpio/Kconfig.creg_gpio" diff --git a/drivers/gpio/Kconfig.cc23x0 b/drivers/gpio/Kconfig.cc23x0 new file mode 100644 index 0000000000000..147fd029cf2cd --- /dev/null +++ b/drivers/gpio/Kconfig.cc23x0 @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_CC23X0 + bool "TI SimpleLink CC23X0 GPIO driver" + default y + depends on DT_HAS_TI_CC23X0_GPIO_ENABLED + help + Enable the TI SimpleLink CC23x0 GPIO driver. diff --git a/drivers/gpio/gpio_cc23x0.c b/drivers/gpio/gpio_cc23x0.c new file mode 100644 index 0000000000000..643766e255d29 --- /dev/null +++ b/drivers/gpio/gpio_cc23x0.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_gpio + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define IOC_ADDR(index) (IOC_BASE + IOC_O_IOC0 + (sizeof(uint32_t) * (index))) + +struct gpio_cc23x0_config { + /* gpio_driver_config needs to be first */ + struct gpio_driver_config common; +}; + +struct gpio_cc23x0_data { + /* gpio_driver_data needs to be first */ + struct gpio_driver_data common; + sys_slist_t callbacks; +}; + +static void set_pin_mask_non_atomic(uint8_t index, uint32_t registerBaseAddress) +{ + GPIOSetConfigDio(GPIO_BASE + registerBaseAddress, BIT(index)); +} + +static int gpio_cc23x0_config(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + uint32_t config = 0; + uint32_t iocfg_reg = IOC_ADDR(pin); + gpio_flags_t direction = flags & GPIO_DIR_MASK; + + if (flags & GPIO_PULL_UP) { + config |= IOC_IOC0_PULLCTL_PULL_UP; + } else if (flags & GPIO_PULL_DOWN) { + config |= IOC_IOC0_PULLCTL_PULL_DOWN; + } else { + config |= IOC_IOC0_PULLCTL_PULL_DIS; + } + + if (!(flags & GPIO_SINGLE_ENDED)) { + config |= IOC_IOC0_IOMODE_NORMAL; + } else { + if (flags & GPIO_LINE_OPEN_DRAIN) { + config |= IOC_IOC0_IOMODE_OPEND; + } else { + config |= IOC_IOC0_IOMODE_OPENS; + } + } + if (direction & GPIO_INPUT) { + config |= IOC_IOC0_INPEN_EN | IOC_IOC0_HYSTEN_EN; + } + + GPIOSetConfigDio(iocfg_reg, config); + + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_OUTPUT_INIT_HIGH) { + GPIOSetDio(pin); + } else if (flags & GPIO_OUTPUT_INIT_LOW) { + GPIOClearDio(pin); + } + GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_ENABLE); + } else { + GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_DISABLE); + } + return 0; +} + +#ifdef CONFIG_GPIO_GET_CONFIG +static int gpio_cc23x0_get_config(const struct device *port, gpio_pin_t pin, gpio_flags_t *flags) +{ + uint32_t out_flag = 0; + uint32_t iocfg_reg = IOC_ADDR(pin); + uint32_t config = GPIOGetConfigDio(iocfg_reg); + + /* GPIO input/output configuration flags */ + if (config & IOC_IOC0_INPEN_EN) { + out_flag |= GPIO_INPUT; + } + + if (GPIOGetOutputEnableDio(pin)) { + out_flag |= GPIO_OUTPUT; + + if (GPIOReadDio(pin)) { + out_flag |= GPIO_OUTPUT_INIT_HIGH; + } else { + /* This is the default value. If not explicitly set, + * the returned config will not be symmetric + */ + out_flag |= GPIO_OUTPUT_INIT_LOW; + } + } + + /* GPIO interrupt configuration flags */ + if ((config & IOC_IOC0_EDGEDET_M) != IOC_IOC0_EDGEDET_EDGE_DIS) { + if (config & IOC_IOC0_EDGEDET_EDGE_POS) { + out_flag |= GPIO_INT_EDGE_RISING; + } + + if (config & IOC_IOC0_EDGEDET_EDGE_NEG) { + out_flag |= GPIO_INT_EDGE_FALLING; + } + } else { + /* This is the default value. If not explicitly set, + * the returned config will not be symmetric + */ + out_flag |= GPIO_INT_DISABLE; + } + + /* GPIO pin drive flags */ + if (config & IOC_IOC0_IOMODE_OPENS) { + out_flag |= GPIO_OPEN_SOURCE; + } + + if (config & IOC_IOC0_IOMODE_OPEND) { + out_flag |= IOC_IOC0_IOMODE_OPEND; + } + + if (config & IOC_IOC0_PULLCTL_PULL_UP) { + out_flag |= GPIO_PULL_UP; + } + + if (config & IOC_IOC0_PULLCTL_PULL_DOWN) { + out_flag |= GPIO_PULL_DOWN; + } + + *flags = out_flag; + + return 0; +} +#endif + +static int gpio_cc23x0_port_get_raw(const struct device *port, uint32_t *value) +{ + *value = GPIOReadMultiDio(GPIO_DIO_ALL_MASK); + + return 0; +} + +static int gpio_cc23x0_port_set_masked_raw(const struct device *port, uint32_t mask, uint32_t value) +{ + GPIOWriteMultiDio(mask, value); + + return 0; +} + +static int gpio_cc23x0_port_set_bits_raw(const struct device *port, uint32_t mask) +{ + GPIOSetMultiDio(mask); + + return 0; +} + +static int gpio_cc23x0_port_clear_bits_raw(const struct device *port, uint32_t mask) +{ + GPIOClearMultiDio(mask); + + return 0; +} + +static int gpio_cc23x0_port_toggle_bits(const struct device *port, uint32_t mask) +{ + GPIOToggleMultiDio(mask); + + return 0; +} + +static int gpio_cc23x0xx_pin_interrupt_configure(const struct device *port, gpio_pin_t pin, + enum gpio_int_mode mode, enum gpio_int_trig trig) +{ + if (mode == GPIO_INT_MODE_LEVEL) { + return ENOTSUP; + } + + uint32_t config = GPIOGetConfigDio(IOC_ADDR(pin)) & ~IOC_IOC0_EDGEDET_M; + + if (mode == GPIO_INT_MODE_DISABLED) { + config |= IOC_IOC1_EDGEDET_EDGE_DIS; + + GPIOSetConfigDio(IOC_ADDR(pin), config); + + /* Disable interrupt mask */ + set_pin_mask_non_atomic(pin, GPIO_O_IMCLR); + + } else if (mode == GPIO_INT_MODE_EDGE) { + switch (trig) { + case GPIO_INT_TRIG_LOW: + config |= IOC_IOC1_EDGEDET_EDGE_NEG; + break; + case GPIO_INT_TRIG_HIGH: + config |= IOC_IOC1_EDGEDET_EDGE_POS; + break; + case GPIO_INT_TRIG_BOTH: + config |= IOC_IOC1_EDGEDET_EDGE_BOTH; + break; + default: + return ENOTSUP; + } + + GPIOSetConfigDio(IOC_ADDR(pin), config); + + /* Enable interrupt mask */ + set_pin_mask_non_atomic(pin, GPIO_O_ICLR); + set_pin_mask_non_atomic(pin, GPIO_O_IMSET); + } + + return 0; +} + +static int gpio_cc23x0_manage_callback(const struct device *port, struct gpio_callback *callback, + bool set) +{ + struct gpio_cc23x0_data *data = port->data; + + return gpio_manage_callback(&data->callbacks, callback, set); +} + +static uint32_t gpio_cc23x0_get_pending_int(const struct device *dev) +{ + return GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK); +} + +static void gpio_cc23x0_isr(const struct device *dev) +{ + struct gpio_cc23x0_data *data = dev->data; + + uint32_t status = GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK); + + GPIOClearEventMultiDio(status); + + gpio_fire_callbacks(&data->callbacks, dev, status); +} + +static int gpio_cc23x0_init(const struct device *dev) +{ + /* Enable GPIO domain clock */ + CLKCTLEnable(CLKCTL_BASE, CLKCTL_GPIO); + + /* Enable IRQ */ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), gpio_cc23x0_isr, + DEVICE_DT_INST_GET(0), 0); + + irq_enable(DT_INST_IRQN(0)); + + return 0; +} + +static const struct gpio_driver_api gpio_cc23x0_driver_api = { + .pin_configure = gpio_cc23x0_config, +#ifdef CONFIG_GPIO_GET_CONFIG + .pin_get_config = gpio_cc23x0_get_config, +#endif + .port_get_raw = gpio_cc23x0_port_get_raw, + .port_set_masked_raw = gpio_cc23x0_port_set_masked_raw, + .port_set_bits_raw = gpio_cc23x0_port_set_bits_raw, + .port_clear_bits_raw = gpio_cc23x0_port_clear_bits_raw, + .port_toggle_bits = gpio_cc23x0_port_toggle_bits, + .pin_interrupt_configure = gpio_cc23x0xx_pin_interrupt_configure, + .manage_callback = gpio_cc23x0_manage_callback, + .get_pending_int = gpio_cc23x0_get_pending_int, +}; + +static const struct gpio_cc23x0_config gpio_cc23x0_config_0 = { + .common = {/* Read ngpios from DT */ + .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}}; + +static struct gpio_cc23x0_data gpio_cc23x0_data_0; + +DEVICE_DT_INST_DEFINE(0, gpio_cc23x0_init, NULL, &gpio_cc23x0_data_0, &gpio_cc23x0_config_0, + PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_cc23x0_driver_api); diff --git a/dts/bindings/gpio/ti,cc23x0-gpio.yaml b/dts/bindings/gpio/ti,cc23x0-gpio.yaml new file mode 100644 index 0000000000000..ced5e1352d97a --- /dev/null +++ b/dts/bindings/gpio/ti,cc23x0-gpio.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +description: TI SimpleLink CC23X0 GPIO node + +compatible: "ti,cc23x0-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags From b10aa5af31bab17237313048bd1ea61ebebbd229 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:26:21 +0200 Subject: [PATCH 13/18] dts: arm: ti: cc23x0: Add GPIO support Add support for GPIO to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc23x0.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index aa54498885331..947543379a17f 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -61,6 +61,16 @@ compatible = "ti,cc23x0-pinctrl"; reg = <0x40003000 0xc14>; }; + + gpio0: gpio@40023000 { + compatible = "ti,cc23x0-gpio"; + reg = <0x40023000 0x804>; + interrupts = <5 0>; /* GPIO combined on CPUIRQ5 */ + status = "disabled"; + gpio-controller; + #gpio-cells = <2>; /* Pin (ID), and flags */ + ngpios = <26>; /* Only [DIO0, DIO25] are available */ + }; }; }; From 5cee38bd73d68a12498634e0580aab578b24817b Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:26:27 +0200 Subject: [PATCH 14/18] boards: ti: lp_em_cc2340r5: Add GPIO support Enable GPIO. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index 2a75adaba0b01..954f077cc2409 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -19,3 +19,7 @@ zephyr,code-partition = &slot0_partition; }; }; + +&gpio0 { + status = "okay"; +}; From 00142160bc0ea1721e116ca234e4154d954e886b Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:34:35 +0200 Subject: [PATCH 15/18] boards: ti: lp_em_cc2340r5: Add leds and keys support Add support for LEDs and buttons. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index 954f077cc2409..aad376e0690a4 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -8,6 +8,9 @@ /dts-v1/; #include +#include "boosterpack_connector.dtsi" +#include +#include / { model = "LP_EM_CC2340R5"; @@ -18,6 +21,43 @@ zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; }; + + aliases { + led0 = &led0; + led1 = &led1; + sw0 = &btn0; + sw1 = &btn1; + }; + + leds { + compatible = "gpio-leds"; + + led0: led_0 { + gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + + led1: led_1 { + gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + }; + + keys { + compatible = "gpio-keys"; + + btn0: btn_0 { + gpios = <&gpio0 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + label = "Button 1"; + zephyr,code = ; + }; + + btn1: btn_1 { + gpios = <&gpio0 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + label = "Button 2"; + zephyr,code = ; + }; + }; }; &gpio0 { From 6c59391866975b47fc7422b0dbfd34b0b747a011 Mon Sep 17 00:00:00 2001 From: Vebjorn Myklebust Date: Wed, 24 Jul 2024 14:53:31 +0200 Subject: [PATCH 16/18] drivers: serial: Add support for cc23x0 UART Add support for UART to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- drivers/serial/CMakeLists.txt | 1 + drivers/serial/Kconfig | 1 + drivers/serial/Kconfig.cc23x0 | 14 + drivers/serial/uart_cc23x0.c | 405 ++++++++++++++++++++++++ dts/bindings/serial/ti,cc23x0-uart.yaml | 33 ++ 5 files changed, 454 insertions(+) create mode 100644 drivers/serial/Kconfig.cc23x0 create mode 100644 drivers/serial/uart_cc23x0.c create mode 100644 dts/bindings/serial/ti,cc23x0-uart.yaml diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 8aeea35684b25..6c55d9d11247d 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c) zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c) zephyr_library_sources_ifdef(CONFIG_UART_BT uart_bt.c) zephyr_library_sources_ifdef(CONFIG_UART_CC13XX_CC26XX uart_cc13xx_cc26xx.c) +zephyr_library_sources_ifdef(CONFIG_UART_CC23X0 uart_cc23x0.c) zephyr_library_sources_ifdef(CONFIG_UART_CC32XX uart_cc32xx.c) zephyr_library_sources_ifdef(CONFIG_UART_CDNS uart_cdns.c) zephyr_library_sources_ifdef(CONFIG_UART_CMSDK_APB uart_cmsdk_apb.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2b1ff32c56622..92e68f90741f2 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -164,6 +164,7 @@ rsource "Kconfig.b91" rsource "Kconfig.bcm2711" rsource "Kconfig.bt" rsource "Kconfig.cc13xx_cc26xx" +rsource "Kconfig.cc23x0" rsource "Kconfig.cc32xx" rsource "Kconfig.cdns" rsource "Kconfig.cmsdk_apb" diff --git a/drivers/serial/Kconfig.cc23x0 b/drivers/serial/Kconfig.cc23x0 new file mode 100644 index 0000000000000..e285ee14671a8 --- /dev/null +++ b/drivers/serial/Kconfig.cc23x0 @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config UART_CC23X0 + bool "TI SimpleLink CC23x0 UART driver" + default y + depends on DT_HAS_TI_CC23X0_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + select PINCTRL + help + Enable the TI SimpleLink CC23x0 UART driver. diff --git a/drivers/serial/uart_cc23x0.c b/drivers/serial/uart_cc23x0.c new file mode 100644 index 0000000000000..5576871aacac7 --- /dev/null +++ b/drivers/serial/uart_cc23x0.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_uart + +#include +#include +#include +#include + +#include + +#include +#include + +struct uart_cc23x0_config { + uint32_t reg; + uint32_t sys_clk_freq; + const struct pinctrl_dev_config *pcfg; +}; + +struct uart_cc23x0_data { + struct uart_config uart_config; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t callback; + void *user_data; +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +static int uart_cc23x0_poll_in(const struct device *dev, unsigned char *c) +{ + const struct uart_cc23x0_config *config = dev->config; + + if (!UARTCharAvailable(config->reg)) { + return -1; + } + + *c = UARTGetCharNonBlocking(config->reg); + + return 0; +} + +static void uart_cc23x0_poll_out(const struct device *dev, unsigned char c) +{ + const struct uart_cc23x0_config *config = dev->config; + + UARTPutChar(config->reg, c); +} + +static int uart_cc23x0_err_check(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + uint32_t flags = UARTGetRxError(config->reg); + int error = 0; + + error |= (flags & UART_RXERROR_FRAMING) ? UART_ERROR_FRAMING : 0; + error |= (flags & UART_RXERROR_PARITY) ? UART_ERROR_PARITY : 0; + error |= (flags & UART_RXERROR_BREAK) ? UART_BREAK : 0; + error |= (flags & UART_RXERROR_OVERRUN) ? UART_ERROR_OVERRUN : 0; + + UARTClearRxError(config->reg); + + return error; +} + +static int uart_cc23x0_configure(const struct device *dev, const struct uart_config *cfg) +{ + const struct uart_cc23x0_config *config = dev->config; + struct uart_cc23x0_data *data = dev->data; + uint32_t line_ctrl = 0; + bool flow_ctrl; + + switch (cfg->parity) { + case UART_CFG_PARITY_NONE: + line_ctrl |= UART_CONFIG_PAR_NONE; + break; + case UART_CFG_PARITY_ODD: + line_ctrl |= UART_CONFIG_PAR_ODD; + break; + case UART_CFG_PARITY_EVEN: + line_ctrl |= UART_CONFIG_PAR_EVEN; + break; + case UART_CFG_PARITY_MARK: + line_ctrl |= UART_CONFIG_PAR_ONE; + break; + case UART_CFG_PARITY_SPACE: + line_ctrl |= UART_CONFIG_PAR_ZERO; + break; + default: + return -EINVAL; + } + + switch (cfg->stop_bits) { + case UART_CFG_STOP_BITS_1: + line_ctrl |= UART_CONFIG_STOP_ONE; + break; + case UART_CFG_STOP_BITS_2: + line_ctrl |= UART_CONFIG_STOP_TWO; + break; + case UART_CFG_STOP_BITS_0_5: + case UART_CFG_STOP_BITS_1_5: + return -ENOTSUP; + default: + return -EINVAL; + } + + switch (cfg->data_bits) { + case UART_CFG_DATA_BITS_5: + line_ctrl |= UART_CONFIG_WLEN_5; + break; + case UART_CFG_DATA_BITS_6: + line_ctrl |= UART_CONFIG_WLEN_6; + break; + case UART_CFG_DATA_BITS_7: + line_ctrl |= UART_CONFIG_WLEN_7; + break; + case UART_CFG_DATA_BITS_8: + line_ctrl |= UART_CONFIG_WLEN_8; + break; + default: + return -EINVAL; + } + + switch (cfg->flow_ctrl) { + case UART_CFG_FLOW_CTRL_NONE: + flow_ctrl = false; + break; + case UART_CFG_FLOW_CTRL_RTS_CTS: + flow_ctrl = true; + break; + case UART_CFG_FLOW_CTRL_DTR_DSR: + return -ENOTSUP; + default: + return -EINVAL; + } + + /* Disables UART before setting control registers */ + UARTConfigSetExpClk(config->reg, config->sys_clk_freq, cfg->baudrate, line_ctrl); + + if (flow_ctrl) { + UARTEnableCTS(config->reg); + UARTEnableRTS(config->reg); + } else { + UARTDisableCTS(config->reg); + UARTDisableRTS(config->reg); + } + + /* Re-enable UART */ + UARTEnable(config->reg); + + /* Make use of the FIFO to reduce chances of data being lost */ + UARTEnableFifo(config->reg); + + data->uart_config = *cfg; + + return 0; +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_cc23x0_config_get(const struct device *dev, struct uart_config *cfg) +{ + const struct uart_cc23x0_data *data = dev->data; + + *cfg = data->uart_config; + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + +static int uart_cc23x0_fifo_fill(const struct device *dev, const uint8_t *buf, int len) +{ + const struct uart_cc23x0_config *config = dev->config; + int n = 0; + + while (n < len) { + if (!UARTSpaceAvailable(config->reg)) { + break; + } + UARTPutCharNonBlocking(config->reg, buf[n]); + n++; + } + + return n; +} + +static int uart_cc23x0_fifo_read(const struct device *dev, uint8_t *buf, const int len) +{ + const struct uart_cc23x0_config *config = dev->config; + int c, n; + + n = 0; + while (n < len) { + if (!UARTCharAvailable(config->reg)) { + break; + } + c = UARTGetCharNonBlocking(config->reg); + buf[n++] = c; + } + + return n; +} + +static void uart_cc23x0_irq_tx_enable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + UARTEnableInt(config->reg, UART_INT_TX); +} + +static void uart_cc23x0_irq_tx_disable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + UARTDisableInt(config->reg, UART_INT_TX); +} + +static int uart_cc23x0_irq_tx_ready(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + return UARTSpaceAvailable(config->reg) ? 1 : 0; +} + +static void uart_cc23x0_irq_rx_enable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + /* Trigger the ISR on both RX and Receive Timeout. This is to allow + * the use of the hardware FIFOs for more efficient operation + */ + UARTEnableInt(config->reg, UART_INT_RX | UART_INT_RT); +} + +static void uart_cc23x0_irq_rx_disable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + UARTDisableInt(config->reg, UART_INT_RX | UART_INT_RT); +} + +static int uart_cc23x0_irq_tx_complete(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + return UARTBusy(config->reg) ? 0 : 1; +} + +static int uart_cc23x0_irq_rx_ready(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + return UARTCharAvailable(config->reg) ? 1 : 0; +} + +static void uart_cc23x0_irq_err_enable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + return UARTEnableInt(config->reg, UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); +} + +static void uart_cc23x0_irq_err_disable(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + return UARTDisableInt(config->reg, UART_INT_OE | UART_INT_BE | UART_INT_PE | UART_INT_FE); +} + +static int uart_cc23x0_irq_is_pending(const struct device *dev) +{ + const struct uart_cc23x0_config *config = dev->config; + + /* Read masked interrupt status */ + uint32_t status = UARTIntStatus(config->reg, true); + + return status ? 1 : 0; +} + +static int uart_cc23x0_irq_update(const struct device *dev) +{ + ARG_UNUSED(dev); + return 1; +} + +static void uart_cc23x0_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb, + void *user_data) +{ + struct uart_cc23x0_data *data = dev->data; + + data->callback = cb; + data->user_data = user_data; +} + +static void uart_cc23x0_isr(const struct device *dev) +{ + struct uart_cc23x0_data *data = dev->data; + + if (data->callback) { + data->callback(dev, data->user_data); + } +} + +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +static const struct uart_driver_api uart_cc23x0_driver_api = { + .poll_in = uart_cc23x0_poll_in, + .poll_out = uart_cc23x0_poll_out, + .err_check = uart_cc23x0_err_check, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_cc23x0_configure, + .config_get = uart_cc23x0_config_get, +#endif +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + .fifo_fill = uart_cc23x0_fifo_fill, + .fifo_read = uart_cc23x0_fifo_read, + .irq_tx_enable = uart_cc23x0_irq_tx_enable, + .irq_tx_disable = uart_cc23x0_irq_tx_disable, + .irq_tx_ready = uart_cc23x0_irq_tx_ready, + .irq_rx_enable = uart_cc23x0_irq_rx_enable, + .irq_rx_disable = uart_cc23x0_irq_rx_disable, + .irq_tx_complete = uart_cc23x0_irq_tx_complete, + .irq_rx_ready = uart_cc23x0_irq_rx_ready, + .irq_err_enable = uart_cc23x0_irq_err_enable, + .irq_err_disable = uart_cc23x0_irq_err_disable, + .irq_is_pending = uart_cc23x0_irq_is_pending, + .irq_update = uart_cc23x0_irq_update, + .irq_callback_set = uart_cc23x0_irq_callback_set, +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ +}; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN +#define UART_CC23X0_IRQ_CFG(n) \ + do { \ + UARTClearInt(config->reg, UART_INT_RX); \ + UARTClearInt(config->reg, UART_INT_RT); \ + \ + IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), uart_cc23x0_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + irq_enable(DT_INST_IRQN(n)); \ + } while (false) + +#define UART_CC23X0_INT_FIELDS .callback = NULL, .user_data = NULL, +#else +#define UART_CC23X0_IRQ_CFG(n) +#define UART_CC23X0_INT_FIELDS +#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ + +#define UART_CC23X0_DEVICE_DEFINE(n) \ + \ + DEVICE_DT_INST_DEFINE(n, uart_cc23x0_init_##n, NULL, &uart_cc23x0_data_##n, \ + &uart_cc23x0_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_cc23x0_driver_api) + +#define UART_CC23X0_INIT_FUNC(n) \ + static int uart_cc23x0_init_##n(const struct device *dev) \ + { \ + const struct uart_cc23x0_config *config = dev->config; \ + struct uart_cc23x0_data *data = dev->data; \ + int ret; \ + \ + CLKCTLEnable(CLKCTL_BASE, CLKCTL_UART0); \ + \ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); \ + if (ret < 0) { \ + return ret; \ + } \ + \ + /* Configure and enable UART */ \ + ret = uart_cc23x0_configure(dev, &data->uart_config); \ + \ + /* Enable interrupts */ \ + UART_CC23X0_IRQ_CFG(n); \ + \ + return ret; \ + } + +#define UART_CC23X0_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + UART_CC23X0_INIT_FUNC(n); \ + \ + static struct uart_cc23x0_config uart_cc23x0_config_##n = { \ + .reg = DT_INST_REG_ADDR(n), \ + .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct uart_cc23x0_data uart_cc23x0_data_##n = { \ + .uart_config = \ + { \ + .baudrate = DT_INST_PROP(n, current_speed), \ + .parity = DT_INST_ENUM_IDX(n, parity), \ + .stop_bits = DT_INST_ENUM_IDX(n, stop_bits), \ + .data_bits = DT_INST_ENUM_IDX(n, data_bits), \ + .flow_ctrl = DT_INST_PROP(n, hw_flow_control), \ + }, \ + UART_CC23X0_INT_FIELDS \ + }; \ + UART_CC23X0_DEVICE_DEFINE(n); + +DT_INST_FOREACH_STATUS_OKAY(UART_CC23X0_INIT) diff --git a/dts/bindings/serial/ti,cc23x0-uart.yaml b/dts/bindings/serial/ti,cc23x0-uart.yaml new file mode 100644 index 0000000000000..f2587a0a26761 --- /dev/null +++ b/dts/bindings/serial/ti,cc23x0-uart.yaml @@ -0,0 +1,33 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +description: TI SimpleLink CC23X0 UART node + +compatible: "ti,cc23x0-uart" + +include: [uart-controller.yaml, pinctrl-device.yaml, base.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + stop-bits: + description: | + Sets the number of stop bits. Defaults to standard of 1 if not specified. + default: "1" + + data-bits: + description: | + Sets the number of data bits. Defaults to standard of 8 if not specified. + default: 8 From 86c472d15f565283e853f89fceb298273d836d5d Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:37:42 +0200 Subject: [PATCH 17/18] dts: arm: ti: cc23x0: Add UART support Add support for UART to cc23x0 SoC. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- dts/arm/ti/cc23x0.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index 947543379a17f..6b307980ce3e7 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -71,6 +71,14 @@ #gpio-cells = <2>; /* Pin (ID), and flags */ ngpios = <26>; /* Only [DIO0, DIO25] are available */ }; + + uart0: uart@40034000 { + compatible = "ti,cc23x0-uart"; + reg = <0x40034000 0x52>; + interrupts = <11 0>; + clocks = <&sysclk>; + status = "disabled"; + }; }; }; From b2b01815696736a9e20b1583153666ab4409d0c5 Mon Sep 17 00:00:00 2001 From: Stoyan Bogdanov Date: Wed, 24 Jul 2024 16:38:51 +0200 Subject: [PATCH 18/18] boards: ti: lp_em_cc2340r5: Add UART support Enable UART. Signed-off-by: Lars Thalian Morstad Signed-off-by: Vebjorn Myklebust Signed-off-by: Stoyan Bogdanov Signed-off-by: Julien Panis --- .../lp_em_cc2340r5-pinctrl.dtsi | 21 +++++++++++++++++++ boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts | 10 +++++++++ 2 files changed, 31 insertions(+) create mode 100644 boards/ti/lp_em_cc2340r5/lp_em_cc2340r5-pinctrl.dtsi diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5-pinctrl.dtsi b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5-pinctrl.dtsi new file mode 100644 index 0000000000000..1d929cfa6acaa --- /dev/null +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5-pinctrl.dtsi @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + /* UART0 */ + uart0_tx_default: uart0_tx_default { + pinmux = <20 DIO20_UART0_TXD>; + bias-disable; + }; + uart0_rx_default: uart0_rx_default { + pinmux = <22 DIO22_UART0_RXD>; + bias-disable; + input-enable; + }; +}; diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index aad376e0690a4..64d3e15020750 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -9,6 +9,7 @@ #include #include "boosterpack_connector.dtsi" +#include "lp_em_cc2340r5-pinctrl.dtsi" #include #include @@ -20,6 +21,8 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; }; aliases { @@ -63,3 +66,10 @@ &gpio0 { status = "okay"; }; + +&uart0 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart0_rx_default &uart0_tx_default>; + pinctrl-names = "default"; +};