diff --git a/dts/arm/silabs/sim3u.dtsi b/dts/arm/silabs/sim3u.dtsi new file mode 100644 index 00000000000..77320768280 --- /dev/null +++ b/dts/arm/silabs/sim3u.dtsi @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 GARDENA GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/ { + chosen { + zephyr,flash-controller = &flash; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "arm,cortex-m3"; + device_type = "cpu"; + clock-frequency = <20000000>; + reg = <0>; + }; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + }; + + pinctrl: pinctrl { + compatible = "silabs,si32-pinctrl"; + status = "okay"; + }; + + soc { + flash: flash-controller@4002e000 { + compatible = "silabs,si32-flash-controller"; + reg = <0x4002e000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + write-block-size = <2>; + }; + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <4>; +}; diff --git a/dts/arm/silabs/sim3u167.dtsi b/dts/arm/silabs/sim3u167.dtsi new file mode 100644 index 00000000000..c0a9461ccfb --- /dev/null +++ b/dts/arm/silabs/sim3u167.dtsi @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 GARDENA GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/ { + sram0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(32)>; + }; + + soc { + compatible = "silabs,sim3u167", \ + "silabs,sim3u", \ + "silabs,sim3", \ + "simple-bus"; + + flash-controller@4002e000 { + flash0: flash@0 { + reg = <0 DT_SIZE_K(256)>; + erase-block-size = ; + }; + }; + }; +}; diff --git a/include/zephyr/dt-bindings/pinctrl/si32-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/si32-pinctrl.h new file mode 100644 index 00000000000..994480b3257 --- /dev/null +++ b/include/zephyr/dt-bindings/pinctrl/si32-pinctrl.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 GARDENA GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_SI32_PINCTRL_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_SI32_PINCTRL_ + +#define SI32_SIGNAL_USART0_TX 0 +#define SI32_SIGNAL_USART0_RX 1 +#define SI32_SIGNAL_USART0_RTS 2 +#define SI32_SIGNAL_USART0_CTS 3 +#define SI32_SIGNAL_USART0_UCLK 4 + +#define SI32_SIGNAL_SPI0_SCK 5 +#define SI32_SIGNAL_SPI0_MISO 6 +#define SI32_SIGNAL_SPI0_MOSI 7 +#define SI32_SIGNAL_SPI0_NSS 8 + +#define SI32_SIGNAL_USART1_TX 9 +#define SI32_SIGNAL_USART1_RX 10 +#define SI32_SIGNAL_USART1_RTS 11 +#define SI32_SIGNAL_USART1_CTS 12 +#define SI32_SIGNAL_USART1_UCLK 13 + +#define SI32_SIGNAL_EPCA0_CEX0 14 +#define SI32_SIGNAL_EPCA0_CEX1 15 +#define SI32_SIGNAL_EPCA0_CEX2 16 +#define SI32_SIGNAL_EPCA0_CEX3 17 +#define SI32_SIGNAL_EPCA0_CEX4 18 +#define SI32_SIGNAL_EPCA0_CEX4 19 + +#define SI32_SIGNAL_PCA0_CEX0 20 +#define SI32_SIGNAL_PCA0_CEX1 21 + +#define SI32_SIGNAL_PCA1_CEX0 22 +#define SI32_SIGNAL_PCA1_CEX1 23 + +#define SI32_SIGNAL_EPCA0_ECI 24 + +#define SI32_SIGNAL_PCA0_ECI 25 + +#define SI32_SIGNAL_PCA1_ECI 26 + +#define SI32_SIGNAL_I2S0_TX_WS 27 +#define SI32_SIGNAL_I2S0_TX_SCK 28 +#define SI32_SIGNAL_I2S0_TX_SD 29 + +#define SI32_SIGNAL_I2C0_SDA 30 +#define SI32_SIGNAL_I2C0_SCL 31 + +#define SI32_SIGNAL_CMP0S 32 +#define SI32_SIGNAL_CMP0A 33 + +#define SI32_SIGNAL_CMP1S 34 +#define SI32_SIGNAL_CMP1A 35 + +#define SI32_SIGNAL_TIMER0_CT 36 +#define SI32_SIGNAL_TIMER0_EX 37 + +#define SI32_SIGNAL_TIMER1_CT 38 +#define SI32_SIGNAL_TIMER1_EX 39 + +#define SI32_SIGNAL_UART0_TX 40 +#define SI32_SIGNAL_UART0_RX 41 +#define SI32_SIGNAL_UART0_RTS 42 +#define SI32_SIGNAL_UART0_CTS 43 + +#define SI32_SIGNAL_UART1_TX 44 +#define SI32_SIGNAL_UART1_RX 45 + +#define SI32_SIGNAL_SPI1_SCK 46 +#define SI32_SIGNAL_SPI1_MISO 47 +#define SI32_SIGNAL_SPI1_MOSI 48 +#define SI32_SIGNAL_SPI1_NSS 49 + +#define SI32_SIGNAL_SPI2_SCK 50 +#define SI32_SIGNAL_SPI2_MISO 51 +#define SI32_SIGNAL_SPI2_MOSI 52 +#define SI32_SIGNAL_SPI2_NSS 53 + +#define SI32_SIGNAL_AHB_OUT 54 + +#define SI32_SIGNAL_SSG0_EX0 55 +#define SI32_SIGNAL_SSG0_EX1 56 +#define SI32_SIGNAL_SSG0_EX2 57 +#define SI32_SIGNAL_SSG0_EX3 58 + +#define SI32_SIGNAL_RTC0_OUT 59 + +#define SI32_SIGNAL_I2S0_RX_WS 60 +#define SI32_SIGNAL_I2S0_RX_SCK 61 +#define SI32_SIGNAL_I2S0_RX_SD 62 + +#define SI32_SIGNAL_LPTIMER0_OUT 63 + +#define SI32_SIGNAL_I2C1_SDA 64 +#define SI32_SIGNAL_I2C1_SCL 65 + +#define SI32_SIGNAL_PB_HDKILL 66 + +/** + * @brief Specify MUX field + * + * @param fun Function name + * @param port Port number (0 to 4) + * @param pin Port pin number (0 to 15) + */ +#define SI32_MUX(fun, port, pin) \ + ((((port)&0x7)) | (((pin)&0xF) << 3) | ((SI32_SIGNAL_##fun & 0x7F) << 22)) + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_PINCTRL_SI32_PINCTRL_ */ diff --git a/modules/Kconfig.silabs b/modules/Kconfig.silabs index c5fb0d6ca14..a0aab1bd483 100644 --- a/modules/Kconfig.silabs +++ b/modules/Kconfig.silabs @@ -1,4 +1,4 @@ -# Gecko SDK +# Gecko and Si32 SDK # Copyright (c) 2017, Christian Taedcke # SPDX-License-Identifier: Apache-2.0 @@ -7,3 +7,7 @@ config HAS_SILABS_GECKO bool select HAS_CMSIS_CORE depends on SOC_FAMILY_SILABS_S0 || SOC_FAMILY_SILABS_S1 || SOC_FAMILY_SILABS_S2 + +config HAS_SILABS_SI32 + bool + select HAS_CMSIS_CORE diff --git a/soc/silabs/CMakeLists.txt b/soc/silabs/CMakeLists.txt index 17eca2d8d6b..53c5acb87d2 100644 --- a/soc/silabs/CMakeLists.txt +++ b/soc/silabs/CMakeLists.txt @@ -3,3 +3,5 @@ add_subdirectory(common) zephyr_include_directories(${SOC_FAMILY}/${SOC_SERIES}) + +add_subdirectory_ifdef(CONFIG_SOC_SERIES_SIM3U silabs_sim3/sim3u) diff --git a/soc/silabs/Kconfig.soc b/soc/silabs/Kconfig.soc index d3e52c95cd7..7b1174c6864 100644 --- a/soc/silabs/Kconfig.soc +++ b/soc/silabs/Kconfig.soc @@ -5,5 +5,6 @@ config SOC_FAMILY default "silabs_s0" if SOC_FAMILY_SILABS_S0 default "silabs_s1" if SOC_FAMILY_SILABS_S1 default "silabs_s2" if SOC_FAMILY_SILABS_S2 + default "silabs_sim3" if SOC_FAMILY_SILABS_SIM3 rsource "*/Kconfig.soc" diff --git a/soc/silabs/silabs_sim3/Kconfig b/soc/silabs/silabs_sim3/Kconfig new file mode 100644 index 00000000000..3f8dbad2a7c --- /dev/null +++ b/soc/silabs/silabs_sim3/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_FAMILY_SILABS_SIM3 + +config SOC_FAMILY_SILABS_SIM3 + select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select BUILD_OUTPUT_HEX + +rsource "*/Kconfig" + +endif # SOC_FAMILY_SILABS_SIM3 diff --git a/soc/silabs/silabs_sim3/Kconfig.soc b/soc/silabs/silabs_sim3/Kconfig.soc new file mode 100644 index 00000000000..f938cb0bb5e --- /dev/null +++ b/soc/silabs/silabs_sim3/Kconfig.soc @@ -0,0 +1,8 @@ +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_FAMILY_SILABS_SIM3 + bool + +rsource "*/Kconfig.soc" diff --git a/soc/silabs/silabs_sim3/sim3u/CMakeLists.txt b/soc/silabs/silabs_sim3/sim3u/CMakeLists.txt new file mode 100644 index 00000000000..f290d24a4c0 --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(soc.c) + +set(CROSSBAR_CONFIG_H ${CMAKE_BINARY_DIR}/zephyr/include/generated/silabs_crossbar_config.h) +add_custom_command( + OUTPUT ${CROSSBAR_CONFIG_H} + DEPENDS ${EDT_PICKLE} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen_crossbar_config.py + ${EDT_PICKLE} ${CROSSBAR_CONFIG_H}) +add_custom_target(silabs_crossbar_config_h DEPENDS ${CROSSBAR_CONFIG_H}) +add_dependencies(zephyr_interface silabs_crossbar_config_h) diff --git a/soc/silabs/silabs_sim3/sim3u/Kconfig b/soc/silabs/silabs_sim3/sim3u/Kconfig new file mode 100644 index 00000000000..7b52312ee94 --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIM3U + select ARM + select CPU_CORTEX_M3 + select CPU_CORTEX_M_HAS_SYSTICK + select HAS_SILABS_SI32 diff --git a/soc/silabs/silabs_sim3/sim3u/Kconfig.defconfig b/soc/silabs/silabs_sim3/sim3u/Kconfig.defconfig new file mode 100644 index 00000000000..8091a25d361 --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/Kconfig.defconfig @@ -0,0 +1,17 @@ +# SiM3U series configuration options + +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +if SOC_SERIES_SIM3U + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) + +config NUM_IRQS + int + # must be >= the highest interrupt number used + default 53 + +endif # SOC_SERIES_SIM3U diff --git a/soc/silabs/silabs_sim3/sim3u/Kconfig.soc b/soc/silabs/silabs_sim3/sim3u/Kconfig.soc new file mode 100644 index 00000000000..b399f388152 --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/Kconfig.soc @@ -0,0 +1,28 @@ +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +config SOC_SERIES_SIM3U + bool + select SOC_FAMILY_SILABS_SIM3 + help + Enable support for SiM3U MCU series + +config SOC_PART_NUMBER_SIM3U167BGM + bool + select SOC_SERIES_SIM3U + +config SOC_PART_NUMBER_SIM3U167AGQ + bool + select SOC_SERIES_SIM3U + +config SOC_SERIES + default "sim3u" if SOC_SERIES_SIM3U + +config SOC + default "sim3u167" if SOC_PART_NUMBER_SIM3U167BGM + default "sim3u167" if SOC_PART_NUMBER_SIM3U167AGQ + +config SOC_PART_NUMBER + default "SiM3U167BGM" if SOC_PART_NUMBER_SIM3U167BGM + default "SiM3U167AGQ" if SOC_PART_NUMBER_SIM3U167AGQ diff --git a/soc/silabs/silabs_sim3/sim3u/gen_crossbar_config.py b/soc/silabs/silabs_sim3/sim3u/gen_crossbar_config.py new file mode 100755 index 00000000000..f57efa61adb --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/gen_crossbar_config.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2024 GARDENA GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +"""Generate crossbar register values from devicetree pinctrl nodes. + +The SiM3U1xx SoCs do support pinmuxing, but with many limimitations. It's also non-optional, so we +can't just not support it and rely on default values. + +The hardware doesn't allow us to properly implement the pinmux API, but we still want to use the +standard pinctrl nodes inside the devicetree to define which peripheral should be muxed to which +pins. To accomplish that, this script parses these nodes and generates code that applies all +`default` nodes of all enabled devices within soc.c. + +There's two crossbars: +- crossbar 0: Controls portbanks 0 and 1 +- crossbar 1: Controls portbanks 2 and 3 + +Each crossbar has two configuration-values which reside in different registers: +- config: A bitmask which tells the crossbar which peripherals should be muxed. Some peripherals + have multiple bits to prevent having to mux unused pins (like UART flow control). +- enable: A bit which enables or disables the whole crossbar. When disabled, all pins of the + crossbar are disconnected. + +And each portbank has this related config: +- pbskipen: A bitmask where value `1` means, that the pin will not be muxed. + The index of the bit refers to the pin number. + +A crossbar has a list of signals that it tries to mux to pins that it controls. That list has a +fixed order and signals that belong to the same peripheral are next to each other. +The crossbar hardware simply iterates the signal list and assigns each signal to the lowest +available pin. That has a few implications: + +- Pins of a peripheral are always consecutive within all non-skipped pins. +- Peripherals that appear first in the signal list will always use lower pin-numbers than later ones +- There's no way to change the muxing without side effects. Writing to pbskipen while the crossbar + is enabled might temporarily cause unwanted muxing. Disabling the crossbar will disconnect all + peripherals for a short time. + +The last point is the reason why we don't implement Zephyrs runtime pinmuxing API. Applying the +pinmuxing one by one as drivers get initialized would require disconnecting pins quite often. +""" + +import argparse +import enum +import os +import pickle +import sys + +sys.path.insert( + 0, os.path.join(os.environ["ZEPHYR_BASE"], "scripts/dts/python-devicetree/src") +) + + +class Signal(enum.Enum): + USART0_TX = 0 + USART0_RX = 1 + USART0_RTS = 2 + USART0_CTS = 3 + USART0_UCLK = 4 + + USART1_TX = 9 + USART1_RX = 10 + USART1_RTS = 11 + USART1_CTS = 12 + USART1_UCLK = 13 + + SPI2_SCK = 50 + SPI2_MISO = 51 + SPI2_MOSI = 52 + SPI2_NSS = 53 + + +class PinMode(enum.Enum): + ANALOG = 0 + DIGITAL_INPUT = 1 + PUSH_PULL_OUTPUT = 2 + + +class Pinmux: + def __init__(self, value, props): + self.pin = (value & 0x7, (value >> 3) & 0xFF) + self.signal = Signal((value >> 22) & 0x7F) + + output_low = props["output-low"].val + output_high = props["output-high"].val + output_enable = props["output-enable"].val or output_low or output_high + + input_enable = props["input-enable"].val + + if output_enable and input_enable: + raise Exception("can't enable both output and input") + if output_low and output_high: + raise Exception("can't define output as both low and high") + + if input_enable: + self.pinmode = PinMode.DIGITAL_INPUT + elif output_enable: + self.pinmode = PinMode.PUSH_PULL_OUTPUT + + if output_low: + self.output_value = True + elif output_high: + self.output_value = False + else: + self.output_value = None + else: + self.pinmode = None + + def __repr__(self): + return self.__dict__.__repr__() + + +def parse_args(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument( + "edt_pickle", help="path to read the pickled edtlib.EDT object from" + ) + parser.add_argument("out", help="path to write the header file") + + return parser.parse_args() + + +class CrossbarBit: + def __init__(self, bit, signals, pin_first, pin_last): + assert pin_first <= pin_last + + self.bit = bit + self.signals = signals + self.pin_first = pin_first + self.pin_last = pin_last + + def __repr__(self): + return self.__dict__.__repr__() + + +class Crossbar: + def __init__(self, number, bits, portbanks): + self.number = number + self.value = 0 + self.bits = bits + self.first_configurable = (0, 0) + self.portbanks = portbanks + + def enable_bit(self, bit, pins): + if len(pins) != len(bit.signals): + raise Exception( + f"pins({pins}) and signals({bit.signals}) must be the same length" + ) + + for pin in pins: + if pin < self.first_configurable: + raise Exception( + "can't enable crossbar pin anymore", pin, self.first_configurable + ) + + self.portbanks[pin[0]].unskip(pin[1]) + + self.first_configurable = (pin[0], pin[1] + 1) + + self.value |= 1 << bit.bit + + def mux(self, muxs): + for bit in self.bits: + # collect the signals that are enabled by this bit + signal_muxs = {} + for mux in muxs: + if self.number == 0 and mux.pin[0] != 0 and mux.pin[0] != 1: + continue + if self.number == 1 and mux.pin[0] != 2 and mux.pin[0] != 3: + continue + + if mux.signal not in bit.signals: + continue + if mux.signal in signal_muxs: + raise Exception("duplicate signal", mux) + if mux.pin < bit.pin_first or mux.pin > bit.pin_last: + raise Exception("can't mux signal to pin", mux, bit) + + signal_muxs[mux.signal] = mux + + # this bit is disabled + if len(signal_muxs.keys()) == 0: + continue + # we have to enable all the signals + if len(signal_muxs.keys()) != len(bit.signals): + raise Exception("missing signals for bit", bit, signal_muxs) + + # build pin list for this bit in the required order + pins = [] + for _index, signal in enumerate(bit.signals): + mux = signal_muxs[signal] + pins.append(mux.pin) + + self.enable_bit(bit, pins) + + for mux in signal_muxs.values(): + self.portbanks[mux.pin[0]].apply_mux(mux.pin[1], mux) + + def __repr__(self): + return self.__dict__.__repr__() + + +class Portbank: + def __init__(self): + self.pins_high = 0 + self.pins_low = 0 + self.pins_push_pull_output = 0 + self.pins_digital_input = 0 + self.pins_analog = 0 + + # skip all pins by default + self.skip_enable = 0xFFFF + + def unskip(self, pin): + self.skip_enable &= ~(1 << pin) + + def apply_mux(self, pin, mux): + if mux.pinmode == PinMode.ANALOG: + self.pins_analog |= 1 << pin + elif mux.pinmode == PinMode.DIGITAL_INPUT: + self.pins_digital_input |= 1 << pin + elif mux.pinmode == PinMode.PUSH_PULL_OUTPUT: + self.pins_push_pull_output |= 1 << pin + + if mux.output_value: + self.pins_high |= 1 << pin + elif not mux.output_value: + self.pins_low |= 1 << pin + elif mux.output_value is None: + pass + else: + raise Exception("unsupported output value", mux.output_value) + elif mux.pinmode is None: + pass + else: + raise Exception("unsupported pinmode", mux.pinmode) + + def __repr__(self): + return self.__dict__.__repr__() + + +def main(): + args = parse_args() + + with open(args.edt_pickle, "rb") as f: + edt = pickle.load(f) + + pinmux_table = [] + for node in edt.nodes: + if node.status != "okay": + continue + if not node.pinctrls: + continue + + pinctrl = None + for p in node.pinctrls: + if p.name != "default": + continue + + if pinctrl is not None: + raise Exception("multiple default nodes", node) + pinctrl = p + + if pinctrl is None: + raise Exception("no default node", node) + + for conf_node in pinctrl.conf_nodes: + for child in conf_node.children.values(): + for pin in child.props["pinmux"].val: + pinmux_table.append(Pinmux(pin, child.props)) + + crossbar0_bits = [ + CrossbarBit(0, [Signal.USART0_TX, Signal.USART0_RX], (0, 0), (1, 15)), + CrossbarBit(1, [Signal.USART0_RTS, Signal.USART0_CTS], (0, 0), (1, 15)), + CrossbarBit(2, [Signal.USART0_UCLK], (0, 0), (1, 15)), + CrossbarBit(5, [Signal.USART1_TX, Signal.USART1_RX], (0, 0), (1, 15)), + CrossbarBit(6, [Signal.USART1_RTS, Signal.USART1_CTS], (0, 0), (1, 15)), + CrossbarBit(7, [Signal.USART1_UCLK], (0, 0), (1, 15)), + CrossbarBit( + 32 + 3, + [Signal.SPI2_SCK, Signal.SPI2_MISO, Signal.SPI2_MOSI], + (0, 0), + (1, 15), + ), + CrossbarBit(32 + 4, [Signal.SPI2_NSS], (0, 0), (1, 15)), + ] + crossbar1_bits = [ + CrossbarBit( + 7, [Signal.SPI2_SCK, Signal.SPI2_MISO, Signal.SPI2_MOSI], (2, 6), (3, 11) + ), + CrossbarBit(8, [Signal.SPI2_NSS], (2, 6), (3, 11)), + ] + + portbanks = [Portbank(), Portbank(), Portbank(), Portbank()] + crossbars = [ + Crossbar(0, crossbar0_bits, portbanks), + Crossbar(1, crossbar1_bits, portbanks), + ] + + for crossbar in crossbars: + crossbar.mux(pinmux_table) + + with open(args.out, "w", encoding="utf-8") as f: + for index, crossbar in enumerate(crossbars): + print(f"#define CROSSBAR_{index}_CONFIG 0x{crossbar.value:08X}ULL", file=f) + + for index, portbank in enumerate(portbanks): + print( + f"#define PORTBANK_{index}_SKIPEN_VALUE 0x{portbank.skip_enable:04X}", + file=f, + ) + + print( + f"#define PORTBANK_{index}_PINS_HIGH 0x{portbank.pins_high:04X}", + file=f, + ) + print( + f"#define PORTBANK_{index}_PINS_LOW 0x{portbank.pins_low:04X}", + file=f, + ) + + print( + f"#define PORTBANK_{index}_PINS_DIGITAL_INPUT 0x{portbank.pins_digital_input:04X}", + file=f, + ) + print( + f"#define PORTBANK_{index}_PINS_PUSH_PULL_OUTPUT 0x{portbank.pins_push_pull_output:04X}", + file=f, + ) + print( + f"#define PORTBANK_{index}_PINS_ANALOG 0x{portbank.pins_analog:04X}", + file=f, + ) + + +if __name__ == "__main__": + main() diff --git a/soc/silabs/silabs_sim3/sim3u/soc.c b/soc/silabs/silabs_sim3/sim3u/soc.c new file mode 100644 index 00000000000..88355105b1e --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/soc.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 GARDENA GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static void gpio_init(void) +{ + /* After a device reset, all crossbars enter a disabled default reset state, causing all + * port bank pins into a high impedance digital input mode. + */ + + /* Enable clocks that we need in any case */ + SI32_CLKCTRL_A_enable_apb_to_modules_0( + SI32_CLKCTRL_0, SI32_CLKCTRL_A_APBCLKG0_PB0 | SI32_CLKCTRL_A_APBCLKG0_FLASHCTRL0); + + /* Enable misc clocks. + * We may or may nor need all of that but it includes some basics like + * LOCK0, WDTIMER0 and DMA. Doing it here prevents the actual drivers + * needing to know whoelse needs one of these clocks. + */ + SI32_CLKCTRL_A_enable_apb_to_modules_1( + SI32_CLKCTRL_0, SI32_CLKCTRL_A_APBCLKG1_MISC0 | SI32_CLKCTRL_A_APBCLKG1_MISC1); + SI32_CLKCTRL_A_enable_ahb_to_dma_controller(SI32_CLKCTRL_0); + + /* Apply pinctrl gpio settings */ + SI32_PBSTD_A_write_pins_high(SI32_PBSTD_0, PORTBANK_0_PINS_HIGH); + SI32_PBSTD_A_write_pins_low(SI32_PBSTD_0, PORTBANK_0_PINS_LOW); + SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_0, PORTBANK_0_PINS_DIGITAL_INPUT); + SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_0, PORTBANK_0_PINS_PUSH_PULL_OUTPUT); + SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_0, PORTBANK_0_PINS_ANALOG); + + SI32_PBSTD_A_write_pins_high(SI32_PBSTD_1, PORTBANK_1_PINS_HIGH); + SI32_PBSTD_A_write_pins_low(SI32_PBSTD_1, PORTBANK_1_PINS_LOW); + SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_1, PORTBANK_1_PINS_DIGITAL_INPUT); + SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_1, PORTBANK_1_PINS_PUSH_PULL_OUTPUT); + SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_1, PORTBANK_1_PINS_ANALOG); + + SI32_PBSTD_A_write_pins_high(SI32_PBSTD_2, PORTBANK_2_PINS_HIGH); + SI32_PBSTD_A_write_pins_low(SI32_PBSTD_2, PORTBANK_2_PINS_LOW); + SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_2, PORTBANK_2_PINS_DIGITAL_INPUT); + SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_2, PORTBANK_2_PINS_PUSH_PULL_OUTPUT); + SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_2, PORTBANK_2_PINS_ANALOG); + + SI32_PBSTD_A_write_pins_high(SI32_PBSTD_3, PORTBANK_3_PINS_HIGH); + SI32_PBSTD_A_write_pins_low(SI32_PBSTD_3, PORTBANK_3_PINS_LOW); + SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_3, PORTBANK_3_PINS_DIGITAL_INPUT); + SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_3, PORTBANK_3_PINS_PUSH_PULL_OUTPUT); + SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_3, PORTBANK_3_PINS_ANALOG); + + /* Configure skips */ + SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_0, PORTBANK_0_SKIPEN_VALUE); + SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_1, PORTBANK_1_SKIPEN_VALUE); + SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_2, PORTBANK_2_SKIPEN_VALUE); + SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_3, PORTBANK_3_SKIPEN_VALUE); + + /* Configure crossbars */ + SI32_PBCFG_A_enable_xbar0l_peripherals(SI32_PBCFG_0, CROSSBAR_0_CONFIG & 0xFFFFFFFF); + SI32_PBCFG_A_enable_xbar0h_peripherals(SI32_PBCFG_0, + (CROSSBAR_0_CONFIG >> 32) & 0xFFFFFFFF); + SI32_PBCFG_A_enable_xbar1_peripherals(SI32_PBCFG_0, CROSSBAR_1_CONFIG & 0xFFFFFFFF); + + /* Enable crossbars */ + SI32_PBCFG_A_enable_crossbar_0(SI32_PBCFG_0); + SI32_PBCFG_A_enable_crossbar_1(SI32_PBCFG_0); +} + +static void vddlow_irq_handler(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* nothing to do here, we just don't want any spurious interrupts */ +} + +static void vmon_init(void) +{ + /* VMON must be enabled for flash write/erase support */ + + NVIC_ClearPendingIRQ(VDDLOW_IRQn); + + IRQ_CONNECT(VDDLOW_IRQn, 0, vddlow_irq_handler, NULL, 0); + irq_enable(VDDLOW_IRQn); + + SI32_VMON_A_enable_vdd_supply_monitor(SI32_VMON_0); + SI32_VMON_A_enable_vdd_low_interrupt(SI32_VMON_0); + SI32_VMON_A_select_vdd_standard_threshold(SI32_VMON_0); +} + +__no_optimization static void busy_delay(uint32_t cycles) +{ + while (cycles) { + cycles--; + } +} + +static int silabs_sim3u_init(void) +{ + uint32_t key; + + key = irq_lock(); + + /* The watchdog may be enabled already so we have to disable it */ + SI32_WDTIMER_A_reset_counter(SI32_WDTIMER_0); + SI32_WDTIMER_A_stop_counter(SI32_WDTIMER_0); + SI32_RSTSRC_A_disable_watchdog_timer_reset_source(SI32_RSTSRC_0); + + /* Since a hardware reset affects the debug hardware as well, this makes it easier to + * recover from a broken firmware. + * + * For details, see erratum #H2 in the document "SiM3U1xx and SiM3C1xx Revision B Errata". + */ + busy_delay(3000000); + + gpio_init(); + vmon_init(); + + irq_unlock(key); + + return 0; +} + +SYS_INIT(silabs_sim3u_init, PRE_KERNEL_1, 0); diff --git a/soc/silabs/silabs_sim3/sim3u/soc.h b/soc/silabs/silabs_sim3/sim3u/soc.h new file mode 100644 index 00000000000..dd8f06db26f --- /dev/null +++ b/soc/silabs/silabs_sim3/sim3u/soc.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024 GARDENA GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SOC_SILABS_SIM3U_H_ +#define SOC_SILABS_SIM3U_H_ + +#include + +#include + +#endif /* SOC_SILABS_SIM3U_H_ */ diff --git a/soc/silabs/soc.yml b/soc/silabs/soc.yml index 539631500f1..f1765c8c839 100644 --- a/soc/silabs/soc.yml +++ b/soc/silabs/soc.yml @@ -55,3 +55,8 @@ family: - name: efr32bg27 socs: - name: efr32bg27c140f768im40 + - name: silabs_sim3 + series: + - name: sim3u + socs: + - name: sim3u167