From 8aa75e2d6f8001430b974ea03ee696dd0313fa33 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 5 Feb 2025 18:03:21 +0100 Subject: [PATCH 01/11] renesas/ra6m5: clear NVIC->ITNS at startup for non TZ Otherwise, interrupts will trigger a very funny fault See https://github.com/arduino/ArduinoCore-renesas/blob/main/cores/arduino/main.cpp#L49-L57 Signed-off-by: Martino Facchin --- soc/renesas/ra/ra6m5/soc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/soc/renesas/ra/ra6m5/soc.c b/soc/renesas/ra/ra6m5/soc.c index 872b89421d305..b2819aed795dd 100644 --- a/soc/renesas/ra/ra6m5/soc.c +++ b/soc/renesas/ra/ra6m5/soc.c @@ -60,6 +60,9 @@ void soc_early_init_hook(void) R_CPSCU->ICUSARG = 0; R_CPSCU->ICUSARH = 0; R_CPSCU->ICUSARI = 0; + for (int i = 0; i < 16; i++) { + NVIC->ITNS[i] = 0; + } /* Enable protection using PRCR register. */ R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SAR); From 3f1de4c8cb97dee5ef5e62cd9164f8368a961160 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 5 Feb 2025 18:07:07 +0100 Subject: [PATCH 02/11] renesas/ra6m5: allow removal of option_bits sections Need to disable them for boards with bootloader. When the nodes are disabled, BUILD_OUTPUT_BIN is usable (not a 400MB file) Signed-off-by: Martino Facchin --- soc/renesas/ra/ra6m5/sections.ld | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/soc/renesas/ra/ra6m5/sections.ld b/soc/renesas/ra/ra6m5/sections.ld index 1fe7db907a3d9..8f137924c13db 100644 --- a/soc/renesas/ra/ra6m5/sections.ld +++ b/soc/renesas/ra/ra6m5/sections.ld @@ -11,6 +11,8 @@ SECTION_DATA_PROLOGUE(.fsp_dtc_vector_table,(NOLOAD),) *(.fsp_dtc_vector_table) } GROUP_DATA_LINK_IN(RAMABLE_REGION, RAMABLE_REGION) +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_ofs), okay) + SECTION_PROLOGUE(.option_setting_ofs,,) { __OPTION_SETTING_OFS_Start = .; @@ -22,6 +24,10 @@ SECTION_PROLOGUE(.option_setting_ofs,,) __OPTION_SETTING_OFS_End = .; } GROUP_LINK_IN(OPTION_SETTING_OFS) = 0xFF +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_sas), okay) + SECTION_PROLOGUE(.option_setting_sas,,) { __OPTION_SETTING_SAS_Start = .; @@ -29,6 +35,10 @@ SECTION_PROLOGUE(.option_setting_sas,,) __OPTION_SETTING_SAS_End = .; } GROUP_LINK_IN(OPTION_SETTING_SAS) = 0xFF +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(option_setting_s), okay) + SECTION_PROLOGUE(.option_setting_s,,) { __OPTION_SETTING_S_Start = .; @@ -69,3 +79,5 @@ SECTION_PROLOGUE(.option_setting_s,,) KEEP(*(.option_setting_bps_sel3)) __OPTION_SETTING_S_End = .; } GROUP_LINK_IN(OPTION_SETTING_S) = 0xFF + +#endif From bf6c6535309cc368f9f95e75ff78c11ce787f5a2 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Thu, 6 Feb 2025 17:38:09 +0100 Subject: [PATCH 03/11] renesas/ra: add ethernet support for RA6 family Borrowed from RA8 nodes Signed-off-by: Martino Facchin --- dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi | 4 ++++ dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi b/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi index 9809fe379ad49..a0f9cee3a3f47 100644 --- a/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi +++ b/dts/arm/renesas/ra/ra6/r7fa6e2bx.dtsi @@ -14,6 +14,10 @@ /delete-node/ &agt3; /delete-node/ &agt4; /delete-node/ &agt5; +/delete-node/ ð +/delete-node/ &mdio; +#include + /delete-node/ &adc1; /delete-node/ &usbfs; /delete-node/ &usbfs_phy; diff --git a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi index ae50b0ddf5610..daeabd1e3f81f 100644 --- a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi +++ b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi @@ -536,6 +536,22 @@ clocks = <&pclkb 0 0>; status = "disabled"; }; + + eth: ethernet@40114100 { + compatible = "renesas,ra-ethernet"; + reg = <0x40114100 0xfc>; + interrupts = <51 12>; + local-mac-address = [00 11 22 33 44 55]; + phy-connection-type = "rmii"; + status = "disabled"; + }; + + mdio: mdio { + compatible = "renesas,ra-mdio"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; }; usbfs_phy: usbfs-phy { From 927783996a36ce2071088c38e24d55916617d0a9 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Wed, 5 Feb 2025 18:07:26 +0100 Subject: [PATCH 04/11] boards: add support for Arduino Portenta C33 Tested: * GPIO * UART * USB (using USB_DEVICE_NEXT) * BLE dts to be fixed and completed Signed-off-by: Martino Facchin --- boards/arduino/portenta_c33/CMakeLists.txt | 4 + .../portenta_c33/Kconfig.arduino_portenta_c33 | 5 + boards/arduino/portenta_c33/Kconfig.defconfig | 13 + .../arduino_portenta_c33-pinctrl.dtsi | 152 +++++++++ .../portenta_c33/arduino_portenta_c33.dts | 300 ++++++++++++++++++ .../portenta_c33/arduino_portenta_c33.yaml | 11 + .../arduino_portenta_c33_defconfig | 20 ++ boards/arduino/portenta_c33/board.cmake | 10 + boards/arduino/portenta_c33/board.yml | 6 + boards/arduino/portenta_c33/eth_pwm_clock.c | 42 +++ 10 files changed, 563 insertions(+) create mode 100644 boards/arduino/portenta_c33/CMakeLists.txt create mode 100644 boards/arduino/portenta_c33/Kconfig.arduino_portenta_c33 create mode 100644 boards/arduino/portenta_c33/Kconfig.defconfig create mode 100644 boards/arduino/portenta_c33/arduino_portenta_c33-pinctrl.dtsi create mode 100644 boards/arduino/portenta_c33/arduino_portenta_c33.dts create mode 100644 boards/arduino/portenta_c33/arduino_portenta_c33.yaml create mode 100644 boards/arduino/portenta_c33/arduino_portenta_c33_defconfig create mode 100644 boards/arduino/portenta_c33/board.cmake create mode 100644 boards/arduino/portenta_c33/board.yml create mode 100644 boards/arduino/portenta_c33/eth_pwm_clock.c diff --git a/boards/arduino/portenta_c33/CMakeLists.txt b/boards/arduino/portenta_c33/CMakeLists.txt new file mode 100644 index 0000000000000..973775b8077c1 --- /dev/null +++ b/boards/arduino/portenta_c33/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources_ifdef(CONFIG_NETWORKING eth_pwm_clock.c) diff --git a/boards/arduino/portenta_c33/Kconfig.arduino_portenta_c33 b/boards/arduino/portenta_c33/Kconfig.arduino_portenta_c33 new file mode 100644 index 0000000000000..1db7ac3de08d9 --- /dev/null +++ b/boards/arduino/portenta_c33/Kconfig.arduino_portenta_c33 @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_ARDUINO_PORTENTA_C33 + select SOC_R7FA6M5BH3CFC diff --git a/boards/arduino/portenta_c33/Kconfig.defconfig b/boards/arduino/portenta_c33/Kconfig.defconfig new file mode 100644 index 0000000000000..5c68a2fdc6f3d --- /dev/null +++ b/boards/arduino/portenta_c33/Kconfig.defconfig @@ -0,0 +1,13 @@ +# Copyright 2024 Rahul Arasikere +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_ARDUINO_PORTENTA_C33 + +if NETWORKING + +config NET_L2_ETHERNET + default y + +endif # NETWORKING + +endif # BOARD_ARDUINO_PORTENTA_C33 diff --git a/boards/arduino/portenta_c33/arduino_portenta_c33-pinctrl.dtsi b/boards/arduino/portenta_c33/arduino_portenta_c33-pinctrl.dtsi new file mode 100644 index 0000000000000..a2fa71311c284 --- /dev/null +++ b/boards/arduino/portenta_c33/arduino_portenta_c33-pinctrl.dtsi @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024 Arduino SA + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + sci7_default: sci7_default { + group1 { + /* tx rx */ + psels = , + , + , + ; + }; + }; + + sci9_default: sci9_default { + group1 { + /* tx rx */ + psels = , + , + , + ; + }; + }; + + sci5_default: sci5_default { + group1 { + /* tx rx */ + psels = , + , + , + ; + }; + }; + + sci6_default: sci6_default { + group1 { + /* tx rx */ + psels = , + , + , + ; + }; + }; + + sci8_default: sci8_default { + group1 { + /* tx rx rts cts - BLE */ + psels = , + , + , + ; + }; + }; + + iic1_default: iic1_default { + group1 { + /* SCL1 SDA1 */ + psels = , + ; + drive-strength = "medium"; + }; + }; + + spi1_default: spi1_default { + group1 { + /* MISO MOSI RSPCK SSL0 SSL1 */ + psels = , + , + , + , + ; + }; + }; + + usbhs_default: usbhs_default { + group1 { + psels = ; /* USBHS-VBUS */ + drive-strength = "high"; + }; + }; + + adc0_default: adc0_default { + group1 { + /* input */ + psels = , + , + , + , + , + , + , + ; + renesas,analog-enable; + }; + }; + + ether_default: ether_default { + group1 { + psels = , /* ET0_MDC */ + , /* ET0_MDIO */ + , /* RMII0_TXD_EN_B */ + , /* RMII0_TXD1_BR */ + , /* RMII0_TXD0_B */ + , /* REF50CK0_B */ + , /* RMII0_RXD0_B */ + , /* RMII0_RXD1_B */ + , /* RMII0_RX_ER_B */ + ; /* RMII0_CRS_DV_B */ + drive-strength = "high"; + }; + }; + + pwm1_default: pwm1_default { + group1 { + psels = ; + }; + }; + + pwm3_default: pwm3_default { + group1 { + psels = ; + }; + }; + + pwm4_default: pwm4_default { + group1 { + psels = ; + }; + }; + + pwm6_default: pwm6_default { + group1 { + psels = , + ; + }; + }; + + pwm7_default: pwm7_default { + group1 { + psels = ; + }; + }; + + pwm8_default: pwm8_default { + group1 { + psels = , + ; + }; + }; +}; diff --git a/boards/arduino/portenta_c33/arduino_portenta_c33.dts b/boards/arduino/portenta_c33/arduino_portenta_c33.dts new file mode 100644 index 0000000000000..dd8a73a1fa1a3 --- /dev/null +++ b/boards/arduino/portenta_c33/arduino_portenta_c33.dts @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2025 Arduino SA + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include +#include + +#include "arduino_portenta_c33-pinctrl.dtsi" + +/ { + model = "Arduino Portenta C33"; + compatible = "renesas,ra6m5", "renesas,ra"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash-controller = &flash1; + zephyr,code-partition = &code_partition; + zephyr,flash = &flash0; + zephyr,console = &uart9; + zephyr,shell-uart = &uart9; + zephyr,entropy = &trng; + zephyr,bt-hci = &bt_hci_uart; + }; + + leds { + compatible = "gpio-leds"; + + led1: led1 { + gpios = <&ioport1 7 GPIO_ACTIVE_LOW>; + label = "LEDR"; + }; + + led2: led2 { + gpios = <&ioport4 0 GPIO_ACTIVE_HIGH>; + label = "LEDG"; + }; + + led3: led3 { + gpios = <&ioport8 0 GPIO_ACTIVE_HIGH>; + label = "LEDB"; + }; + }; + + download-esp32 { + compatible = "regulator-fixed"; + regulator-name = "download_esp32"; + enable-gpios = <&ioport8 3 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + + aliases { + led0 = &led1; + }; +}; + +&sci9 { + pinctrl-0 = <&sci9_default>; + pinctrl-names = "default"; + status = "okay"; + + uart9: uart { + current-speed = <115200>; + status = "okay"; + }; +}; + +&sci8 { + pinctrl-0 = <&sci8_default>; + pinctrl-names = "default"; + status = "okay"; + + uart8: uart { + current-speed = <921600>; + status = "okay"; + hw-flow-control; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + + esp32 { + compatible = "renesas,bt-hci-da1453x"; + status = "okay"; + reset-gpios = <&ioport8 4 GPIO_ACTIVE_LOW>; + reset-assert-duration-ms = <100>; + boot-duration-ms = <2000>; + }; + }; + }; +}; + +&option_setting_s { + status = "disabled"; +}; + +&option_setting_sas { + status = "disabled"; +}; + +&option_setting_ofs { + status = "disabled"; +}; + +&iic1 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <91 1>, <92 1>, <93 1>, <94 1>; + interrupt-names = "rxi", "txi", "tei", "eri"; + clock-frequency = ; + pinctrl-0 = <&iic1_default>; + pinctrl-names = "default"; +}; + +&spi1 { + pinctrl-0 = <&spi1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&ioport0 { + status = "okay"; +}; + +&ioport1 { + status = "okay"; +}; + +&ioport2 { + status = "okay"; +}; + +&ioport3 { + status = "okay"; +}; + +&ioport4 { + status = "okay"; +}; + +&ioport5 { + status = "okay"; +}; + +&ioport6 { + status = "okay"; +}; + +&ioport7 { + status = "okay"; +}; + +&ioport8 { + status = "okay"; +}; + +&ioport9 { + status = "okay"; +}; + +&ioporta { + status = "okay"; +}; + +&ioportb { + status = "okay"; +}; + +&xtal { + clock-frequency = ; + mosel = <0>; + #clock-cells = <0>; + status = "okay"; +}; + +&subclk { + status = "okay"; +}; + +&pll { + clocks = <&xtal>; + div = <3>; + mul = <25 0>; + status = "okay"; +}; + +&usbhs { + pinctrl-0 = <&usbhs_default>; + pinctrl-names = "default"; + maximum-speed = "high-speed"; + status = "okay"; + + zephyr_udc0: udc { + status = "okay"; + }; +}; + +&usbhs_phy { + phys-clock-src = "xtal"; +}; + +&adc0 { + status = "okay"; + pinctrl-0 = <&adc0_default>; + pinctrl-names = "default"; +}; + +&port_irq9 { + interrupts = <41 12>; + status = "okay"; +}; + +&port_irq10 { + interrupts = <42 12>; + status = "okay"; +}; + +&pwm1 { + pinctrl-0 = <&pwm1_default>; + pinctrl-names = "default"; + interrupts = <63 1>, <64 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; +}; + +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + read-only; + }; + + code_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 (DT_SIZE_M(2) - DT_SIZE_K(64))>; + }; + }; +}; + +&flash1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0X0 DT_SIZE_K(8)>; + }; + }; +}; + +&trng { + status = "okay"; +}; + +ð { + local-mac-address = [74 90 50 B0 5D E9]; + status = "okay"; + phy-handle = <&phy>; +}; + +&mdio { + pinctrl-0 = <ðer_default>; + pinctrl-names = "default"; + status = "okay"; + + phy: ethernet-phy@0 { + compatible = "ethernet-phy"; + reg = <0>; + status = "okay"; + }; +}; + +&pwm6 { + pinctrl-0 = <&pwm6_default>; + pinctrl-names = "default"; + interrupts = <63 1>, <64 1>; + interrupt-names = "gtioca", "overflow"; + status = "okay"; + + pwmclock: pwmclock { + status = "okay"; + compatible = "pwm-clock"; + clock-frequency = <25000000>; + #clock-cells = <1>; + pwms = <&pwm6 1 PWM_HZ(25000000) PWM_POLARITY_NORMAL>; + }; +}; diff --git a/boards/arduino/portenta_c33/arduino_portenta_c33.yaml b/boards/arduino/portenta_c33/arduino_portenta_c33.yaml new file mode 100644 index 0000000000000..29764cfcd4d11 --- /dev/null +++ b/boards/arduino/portenta_c33/arduino_portenta_c33.yaml @@ -0,0 +1,11 @@ +identifier: portenta_c33 +name: Arduino Portenta C33 +type: mcu +arch: arm +ram: 512 +flash: 2048 +toolchain: + - zephyr + - gnuarmemb +supported: + - gpio diff --git a/boards/arduino/portenta_c33/arduino_portenta_c33_defconfig b/boards/arduino/portenta_c33/arduino_portenta_c33_defconfig new file mode 100644 index 0000000000000..11b6a78abebd9 --- /dev/null +++ b/boards/arduino/portenta_c33/arduino_portenta_c33_defconfig @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=200000000 + +CONFIG_GPIO=y + +CONFIG_BUILD_OUTPUT_BIN=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_CLOCK_CONTROL=y + +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_CONSOLE=y + +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_DYNAMIC_INTERRUPTS=y + +CONFIG_REGULATOR=y diff --git a/boards/arduino/portenta_c33/board.cmake b/boards/arduino/portenta_c33/board.cmake new file mode 100644 index 0000000000000..3375cade093f8 --- /dev/null +++ b/boards/arduino/portenta_c33/board.cmake @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + + +# FIXME: Arduino dfu-util provides -Q to reset the board after flashing +board_runner_args(dfu-util "--pid=2341:0368" "--alt=0") +board_runner_args(jlink "--device=R7FA6M5BH") + +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/boards/arduino/portenta_c33/board.yml b/boards/arduino/portenta_c33/board.yml new file mode 100644 index 0000000000000..111e046ca645f --- /dev/null +++ b/boards/arduino/portenta_c33/board.yml @@ -0,0 +1,6 @@ +board: + name: arduino_portenta_c33 + full_name: Arduino Portenta C33 + vendor: arduino + socs: + - name: r7fa6m5bh3cfc diff --git a/boards/arduino/portenta_c33/eth_pwm_clock.c b/boards/arduino/portenta_c33/eth_pwm_clock.c new file mode 100644 index 0000000000000..1bf4f6c422901 --- /dev/null +++ b/boards/arduino/portenta_c33/eth_pwm_clock.c @@ -0,0 +1,42 @@ +/* + * Copyright 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(eth_pwm_clock, CONFIG_CLOCK_CONTROL_LOG_LEVEL); + +int eth_pwm_clock_enable(void) +{ + int ret; + uint32_t rate; + const struct device *eth_pwm_clk_dev = DEVICE_DT_GET(DT_NODELABEL(pwmclock)); + + if (!device_is_ready(eth_pwm_clk_dev)) { + LOG_ERR("Camera external clock source device is not ready!"); + return -ENODEV; + } + + ret = clock_control_on(eth_pwm_clk_dev, (clock_control_subsys_t)0); + if (ret < 0) { + LOG_ERR("Failed to enable camera external clock error: (%d)", ret); + return ret; + } + + ret = clock_control_get_rate(eth_pwm_clk_dev, (clock_control_subsys_t)0, &rate); + if (ret < 0) { + LOG_ERR("Failed to get camera external clock rate, error: (%d)", ret); + return ret; + } + + LOG_INF("Camera external clock rate: (%u) Hz", rate); + + return 0; +} + +SYS_INIT(eth_pwm_clock_enable, POST_KERNEL, CONFIG_CLOCK_CONTROL_PWM_INIT_PRIORITY); From 3333795ebe8b2b71f7f291d68c131a99a68a2d2a Mon Sep 17 00:00:00 2001 From: Ibrahim Abdalkader Date: Tue, 11 Feb 2025 09:45:02 +0100 Subject: [PATCH 05/11] drivers: display: Add Sitronix ST7701 driver. Display driver for Sitronix ST7701. Signed-off-by: Ibrahim Abdalkader --- drivers/display/CMakeLists.txt | 1 + drivers/display/Kconfig | 1 + drivers/display/Kconfig.st7701 | 20 + drivers/display/display_st7701.c | 449 ++++++++++++++++++++++ drivers/display/display_st7701.h | 65 ++++ dts/bindings/display/sitronix,st7701.yaml | 88 +++++ 6 files changed, 624 insertions(+) create mode 100644 drivers/display/Kconfig.st7701 create mode 100644 drivers/display/display_st7701.c create mode 100644 drivers/display/display_st7701.h create mode 100644 dts/bindings/display/sitronix,st7701.yaml diff --git a/drivers/display/CMakeLists.txt b/drivers/display/CMakeLists.txt index 7071303dfb6fe..5123faeafd085 100644 --- a/drivers/display/CMakeLists.txt +++ b/drivers/display/CMakeLists.txt @@ -34,6 +34,7 @@ zephyr_library_sources_ifdef(CONFIG_DISPLAY_RENESAS_LCDC display_renesas_lcdc.c) zephyr_library_sources_ifdef(CONFIG_NT35510 display_nt35510.c) zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_GLCDC display_renesas_ra.c) zephyr_library_sources_ifdef(CONFIG_ILI9806E_DSI display_ili9806e_dsi.c) +zephyr_library_sources_ifdef(CONFIG_ST7701 display_st7701.c) zephyr_library_sources_ifdef(CONFIG_MICROBIT_DISPLAY mb_display.c diff --git a/drivers/display/Kconfig b/drivers/display/Kconfig index 13206b8a63c78..08de8a09ce532 100644 --- a/drivers/display/Kconfig +++ b/drivers/display/Kconfig @@ -51,5 +51,6 @@ source "drivers/display/Kconfig.renesas_lcdc" source "drivers/display/Kconfig.nt35510" source "drivers/display/Kconfig.renesas_ra" source "drivers/display/Kconfig.ili9806e_dsi" +source "drivers/display/Kconfig.st7701" endif # DISPLAY diff --git a/drivers/display/Kconfig.st7701 b/drivers/display/Kconfig.st7701 new file mode 100644 index 0000000000000..10752b70d65d4 --- /dev/null +++ b/drivers/display/Kconfig.st7701 @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config ST7701 + bool "ST7701 display driver" + default y + depends on DT_HAS_SITRONIX_ST7701_ENABLED + select MIPI_DSI + help + Enable driver for ST7701 display driver. + +if ST7701 + +config DISPLAY_ST7701_INIT_PRIORITY + int "Initialization priority" + default DISPLAY_INIT_PRIORITY + help + ST7701 display driver initialization priority. + +endif diff --git a/drivers/display/display_st7701.c b/drivers/display/display_st7701.c new file mode 100644 index 0000000000000..cc53f00fa9b12 --- /dev/null +++ b/drivers/display/display_st7701.c @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT sitronix_st7701 + +#include +#include +#include +#include +#include +#include +#include "display_st7701.h" + +LOG_MODULE_REGISTER(st7701, CONFIG_DISPLAY_LOG_LEVEL); + +struct st7701_config { + const struct device *mipi_dsi; + const struct gpio_dt_spec reset; + const struct gpio_dt_spec backlight; + uint8_t data_lanes; + uint16_t width; + uint16_t height; + uint8_t channel; + uint16_t rotation; + uint32_t hbp; + uint32_t hsync; + uint32_t hfp; + uint32_t vbp; + uint32_t vsync; + uint32_t vfp; + uint8_t gip_e0[4]; + uint8_t gip_e1[12]; + uint8_t gip_e2[14]; + uint8_t gip_e3[5]; + uint8_t gip_e4[3]; + uint8_t gip_e5[17]; + uint8_t gip_e6[5]; + uint8_t gip_e7[3]; + uint8_t gip_e8[17]; + uint8_t gip_eb[8]; + uint8_t gip_ec[3]; + uint8_t gip_ed[17]; + uint8_t pvgamctrl[17]; + uint8_t nvgamctrl[17]; +}; + +struct st7701_data { + uint16_t xres; + uint16_t yres; + uint8_t dsi_pixel_format; + enum display_pixel_format pixel_format; + enum display_orientation orientation; +}; + +static inline int st7701_dcs_write(const struct device *dev, uint8_t cmd, const void *buf, + size_t len) +{ + const struct st7701_config *cfg = dev->config; + int ret; + + ret = mipi_dsi_dcs_write(cfg->mipi_dsi, cfg->channel, cmd, buf, len); + if (ret < 0) { + LOG_ERR("DCS 0x%x write failed! (%d)", cmd, ret); + return ret; + } + + return 0; +} + +static int st7701_short_write_1p(const struct device *dev, uint8_t cmd, uint8_t val) +{ + const struct st7701_config *cfg = dev->config; + int ret; + uint8_t buf[] = {cmd, val}; + + ret = mipi_dsi_generic_write(cfg->mipi_dsi, cfg->channel, buf, sizeof(val)); + if (ret < 0) { + LOG_ERR("Short write failed! (%d)", ret); + return ret; + } + + return 0; +} + +static int st7701_generic_write(const struct device *dev, const void *buf, size_t len) +{ + const struct st7701_config *cfg = dev->config; + int ret; + + ret = mipi_dsi_generic_write(cfg->mipi_dsi, cfg->channel, buf, len); + if (ret < 0) { + LOG_ERR("Generic write failed! (%d)", ret); + return ret; + } + + return 0; +} + +static int st7701_check_id(const struct device *dev) +{ + const struct st7701_config *cfg = dev->config; + uint32_t id = 0; + int ret; + + ret = mipi_dsi_dcs_read(cfg->mipi_dsi, cfg->channel, ST7701_CMD_ID1, &id, sizeof(id)); + if (ret != sizeof(id)) { + LOG_ERR("Read panel ID failed! (%d)", ret); + return -EIO; + } + + if (id != ST7701_ID) { + LOG_ERR("ID 0x%x (should 0x%x)", id, ST7701_ID); + return -EINVAL; + } + + return 0; +} + +static int st7701_configure(const struct device *dev) +{ + struct st7701_data *data = dev->data; + const struct st7701_config *cfg = dev->config; + uint8_t buf[4]; + int ret; + + const uint8_t control0[] = {DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK0_SEL}; + const uint8_t control1[] = {0xC0, 0x63, 0x00}; + const uint8_t control2[] = {0xC1, 0x11, 0x02}; + const uint8_t control3[] = {0xC2, 0x01, 0x08}; + const uint8_t control4[] = {0xCC, 0x18}; + + st7701_generic_write(dev, control0, sizeof(control0)); + st7701_generic_write(dev, control1, sizeof(control1)); + st7701_generic_write(dev, control2, sizeof(control2)); + st7701_generic_write(dev, control3, sizeof(control3)); + st7701_generic_write(dev, control4, sizeof(control4)); + + /* Gamma Cluster Setting */ + st7701_generic_write(dev, cfg->pvgamctrl, sizeof(cfg->pvgamctrl)); + st7701_generic_write(dev, cfg->nvgamctrl, sizeof(cfg->nvgamctrl)); + + /* Initial power control registers */ + const uint8_t _FF1[] = {DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BK1_SEL}; + + st7701_generic_write(dev, _FF1, sizeof(_FF1)); + + st7701_short_write_1p(dev, DSI_CMD2_BK1_VRHS, 0x65); + st7701_short_write_1p(dev, DSI_CMD2_BK1_VCOM, 0x34); + st7701_short_write_1p(dev, DSI_CMD2_BK1_VGHSS, 0x87); + st7701_short_write_1p(dev, DSI_CMD2_BK1_TESTCMD, 0x80); + + st7701_short_write_1p(dev, DSI_CMD2_BK1_VGLS, 0x49); + st7701_short_write_1p(dev, DSI_CMD2_BK1_PWCTLR1, 0x85); + + st7701_short_write_1p(dev, DSI_CMD2_BK1_PWCTLR2, 0x20); + st7701_short_write_1p(dev, 0xB9, 0x10); + st7701_short_write_1p(dev, DSI_CMD2_BK1_SPD1, 0x78); + st7701_short_write_1p(dev, DSI_CMD2_BK1_SPD2, 0x78); + st7701_short_write_1p(dev, DSI_CMD2_BK1_MIPISET1, 0x88); + k_msleep(100); + + /* GIP Setting */ + st7701_generic_write(dev, cfg->gip_e0, sizeof(cfg->gip_e0)); + st7701_generic_write(dev, cfg->gip_e1, sizeof(cfg->gip_e1)); + st7701_generic_write(dev, cfg->gip_e2, sizeof(cfg->gip_e2)); + st7701_generic_write(dev, cfg->gip_e3, sizeof(cfg->gip_e3)); + st7701_generic_write(dev, cfg->gip_e4, sizeof(cfg->gip_e4)); + st7701_generic_write(dev, cfg->gip_e5, sizeof(cfg->gip_e5)); + st7701_generic_write(dev, cfg->gip_e6, sizeof(cfg->gip_e6)); + st7701_generic_write(dev, cfg->gip_e7, sizeof(cfg->gip_e7)); + st7701_generic_write(dev, cfg->gip_e8, sizeof(cfg->gip_e8)); + st7701_generic_write(dev, cfg->gip_eb, sizeof(cfg->gip_eb)); + st7701_generic_write(dev, cfg->gip_ec, sizeof(cfg->gip_ec)); + st7701_generic_write(dev, cfg->gip_ed, sizeof(cfg->gip_ed)); + + /* Bank1 setting */ + const uint8_t _FF2[] = {DSI_CMD2BKX_SEL, 0x77, 0x01, 0x00, 0x00, DSI_CMD2BKX_SEL_NONE}; + + st7701_generic_write(dev, _FF2, sizeof(_FF2)); + + /* Exit sleep mode */ + ret = st7701_dcs_write(dev, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); + if (ret < 0) { + return ret; + } + + k_msleep(50); + + /* Set pixel color format */ + switch (data->dsi_pixel_format) { + case MIPI_DSI_PIXFMT_RGB565: + buf[0] = MIPI_DCS_PIXEL_FORMAT_16BIT; + break; + case MIPI_DSI_PIXFMT_RGB888: + buf[0] = MIPI_DCS_PIXEL_FORMAT_24BIT; + break; + default: + LOG_ERR("Unsupported pixel format 0x%x!", data->dsi_pixel_format); + return -ENOTSUP; + } + + ret = st7701_dcs_write(dev, MIPI_DCS_SET_PIXEL_FORMAT, buf, 1); + if (ret < 0) { + return ret; + } + + buf[0] = 0x00; + buf[1] = 0x00; + sys_put_be16(data->xres, (uint8_t *)&buf[2]); + ret = st7701_dcs_write(dev, MIPI_DCS_SET_COLUMN_ADDRESS, buf, 4); + if (ret < 0) { + return ret; + } + + buf[0] = 0x00; + buf[1] = 0x00; + sys_put_be16(data->yres, (uint8_t *)&buf[2]); + ret = st7701_dcs_write(dev, MIPI_DCS_SET_PAGE_ADDRESS, buf, 4); + if (ret < 0) { + return ret; + } + + /* Backlight control */ + buf[0] = ST7701_WRCTRLD_BCTRL | ST7701_WRCTRLD_DD | ST7701_WRCTRLD_BL; + ret = st7701_dcs_write(dev, MIPI_DCS_WRITE_CONTROL_DISPLAY, buf, 1); + if (ret < 0) { + return ret; + } + + /* Adaptive brightness control */ + buf[0] = ST7701_WRCABC_UI; + ret = st7701_dcs_write(dev, MIPI_DCS_WRITE_POWER_SAVE, buf, 1); + if (ret < 0) { + return ret; + } + + /* Adaptive brightness control minimum brightness */ + buf[0] = 0xFF; + ret = st7701_dcs_write(dev, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, buf, 1); + if (ret < 0) { + return ret; + } + + /* Brightness */ + buf[0] = 0xFF; + ret = st7701_dcs_write(dev, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, buf, 1); + if (ret < 0) { + return ret; + } + + /* Display On */ + ret = st7701_dcs_write(dev, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int st7701_blanking_on(const struct device *dev) +{ + const struct st7701_config *cfg = dev->config; + int ret; + + if (cfg->backlight.port != NULL) { + ret = gpio_pin_set_dt(&cfg->backlight, 0); + if (ret) { + LOG_ERR("Disable backlight failed! (%d)", ret); + return ret; + } + } + + return st7701_dcs_write(dev, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); +} + +static int st7701_blanking_off(const struct device *dev) +{ + const struct st7701_config *cfg = dev->config; + int ret; + + if (cfg->backlight.port != NULL) { + ret = gpio_pin_set_dt(&cfg->backlight, 1); + if (ret) { + LOG_ERR("Enable backlight failed! (%d)", ret); + return ret; + } + } + + return st7701_dcs_write(dev, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); +} + +static int st7701_set_brightness(const struct device *dev, uint8_t brightness) +{ + return st7701_dcs_write(dev, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, &brightness, 1); +} + +static void st7701_get_capabilities(const struct device *dev, + struct display_capabilities *capabilities) +{ + const struct st7701_config *cfg = dev->config; + struct st7701_data *data = dev->data; + + if (!capabilities) { + return; + } + + memset(capabilities, 0, sizeof(struct display_capabilities)); + capabilities->x_resolution = cfg->width; + capabilities->y_resolution = cfg->height; + capabilities->supported_pixel_formats = data->pixel_format; + capabilities->current_pixel_format = data->pixel_format; + capabilities->current_orientation = data->orientation; +} + +static DEVICE_API(display, st7701_api) = { + .blanking_on = st7701_blanking_on, + .blanking_off = st7701_blanking_off, + .set_brightness = st7701_set_brightness, + .get_capabilities = st7701_get_capabilities, +}; + +static int st7701_init(const struct device *dev) +{ + const struct st7701_config *cfg = dev->config; + struct st7701_data *data = dev->data; + struct mipi_dsi_device mdev; + int ret; + + if (cfg->reset.port) { + if (!gpio_is_ready_dt(&cfg->reset)) { + LOG_ERR("Reset GPIO device is not ready!"); + return -ENODEV; + } + ret = gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_INACTIVE); + if (ret < 0) { + LOG_ERR("Reset display failed! (%d)", ret); + return ret; + } + k_msleep(10); + ret = gpio_pin_set_dt(&cfg->reset, 1); + if (ret < 0) { + LOG_ERR("Enable display failed! (%d)", ret); + return ret; + } + k_msleep(100); + } + + /* store x/y resolution & rotation */ + if (cfg->rotation == 0) { + data->xres = cfg->width; + data->yres = cfg->height; + data->orientation = DISPLAY_ORIENTATION_NORMAL; + } else if (cfg->rotation == 90) { + data->xres = cfg->height; + data->yres = cfg->width; + data->orientation = DISPLAY_ORIENTATION_ROTATED_90; + } else if (cfg->rotation == 180) { + data->xres = cfg->width; + data->yres = cfg->height; + data->orientation = DISPLAY_ORIENTATION_ROTATED_180; + } else if (cfg->rotation == 270) { + data->xres = cfg->height; + data->yres = cfg->width; + data->orientation = DISPLAY_ORIENTATION_ROTATED_270; + } + + /* attach to MIPI-DSI host */ + mdev.data_lanes = cfg->data_lanes; + mdev.pixfmt = data->dsi_pixel_format; + mdev.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM; + + mdev.timings.hactive = cfg->width; + mdev.timings.hbp = cfg->hbp; + mdev.timings.hsync = cfg->hsync; + mdev.timings.hfp = cfg->hfp; + mdev.timings.vactive = cfg->height; + mdev.timings.vbp = cfg->vbp; + mdev.timings.vsync = cfg->vsync; + mdev.timings.vfp = cfg->vfp; + + ret = mipi_dsi_attach(cfg->mipi_dsi, cfg->channel, &mdev); + if (ret < 0) { + LOG_ERR("MIPI-DSI attach failed! (%d)", ret); + return ret; + } + + ret = st7701_check_id(dev); + if (ret) { + LOG_ERR("Panel ID check failed! (%d)", ret); + return ret; + } + + ret = st7701_configure(dev); + if (ret) { + LOG_ERR("DSI init sequence failed! (%d)", ret); + return ret; + } + + ret = st7701_blanking_off(dev); + if (ret) { + LOG_ERR("Display blanking off failed! (%d)", ret); + return ret; + } + + return 0; +} + +#define ST7701_DEVICE(inst) \ + static const struct st7701_config st7701_config_##inst = { \ + .mipi_dsi = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \ + .backlight = GPIO_DT_SPEC_INST_GET_OR(inst, bl_gpios, {0}), \ + .data_lanes = DT_INST_PROP_BY_IDX(inst, data_lanes, 0), \ + .width = DT_INST_PROP(inst, width), \ + .height = DT_INST_PROP(inst, height), \ + .channel = DT_INST_REG_ADDR(inst), \ + .rotation = DT_INST_PROP(inst, rotation), \ + .hbp = DT_PROP(DT_INST_CHILD(inst, display_timings), hback_porch), \ + .hsync = DT_PROP(DT_INST_CHILD(inst, display_timings), hsync_len), \ + .hfp = DT_PROP(DT_INST_CHILD(inst, display_timings), hfront_porch), \ + .vbp = DT_PROP(DT_INST_CHILD(inst, display_timings), vback_porch), \ + .vsync = DT_PROP(DT_INST_CHILD(inst, display_timings), vsync_len), \ + .vfp = DT_PROP(DT_INST_CHILD(inst, display_timings), vfront_porch), \ + .gip_e0 = DT_INST_PROP_OR(inst, gip_e0, {}), \ + .gip_e1 = DT_INST_PROP_OR(inst, gip_e1, {}), \ + .gip_e2 = DT_INST_PROP_OR(inst, gip_e2, {}), \ + .gip_e3 = DT_INST_PROP_OR(inst, gip_e3, {}), \ + .gip_e4 = DT_INST_PROP_OR(inst, gip_e4, {}), \ + .gip_e5 = DT_INST_PROP_OR(inst, gip_e5, {}), \ + .gip_e6 = DT_INST_PROP_OR(inst, gip_e6, {}), \ + .gip_e7 = DT_INST_PROP_OR(inst, gip_e7, {}), \ + .gip_e8 = DT_INST_PROP_OR(inst, gip_e8, {}), \ + .gip_eb = DT_INST_PROP_OR(inst, gip_eb, {}), \ + .gip_ec = DT_INST_PROP_OR(inst, gip_ec, {}), \ + .gip_ed = DT_INST_PROP_OR(inst, gip_ed, {}), \ + .pvgamctrl = DT_INST_PROP_OR(inst, pvgamctrl, {}), \ + .nvgamctrl = DT_INST_PROP_OR(inst, nvgamctrl, {}), \ + }; \ + static struct st7701_data st7701_data_##inst = { \ + .dsi_pixel_format = DT_INST_PROP(inst, pixel_format), \ + }; \ + DEVICE_DT_INST_DEFINE(inst, &st7701_init, NULL, &st7701_data_##inst, \ + &st7701_config_##inst, POST_KERNEL, \ + CONFIG_DISPLAY_ST7701_INIT_PRIORITY, &st7701_api); + +DT_INST_FOREACH_STATUS_OKAY(ST7701_DEVICE) diff --git a/drivers/display/display_st7701.h b/drivers/display/display_st7701.h new file mode 100644 index 0000000000000..3a910456b75a4 --- /dev/null +++ b/drivers/display/display_st7701.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ST7701_H_ +#define ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ST7701_H_ + +/** + * @name General parameters. + * @{ + */ + +/* Command2 BKx selection command */ +#define DSI_CMD2BKX_SEL 0xFF +#define DSI_CMD2BK1_SEL 0x11 +#define DSI_CMD2BK0_SEL 0x10 +#define DSI_CMD2BKX_SEL_NONE 0x00 + +/* Command2, BK0 commands */ +#define DSI_CMD2_BK0_PVGAMCTRL 0xB0 /* Positive Voltage Gamma Control */ +#define DSI_CMD2_BK0_NVGAMCTRL 0xB1 /* Negative Voltage Gamma Control */ +#define DSI_CMD2_BK0_LNESET 0xC0 /* Display Line setting */ +#define DSI_CMD2_BK0_PORCTRL 0xC1 /* Porch control */ +#define DSI_CMD2_BK0_INVSEL 0xC2 /* Inversion selection, Frame Rate Control */ + +/* Command2, BK1 commands */ +#define DSI_CMD2_BK1_VRHS 0xB0 /* Vop amplitude setting */ +#define DSI_CMD2_BK1_VCOM 0xB1 /* VCOM amplitude setting */ +#define DSI_CMD2_BK1_VGHSS 0xB2 /* VGH Voltage setting */ +#define DSI_CMD2_BK1_TESTCMD 0xB3 /* TEST Command Setting */ +#define DSI_CMD2_BK1_VGLS 0xB5 /* VGL Voltage setting */ +#define DSI_CMD2_BK1_PWCTLR1 0xB7 /* Power Control 1 */ +#define DSI_CMD2_BK1_PWCTLR2 0xB8 /* Power Control 2 */ +#define DSI_CMD2_BK1_SPD1 0xC1 /* Source pre_drive timing set1 */ +#define DSI_CMD2_BK1_SPD2 0xC2 /* Source EQ2 Setting */ +#define DSI_CMD2_BK1_MIPISET1 0xD0 /* MIPI Setting 1 */ + +#define ST7701_CMD_ID1 0xDA +#define ST7701_ID 0xFF + +/** + * @name MIPI DCS Write Control Display fields. + * @{ + */ + +/** Write Control Display: brightness control. */ +#define ST7701_WRCTRLD_BCTRL BIT(5) +/** Write Control Display: display dimming. */ +#define ST7701_WRCTRLD_DD BIT(3) +/** Write Control Display: backlight. */ +#define ST7701_WRCTRLD_BL BIT(2) + +/** Adaptive Brightness Control: off. */ +#define ST7701_WRCABC_OFF 0x00U +/** Adaptibe Brightness Control: user interface. */ +#define ST7701_WRCABC_UI 0x01U +/** Adaptibe Brightness Control: still picture. */ +#define ST7701_WRCABC_ST 0x02U +/** Adaptibe Brightness Control: moving image. */ +#define ST7701_WRCABC_MV 0x03U +/** @} */ + +#endif /* ZEPHYR_DRIVERS_DISPLAY_DISPLAY_ST7701_H_ */ diff --git a/dts/bindings/display/sitronix,st7701.yaml b/dts/bindings/display/sitronix,st7701.yaml new file mode 100644 index 0000000000000..d17aff0dcf409 --- /dev/null +++ b/dts/bindings/display/sitronix,st7701.yaml @@ -0,0 +1,88 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +description: Sitronix ST7701 Panel + +compatible: "sitronix,st7701" + +include: [mipi-dsi-device.yaml, display-controller.yaml] + +properties: + reset-gpios: + type: phandle-array + description: | + The RESETn pin is asserted to disable the sensor causing a hard + reset. The sensor receives this as an active-low signal. + + bl-gpios: + type: phandle-array + description: | + The BLn pin is asserted to control the backlight of the panel. + The sensor receives this as an active-high signal. + + rotation: + type: int + default: 0 + enum: + - 0 + - 90 + - 180 + - 270 + description: | + Display rotation (CW) in degrees. Defaults to 0, display default. + + gip-e0: + type: uint8-array + description: GIP setting at address 0xE0. + + gip-e1: + type: uint8-array + description: GIP setting at address 0xE1. + + gip-e2: + type: uint8-array + description: GIP setting at address 0xE2. + + gip-e3: + type: uint8-array + description: GIP setting at address 0xE3. + + gip-e4: + type: uint8-array + description: GIP setting at address 0xE4. + + gip-e5: + type: uint8-array + description: GIP setting at address 0xE5. + + gip-e6: + type: uint8-array + description: GIP setting at address 0xE6. + + gip-e7: + type: uint8-array + description: GIP setting at address 0xE7. + + gip-e8: + type: uint8-array + description: GIP setting at address 0xE8. + + gip-eb: + type: uint8-array + description: GIP setting at address 0xEB. + + gip-ec: + type: uint8-array + description: GIP setting at address 0xEC. + + gip-ed: + type: uint8-array + description: GIP setting at address 0xED. + + pvgamctrl: + type: uint8-array + description: Positive voltage gamma control. + + nvgamctrl: + type: uint8-array + description: Negative voltage gamma control. From 2f3e52eb6a2be32224d8cc67fc52c874f2052cf4 Mon Sep 17 00:00:00 2001 From: Ibrahim Abdalkader Date: Thu, 13 Feb 2025 09:26:48 +0100 Subject: [PATCH 06/11] tests: drivers: Add ST7701 test. Add a test for ST7701 display driver. Signed-off-by: Ibrahim Abdalkader --- tests/drivers/build_all/display/app.overlay | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/drivers/build_all/display/app.overlay b/tests/drivers/build_all/display/app.overlay index 1ea1ce4b34d8a..e41973d3c6b3a 100644 --- a/tests/drivers/build_all/display/app.overlay +++ b/tests/drivers/build_all/display/app.overlay @@ -249,6 +249,31 @@ height = <1280>; pixel-format = <0>; }; + + test_st7701: st7701@5 { + compatible = "sitronix,st7701"; + reg = <0x5>; + height = <800>; + width = <480>; + data-lanes = <2>; + pixel-format = <0>; + rotation = <0>; + pvgamctrl = [00 10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10]; + nvgamctrl = [00 10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10]; + display-timings { + compatible = "zephyr,panel-timing"; + hsync-active = <1>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + hback-porch = <40>; + hsync-len = <32>; + hfront-porch = <8>; + vback-porch = <6>; + vsync-len = <8>; + vfront-porch = <9>; + }; + }; }; test_spi: spi@33334444 { From 7313c9e74364aa97e9bf1b8ae2ae163dbe441247 Mon Sep 17 00:00:00 2001 From: Ibrahim Abdalkader Date: Tue, 11 Feb 2025 11:04:52 +0100 Subject: [PATCH 07/11] boards: arduino: giga_r1: Add aliases for the display shield. Aliases used by the Giga display shield. Signed-off-by: Ibrahim Abdalkader --- boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts index 5d6e0dd7d883c..7505ba0f2df7a 100644 --- a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts +++ b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts @@ -252,3 +252,9 @@ zephyr_udc0: &usbotg_fs { pinctrl-0 = <&usb_otg_fs_dm_pa11 &usb_otg_fs_dp_pa12>; pinctrl-names = "default"; }; + +/* alias used by display shields */ +zephyr_mipi_dsi: &mipi_dsi {}; + +/* alias used by LCD display shields */ +zephyr_lcd_controller: <dc {}; From 541a5c76cfd34258518fe846409520f0a0a4891d Mon Sep 17 00:00:00 2001 From: Ibrahim Abdalkader Date: Tue, 11 Feb 2025 11:06:47 +0100 Subject: [PATCH 08/11] boards: shields: Add Arduino Giga display shield. Add board support for the Arduino Giga display shield. Signed-off-by: Ibrahim Abdalkader --- .../giga_display_shield/Kconfig.defconfig | 37 +++++++ .../giga_display_shield/Kconfig.shield | 5 + .../boards/arduino_giga_r1_m7.conf | 9 ++ .../boards/arduino_giga_r1_m7.overlay | 96 +++++++++++++++++++ .../giga_display_shield.overlay | 47 +++++++++ 5 files changed, 194 insertions(+) create mode 100644 boards/shields/giga_display_shield/Kconfig.defconfig create mode 100644 boards/shields/giga_display_shield/Kconfig.shield create mode 100644 boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.conf create mode 100644 boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.overlay create mode 100644 boards/shields/giga_display_shield/giga_display_shield.overlay diff --git a/boards/shields/giga_display_shield/Kconfig.defconfig b/boards/shields/giga_display_shield/Kconfig.defconfig new file mode 100644 index 0000000000000..03eff24537300 --- /dev/null +++ b/boards/shields/giga_display_shield/Kconfig.defconfig @@ -0,0 +1,37 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +if SHIELD_ARDUINO_GIGA_DISPLAY_SHIELD + +# Double frame buffer maintained by lvgl. +if LVGL + +config STM32_LTDC_FB_NUM + default 0 + +config INPUT + default y + +config LV_Z_DOUBLE_VDB + default y + +config LV_Z_FULL_REFRESH + default y + +config LV_Z_BITS_PER_PIXEL + default 16 + +config LV_DPI_DEF + default 128 + +config LV_Z_FLUSH_THREAD + default y + +choice LV_COLOR_DEPTH + default LV_COLOR_DEPTH_16 + +endchoice + +endif # LVGL + +endif # SHIELD_ARDUINO_GIGA_DISPLAY_SHIELD diff --git a/boards/shields/giga_display_shield/Kconfig.shield b/boards/shields/giga_display_shield/Kconfig.shield new file mode 100644 index 0000000000000..16714a397c941 --- /dev/null +++ b/boards/shields/giga_display_shield/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_ARDUINO_GIGA_DISPLAY_SHIELD + def_bool $(shields_list_contains,arduino_giga_display_shield) diff --git a/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.conf b/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.conf new file mode 100644 index 0000000000000..31d6841989807 --- /dev/null +++ b/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_MEMC=y +CONFIG_STM32_LTDC_RGB565=y +CONFIG_HEAP_MEM_POOL_SIZE=65536 +CONFIG_DISPLAY_ST7701_INIT_PRIORITY=87 +CONFIG_STM32_LTDC_DISABLE_FMC_BANK1=y +CONFIG_INPUT_GT911_INTERRUPT=y diff --git a/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.overlay b/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.overlay new file mode 100644 index 0000000000000..72fe8031f71f1 --- /dev/null +++ b/boards/shields/giga_display_shield/boards/arduino_giga_r1_m7.overlay @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <>911>; + }; + + aliases { + accel0 = >911; + }; + + chosen { + zephyr,display = &zephyr_lcd_controller; + zephyr,touch = >911; + }; +}; + +&sdram1 { + /* Frame buffer memory cache will cause screen flickering. */ + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; +}; + +&zephyr_lcd_controller { + status = "okay"; + ext-sdram = <&sdram1>; + width = <480>; + height = <800>; + def-back-color-red = <0>; + def-back-color-green = <0>; + def-back-color-blue = <0>; + pixel-format = ; + + disp-on-gpios = <&gpioc 6 GPIO_ACTIVE_HIGH>; + bl-ctrl-gpios = <&gpiob 12 GPIO_ACTIVE_HIGH>; + + /* sitronix, st7701 */ + display-timings { + compatible = "zephyr,panel-timing"; + hsync-active = <1>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + hback-porch = <40>; + hsync-len = <32>; + hfront-porch = <8>; + vback-porch = <6>; + vsync-len = <8>; + vfront-porch = <9>; + }; +}; + +/* ltdc uses pll3_r as pixel clock */ +&pll3 { + status = "okay"; + clocks = <&clk_hse>; + div-m = <16>; + mul-n = <110>; + div-p = <2>; + div-q = <2>; + div-r = <4>; /* 27.5 MHz */ +}; + +&zephyr_mipi_dsi { + status = "okay"; + + pll-ndiv = <125>; + pll-idf = <4>; + pll-odf = <0>; + + de-active-high; + largest-packet-size = <0>; + + phy-timings = <35 35 35 35 0 10>; +}; + +&i2c4 { + pinctrl-0 = <&i2c4_scl_pb6 &i2c4_sda_ph12>; + pinctrl-names = "default"; + clock-frequency = ; + status = "okay"; + + gt911: gt911@5d { + compatible = "goodix,gt911"; + reg = <0x5d>; + alt-addr = <0x14>; + reset-gpios = <&gpioi 2 GPIO_ACTIVE_LOW>; + irq-gpios = <&gpioi 1 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/boards/shields/giga_display_shield/giga_display_shield.overlay b/boards/shields/giga_display_shield/giga_display_shield.overlay new file mode 100644 index 0000000000000..5da125332dbd7 --- /dev/null +++ b/boards/shields/giga_display_shield/giga_display_shield.overlay @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Arduino SA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&zephyr_mipi_dsi { + st7701: st7701@0 { + status = "okay"; + compatible = "sitronix,st7701"; + reg = <0x0>; + height = <800>; + width = <480>; + data-lanes = <2>; + pixel-format = ; + rotation = <0>; + gip-e0 = [E0 00 00 02]; + gip-e1 = [E1 08 00 0A 00 07 00 09 00 00 33 33]; + gip-e2 = [E2 00 00 00 00 00 00 00 00 00 00 00 00 00]; + gip-e3 = [E3 00 00 33 33]; + gip-e4 = [E4 44 44]; + gip-e5 = [E5 0E 60 A0 A0 10 60 A0 A0 0A 60 A0 A0 0C 60 A0 A0]; + gip-e6 = [E6 00 00 33 33]; + gip-e7 = [E7 44 44]; + gip-e8 = [E8 0D 60 A0 A0 0F 60 A0 A0 09 60 A0 A0 0B 60 A0 A0]; + gip-eb = [EB 02 01 E4 E4 44 00 40]; + gip-ec = [EC 02 01]; + gip-ed = [ED AB 89 76 54 01 FF FF FF FF FF FF 10 45 67 98 BA]; + gip-ed = [ED AB 89 76 54 01 FF FF FF FF FF FF 10 45 67 98 BA]; + pvgamctrl = [B0 40 C9 91 0D 12 07 02 09 09 1F 04 50 0F E4 29 DF]; + nvgamctrl = [B1 40 CB D0 11 92 07 00 08 07 1C 06 53 12 63 EB DF]; + + display-timings { + compatible = "zephyr,panel-timing"; + hsync-active = <1>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + hback-porch = <40>; + hsync-len = <32>; + hfront-porch = <8>; + vback-porch = <6>; + vsync-len = <8>; + vfront-porch = <9>; + }; + }; +}; From fa73f9ad5246c08dede82ade87951469a557a29f Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Thu, 20 Mar 2025 14:49:22 +0100 Subject: [PATCH 09/11] llext-edk: fix BOARD_TARGET variable generation to be Zephyr-compatible The board revision is not part of the NORMALIZED_BOARD_TARGET variable as composed by Zephyr, so it must also not be used in the EDK exported value to avoid mismatches. The revision is exported as a separate variable, so it can still be used to differentiate between board revisions. Signed-off-by: Luca Burelli --- cmake/llext-edk.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/llext-edk.cmake b/cmake/llext-edk.cmake index 1fca00322659f..1475931968dd2 100644 --- a/cmake/llext-edk.cmake +++ b/cmake/llext-edk.cmake @@ -166,8 +166,7 @@ yaml_get(board_qualifiers NAME build_info KEY cmake board qualifiers) yaml_get(board_revision NAME build_info KEY cmake board revision) zephyr_build_string(normalized_board_target BOARD ${board_name} - BOARD_QUALIFIERS ${board_qualifiers} - BOARD_REVISION ${board_revision}) + BOARD_QUALIFIERS ${board_qualifiers}) set(llext_edk_name ${CONFIG_LLEXT_EDK_NAME}) set(llext_edk ${PROJECT_BINARY_DIR}/${llext_edk_name}) From 9f06fc60e2559aa030ac7b5666c0eb08ae7a9013 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Fri, 21 Mar 2025 11:14:11 +0100 Subject: [PATCH 10/11] cmake: package_helper: add -R option to run additional commands The 'package_helper.cmake' script is used to load a certain subset of Zephyr modules, as required by the caller. Some use cases may require additional commands to be executed in the same context after the modules have been loaded, because not enough information is reported or saved in the build directory by default. This patch adds a new '-R' option to 'package_helper.cmake', which allows the caller to specify a script to be executed in the current context after the modules have been loaded. Signed-off-by: Luca Burelli --- cmake/package_helper.cmake | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/cmake/package_helper.cmake b/cmake/package_helper.cmake index 886dbfff71ddf..a360f2032c48d 100644 --- a/cmake/package_helper.cmake +++ b/cmake/package_helper.cmake @@ -19,6 +19,9 @@ # The build directory will default to current working directory but can be # controlled with: '-B ' # +# After the modules have been loaded, additional commands can be optionally +# executed in the current context by providing the '-R ' option. +# # For example, if you were invoking CMake for 'hello_world' sample as: # $ cmake -DBOARD= -B build -S samples/hello_world # @@ -49,10 +52,12 @@ foreach(i RANGE ${CMAKE_ARGC}) if(CMAKE_ARGV${i} MATCHES "^-B(.*)") set(argB ${CMAKE_MATCH_1}) set(argB_index ${i}) - elseif() elseif(CMAKE_ARGV${i} MATCHES "^-S(.*)") set(argS_index ${i}) set(argS ${CMAKE_MATCH_1}) + elseif(CMAKE_ARGV${i} MATCHES "^-R(.*)") + set(argR_index ${i}) + set(argR ${CMAKE_MATCH_1}) endif() endforeach() @@ -76,6 +81,16 @@ if(DEFINED argS_index) endif() endif() +if(DEFINED argR_index) + if(DEFINED argR) + set(RUN_SCRIPT ${argR}) + else() + # value of -R follows in next index + math(EXPR argR_value_index "${argR_index} + 1") + set(RUN_SCRIPT ${CMAKE_ARGV${argR_value_index}}) + endif() +endif() + if(NOT DEFINED APPLICATION_SOURCE_DIR) message(FATAL_ERROR "Source directory not defined, please use '-S ' to the " @@ -99,3 +114,7 @@ endif() string(REPLACE ";" "," MODULES "${MODULES}") find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE} COMPONENTS zephyr_default:${MODULES}) + +if (DEFINED RUN_SCRIPT) + include(${RUN_SCRIPT}) +endif() From 1101c22b3f2acdb3504ef28e73f67eeccd1f178a Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sun, 23 Mar 2025 07:53:10 -0700 Subject: [PATCH 11/11] Portenta H7: remove usage of cdc_acm_serial.dtsi Including this file here plus not overriding one of the new defines in the overlay was causing two CDC_ACM objects to be created under USB and this caused the boards to no longer create a USB Serial port --- .../arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts index 001d8509059e2..fe77a36963303 100644 --- a/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts +++ b/boards/arduino/portenta_h7/arduino_portenta_h7_stm32h747xx_m7.dts @@ -8,7 +8,7 @@ #include #include #include "arduino_portenta_h7-common.dtsi" -#include <../boards/common/usb/cdc_acm_serial.dtsi> +/* #include <../boards/common/usb/cdc_acm_serial.dtsi> */ / { model = "Arduino Portenta H7 board";