diff --git a/boards/tcc/index.rst b/boards/tcc/index.rst new file mode 100644 index 0000000000000..0cb1db732df0b --- /dev/null +++ b/boards/tcc/index.rst @@ -0,0 +1,10 @@ +.. _boards-tcc: + +Telechips, Inc. +###################### + +.. toctree:: + :maxdepth: 1 + :glob: + + **/* diff --git a/boards/tcc/topst_vcp45/Kconfig.defconfig b/boards/tcc/topst_vcp45/Kconfig.defconfig new file mode 100644 index 0000000000000..faccb6c7caab7 --- /dev/null +++ b/boards/tcc/topst_vcp45/Kconfig.defconfig @@ -0,0 +1,18 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_TOPST_VCP45 + +config BUILD_OUTPUT_BIN + default y + +config USERSPACE + default y + +config MAX_THREAD_BYTES + default 3 + +config BOUNDS_CHECK_BYPASS_MITIGATION + default y + +endif # BOARD_TOPST_VCP45 diff --git a/boards/tcc/topst_vcp45/Kconfig.topst_vcp45 b/boards/tcc/topst_vcp45/Kconfig.topst_vcp45 new file mode 100644 index 0000000000000..8dd365d4602ed --- /dev/null +++ b/boards/tcc/topst_vcp45/Kconfig.topst_vcp45 @@ -0,0 +1,5 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TOPST_VCP45 + select SOC_TCC7045 diff --git a/boards/tcc/topst_vcp45/board.yml b/boards/tcc/topst_vcp45/board.yml new file mode 100644 index 0000000000000..0ca2767d2da9e --- /dev/null +++ b/boards/tcc/topst_vcp45/board.yml @@ -0,0 +1,5 @@ +board: + name: topst_vcp45 + vendor: tcc + socs: + - name: tcc7045 diff --git a/boards/tcc/topst_vcp45/doc/index.rst b/boards/tcc/topst_vcp45/doc/index.rst new file mode 100644 index 0000000000000..82fdf051970ad --- /dev/null +++ b/boards/tcc/topst_vcp45/doc/index.rst @@ -0,0 +1,459 @@ +.. _topst_vcp45: + +TOPST_VCP45 +################### + +Overview +******** + +The TOPST_VCP45 is a 32-Bit MCU Board for Real time Applications. + +TOPST VCP can implement the following functions: + +* Automotive Application + Car Audio Video Navigation (AVN)System, Digital Cluster, Head Up Display (HUD), etc. +* IOT Application + Smart Factory, etc. +* Training & Education + Sensor, Actuator Application, CAN Application, etc. + +TOPST: Total Open-Platform for System development and Training + +VCP: Vehicle Control Processor + +Hardware +******** + +- ARM Cortex-R5F CPU +- 512KB(Including Retention RAM 16KB) SRAM +- 128KB Data Flash +- 1 Gbps with AVB Ethernet + +Supported Features +================== + +The following features are supported: + +.. list-table:: + :header-rows: 1 + + * - Peripheral + - Kconfig option + - Devicetree compatible + * - TIC + - :kconfig:option:`CONFIG_TIC` + - :dtcompatible:`tcc,tic` + * - GPIO + - :kconfig:option:`CONFIG_GPIO` & 'GPIO_TCCVCP' + - :dtcompatible:`tcc,tccvcp-gpio` + * - Timer + - :kconfig:option:`CONFIG_TCC_VCPTTC_TIMER` + - :dtcompatible:`tcc,ttcvcp` + * - Clock + - :kconfig:option:`CONFIG_CLOCK_CONTROL_TCC_CCU` + - :dtcompatible:`tcc,ccu` + +Not all hardware features are supported yet. See "TCC70xx Full Specification" for the complete list of hardware features. + +The default configuration can be found in + :zephyr_file:`boards/tcc/topst_vcp45/topst_vcp45_defconfig` + + + +Programming and Debugging +************************* + +hello_world +=========== + +zephyr.bin +---------- + +Build a Zephyr application, such as the hello world sample shown below: + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: topst_vcp45 + :goals: build + +When building an image for the topst_vcp45 board, build it by specifying the directory as follows: + +.. code-block:: console + + $ west build -b topst_vcp45 samples/hello_world + + +Creating a ROM Build Directory and Downloading Necessary Tools and Images +------------------------------------------------------------------------- +Create a ROM build directory and download the necessary tools and images, follow these steps: + +**1. Create the ROM Build Directory** + +.. code-block:: console + + $ mkdir rom-build + $ cd rom-build/ + +**2. Download the Required Tools and Images** + +**Downloading the Tools** + +Access the GitLab Repository: Navigate to the GitLab repository containing the necessary tools. +https://gitlab.com/topst.ai/topst-vcp/-/tree/main/tools?ref_type=heads + +Download the Tools: Select the Code dropdown menu on the right side of the page and choose Download this directory. + +Then, select the tar.gz file. + +Move the Downloaded File: Move the downloaded topst-vcp-main-tools.tar.gz file to your rom-build directory. + + +**Downloading the Prebuilt Images** + +Access the GitLab Repository: Navigate to the GitLab repository containing the prebuilt images. +https://gitlab.com/topst.ai/topst-vcp/-/tree/main/build/tcc70xx/make_utility?ref_type=heads + +Download the Images: Select the Code dropdown menu on the right side of the page and choose Download this directory. + +Then, select the tar.gz file. + +Move the Downloaded File: Move the downloaded topst-vcp-main-build-tcc70xx-make_utility.tar.gz file to your rom-build directory. + + +**Extracting the Files** + +Extract the Tool Files: Use the following command to extract the tool files: + +.. code-block:: console + + $ tar xvfz topst-vcp-main-tools.tar.gz + +Extract the Image Files: Use the following command to extract the image files: + +.. code-block:: console + + $ tar xvfz topst-vcp-main-build-tcc70xx-make_utility.tar.gz + + +**3. Writing and Modifying Script Files** + +To create and modify the mkimg.sh script using vi or another text editor, follow these steps: + +**Creating the mkimg.sh Script** +Open the Text Editor: + +Open vi or another text editor of your choice to create the mkimg.sh script. + +For example, using vi: + +.. code-block:: console + + $ vi mkimg.sh + +Write the Script: + + Add the following content to the mkimg.sh file: + +.. code-block:: shell + + #!/bin/bash + for ARGUMENT in "$@" + do + KEY=$(echo $ARGUMENT | cut -f1 -d=) + VALUE=$(echo $ARGUMENT | cut -f2 -d=) + case "$KEY" in + TOOL_PATH) TOOL_PATH=${VALUE} ;; + INPUT_PATH) INPUT_PATH=${VALUE} ;; + OUTPUT_PATH) OUTPUT_PATH=${VALUE} ;; + IMAGE_VERSION) IMAGE_VERSION=${VALUE} ;; + TARGET_ADDRESS) TARGET_ADDRESS=${VALUE} ;; + \*) + esac + done + + MKTOOL_INPUT=$INPUT_PATH/boot.bin + MKTOOL_OUTPUT=$OUTPUT_PATH/r5_fw.rom + MKTOOL_NAME=R5-FW + MKTOOL_SOC_NAME=70xx + chmod 755 $TOOL_PATH/tcmktool + $TOOL_PATH/tcmktool $MKTOOL_INPUT $MKTOOL_OUTPUT $MKTOOL_NAME $IMAGE_VERSION $TARGET_ADDRESS $MKTOOL_SOC_NAME + +Save and Exit: + Save the changes by pressing Esc, then type :wq and press Enter to write and quit the file. + +Make the script executable + +.. code-block:: console + + $ chmod +x mkimg.sh + +**Creating the mkrom.sh Script** + +.. code-block:: console + + $ vi mkrom.sh + +Write the Script: + + Add the following content to the mkrom.sh file: + +.. code-block:: shell + + #!/bin/bash + # Parse command-line arguments + for ARGUMENT in "$@" + do + KEY=$(echo $ARGUMENT | cut -f1 -d=) + VALUE=$(echo $ARGUMENT | cut -f2 -d=) + + case "$KEY" in + BOARD_NAME) BOARD_NAME=${VALUE} ;; + OUTPUT_PATH) OUTPUT_PATH=${VALUE} ;; + \*) + esac + done + + # Define constants + SNOR_SIZE=4 + UTILITY_DIR=./topst-vcp-main-build-tcc70xx-make_utility/build/tcc70xx/make_utility/tcc70xx_pflash_mkimage + OUTPUT_DIR=../../../../../output + OUTPUT_FILE=tcc70xx_pflash_boot.rom + + # Change to utility directory + pushd $UTILITY_DIR + + # Grant execute permissions to the VCP tool (temporary solution) + chmod 755 ./tcc70xx-pflash-mkimage + + # Execute the VCP tool to create the boot ROM image + ./tcc70xx-pflash-mkimage -i ./tcc70xx.cfg -o $OUTPUT_DIR/$OUTPUT_FILE + + # Return to the original directory + popd + +Save and Exit: + Save the changes by pressing Esc, then type :wq and press Enter to write and quit the file. + +Make the script executable + +.. code-block:: console + + $ chmod +x mkrom.sh + + +**Creating the create_rom_with_zephyr_image.sh Script** + +.. code-block:: console + + $ vi create_rom_with_zephyr_image.sh + +Write the Script: + + Add the following content to the create_rom_with_zephyr_image.sh file: + +.. code-block:: shell + + #!/bin/bash + + # Define output and input directories + OUTPUT="./output" + INPUT="./input" + + # Clean up existing directories + rm -rf "$OUTPUT" + rm -rf "$INPUT" + + # Create fresh directories + mkdir -p "$OUTPUT" + mkdir -p "$INPUT" + echo "Directory structure created:" + echo "Output directory: $OUTPUT" + echo "Input directory: $INPUT" + + # Extract and copy Zephyr artifacts + + # Note: Ensure correct paths are specified for zephyr.bin, zephyr.elf, and zephyr.map + ./binary_extractor zephyr.bin "$INPUT"/boot.bin + cp zephyr.elf "$INPUT"/boot + cp zephyr.map "$INPUT"/boot.map + + # Execute mkimg.sh script + chmod 755 ./mkimg.sh + ./mkimg.sh TOOL_PATH=./topst-vcp-main-tools/tools INPUT_PATH="$INPUT" OUTPUT_PATH="$OUTPUT" TARGET_ADDRESS=0x00000000 IMAGE_VERSION=0.0.0 + + # Execute mkrom.sh script + chmod 755 ./mkrom.sh + ./mkrom.sh BOARD_NAME="$MCU_BSP_CONFIG_BOARD_NAME" OUTPUT_PATH="$OUTPUT" + +Save and Exit: + Save the changes by pressing Esc, then type :wq and press Enter to write and quit the file. + +Make the script executable + +.. code-block:: console + + $ chmod +x create_rom_with_zephyr_image.sh + +**Modifying tcc70xx.cfg file** + +.. code-block:: console + + $ vi ./topst-vcp-main-build-tcc70xx-make_utility/build/tcc70xx/make_utility/tcc70xx_pflash_mkimage/tcc70xx.cfg + +Modify the 6th line as follows: + +Change: + + MICOM_BIN=../../gcc/output/r5_fw.rom + +To: + + MICOM_BIN=../../../../../output/r5_fw.rom + + +**Creating the ROM Code Extractor** + +.. code-block:: console + + $ vi binary_extractor.c + +Write c code: + + Add the following content to the binary_extractor.c file: + +.. code-block:: c + + #include + #include + #include + #define BUFFER_SIZE 4096 + #define OFFSET 0x01043000 + + int main(int argc, char *argv[]) { + FILE *input_file, *output_file; + uint8_t buffer[BUFFER_SIZE]; + size_t bytes_read; + if (argc != 3) { + fprintf(stderr, "Usage: %s \\n", argv[0]); + return 1; + } + + input_file = fopen(argv[1], "rb"); + if (input_file == NULL) { + perror("Cannot open input file"); + return 1; + } + + output_file = fopen(argv[2], "wb"); + if (output_file == NULL) { + perror("Cannot create output file"); + fclose(input_file); + return 1; + } + + if (fseek(input_file, OFFSET, SEEK_SET) != 0) { + perror("Cannot move to offset in file"); + fclose(input_file); + fclose(output_file); + return 1; + } + + while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, input_file)) > 0) { + if (fwrite(buffer, 1, bytes_read, output_file) != bytes_read) { + perror("Error writing to output file"); + fclose(input_file); + fclose(output_file); + return 1; + } + } + + fclose(input_file); + fclose(output_file); + printf("The file has been processed successfully.\\n"); + + return 0; + } + +Build the C file to create an executable. + +.. code-block:: console + + $ gcc -o binary_extractor binary_extractor.c + +**4. Creating the ROM File** + +The ROM file for fusing onto the TOPST VCP board is created using three components: + Prebuilt hsm.bin file + + updater.rom file + + zephyr.bin file (Zephyr RTOS image) + +To create the ROM file, execute the following command: + +.. code-block:: console + + $ ./create_rom_with_zephyr_image.sh + +After running the script, verify that the ROM file has been generated by checking the output directory: + +.. code-block:: console + + $ ls -al ./output/ + +Ensure that the file tcc70xx_pflash_boot_4M_ECC.rom is present in the output directory. This file is the final ROM image that can be fused onto the TOPST VCP board. + + +Flashing +======== + +USB C Cable Connection + Connect the TOPST-VCP board to your development host PC using a USB C cable. + +Verify the Connection + On your Linux machine, run: + +.. code-block:: console + + $ sudo mesg | grep ttyU + +Set the Board to Download Mode + Flip the FWDN switch to the FWDN position on the TOPST-VCP board. + + Press the PORN button to reset the board. + + The board is now in FWDN download mode. + +Execute the Download Command + Use the FWDN tool to download the software for 4MB flash: + +.. code-block:: console + + sudo ./topst-vcp-main-tools/tools/fwdn_vcp/fwdn --fwdn ./topst-vcp-main-tools/tools/fwdn_vcp/vcp_fwdn.rom -w ./output/tcc70xx_pflash_boot_4M_ECC.rom + +Reset the Board + Switch the FWDN switch back to the NORMAL position. + + Reset the board by either powering it on again or pressing the PORN button. + + +Debugging +========= + +Verifying the Software on the Board + +Install tio + +.. code-block:: console + + $ sudo apt install tio + +Open a Serial Connection + Initiate a serial connection with: + +.. code-block:: console + + $ sudo tio -b 115200 /dev/ttyUSB0 + +Verify the Software + Because the serial device driver has not yet been added to this PR, you cannot see the sentences output by the hello_world program. diff --git a/boards/tcc/topst_vcp45/topst_vcp45.dts b/boards/tcc/topst_vcp45/topst_vcp45.dts new file mode 100644 index 0000000000000..1d4b2cfdbff8b --- /dev/null +++ b/boards/tcc/topst_vcp45/topst_vcp45.dts @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include + +/ { + compatible = "tcc,topst_vcc45"; + model = "TOPST VCP45 Cortex-R5"; + + aliases { + led0 = &led_act; + }; + + chosen { + zephyr,sram = &ram_dlm; + zephyr,flash = &flash0; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + }; + + leds { + compatible = "gpio-leds"; + + led_act: led-act { + gpios = <&gio_aon 6 GPIO_ACTIVE_HIGH>; + label = "ACT"; + }; + }; + +}; + +&flash0 { + status = "okay"; +}; + +&gio_aon { + status = "okay"; +}; + +&sysclk { + status = "okay"; +}; + +&tic { + status = "okay"; +}; + +&systick_timer { + status = "okay"; + clock-frequency = <12000000>; +}; + +&uart1 { + status = "okay"; + current-speed = <115200>; + clock-frequency = <48000000>; +}; diff --git a/boards/tcc/topst_vcp45/topst_vcp45.yaml b/boards/tcc/topst_vcp45/topst_vcp45.yaml new file mode 100644 index 0000000000000..c0c1280eada9f --- /dev/null +++ b/boards/tcc/topst_vcp45/topst_vcp45.yaml @@ -0,0 +1,9 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 +identifier: topst_vcp45 +name: Telechips TOPST VCP45 board for Cortex-R5F +type: mcu +arch: arm +toolchain: + - zephyr + - cross-compile diff --git a/boards/tcc/topst_vcp45/topst_vcp45_defconfig b/boards/tcc/topst_vcp45/topst_vcp45_defconfig new file mode 100644 index 0000000000000..fff68722b9710 --- /dev/null +++ b/boards/tcc/topst_vcp45/topst_vcp45_defconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright 2024 Hounjoung Rim + +CONFIG_GPIO=y + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y + +CONFIG_USERSPACE=y diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 18b6025df6c7c..8aefcf64f94ce 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -56,6 +56,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_HSFLL_LOCAL clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_LFCLK clock_control_nrf_lfclk.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_AUXPLL clock_control_nrf_auxpll.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BOUFFALOLAB_BL60X clock_control_bl60x.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_TCC_CCU clock_control_tccvcp.c) if(CONFIG_CLOCK_CONTROL_RENESAS_RZA2M_CPG) zephyr_library_sources(clock_control_renesas_rza2m_cpg.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index 05a2a7fb8fa67..dc58dc236a250 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -110,6 +110,8 @@ source "drivers/clock_control/Kconfig.silabs" source "drivers/clock_control/Kconfig.siwx91x" +source "drivers/clock_control/Kconfig.tcc" + source "drivers/clock_control/Kconfig.wch_rcc" source "drivers/clock_control/Kconfig.it51xxx" diff --git a/drivers/clock_control/Kconfig.tcc b/drivers/clock_control/Kconfig.tcc new file mode 100644 index 0000000000000..3c83330b4a280 --- /dev/null +++ b/drivers/clock_control/Kconfig.tcc @@ -0,0 +1,9 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_TCC_CCU + bool "Telechips clock control driver" + default y + depends on DT_HAS_TCC_CCU_ENABLED + help + This option enables the clock driver for Telechips TCC70XX series SOC. diff --git a/drivers/clock_control/clock_control_tccvcp.c b/drivers/clock_control/clock_control_tccvcp.c new file mode 100644 index 0000000000000..5e9d0fdd35249 --- /dev/null +++ b/drivers/clock_control/clock_control_tccvcp.c @@ -0,0 +1,1050 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#define DT_DRV_COMPAT tcc_ccu + +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(clock_control_tcc_ccu); + +#include +#include + +#include + +struct clock_tcc_config { + const struct device *syscon; +}; + +static uint32_t micom_clock_source[CLOCK_SRC_MAX_NUM]; + +static void clock_dev_write_pll(uint32_t uiReg, uint32_t en, uint32_t p, uint32_t m, uint32_t s); + +static void clock_dev_write_pclk_ctrl(uint32_t uiReg, uint32_t md, uint32_t en, uint32_t sel, + uint32_t uiDiv, uint32_t uiType); + +static void clock_dev_write_clk_ctrl(uint32_t uiReg, uint32_t en, uint32_t conf, uint32_t sel); + +static int32_t clock_dev_find_pms(struct clock_pms *psPll, uint32_t srcFreq); + +static int32_t clock_dev_set_pll_rate(uint32_t uiReg, uint32_t uiRate); + +static uint32_t clock_dev_get_pll_rate(uint32_t uiReg); + +static uint32_t clock_dev_get_pll_div(int32_t iId); + +static int32_t clock_dev_find_clk_ctrl(struct clock_clk_ctrl *CLKCTRL); + +static uint32_t clock_dev_cal_pclk_div(const struct clock_pclk_ctrl *psPclkCtrl, + uint32_t *puiClkDiv, const uint32_t srcClk, + uint32_t uiDivMax); + +static int32_t clock_dev_find_pclk(struct clock_pclk_ctrl *psPclkCtrl, + enum clock_pclk_ctrl_type eType); + +static void clock_dev_reset_clk_src(int32_t iId); + +/* PLL Configuration Macro */ +static void clock_dev_write_pll(uint32_t reg, uint32_t en, uint32_t p, uint32_t m, uint32_t s) +{ + const uint32_t timeout = 4000000000UL; + uint32_t try_count = 0; + + if (reg != 0UL) { + if (en != 0UL) { + sys_write32(0UL | (1UL << (uint32_t)CLOCK_PLL_LOCKEN_SHIFT) | + (2UL << (uint32_t)CLOCK_PLL_CHGPUMP_SHIFT) | + (((s) & (uint32_t)CLOCK_PLL_S_MASK) + << (uint32_t)CLOCK_PLL_S_SHIFT) | + (((m) & (uint32_t)CLOCK_PLL_M_MASK) + << (uint32_t)CLOCK_PLL_M_SHIFT) | + (((p) & (uint32_t)CLOCK_PLL_P_MASK) + << (uint32_t)CLOCK_PLL_P_SHIFT), + reg); + + sys_write32(sys_read32(reg) | ((en & 1UL) << (uint32_t)CLOCK_PLL_EN_SHIFT), + reg); + + while ((sys_read32(reg) & (1UL << (uint32_t)CLOCK_PLL_LOCKST_SHIFT)) == + 0UL) { + try_count++; + + if (try_count > timeout) { + break; + } + } + } else { + sys_write32((uint32_t)(sys_read32(reg)) & + (~(1UL << (uint32_t)CLOCK_PLL_EN_SHIFT)), + reg); + } + } +} + +static void clock_dev_write_pclk_ctrl(uint32_t reg, uint32_t md, uint32_t en, uint32_t sel, + uint32_t divider, uint32_t type) +{ + if (type == (uint32_t)CLOCK_PCLKCTRL_TYPE_XXX) { + sys_write32(sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_OUTEN_SHIFT), reg); + sys_write32(sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT), reg); + sys_write32((sys_read32(reg) & ~((uint32_t)CLOCK_PCLKCTRL_SEL_MASK + << (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT)), + reg); + sys_write32((sys_read32(reg) & ~((uint32_t)CLOCK_PCLKCTRL_DIV_XXX_MASK + << (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT)), + reg); + + sys_write32((sys_read32(reg) | ((divider & (uint32_t)CLOCK_PCLKCTRL_DIV_XXX_MASK) + << (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT)), + reg); + sys_write32((sys_read32(reg) | ((sel & (uint32_t)CLOCK_PCLKCTRL_SEL_MASK) + << (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT)), + reg); + sys_write32((sys_read32(reg) | ((en & 1UL) << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT)), + reg); + sys_write32( + (sys_read32(reg) | ((en & 1UL) << (uint32_t)CLOCK_PCLKCTRL_OUTEN_SHIFT)), + reg); + } else if (type == (uint32_t)CLOCK_PCLKCTRL_TYPE_YYY) { + sys_write32(sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT), reg); + sys_write32((sys_read32(reg) & ~((uint32_t)CLOCK_PCLKCTRL_DIV_YYY_MASK + << (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT)) | + ((divider & (uint32_t)CLOCK_PCLKCTRL_DIV_YYY_MASK) + << (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT), + reg); + sys_write32((sys_read32(reg) & ~((uint32_t)CLOCK_PCLKCTRL_SEL_MASK + << (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT)) | + ((sel & (uint32_t)CLOCK_PCLKCTRL_SEL_MASK) + << (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT), + reg); + sys_write32((sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_MD_SHIFT)) | + ((md & 1UL) << (uint32_t)CLOCK_PCLKCTRL_MD_SHIFT), + reg); + sys_write32((sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT)) | + ((en & 1UL) << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT), + reg); + } else { + return; + } +} + +static void write_and_wait(uint32_t reg, uint32_t value, uint32_t mask, uint32_t shift, + uint32_t wait_shift, uint32_t timeout) +{ + sys_write32((sys_read32(reg) & ~(mask << shift)) | ((value & mask) << shift), reg); + + uint32_t try_count = 0; + + while ((sys_read32(reg) & (1UL << wait_shift)) != 0UL) { + try_count++; + if (try_count > timeout) { + break; + } + } +} + +static void clock_dev_write_clk_ctrl(uint32_t reg, uint32_t en, uint32_t conf, uint32_t sel) +{ + const uint32_t timeout = 4000000000; + uint32_t cur_conf = (sys_read32(reg) >> (uint32_t)CLOCK_MCLKCTRL_CONFIG_SHIFT) & + (uint32_t)CLOCK_MCLKCTRL_CONFIG_MASK; + + if (conf >= cur_conf) { + write_and_wait(reg, conf, CLOCK_MCLKCTRL_CONFIG_MASK, CLOCK_MCLKCTRL_CONFIG_SHIFT, + CLOCK_MCLKCTRL_CLKCHG_SHIFT, timeout); + write_and_wait(reg, sel, CLOCK_MCLKCTRL_SEL_MASK, CLOCK_MCLKCTRL_SEL_SHIFT, + CLOCK_MCLKCTRL_CLKCHG_SHIFT, timeout); + } else { + write_and_wait(reg, sel, CLOCK_MCLKCTRL_SEL_MASK, CLOCK_MCLKCTRL_SEL_SHIFT, + CLOCK_MCLKCTRL_CLKCHG_SHIFT, timeout); + write_and_wait(reg, conf, CLOCK_MCLKCTRL_CONFIG_MASK, CLOCK_MCLKCTRL_CONFIG_SHIFT, + CLOCK_MCLKCTRL_CLKCHG_SHIFT, timeout); + } + + if (en != 0UL) { + write_and_wait(reg, en & 1UL, 1UL, CLOCK_MCLKCTRL_EN_SHIFT, + CLOCK_MCLKCTRL_DIVSTS_SHIFT, timeout); + } +} + +static inline int is_valid_fvco(uint64_t fvco) +{ + return (fvco >= (uint64_t)CLOCK_PLL_VCO_MIN) && (fvco <= (uint64_t)CLOCK_PLL_VCO_MAX); +} + +static inline int is_valid_m(uint64_t m) +{ + return (m >= (uint64_t)CLOCK_PLL_M_MIN) && (m <= (uint64_t)CLOCK_PLL_M_MAX); +} + +static inline int is_valid_src_pll(uint64_t src_pll) +{ + return (src_pll >= (uint64_t)CLOCK_PLL_MIN_RATE) && + (src_pll <= (uint64_t)CLOCK_PLL_MAX_RATE); +} + +static void update_best_err(uint32_t *err, uint32_t srch_err, struct clock_pms *pll_ptr, uint32_t p, + uint32_t m, uint32_t s) +{ + if (srch_err < *err) { + *err = srch_err; + pll_ptr->p = p; + pll_ptr->m = m; + pll_ptr->s = s; + } +} + +static int32_t clock_dev_find_pms(struct clock_pms *pll_ptr, uint32_t src_freq) +{ + uint64_t pll, src, fvco; + uint64_t srch_m, temp, src_pll; + uint32_t err, srch_err; + + if (!pll_ptr) { + return 0; + } + if (pll_ptr->fpll == 0UL) { + pll_ptr->en = 0; + return 0; + } + + pll = (uint64_t)pll_ptr->fpll; + src = (uint64_t)src_freq; + err = 0xFFFFFFFFUL; + + for (int32_t srch_s = CLOCK_PLL_S_MIN; srch_s <= CLOCK_PLL_S_MAX; srch_s++) { + fvco = pll << srch_s; + if (!is_valid_fvco(fvco)) { + continue; + } + + for (uint64_t srch_p = CLOCK_PLL_P_MIN; srch_p <= CLOCK_PLL_P_MAX; srch_p++) { + srch_m = fvco * srch_p; + soc_div64_to_32(&srch_m, src_freq, NULL); + if (!is_valid_m(srch_m)) { + continue; + } + + temp = srch_m * src; + soc_div64_to_32(&temp, srch_p, NULL); + src_pll = (temp >> srch_s); + if (!is_valid_src_pll(src_pll)) { + continue; + } + + srch_err = (uint32_t)((src_pll > pll) ? (src_pll - pll) : (pll - src_pll)); + update_best_err(&err, srch_err, pll_ptr, (uint32_t)srch_p, (uint32_t)srch_m, + (uint32_t)srch_s); + } + } + + if (err == 0xFFFFFFFFUL) { + return -EIO; + } + + temp = src * (uint64_t)pll_ptr->m; + soc_div64_to_32(&temp, pll_ptr->p, NULL); + pll_ptr->fpll = (uint32_t)(temp >> pll_ptr->s); + pll_ptr->en = 1; + + return 0; +} + +static int32_t clock_dev_set_pll_rate(uint32_t reg, uint32_t rate) +{ + struct clock_pms pll; + uint64_t cal_m; + int32_t err; + + err = 0; + memset(&pll, 0, sizeof(pll)); + pll.fpll = rate; + + if (clock_dev_find_pms(&pll, CLOCK_XIN_CLK_RATE) != 0L) { + cal_m = (uint64_t)CLOCK_PLL_P_MIN * (uint64_t)CLOCK_PLL_VCO_MIN; + cal_m += (uint64_t)CLOCK_XIN_CLK_RATE; + cal_m /= (uint64_t)CLOCK_XIN_CLK_RATE; + clock_dev_write_pll(reg, 0UL, (uint32_t)CLOCK_PLL_P_MIN, (uint32_t)cal_m, + (uint32_t)CLOCK_PLL_S_MIN); + err = -EIO; + } else { + clock_dev_write_pll(reg, pll.en, pll.p, pll.m, pll.s); + } + + return err; +} + +static uint32_t clock_dev_get_pll_rate(uint32_t reg) +{ + uint32_t reg_val; + struct clock_pms pll_cfg; + uint64_t temp; + + if (reg == 0UL) { + return 0; + } + + reg_val = sys_read32(reg); + + pll_cfg.p = (reg_val >> (uint32_t)CLOCK_PLL_P_SHIFT) & ((uint32_t)CLOCK_PLL_P_MASK); + pll_cfg.m = (reg_val >> (uint32_t)CLOCK_PLL_M_SHIFT) & ((uint32_t)CLOCK_PLL_M_MASK); + pll_cfg.s = (reg_val >> (uint32_t)CLOCK_PLL_S_SHIFT) & ((uint32_t)CLOCK_PLL_S_MASK); + pll_cfg.en = (reg_val >> (uint32_t)CLOCK_PLL_EN_SHIFT) & (1UL); + pll_cfg.src = (reg_val >> (uint32_t)CLOCK_PLL_SRC_SHIFT) & ((uint32_t)CLOCK_PLL_SRC_MASK); + temp = (uint64_t)CLOCK_XIN_CLK_RATE * (uint64_t)pll_cfg.m; + soc_div64_to_32(&temp, (uint32_t)(pll_cfg.p), NULL); + + return (uint32_t)((temp) >> pll_cfg.s); +} + +static uint32_t clock_dev_get_pll_div(int32_t id) +{ + uint32_t ret; + CLOCKMpll_t m_pll_id; + uint32_t reg, offset, reg_val; + + ret = 0; + m_pll_id = (CLOCKMpll_t)id; + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_CLKDIVC; + + switch (m_pll_id) { + case CLOCK_MPLL_0: + case CLOCK_MPLL_1: + offset = (3UL - (uint32_t)id) * 8UL; + break; + case CLOCK_MPLL_XIN: + offset = 8UL; + break; + default: + offset = 0UL; + break; + } + + reg_val = sys_read32(reg); + + if (offset != 0UL) { + ret = ((reg_val >> offset) & 0x3FUL); + } + + return ret; +} + +static uint32_t clock_dev_cal_pclk_div(const struct clock_pclk_ctrl *pclk_ctrl_ptr, + uint32_t *clk_div_ptr, const uint32_t src_clk, + uint32_t div_max) +{ + uint32_t clk_rate1, clk_rate2; + uint32_t err1, err2; + + if (pclk_ctrl_ptr == NULL) { + return 0; + } + + if (clk_div_ptr == NULL) { + return 0; + } + + if (src_clk <= pclk_ctrl_ptr->freq) { + *clk_div_ptr = 1UL; + } else { + *clk_div_ptr = src_clk / pclk_ctrl_ptr->freq; + } + + if ((*clk_div_ptr) > div_max) { + *clk_div_ptr = div_max; + } + + if (*clk_div_ptr == 0) { + return 0; + } + + clk_rate1 = (src_clk) / (*clk_div_ptr); + clk_rate2 = + (src_clk) / (((*clk_div_ptr) < div_max) ? ((*clk_div_ptr) + 1UL) : (*clk_div_ptr)); + err1 = (clk_rate1 > pclk_ctrl_ptr->freq) ? (clk_rate1 - pclk_ctrl_ptr->freq) + : (pclk_ctrl_ptr->freq - clk_rate1); + err2 = (clk_rate2 > pclk_ctrl_ptr->freq) ? (clk_rate2 - pclk_ctrl_ptr->freq) + : (pclk_ctrl_ptr->freq - clk_rate2); + + if (err1 > err2) { + *clk_div_ptr += 1UL; + } + + return (err1 < err2) ? err1 : err2; +} + +static int32_t clock_dev_find_pclk(struct clock_pclk_ctrl *pclk_ctrl_ptr, + enum clock_pclk_ctrl_type type) +{ + int32_t ret, last_idx; + uint32_t div_max, srch_src, err_div, md; + uint32_t divider[CLOCK_SRC_MAX_NUM]; + uint32_t err[CLOCK_SRC_MAX_NUM]; + uint32_t div_div; + enum clock_pclk_ctrl_mode pclk_sel; + + div_div = CLOCK_PCLKCTRL_DIV_MIN; + pclk_sel = CLOCK_PCLKCTRL_MODE_DIVIDER; + ret = 0; + + if (pclk_ctrl_ptr == NULL) { + return -EINVAL; + } + + pclk_ctrl_ptr->md = (uint32_t)pclk_sel; + div_max = CLOCK_PCLKCTRL_DIV_XXX_MAX; + + memset((void *)divider, 0x00U, sizeof(divider)); + srch_src = 0xFFFFFFFFUL; + last_idx = (int32_t)CLOCK_SRC_MAX_NUM - 1L; + + for (int32_t idx = last_idx; idx >= 0L; idx--) { + if (micom_clock_source[idx] == 0UL) { + continue; + } + + if ((micom_clock_source[idx] >= (uint32_t)CLOCK_PCLKCTRL_MAX_FCKS) && + (type == CLOCK_PCLKCTRL_TYPE_XXX)) { + continue; + } + + /* divider mode */ + err_div = clock_dev_cal_pclk_div( + pclk_ctrl_ptr, &div_div, + micom_clock_source[idx], /*CLOCK_PCLKCTRL_DIV_MIN+1, \*/ + div_max + 1UL); + + err[idx] = err_div; + divider[idx] = div_div; + md = (uint32_t)pclk_sel; + + if (srch_src == 0xFFFFFFFFUL) { + srch_src = (uint32_t)idx; + pclk_ctrl_ptr->md = md; + } else { + /* find similar clock */ + if (err[idx] <= err[srch_src]) { + srch_src = (uint32_t)idx; + pclk_ctrl_ptr->md = md; + } + } + } + + switch (srch_src) { + case (uint32_t)CLOCK_MPLL_0: + pclk_ctrl_ptr->sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_PLL0; + break; + case (uint32_t)CLOCK_MPLL_1: + pclk_ctrl_ptr->sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_PLL1; + break; + case (uint32_t)CLOCK_MPLL_DIV_0: + pclk_ctrl_ptr->sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_PLL0DIV; + break; + case (uint32_t)CLOCK_MPLL_DIV_1: + pclk_ctrl_ptr->sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_PLL1DIV; + break; + case (uint32_t)CLOCK_MPLL_XIN: + pclk_ctrl_ptr->sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_XIN; + break; + default: + ret = -EINVAL; + break; + } + + if (ret != 0) { + return ret; + } + + pclk_ctrl_ptr->div_val = divider[srch_src]; + + if ((pclk_ctrl_ptr->div_val >= ((uint32_t)CLOCK_PCLKCTRL_DIV_MIN + 1UL)) && + (pclk_ctrl_ptr->div_val <= (div_max + 1UL))) { + pclk_ctrl_ptr->div_val -= 1UL; + } else { + return -EINVAL; + } + + pclk_ctrl_ptr->freq = micom_clock_source[srch_src] / (pclk_ctrl_ptr->div_val + 1UL); + + return 0; +} + +static void clock_dev_reset_clk_src(int32_t id) +{ + if ((id < 0) || (id >= (int32_t)CLOCK_SRC_MAX_NUM)) { + return; + } + + if (id < (int32_t)CLOCK_PLL_MAX_NUM) { + micom_clock_source[id] = clock_get_pll_rate(id); + micom_clock_source[CLOCK_PLL_MAX_NUM + id] = + micom_clock_source[id] / (clock_dev_get_pll_div(id) + 1UL); + } +} + +void vcp_clock_init(void) +{ + static int32_t initialized = -1; + int32_t idx; + + if (initialized == 1L) { + return; + } + + initialized = 1; + + for (idx = 0L; idx < ((int32_t)CLOCK_PLL_MAX_NUM * 2L); idx++) { + micom_clock_source[idx] = 0; + } + + micom_clock_source[CLOCK_PLL_MAX_NUM * 2] = (uint32_t)CLOCK_XIN_CLK_RATE; + micom_clock_source[(CLOCK_PLL_MAX_NUM * 2) + 1] = 0UL; + + for (idx = 0L; idx < (int32_t)CLOCK_PLL_MAX_NUM; idx++) { + clock_dev_reset_clk_src(idx); + } +} + +int32_t clock_set_pll_div(int32_t id, uint32_t pll_div) +{ + CLOCKMpll_t mpll_id; + uint32_t reg, offset, reg_val, real_pll_div; + + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_CLKDIVC; + mpll_id = (CLOCKMpll_t)id; + + real_pll_div = ((pll_div > 1UL) ? (pll_div - 1UL) : (0UL)); + + switch (mpll_id) { + case CLOCK_MPLL_0: + offset = (3UL - (uint32_t)id) * 8UL; + break; + case CLOCK_MPLL_1: + offset = (3UL - (uint32_t)id) * 8UL; + break; + case CLOCK_MPLL_XIN: + offset = 8UL; + break; + default: + offset = 0; + break; + } + + if (offset == 0UL) { + return -EINVAL; + } + + reg_val = (uint32_t)(sys_read32(reg)) & (~(((uint32_t)0xFFUL << offset))); + sys_write32(reg_val, reg); + + if (real_pll_div != 0UL) { + reg_val |= (0x80UL | (real_pll_div & 0x3FUL)) << offset; + } else { + reg_val |= ((0x01UL) << offset); + } + + sys_write32(reg_val, reg); + + return 0; +} + +uint32_t clock_get_pll_rate(int32_t id) +{ + uint32_t reg; + CLOCKPll_t pll_id; + + pll_id = (CLOCKPll_t)id; + + if (pll_id == CLOCK_PLL_MICOM_0) { + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PLL0PMS; + } else if (pll_id == CLOCK_PLL_MICOM_1) { + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PLL1PMS; + } else { + return 0; + } + + return clock_dev_get_pll_rate(reg); +} + +int32_t clock_set_pll_rate(int32_t id, uint32_t rate) +{ + uint32_t reg; + CLOCKPll_t pll_id; + enum clock_mpclk_ctrl_sel mpclk_sel; + int32_t idx; + + pll_id = (CLOCKPll_t)id; + + if (pll_id == CLOCK_PLL_MICOM_0) { + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PLL0PMS; + mpclk_sel = CLOCK_MPCLKCTRL_SEL_PLL0; + } else if (pll_id == CLOCK_PLL_MICOM_1) { + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PLL1PMS; + mpclk_sel = CLOCK_MPCLKCTRL_SEL_PLL1; + } else { + return -EINVAL; + } + + idx = (int32_t)mpclk_sel; + clock_dev_set_pll_rate(reg, rate); + micom_clock_source[idx] = clock_dev_get_pll_rate(reg); + + return 0; +} + +static uint32_t calc_div(uint32_t src, uint32_t freq) +{ + uint32_t div_val = (src + (freq - 1UL)) / freq; + + if (div_val > CLOCK_MCLKCTRL_CONFIG_MAX + 1UL) { + return CLOCK_MCLKCTRL_CONFIG_MAX + 1UL; + } + if (div_val < CLOCK_MCLKCTRL_CONFIG_MIN + 1UL) { + return CLOCK_MCLKCTRL_CONFIG_MIN + 1UL; + } + return div_val; +} + +static void update_best_src(uint32_t idx, uint32_t err, uint32_t div, uint32_t *srch_src, + uint32_t *best_err, uint32_t *div_table, uint32_t *err_table) +{ + if (*srch_src == 0xFFFFFFFFUL || err < *best_err || + (err == *best_err && (div % 2UL == 0UL))) { + *srch_src = idx; + *best_err = err; + } + err_table[idx] = err; + div_table[idx] = div; +} + +static int32_t clock_dev_find_clk_ctrl(struct clock_clk_ctrl *clk_ctrl) +{ + if (!clk_ctrl) { + return -EINVAL; + } + + uint32_t xin_freq = (clk_ctrl->en != 0UL) ? (CLOCK_XIN_CLK_RATE / 2UL) : CLOCK_XIN_CLK_RATE; + + if (clk_ctrl->freq <= xin_freq) { + clk_ctrl->sel = CLOCK_MCLKCTRL_SEL_XIN; + clk_ctrl->freq = xin_freq; + clk_ctrl->conf = (clk_ctrl->en != 0UL) ? 1 : 0; + return 0; + } + + uint32_t div_table[CLOCK_SRC_MAX_NUM] = {0}; + uint32_t err_table[CLOCK_SRC_MAX_NUM] = {0}; + uint32_t srch_src = 0xFFFFFFFFUL; + uint32_t best_err = 0xFFFFFFFFUL; + + for (uint32_t idx = 0; idx < CLOCK_SRC_MAX_NUM; idx++) { + uint32_t src = micom_clock_source[idx]; + + if (src == 0UL) { + continue; + } + + uint32_t clk_rate, div_val = 1; + + if (clk_ctrl->en != 0UL) { + div_val = calc_div(src, clk_ctrl->freq); + clk_rate = src / div_val; + } else { + clk_rate = src; + } + + if (clk_ctrl->freq < clk_rate) { + continue; + } + + uint32_t err = clk_ctrl->freq - clk_rate; + + update_best_src(idx, err, div_val, &srch_src, &best_err, div_table, err_table); + + if (best_err == 0UL) { + break; + } + } + + if (srch_src == 0xFFFFFFFFUL) { + return -EIO; + } + + static const uint32_t sel_table[CLOCK_SRC_MAX_NUM] = { + [CLOCK_MPLL_0] = CLOCK_MCLKCTRL_SEL_PLL0, + [CLOCK_MPLL_1] = CLOCK_MCLKCTRL_SEL_PLL1, + [CLOCK_MPLL_DIV_0] = CLOCK_MCLKCTRL_SEL_PLL0DIV, + [CLOCK_MPLL_DIV_1] = CLOCK_MCLKCTRL_SEL_PLL1DIV, + [CLOCK_MPLL_XIN] = CLOCK_MCLKCTRL_SEL_XIN, + }; + + if (srch_src >= CLOCK_SRC_MAX_NUM || sel_table[srch_src] == 0) { + return -EINVAL; + } + + clk_ctrl->sel = sel_table[srch_src]; + + if (clk_ctrl->en != 0UL) { + uint32_t div_tbl = div_table[srch_src]; + + if (div_tbl > CLOCK_MCLKCTRL_CONFIG_MAX + 1UL) { + div_tbl = CLOCK_MCLKCTRL_CONFIG_MAX + 1UL; + } + if (div_tbl <= CLOCK_MCLKCTRL_CONFIG_MIN) { + div_tbl = CLOCK_MCLKCTRL_CONFIG_MIN + 1UL; + } + clk_ctrl->freq = micom_clock_source[srch_src] / div_tbl; + clk_ctrl->conf = div_tbl - 1UL; + } else { + clk_ctrl->freq = micom_clock_source[srch_src]; + clk_ctrl->conf = 0; + } + + return 0; +} + +int32_t clock_set_clk_ctrl_rate(int32_t id, uint32_t rate) +{ + uint32_t reg; + struct clock_clk_ctrl clk_ctrl; + + reg = (uint32_t)((uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_CLKCTRL + + ((uint32_t)id * 4UL)); + + if ((sys_read32(reg) & (1UL << (uint32_t)CLOCK_MCLKCTRL_EN_SHIFT)) != 0UL) { + clk_ctrl.en = 1; + } else { + clk_ctrl.en = 0; + } + + clk_ctrl.freq = rate; + + if (clock_dev_find_clk_ctrl(&clk_ctrl) != 0L) { + return -EIO; + } + + clock_dev_write_clk_ctrl(reg, clk_ctrl.en, clk_ctrl.conf, clk_ctrl.sel); + + return 0; +} + +uint32_t clock_get_clk_ctrl_rate(int32_t id) +{ + struct clock_clk_ctrl clk_ctrl; + enum clock_mclk_ctrl_sel mclk_sel; + uint32_t reg, reg_val, src_freq, ret; + + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_CLKCTRL + ((uint32_t)id * 4UL); + ret = 0; + reg_val = sys_read32(reg); + + clk_ctrl.sel = (reg_val & ((uint32_t)CLOCK_MCLKCTRL_SEL_MASK + << (uint32_t)CLOCK_MCLKCTRL_SEL_SHIFT)) >> + (uint32_t)CLOCK_MCLKCTRL_SEL_SHIFT; + mclk_sel = (enum clock_mclk_ctrl_sel)clk_ctrl.sel; + + switch (mclk_sel) { + case CLOCK_MCLKCTRL_SEL_XIN: + src_freq = (uint32_t)CLOCK_XIN_CLK_RATE; + break; + case CLOCK_MCLKCTRL_SEL_PLL0: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_0); + break; + case CLOCK_MCLKCTRL_SEL_PLL1: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_1); + break; + case CLOCK_MCLKCTRL_SEL_PLL0DIV: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_0) / + (clock_dev_get_pll_div((int32_t)CLOCK_PLL_MICOM_0) + 1UL); + break; + case CLOCK_MCLKCTRL_SEL_PLL1DIV: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_1) / + (clock_dev_get_pll_div((int32_t)CLOCK_PLL_MICOM_1) + 1UL); + break; + default: + src_freq = 0UL; + break; + } + + if (src_freq > 0UL) { + clk_ctrl.conf = (reg_val & ((uint32_t)CLOCK_MCLKCTRL_CONFIG_MASK + << (uint32_t)CLOCK_MCLKCTRL_CONFIG_SHIFT)) >> + (uint32_t)CLOCK_MCLKCTRL_CONFIG_SHIFT; + + clk_ctrl.freq = src_freq / (clk_ctrl.conf + 1UL); + ret = (uint32_t)clk_ctrl.freq; + } + + return ret; +} + +int32_t clock_is_peri_enabled(int32_t id) +{ + CLOCKPeri_t peri_offset; + uint32_t reg; + + peri_offset = CLOCK_PERI_SFMC; + reg = ((uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PCLKCTRL) + + (((uint32_t)id - (uint32_t)peri_offset) * 4UL); + + return ((sys_read32(reg) & (1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT)) != 0UL) ? 1L : 0L; +} + +int32_t clock_enable_peri(int32_t id) +{ + CLOCKPeri_t peri_offset; + uint32_t reg; + + peri_offset = CLOCK_PERI_SFMC; + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PCLKCTRL + + (((uint32_t)id - (uint32_t)peri_offset) * 4UL); + sys_write32((sys_read32(reg) | (1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT)), reg); + + return 0; +} + +int32_t clock_disable_peri(int32_t id) +{ + CLOCKPeri_t peri_offset; + uint32_t reg; + + peri_offset = CLOCK_PERI_SFMC; + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PCLKCTRL + + (((uint32_t)id - (uint32_t)peri_offset) * 4UL); + + sys_write32(sys_read32(reg) & ~(1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT), reg); + + return 0; +} + +uint32_t clock_get_peri_rate(int32_t id) +{ + CLOCKPeri_t peri_offset; + uint32_t reg, reg_va, src_freq, ret; + struct clock_pclk_ctrl pclk_ctrl; + CLOCKPclkctrlSel_t pclk_sel; + + peri_offset = CLOCK_PERI_SFMC; + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PCLKCTRL + + (((uint32_t)id - (uint32_t)peri_offset) * 4UL); + reg_va = sys_read32(reg); + ret = 0; + pclk_ctrl.sel = (reg_va & ((uint32_t)CLOCK_PCLKCTRL_SEL_MASK + << (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT)) >> + (uint32_t)CLOCK_PCLKCTRL_SEL_SHIFT; + + pclk_sel = (CLOCKPclkctrlSel_t)(pclk_ctrl.sel); + + switch (pclk_sel) { + case CLOCK_PCLKCTRL_SEL_PLL0: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_0); + break; + case CLOCK_PCLKCTRL_SEL_PLL1: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_1); + break; + case CLOCK_PCLKCTRL_SEL_PLL0DIV: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_0) / + (clock_dev_get_pll_div((int32_t)CLOCK_PLL_MICOM_0) + 1UL); + break; + case CLOCK_PCLKCTRL_SEL_PLL1DIV: + src_freq = clock_get_pll_rate((int32_t)CLOCK_PLL_MICOM_1) / + (clock_dev_get_pll_div((int32_t)CLOCK_PLL_MICOM_1) + 1UL); + break; + case CLOCK_PCLKCTRL_SEL_XIN: + src_freq = (uint32_t)CLOCK_XIN_CLK_RATE; + break; + default: + src_freq = 0UL; + break; + } + + if (src_freq > 0UL) { + pclk_ctrl.freq = 0; + pclk_ctrl.div_val = (reg_va & ((uint32_t)CLOCK_PCLKCTRL_DIV_XXX_MASK + << (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT)) >> + (uint32_t)CLOCK_PCLKCTRL_DIV_SHIFT; + pclk_ctrl.freq = src_freq / (pclk_ctrl.div_val + 1UL); + ret = (uint32_t)pclk_ctrl.freq; + } + + return ret; +} + +int32_t clock_set_peri_rate(int32_t id, uint32_t rate) +{ + CLOCKPeri_t peri_offset; + uint32_t reg; + int32_t err; + struct clock_pclk_ctrl pclk_ctrl; + + peri_offset = CLOCK_PERI_SFMC; + reg = (uint32_t)CLOCK_BASE_ADDR + (uint32_t)CLOCK_MCKC_PCLKCTRL + + (((uint32_t)id - (uint32_t)peri_offset) * 4UL); + err = 0; + pclk_ctrl.freq = rate; + pclk_ctrl.peri_name = (uint32_t)id; + pclk_ctrl.div_val = 0; + pclk_ctrl.md = (uint32_t)CLOCK_PCLKCTRL_MODE_DIVIDER; + pclk_ctrl.sel = (uint32_t)CLOCK_MPCLKCTRL_SEL_XIN; + + if (clock_dev_find_pclk(&pclk_ctrl, CLOCK_PCLKCTRL_TYPE_XXX) != 0L) { + clock_dev_write_pclk_ctrl(reg, (uint32_t)CLOCK_PCLKCTRL_MODE_DIVIDER, + (uint32_t)false, (uint32_t)CLOCK_MPCLKCTRL_SEL_XIN, 1UL, + (uint32_t)CLOCK_PCLKCTRL_TYPE_XXX); + err = -EIO; + } else { + if ((sys_read32(reg) & (1UL << (uint32_t)CLOCK_PCLKCTRL_EN_SHIFT)) != 0UL) { + pclk_ctrl.en = 1; + } else { + pclk_ctrl.en = 0; + } + + clock_dev_write_pclk_ctrl(reg, pclk_ctrl.md, pclk_ctrl.en, pclk_ctrl.sel, + pclk_ctrl.div_val, (uint32_t)CLOCK_PCLKCTRL_TYPE_XXX); + } + + return err; +} + +int32_t clock_is_iobus_pwdn(int32_t id) +{ + uint32_t reg; + int32_t rest; + CLOCKIobus_t iobus; + + iobus = (CLOCKIobus_t)id; + + if ((int32_t)iobus < (32L * 1L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK0; + } else if ((int32_t)iobus < (32L * 2L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK1; + } else if ((int32_t)iobus < (32L * 3L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK2; + } else { + return -EINVAL; + } + + rest = (int32_t)iobus % 32L; + + return ((sys_read32(reg) & (1UL << (uint32_t)rest)) != 0UL) ? 0L : 1L; +} + +int32_t clock_enable_iobus(int32_t id, bool en) +{ + int32_t ret; + + if (en == true) { + if (clock_set_iobus_pwdn(id, false) == 0L) { + ret = clock_set_sw_reset(id, false); + } else { + ret = -EIO; + } + } else { + if (clock_set_sw_reset(id, true) == 0L) { + ret = clock_set_iobus_pwdn(id, true); + } else { + ret = -EIO; + } + } + + return ret; +} + +int32_t clock_set_iobus_pwdn(int32_t id, bool en) +{ + uint32_t reg; + int32_t rest; + CLOCKIobus_t iobus; + + iobus = (CLOCKIobus_t)id; + + if ((int32_t)iobus < (32L * 1L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK0; + } else if ((int32_t)iobus < (32L * 2L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK1; + } else if ((int32_t)iobus < (32L * 3L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLK2; + } else { + return -EINVAL; + } + + rest = (int32_t)iobus % 32; + + if (en == true) { + sys_write32(sys_read32(reg) & ~((uint32_t)1UL << (uint32_t)rest), reg); + } else { + sys_write32(sys_read32(reg) | ((uint32_t)1UL << (uint32_t)rest), reg); + } + + return 0; +} + +int32_t clock_set_sw_reset(int32_t id, bool reset) +{ + uint32_t reg; + int32_t rest; + CLOCKIobus_t iobus; + + iobus = (CLOCKIobus_t)id; + + if ((int32_t)iobus < (32L * 1L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLKSWR0; + } else if ((int32_t)iobus < (32L * 2L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLKSWR1; + } else if ((int32_t)iobus < (32L * 3L)) { + reg = (uint32_t)MCU_BSP_SUBSYS_BASE + (uint32_t)CLOCK_MCKC_HCLKSWR2; + } else { + return -EINVAL; + } + + rest = (int32_t)iobus % 32; + + if (reset == true) { + sys_write32(sys_read32(reg) & ~((uint32_t)1UL << (uint32_t)rest), reg); + } else { + sys_write32(sys_read32(reg) | ((uint32_t)1UL << (uint32_t)rest), reg); + } + + return 0; +} + +static int tcc_clock_control_get_rate(const struct device *dev, clock_control_subsys_t sys, + uint32_t *rate) +{ + /* const struct device *syscon = DEV_CFG(dev)->syscon; */ + uint32_t clk_id = (uint32_t)sys; + + *rate = clock_get_clk_ctrl_rate(clk_id); + + return 0; +} + +static int clock_control_tcc_vcp_init(const struct device *dev) +{ + vcp_clock_init(); + + return 0; +} + +static const struct clock_control_driver_api tcc_clk_api = { + .get_rate = tcc_clock_control_get_rate, +}; + +#define TCC_CLOCK_INIT(n) \ + static const struct clock_tcc_config clock_tcc_cfg_##n = { \ + .syscon = DEVICE_DT_GET(DT_NODELABEL(syscon)), \ + }; \ + DEVICE_DT_INST_DEFINE(n, clock_control_tcc_vcp_init, NULL, NULL, &clock_tcc_cfg_##n, \ + PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &tcc_clk_api); + +DT_INST_FOREACH_STATUS_OKAY(TCC_CLOCK_INIT) diff --git a/drivers/console/CMakeLists.txt b/drivers/console/CMakeLists.txt index b31486dee4242..ffd5c5027b2b9 100644 --- a/drivers/console/CMakeLists.txt +++ b/drivers/console/CMakeLists.txt @@ -15,3 +15,4 @@ zephyr_library_sources_ifdef(CONFIG_UART_MCUMGR uart_mcumgr.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_SIM_CONSOLE xtensa_sim_console.c) zephyr_library_sources_ifdef(CONFIG_EFI_CONSOLE efi_console.c) zephyr_library_sources_ifdef(CONFIG_WINSTREAM_CONSOLE winstream_console.c) +zephyr_library_sources_ifdef(CONFIG_TCCVCP_CONSOLE tccvcp_console.c) diff --git a/drivers/console/Kconfig b/drivers/console/Kconfig index 17e45604b43ec..fe981ef39bb18 100644 --- a/drivers/console/Kconfig +++ b/drivers/console/Kconfig @@ -304,4 +304,11 @@ config WINSTREAM_CONSOLE_STATIC_SIZE endif # WINSTREAM_CONSOLE +config TCCVCP_CONSOLE + bool "Use TCCVCP console" + depends on SERIAL && SERIAL_HAS_DRIVER && UART_TCCVCP + select CONSOLE_HAS_DRIVER + help + Use tccvcp as a console. + endif # CONSOLE diff --git a/drivers/console/tccvcp_console.c b/drivers/console/tccvcp_console.c new file mode 100644 index 0000000000000..5ee4e014327e9 --- /dev/null +++ b/drivers/console/tccvcp_console.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static const struct device *const uart_console_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + +void uart_tccvcp_poll_out(const struct device *dev, unsigned char c); + +static int arch_printk_char_out(int c) +{ + if (!device_is_ready(uart_console_dev)) { + return -ENODEV; + } + + if ('\n' == c) { + uart_tccvcp_poll_out(uart_console_dev, '\r'); + } + uart_tccvcp_poll_out(uart_console_dev, c); + + return c; +} + +static void tccvcp_console_hook_install(void) +{ +#if defined(CONFIG_PRINTK) + __printk_hook_install(arch_printk_char_out); +#endif + __stdout_hook_install(arch_printk_char_out); +} + +static int tccvcp_console_init(void) +{ + if (!device_is_ready(uart_console_dev)) { + return -ENODEV; + } + + tccvcp_console_hook_install(); + + return 0; +} + +SYS_INIT(tccvcp_console_init, POST_KERNEL, CONFIG_CONSOLE_INIT_PRIORITY); diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index 9772dd8e4ef43..e8cf62b6acdc3 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -111,6 +111,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_STMPE1600 gpio_stmpe1600.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c) zephyr_library_sources_ifdef(CONFIG_GPIO_SY1XX gpio_sy1xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TCA6424A gpio_tca6424a.c) +zephyr_library_sources_ifdef(CONFIG_GPIO_TCCVCP gpio_tccvcp.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TELINK_B91 gpio_b91.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TEST gpio_test.c) zephyr_library_sources_ifdef(CONFIG_GPIO_TLE9104 gpio_tle9104.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index dcf5a8c043c6e..b3e37d46f431c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -193,6 +193,7 @@ source "drivers/gpio/Kconfig.stmpe1600" source "drivers/gpio/Kconfig.sx1509b" source "drivers/gpio/Kconfig.sy1xx" source "drivers/gpio/Kconfig.tca6424a" +source "drivers/gpio/Kconfig.tccvcp" source "drivers/gpio/Kconfig.test" source "drivers/gpio/Kconfig.tle9104" source "drivers/gpio/Kconfig.wch_ch32v00x" diff --git a/drivers/gpio/Kconfig.tccvcp b/drivers/gpio/Kconfig.tccvcp new file mode 100644 index 0000000000000..eacc38ce36b7a --- /dev/null +++ b/drivers/gpio/Kconfig.tccvcp @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config GPIO_TCCVCP + bool "Telechips TOPST VCP SoC GPIO Driver" + default y + depends on DT_HAS_TCC_TCCVCP_GPIO_ENABLED + help + Enable Driver for Telechips TOPST VCP SoC GPIO Banks. diff --git a/drivers/gpio/gpio_tccvcp.c b/drivers/gpio/gpio_tccvcp.c new file mode 100644 index 0000000000000..ee19972fb25b5 --- /dev/null +++ b/drivers/gpio/gpio_tccvcp.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT tcc_tccvcp_gpio + +#include +#include +#include +#include +#include + +struct gpio_tccvcp_config { + struct gpio_driver_config common; + + DEVICE_MMIO_NAMED_ROM(reg_base); + mem_addr_t offset; +}; + +struct gpio_tccvcp_data { + struct gpio_driver_data common; + + DEVICE_MMIO_NAMED_RAM(reg_base); + mem_addr_t base; +}; + +typedef struct { + uint32_t peri_sel; + uint32_t ch_sel; + uint32_t peri_sel_shift; + uint32_t ch_sel_shift; + int flag_idx; +} mfio_cfg_info_t; + +#define DEV_CFG(dev) ((const struct gpio_tccvcp_config *)(dev)->config) +#define DEV_DATA(dev) ((struct gpio_tccvcp_data *)(dev)->data) + +int mfio_ch_cfg_flag[3] = { + 0, +}; + +int32_t vcp_gpio_set(uint32_t port, uint32_t data) +{ + uint32_t bit, data_or, data_bic; + + bit = (uint32_t)1 << (port & GPIO_PIN_MASK); + + if (data > 1UL) { + return -EINVAL; + } + + /* set data */ + if (data != 0UL) { + data_or = GPIO_REG_DATA_OR(port); + sys_write32(bit, data_or); + } else { + data_bic = GPIO_REG_DATA_BIC(port); + sys_write32(bit, data_bic); + } + + return 0; +} + +static void vcp_gpio_set_register(uint32_t addr, uint32_t bit, uint32_t enable) +{ + uint32_t base_val, set_val; + + base_val = sys_read32(addr); + + if (enable == 1UL) { + set_val = (base_val | bit); + } else if (enable == 0UL) { + set_val = (base_val & ~bit); + } else { + set_val = 0UL; + } + + sys_write32(set_val, addr); +} + +int32_t vcp_gpio_peri_chan_sel(uint32_t peri_chan_sel, uint32_t chan) +{ + uint32_t peri_sel_addr, clear_bit; + uint32_t set_bit, base_val, comp_val; + + peri_sel_addr = GPIO_PERICH_SEL; + base_val = sys_read32(peri_sel_addr); + + if (peri_chan_sel < GPIO_PERICH_SEL_I2SSEL_0) { + if (chan < 2) { + /* clear bit */ + clear_bit = base_val & ~((0x1UL) << peri_chan_sel); + sys_write32(clear_bit, peri_sel_addr); + /* set bit */ + base_val = sys_read32(peri_sel_addr); + set_bit = base_val | ((chan & 0x1UL) << peri_chan_sel); + sys_write32(set_bit, peri_sel_addr); + comp_val = sys_read32(peri_sel_addr); + + if (comp_val != set_bit) { + return -EIO; + } + } else { + return -EINVAL; + } + } else { + if (chan < 4) { + /* clear bit */ + clear_bit = base_val & ~((0x3UL) << peri_chan_sel); + sys_write32(clear_bit, peri_sel_addr); + /* set bit */ + base_val = sys_read32(peri_sel_addr); + set_bit = base_val | ((chan & 0x3UL) << peri_chan_sel); + sys_write32(set_bit, peri_sel_addr); + comp_val = sys_read32(peri_sel_addr); + + if (comp_val != set_bit) { + return -EIO; + } + } else { + return -EINVAL; + } + } + + return 0; +} + +static inline uint32_t get_pullen_addr(uint32_t port) +{ + return GPIO_IS_GPIOK(port) ? (GPIO_PMGPIO_BASE + 0x10UL) : (GPIO_REG_BASE(port) + 0x1CUL); +} +static inline uint32_t get_pullsel_addr(uint32_t port) +{ + return GPIO_IS_GPIOK(port) ? (GPIO_PMGPIO_BASE + 0x14UL) : (GPIO_REG_BASE(port) + 0x20UL); +} +static inline uint32_t get_cd_addr(uint32_t port, uint32_t pin) +{ + uint32_t offset = 0x4UL * (pin / 16U); + + return GPIO_IS_GPIOK(port) ? (GPIO_PMGPIO_BASE + 0x18UL + offset) + : (GPIO_REG_BASE(port) + 0x14UL + offset); +} +static inline uint32_t get_ien_addr(uint32_t port) +{ + return GPIO_IS_GPIOK(port) ? (GPIO_PMGPIO_BASE + 0x0CUL) : (GPIO_REG_BASE(port) + 0x24UL); +} + +static void set_pull_config(uint32_t port, uint32_t bit, uint32_t pull) +{ + uint32_t pullen_addr = get_pullen_addr(port); + uint32_t pullsel_addr = get_pullsel_addr(port); + + if (pull == GPIO_PULLUP) { + vcp_gpio_set_register(pullen_addr, bit, true); + vcp_gpio_set_register(pullsel_addr, bit, true); + } else if (pull == GPIO_PULLDN) { + vcp_gpio_set_register(pullen_addr, bit, true); + vcp_gpio_set_register(pullsel_addr, bit, false); + } else { + vcp_gpio_set_register(pullen_addr, bit, false); + } +} + +static void set_inputbuf_config(uint32_t port, uint32_t bit, uint32_t ien) +{ + uint32_t ien_addr = get_ien_addr(port); + + if (ien == GPIO_INPUTBUF_EN) { + vcp_gpio_set_register(ien_addr, bit, true); + } + + if (ien == GPIO_INPUTBUF_DIS) { + vcp_gpio_set_register(ien_addr, bit, false); + } +} + +static void set_drive_strength(uint32_t port, uint32_t pin, uint32_t ds) +{ + if (ds == 0UL) { + return; + } + uint32_t cd_addr = get_cd_addr(port, pin); + + ds = ds >> GPIO_DS_SHIFT; + uint32_t base_val = sys_read32(cd_addr) & ~(3U << ((pin % 16U) * 2U)); + uint32_t set_val = base_val | ((ds & 0x3U) << ((pin % 16U) * 2U)); + + sys_write32(set_val, cd_addr); +} + +int32_t vcp_gpio_config(uint32_t port, uint32_t config) +{ + uint32_t pin = port & GPIO_PIN_MASK; + uint32_t bit = 1U << pin; + uint32_t func = config & GPIO_FUNC_MASK; + uint32_t pull = config & (GPIO_PULL_MASK << GPIO_PULL_SHIFT); + uint32_t ds = config & (GPIO_DS_MASK << GPIO_DS_SHIFT); + uint32_t ien = config & (GPIO_INPUTBUF_MASK << GPIO_INPUTBUF_SHIFT); + + uint32_t reg_fn = GPIO_REG_FN(port, pin); + uint32_t base_val = sys_read32(reg_fn) & ~(0xFU << ((pin % 8U) * 4U)); + uint32_t set_val = base_val | (func << ((pin % 8U) * 4U)); + + sys_write32(set_val, reg_fn); + + if (sys_read32(reg_fn) != set_val) { + return -EINVAL; + } + + set_pull_config(port, bit, pull); + + set_drive_strength(port, pin, ds); + + uint32_t outen_addr = GPIO_REG_OUTEN(port); + + vcp_gpio_set_register(outen_addr, bit, (config & VCP_GPIO_OUTPUT) != 0UL); + + set_inputbuf_config(port, bit, ien); + + return 0; +} + +static const mfio_cfg_info_t mfio_cfg_table[] = { + {GPIO_MFIO_CFG_PERI_SEL0, GPIO_MFIO_CFG_CH_SEL0, GPIO_MFIO_CFG_PERI_SEL0, + GPIO_MFIO_CFG_CH_SEL0, 0}, + {GPIO_MFIO_CFG_PERI_SEL1, GPIO_MFIO_CFG_CH_SEL1, GPIO_MFIO_CFG_PERI_SEL1, + GPIO_MFIO_CFG_CH_SEL1, 1}, + {GPIO_MFIO_CFG_PERI_SEL2, GPIO_MFIO_CFG_CH_SEL2, GPIO_MFIO_CFG_PERI_SEL2, + GPIO_MFIO_CFG_CH_SEL2, 2}, +}; + +static int find_mfio_cfg_index(uint32_t peri_sel, uint32_t ch_sel) +{ + for (int i = 0; i < 3; ++i) { + if (mfio_cfg_table[i].peri_sel == peri_sel && mfio_cfg_table[i].ch_sel == ch_sel) { + return i; + } + } + return -1; +} + +static int mfio_cfg_set(const mfio_cfg_info_t *info, uint32_t peri_type, uint32_t chan_num) +{ + if (mfio_ch_cfg_flag[info->flag_idx] != 0) { + return -EINVAL; + } + + uint32_t base_val = sys_read32(GPIO_MFIO_CFG); + uint32_t clear_bit = + base_val & ~((0x3UL) << info->ch_sel_shift) & ~((0x3UL) << info->peri_sel_shift); + sys_write32(clear_bit, GPIO_MFIO_CFG); + + base_val = sys_read32(GPIO_MFIO_CFG); + uint32_t set_val = base_val | ((chan_num & 0x3UL) << info->ch_sel_shift) | + ((peri_type & 0x3UL) << info->peri_sel_shift); + sys_write32(set_val, GPIO_MFIO_CFG); + + uint32_t comp_val = sys_read32(GPIO_MFIO_CFG); + + if (comp_val != set_val) { + return -EIO; + } + + mfio_ch_cfg_flag[info->flag_idx] = 1; + return 0; +} + +int32_t vcp_gpio_mfio_config(uint32_t peri_sel, uint32_t peri_type, uint32_t chan_sel, + uint32_t chan_num) +{ + int idx = find_mfio_cfg_index(peri_sel, chan_sel); + + if (idx < 0) { + return -EINVAL; + } + + return mfio_cfg_set(&mfio_cfg_table[idx], peri_type, chan_num); +} + +static int gpio_tccvcp_pin_configure(const struct device *port, gpio_pin_t pin, gpio_flags_t flags) +{ + struct gpio_tccvcp_data *data = port->data; + + if (flags & (GPIO_SINGLE_ENDED | GPIO_PULL_UP | GPIO_PULL_DOWN)) { + return -ENOTSUP; + } + + if (flags & GPIO_INPUT) { + sys_set_bit(data->base + GPIO_IN_EN, pin); + } else if (flags & GPIO_OUTPUT) { + sys_set_bit(data->base + GPIO_OUT_EN, pin); + } else { + return 0; + } + + return 0; +} + +static int gpio_tccvcp_port_get_raw(const struct device *port, gpio_port_value_t *value) +{ + struct gpio_tccvcp_data *data = port->data; + + *value = sys_read32(data->base + GPIO_DATA); + + return 0; +} + +static int gpio_tccvcp_port_set_masked_raw(const struct device *port, gpio_port_pins_t mask, + gpio_port_value_t value) +{ + struct gpio_tccvcp_data *data = port->data; + + sys_write32(mask, data->base + GPIO_OUT_DATA_BIC); + sys_write32((value & mask), data->base + GPIO_OUT_DATA_OR); + + return 0; +} + +static int gpio_tccvcp_port_set_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_tccvcp_data *data = port->data; + + sys_write32(pins, data->base + GPIO_OUT_DATA_OR); + + return 0; +} + +static int gpio_tccvcp_port_clear_bits_raw(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_tccvcp_data *data = port->data; + + sys_write32(pins, data->base + GPIO_OUT_DATA_BIC); + + return 0; +} + +static int gpio_tccvcp_port_toggle_bits(const struct device *port, gpio_port_pins_t pins) +{ + struct gpio_tccvcp_data *data = port->data; + uint32_t reg_data; + + reg_data = sys_read32(data->base + GPIO_DATA); + if (reg_data & pins) { /* 1 -> 0 */ + sys_write32(pins, data->base + GPIO_OUT_DATA_BIC); + } else { /* 0 -> 1 */ + sys_write32(pins, data->base + GPIO_OUT_DATA_OR); + } + + return 0; +} + +static const struct gpio_driver_api gpio_tccvcp_api = { + .pin_configure = gpio_tccvcp_pin_configure, + .port_get_raw = gpio_tccvcp_port_get_raw, + .port_set_masked_raw = gpio_tccvcp_port_set_masked_raw, + .port_set_bits_raw = gpio_tccvcp_port_set_bits_raw, + .port_clear_bits_raw = gpio_tccvcp_port_clear_bits_raw, + .port_toggle_bits = gpio_tccvcp_port_toggle_bits, +}; + +static int gpio_tccvcp_init(const struct device *port) +{ + const struct gpio_tccvcp_config *config = port->config; + struct gpio_tccvcp_data *data = port->data; + + DEVICE_MMIO_NAMED_MAP(port, reg_base, K_MEM_CACHE_NONE); + data->base = DEVICE_MMIO_NAMED_GET(port, reg_base) + config->offset; + + return 0; +} + +#define GPIO_TCCVCP_INIT(n) \ + static struct gpio_tccvcp_data gpio_tccvcp_data_##n; \ + \ + static const struct gpio_tccvcp_config gpio_tccvcp_cfg_##n = { \ + .common = {.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}, \ + DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_INST_PARENT(n)), \ + .offset = DT_INST_REG_ADDR(n), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, gpio_tccvcp_init, NULL, &gpio_tccvcp_data_##n, \ + &gpio_tccvcp_cfg_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \ + &gpio_tccvcp_api); + +DT_INST_FOREACH_STATUS_OKAY(GPIO_TCCVCP_INIT) diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 543fdffdf1859..e3d85a5fc73d5 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -47,6 +47,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) zephyr_library_sources_ifdef(CONFIG_INTC_MTK_ADSP intc_mtk_adsp.c) zephyr_library_sources_ifdef(CONFIG_WCH_PFIC intc_wch_pfic.c) zephyr_library_sources_ifdef(CONFIG_WCH_EXTI intc_wch_exti.c) +zephyr_library_sources_ifdef(CONFIG_TIC intc_tic.c) if(CONFIG_INTEL_VTD_ICTL) zephyr_library_include_directories(${ZEPHYR_BASE}/arch/x86/include) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index 3e6e554bc6d87..c8e23f0b27dab 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -114,4 +114,6 @@ source "drivers/interrupt_controller/Kconfig.wch_pfic" source "drivers/interrupt_controller/Kconfig.wch_exti" +source "drivers/interrupt_controller/Kconfig.tic" + endmenu diff --git a/drivers/interrupt_controller/Kconfig.tic b/drivers/interrupt_controller/Kconfig.tic new file mode 100644 index 0000000000000..b32d3327b60cc --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.tic @@ -0,0 +1,14 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +if CPU_CORTEX_R5 + +config TIC + bool "Telechips Interrupt Controller" + default y + depends on DT_HAS_TCC_TIC_ENABLED + help + The Telechips Interrupt Controller provides hardware assistance for prioritizing + and aggregating the interrupt sources for ARM Cortex-R5 processor cores. + +endif diff --git a/drivers/interrupt_controller/intc_tic.c b/drivers/interrupt_controller/intc_tic.c new file mode 100644 index 0000000000000..b1cf0672a3e20 --- /dev/null +++ b/drivers/interrupt_controller/intc_tic.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * NOTE: This driver implements the GIC400 interfaces. + */ + +#define DT_DRV_COMPAT tcc_tic + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(tic); + +static tic_irq_func_ptr tic_intr_table[TIC_INT_SRC_CNT]; + +static void tic_irq_pri_set_internal(uint32_t irq, uint32_t pri) +{ + uint32_t reg_offset, reg_bits, intr_pri_reg; + + reg_offset = 0; + reg_bits = 0; + intr_pri_reg = 0; + + if ((pri < TIC_PRIORITY_NO_MEAN) && (irq < TIC_INT_SRC_CNT)) { + reg_offset = (irq >> 2u); + reg_bits = (irq & 0x03u); + + intr_pri_reg = tic_distributer->dist_intr_pri[reg_offset]; + intr_pri_reg = (uint32_t)(intr_pri_reg & ~(0xFFu << (reg_bits * 8u))); + intr_pri_reg = (uint32_t)(intr_pri_reg | ((pri & 0xFFu) << (reg_bits * 8u))); + + tic_distributer->dist_intr_pri[reg_offset] = intr_pri_reg; + } +} + +static void tic_irq_config_set(uint32_t irq, uint8_t irq_type) +{ + uint32_t reg_offset, reg_mask, intr_config; + + reg_offset = 0; + reg_mask = 0; + intr_config = 0; + + if (irq < TIC_INT_SRC_CNT) { + reg_offset = (irq >> 4u); + reg_mask = (uint32_t)(0x2u << ((irq & 0xfu) * 2u)); + intr_config = tic_distributer->dist_intr_config[reg_offset]; + + if (((irq_type & (uint8_t)TIC_INT_TYPE_LEVEL_HIGH) == + (uint8_t)TIC_INT_TYPE_LEVEL_HIGH) || + ((irq_type & (uint8_t)TIC_INT_TYPE_LEVEL_LOW) == + (uint8_t)TIC_INT_TYPE_LEVEL_LOW)) { + intr_config = (uint32_t)(intr_config & ~reg_mask); + } else { + intr_config = (uint32_t)(intr_config | reg_mask); + } + + tic_distributer->dist_intr_config[reg_offset] = intr_config; + } +} + +void tic_irq_vector_set(uint32_t irq, uint32_t pri, uint8_t irq_type, tic_isr_func irq_func, + void *irq_arg) +{ + uint32_t rsvd_irq; + + rsvd_irq = 0; + + if ((pri > TIC_PRIORITY_NO_MEAN) || (irq >= TIC_INT_SRC_CNT)) { + return; + } + + tic_irq_pri_set_internal(irq, pri); + tic_irq_config_set(irq, irq_type); + + tic_intr_table[irq].if_func_ptr = irq_func; + tic_intr_table[irq].if_arg_ptr = irq_arg; + tic_intr_table[irq].if_is_both_edge = 0; + + if ((irq >= (uint32_t)TIC_EINT_START_INT) && + (irq <= (uint32_t)TIC_EINT_END_INT) /* Set reversed external interrupt */ + && (irq_type == (uint8_t)TIC_INT_TYPE_EDGE_BOTH)) { /* for supporting both edge. */ + + rsvd_irq = (irq + TIC_EINT_NUM); /* add offset of IRQn */ + + tic_irq_pri_set_internal(rsvd_irq, pri); + tic_irq_config_set(rsvd_irq, irq_type); + + tic_intr_table[rsvd_irq].if_func_ptr = irq_func; + tic_intr_table[rsvd_irq].if_arg_ptr = irq_arg; + tic_intr_table[irq].if_is_both_edge = (1U); + } +} + +unsigned int z_tic_irq_get_active(void) +{ + uint32_t int_id; + + int_id = tic_cpu_if->cpu_intr_ack; + + return int_id; +} + +void z_tic_irq_eoi(unsigned int irq) +{ + tic_cpu_if->cpu_end_intr = irq; +} + +void z_tic_irq_init(void) +{ + unsigned long reg_offset; + + reg_offset = 0; + + /* Global TIC disable -> enable. */ + tic_distributer->dist_ctrl &= (unsigned long)(~ARM_BIT_TIC_DIST_ICDDCR_EN); + tic_distributer->dist_ctrl |= (unsigned long)ARM_BIT_TIC_DIST_ICDDCR_EN; + + for (; reg_offset <= ((unsigned long)(TIC_INT_SRC_CNT - 1UL) / 4UL); reg_offset++) { + tic_distributer->dist_intr_pri[reg_offset] = 0xFAFAFAFAUL; + } + + tic_cpu_if->cpu_pri_mask = UNMASK_VALUE; + tic_cpu_if->cpu_ctlr |= + (TIC_CPUIF_CTRL_ENABLEGRP0 | TIC_CPUIF_CTRL_ENABLEGRP1 | TIC_CPUIF_CTRL_ACKCTL); + + LOG_DBG("TIC: Number of IRQs = %lu\n", (unsigned long)TIC_INT_SRC_CNT); +} + +void z_tic_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags) +{ + tic_irq_pri_set_internal(irq, prio); +} + +void z_tic_irq_enable(unsigned int irq) +{ + uint32_t reg_offset, mask_bit_id; + + reg_offset = 0; + mask_bit_id = 0; + + if (irq < TIC_INT_SRC_CNT) { + reg_offset = (irq >> 5u); /* Calculate the register offset. */ + mask_bit_id = (irq & 0x1Fu); /* Mask bit ID. */ + + tic_distributer->dist_intr_set_en[reg_offset] = (1UL << mask_bit_id); + + if (tic_intr_table[irq].if_is_both_edge == (1UL)) { + reg_offset = ((irq + 10UL) >> 5UL); /* Calculate the register offset. */ + mask_bit_id = ((irq + 10UL) & 0x1FUL); /* Mask bit ID. */ + + tic_distributer->dist_intr_set_en[reg_offset] = (1UL << mask_bit_id); + } + } else { + LOG_ERR("%s: Invalid irq number = %u\n", __func__, irq); + return; + } +} + +void z_tic_irq_disable(unsigned int irq) +{ + uint32_t reg_offset, mask_bit_id; + + reg_offset = 0; + mask_bit_id = 0; + + if (irq < TIC_INT_SRC_CNT) { + reg_offset = (irq >> 5UL); /* Calculate the register offset. */ + mask_bit_id = (irq & 0x1FUL); /* Mask bit ID. */ + + tic_distributer->dist_intr_clr_en[reg_offset] = (1UL << mask_bit_id); + + if (tic_intr_table[irq].if_is_both_edge == (1UL)) { + reg_offset = ((irq + 10UL) >> 5UL); /* Calculate the register offset. */ + mask_bit_id = ((irq + 10UL) & 0x1FUL); /* Mask bit ID. */ + + tic_distributer->dist_intr_clr_en[reg_offset] = (1UL << mask_bit_id); + } + } else { + LOG_ERR("%s: Invalid irq number = %u\n", __func__, irq); + return; + } +} + +bool z_tic_irq_is_enabled(unsigned int irq) +{ + uint32_t reg_offset, mask_bit_id, enabler; + + reg_offset = 0; + mask_bit_id = 0; + + if (irq < TIC_INT_SRC_CNT) { + reg_offset = (irq >> 5u); /* Calculate the register offset. */ + mask_bit_id = (irq & 0x1Fu); /* Mask bit ID. */ + + enabler = tic_distributer->dist_intr_set_en[reg_offset]; + + return (enabler & (1 << mask_bit_id)) != 0; + } + + LOG_ERR("%s: Invalid irq number = %u\n", __func__, irq); + return false; +} + +void z_tic_arm_enter_irq(int irq) +{ + uint32_t target_list_filter; + uint32_t cpu_target_list, group_id; + + target_list_filter = TIC_SGI_TO_TARGETLIST; + cpu_target_list = 0x1UL; /* bitfiled 0 : cpu #0, bitfield n : cpu #n, n : 0 ~ 7 */ + group_id = 0UL; /* 0 : group 0 , 1: group 1 */ + + if (irq <= 15UL) { + tic_distributer->dist_sw_gen_intr = (uint32_t)((target_list_filter & 0x3UL) << 24) | + ((cpu_target_list & 0xffUL) << 16) | + ((group_id & 0x1UL) << 15) | (irq & 0xfUL); + } else { + LOG_ERR("%s: Invalid irq number = %u\n", __func__, irq); + } +} + +void tic_irq_handler(void *arg) +{ + uint32_t intr_ack_reg, irq; + tic_isr_func func_isr; + void *intr_arg_ptr; + + intr_ack_reg = z_tic_irq_get_active(); + irq = intr_ack_reg & 0x3FFU; /* Mask away the CPUID. */ + func_isr = (tic_isr_func)NULL; + intr_arg_ptr = TCC_NULL_PTR; + + if (irq < TIC_INT_SRC_CNT) { + func_isr = tic_intr_table[irq].if_func_ptr; /* Fetch ISR handler. */ + intr_arg_ptr = tic_intr_table[irq].if_arg_ptr; + + if (func_isr != (tic_isr_func)NULL) { + (*func_isr)(intr_arg_ptr); /* Call ISR handler. */ + } + + z_tic_irq_eoi(intr_ack_reg); + } +} diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt index 96574f8714ad2..39e6a12d41d75 100644 --- a/drivers/serial/CMakeLists.txt +++ b/drivers/serial/CMakeLists.txt @@ -92,6 +92,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_SMARTBOND uart_smartbond.c) zephyr_library_sources_ifdef(CONFIG_UART_STELLARIS uart_stellaris.c) zephyr_library_sources_ifdef(CONFIG_UART_STM32 uart_stm32.c) zephyr_library_sources_ifdef(CONFIG_UART_SY1XX uart_sy1xx.c) +zephyr_library_sources_ifdef(CONFIG_UART_TCCVCP uart_tccvcp.c) zephyr_library_sources_ifdef(CONFIG_UART_TELINK_B91 uart_b91.c) zephyr_library_sources_ifdef(CONFIG_UART_WCH_USART uart_wch_usart.c) zephyr_library_sources_ifdef(CONFIG_UART_XEC uart_mchp_xec.c) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ea3fbed123bac..2c38db2418d41 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -231,6 +231,7 @@ rsource "Kconfig.smartbond" rsource "Kconfig.stellaris" rsource "Kconfig.stm32" rsource "Kconfig.sy1xx" +rsource "Kconfig.tccvcp" rsource "Kconfig.test" rsource "Kconfig.uart_sam" rsource "Kconfig.usart_sam" diff --git a/drivers/serial/Kconfig.tccvcp b/drivers/serial/Kconfig.tccvcp new file mode 100644 index 0000000000000..2c72a5fec2abf --- /dev/null +++ b/drivers/serial/Kconfig.tccvcp @@ -0,0 +1,11 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config UART_TCCVCP + bool "Telechips TCC VCP serial driver" + default y + depends on DT_HAS_TCC_TCCVCP_UART_ENABLED + select SERIAL_HAS_DRIVER + select SERIAL_SUPPORT_INTERRUPT + help + This option enables the UART driver for Telechips VCP platforms. diff --git a/drivers/serial/uart_tccvcp.c b/drivers/serial/uart_tccvcp.c new file mode 100644 index 0000000000000..034d9b2c41feb --- /dev/null +++ b/drivers/serial/uart_tccvcp.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT tcc_tccvcp_uart + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "uart_tccvcp.h" +#include + +static struct uart_status uart[UART_CH_MAX]; + +static void uart_write_reg(uint8_t chan, uint32_t addr, uint32_t set_value) +{ + uint32_t base_addr, reg_addr; + + if (uart[chan].status_base == 0UL) { + uart[chan].status_base = UART_GET_BASE(chan); + } + + base_addr = uart[chan].status_base & 0xAFFFFFFFU; + addr &= 0xFFFFU; + reg_addr = base_addr + addr; + sys_write32(set_value, reg_addr); +} + +static int32_t uart_clear_gpio(uint8_t chan) +{ + uint32_t gpio_tx = 0, gpio_rx = 0; + uint32_t gpio_clr2send = 0, gpio_req2send = 0; + uint32_t ret, ret1, ret2; + + ret = 0; + ret1 = 0; + ret2 = 0; + + if (chan >= UART_CH_MAX) { + return -EINVAL; + } + + gpio_tx = uart[chan].status_port.bd_port_tx; + gpio_rx = uart[chan].status_port.bd_port_rx; + + /* Reset gpio */ + ret1 = vcp_gpio_config(gpio_tx, GPIO_FUNC(0UL)); + ret2 = vcp_gpio_config(gpio_rx, GPIO_FUNC(0UL)); + + if ((ret1 != 0) || (ret2 != 0)) { + return -EIO; + } + + if (uart[chan].status_cts_rts == TCC_ON) { + gpio_clr2send = uart[chan].status_port.bd_port_cts; + gpio_req2send = uart[chan].status_port.bd_port_rts; + + ret1 = vcp_gpio_config(gpio_clr2send, GPIO_FUNC(0UL)); + ret2 = vcp_gpio_config(gpio_req2send, GPIO_FUNC(0UL)); + + if ((ret1 != 0) || (ret2 != 0)) { + return -EIO; + } + } + + if ((ret == 0) && (chan >= UART_CH3)) { + /* Reset MFIO Configuration */ + if (chan == UART_CH3) { + ret = vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL0, GPIO_MFIO_DISABLE, + GPIO_MFIO_CFG_CH_SEL0, GPIO_MFIO_CH0); + } else if (chan == UART_CH4) { + ret = vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL1, GPIO_MFIO_DISABLE, + GPIO_MFIO_CFG_CH_SEL1, GPIO_MFIO_CH0); + } else if (chan == UART_CH5) { + ret = vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL2, GPIO_MFIO_DISABLE, + GPIO_MFIO_CFG_CH_SEL2, GPIO_MFIO_CH0); + } else { + return ret; + } + } + + return ret; +} + +static int32_t uart_reset(uint8_t chan) +{ + uint32_t ret; + int32_t clk_ret, clk_bus_id; + + ret = 0; + clk_bus_id = (int32_t)CLOCK_IOBUS_UART0 + (int32_t)chan; + + /* SW reset */ + clk_ret = clock_set_sw_reset(clk_bus_id, true); + + if (clk_ret != (int32_t)NULL) { + return -EIO; + } + + /* Bit Clear */ + clk_ret = clock_set_sw_reset(clk_bus_id, false); + + if (clk_ret != (int32_t)NULL) { + return -EIO; + } + + return ret; +} + +static void uart_close(uint8_t chan) +{ + int32_t clk_bus_id; + uint32_t ret; + + if (chan < UART_CH_MAX) { + /* Disable the UART controller Bus clock */ + clk_bus_id = (int32_t)CLOCK_IOBUS_UART0 + (int32_t)chan; + clock_set_iobus_pwdn(clk_bus_id, true); + + ret = uart_clear_gpio(chan); + + /* Disable the UART ch */ + sys_write32((uint32_t)NULL, MCU_BSP_UART_BASE + (0x10000UL * (chan)) + UART_REG_CR); + + /* Initialize UART Structure */ + memset(&uart[chan], 0, sizeof(struct uart_status)); + + /* UART SW Reset */ + uart_reset(chan); + } +} + +static void uart_status_init(uint8_t chan) +{ + uart[chan].status_is_probed = TCC_OFF; + uart[chan].status_base = UART_GET_BASE(chan); + uart[chan].status_chan = chan; + uart[chan].status_op_mode = UART_POLLING_MODE; + uart[chan].status_cts_rts = 0; + uart[chan].status_word_len = WORD_LEN_5; + uart[chan].status_2stop_bit = 0; + uart[chan].status_parity = PARITY_SPACE; + + /* Interrupt mode init */ + uart[chan].status_tx_intr.irq_data_xmit_buf = NULL; + uart[chan].status_tx_intr.irq_data_head = -1; + uart[chan].status_tx_intr.irq_data_tail = -1; + uart[chan].status_tx_intr.irq_data_size = 0; + uart[chan].status_rx_intr.irq_data_xmit_buf = NULL; + uart[chan].status_rx_intr.irq_data_head = -1; + uart[chan].status_rx_intr.irq_data_tail = -1; + uart[chan].status_rx_intr.irq_data_size = 0; +} + +static int32_t uart_set_gpio(uint8_t chan, const struct uart_board_port *port_info) +{ + int32_t ret; + uint32_t ret1, ret2, ret3, ret4; + uint32_t ret_cfg; + + ret = 0; + ret_cfg = 1; + + if (port_info != TCC_NULL_PTR) { + /* set port controller, channel */ + switch (chan) { + case UART_CH0: + ret_cfg = vcp_gpio_peri_chan_sel(GPIO_PERICH_SEL_UARTSEL_0, + port_info->bd_port_ch); + break; + case UART_CH1: + ret_cfg = vcp_gpio_peri_chan_sel(GPIO_PERICH_SEL_UARTSEL_1, + port_info->bd_port_ch); + break; + case UART_CH2: + ret_cfg = vcp_gpio_peri_chan_sel(GPIO_PERICH_SEL_UARTSEL_2, + port_info->bd_port_ch); + break; + case UART_CH3: + ret_cfg = + vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL0, GPIO_MFIO_UART3, + GPIO_MFIO_CFG_CH_SEL0, port_info->bd_port_ch); + break; + case UART_CH4: + ret_cfg = + vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL1, GPIO_MFIO_UART4, + GPIO_MFIO_CFG_CH_SEL1, port_info->bd_port_ch); + break; + case UART_CH5: + ret_cfg = + vcp_gpio_mfio_config(GPIO_MFIO_CFG_PERI_SEL2, GPIO_MFIO_UART5, + GPIO_MFIO_CFG_CH_SEL2, port_info->bd_port_ch); + break; + default: + ret_cfg = -EINVAL; + break; + } + + if (ret_cfg == 0) { + /* set debug port */ + ret1 = vcp_gpio_config(port_info->bd_port_tx, + (port_info->bd_port_fs)); /* TX */ + ret2 = vcp_gpio_config(port_info->bd_port_rx, + (port_info->bd_port_fs | VCP_GPIO_INPUT | + GPIO_INPUTBUF_EN)); /* RX */ + + uart[chan].status_port.bd_port_cfg = port_info->bd_port_cfg; + uart[chan].status_port.bd_port_tx = port_info->bd_port_tx; + uart[chan].status_port.bd_port_rx = port_info->bd_port_rx; + uart[chan].status_port.bd_port_fs = port_info->bd_port_fs; + + if (uart[chan].status_cts_rts != 0UL) { + ret3 = vcp_gpio_config(port_info->bd_port_rts, + port_info->bd_port_fs); /* RTS */ + ret4 = vcp_gpio_config(port_info->bd_port_cts, + port_info->bd_port_fs); /* CTS */ + + if ((ret1 != 0) || (ret2 != 0) || (ret3 != 0) || (ret4 != 0)) { + ret = -EIO; + } else { + uart[chan].status_port.bd_port_cts = port_info->bd_port_cts; + uart[chan].status_port.bd_port_rts = port_info->bd_port_rts; + } + } + + if ((uart[chan].status_cts_rts == 0) && ((ret1 != 0) || (ret2 != 0))) { + ret = -EIO; + } + } else { + ret = -EIO; + } + } else { + ret = -EINVAL; + } + + return ret; +} + +static int32_t uart_set_port_config(uint8_t chan, uint32_t port) +{ + uint32_t idx; + int32_t ret = 0; + static const struct uart_board_port board_serial[UART_PORT_TBL_SIZE] = { + {0UL, GPIO_GPA(28UL), GPIO_GPA(29UL), TCC_GPNONE, TCC_GPNONE, GPIO_FUNC(1UL), + GPIO_PERICH_CH0}, /* CTL_0, CH_0 */ + {1UL, GPIO_GPC(16UL), GPIO_GPC(17UL), GPIO_GPC(18UL), GPIO_GPC(19UL), + GPIO_FUNC(2UL), GPIO_PERICH_CH1}, /* CTL_0, CH_1 */ + + {2UL, GPIO_GPB(8UL), GPIO_GPB(9UL), GPIO_GPB(10UL), GPIO_GPB(11UL), GPIO_FUNC(1UL), + GPIO_PERICH_CH0}, /* CTL_1, CH_0 */ + {3UL, GPIO_GPA(6UL), GPIO_GPA(7UL), GPIO_GPA(8UL), GPIO_GPA(9UL), GPIO_FUNC(2UL), + GPIO_PERICH_CH1}, /* CTL_1, CH_1 */ + + {4UL, GPIO_GPB(25UL), GPIO_GPB(26UL), GPIO_GPB(27UL), GPIO_GPB(28UL), + GPIO_FUNC(1UL), GPIO_PERICH_CH0}, /* CTL_2, CH_0 */ + {5UL, GPIO_GPC(0UL), GPIO_GPC(1UL), GPIO_GPC(2UL), GPIO_GPC(3UL), GPIO_FUNC(2UL), + GPIO_PERICH_CH1}, /* CTL_2, CH_1 */ + + {6UL, GPIO_GPA(16UL), GPIO_GPA(17UL), GPIO_GPA(18UL), GPIO_GPA(19UL), + GPIO_FUNC(3UL), GPIO_MFIO_CH0}, /* CTL_3, CH_0 */ + {7UL, GPIO_GPB(0UL), GPIO_GPB(1UL), GPIO_GPB(2UL), GPIO_GPB(3UL), GPIO_FUNC(3UL), + GPIO_MFIO_CH1}, /* CTL_3, CH_1 */ + {8UL, GPIO_GPC(4UL), GPIO_GPC(5UL), GPIO_GPC(6UL), GPIO_GPC(7UL), GPIO_FUNC(3UL), + GPIO_MFIO_CH2}, /* CTL_3, CH_2 */ + {9UL, GPIO_GPK(11UL), GPIO_GPK(12UL), GPIO_GPK(13UL), GPIO_GPK(14UL), + GPIO_FUNC(3UL), GPIO_MFIO_CH3}, /* CTL_3, CH_3 */ + + {10UL, GPIO_GPA(20UL), GPIO_GPA(21UL), GPIO_GPA(22UL), GPIO_GPA(23UL), + GPIO_FUNC(3UL), GPIO_MFIO_CH0}, /* CTL_4, CH_0 */ + {11UL, GPIO_GPB(4UL), GPIO_GPB(5UL), GPIO_GPB(6UL), GPIO_GPB(7UL), GPIO_FUNC(3UL), + GPIO_MFIO_CH1}, /* CTL_4, CH_1 */ + {12UL, GPIO_GPC(8UL), GPIO_GPC(9UL), GPIO_GPC(10UL), GPIO_GPC(11UL), GPIO_FUNC(3UL), + GPIO_MFIO_CH2}, /* CTL_4, CH_2 */ + + {13UL, GPIO_GPA(24UL), GPIO_GPA(25UL), GPIO_GPA(26UL), GPIO_GPA(27UL), + GPIO_FUNC(3UL), GPIO_MFIO_CH0}, /* CTL_5, CH_0 */ + {14UL, GPIO_GPB(8UL), GPIO_GPB(9UL), GPIO_GPB(10UL), GPIO_GPB(11UL), GPIO_FUNC(3UL), + GPIO_MFIO_CH1}, /* CTL_5, CH_1 */ + {15UL, GPIO_GPC(12UL), GPIO_GPC(13UL), GPIO_GPC(14UL), GPIO_GPC(15UL), + GPIO_FUNC(3UL), GPIO_MFIO_CH2}, /* CTL_5, CH_2 */ + }; + + if ((port < UART_PORT_CFG_MAX) && (chan < UART_CH_MAX)) { + for (idx = 0UL; idx < UART_PORT_CFG_MAX; idx++) { + if (board_serial[idx].bd_port_cfg == port) { + ret = uart_set_gpio(chan, &board_serial[idx]); + break; + } + } + } + + return ret; +} + +static int32_t uart_set_baud_rate(uint8_t chan, uint32_t baud) +{ + uint32_t divider, mod, brd_i, brd_f, pclk; + int32_t ret; + + if (chan >= UART_CH_MAX) { + ret = -EINVAL; + } else { + /* Read the peri clock */ + pclk = clock_get_peri_rate((int32_t)CLOCK_PERI_UART0 + (int32_t)chan); + + if (pclk == 0UL) { + ret = -EIO; + } else { + /* calculate integer baud rate divisor */ + divider = 16UL * baud; + brd_i = pclk / divider; + uart_write_reg(chan, UART_REG_IBRD, brd_i); + + /* calculate faction baud rate divisor */ + /* NOTICE : fraction maybe need sampling */ + baud &= 0xFFFFFFU; + mod = (pclk % (16UL * baud)) & 0xFFFFFFU; + divider = ((((1UL << 3UL) * 16UL) * mod) / (16UL * baud)); + brd_f = divider / 2UL; + uart_write_reg(chan, UART_REG_FBRD, brd_f); + ret = (int32_t)0; + } + } + return ret; +} + +static int32_t uart_set_chan_config(struct uart_param *uart_cfg) +{ + uint8_t chan; + uint8_t word_len = (uint8_t)uart_cfg->word_length; + uint32_t cr_data = 0, lcr_data = 0; + int32_t ret, clk_bus_id, clk_peri_id; + + chan = uart_cfg->channel; + /* Enable the UART controller peri clock */ + clk_bus_id = (int32_t)CLOCK_IOBUS_UART0 + (int32_t)chan; + clock_set_iobus_pwdn(clk_bus_id, false); + clk_peri_id = (int32_t)CLOCK_PERI_UART0 + (int32_t)chan; + ret = clock_set_peri_rate(clk_peri_id, UART_DEBUG_CLK); + clock_enable_peri(clk_peri_id); + + if (ret == 0) { + uart_set_baud_rate(chan, uart_cfg->baud_rate); + + /* line control setting */ + /* Word Length */ + word_len &= 0x3U; + uart_cfg->word_length = (enum uart_word_len)word_len; + lcr_data |= UART_LCRH_WLEN((uint32_t)uart_cfg->word_length); + + /* Enables FIFOs */ + if (uart_cfg->fifo == ENABLE_FIFO) { + lcr_data |= UART_LCRH_FEN; + } + + /* Two Stop Bits */ + if (uart_cfg->stop_bit == TCC_ON) { + lcr_data |= UART_LCRH_STP2; + } + + /* Parity Enable */ + switch (uart_cfg->parity) { + case PARITY_SPACE: + lcr_data &= ~(UART_LCRH_PEN); + break; + case PARITY_EVEN: + lcr_data |= ((UART_LCRH_PEN | UART_LCRH_EPS) & ~(UART_LCRH_SPS)); + break; + case PARITY_ODD: + lcr_data |= ((UART_LCRH_PEN & ~(UART_LCRH_EPS)) & ~(UART_LCRH_SPS)); + break; + case PARITY_MARK: + lcr_data |= ((UART_LCRH_PEN & ~(UART_LCRH_EPS)) | UART_LCRH_SPS); + break; + default: + break; + } + + uart_write_reg(chan, UART_REG_LCRH, lcr_data); + + /* control register setting */ + cr_data = UART_CR_EN; + cr_data |= UART_CR_TXE; + cr_data |= UART_CR_RXE; + + if (uart[chan].status_cts_rts != 0UL) { /* brace */ + cr_data |= (UART_CR_RTSEN | UART_CR_CTSEN); + } + + uart_write_reg(chan, UART_REG_CR, cr_data); + } + + return ret; +} + +static uint32_t uart_read_reg(uint8_t chan, uint32_t addr) +{ + uint32_t ret, base_addr, reg_addr; + + ret = 0; + + if (uart[chan].status_base == 0UL) { + uart[chan].status_base = UART_GET_BASE(chan); + } + + base_addr = uart[chan].status_base & 0xAFFFFFFFU; + addr &= 0xFFFFU; + reg_addr = base_addr + addr; + ret = sys_read32(reg_addr); + + return ret; +} + +static int32_t uart_probe(struct uart_param *uart_cfg) +{ + uint8_t chan; + int32_t ret = -1; + + chan = uart_cfg->channel; + + if ((chan < UART_CH_MAX) && (uart[chan].status_is_probed == TCC_OFF)) { + uart[chan].status_op_mode = uart_cfg->mode; + uart[chan].status_cts_rts = uart_cfg->cts_rts; + + /* Set port config */ + ret = uart_set_port_config(chan, uart_cfg->port_cfg); + + if (ret == 0) { + ret = uart_set_chan_config(uart_cfg); + + if (ret == 0) { + uart[chan].status_is_probed = TCC_ON; + } + } + } + + return ret; +} + +static int32_t uart_open(struct uart_param *uart_cfg) +{ + uint8_t chan = uart_cfg->channel; + int32_t ret = -EINVAL; + + uart_status_init(chan); + + if (uart_cfg->port_cfg <= UART_PORT_CFG_MAX) { + ret = uart_probe(uart_cfg); + } + + return ret; +} + +static int uart_tccvcp_init(const struct device *dev) +{ + struct uart_param uart_pars; + uint8_t uart_port; + + uart_port = ((UART_BASE_ADDR - MCU_BSP_UART_BASE) / 0x10000); + + uart_pars.channel = uart_port; + uart_pars.priority = TIC_PRIORITY_NO_MEAN; + uart_pars.baud_rate = 115200; + uart_pars.mode = UART_POLLING_MODE; + uart_pars.cts_rts = UART_CTSRTS_OFF; + uart_pars.port_cfg = (uint8_t)(3U + uart_port); + uart_pars.fifo = DISABLE_FIFO, uart_pars.stop_bit = TWO_STOP_BIT_OFF; + uart_pars.word_length = WORD_LEN_8; + uart_pars.parity = PARITY_SPACE; + uart_pars.callback_fn = TCC_NULL_PTR; + + uart_close(uart_pars.channel); + uart_open(&uart_pars); + + return 0; +} + +int uart_tccvcp_poll_in(const struct device *dev, unsigned char *c) +{ + uint8_t chan; + uint32_t data, repeat = 0; + + chan = (uint8_t)((UART_BASE_ADDR - 0xA0200000) / 0x10000); + + if (chan >= UART_CH_MAX) { + return -EINVAL; + } + + while ((uart_read_reg(chan, UART_REG_FR) & UART_FR_RXFE) != 0UL) { + if ((uart_read_reg(chan, UART_REG_FR) & UART_FR_RXFE) == 0UL) { + break; + } + repeat++; + if (repeat > 100) { + return -EIO; + } + } + + data = uart_read_reg(chan, UART_REG_DR); + *c = (unsigned char)(data & 0xFFUL); + + return 0; +} + +void uart_tccvcp_poll_out(const struct device *dev, unsigned char c) +{ + uint8_t chan; + uint32_t repeat = 0; + + chan = (uint8_t)((UART_BASE_ADDR - 0xA0200000) / 0x10000); + + if (chan >= UART_CH_MAX) { + return; + } + + while ((uart_read_reg(chan, UART_REG_FR) & UART_FR_TXFF) != 0UL) { + if ((uart_read_reg(chan, UART_REG_FR) & UART_FR_TXFF) == 0UL) { + break; + } + repeat++; + if (repeat > 100) { + return; + } + } + uart_write_reg(chan, UART_REG_DR, c); +} + +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE +static int uart_tccvcp_configure(const struct device *dev, const struct uart_config *cfg) +{ + const struct uart_tccvcp_dev_config *dev_cfg = dev->config; + uint8_t chan; + struct uart_param uart_cfg; + int32_t ret; + + chan = (uint8_t)((UART_BASE_ADDR - 0xA0200000) / 0x10000); + + uart_cfg.channel = chan; + uart_cfg.priority = TIC_PRIORITY_NO_MEAN; + uart_cfg.baud_rate = 115200; + uart_cfg.mode = UART_POLLING_MODE; + switch (cfg->flow_ctrl) { + case UART_CFG_FLOW_CTRL_NONE: + uart_cfg.cts_rts = UART_CTSRTS_OFF; + break; + case UART_CFG_FLOW_CTRL_RTS_CTS: + uart_cfg.cts_rts = UART_CTSRTS_ON; + break; + default: + uart_cfg.cts_rts = UART_CTSRTS_OFF; + break; + } + + uart_cfg.port_cfg = (uint8_t)(4U + dev_cfg->channel); + + switch (cfg->data_bits) { + case UART_CFG_DATA_BITS_8: + uart_cfg.word_length = WORD_LEN_8; + break; + case UART_CFG_DATA_BITS_7: + uart_cfg.word_length = WORD_LEN_7; + break; + case UART_CFG_DATA_BITS_6: + uart_cfg.word_length = WORD_LEN_6; + break; + case UART_CFG_DATA_BITS_5: + uart_cfg.word_length = WORD_LEN_5; + break; + default: + uart_cfg.word_length = WORD_LEN_8 + 1; + break; + } + + uart_cfg.fifo = DISABLE_FIFO; + + if (cfg->stop_bits == UART_CFG_STOP_BITS_2) { + uart_cfg.stop_bit = TWO_STOP_BIT_ON; + } else { + uart_cfg.stop_bit = TWO_STOP_BIT_OFF; + } + + switch (cfg->parity) { + case UART_CFG_PARITY_EVEN: + uart_cfg.parity = PARITY_EVEN; + break; + case UART_CFG_PARITY_ODD: + uart_cfg.parity = PARITY_ODD; + break; + case UART_CFG_PARITY_SPACE: + uart_cfg.parity = PARITY_SPACE; + break; + case UART_CFG_PARITY_MARK: + uart_cfg.parity = PARITY_MARK; + break; + default: + uart_cfg.parity = PARITY_MARK + 1; + break; + } + + uart_cfg.callback_fn = TCC_NULL_PTR; + + ret = uart_set_chan_config(&uart_cfg); + if (ret == 0) { + uart[chan].status_cts_rts = uart_cfg.cts_rts; + uart[chan].status_2stop_bit = uart_cfg.stop_bit; + uart[chan].status_parity = uart_cfg.parity; + uart[chan].status_word_len = uart_cfg.word_length; + uart[chan].baudrate = uart_cfg.baud_rate; + } + + return ret; +}; + +static int uart_tccvcp_config_get(const struct device *dev, struct uart_config *cfg) +{ + uint8_t chan; + + chan = (uint8_t)((UART_BASE_ADDR - MCU_BSP_UART_BASE) / 0x10000); + cfg->baudrate = uart[chan].baudrate; + + if (uart[chan].status_cts_rts == UART_CTSRTS_ON) { + cfg->flow_ctrl = UART_CFG_FLOW_CTRL_RTS_CTS; + } else { + cfg->flow_ctrl = UART_CFG_FLOW_CTRL_NONE; + } + + switch (uart[chan].status_word_len) { + case WORD_LEN_8: + cfg->data_bits = UART_CFG_DATA_BITS_8; + break; + case WORD_LEN_7: + cfg->data_bits = UART_CFG_DATA_BITS_7; + break; + case WORD_LEN_6: + cfg->data_bits = UART_CFG_DATA_BITS_6; + break; + case WORD_LEN_5: + cfg->data_bits = UART_CFG_DATA_BITS_5; + break; + default: + cfg->data_bits = UART_CFG_DATA_BITS_9; + break; + } + + if (uart[chan].status_2stop_bit == TWO_STOP_BIT_ON) { + cfg->stop_bits = UART_CFG_STOP_BITS_2; + } else { + cfg->stop_bits = UART_CFG_STOP_BITS_0_5; + } + + switch (uart[chan].status_parity) { + case PARITY_EVEN: + cfg->parity = UART_CFG_PARITY_EVEN; + break; + case PARITY_ODD: + cfg->parity = UART_CFG_PARITY_ODD; + break; + case PARITY_SPACE: + cfg->parity = UART_CFG_PARITY_SPACE; + break; + case PARITY_MARK: + cfg->parity = UART_CFG_PARITY_MARK; + break; + default: + cfg->parity = UART_CFG_PARITY_NONE; + break; + } + + return 0; +} +#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ + +static const struct uart_driver_api uart_tccvcp_driver_api = { + .poll_in = uart_tccvcp_poll_in, + .poll_out = uart_tccvcp_poll_out, +#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE + .configure = uart_tccvcp_configure, + .config_get = uart_tccvcp_config_get, +#endif +}; + +#define UART_TCC_VCP_IRQ_CONF_FUNC_SET(port) +#define UART_TCC_VCP_IRQ_CONF_FUNC(port) + +#define UART_TCC_VCP_DEV_DATA(port) static struct uart_tccvcp_dev_data_t uart_tccvcp_dev_data_##port + +#if CONFIG_PINCTRL +#define UART_TCC_VCP_PINCTRL_DEFINE(port) PINCTRL_DT_INST_DEFINE(port); +#define UART_TCC_VCP_PINCTRL_INIT(port) .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(port), +#else +#define UART_TCC_VCP_PINCTRL_DEFINE(port) +#define UART_TCC_VCP_PINCTRL_INIT(port) +#endif /* CONFIG_PINCTRL */ + +#define UART_TCC_VCP_DEV_CFG(port) \ + static struct uart_tccvcp_dev_config uart_tccvcp_dev_cfg_##port = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(port)), \ + .sys_clk_freq = DT_INST_PROP(port, clock_frequency), \ + .baud_rate = DT_INST_PROP(port, current_speed), .channel = port, \ + UART_TCC_VCP_IRQ_CONF_FUNC_SET(port) UART_TCC_VCP_PINCTRL_INIT(port)} + +#define UART_TCC_VCP_INIT(port) \ + DEVICE_DT_INST_DEFINE(port, uart_tccvcp_init, NULL, &uart_tccvcp_dev_data_##port, \ + &uart_tccvcp_dev_cfg_##port, PRE_KERNEL_1, \ + CONFIG_SERIAL_INIT_PRIORITY, &uart_tccvcp_driver_api) + +#define UART_TCC_INSTANTIATE(inst) \ + UART_TCC_VCP_PINCTRL_DEFINE(inst) \ + UART_TCC_VCP_IRQ_CONF_FUNC(inst); \ + UART_TCC_VCP_DEV_DATA(inst); \ + UART_TCC_VCP_DEV_CFG(inst); \ + UART_TCC_VCP_INIT(inst); + +DT_INST_FOREACH_STATUS_OKAY(UART_TCC_INSTANTIATE) diff --git a/drivers/serial/uart_tccvcp.h b/drivers/serial/uart_tccvcp.h new file mode 100644 index 0000000000000..0b90d1099c9fd --- /dev/null +++ b/drivers/serial/uart_tccvcp.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SERIAL_UART_TCCVCP_H_ +#define ZEPHYR_DRIVERS_SERIAL_UART_TCCVCP_H_ + +#define UART_POLLING_MODE 0U +#define UART_INTR_MODE 1U +#define UART_DMA_MODE 2U + +#define UART_CTSRTS_ON 1U +#define UART_CTSRTS_OFF 0U + +#define ENABLE_FIFO 1U +#define DISABLE_FIFO 0U + +#define TWO_STOP_BIT_ON 1U +#define TWO_STOP_BIT_OFF 0U + +/* UART Channels */ +#define UART_CH0 0U +#define UART_CH1 1U +#define UART_CH2 2U +#define UART_CH3 3U +#define UART_CH4 4U +#define UART_CH5 5U +#define UART_CH_MAX 6U + +#define UART_DEBUG_CLK 48000000UL /* 48MHz */ + +/* UART Base address */ +#define UART_GET_BASE(n) (MCU_BSP_UART_BASE + (0x10000UL * (n))) + +/* UART Register (BASE Address + Offset) */ +#define UART_REG_DR 0x00U /* Data register */ +#define UART_REG_RSR 0x04U /* Receive Status register */ +#define UART_REG_ECR 0x04U /* Error Clear register */ +#define UART_REG_FR 0x18U /* Flag register */ +#define UART_REG_IBRD 0x24U /* Integer Baud rate register */ +#define UART_REG_FBRD 0x28U /* Fractional Baud rate register */ +#define UART_REG_LCRH 0x2cU /* Line Control register */ +#define UART_REG_CR 0x30U /* Control register */ +#define UART_REG_IFLS 0x34U /* Interrupt FIFO Level status register */ +#define UART_REG_IMSC 0x38U /* Interrupt Mask Set/Clear register */ +#define UART_REG_RIS 0x3cU /* Raw Interrupt Status register */ +#define UART_REG_MIS 0x40U /* Masked Interrupt Status register */ +#define UART_REG_ICR 0x44U /* Interrupt Clear register */ +#define UART_REG_DMACR 0x48U /* DMA Control register */ + +/* UART Flag Register(FR) Fields */ +#define UART_FR_TXFE (1UL << 7U) /* Transmit FIFO empty */ +#define UART_FR_RXFF (1UL << 6U) /* Receive FIFO full */ +#define UART_FR_TXFF (1UL << 5U) /* Transmit FIFO full */ +#define UART_FR_RXFE (1UL << 4U) /* Receive FIFO empty */ +#define UART_FR_BUSY (1UL << 3U) /* UART busy */ +#define UART_FR_CTS (1UL << 0U) /* Clear to send */ + +/* UART Line Control Register (LCR_H) Fields */ +#define UART_LCRH_SPS (1UL << 7U) /* Stick parity select */ +#define UART_LCRH_WLEN(x) ((x) << 5U) /* Word length */ +#define UART_LCRH_FEN (1UL << 4U) /* Enable FIFOs */ +#define UART_LCRH_STP2 (1UL << 3U) /* Two stop bits select */ +#define UART_LCRH_EPS (1UL << 2U) /* Even parity select */ +#define UART_LCRH_PEN (1UL << 1U) /* Parity enable */ +#define UART_LCRH_BRK (1UL << 0U) /* Send break */ + +/* UART Control Register (CR) Fields */ +#define UART_CR_CTSEN (1UL << 15U) /* CTS hardware flow control enable */ +#define UART_CR_RTSEN (1UL << 14U) /* RTS hardware flow control enable */ +#define UART_CR_RTS (1UL << 11U) /* Request to send */ +#define UART_CR_RXE (1UL << 9U) /* Receive enable */ +#define UART_CR_TXE (1UL << 8U) /* Transmit enable */ +#define UART_CR_LBE (1UL << 7U) /* Loopback enable */ +#define UART_CR_EN (1UL << 0U) /* UART enable */ + +#define UART_TX_FIFO_SIZE 8UL +#define UART_RX_FIFO_SIZE 12UL + +#define UART_INT_OEIS (1UL << 10U) /* Overrun error interrupt */ +#define UART_INT_BEIS (1UL << 9U) /* Break error interrupt */ +#define UART_INT_PEIS (1UL << 8U) /* Parity error interrupt */ +#define UART_INT_FEIS (1UL << 7U) /* Framing error interrupt */ +#define UART_INT_RTIS (1UL << 6U) /* Receive timeout interrupt */ +#define UART_INT_TXIS (1UL << 5U) /* Transmit interrupt */ +#define UART_INT_RXIS (1UL << 4U) /* Receive interrupt */ + +/* UART Settings */ +#define UART_BUFF_SIZE 0x100UL /* 256 */ + +#define UART_MODE_TX 0UL +#define UART_MODE_RX 1UL + +#define UART_PORT_CFG_MAX 16U +#define UART_PORT_TBL_SIZE UART_PORT_CFG_MAX + +/* DMA Control Register (DMACR) Fields */ +#define UART_DMACR_DMAONERR (1UL << 2U) /* DMA on error */ +#define UART_DMACR_TXDMAE (1UL << 1U) /* Transmit DMA enable */ +#define UART_DMACR_RXDMAE (1UL << 0U) /* Receive DMA enable */ + +#define UART_BASE_ADDR DT_INST_REG_ADDR(0) + +#define TCC_GPNONE 0xFFFFUL + +enum uart_word_len { + WORD_LEN_5 = 0, + WORD_LEN_6, + WORD_LEN_7, + WORD_LEN_8 +}; + +enum uart_parity { + PARITY_SPACE = 0, + PARITY_EVEN, + PARITY_ODD, + PARITY_MARK +}; + +struct uart_board_port { + uint32_t bd_port_cfg; /* Config port ID */ + uint32_t bd_port_tx; /* UT_TXD GPIO */ + uint32_t bd_port_rx; /* UT_RXD GPIO */ + uint32_t bd_port_rts; /* UT_RTS GPIO */ + uint32_t bd_port_cts; /* UT_CTS GPIO */ + uint32_t bd_port_fs; /* UART function select */ + uint32_t bd_port_ch; /* Channel */ +}; + +struct uart_interrupt_data { + int8_t *irq_data_xmit_buf; + int32_t irq_data_head; + int32_t irq_data_tail; + int32_t irq_data_size; +}; + +struct uart_param { + uint8_t channel; + uint32_t priority; /* Interrupt priority */ + uint32_t baud_rate; /* Baudrate */ + uint8_t mode; /* polling or interrupt */ + uint8_t cts_rts; /* on/off */ + uint8_t port_cfg; /* port selection */ + uint8_t fifo; /* on/off */ + uint8_t stop_bit; /* on/off */ + enum uart_word_len word_length; /* 5~8 bits */ + enum uart_parity parity; /* space, even, odd, mark */ + tic_isr_func callback_fn; /* callback function */ +}; + +struct uart_status { + unsigned char status_is_probed; + uint32_t status_base; /* UART Controller base address */ + uint8_t status_chan; /* UART Channel */ + uint8_t status_op_mode; /* Operation Mode */ + uint8_t status_cts_rts; /* CTS and RTS */ + uint8_t status_2stop_bit; /* 1: two stop bits are transmitted */ + uint32_t baudrate; /* Baudrate setting in bps */ + enum uart_parity status_parity; /* 0:disable, 1:enable */ + enum uart_word_len status_word_len; /* Word Length */ + struct uart_board_port status_port; /* GPIO Port Information */ + struct uart_interrupt_data status_rx_intr; /* Rx Interrupt */ + struct uart_interrupt_data status_tx_intr; /* Tx Interrupt */ +}; + +/** Device configuration structure */ +struct uart_tccvcp_dev_config { + DEVICE_MMIO_ROM; + uint8_t channel; + uint32_t sys_clk_freq; + struct uart_param uart_pars; +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_config_func_t irq_config_func; +#endif +#ifdef CONFIG_PINCTRL + const struct pinctrl_dev_config *pincfg; +#endif + uint32_t baud_rate; +}; + +/** Device data structure */ +struct uart_tccvcp_dev_data_t { + DEVICE_MMIO_RAM; + uint32_t parity; + uint32_t stopbits; + uint32_t databits; + uint32_t flowctrl; + +#ifdef CONFIG_UART_INTERRUPT_DRIVEN + uart_irq_callback_user_data_t user_cb; + void *user_data; +#endif +}; + +#endif /* ZEPHYR_DRIVERS_SERIAL_UART_TCCVCP_H_ */ diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 3c488da9a3e72..9388a77dab173 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -41,6 +41,7 @@ zephyr_library_sources_ifdef(CONFIG_REALTEK_RTS5912_RTMR realtek_rts5912_rtmr.c) zephyr_library_sources_ifdef(CONFIG_SAM0_RTC_TIMER sam0_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_SILABS_SLEEPTIMER_TIMER silabs_sleeptimer_timer.c) zephyr_library_sources_ifdef(CONFIG_STM32_LPTIM_TIMER stm32_lptim_timer.c) +zephyr_library_sources_ifdef(CONFIG_TCC_VCPTTC_TIMER tcc_vcpttc_timer.c) zephyr_library_sources_ifdef(CONFIG_TI_DM_TIMER ti_dmtimer.c) zephyr_library_sources_ifdef(CONFIG_XLNX_PSTTC_TIMER xlnx_psttc_timer.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_TIMER xtensa_sys_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index c154370c45630..2016c2a541499 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -99,6 +99,7 @@ source "drivers/timer/Kconfig.sam0_rtc" source "drivers/timer/Kconfig.silabs" source "drivers/timer/Kconfig.smartbond" source "drivers/timer/Kconfig.stm32_lptim" +source "drivers/timer/Kconfig.tcc_vcpttc" source "drivers/timer/Kconfig.ti_dm_timer" source "drivers/timer/Kconfig.xlnx_psttc" source "drivers/timer/Kconfig.xtensa" diff --git a/drivers/timer/Kconfig.tcc_vcpttc b/drivers/timer/Kconfig.tcc_vcpttc new file mode 100644 index 0000000000000..eafaacd13fc4c --- /dev/null +++ b/drivers/timer/Kconfig.tcc_vcpttc @@ -0,0 +1,19 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config TCC_VCPTTC_TIMER + bool "Telechips VCP ttc timer support" + default y + depends on DT_HAS_TCC_TTCVCP_ENABLED + help + This module implements a kernel device driver for the Telechips VCP + platform provides the standard "system clock driver" interfaces. + If unchecked, no timer will be used. + +config TCC_VCPTTC_TIMER_INDEX + int "Telechips VCP ttc timer index" + range 0 9 + default 0 + depends on TCC_VCPTTC_TIMER + help + This is the index of TTC timer picked to provide system clock. diff --git a/drivers/timer/tcc_vcpttc_timer.c b/drivers/timer/tcc_vcpttc_timer.c new file mode 100644 index 0000000000000..52e6ee899ef86 --- /dev/null +++ b/drivers/timer/tcc_vcpttc_timer.c @@ -0,0 +1,464 @@ +/* + * Copyright 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT tcc_ttcvcp + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcc_vcpttc_timer.h" +#include + +#define VCP_CPU_TIMER_ID CONFIG_TCC_VCPTTC_TIMER_INDEX /* HW Timer Resource for OS sheduling */ +#define VCP_TICK_RATE_HZ ((uint32_t)1000UL) + +#define VCP_TIMER_IRQ_NUM DT_INST_IRQN(0) +#define VCP_TIMER_IRQ_PRIO DT_INST_IRQ(0, priority) +#define VCP_TIMER_IRQ_FLAGS DT_INST_IRQ(0, flags) + +#if defined(CONFIG_TEST) +const int32_t z_sys_timer_irq_for_test = DT_IRQN(DT_INST(0, tcc_ttcvcp)); +#endif + +#ifdef CONFIG_TICKLESS_KERNEL +static uint32_t last_cycles; +#endif +static bool flag_timer_initialized; +static struct timer_resource_table vcp_timer_resource[TIMER_CH_MAX]; + +uint32_t vcp_timer_irq_clear(enum timer_channel channel); + +static uint32_t read_count(void) +{ + /* Read current counter value */ + return sys_read32(TIMER_BASE_ADDR + TMR_MAIN_CNT); +} + +#ifdef CONFIG_TICKLESS_KERNEL +static void update_match(uint32_t cycles, uint32_t match) +{ + uint32_t delta = match - cycles; + + /* Ensure that the match value meets the minimum timing requirements */ + if (delta < CYCLES_NEXT_MIN) { + match += CYCLES_NEXT_MIN - delta; + } + + /* Write counter match value for interrupt generation */ + sys_write32(match, TIMER_BASE_ADDR + TMR_CMP_VALUE0); +} +#endif + +static void ttc_timer_compare_isr(const void *arg) +{ + cpu_irq_disable(); + + tic_cpu_if->cpu_pri_mask = (uint32_t)(MAX_API_CALL_INTERRUPT_PRIORITY << PRIORITY_SHIFT); + + __asm volatile("dsb\n" + "isb\n"); + + cpu_irq_enable(); + + sys_clock_announce(1); + + /* Ensure all interrupt priorities are active again. */ + vcp_timer_irq_clear(VCP_CPU_TIMER_ID); + clear_interrupt_mask(); +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ +#ifdef CONFIG_TICKLESS_KERNEL + uint32_t cycles, next_cycles; + + /* Read counter value */ + cycles = read_count(); + + /* Calculate timeout counter value */ + if (ticks == K_TICKS_FOREVER) { + next_cycles = cycles + CYCLES_NEXT_MAX; + } else { + next_cycles = cycles + ((uint32_t)ticks * CYCLES_PER_TICK); + } + + /* Set match value for the next interrupt */ + update_match(cycles, next_cycles); +#endif +} + +uint32_t sys_clock_elapsed(void) +{ +#ifdef CONFIG_TICKLESS_KERNEL + uint32_t cycles; + + /* Read counter value */ + cycles = read_count(); + + /* Return the number of ticks since last announcement */ + return (cycles - last_cycle) / CYCLES_PER_TICK; +#else + return 0; +#endif +} + +uint32_t sys_clock_cycle_get_32(void) +{ + /* Return the current counter value */ + return read_count(); +} + +uint32_t vcp_timer_irq_clear(enum timer_channel channel) +{ + uint32_t reg, clr_ctl; + + reg = TIMER_BASE_ADDR + TMR_IRQ_CTRL; + clr_ctl = sys_read32(reg); + + if ((clr_ctl & TMR_IRQ_CLR_CTRL_WRITE) != 0U) { + sys_write32(clr_ctl | TMR_IRQ_MASK_ALL, reg); + } else { + sys_read32(reg); + } + + return 0; +} + +static void vcp_timer_handler(void *arg_ptr) +{ + struct timer_resource_table *timer = TCC_NULL_PTR; + uint32_t reg; + + memcpy(&timer, (const void *)&arg_ptr, sizeof(struct timer_resource_table *)); + + if (timer != TCC_NULL_PTR) { + reg = TIMER_BASE_ADDR + TMR_IRQ_CTRL; + + if (((sys_read32(reg) & TMR_IRQ_CTRL_IRQ_ALLEN) != 0UL) && + (timer->rsc_table_used == true)) { + vcp_timer_irq_clear(timer->rsc_table_channel); + + if (timer->rsc_table_handler != TCC_NULL_PTR) { + timer->rsc_table_handler(timer->rsc_table_channel, + timer->rsc_table_arg); + } + } + + z_tic_irq_eoi(TIC_TIMER_0); + } +} + +static void vcp_timer_set_enable_core_reg(const struct vcp_timer_config *cfg_ptr, + const uint32_t cmp0_val, const uint32_t cmp1_val, + uint32_t config_val, const uint32_t irq_val) +{ + uint32_t mainval; + uint32_t tmpval; + uint32_t reg = TIMER_BASE_ADDR; + uint32_t rate_factor = (TMR_CLK_RATE / 1000UL) / ((TMR_PRESCALE + 1UL) * 1000UL); + + mainval = (cfg_ptr->cfg_main_val_usec == 0UL) + ? 0xFFFFFFFFUL + : ((cfg_ptr->cfg_main_val_usec * rate_factor) - 1UL); + + sys_write32(mainval, (uint32_t)(reg + TMR_MAIN_CNT_LVD)); + sys_write32(cmp0_val, (uint32_t)(reg + TMR_CMP_VALUE0)); + sys_write32(cmp1_val, (uint32_t)(reg + TMR_CMP_VALUE1)); + + config_val |= (TMR_PRESCALE | TMR_OP_EN_CFG_CNT_EN | + ((uint32_t)cfg_ptr->cfg_start_mode << TMR_OP_EN_CFG_LDZERO_OFFSET)); + + if (cfg_ptr->cfg_op_mode == TIMER_OP_ONESHOT) { + config_val |= TMR_OP_EN_CFG_OPMODE_ONE_SHOT; + } + + tmpval = sys_read32((uint32_t)(reg + TMR_IRQ_CTRL)); + + sys_write32(config_val, (uint32_t)(reg + TMR_OP_EN_CFG)); + sys_write32((tmpval | irq_val), (uint32_t)(reg + TMR_IRQ_CTRL)); +} + +static int32_t vcp_timer_enable_comp0(const struct vcp_timer_config *cfg_ptr) +{ + uint32_t tmpval, rate_factor; + uint32_t mainval, cmpval0; + uint32_t cmpval1 = 0x0UL; + uint32_t reg_cfgval; + uint32_t reg_irqval = TMR_IRQ_CTRL_IRQ_EN2; + int32_t ret = 0; + + rate_factor = (TMR_CLK_RATE / 1000UL) / ((TMR_PRESCALE + 1UL) * 1000UL); + + if ((VCP_MAX_INT_VAL / rate_factor) < cfg_ptr->cfg_cmp0_val_usec) { + ret = -EINVAL; + } else { + mainval = (cfg_ptr->cfg_main_val_usec == 0UL) + ? 0xFFFFFFFFUL + : ((cfg_ptr->cfg_main_val_usec * rate_factor) - 1UL); + tmpval = (cfg_ptr->cfg_cmp0_val_usec * rate_factor) - 1UL; + + if ((cfg_ptr->cfg_start_mode == TIMER_START_MAINCNT) && + (((0xFFFFFFFFUL - tmpval) == 0xFFFFFFFFUL) || + (mainval > (0xFFFFFFFFUL - tmpval)))) { + ret = -EINVAL; + } else { + cmpval0 = (cfg_ptr->cfg_start_mode == TIMER_START_ZERO) + ? tmpval + : (mainval + tmpval); + reg_cfgval = TMR_OP_EN_CFG_LDM0_ON; + reg_irqval |= TMR_IRQ_CTRL_IRQ_EN0; + + vcp_timer_set_enable_core_reg(cfg_ptr, cmpval0, cmpval1, reg_cfgval, + reg_irqval); + } + } + + return ret; +} + +static int32_t vcp_timer_enable_comp1(const struct vcp_timer_config *cfg_ptr) +{ + uint32_t tmpval; + uint32_t rate_factor, mainval; + uint32_t cmpval0 = 0x0UL; + uint32_t cmpval1, reg_cfgval; + uint32_t reg_irqval = TMR_IRQ_CTRL_IRQ_EN2; + int32_t ret = 0; + + rate_factor = (TMR_CLK_RATE / 1000UL) / ((TMR_PRESCALE + 1UL) * 1000UL); + + if ((VCP_MAX_INT_VAL / rate_factor) < cfg_ptr->cfg_cmp1_val_usec) { + ret = -EINVAL; + } else { + mainval = (cfg_ptr->cfg_main_val_usec == 0UL) + ? 0xFFFFFFFFUL + : ((cfg_ptr->cfg_main_val_usec * rate_factor) - 1UL); + tmpval = (cfg_ptr->cfg_cmp1_val_usec * rate_factor) - 1UL; + + if ((cfg_ptr->cfg_start_mode == TIMER_START_MAINCNT) && + (((0xFFFFFFFFUL - tmpval) == 0xFFFFFFFFUL) || + (mainval > (0xFFFFFFFFUL - tmpval)))) { + ret = -EINVAL; + } else { + cmpval1 = (cfg_ptr->cfg_start_mode == TIMER_START_ZERO) + ? tmpval + : (mainval + tmpval); + reg_cfgval = TMR_OP_EN_CFG_LDM1_ON; + reg_irqval |= TMR_IRQ_CTRL_IRQ_EN1; + + vcp_timer_set_enable_core_reg(cfg_ptr, cmpval0, cmpval1, reg_cfgval, + reg_irqval); + } + } + + return ret; +} + +static int32_t vcp_timer_enable_small_comp(const struct vcp_timer_config *cfg_ptr) +{ + uint32_t rate_factor, tmpval0, tmpval1, mainval; + uint32_t cmpval0, cmpval1, reg_cfgval; + uint32_t reg_irqval = TMR_IRQ_CTRL_IRQ_EN2; + int32_t ret = 0; + + rate_factor = (TMR_CLK_RATE / 1000UL) / ((TMR_PRESCALE + 1UL) * 1000UL); + mainval = (cfg_ptr->cfg_main_val_usec == 0UL) + ? 0xFFFFFFFFUL + : ((cfg_ptr->cfg_main_val_usec * rate_factor) - 1UL); + + if ((VCP_MAX_INT_VAL / rate_factor) < cfg_ptr->cfg_cmp0_val_usec) { + ret = -EINVAL; + } else if ((VCP_MAX_INT_VAL / rate_factor) < cfg_ptr->cfg_cmp1_val_usec) { + ret = -EINVAL; + } else { + tmpval0 = (cfg_ptr->cfg_cmp0_val_usec * rate_factor) - 1UL; + tmpval1 = (cfg_ptr->cfg_cmp1_val_usec * rate_factor) - 1UL; + + if (cfg_ptr->cfg_start_mode == TIMER_START_MAINCNT) { + if (tmpval0 <= tmpval1) { + if ((VCP_MAX_INT_VAL - mainval) <= tmpval0) { + ret = -EINVAL; + } else { + cmpval0 = mainval + tmpval0; + cmpval1 = VCP_MAX_INT_VAL; + } + } else { + if ((VCP_MAX_INT_VAL - mainval) <= tmpval1) { + ret = -EINVAL; + } else { + cmpval0 = VCP_MAX_INT_VAL; + cmpval1 = mainval + tmpval1; + } + } + } else { + cmpval0 = tmpval0; + cmpval1 = tmpval1; + } + + if (ret == 0) { + reg_cfgval = (TMR_OP_EN_CFG_LDM0_ON | TMR_OP_EN_CFG_LDM1_ON); + reg_irqval |= (TMR_IRQ_CTRL_IRQ_EN0 | TMR_IRQ_CTRL_IRQ_EN1); + + vcp_timer_set_enable_core_reg(cfg_ptr, cmpval0, cmpval1, reg_cfgval, + reg_irqval); + } + } + + return ret; +} + +static int32_t vcp_timer_enable_mode(const struct vcp_timer_config *cfg_ptr) +{ + int32_t ret = 0; + + switch (cfg_ptr->cfg_counter_mode) { + case TIMER_COUNTER_COMP0: + ret = vcp_timer_enable_comp0(cfg_ptr); + break; + case TIMER_COUNTER_COMP1: + ret = vcp_timer_enable_comp1(cfg_ptr); + break; + case TIMER_COUNTER_SMALL_COMP: + ret = vcp_timer_enable_small_comp(cfg_ptr); + break; + default: + vcp_timer_set_enable_core_reg(cfg_ptr, 0x0UL, 0x0UL, 0x0UL, TMR_IRQ_CTRL_IRQ_EN2); + break; + } + + return ret; +} + +static int32_t vcp_timer_enable_with_config(const struct vcp_timer_config *cfg_ptr) +{ + int32_t ret = 0; + + if (flag_timer_initialized == false) { + return -EIO; + } + + if ((cfg_ptr == TCC_NULL_PTR) || (TIMER_CH_MAX <= cfg_ptr->cfg_channel)) { + return -EINVAL; + } + + ret = vcp_timer_enable_mode(cfg_ptr); + + if (ret == 0) { + vcp_timer_resource[cfg_ptr->cfg_channel].rsc_table_used = true; + vcp_timer_resource[cfg_ptr->cfg_channel].rsc_table_handler = cfg_ptr->handler_fn; + vcp_timer_resource[cfg_ptr->cfg_channel].rsc_table_arg = cfg_ptr->arg_ptr; + + if (cfg_ptr->cfg_channel != VCP_CPU_TIMER_ID) { + tic_irq_vector_set((uint32_t)TIC_TIMER_0 + (uint32_t)cfg_ptr->cfg_channel, + TIC_IRQ_DEFAULT_PRIORITY, TIC_INT_TYPE_LEVEL_HIGH, + (tic_isr_func)&vcp_timer_handler, + (void *)&vcp_timer_resource[cfg_ptr->cfg_channel]); + } + } + + return ret; +} + +static int32_t vcp_timer_enable_with_mode(enum timer_channel channel, uint32_t u_sec, + enum vcp_timer_op_mode op_mode, + vcp_timer_handler_fn handler_fn, void *arg_ptr) +{ + struct vcp_timer_config cfg; + + cfg.cfg_channel = channel; + cfg.cfg_start_mode = TIMER_START_ZERO; + cfg.cfg_op_mode = op_mode; + cfg.cfg_counter_mode = TIMER_COUNTER_COMP0; + cfg.cfg_main_val_usec = 0; + cfg.cfg_cmp0_val_usec = u_sec; + cfg.cfg_cmp1_val_usec = 0; + cfg.handler_fn = handler_fn; + cfg.arg_ptr = arg_ptr; + + return vcp_timer_enable_with_config(&cfg); +} + +static int32_t vcp_timer_enable(uint32_t channel, uint32_t u_sec, vcp_timer_handler_fn handler_fn, + void *arg_ptr) +{ + return vcp_timer_enable_with_mode(channel, u_sec, TIMER_OP_FREERUN, handler_fn, arg_ptr); +} + +static int32_t vcp_timer_init(void) +{ + uint32_t reg, resIndex, reg_val; + int32_t ret; + + ret = 0; + + if (flag_timer_initialized == true) { + return ret; + } + + for (resIndex = 0; resIndex < (uint32_t)TIMER_CH_MAX; resIndex++) { + reg = MCU_BSP_TIMER_BASE + (resIndex * 0x100UL); + + vcp_timer_resource[resIndex].rsc_table_channel = (enum timer_channel)resIndex; + vcp_timer_resource[resIndex].rsc_table_used = false; + vcp_timer_resource[resIndex].rsc_table_handler = TCC_NULL_PTR; + vcp_timer_resource[resIndex].rsc_table_arg = TCC_NULL_PTR; + + sys_write32(0x7FFFU, (uint32_t)(reg + TMR_OP_EN_CFG)); + sys_write32(0x0U, (uint32_t)(reg + TMR_MAIN_CNT_LVD)); + sys_write32(0x0U, (uint32_t)(reg + TMR_CMP_VALUE0)); + sys_write32(0x0U, (uint32_t)(reg + TMR_CMP_VALUE1)); + + reg_val = TMR_IRQ_CLR_CTRL_WRITE | TMR_IRQ_MASK_ALL; + + sys_write32(reg_val, (uint32_t)(reg + TMR_IRQ_CTRL)); + } + + flag_timer_initialized = true; + + return ret; +} + +static int sys_clock_driver_init(void) +{ + uint32_t timer_channel, tic_to_sec; + + vcp_timer_init(); + + timer_channel = ((TIMER_BASE_ADDR - MCU_BSP_TIMER_BASE) / 0x100); + if (timer_channel >= TIMER_CH_MAX) { + return -EINVAL; + } + + if (timer_channel != VCP_CPU_TIMER_ID) { + return -EINVAL; + } + +#ifdef CONFIG_TICKLESS_KERNEL + /* Initialise internal states */ + last_cycles = 0; +#endif + + tic_irq_vector_set(TIMER_IRQ, TIC_IRQ_DEFAULT_PRIORITY, TIC_INT_TYPE_LEVEL_HIGH, + (tic_isr_func)ttc_timer_compare_isr, NULL); + + tic_to_sec = (uint32_t)(((uint32_t)1000 * (uint32_t)1000) / VCP_TICK_RATE_HZ); + + IRQ_CONNECT(VCP_TIMER_IRQ_NUM, VCP_TIMER_IRQ_PRIO, ttc_timer_compare_isr, NULL, 0); + + z_tic_irq_enable(TIC_TIMER_0 + VCP_CPU_TIMER_ID); + + vcp_timer_enable((enum timer_channel)timer_channel, tic_to_sec, 0, 0); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/drivers/timer/tcc_vcpttc_timer.h b/drivers/timer/tcc_vcpttc_timer.h new file mode 100644 index 0000000000000..5002b37d8614d --- /dev/null +++ b/drivers/timer/tcc_vcpttc_timer.h @@ -0,0 +1,127 @@ +/* + * Copyright 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_TIMER_TCC_VCPTTC_TIMER_H_ +#define ZEPHYR_DRIVERS_TIMER_TCC_VCPTTC_TIMER_H_ + +#define TIMER_INDEX CONFIG_TCC_VCPTTC_TIMER_INDEX + +#define TIMER_IRQ DT_INST_IRQN(0) +#define TIMER_BASE_ADDR DT_INST_REG_ADDR(0) +#define TIMER_CLOCK_FREQUECY DT_INST_PROP(0, clock_frequency) + +#define TICKS_PER_SEC CONFIG_SYS_CLOCK_TICKS_PER_SEC +#define CYCLES_PER_SEC TIMER_CLOCK_FREQUECY +#define CYCLES_PER_TICK (CYCLES_PER_SEC / TICKS_PER_SEC) + +/* Maximum value of interval counter */ +#define VCP_MAX_INTERVAL_COUNT 0xFFFFFFFFU + +#define CYCLES_NEXT_MIN 10000 +#define CYCLES_NEXT_MAX VCP_MAX_INTERVAL_COUNT + +/* Register Map */ +#define TMR_OP_EN_CFG 0x000UL +#define TMR_MAIN_CNT_LVD 0x004UL +#define TMR_CMP_VALUE0 0x008UL +#define TMR_CMP_VALUE1 0x00CUL +#define TMR_PSCL_CNT 0x010UL +#define TMR_MAIN_CNT 0x014UL +#define TMR_IRQ_CTRL 0x018UL + +/* Configuration Value */ +#define TMR_OP_EN_CFG_LDM0_ON (1UL << 28UL) +#define TMR_OP_EN_CFG_LDM1_ON (1UL << 29UL) +#define TMR_OP_EN_CFG_OPMODE_FREE_RUN (0UL << 26UL) +#define TMR_OP_EN_CFG_OPMODE_ONE_SHOT (1UL << 26UL) +#define TMR_OP_EN_CFG_LDZERO_OFFSET 25UL +#define TMR_OP_EN_CFG_CNT_EN (1UL << 24UL) + +/** + * 0: Reading this register to be cleared, + * 1: Writing a non-zero value to MASKED_IRQ_STATUS to be cleared. + */ +#define TMR_IRQ_CLR_CTRL_WRITE (1UL << 31UL) +#define TMR_IRQ_CLR_CTRL_READ (0UL << 31UL) +#define TMR_IRQ_MASK_ALL 0x1FUL +#define TMR_IRQ_CTRL_IRQ_EN0 (1UL << 16UL) +#define TMR_IRQ_CTRL_IRQ_EN1 (2UL << 16UL) +#define TMR_IRQ_CTRL_IRQ_EN2 (4UL << 16UL) +#define TMR_IRQ_CTRL_IRQ_EN3 (8UL << 16UL) +#define TMR_IRQ_CTRL_IRQ_EN4 (16UL << 16UL) +#define TMR_IRQ_CTRL_IRQ_ALLEN \ + ((TMR_IRQ_CTRL_IRQ_EN0) | (TMR_IRQ_CTRL_IRQ_EN1) | (TMR_IRQ_CTRL_IRQ_EN2) | \ + (TMR_IRQ_CTRL_IRQ_EN3) | (TMR_IRQ_CTRL_IRQ_EN4)) + +#define TMR_PRESCALE 11UL +#define TMR_CLK_RATE (12UL * 1000UL * 1000UL) + +#define VCP_MAX_INT_VAL 4294967295UL + +BUILD_ASSERT(TIMER_CLOCK_FREQUECY == CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, + "Configured system timer frequency does not match the TTC " + "clock frequency in the device tree"); + +BUILD_ASSERT(CYCLES_PER_SEC >= TICKS_PER_SEC, + "Timer clock frequency must be greater than the system tick " + "frequency"); + +BUILD_ASSERT((CYCLES_PER_SEC % TICKS_PER_SEC) == 0, + "Timer clock frequency is not divisible by the system tick " + "frequency"); + +enum vcp_timer_start_mode { + TIMER_START_MAINCNT = 0x0UL, + TIMER_START_ZERO = 0x1UL, +}; + +enum timer_channel { + TIMER_CH_0 = 0UL, + TIMER_CH_1 = 1UL, + TIMER_CH_2 = 2UL, + TIMER_CH_3 = 3UL, + TIMER_CH_4 = 4UL, + TIMER_CH_5 = 5UL, + TIMER_CH_6 = 6UL, + TIMER_CH_7 = 7UL, + TIMER_CH_8 = 8UL, + TIMER_CH_9 = 9UL, + TIMER_CH_MAX = 10UL, +}; + +enum vcp_timer_counter_mode { + TIMER_COUNTER_MAIN = 0UL, + TIMER_COUNTER_COMP0 = 1UL, + TIMER_COUNTER_COMP1 = 2UL, + TIMER_COUNTER_SMALL_COMP = 3UL, +}; + +enum vcp_timer_op_mode { + TIMER_OP_FREERUN = 0UL, + TIMER_OP_ONESHOT +}; + +typedef void (*vcp_timer_handler_fn)(enum timer_channel channel, const void *arg_ptr); + +struct vcp_timer_config { + enum timer_channel cfg_channel; + enum vcp_timer_start_mode cfg_start_mode; + enum vcp_timer_op_mode cfg_op_mode; + enum vcp_timer_counter_mode cfg_counter_mode; + uint32_t cfg_main_val_usec; + uint32_t cfg_cmp0_val_usec; + uint32_t cfg_cmp1_val_usec; + vcp_timer_handler_fn handler_fn; + void *arg_ptr; +}; + +struct timer_resource_table { + enum timer_channel rsc_table_channel; + bool rsc_table_used; + vcp_timer_handler_fn rsc_table_handler; + void *rsc_table_arg; +}; + +#endif /* ZEPHYR_DRIVERS_TIMER_TCC_VCPTTC_TIMER_H_ */ diff --git a/dts/arm/tcc/tcc7045.dtsi b/dts/arm/tcc/tcc7045.dtsi new file mode 100644 index 0000000000000..1efd13bf98377 --- /dev/null +++ b/dts/arm/tcc/tcc7045.dtsi @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + clock-frequency = <12000000>; + compatible = "arm,cortex-r5f"; + reg = <0>; + }; + + tic: interrupt-controller@a0f10000 { + compatible = "tcc,tic"; + reg = <0xa0f10000 0x1000>, + <0xa0f20000 0x20000>; + interrupt-controller; + #interrupt-cells = <4>; + #address-cells = <1>; + status = "disabled"; + }; + }; +}; diff --git a/dts/arm/tcc/tcc70xx.dtsi b/dts/arm/tcc/tcc70xx.dtsi new file mode 100644 index 0000000000000..d7ed49257d4d1 --- /dev/null +++ b/dts/arm/tcc/tcc70xx.dtsi @@ -0,0 +1,240 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + soc { + flash0: flash@20000000 { + compatible = "soc-nv-flash"; + reg = <0x20000000 DT_SIZE_M(2)>; + }; + + ram_ilm: memory@0 { + compatible = "mmio-sram"; + reg = <0 DT_SIZE_K(512)>; + }; + + ram_dlm: memory@1043000 { + compatible = "mmio-sram"; + reg = <0x1043000 DT_SIZE_K(128)>; + }; + + syscon: syscon@a0f24000 { + compatible = "syscon"; + reg = <0xa0f24000 0x104>; + + sysclk: sysclk { + compatible = "tcc,ccu"; + #clock-cells = <1>; + }; + }; + + uart0: uart@a0200000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0200000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart0"; + interrupt-parent = <&tic>; + }; + + uart1: uart@a0210000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0210000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart1"; + interrupt-parent = <&tic>; + }; + + uart2: uart@a0220000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0220000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart2"; + interrupt-parent = <&tic>; + }; + + uart3: uart@a0230000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0230000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart3"; + interrupt-parent = <&tic>; + }; + + uart4: uart@a0240000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0240000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart4"; + interrupt-parent = <&tic>; + }; + + uart5: uart@a0250000 { + compatible = "tcc,tccvcp-uart"; + reg = <0xa0250000 0x4c>; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_uart5"; + interrupt-parent = <&tic>; + }; + + systick_timer: timer@a0f2a000 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer0"; + interrupt-parent = <&tic>; + reg = <0xa0f2a000 0x20>; + }; + + ttc1: timer@a0f2a100 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer1"; + interrupt-parent = <&tic>; + reg = <0xa0f2a100 0x20>; + }; + + ttc2: timer@a0f2a200 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer2"; + interrupt-parent = <&tic>; + reg = <0xa0f2a200 0x20>; + }; + + ttc3: timer@a0f2a300 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer3"; + interrupt-parent = <&tic>; + reg = <0xa0f2a300 0x20>; + }; + + ttc4: timer@a0f2a400 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer4"; + interrupt-parent = <&tic>; + reg = <0xa0f2a400 0x20>; + }; + + ttc5: timer@a0f2a500 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer5"; + interrupt-parent = <&tic>; + reg = <0xa0f2a500 0x20>; + }; + + ttc6: timer@a0f2a600 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer6"; + interrupt-parent = <&tic>; + reg = <0xa0f2a600 0x20>; + }; + + ttc7: timer@a0f2a700 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer7"; + interrupt-parent = <&tic>; + reg = <0xa0f2a700 0x20>; + }; + + ttc8: timer@a0f2a800 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer8"; + interrupt-parent = <&tic>; + reg = <0xa0f2a800 0x20>; + }; + + ttc9: timer@a0f2a900 { + compatible = "tcc,ttcvcp"; + status = "disabled"; + interrupts = ; + interrupt-names = "irq_timer9"; + interrupt-parent = <&tic>; + reg = <0xa0f2a900 0x20>; + }; + + gpioa@a0f22000 { + compatible = "simple-bus"; + reg = <0xa0f22000 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + gpiob@a0f22040 { + compatible = "simple-bus"; + reg = <0xa0f22040 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + + gio_aon: gpio@0 { + compatible = "tcc,tccvcp-gpio"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <29>; + status = "disabled"; + }; + }; + + gpioc@a0f22080 { + compatible = "simple-bus"; + reg = <0xa0f22080 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + gpiok@a0f220c0 { + compatible = "simple-bus"; + reg = <0xa0f220c0 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; diff --git a/dts/bindings/clock/tcc,ccu.yaml b/dts/bindings/clock/tcc,ccu.yaml new file mode 100644 index 0000000000000..e321907380cd7 --- /dev/null +++ b/dts/bindings/clock/tcc,ccu.yaml @@ -0,0 +1,15 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +description: Telechips TCP70xx Clock Controller + +compatible: "tcc,ccu" + +include: [clock-controller.yaml, base.yaml] + +properties: + "#clock-cells": + const: 1 + +clock-cells: + - clk_id diff --git a/dts/bindings/gpio/tcc,tccvcp-gpio.yaml b/dts/bindings/gpio/tcc,tccvcp-gpio.yaml new file mode 100644 index 0000000000000..df408037244b4 --- /dev/null +++ b/dts/bindings/gpio/tcc,tccvcp-gpio.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +description: TCCVCP GPIO + +compatible: "tcc,tccvcp-gpio" + +include: [gpio-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#gpio-cells": + const: 2 + +gpio-cells: + - pin + - flags diff --git a/dts/bindings/interrupt-controller/tcc,tic.yaml b/dts/bindings/interrupt-controller/tcc,tic.yaml new file mode 100644 index 0000000000000..9bfe1ed4edc9b --- /dev/null +++ b/dts/bindings/interrupt-controller/tcc,tic.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +description: Telechips Generic Interrupt Controller 400 + +compatible: "tcc,tic" + +include: base.yaml + +properties: + reg: + required: true + +interrupt-cells: + - type + - irq + - flags + - priority diff --git a/dts/bindings/serial/tcc,tccvcp-uart.yaml b/dts/bindings/serial/tcc,tccvcp-uart.yaml new file mode 100644 index 0000000000000..01c2925cfd0f4 --- /dev/null +++ b/dts/bindings/serial/tcc,tccvcp-uart.yaml @@ -0,0 +1,9 @@ +description: Telechips UART + +compatible: "tcc,tccvcp-uart" + +include: uart-controller.yaml + +properties: + reg: + required: true diff --git a/dts/bindings/timer/tcc,ttcvcp.yaml b/dts/bindings/timer/tcc,ttcvcp.yaml new file mode 100644 index 0000000000000..2701a20b9aa24 --- /dev/null +++ b/dts/bindings/timer/tcc,ttcvcp.yaml @@ -0,0 +1,14 @@ +description: Telechips VCP TTC timer + +compatible: "tcc,ttcvcp" + +include: base.yaml + +properties: + reg: + required: true + + clock-frequency: + type: int + required: true + description: Clock frequency information for Timer operation diff --git a/dts/bindings/vendor-prefixes.txt b/dts/bindings/vendor-prefixes.txt index c6874ab32dee0..8ab69ef5f7137 100644 --- a/dts/bindings/vendor-prefixes.txt +++ b/dts/bindings/vendor-prefixes.txt @@ -669,6 +669,7 @@ syna Synaptics Inc. synology Synology, Inc. tbs TBS Technologies tbs-biometrics Touchless Biometric Systems AG +tcc TELECHIPS INC. tcg Trusted Computing Group tcl Toby Churchill Ltd. tcs Shenzhen City Tang Cheng Technology Co., Ltd. diff --git a/include/zephyr/drivers/clock_control/clock_control_tcc_ccu.h b/include/zephyr/drivers/clock_control/clock_control_tcc_ccu.h new file mode 100644 index 0000000000000..5561d2a1d315c --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_tcc_ccu.h @@ -0,0 +1,135 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCC_CCU_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCC_CCU_H_ + +/** @brief Initializes the clock controller + * + */ +void vcp_clock_init(void); + +/** @brief Controls the PLL0PMS and PLL1PMS register + * + * @param id MPLL index. + * @param rate Clock rate + * + * @return 0 on success + */ +int32_t clock_set_pll_rate(int32_t id, uint32_t rate); + +/** @brief Gets the PLL rate + * + * @param id Clock index + * + * @return Clock rate + */ +uint32_t clock_get_pll_rate(int32_t id); + +/** @brief Sets the PLL divisor value + * + * @param id Clock index + * @param pll_div PLL divisor value + * + * @return 0 on success + */ +int32_t clock_set_pll_div(int32_t id, uint32_t pll_div); + +/** @brief Controls the CPU_CLK_CTRL register + * + * @param id Clock index + * @param rate Clock rate + * + * @return 0 on success + */ +int32_t clock_set_clk_ctrl_rate(int32_t id, uint32_t rate); + +/** @brief Gets the clock rate for CPU_CLK_CTRL register + * + * @param id Clock index + * + * @return Clock rate + */ +uint32_t clock_get_clk_ctrl_rate(int32_t id); + +/** @brief Checks the peripheral enable status + * + * @param id Clock index + * + * @return Clock rate + */ +int32_t clock_is_peri_enabled(int32_t id); + +/** @brief Enables the peripheral clock + * + * @param id Clock index + * + * @return 0 on success + */ +int32_t clock_enable_peri(int32_t id); + +/** @brief Disables the peripheral clock + * + * @param id Clock index + * + * @return 0 on success + */ +int32_t clock_disable_peri(int32_t id); + +/** @brief Gets the peripheral clock rate + * + * @param id Clock index + * + * @return Clock rate + */ +uint32_t clock_get_peri_rate(int32_t id); + +/** @brief Sets the peripheral clock rate (CLOCK_MCKC_PCLKCTRL register) + * + * @param id Clock index + * @param rate Clock rate + * + * @return 0 on success + */ +int32_t clock_set_peri_rate(int32_t id, uint32_t rate); + +/** @brief Gets the peripheral's IO bus clock power-down mask status (HCLK_MASK# register) + * + * @param id Bus clock index + * + * @return 0 on success + */ +int32_t clock_is_iobus_pwdn(int32_t id); + +/** @brief Enables peripheral's IO bus clock power-down (HCLK_MASK# , SW_RESET# register) + * + * @param id Bus clock index + * @param en Bus clock enable + * + * @return 0 on success + */ +int32_t clock_enable_iobus(int32_t id, bool en); + +/** @brief Sets the peripheral's IO bus clock power-down mask status (HCLK_MASK# register) + * + * @param id Bus clock index + * @param en Bus clock power-down enable + * + * @return 0 on success + */ +int32_t clock_set_iobus_pwdn(int32_t id, bool en); + +/** @brief Controls the SW_RESET# register + * + * @param id Bus clock index + * @param reset Bus clock reset enable + * + * @return 0 on success + */ +int32_t clock_set_sw_reset(int32_t id, bool reset); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCC_CCU_H_ */ diff --git a/include/zephyr/drivers/clock_control/clock_control_tccvcp.h b/include/zephyr/drivers/clock_control/clock_control_tccvcp.h new file mode 100644 index 0000000000000..7684f758ebf4a --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_tccvcp.h @@ -0,0 +1,310 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCCVCP_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCCVCP_H_ + +#define CLOCK_PLL_MAX_NUM 2 +#define CLOCK_SRC_MAX_NUM ((CLOCK_PLL_MAX_NUM * 2) + 2) + +#define CLOCK_XIN_CLK_RATE 12000000UL /* 12MHz */ + +/* PLL channel index */ +typedef enum CLOCK_PLL { + CLOCK_PLL_MICOM_0 = 0, + CLOCK_PLL_MICOM_1 = 1 +} CLOCKPll_t; + +/* MICOM pll source channel index */ +typedef enum CLOCK_M_PLL { + CLOCK_MPLL_0 = 0, + CLOCK_MPLL_1 = 1, + CLOCK_MPLL_DIV_0 = 2, + CLOCK_MPLL_DIV_1 = 3, + CLOCK_MPLL_XIN = 4 +} CLOCKMpll_t; + +typedef enum CLOCK_PCLK_CTRL_SEL { + CLOCK_PCLKCTRL_SEL_PLL0 = 0, + CLOCK_PCLKCTRL_SEL_PLL1 = 1, + CLOCK_PCLKCTRL_SEL_XIN = 5, + CLOCK_PCLKCTRL_SEL_PLL0DIV = 10, + CLOCK_PCLKCTRL_SEL_PLL1DIV = 11, + CLOCK_PCLKCTRL_SEL_XINDIV = 23 +} CLOCKPclkctrlSel_t; + +/* Peripheral Clocks */ +typedef enum CLOCK_PERI { /* Peri. Name */ + /* MICOM Peri */ + CLOCK_PERI_SFMC = 0, + CLOCK_PERI_CAN0 = 1, + CLOCK_PERI_CAN1 = 2, + CLOCK_PERI_CAN2 = 3, + CLOCK_PERI_GPSB0 = 4, + CLOCK_PERI_GPSB1 = 5, + CLOCK_PERI_GPSB2 = 6, + CLOCK_PERI_GPSB3 = 7, + CLOCK_PERI_GPSB4 = 8, + CLOCK_PERI_UART0 = 9, + CLOCK_PERI_UART1 = 10, + CLOCK_PERI_UART2 = 11, + CLOCK_PERI_UART3 = 12, + CLOCK_PERI_UART4 = 13, + CLOCK_PERI_UART5 = 14, + CLOCK_PERI_I2C0 = 15, + CLOCK_PERI_I2C1 = 16, + CLOCK_PERI_I2C2 = 17, + CLOCK_PERI_I2C3 = 18, + CLOCK_PERI_I2C4 = 19, + CLOCK_PERI_I2C5 = 20, + CLOCK_PERI_PWM0 = 21, + CLOCK_PERI_PWM1 = 22, + CLOCK_PERI_PWM2 = 23, + CLOCK_PERI_ICTC0 = 24, + CLOCK_PERI_ICTC1 = 25, + CLOCK_PERI_ICTC2 = 26, + CLOCK_PERI_ICTC3 = 27, + CLOCK_PERI_ICTC4 = 28, + CLOCK_PERI_ICTC5 = 29, + CLOCK_PERI_ADC0 = 30, + CLOCK_PERI_ADC1 = 31, + CLOCK_PERI_TIMER0 = 32, + CLOCK_PERI_TIMER1 = 33, + CLOCK_PERI_TIMER2 = 34, + CLOCK_PERI_TIMER3 = 35, + CLOCK_PERI_TIMER4 = 36, + CLOCK_PERI_TIMER5 = 37, + CLOCK_PERI_TIMER6 = 38, + CLOCK_PERI_TIMER7 = 39, + CLOCK_PERI_TIMER8 = 40, + CLOCK_PERI_TIMER9 = 41, + CLOCK_PERI_I2S0 = 42, + CLOCK_PERI_I2S1 = 43, + CLOCK_PERI_GMAC0 = 44, + CLOCK_PERI_GMAC1 = 45, + CLOCK_PERI_MAX = 46 +} CLOCKPeri_t; + +/* I/O Bus pwdn/swreset */ +typedef enum CLOCK_IO_BUS { + CLOCK_IOBUS_SFMC = 0, + CLOCK_IOBUS_IMC = 1, + CLOCK_IOBUS_PFLASH = 2, + CLOCK_IOBUS_DFLASH = 3, + CLOCK_IOBUS_GIC = 4, + CLOCK_IOBUS_SOC400 = 5, + CLOCK_IOBUS_DMA_CON0 = 6, + CLOCK_IOBUS_DMA_CON1 = 7, + CLOCK_IOBUS_DMA_CON2 = 8, + CLOCK_IOBUS_DMA_CON3 = 9, + CLOCK_IOBUS_DMA_CON4 = 10, + CLOCK_IOBUS_DMA_CON5 = 11, + CLOCK_IOBUS_DMA_CON6 = 12, + CLOCK_IOBUS_DMA_CON7 = 13, + CLOCK_IOBUS_CAN0 = 14, + CLOCK_IOBUS_CAN1 = 15, + CLOCK_IOBUS_CAN2 = 16, + CLOCK_IOBUS_CAN_CONF = 17, + CLOCK_IOBUS_UART0 = 18, + CLOCK_IOBUS_UART1 = 19, + CLOCK_IOBUS_UART2 = 20, + CLOCK_IOBUS_UART3 = 21, + CLOCK_IOBUS_UART4 = 22, + CLOCK_IOBUS_UART5 = 23, + CLOCK_IOBUS_CONF = 24, + CLOCK_IOBUS_I2C0 = 25, + CLOCK_IOBUS_I2C1 = 26, + CLOCK_IOBUS_I2C2 = 27, + CLOCK_IOBUS_I2C3 = 28, + CLOCK_IOBUS_I2C4 = 29, + CLOCK_IOBUS_I2C5 = 30, + CLOCK_IOBUS_I2C_M_PORTCFG = 31, + CLOCK_IOBUS_PWM0 = 32, /* HCLK_MASK1[0] */ + CLOCK_IOBUS_PWM1 = 33, /* HCLK_MASK1[1] */ + CLOCK_IOBUS_PWM2 = 34, /* HCLK_MASK1[2] */ + CLOCK_IOBUS_PWM_CONF = 35, /* HCLK_MASK1[3] */ + CLOCK_IOBUS_ICTC0 = 36, /* HCLK_MASK1[4] */ + CLOCK_IOBUS_ICTC1 = 37, /* HCLK_MASK1[5] */ + CLOCK_IOBUS_ICTC2 = 38, /* HCLK_MASK1[6] */ + CLOCK_IOBUS_ICTC3 = 39, /* HCLK_MASK1[7] */ + CLOCK_IOBUS_ICTC4 = 40, /* HCLK_MASK1[8] */ + CLOCK_IOBUS_ICTC5 = 41, /* HCLK_MASK1[9] */ + CLOCK_IOBUS_ADC0 = 42, /* HCLK_MASK1[10] */ + CLOCK_IOBUS_ADC1 = 43, /* HCLK_MASK1[11] */ + CLOCK_IOBUS_TIMER0 = 44, /* HCLK_MASK1[12] */ + CLOCK_IOBUS_TIMER1 = 45, /* HCLK_MASK1[13] */ + CLOCK_IOBUS_TIMER2 = 46, /* HCLK_MASK1[14] */ + CLOCK_IOBUS_TIMER3 = 47, /* HCLK_MASK1[15] */ + CLOCK_IOBUS_TIMER4 = 48, /* HCLK_MASK1[16] */ + CLOCK_IOBUS_TIMER5 = 49, /* HCLK_MASK1[17] */ + CLOCK_IOBUS_TIMER6 = 50, /* HCLK_MASK1[18] */ + CLOCK_IOBUS_TIMER7 = 51, /* HCLK_MASK1[19] */ + CLOCK_IOBUS_TIMER8 = 52, /* HCLK_MASK1[20] */ + CLOCK_IOBUS_TIMER9 = 53, /* HCLK_MASK1[21] */ + CLOCK_IOBUS_GPSB0 = 54, /* HCLK_MASK1[22] */ + CLOCK_IOBUS_GPSB1 = 55, /* HCLK_MASK1[23] */ + CLOCK_IOBUS_GPSB2 = 56, /* HCLK_MASK1[24] */ + CLOCK_IOBUS_GPSB3 = 57, /* HCLK_MASK1[25] */ + CLOCK_IOBUS_GPSB4 = 58, /* HCLK_MASK1[26] */ + CLOCK_IOBUS_GPSB_CONF = 59, /* HCLK_MASK1[27] */ + CLOCK_IOBUS_GPSB_SM = 60, /* HCLK_MASK1[28] */ + CLOCK_IOBUS_I2S = 61, /* HCLK_MASK1[29] */ + CLOCK_IOBUS_GMAC = 62, /* HCLK_MASK1[30] */ + CLOCK_IOBUS_RESERVED = 63, /* HCLK_MASK1[31] */ + CLOCK_IOBUS_WDT = 64, /* HCLK_MASK2[0] */ + CLOCK_IOBUS_GPIO = 65, /* HCLK_MASK2[1] */ + CLOCK_IOBUS_CMU = 66, /* HCLK_MASK2[2] */ + CLOCK_IOBUS_SYSSM = 67, /* HCLK_MASK2[3] */ + CLOCK_IOBUS_MAX = 68 +} CLOCKIobus_t; + +/* + * CKC Register Offsets + */ + +/* MICOM Register Offsets */ +#define CLOCK_MCKC_PLL0PMS 0x000 +#define CLOCK_MCKC_PLL1PMS 0x00C +#define CLOCK_MCKC_CLKDIVC 0x018 +#define CLOCK_MCKC_CLKCTRL 0x020 +#define CLOCK_MCKC_PCLKCTRL 0x028 + +/* MICOM Subsystem Register Offsets */ +#define CLOCK_MCKC_HCLK0 0x000 +#define CLOCK_MCKC_HCLK1 0x004 +#define CLOCK_MCKC_HCLK2 0x008 +#define CLOCK_MCKC_HCLKSWR0 0x00C +#define CLOCK_MCKC_HCLKSWR1 0x010 +#define CLOCK_MCKC_HCLKSWR2 0x014 + +/* + * MICOM CLKCTRL Configuration Register + */ +#define CLOCK_MCLKCTRL_SEL_SHIFT 4 +#define CLOCK_MCLKCTRL_SEL_MASK 0x7 + +#define CLOCK_MCLKCTRL_CONFIG_MIN 1 +#define CLOCK_MCLKCTRL_CONFIG_MAX 15 +#define CLOCK_MCLKCTRL_CONFIG_SHIFT 5 +#define CLOCK_MCLKCTRL_CONFIG_MASK 0xF +#define CLOCK_MCLKCTRL_EN_SHIFT 22 +#define CLOCK_MCLKCTRL_DIVSTS_SHIFT 29 +#define CLOCK_MCLKCTRL_CLKCHG_SHIFT 31 + +/* + * PLL Configuration Register + */ +#define CLOCK_PLL_MAX_RATE 3200000000 /* Max. 3200MHz */ +#define CLOCK_PLL_MIN_RATE 25000000 /* Min. 25MHz */ +#define CLOCK_PLL_VCO_MAX 3200000000 /* Max. 3200MHz */ +#define CLOCK_PLL_VCO_MIN 1600000000 /* Min. 1600MHz */ +#define CLOCK_PLL_P_MAX 6 /* 63 FREF = FIN/p (4MHz ~ 12MHz) */ +#define CLOCK_PLL_P_MIN 2 /* 1 FREF = FIN/p (4MHz ~ 12MHz) */ +#define CLOCK_PLL_P_SHIFT 0 +#define CLOCK_PLL_P_MASK 0x3F +#define CLOCK_PLL_M_MAX 1023 +#define CLOCK_PLL_M_MIN 64 +#define CLOCK_PLL_M_SHIFT 6 +#define CLOCK_PLL_M_MASK 0x1FF +#define CLOCK_PLL_S_MAX 6 +#define CLOCK_PLL_S_MIN 0 +#define CLOCK_PLL_S_SHIFT 15 +#define CLOCK_PLL_S_MASK 0x7 +#define CLOCK_PLL_SRC_SHIFT 18 +#define CLOCK_PLL_SRC_MASK 0x3 +#define CLOCK_PLL_BYPASS_SHIFT 20 +#define CLOCK_PLL_LOCKST_SHIFT 21 +#define CLOCK_PLL_CHGPUMP_SHIFT 22 +#define CLOCK_PLL_CHGPUMP_MASK 0x3 +#define CLOCK_PLL_LOCKEN_SHIFT 24 +#define CLOCK_PLL_RSEL_SHIFT 25 +#define CLOCK_PLL_RSEL_MASK 0xF +#define CLOCK_PLL_EN_SHIFT 31 + +/* + * PCLKCTRL Configuration Register + */ +#define CLOCK_PCLKCTRL_MAX_FCKS 1600000000 +#define CLOCK_PCLKCTRL_DIV_MIN 0 +#define CLOCK_PCLKCTRL_DIV_SHIFT 0 +#define CLOCK_PCLKCTRL_DIV_XXX_MAX 0xFFF +#define CLOCK_PCLKCTRL_DIV_XXX_MASK CLOCK_PCLKCTRL_DIV_XXX_MAX +#define CLOCK_PCLKCTRL_DIV_YYY_MAX 0xFFFFFF +#define CLOCK_PCLKCTRL_DIV_YYY_MASK CLOCK_PCLKCTRL_DIV_YYY_MAX +#define CLOCK_PCLKCTRL_SEL_MIN 0 +#define CLOCK_PCLKCTRL_SEL_MAX 28 +#define CLOCK_PCLKCTRL_SEL_SHIFT 24 +#define CLOCK_PCLKCTRL_SEL_MASK 0x1F +#define CLOCK_PCLKCTRL_EN_SHIFT 29 +#define CLOCK_PCLKCTRL_OUTEN_SHIFT 30 +#define CLOCK_PCLKCTRL_MD_SHIFT 31 + +/* CLKCTRL SEL */ +enum clock_mclk_ctrl_sel { + CLOCK_MCLKCTRL_SEL_XIN = 0, + CLOCK_MCLKCTRL_SEL_PLL0 = 1, + CLOCK_MCLKCTRL_SEL_PLL1 = 2, + CLOCK_MCLKCTRL_SEL_XINDIV = 3, + CLOCK_MCLKCTRL_SEL_PLL0DIV = 4, + CLOCK_MCLKCTRL_SEL_PLL1DIV = 5, + CLOCK_MCLKCTRL_SEL_EXTIN0 = 6, + CLOCK_MCLKCTRL_SEL_EXTIN1 = 7 +}; + +/* PCLK Type */ +enum clock_pclk_ctrl_type { + CLOCK_PCLKCTRL_TYPE_XXX = 0, + CLOCK_PCLKCTRL_TYPE_YYY = 1, + CLOCK_PCLKCTRL_TYPE_MAX = 2 +}; + +/* PCLK Mode Selection */ +enum clock_pclk_ctrl_mode { + CLOCK_PCLKCTRL_MODE_DCO = 0, + CLOCK_PCLKCTRL_MODE_DIVIDER = 1, + CLOCK_PCLKCTRL_MODE_MAX = 2 +}; + +enum clock_mpclk_ctrl_sel { + CLOCK_MPCLKCTRL_SEL_PLL0 = 0, + CLOCK_MPCLKCTRL_SEL_PLL1 = 1, + CLOCK_MPCLKCTRL_SEL_XIN = 5, + CLOCK_MPCLKCTRL_SEL_PLL0DIV = 10, + CLOCK_MPCLKCTRL_SEL_PLL1DIV = 11, + CLOCK_MPCLKCTRL_SEL_XINDIV = 23, + CLOCK_MPCLKCTRL_SEL_EXTIN0 = 25, + CLOCK_MPCLKCTRL_SEL_EXTIN1 = 26, + CLOCK_MPCLKCTRL_SEL_EXTIN2 = 27, + CLOCK_MPCLKCTRL_SEL_EXTIN3 = 28 +}; + +struct clock_pms { + uint32_t fpll; + uint32_t en; + uint32_t p; + uint32_t m; + uint32_t s; + uint32_t src; +}; + +struct clock_clk_ctrl { + uint32_t freq; + uint32_t en; + uint32_t conf; + uint32_t sel; +}; + +struct clock_pclk_ctrl { + uint32_t peri_name; + uint32_t freq; + uint32_t md; + uint32_t en; + uint32_t sel; + uint32_t div_val; +}; + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_CLOCK_CONTROL_TCCVCP_H_ */ diff --git a/include/zephyr/drivers/gpio/gpio_tccvcp.h b/include/zephyr/drivers/gpio/gpio_tccvcp.h new file mode 100644 index 0000000000000..65fa58a0c3db5 --- /dev/null +++ b/include/zephyr/drivers/gpio/gpio_tccvcp.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_TCCVCP_H_ +#define ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_TCCVCP_H_ + +/* + * GLOBAL DEFINITIONS + */ + +/* + * gpio cfg structures + * [31:14]: reserved + * [11:10]: input buffer + * [9] : direction + * [8:6] : driver strength (0~3) + * [5:4] : pull up/down + * [3:0] : function selection (0~15) + */ + +#define GPIO_INPUTBUF_SHIFT 10 +#define GPIO_INPUTBUF_MASK 0x3UL +#define GPIO_INPUTBUF_EN ((2UL | 1UL) << (uint32_t)GPIO_INPUTBUF_SHIFT) +#define GPIO_INPUTBUF_DIS ((2UL | 0UL) << (uint32_t)GPIO_INPUTBUF_SHIFT) + +#define GPIO_OUTPUT_SHIFT 9 +#define VCP_GPIO_OUTPUT (1UL << (uint32_t)GPIO_OUTPUT_SHIFT) +#define VCP_GPIO_INPUT (0UL << (uint32_t)GPIO_OUTPUT_SHIFT) + +#define GPIO_DS_SHIFT 6 +#define GPIO_DS_MASK 0x7UL +#define GPIO_DS(x) ((((x) & (uint32_t)GPIO_DS_MASK) | 0x4UL) << (uint32_t)GPIO_DS_SHIFT) + +#define GPIO_PULL_SHIFT 4 +#define GPIO_PULL_MASK 0x3UL +#define GPIO_NOPULL (0UL << (uint32_t)GPIO_PULL_SHIFT) +#define GPIO_PULLUP (1UL << (uint32_t)GPIO_PULL_SHIFT) +#define GPIO_PULLDN (2UL << (uint32_t)GPIO_PULL_SHIFT) + +#define GPIO_DATA 0x00 +#define GPIO_OUT_EN 0x04 +#define GPIO_OUT_DATA_OR 0x08 +#define GPIO_OUT_DATA_BIC 0x0C +#define GPIO_OUT_DATA_XOR 0x10 +#define GPIO_IN_EN 0x24 +#define GPIO_IODIR 0x08 + +#define GPIO_FUNC_MASK 0xFUL +#define GPIO_FUNC(x) ((x) & (uint32_t)GPIO_FUNC_MASK) + +#define GPIO_MFIO_CFG_CH_SEL0 0 +#define GPIO_MFIO_CFG_PERI_SEL0 4 +#define GPIO_MFIO_CFG_CH_SEL1 8 +#define GPIO_MFIO_CFG_PERI_SEL1 12 +#define GPIO_MFIO_CFG_CH_SEL2 16 +#define GPIO_MFIO_CFG_PERI_SEL2 20 +#define GPIO_MFIO_DISABLE 0 +#define GPIO_MFIO_SPI2 1 +#define GPIO_MFIO_UART3 2 +#define GPIO_MFIO_I2C3 3 +#define GPIO_MFIO_SPI3 1 +#define GPIO_MFIO_UART4 2 +#define GPIO_MFIO_I2C4 3 +#define GPIO_MFIO_SPI4 1 +#define GPIO_MFIO_UART5 2 +#define GPIO_MFIO_I2C5 3 +#define GPIO_MFIO_CH0 0 +#define GPIO_MFIO_CH1 1 +#define GPIO_MFIO_CH2 2 +#define GPIO_MFIO_CH3 3 +#define GPIO_PERICH_SEL_UARTSEL_0 0 +#define GPIO_PERICH_SEL_UARTSEL_1 1 +#define GPIO_PERICH_SEL_UARTSEL_2 2 +#define GPIO_PERICH_SEL_I2CSEL_0 3 +#define GPIO_PERICH_SEL_I2CSEL_1 4 +#define GPIO_PERICH_SEL_I2CSEL_2 5 +#define GPIO_PERICH_SEL_SPISEL_0 6 +#define GPIO_PERICH_SEL_SPISEL_1 7 +#define GPIO_PERICH_SEL_I2SSEL_0 8 +#define GPIO_PERICH_SEL_PWMSEL_0 10 +#define GPIO_PERICH_SEL_PWMSEL_1 12 +#define GPIO_PERICH_SEL_PWMSEL_2 14 +#define GPIO_PERICH_SEL_PWMSEL_3 16 +#define GPIO_PERICH_SEL_PWMSEL_4 18 +#define GPIO_PERICH_SEL_PWMSEL_5 20 +#define GPIO_PERICH_SEL_PWMSEL_6 22 +#define GPIO_PERICH_SEL_PWMSEL_7 24 +#define GPIO_PERICH_SEL_PWMSEL_8 26 +#define GPIO_PERICH_CH0 0 +#define GPIO_PERICH_CH1 1 +#define GPIO_PERICH_CH2 2 +#define GPIO_PERICH_CH3 3 + +/* + * gpio port & pin structures + * [31:10]: reserved + * [9:5] : port (A,B,C,...) + * [4:0] : pin number (0~31) + */ + +#define GPIO_PIN_MASK 0x1FUL +#define GPIO_PIN_NUM_MASK 0x3FUL + +#define GPIO_PORT_SHIFT 5 +#define GPIO_PORT_MASK ((uint32_t)0x1F << (uint32_t)GPIO_PORT_SHIFT) + +#define GPIO_PORT_A ((uint32_t)0 << (uint32_t)GPIO_PORT_SHIFT) +#define GPIO_PORT_B ((uint32_t)1 << (uint32_t)GPIO_PORT_SHIFT) +#define GPIO_PORT_C ((uint32_t)2 << (uint32_t)GPIO_PORT_SHIFT) +#define GPIO_PORT_K ((uint32_t)3 << (uint32_t)GPIO_PORT_SHIFT) + +#define GPIO_GPA(x) (GPIO_PORT_A | ((x) & (uint32_t)0x1F)) +#define GPIO_GPB(x) (GPIO_PORT_B | ((x) & (uint32_t)0x1F)) +#define GPIO_GPC(x) (GPIO_PORT_C | ((x) & (uint32_t)0x1F)) +#define GPIO_GPK(x) (GPIO_PORT_K | ((x) & (uint32_t)0x1F)) + +#define GPIO_GP_MAX GPIO_GPK((uint32_t)0x1f) + +#define GPIO_PMGPIO_BASE (MCU_BSP_PMIO_BASE) + +#define GPIO_REG_BASE(x) \ + (MCU_BSP_GPIO_BASE + ((((x) & GPIO_PORT_MASK) >> (uint32_t)GPIO_PORT_SHIFT) * 0x40UL)) + +#define GPIO_IS_GPIOK(x) (bool)((((x) & GPIO_PORT_MASK) == GPIO_PORT_K) ? 1 : 0) + +#define GPIO_REG_DATA(x) (GPIO_REG_BASE(x) + 0x00UL) +#define GPIO_REG_OUTEN(x) (GPIO_REG_BASE(x) + 0x04UL) +#define GPIO_REG_DATA_OR(x) (GPIO_REG_BASE(x) + 0x08UL) +#define GPIO_REG_DATA_BIC(x) (GPIO_REG_BASE(x) + 0x0CUL) +#define GPIO_REG_PULLEN(x) \ + (GPIO_IS_GPIOK(x) ? (GPIO_PMGPIO_BASE + 0x10UL) : (GPIO_REG_BASE(x) + 0x1CUL)) +#define GPIO_REG_PULLSEL(x) \ + (GPIO_IS_GPIOK(x) ? (GPIO_PMGPIO_BASE + 0x14UL) : (GPIO_REG_BASE(x) + 0x20UL)) +#define GPIO_REG_CD(x, pin) \ + ((GPIO_IS_GPIOK(x) ? (GPIO_PMGPIO_BASE + 0x18UL) : (GPIO_REG_BASE(x) + 0x14UL)) + \ + (0x4UL * ((pin) / (uint32)16))) +#define GPIO_REG_IEN(x) \ + (GPIO_IS_GPIOK(x) ? (GPIO_PMGPIO_BASE + 0x0CUL) : (GPIO_REG_BASE(x) + 0x24UL)) +#define GPIO_REG_FN(x, pin) ((GPIO_REG_BASE(x) + 0x30UL) + (0x4UL * ((pin) / (uint32_t)8))) +#define GPIO_MFIO_CFG (MCU_BSP_GPIO_BASE + (0x2B4UL)) +#define GPIO_PERICH_SEL (MCU_BSP_GPIO_BASE + (0x2B8UL)) + +#define GPIO_PMGPIO_SEL (GPIO_PMGPIO_BASE + 0x8UL) + +#define GPIO_LIST_NUM 6 + +/* + * FUNCTION PROTOTYPES + */ + +/* + * vcp_gpio_config + * + * @param [In] port : Gpio port index, GPIO_GPX(X) + * @param [In] config : Gpio configuration options + * @return + * Notes + */ +int32_t vcp_gpio_config(uint32_t port, uint32_t config); + +/* + * vcp_gpio_set + * + * @param [In] port : Gpio port index, GPIO_GPX(X) + * @param [In] data : Gpio data value, (0 or 1) + * @return 0 or 1 + * + * Notes + */ +int32_t vcp_gpio_set(uint32_t port, uint32_t data); + +/* + * vcp_gpio_peri_chan_sel + * + * @param [In] peri_sel : Gpio peri select index + * @param [In] chan : Gpio peri select channel index + * @return 0 or 1 + * + * Notes + */ +int32_t vcp_gpio_peri_chan_sel(uint32_t peri_sel, uint32_t chan); + +/* + * vcp_gpio_mfio_config + * + * @param [In] peri_sel : MFIO peri select index + * @param [In] peri_type : MFIO peri select type (Disable/GPSB/UART/I2C) + * @param [In] chan_sel : MFIO channel select index + * @param [In] chan_num : MFIO channel select value + * @return 0 or 1 + * + * Notes + */ +int32_t vcp_gpio_mfio_config(uint32_t peri_sel, uint32_t peri_type, uint32_t chan_sel, + uint32_t chan_num); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_GPIO_GPIO_TCCVCP_H_ */ diff --git a/include/zephyr/drivers/interrupt_controller/intc_tic.h b/include/zephyr/drivers/interrupt_controller/intc_tic.h new file mode 100644 index 0000000000000..a5a1449594c5b --- /dev/null +++ b/include/zephyr/drivers/interrupt_controller/intc_tic.h @@ -0,0 +1,205 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_TIC_H_ +#define ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_TIC_H_ + +#include + +#include +#include +#include + +typedef struct tic_distributor { + uint32_t dist_ctrl; /* Distributor Control Register. */ + uint32_t dist_type; /* Interrupt Controller Type Register. */ + uint32_t dist_impl_id; /* Distributor Implementer Identification Register. */ + uint32_t dist_rsvd1[29]; /* Reserved. */ + uint32_t dist_intr_sec[32]; /* Interrupt Security Registers. */ + uint32_t dist_intr_set_en[32]; /* Interrupt Set-Enable Registers. */ + uint32_t dist_intr_clr_en[32]; /* Interrupt Clear-Enable Registers. */ + uint32_t dist_intr_set_pend[32]; /* Interrupt Set-Pending Registers. */ + uint32_t dist_intr_clr_pend[32]; /* Interrupt Clear-Pending Registers. */ + uint32_t dist_intr_set_act[32]; /* Interrupt Set-Active Registers. */ + uint32_t dist_intr_clr_act[32]; /* Interrupt Clear-Active Registers. */ + uint32_t dist_intr_pri[255]; /* Interrupt Priority Registers. */ + uint32_t dist_rsvd3[1]; /* Reserved. */ + uint32_t dist_intr_proc_target[255]; /* Interrupt Processor Target Registers. */ + uint32_t dist_rsvd4[1]; /* Reserved. */ + uint32_t dist_intr_config[64]; /* Interrupt Configuration Registers. */ + uint32_t dist_ppisr[1]; /* TICD_PPISR. */ + uint32_t dist_spisr[15]; /* TICD_SPISRn */ + uint32_t dist_rsvd5[112]; /* Reserved. */ + uint32_t dist_sw_gen_intr; /* Software Generate Interrupt Register. */ + uint32_t dist_rsvd6[3]; /* Reserved. */ + uint32_t dist_sg_intr_clr_act[4]; /* SGInterrupt Clear-Active Registers. */ + uint32_t dist_sg_intr_set_act[4]; /* SGInterrupt Set-Active Registers. */ +} tic_distributor; + +typedef struct tic_cpu_interface { + uint32_t cpu_ctlr; /* CPU Interface Control Register. */ + uint32_t cpu_pri_mask; /* Interrupt Priority Mask Register. */ + uint32_t cpu_bin_ptr; /* Binary Point Register. */ + uint32_t cpu_intr_ack; /* Interrupt Acknowledge Register. */ + uint32_t cpu_end_intr; /* End Interrupt Register. */ + uint32_t cpu_run_pri; /* Running Priority Register. */ + uint32_t cpu_high_pend_intr; /* Highest Pending Interrupt Register. */ + uint32_t cpu_alias_bin_ptr; /* Aliased Binary Point Register. */ + uint32_t cpu_alias_intr_ack; /* Aliased Interrupt Acknowledge Register */ + uint32_t cpu_alias_end_intr; /* Aliased End Interrupt Register. */ + uint32_t cpu_aliase_high_pend_intr; /* Aliased Highest Pending Interrupt Register. */ + uint32_t cpu_rsvd[52]; /* Reserved. */ + uint32_t cpu_if_ident; /* CPU Interface Identification Register. */ +} tic_cpu_interface; + +typedef void (*tic_isr_func)(void *pArg); + +typedef struct tic_irq_func_ptr { + tic_isr_func if_func_ptr; + uint8_t if_is_both_edge; + void *if_arg_ptr; +} tic_irq_func_ptr; + +#define VCP_TIC_DIST_BASE (MCU_BSP_TIC_BASE + 0x1000UL) +#define VCP_TIC_CPU_BASE (MCU_BSP_TIC_BASE + 0x2000UL) + +#define tic_distributer ((volatile tic_distributor *)(VCP_TIC_DIST_BASE)) +#define tic_cpu_if ((volatile tic_cpu_interface *)(VCP_TIC_CPU_BASE)) + +/* ----------- DISTRIBUTOR CONTROL REGISTER ----------- */ +#define ARM_BIT_TIC_DIST_ICDDCR_EN 0x00000001UL /* Global TIC enable. */ + +/* ----------- CPU INTERFACE CONTROL REGISTER --------- */ +#define TIC_CPUIF_CTRL_ENABLEGRP0 0x00000001UL /* Enable secure interrupts. */ +#define TIC_CPUIF_CTRL_ENABLEGRP1 0x00000002UL /* Enable non-secure interrupts. */ +#define TIC_CPUIF_CTRL_ACKCTL 0x00000004UL /* Secure ack of NS interrupts. */ + +#define TIC_SGI_TO_TARGETLIST 0 + +#define MAX_API_CALL_INTERRUPT_PRIORITY 0 + +#define UNIQUE_INTERRUPT_PRIORITIES 32 + +/* The number of bits to shift for an interrupt priority is dependent on the + * number of bits implemented by the interrupt controller. + */ +#if UNIQUE_INTERRUPT_PRIORITIES == 16 +#define PRIORITY_SHIFT 4 +#define MAX_BINARY_POINT_VALUE 3 +#elif UNIQUE_INTERRUPT_PRIORITIES == 32 +#define PRIORITY_SHIFT 3 +#define MAX_BINARY_POINT_VALUE 2 +#elif UNIQUE_INTERRUPT_PRIORITIES == 64 +#define PRIORITY_SHIFT 2 +#define MAX_BINARY_POINT_VALUE 1 +#elif UNIQUE_INTERRUPT_PRIORITIES == 128 +#define PRIORITY_SHIFT 1 +#define MAX_BINARY_POINT_VALUE 0 +#elif UNIQUE_INTERRUPT_PRIORITIES == 256 +#define PRIORITY_SHIFT 0 +#define MAX_BINARY_POINT_VALUE 0 +#else +#error Invalid UNIQUE_INTERRUPT_PRIORITIES setting. UNIQUE_INTERRUPT_PRIORITIES must be \ +set to the number of unique priorities implemented by the target hardware +#endif + +#define cpu_irq_disable() \ + __asm volatile("CPSID i"); \ + __asm volatile("DSB"); \ + __asm volatile("ISB"); + +#define cpu_irq_enable() \ + __asm volatile("CPSIE i"); \ + __asm volatile("DSB"); \ + __asm volatile("ISB"); + +#define UNMASK_VALUE (0xFFUL) + +#define clear_interrupt_mask() \ + { \ + cpu_irq_disable(); \ + tic_cpu_if->cpu_pri_mask = UNMASK_VALUE; \ + __asm volatile("DSB\n" \ + "ISB\n"); \ + cpu_irq_enable(); \ + } + +/* + * TIC Driver Interface Functions + */ + +/** + * @brief Get active interrupt ID. + * + * @return Returns the ID of an active interrupt. + */ +unsigned int z_tic_irq_get_active(void); + +/** + * @brief Signal end-of-interrupt. + * + * @param irq interrupt ID. + */ +void z_tic_irq_eoi(unsigned int irq); + +/** + * @brief Interrupt controller initialization. + */ +void z_tic_irq_init(void); + +/** + * @brief Configure priority, irq type for the interrupt ID. + * + * @param irq interrupt ID. + * @param prio interrupt priority. + * @param flags interrupt flags. + */ +void z_tic_irq_priority_set(unsigned int irq, unsigned int prio, uint32_t flags); + +/** + * @brief Enable Interrupt. + * + * @param irq interrupt ID. + */ +void z_tic_irq_enable(unsigned int irq); + +/** + * @brief Disable Interrupt. + * + * @param irq interrupt ID. + */ +void z_tic_irq_disable(unsigned int irq); + +/** + * @brief Check if an interrupt is enabled. + * + * @param irq interrupt ID. + * + * @retval 0 If interrupt is disabled. + * @retval 1 If interrupt is enabled. + */ +bool z_tic_irq_is_enabled(unsigned int irq); + +/** + * @brief Raise a software interrupt. + * + * @param irq interrupt ID. + */ +void z_tic_arm_enter_irq(int irq); + +/** + * @brief Set an interrupt vector. + * + * @param irq interrupt ID. + * @param prio interrupt priority. + * @param irq_type interrupt type. + * @param irq_func interrupt service routine. + * @param irq_arg argument pointer. + */ +void tic_irq_vector_set(uint32_t irq, uint32_t prio, uint8_t irq_type, tic_isr_func irq_func, + void *irq_arg); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_TIC_H_ */ diff --git a/include/zephyr/dt-bindings/interrupt-controller/tcc-tic.h b/include/zephyr/dt-bindings/interrupt-controller/tcc-tic.h new file mode 100644 index 0000000000000..70d57e108e531 --- /dev/null +++ b/include/zephyr/dt-bindings/interrupt-controller/tcc-tic.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024 Hounjoung Rim + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_TCC_TIC_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_TCC_TIC_H_ + +#define TIC_INT_TYPE_LEVEL_HIGH 0x1 +#define TIC_INT_TYPE_LEVEL_LOW 0x2 +#define TIC_INT_TYPE_EDGE_RISING 0x4 +#define TIC_INT_TYPE_EDGE_FALLING 0x8 +#define TIC_INT_TYPE_EDGE_BOTH (TIC_INT_TYPE_EDGE_RISING | TIC_INT_TYPE_EDGE_FALLING) + +#define TIC_IRQ_DEFAULT_PRIORITY 0xFA +#define TIC_PRIORITY_NO_MEAN 0x100 + +#define TIC_SPI 0x0 +#define TIC_PPI 0x1 + +#define TIC_PPI_START 16 +#define TIC_SPI_START 32 + +#define GIC_PPI_INT_BASE TIC_PPI_START + +#define TIC_CAN0_0 (TIC_SPI_START + 0UL) +#define TIC_CAN0_1 (TIC_SPI_START + 1UL) +#define TIC_CAN1_0 (TIC_SPI_START + 2UL) +#define TIC_CAN1_1 (TIC_SPI_START + 3UL) +#define TIC_CAN2_0 (TIC_SPI_START + 4UL) +#define TIC_CAN2_1 (TIC_SPI_START + 5UL) +#define TIC_GPSB (TIC_SPI_START + 6UL) +#define TIC_GPSB1 (TIC_SPI_START + 7UL) +#define TIC_GPSB2 (TIC_SPI_START + 8UL) +#define TIC_GPSB3 (TIC_SPI_START + 9UL) +#define TIC_GPSB4 (TIC_SPI_START + 10UL) +#define TIC_GPSB0_DMA (TIC_SPI_START + 11UL) +#define TIC_GPSB1_DMA (TIC_SPI_START + 12UL) +#define TIC_GPSB2_DMA (TIC_SPI_START + 13UL) +#define TIC_GPSB3_DMA (TIC_SPI_START + 14UL) +#define TIC_GPSB4_DMA (TIC_SPI_START + 15UL) +#define TIC_UART0 (TIC_SPI_START + 16UL) +#define TIC_UART1 (TIC_SPI_START + 17UL) +#define TIC_UART2 (TIC_SPI_START + 18UL) +#define TIC_UART3 (TIC_SPI_START + 19UL) +#define TIC_UART4 (TIC_SPI_START + 20UL) +#define TIC_UART5 (TIC_SPI_START + 21UL) +#define TIC_DMA0 (TIC_SPI_START + 22UL) +#define TIC_DMA1 (TIC_SPI_START + 23UL) +#define TIC_DMA2 (TIC_SPI_START + 24UL) +#define TIC_DMA3 (TIC_SPI_START + 25UL) +#define TIC_DMA4 (TIC_SPI_START + 26UL) +#define TIC_DMA5 (TIC_SPI_START + 27UL) +#define TIC_DMA6 (TIC_SPI_START + 28UL) +#define TIC_DMA7 (TIC_SPI_START + 29UL) +#define TIC_I2C (TIC_SPI_START + 30UL) +#define TIC_I2C1 (TIC_SPI_START + 31UL) +#define TIC_I2C2 (TIC_SPI_START + 32UL) +#define TIC_I2C3 (TIC_SPI_START + 33UL) +#define TIC_I2C4 (TIC_SPI_START + 34UL) +#define TIC_I2C5 (TIC_SPI_START + 35UL) +#define TIC_VS_I2C0 (TIC_SPI_START + 36UL) +#define TIC_VS_I2C1 (TIC_SPI_START + 37UL) +#define TIC_VS_I2C2 (TIC_SPI_START + 38UL) +#define TIC_VS_I2C3 (TIC_SPI_START + 39UL) +#define TIC_VS_I2C4 (TIC_SPI_START + 40UL) +#define TIC_VS_I2C5 (TIC_SPI_START + 41UL) +#define TIC_ICTC0 (TIC_SPI_START + 42UL) +#define TIC_ICTC1 (TIC_SPI_START + 43UL) +#define TIC_ICTC2 (TIC_SPI_START + 44UL) +#define TIC_ICTC3 (TIC_SPI_START + 45UL) +#define TIC_ICTC4 (TIC_SPI_START + 46UL) +#define TIC_ICTC5 (TIC_SPI_START + 47UL) +#define TIC_RED_ICTC0 (TIC_SPI_START + 48UL) +#define TIC_RED_ICTC1 (TIC_SPI_START + 49UL) +#define TIC_RED_ICTC2 (TIC_SPI_START + 50UL) +#define TIC_RED_ICTC3 (TIC_SPI_START + 51UL) +#define TIC_RED_ICTC4 (TIC_SPI_START + 52UL) +#define TIC_RED_ICTC5 (TIC_SPI_START + 53UL) +#define TIC_ADC0 (TIC_SPI_START + 54UL) +#define TIC_ADC1 (TIC_SPI_START + 55UL) +#define TIC_TIMER_0 (TIC_SPI_START + 56UL) +#define TIC_TIMER_1 (TIC_SPI_START + 57UL) +#define TIC_TIMER_2 (TIC_SPI_START + 58UL) +#define TIC_TIMER_3 (TIC_SPI_START + 59UL) +#define TIC_TIMER_4 (TIC_SPI_START + 60UL) +#define TIC_TIMER_5 (TIC_SPI_START + 61UL) +#define TIC_TIMER_6 (TIC_SPI_START + 62UL) +#define TIC_TIMER_7 (TIC_SPI_START + 63UL) +#define TIC_TIMER_8 (TIC_SPI_START + 64UL) +#define TIC_TIMER_9 (TIC_SPI_START + 65UL) +#define TIC_WATCHDOG (TIC_SPI_START + 66UL) +#define TIC_PMU_WATCHDOG (TIC_SPI_START + 67UL) +#define TIC_DEFAULT_SLV_ERR (TIC_SPI_START + 68UL) +#define TIC_SFMC (TIC_SPI_START + 69UL) +#define TIC_CR5_PMU (TIC_SPI_START + 70UL) +#define TIC_EXT0 (TIC_SPI_START + 71UL) +#define TIC_EXT1 (TIC_SPI_START + 72UL) +#define TIC_EXT2 (TIC_SPI_START + 73UL) +#define TIC_EXT3 (TIC_SPI_START + 74UL) +#define TIC_EXT4 (TIC_SPI_START + 75UL) +#define TIC_EXT5 (TIC_SPI_START + 76UL) +#define TIC_EXT6 (TIC_SPI_START + 77UL) +#define TIC_EXT7 (TIC_SPI_START + 78UL) +#define TIC_EXT8 (TIC_SPI_START + 79UL) +#define TIC_EXT9 (TIC_SPI_START + 80UL) +#define TIC_EXT_N0 (TIC_SPI_START + 81UL) +#define TIC_EXT_N1 (TIC_SPI_START + 82UL) +#define TIC_EXT_N2 (TIC_SPI_START + 83UL) +#define TIC_EXT_N3 (TIC_SPI_START + 84UL) +#define TIC_EXT_N4 (TIC_SPI_START + 85UL) +#define TIC_EXT_N5 (TIC_SPI_START + 86UL) +#define TIC_EXT_N6 (TIC_SPI_START + 87UL) +#define TIC_EXT_N7 (TIC_SPI_START + 88UL) +#define TIC_EXT_N8 (TIC_SPI_START + 89UL) +#define TIC_EXT_N9 (TIC_SPI_START + 90UL) +#define TIC_FMU_IRQ (TIC_SPI_START + 91UL) +#define TIC_FMU_FIQ (TIC_SPI_START + 92UL) +#define TIC_I2S_DMA (TIC_SPI_START + 93UL) +#define TIC_GMAC (TIC_SPI_START + 94UL) +#define TIC_GMAC_TX0 (TIC_SPI_START + 95UL) +#define TIC_GMAC_TX1 (TIC_SPI_START + 96UL) +#define TIC_GMAC_RX0 (TIC_SPI_START + 97UL) +#define TIC_GMAC_RX1 (TIC_SPI_START + 98UL) +#define TIC_SRAM_ECC (TIC_SPI_START + 99UL) +#define TIC_DMAC_ (TIC_SPI_START + 100UL) +#define TIC_DMAC_INT_CLEAR (TIC_SPI_START + 101UL) +#define TIC_DMAC_INTERR (TIC_SPI_START + 102UL) +#define TIC_HSM_WDT_OUTPUT (TIC_SPI_START + 103UL) +#define TIC_MBOX_SLV_TX (TIC_SPI_START + 104UL) +#define TIC_MBOX_MST_TX (TIC_SPI_START + 105UL) +#define TIC_AES (TIC_SPI_START + 106UL) +#define TIC_TRNG (TIC_SPI_START + 107UL) +#define TIC_TRNG_FAD (TIC_SPI_START + 108UL) +#define TIC_PKE (TIC_SPI_START + 109UL) +#define TIC_PKE_ECC_S (TIC_SPI_START + 110UL) +#define TIC_PKE_ECC_D (TIC_SPI_START + 111UL) +#define TIC_HSM_DEFAULT_SLV_ERR (TIC_SPI_START + 112UL) +#define TIC_HSM_CPU_SYS_RESET_REQ (TIC_SPI_START + 113UL) +#define TIC_PFLASH (TIC_SPI_START + 114UL) +#define TIC_DFLASH (TIC_SPI_START + 115UL) +#define TIC_RTC_ALARM (TIC_SPI_START + 116UL) +#define TIC_RTC_WAKEUP (TIC_SPI_START + 117UL) +#define TIC_GMAC_TX2 (TIC_SPI_START + 118UL) +#define TIC_GMAC_RX2 (TIC_SPI_START + 119UL) +#define TIC_SFMC1 (TIC_SPI_START + 120UL) +#define TIC_SPU (TIC_SPI_START + 121UL) + +#define TIC_EINT_START_INT (TIC_EXT0) +#define TIC_EINT_END_INT (TIC_EXT9) +#define TIC_EINT_NUM ((unsigned long)TIC_EXT_N0 - (unsigned long)TIC_EXT0) + +#define TIC_INT_SRC_CNT (TIC_SPU + 1UL) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_INTERRUPT_CONTROLLER_TCC_TIC_H_ */ diff --git a/soc/tcc/tcc7045/CMakeLists.txt b/soc/tcc/tcc7045/CMakeLists.txt new file mode 100644 index 0000000000000..edb4dcba18051 --- /dev/null +++ b/soc/tcc/tcc7045/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2024 Hounjoung Rim +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc.c +) + +zephyr_sources_ifdef( + CONFIG_ARM_MPU + arm_mpu_regions.c +) + +zephyr_include_directories(.) + +if(CONFIG_SOC_TCC7045) + set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") +endif() diff --git a/soc/tcc/tcc7045/Kconfig b/soc/tcc/tcc7045/Kconfig new file mode 100644 index 0000000000000..49b497fb73fe7 --- /dev/null +++ b/soc/tcc/tcc7045/Kconfig @@ -0,0 +1,19 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config SOC_TCC7045 + select ARM + select CPU_CORTEX_R5 + select CPU_HAS_ARM_MPU + select VFP_DP_D16 + select CPU_HAS_FPU + select ARMV7_R + select ARMV7_R_FP + select SOC_EARLY_INIT_HOOK + select TIC + select TCC_VCPTTC_TIMER + select CLOCK_CONTROL + select CLOCK_CONTROL_TCC_CCU + select SYSCON + select TIMEOUT_64BIT + select ARCH_HAS_USERSPACE diff --git a/soc/tcc/tcc7045/Kconfig.defconfig b/soc/tcc/tcc7045/Kconfig.defconfig new file mode 100644 index 0000000000000..ed9cdd12605a0 --- /dev/null +++ b/soc/tcc/tcc7045/Kconfig.defconfig @@ -0,0 +1,38 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +if SOC_TCC7045 + +config ARM_CUSTOM_INTERRUPT_CONTROLLER + default y + +config GEN_IRQ_VECTOR_TABLE + default y + +config SHARED_INTERRUPTS + def_bool y + +config NUM_IRQS + default 220 + +config TICKLESS_KERNEL + def_bool n + +config TCCVCP_CONSOLE + def_bool y + +config ARM_MPU + def_bool y + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +DT_CHOSEN_Z_FLASH := zephyr,flash + +config FLASH_SIZE + default $(dt_chosen_reg_size_int,$(DT_CHOSEN_Z_FLASH),0,K) + +config FLASH_BASE_ADDRESS + default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) + +endif diff --git a/soc/tcc/tcc7045/Kconfig.soc b/soc/tcc/tcc7045/Kconfig.soc new file mode 100644 index 0000000000000..39f41bac37c28 --- /dev/null +++ b/soc/tcc/tcc7045/Kconfig.soc @@ -0,0 +1,11 @@ +# Copyright 2024 Hounjoung Rim +# SPDX-License-Identifier: Apache-2.0 + +config SOC_TCC7045 + bool + +config SOC + default "tcc7045" if SOC_TCC7045 + +config SYS_CLOCK_TICKS_PER_SEC + def_int 1000 if SOC_TCC7045 diff --git a/soc/tcc/tcc7045/arm_mpu_regions.c b/soc/tcc/tcc7045/arm_mpu_regions.c new file mode 100644 index 0000000000000..d2ff261d9c703 --- /dev/null +++ b/soc/tcc/tcc7045/arm_mpu_regions.c @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: Apache-2.0 + * + * Copyright 2024 Hounjoung Rim + */ + +#include +#include + +#define MPU_SHAREABLE (0x00000004U) +#define MPU_STRONG_ORDERED_SHARED (0x00000000U) + +#define MPU_DEVICE_SHARED (0x00000001U) +#define MPU_DEVICE_NONSHARED (0x00000010U) + +#define MPU_NORM_NSHARED_WT_NWA (0x00000002U) +#define MPU_NORM_SHARED_WT_NWA (0x00000006U) + +#define MPU_NORM_NSHARED_WB_NWA (0x00000003U) +#define MPU_NORM_SHARED_WB_NWA (0x00000007U) + +#define MPU_NORM_NSHARED_NCACHE (0x00000008U) +#define MPU_NORM_SHARED_NCACHE (0x0000000CU) + +#define MPU_NORM_NSHARED_WB_WA (0x0000000BU) +#define MPU_NORM_SHARED_WB_WA (0x0000000FU) + +#define MPU_NO_ACCESS (0x00000000U << 8U) +#define MPU_PRIV_RW_USER_NA (0x00000001U << 8U) +#define MPU_PRIV_RW_USER_RO (0x00000002U << 8U) +#define MPU_PRIV_RW_USER_RW (0x00000003U << 8U) +#define MPU_PRIV_RO_USER_NA (0x00000005U << 8U) +#define MPU_PRIV_RO_USER_RO (0x00000006U << 8U) + +extern uint32_t _image_rom_end_order; +static const struct arm_mpu_region mpu_regions[] = { + MPU_REGION_ENTRY("SRAM0", 0x00000000, REGION_512K, + {.rasr = (MPU_NORM_SHARED_WB_WA | MPU_PRIV_RW_USER_RW)}), + + MPU_REGION_ENTRY("REMAP_FLASH", 0x01000000, REGION_4M, + {.rasr = MPU_NORM_NSHARED_WB_NWA | MPU_PRIV_RO_USER_RO}), + + MPU_REGION_ENTRY("PFLASH", 0x20000000, REGION_2M, + {.rasr = MPU_NORM_NSHARED_WB_NWA | MPU_PRIV_RO_USER_RO}), + + MPU_REGION_ENTRY("DFLASH", 0x30000000, REGION_256K, + {.rasr = MPU_NORM_NSHARED_WB_NWA | MPU_PRIV_RW_USER_RW}), + + MPU_REGION_ENTRY("SNOR", 0x40000000, REGION_256M, + {.rasr = MPU_NORM_NSHARED_NCACHE | MPU_PRIV_RO_USER_RO}), + + MPU_REGION_ENTRY("PERI", 0xA0000000, REGION_16M, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RW}), + + MPU_REGION_ENTRY("PFLASHCON", 0xA1000000, REGION_64K, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RW}), + + MPU_REGION_ENTRY("PFLASH_OPTAREA", 0xA1010000, REGION_16K, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RO}), + + MPU_REGION_ENTRY("PFLASH_INT", 0xA1020000, REGION_32B, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RW}), + + MPU_REGION_ENTRY("DFLASHCON", 0xA1080000, REGION_64K, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RW}), + + MPU_REGION_ENTRY("DFLASH_OPTAREA", 0xA1090000, REGION_2K, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RO}), + + MPU_REGION_ENTRY("DFLASH_INT", 0xA10A0000, REGION_64B, + {.rasr = MPU_STRONG_ORDERED_SHARED | MPU_PRIV_RW_USER_RW}), +}; + +const struct arm_mpu_config mpu_config = { + .num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions, +}; diff --git a/soc/tcc/tcc7045/linker.ld b/soc/tcc/tcc7045/linker.ld new file mode 100644 index 0000000000000..2074b285fb96d --- /dev/null +++ b/soc/tcc/tcc7045/linker.ld @@ -0,0 +1,385 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include + +/* physical address of RAM */ +#define ROMABLE_REGION REMAP_FLASH +#define RAMABLE_REGION RAM + +#define ROM_ADDR (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET) + +#if defined(CONFIG_ROM_END_OFFSET) +#define ROM_END_OFFSET CONFIG_ROM_END_OFFSET +#else +#define ROM_END_OFFSET 0 +#endif + +#if CONFIG_FLASH_LOAD_SIZE > 0 + #define ROM_SIZE (CONFIG_FLASH_LOAD_SIZE - ROM_END_OFFSET) +#else + #define ROM_SIZE (CONFIG_FLASH_SIZE*1K - CONFIG_FLASH_LOAD_OFFSET - ROM_END_OFFSET) +#endif + +#define RAM_SIZE (CONFIG_SRAM_SIZE * 1K) +#define RAM_ADDR CONFIG_SRAM_BASE_ADDRESS + +/* Set alignment to CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE + * to make linker section alignment comply with MPU granularity. + */ +#if defined(CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE) +_region_min_align = CONFIG_ARM_MPU_REGION_MIN_ALIGN_AND_SIZE; +#elif defined(CONFIG_ARM_AARCH32_MMU) +_region_min_align = CONFIG_MMU_PAGE_SIZE; +#else +/* If building without MPU/MMU support, use default 4-byte alignment. */ +_region_min_align = 4; +#endif + +#if defined(CONFIG_MPU_REQUIRES_POWER_OF_TWO_ALIGNMENT) + #define MPU_ALIGN(region_size) \ + . = ALIGN(_region_min_align); \ + . = ALIGN(1 << LOG2CEIL(region_size)) +#else + #define MPU_ALIGN(region_size) \ + . = ALIGN(_region_min_align) +#endif + +#define BSS_ALIGN ALIGN(_region_min_align) + +#define MMU_ALIGN . = ALIGN(_region_min_align) + +/* Memory Definitions */ + +SRAM_TOTAL_SIZE = 0x80000; /* 512KB */ +MEMORY +{ + + RAM (rwx) : ORIGIN = 0x00000000, LENGTH = SRAM_TOTAL_SIZE + REMAP_FLASH (rx) : ORIGIN = 0x01043000, LENGTH = 0x00200000 + LINKER_DT_REGIONS() + /* Used by and documented in include/linker/intlist.ld */ + IDT_LIST (wx) : ORIGIN = 0xFFFF8000, LENGTH = 32K +} + +ENTRY(CONFIG_KERNEL_ENTRY) + +SECTIONS +{ +#include + +#ifdef CONFIG_LLEXT +#include +#endif + + /* + * .plt and .iplt are here according to 'arm-zephyr-elf-ld --verbose', + * before text section. + */ + SECTION_PROLOGUE(.plt,,) + { + *(.plt) + } + + SECTION_PROLOGUE(.iplt,,) + { + *(.iplt) + } + + GROUP_START(ROMABLE_REGION) + + __rom_region_start = RAM_ADDR; + + SECTION_PROLOGUE(rom_start,,) + { + +/* Located in generated directory. This file is populated by calling + * zephyr_linker_sources(ROM_START ...). This typically contains the vector + * table and debug information. + */ +#include + + } GROUP_LINK_IN(ROMABLE_REGION) + +#ifdef CONFIG_CODE_DATA_RELOCATION + +#include + +#endif /* CONFIG_CODE_DATA_RELOCATION */ + + SECTION_PROLOGUE(_TEXT_SECTION_NAME,,) + { + . = ALIGN(_region_min_align); + __text_region_start = .; + z_mapped_start = .; + +#include + + *(.text) + *(".text.*") + *(.gnu.linkonce.t.*) + + /* + * These are here according to 'arm-zephyr-elf-ld --verbose', + * after .gnu.linkonce.t.* + */ + *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx) + + __text_region_end = .; + . = ALIGN(_region_min_align); + } GROUP_LINK_IN(ROMABLE_REGION) + +#if defined (CONFIG_CPP) + SECTION_PROLOGUE(.ARM.extab,,) + { + /* + * .ARM.extab section containing exception unwinding information. + */ + *(.ARM.extab* .gnu.linkonce.armextab.*) + } GROUP_LINK_IN(ROMABLE_REGION) +#endif + + SECTION_PROLOGUE(.ARM.exidx,,) + { + /* + * This section, related to stack and exception unwinding, is placed + * explicitly to prevent it from being shared between multiple regions. + * It must be defined for gcc to support 64-bit math and avoid + * section overlap. + */ + __exidx_start = .; +#if defined (__GCC_LINKER_CMD__) + *(.ARM.exidx* gnu.linkonce.armexidx.*) +#endif + __exidx_end = .; + } GROUP_LINK_IN(ROMABLE_REGION) + + SECTION_PROLOGUE(rodata_start,,) + { + . = ALIGN(_region_min_align); + __rodata_region_start = .; + } GROUP_LINK_IN(ROMABLE_REGION) + +#include +/* Located in generated directory. This file is populated by calling + * zephyr_linker_sources(ROM_SECTIONS ...). Useful for grouping iterable RO structs. + */ +#include +#include +#include + + SECTION_PROLOGUE(_RODATA_SECTION_NAME,,) + { + *(.rodata) + *(".rodata.*") + *(.gnu.linkonce.r.*) + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#include + + /* + * For XIP images, in order to avoid the situation when __data_rom_start + * is 32-bit aligned, but the actual data is placed right after rodata + * section, which may not end exactly at 32-bit border, pad rodata + * section, so __data_rom_start points at data and it is 32-bit aligned. + * + * On non-XIP images this may enlarge image size up to 3 bytes. This + * generally is not an issue, since modern ROM and FLASH memory is + * usually 4k aligned. + */ + . = ALIGN(4); + + /* + * RODATA must be the last section so that the size of the entire read + * only area will be filled to a power of 2. + */ + MPU_ALIGN(ABSOLUTE(.) - __rom_region_start); + } GROUP_LINK_IN(ROMABLE_REGION) + + __rodata_region_end = .; + __rom_region_end = .; + MPU_ALIGN(__rodata_region_end - __rom_region_start); + _image_rom_end_order = (LOG2CEIL(__rom_region_end) - 1) << 1; + + GROUP_END(ROMABLE_REGION) + + /* + * These are here according to 'arm-zephyr-elf-ld --verbose', + * before data section. + */ + SECTION_PROLOGUE(.got,,) + { + *(.got.plt) + *(.igot.plt) + *(.got) + *(.igot) + } + + GROUP_START(RAMABLE_REGION) + + . = RAM_ADDR; + /* Align the start of image RAM with the + * minimum granularity required by MPU. + */ + . = ALIGN(_region_min_align); + _image_ram_start = .; + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#if defined(CONFIG_USERSPACE) +#define APP_SHARED_ALIGN . = ALIGN(_region_min_align); +#define SMEM_PARTITION_ALIGN MPU_ALIGN + +#include + + _app_smem_size = _app_smem_end - _app_smem_start; + _app_smem_rom_start = LOADADDR(_APP_SMEM_SECTION_NAME); +#endif /* CONFIG_USERSPACE */ + + SECTION_DATA_PROLOGUE(_BSS_SECTION_NAME,(NOLOAD), BSS_ALIGN) + { + /* + * For performance, BSS section is assumed to be 4 byte aligned and + * a multiple of 4 bytes + */ + . = ALIGN(4); + __bss_start = .; + __kernel_ram_start = .; + + *(.bss) + *(".bss.*") + *(COMMON) + *(".kernel_bss.*") + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + + /* + * As memory is cleared in words only, it is simpler to ensure the BSS + * section ends on a 4 byte boundary. This wastes a maximum of 3 bytes. + */ + __bss_end = ALIGN(4); + } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) + +#include + + SECTION_DATA_PROLOGUE(_DATA_SECTION_NAME,,) + { + __data_region_start = .; + __data_start = .; + *(.data) + *(".data.*") + *(".kernel.*") + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#ifdef CONFIG_CODE_DATA_RELOCATION +#include +#endif + __data_end = .; + + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) + __data_size = __data_end - __data_start; + __data_load_start = LOADADDR(_DATA_SECTION_NAME); + + __data_region_load_start = LOADADDR(_DATA_SECTION_NAME); + +#include +#include +#include + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + + __data_region_end = .; + + + /* Define linker symbols */ + + __kernel_ram_end = RAM_ADDR + RAM_SIZE; + __kernel_ram_size = __kernel_ram_end - __kernel_ram_start; + +#if DT_NODE_HAS_STATUS(DT_CHOSEN(zephyr_ocm), okay) +GROUP_START(OCM) + + SECTION_PROLOGUE(_OCM_BSS_SECTION_NAME, (NOLOAD),SUBALIGN(4)) + { + __ocm_start = .; + __ocm_bss_start = .; + *(.ocm_bss) + *(".ocm_bss.*") + __ocm_bss_end = .; + } GROUP_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_CHOSEN(zephyr_ocm))) + + SECTION_PROLOGUE(_OCM_DATA_SECTION_NAME,,SUBALIGN(4)) + { + __ocm_data_start = .; + *(.ocm_data) + *(".ocm_data.*") + __ocm_data_end = .; + } GROUP_LINK_IN(LINKER_DT_NODE_REGION_NAME(DT_CHOSEN(zephyr_ocm))) + + __ocm_end = .; + __ocm_size = __ocm_end - __ocm_start; + +GROUP_END(OCM) +#endif + +/* Located in generated directory. This file is populated by the + * zephyr_linker_sources() Cmake function. + */ +#include + +#define LAST_RAM_ALIGN . = ALIGN(_region_min_align); + +#include + + GROUP_END(RAMABLE_REGION) + +#include + + SECTION_PROLOGUE(.ARM.attributes, 0,) + { + KEEP(*(.ARM.attributes)) + KEEP(*(.gnu.attributes)) + } + + /* Sections generated from 'zephyr,memory-region' nodes */ + LINKER_DT_SECTIONS() + + /* Must be last in romable region */ + SECTION_PROLOGUE(.last_section,,) + { +#ifdef CONFIG_LINKER_LAST_SECTION_ID + /* Fill last section with a word to ensure location counter and actual rom + * region data usage match. */ + LONG(CONFIG_LINKER_LAST_SECTION_ID_PATTERN) +#endif + } GROUP_LINK_IN(ROMABLE_REGION) + + /* To provide the image size as a const expression, + * calculate this value here. */ + _flash_used = LOADADDR(.last_section) + SIZEOF(.last_section) - __rom_region_start; + +} diff --git a/soc/tcc/tcc7045/soc.c b/soc/tcc/tcc7045/soc.c new file mode 100644 index 0000000000000..193a757ad727b --- /dev/null +++ b/soc/tcc/tcc7045/soc.c @@ -0,0 +1,154 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include "soc.h" + +uint32_t z_soc_irq_get_active(void) +{ + return z_tic_irq_get_active(); +} + +void z_soc_irq_eoi(uint32_t irq) +{ + z_tic_irq_eoi(irq); +} + +void z_soc_irq_init(void) +{ + z_tic_irq_init(); +} + +void z_soc_irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags) +{ + /* Configure interrupt type and priority */ + z_tic_irq_priority_set(irq, prio, flags); +} + +void z_soc_irq_enable(uint32_t irq) +{ + /* Enable interrupt */ + z_tic_irq_enable(irq); +} + +void z_soc_irq_disable(uint32_t irq) +{ + /* Disable interrupt */ + z_tic_irq_disable(irq); +} + +int32_t z_soc_irq_is_enabled(uint32_t irq) +{ + /* Check if interrupt is enabled */ + return z_tic_irq_is_enabled(irq); +} + +/** + * @brief Perform basic hardware initialization at boot. + * + * This needs to be run from the very beginning. + */ +void soc_early_init_hook(void) +{ + vcp_clock_init(); + + /* Enable SYS_3P3 */ + vcp_gpio_config(SYS_PWR_EN, (uint32_t)(GPIO_FUNC(0U) | VCP_GPIO_OUTPUT)); + vcp_gpio_set(SYS_PWR_EN, 1UL); +} + +static int32_t reduce_dividend(uint64_t *dividend, uint32_t divisor, uint64_t *res) +{ + uint32_t high = (uint32_t)(*dividend >> 32ULL); + + if (divisor == 0) { + return -EINVAL; + } + + if (high >= divisor) { + high /= divisor; + *res = ((uint64_t)high) << 32ULL; + + if ((*dividend / (uint64_t)divisor) >= (uint64_t)high) { + return -EINVAL; + } + + *dividend -= (((uint64_t)high * (uint64_t)divisor) << 32ULL); + } + return 0; +} + +static void adjust_divisor_and_quotient(uint64_t *b, uint64_t *d, uint64_t rem) +{ + while ((*b > 0ULL) && (*b < rem)) { + *b = *b + *b; + *d = *d + *d; + } +} + +static int32_t perform_division(uint64_t *rem, uint64_t *b, uint64_t *d, uint64_t *res) +{ + do { + if (*rem >= *b) { + *rem -= *b; + + if ((0xFFFFFFFFFFFFFFFFULL - *d) < *res) { + return -EINVAL; + } + + *res += *d; + } + + *b >>= 1UL; + *d >>= 1UL; + } while (*d != 0ULL); + + return 0; +} + +int32_t soc_div64_to_32(uint64_t *dividend_ptr, uint32_t divisor, uint32_t *rem_ptr) +{ + int32_t ret_val = 0; + uint64_t rem = 0; + uint64_t b = divisor; + uint64_t d = 1; + uint64_t res = 0; + + if (dividend_ptr == TCC_NULL_PTR) { + return -EINVAL; + } + + rem = *dividend_ptr; + + ret_val = reduce_dividend(&rem, divisor, &res); + if (ret_val != 0) { + return ret_val; + } + + adjust_divisor_and_quotient(&b, &d, rem); + + ret_val = perform_division(&rem, &b, &d, &res); + if (ret_val != 0) { + return ret_val; + } + + *dividend_ptr = res; + + if (rem_ptr != TCC_NULL_PTR) { + *rem_ptr = (uint32_t)rem; + } + + return ret_val; +} diff --git a/soc/tcc/tcc7045/soc.h b/soc/tcc/tcc7045/soc.h new file mode 100644 index 0000000000000..3a048e4d43189 --- /dev/null +++ b/soc/tcc/tcc7045/soc.h @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_TCC_TCC7045_SOC_H_ +#define ZEPHYR_SOC_TCC_TCC7045_SOC_H_ + +#include "soc_reg_phys.h" + +#define TCC_NULL_PTR (void *)0 + +#define TCC_ON 1U +#define TCC_OFF 0U + +#define SYS_PWR_EN (GPIO_GPC(2UL)) + +int32_t soc_div64_to_32(uint64_t *pullDividend, uint32_t uiDivisor, uint32_t *puiRem); + +#endif /* ZEPHYR_SOC_TCC_TCC7045_SOC_H_ */ diff --git a/soc/tcc/tcc7045/soc.yml b/soc/tcc/tcc7045/soc.yml new file mode 100644 index 0000000000000..e55ca49ed73d9 --- /dev/null +++ b/soc/tcc/tcc7045/soc.yml @@ -0,0 +1,4 @@ +series: +- name: tcc70xx + socs: + - name: tcc7045 diff --git a/soc/tcc/tcc7045/soc_reg_phys.h b/soc/tcc/tcc7045/soc_reg_phys.h new file mode 100644 index 0000000000000..29fee21844be5 --- /dev/null +++ b/soc/tcc/tcc7045/soc_reg_phys.h @@ -0,0 +1,44 @@ +/* + * Copyright 2024 Hounjoung Rim + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef ZEPHYR_SOC_TCC_TCC7045_SOC_REG_PHYS_H_ +#define ZEPHYR_SOC_TCC_TCC7045_SOC_REG_PHYS_H_ + +#define MCU_BSP_CAN_FD_BASE 0xA0000000UL +#define MCU_BSP_ADC_0_BASE 0xA0080000UL +#define MCU_BSP_ADC_1_BASE 0xA0090000UL +#define MCU_BSP_GPSB_BASE 0xA0100000UL +#define MCU_BSP_UART_BASE 0xA0200000UL +#define MCU_BSP_UART_CONF_BASE 0xA02F0000UL +#define MCU_BSP_I2C_BASE 0xA0400000UL +#define MCU_BSP_ICTC_BASE 0xA0600000UL +#define MCU_BSP_PWM_BASE 0xA0700000UL +#define MCU_BSP_PWM_CFG_BASE 0xA07F0000UL +#define MCU_BSP_GDMA_BASE 0xA0800000UL +#define MCU_BSP_I2S_BASE 0xA0880000UL +#define MCU_BSP_GMAC_BASE 0xA0900000UL +#define MCU_BSP_HSM_BASE 0xA0980000UL +#define MCU_BSP_CRYPTO_BASE 0xA09B0000UL +#define MCU_BSP_MBOX_BASE 0xA09F0000UL + +#define MCU_BSP_SFMC_BASE 0xA0F00000UL +#define MCU_BSP_TIC_BASE 0xA0F10000UL +#define MCU_BSP_SUBSYS_BASE 0xA0F20000UL +#define MCU_BSP_R5_CONF_BASE 0xA0F21000UL +#define MCU_BSP_GPIO_BASE 0xA0F22000UL +#define MCU_BSP_WDT_BASE 0xA0F23000UL +#define CLOCK_BASE_ADDR 0xA0F24000UL +#define MCU_BSP_CMU_BASE 0xA0F25000UL +#define MCU_BSP_SYSSM_BASE 0xA0F26000UL +#define MCU_BSP_DSE_BASE 0xA0F27000UL +#define MCU_BSP_PMU_BASE 0xA0F28000UL +#define MCU_BSP_FMU_BASE 0xA0F28400UL +#define MCU_BSP_PMIO_BASE 0xA0F28800UL +#define MCU_BSP_RTC_BASE 0xA0F28C00UL +#define MCU_BSP_TIMER_BASE 0xA0F2A000UL + +#endif /* ZEPHYR_SOC_TCC_TCC7045_SOC_REG_PHYS_H_ */ diff --git a/subsys/testsuite/include/zephyr/interrupt_util.h b/subsys/testsuite/include/zephyr/interrupt_util.h index 15d4770cc1891..846b0968d9bce 100644 --- a/subsys/testsuite/include/zephyr/interrupt_util.h +++ b/subsys/testsuite/include/zephyr/interrupt_util.h @@ -242,6 +242,17 @@ static inline void trigger_irq(int irq) _sw_isr_table[irq - CONFIG_GEN_IRQ_START_VECTOR].arg); } +#elif defined(CONFIG_CPU_CORTEX_R5) && defined(CONFIG_TIC) + +#include + +extern void z_tic_arm_enter_irq(int); + +static inline void trigger_irq(int irq) +{ + z_tic_arm_enter_irq(irq); +} + #else #define NO_TRIGGER_FROM_SW #endif