| /* |
| * 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); |
| } |