blob: 9544d2edff9f70171fe9aba92efac42b80e7b53b [file] [log] [blame]
/*
* 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--;
}
}
void soc_early_init_hook(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);
}