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:
parent
2e1a87543c
commit
5a1c4cd2e9
16 changed files with 789 additions and 1 deletions
55
dts/arm/silabs/sim3u.dtsi
Normal file
55
dts/arm/silabs/sim3u.dtsi
Normal 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>;
|
||||
};
|
28
dts/arm/silabs/sim3u167.dtsi
Normal file
28
dts/arm/silabs/sim3u167.dtsi
Normal 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)>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
113
include/zephyr/dt-bindings/pinctrl/si32-pinctrl.h
Normal file
113
include/zephyr/dt-bindings/pinctrl/si32-pinctrl.h
Normal 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_ */
|
|
@ -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
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
|
||||
add_subdirectory(common)
|
||||
zephyr_include_directories(${SOC_FAMILY}/${SOC_SERIES})
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_SOC_SERIES_SIM3U silabs_sim3/sim3u)
|
||||
|
|
|
@ -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"
|
||||
|
|
13
soc/silabs/silabs_sim3/Kconfig
Normal file
13
soc/silabs/silabs_sim3/Kconfig
Normal 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
|
8
soc/silabs/silabs_sim3/Kconfig.soc
Normal file
8
soc/silabs/silabs_sim3/Kconfig.soc
Normal 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"
|
14
soc/silabs/silabs_sim3/sim3u/CMakeLists.txt
Normal file
14
soc/silabs/silabs_sim3/sim3u/CMakeLists.txt
Normal 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)
|
9
soc/silabs/silabs_sim3/sim3u/Kconfig
Normal file
9
soc/silabs/silabs_sim3/sim3u/Kconfig
Normal 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
|
17
soc/silabs/silabs_sim3/sim3u/Kconfig.defconfig
Normal file
17
soc/silabs/silabs_sim3/sim3u/Kconfig.defconfig
Normal 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
|
28
soc/silabs/silabs_sim3/sim3u/Kconfig.soc
Normal file
28
soc/silabs/silabs_sim3/sim3u/Kconfig.soc
Normal 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
|
340
soc/silabs/silabs_sim3/sim3u/gen_crossbar_config.py
Executable file
340
soc/silabs/silabs_sim3/sim3u/gen_crossbar_config.py
Executable 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()
|
137
soc/silabs/silabs_sim3/sim3u/soc.c
Normal file
137
soc/silabs/silabs_sim3/sim3u/soc.c
Normal 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);
|
14
soc/silabs/silabs_sim3/sim3u/soc.h
Normal file
14
soc/silabs/silabs_sim3/sim3u/soc.h
Normal 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_ */
|
|
@ -55,3 +55,8 @@ family:
|
|||
- name: efr32bg27
|
||||
socs:
|
||||
- name: efr32bg27c140f768im40
|
||||
- name: silabs_sim3
|
||||
series:
|
||||
- name: sim3u
|
||||
socs:
|
||||
- name: sim3u167
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue