soc: Add initial SiM3U1xx support

This is the bare minimum and includes the SoC, pinctrl, flash and
devicetree.

I had to include the flash driver that early because I couldn't make
Zephyr compile without flash driver nodes in the device tree.

Signed-off-by: Michael Zimmermann <michael.zimmermann@grandcentrix.net>
This commit is contained in:
Michael Zimmermann 2023-05-14 07:57:55 +02:00 committed by Carles Cufí
commit 5a1c4cd2e9
16 changed files with 789 additions and 1 deletions

55
dts/arm/silabs/sim3u.dtsi Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2024 GARDENA GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <arm/armv7-m.dtsi>
#include <dt-bindings/gpio/gpio.h>
#include <freq.h>
/ {
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>;
};

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2024 GARDENA GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <mem.h>
#include <silabs/sim3u.dtsi>
/ {
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 = <DT_SIZE_K(1)>;
};
};
};
};

View file

@ -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_ */

View file

@ -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

View file

@ -3,3 +3,5 @@
add_subdirectory(common)
zephyr_include_directories(${SOC_FAMILY}/${SOC_SERIES})
add_subdirectory_ifdef(CONFIG_SOC_SERIES_SIM3U silabs_sim3/sim3u)

View file

@ -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"

View file

@ -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

View file

@ -0,0 +1,8 @@
# Copyright (c) 2024 GARDENA GmbH
#
# SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_SILABS_SIM3
bool
rsource "*/Kconfig.soc"

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2024 GARDENA GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc.h"
#include <zephyr/device.h>
#include <zephyr/init.h>
#include <zephyr/irq.h>
#include <SI32_CLKCTRL_A_Type.h>
#include <SI32_PBCFG_A_Type.h>
#include <SI32_PBSTD_A_Type.h>
#include <SI32_RSTSRC_A_Type.h>
#include <SI32_VMON_A_Type.h>
#include <SI32_WDTIMER_A_Type.h>
#include <si32_device.h>
#include <silabs_crossbar_config.h>
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);

View file

@ -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 <si32_device.h>
#include <cmsis_core_m_defaults.h>
#endif /* SOC_SILABS_SIM3U_H_ */

View file

@ -55,3 +55,8 @@ family:
- name: efr32bg27
socs:
- name: efr32bg27c140f768im40
- name: silabs_sim3
series:
- name: sim3u
socs:
- name: sim3u167