diff --git a/Makefile b/Makefile
index 1983aaf..d92bdf5 100755
--- a/Makefile
+++ b/Makefile
@@ -31,9 +31,10 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
# Hardware.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
- bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o mc.o sdram.o \
- pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
- fuse.o kfuse.o minerva.o \
+ bpmp.o ccplex.o clock.o di.o i2c.o irq.o timer.o \
+ mc.o sdram.o minerva.o \
+ gpio.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
+ fuse.o kfuse.o \
sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o \
bq24193.o max17050.o max7762x.o max77620-rtc.o \
hw_init.o \
diff --git a/bdk/soc/timer.c b/bdk/soc/timer.c
new file mode 100644
index 0000000..5c3338e
--- /dev/null
+++ b/bdk/soc/timer.c
@@ -0,0 +1,114 @@
+/*
+ * Timer/Watchdog driver for Tegra X1
+ *
+ * Copyright (c) 2019 CTCaer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#define EXCP_TYPE_ADDR 0x4003FFF8
+#define EXCP_TYPE_WDT 0x544457 // "WDT".
+
+u32 get_tmr_s()
+{
+ (void)RTC(APBDEV_RTC_MILLI_SECONDS);
+ return (u32)RTC(APBDEV_RTC_SECONDS);
+}
+
+u32 get_tmr_ms()
+{
+ // The registers must be read with the following order:
+ // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
+ return (u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
+}
+
+u32 get_tmr_us()
+{
+ return (u32)TMR(TIMERUS_CNTR_1US);
+}
+
+void msleep(u32 ms)
+{
+#ifdef USE_RTC_TIMER
+ u32 start = (u32)RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
+ // Casting to u32 is important!
+ while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
+ ;
+#else
+ bpmp_msleep(ms);
+#endif
+}
+
+void usleep(u32 us)
+{
+#ifdef USE_RTC_TIMER
+ u32 start = (u32)TMR(TIMERUS_CNTR_1US);
+
+ // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
+ if ((start + us) < start)
+ bpmp_usleep(us);
+ else
+ while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
+ ;
+#else
+ bpmp_usleep(us);
+#endif
+}
+
+void timer_usleep(u32 us)
+{
+ TMR(TIMER_TMR8_TMR_PTV) = TIMER_EN | us;
+
+ irq_wait_event(IRQ_TMR8);
+
+ TMR(TIMER_TMR8_TMR_PCR) = TIMER_INTR_CLR;
+}
+
+void watchdog_start(u32 us, u32 mode)
+{
+ // WDT4 is for BPMP.
+ TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
+ TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN | us;
+ TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | mode;
+ TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
+}
+
+void watchdog_end()
+{
+ // WDT4 is for BPMP.
+ TMR(TIMER_TMR9_TMR_PTV) = 0;
+ TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
+ TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT; // Re-arm to clear any interrupts.
+ TMR(TIMER_WDT4_COMMAND) = TIMER_CNT_DISABLE;
+}
+
+void watchdog_handle()
+{
+ // Disable watchdog and clear its interrupts.
+ watchdog_end();
+
+ // Set watchdog magic.
+ *(u32 *)EXCP_TYPE_ADDR = EXCP_TYPE_WDT;
+}
+
+bool watchdog_fired()
+{
+ // Return if watchdog got fired. User handles clearing.
+ return (*(u32 *)EXCP_TYPE_ADDR == EXCP_TYPE_WDT);
+}
\ No newline at end of file
diff --git a/bdk/soc/timer.h b/bdk/soc/timer.h
new file mode 100644
index 0000000..6fcdb36
--- /dev/null
+++ b/bdk/soc/timer.h
@@ -0,0 +1,62 @@
+/*
+ * Timer/Watchdog driver for Tegra X1
+ *
+ * Copyright (c) 2019 CTCaer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include
+
+// TMR registers.
+#define TIMERUS_CNTR_1US (0x10 + 0x0)
+#define TIMERUS_USEC_CFG (0x10 + 0x4)
+#define TIMER_TMR8_TMR_PTV 0x78
+#define TIMER_TMR9_TMR_PTV 0x80
+#define TIMER_PER_EN BIT(30)
+#define TIMER_EN BIT(31)
+#define TIMER_TMR8_TMR_PCR 0x7C
+#define TIMER_TMR9_TMR_PCR 0x8C
+#define TIMER_INTR_CLR BIT(30)
+
+// WDT registers.
+#define TIMER_WDT4_CONFIG (0x100 + 0x80)
+#define TIMER_SRC(TMR) ((TMR) & 0xF)
+#define TIMER_PER(PER) (((PER) & 0xFF) << 4)
+#define TIMER_IRQENABL_EN BIT(12)
+#define TIMER_FIQENABL_EN BIT(13)
+#define TIMER_SYSRESET_EN BIT(14)
+#define TIMER_PMCRESET_EN BIT(15)
+#define TIMER_WDT4_COMMAND (0x108 + 0x80)
+#define TIMER_START_CNT BIT(0)
+#define TIMER_CNT_DISABLE BIT(1)
+#define TIMER_WDT4_UNLOCK_PATTERN (0x10C + 0x80)
+#define TIMER_MAGIC_PTRN 0xC45A
+
+u32 get_tmr_us();
+u32 get_tmr_ms();
+u32 get_tmr_s();
+void usleep(u32 us);
+void msleep(u32 ms);
+
+void timer_usleep(u32 us);
+
+void watchdog_start(u32 us, u32 mode);
+void watchdog_end();
+void watchdog_handle();
+bool watchdog_fired();
+
+#endif
diff --git a/bdk/utils/util.c b/bdk/utils/util.c
index d249f9d..623d8e4 100644
--- a/bdk/utils/util.c
+++ b/bdk/utils/util.c
@@ -24,14 +24,13 @@
#include
#include
#include
+#include
#include
#include
#include
#define USE_RTC_TIMER
-extern volatile nyx_storage_t *nyx_str;
-
u8 bit_count(u32 val)
{
u8 cnt = 0;
@@ -103,51 +102,6 @@ u64 sqrt64(u64 num)
return square_root;
}
-u32 get_tmr_s()
-{
- return RTC(APBDEV_RTC_SECONDS);
-}
-
-u32 get_tmr_ms()
-{
- // The registers must be read with the following order:
- // RTC_MILLI_SECONDS (0x10) -> RTC_SHADOW_SECONDS (0xC)
- return (RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000));
-}
-
-u32 get_tmr_us()
-{
- return TMR(TIMERUS_CNTR_1US);
-}
-
-void msleep(u32 ms)
-{
-#ifdef USE_RTC_TIMER
- u32 start = RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000);
- // Casting to u32 is important!
- while (((u32)(RTC(APBDEV_RTC_MILLI_SECONDS) + (RTC(APBDEV_RTC_SHADOW_SECONDS) * 1000)) - start) <= ms)
- ;
-#else
- bpmp_msleep(ms);
-#endif
-}
-
-void usleep(u32 us)
-{
-#ifdef USE_RTC_TIMER
- u32 start = TMR(TIMERUS_CNTR_1US);
-
- // Check if timer is at upper limits and use BPMP sleep so it doesn't wake up immediately.
- if ((start + us) < start)
- bpmp_usleep(us);
- else
- while ((u32)(TMR(TIMERUS_CNTR_1US) - start) <= us) // Casting to u32 is important!
- ;
-#else
- bpmp_usleep(us);
-#endif
-}
-
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
{
for(u32 i = 0; i < num_ops; i++)
@@ -195,14 +149,14 @@ void panic(u32 val)
{
// Set panic code.
PMC(APBDEV_PMC_SCRATCH200) = val;
- //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
- TMR(TIMER_WDT4_UNLOCK_PATTERN) = TIMER_MAGIC_PTRN;
- TMR(TIMER_TMR9_TMR_PTV) = TIMER_EN | TIMER_PER_EN;
- TMR(TIMER_WDT4_CONFIG) = TIMER_SRC(9) | TIMER_PER(1) | TIMER_PMCRESET_EN;
- TMR(TIMER_WDT4_COMMAND) = TIMER_START_CNT;
- while (true)
- usleep(1);
+ // Disable SE.
+ //PMC(APBDEV_PMC_CRYPTO_OP) = PMC_CRYPTO_OP_SE_DISABLE;
+
+ // Immediately cause a full system reset.
+ watchdog_start(0, TIMER_PMCRESET_EN);
+
+ while (true);
}
void power_set_state(power_state_t state)
@@ -231,7 +185,7 @@ void power_set_state(power_state_t state)
break;
case POWER_OFF:
- // Initiate power down sequence and do not generate a reset (regulators retain state).
+ // Initiate power down sequence and do not generate a reset (regulators retain state after POR).
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
break;
@@ -246,7 +200,7 @@ void power_set_state(power_state_t state)
reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK;
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg);
- // Initiate power down sequence and generate a reset (regulators' state resets).
+ // Initiate power down sequence and generate a reset (regulators' state resets after POR).
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST);
break;
}
diff --git a/bdk/utils/util.h b/bdk/utils/util.h
index d942f2d..57ef250 100644
--- a/bdk/utils/util.h
+++ b/bdk/utils/util.h
@@ -89,12 +89,6 @@ u64 sqrt64(u64 num);
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
u32 crc32_calc(u32 crc, const u8 *buf, u32 len);
-u32 get_tmr_us();
-u32 get_tmr_ms();
-u32 get_tmr_s();
-void usleep(u32 us);
-void msleep(u32 ms);
-
void panic(u32 val);
void power_set_state(power_state_t state);
void power_set_state_ex(void *param);
diff --git a/nyx/Makefile b/nyx/Makefile
index 0d5c152..9928a97 100644
--- a/nyx/Makefile
+++ b/nyx/Makefile
@@ -33,7 +33,8 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
# Hardware.
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
- bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
+ bpmp.o ccplex.o clock.o di.o i2c.o irq.o timer.o \
+ gpio.o pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
fuse.o kfuse.o \
mc.o sdram.o minerva.o ramdisk.o \
sdmmc.o sdmmc_driver.o emmc.o sd.o nx_emmc_bis.o \