1 /*
2 * Copyright 2024 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_s32_mc_rgm
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/init.h>
11
12 /* Destructive Event Status Register */
13 #define MC_RGM_DES 0x0
14 #define MC_RGM_DES_F_POR_MASK BIT(0)
15 #define MC_RGM_DES_F_POR(v) FIELD_PREP(MC_RGM_DES_F_POR_MASK, (v))
16 /* Functional / External Reset Status Register */
17 #define MC_RGM_FES 0x8
18 #define MC_RGM_FES_F_EXR_MASK BIT(0)
19 #define MC_RGM_FES_F_EXR(v) FIELD_PREP(MC_RGM_FES_F_EXR_MASK, (v))
20 /* Functional Event Reset Disable Register */
21 #define MC_RGM_FERD 0xc
22 /* Functional Bidirectional Reset Enable Register */
23 #define MC_RGM_FBRE 0x10
24 /* Functional Reset Escalation Counter Register */
25 #define MC_RGM_FREC 0x14
26 #define MC_RGM_FREC_FREC_MASK GENMASK(3, 0)
27 #define MC_RGM_FREC_FREC(v) FIELD_PREP(MC_RGM_FREC_FREC_MASK, (v))
28 /* Functional Reset Escalation Threshold Register */
29 #define MC_RGM_FRET 0x18
30 #define MC_RGM_FRET_FRET_MASK GENMASK(3, 0)
31 #define MC_RGM_FRET_FRET(v) FIELD_PREP(MC_RGM_FRET_FRET_MASK, (v))
32 /* Destructive Reset Escalation Threshold Register */
33 #define MC_RGM_DRET 0x1c
34 #define MC_RGM_DRET_DRET_MASK GENMASK(3, 0)
35 #define MC_RGM_DRET_DRET(v) FIELD_PREP(MC_RGM_DRET_DRET_MASK, (v))
36 /* External Reset Control Register */
37 #define MC_RGM_ERCTRL 0x20
38 #define MC_RGM_ERCTRL_ERASSERT_MASK BIT(0)
39 #define MC_RGM_ERCTRL_ERASSERT(v) FIELD_PREP(MC_RGM_ERCTRL_ERASSERT_MASK, (v))
40 /* Reset During Standby Status Register */
41 #define MC_RGM_RDSS 0x24
42 #define MC_RGM_RDSS_DES_RES_MASK BIT(0)
43 #define MC_RGM_RDSS_DES_RES(v) FIELD_PREP(MC_RGM_RDSS_DES_RES_MASK, (v))
44 #define MC_RGM_RDSS_FES_RES_MASK BIT(1)
45 #define MC_RGM_RDSS_FES_RES(v) FIELD_PREP(MC_RGM_RDSS_FES_RES_MASK, (v))
46 /* Functional Reset Entry Timeout Control Register */
47 #define MC_RGM_FRENTC 0x28
48 #define MC_RGM_FRENTC_FRET_EN_MASK BIT(0)
49 #define MC_RGM_FRENTC_FRET_EN(v) FIELD_PREP(MC_RGM_FRENTC_FRET_EN_MASK, (v))
50 #define MC_RGM_FRENTC_FRET_TIMEOUT_MASK GENMASK(31, 1)
51 #define MC_RGM_FRENTC_FRET_TIMEOUT(v) FIELD_PREP(MC_RGM_FRENTC_FRET_TIMEOUT_MASK, (v))
52 /* Low Power Debug Control Register */
53 #define MC_RGM_LPDEBUG 0x2c
54 #define MC_RGM_LPDEBUG_LP_DBG_EN_MASK BIT(0)
55 #define MC_RGM_LPDEBUG_LP_DBG_EN(v) FIELD_PREP(MC_RGM_LPDEBUG_LP_DBG_EN_MASK, (v))
56
57 #define MC_RGM_TIMEOUT_US 50000U
58
59 /* Handy accessors */
60 #define REG_READ(r) sys_read32((mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
61 #define REG_WRITE(r, v) sys_write32((v), (mem_addr_t)(DT_INST_REG_ADDR(0) + (r)))
62
mc_rgm_clear_reset_status(uint32_t reg)63 static int mc_rgm_clear_reset_status(uint32_t reg)
64 {
65 bool timeout;
66
67 /*
68 * Register bits are cleared on write 1 if the triggering event has already
69 * been cleared at the source
70 */
71 timeout = !WAIT_FOR(REG_READ(reg) == 0U, MC_RGM_TIMEOUT_US, REG_WRITE(reg, 0xffffffff));
72 return timeout ? -ETIMEDOUT : 0U;
73 }
74
mc_rgm_init(const struct device * dev)75 static int mc_rgm_init(const struct device *dev)
76 {
77 int err = 0;
78 uint32_t rst_status;
79
80 ARG_UNUSED(dev);
81
82 /*
83 * MC_RGM_FES must be cleared before writing 1 to any of the fields in MC_RGM_FERD,
84 * otherwise an interrupt request may occur
85 */
86 rst_status = REG_READ(MC_RGM_FES);
87 if (rst_status != 0U) {
88 err = mc_rgm_clear_reset_status(MC_RGM_FES);
89 if (err) {
90 return err;
91 }
92 }
93
94 /* All functional reset sources generate a reset event */
95 REG_WRITE(MC_RGM_FERD, 0U);
96
97 rst_status = REG_READ(MC_RGM_DES);
98 if ((DT_INST_PROP(0, func_reset_threshold) != 0U) && (rst_status != 0U)) {
99 /* MC_RGM_FRET value is reset on power-on and any destructive reset */
100 REG_WRITE(MC_RGM_FRET, MC_RGM_FRET_FRET(DT_INST_PROP(0, func_reset_threshold)));
101 } else {
102 REG_WRITE(MC_RGM_FRET, MC_RGM_FRET_FRET(0U));
103 }
104
105 if ((DT_INST_PROP(0, dest_reset_threshold) != 0U) &&
106 (FIELD_GET(MC_RGM_DES_F_POR_MASK, rst_status) != 0U)) {
107 /* MC_RGM_DRET value is reset only on power-on reset */
108 REG_WRITE(MC_RGM_DRET, MC_RGM_DRET_DRET(DT_INST_PROP(0, dest_reset_threshold)));
109 } else {
110 REG_WRITE(MC_RGM_DRET, MC_RGM_DRET_DRET(0U));
111 }
112
113 /* Clear destructive reset status to avoid persisting it across resets */
114 err = mc_rgm_clear_reset_status(MC_RGM_DES);
115 if (err) {
116 return err;
117 }
118
119 return err;
120 }
121
122 DEVICE_DT_INST_DEFINE(0, mc_rgm_init, NULL, NULL, 0, PRE_KERNEL_1, 1, NULL);
123