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