1 /*
2 * Copyright (c) 2024 GARDENA GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "soc.h"
8
9 #include <zephyr/device.h>
10 #include <zephyr/init.h>
11 #include <zephyr/irq.h>
12
13 #include <SI32_CLKCTRL_A_Type.h>
14 #include <SI32_PBCFG_A_Type.h>
15 #include <SI32_PBSTD_A_Type.h>
16 #include <SI32_RSTSRC_A_Type.h>
17 #include <SI32_VMON_A_Type.h>
18 #include <SI32_WDTIMER_A_Type.h>
19 #include <si32_device.h>
20 #include <silabs_crossbar_config.h>
21
gpio_init(void)22 static void gpio_init(void)
23 {
24 /* After a device reset, all crossbars enter a disabled default reset state, causing all
25 * port bank pins into a high impedance digital input mode.
26 */
27
28 /* Enable clocks that we need in any case */
29 SI32_CLKCTRL_A_enable_apb_to_modules_0(
30 SI32_CLKCTRL_0, SI32_CLKCTRL_A_APBCLKG0_PB0 | SI32_CLKCTRL_A_APBCLKG0_FLASHCTRL0);
31
32 /* Enable misc clocks.
33 * We may or may nor need all of that but it includes some basics like
34 * LOCK0, WDTIMER0 and DMA. Doing it here prevents the actual drivers
35 * needing to know whoelse needs one of these clocks.
36 */
37 SI32_CLKCTRL_A_enable_apb_to_modules_1(
38 SI32_CLKCTRL_0, SI32_CLKCTRL_A_APBCLKG1_MISC0 | SI32_CLKCTRL_A_APBCLKG1_MISC1);
39 SI32_CLKCTRL_A_enable_ahb_to_dma_controller(SI32_CLKCTRL_0);
40
41 /* Apply pinctrl gpio settings */
42 SI32_PBSTD_A_write_pins_high(SI32_PBSTD_0, PORTBANK_0_PINS_HIGH);
43 SI32_PBSTD_A_write_pins_low(SI32_PBSTD_0, PORTBANK_0_PINS_LOW);
44 SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_0, PORTBANK_0_PINS_DIGITAL_INPUT);
45 SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_0, PORTBANK_0_PINS_PUSH_PULL_OUTPUT);
46 SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_0, PORTBANK_0_PINS_ANALOG);
47
48 SI32_PBSTD_A_write_pins_high(SI32_PBSTD_1, PORTBANK_1_PINS_HIGH);
49 SI32_PBSTD_A_write_pins_low(SI32_PBSTD_1, PORTBANK_1_PINS_LOW);
50 SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_1, PORTBANK_1_PINS_DIGITAL_INPUT);
51 SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_1, PORTBANK_1_PINS_PUSH_PULL_OUTPUT);
52 SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_1, PORTBANK_1_PINS_ANALOG);
53
54 SI32_PBSTD_A_write_pins_high(SI32_PBSTD_2, PORTBANK_2_PINS_HIGH);
55 SI32_PBSTD_A_write_pins_low(SI32_PBSTD_2, PORTBANK_2_PINS_LOW);
56 SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_2, PORTBANK_2_PINS_DIGITAL_INPUT);
57 SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_2, PORTBANK_2_PINS_PUSH_PULL_OUTPUT);
58 SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_2, PORTBANK_2_PINS_ANALOG);
59
60 SI32_PBSTD_A_write_pins_high(SI32_PBSTD_3, PORTBANK_3_PINS_HIGH);
61 SI32_PBSTD_A_write_pins_low(SI32_PBSTD_3, PORTBANK_3_PINS_LOW);
62 SI32_PBSTD_A_set_pins_digital_input(SI32_PBSTD_3, PORTBANK_3_PINS_DIGITAL_INPUT);
63 SI32_PBSTD_A_set_pins_push_pull_output(SI32_PBSTD_3, PORTBANK_3_PINS_PUSH_PULL_OUTPUT);
64 SI32_PBSTD_A_set_pins_analog(SI32_PBSTD_3, PORTBANK_3_PINS_ANALOG);
65
66 /* Configure skips */
67 SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_0, PORTBANK_0_SKIPEN_VALUE);
68 SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_1, PORTBANK_1_SKIPEN_VALUE);
69 SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_2, PORTBANK_2_SKIPEN_VALUE);
70 SI32_PBSTD_A_write_pbskipen(SI32_PBSTD_3, PORTBANK_3_SKIPEN_VALUE);
71
72 /* Configure crossbars */
73 SI32_PBCFG_A_enable_xbar0l_peripherals(SI32_PBCFG_0, CROSSBAR_0_CONFIG & 0xFFFFFFFF);
74 SI32_PBCFG_A_enable_xbar0h_peripherals(SI32_PBCFG_0,
75 (CROSSBAR_0_CONFIG >> 32) & 0xFFFFFFFF);
76 SI32_PBCFG_A_enable_xbar1_peripherals(SI32_PBCFG_0, CROSSBAR_1_CONFIG & 0xFFFFFFFF);
77
78 /* Enable crossbars */
79 SI32_PBCFG_A_enable_crossbar_0(SI32_PBCFG_0);
80 SI32_PBCFG_A_enable_crossbar_1(SI32_PBCFG_0);
81 }
82
vddlow_irq_handler(const struct device * dev)83 static void vddlow_irq_handler(const struct device *dev)
84 {
85 ARG_UNUSED(dev);
86
87 /* nothing to do here, we just don't want any spurious interrupts */
88 }
89
vmon_init(void)90 static void vmon_init(void)
91 {
92 /* VMON must be enabled for flash write/erase support */
93
94 NVIC_ClearPendingIRQ(VDDLOW_IRQn);
95
96 IRQ_CONNECT(VDDLOW_IRQn, 0, vddlow_irq_handler, NULL, 0);
97 irq_enable(VDDLOW_IRQn);
98
99 SI32_VMON_A_enable_vdd_supply_monitor(SI32_VMON_0);
100 SI32_VMON_A_enable_vdd_low_interrupt(SI32_VMON_0);
101 SI32_VMON_A_select_vdd_standard_threshold(SI32_VMON_0);
102 }
103
busy_delay(uint32_t cycles)104 __no_optimization static void busy_delay(uint32_t cycles)
105 {
106 while (cycles) {
107 cycles--;
108 }
109 }
110
soc_early_init_hook(void)111 void soc_early_init_hook(void)
112 {
113 uint32_t key;
114
115 key = irq_lock();
116
117 /* The watchdog may be enabled already so we have to disable it */
118 SI32_WDTIMER_A_reset_counter(SI32_WDTIMER_0);
119 SI32_WDTIMER_A_stop_counter(SI32_WDTIMER_0);
120 SI32_RSTSRC_A_disable_watchdog_timer_reset_source(SI32_RSTSRC_0);
121
122 /* Since a hardware reset affects the debug hardware as well, this makes it easier to
123 * recover from a broken firmware.
124 *
125 * For details, see erratum #H2 in the document "SiM3U1xx and SiM3C1xx Revision B Errata".
126 */
127 busy_delay(3000000);
128
129 gpio_init();
130 vmon_init();
131
132 irq_unlock(key);
133 }
134