Files
OmniNX-Installer-Payload/bdk/soc/timer.c
T
niklascfw 1b4a81239b Update BDK to hekate v6.5.5
Replaces the old vendored BDK with the one from hekate v6.5.5 (CTCaer's
2025/2026 refactors: sdmmc, SE, minerva v1.6, display, heap, return
value homogenisation). OmniNX additions re-applied on top:
bq24193_charger_connected() and jc_clear_input(); s_vprintf now ships
with the BDK.

Ported to the new API:
- sd_mount(), sdmmc_storage_* and ini_parse() now return 0 on success.
  The installer checked ini_parse() != 1, which would have made it miss
  manifest.ini and run every install as a clean install.
- SD helpers come from bdk/storage/sd.c (source/nx_sd.* removed),
  ffsystem.c from the BDK, diskio.c/ffconf.h from hekate (ffconf keeps
  the sd:/ volume prefix).
- minerva_init() needs the minerva storage; the installer still drops
  to 800 MHz afterwards.
- Payload launch follows hekate (sd_file_read, hw_deinit); coreboot
  path removed upstream.
- Stack moved to 0x96000000: the old 0x83100000 is inside the new heap.
- GUI/USB/compression parts of the BDK are not built.
2026-11-12 23:17:18 +01:00

124 lines
3.1 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <soc/bpmp.h>
#include <soc/irq.h>
#include <soc/timer.h>
#include <soc/t210.h>
#include <utils/types.h>
#define EXCP_TYPE_ADDR 0x4003FF18
#define EXCP_TYPE_WDT 0x544457 // "WDT".
#define USE_RTC_TIMER
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
}
// Instruction wait loop. Each loop is 3 cycles (SUBS+BGT). Usage: isleep(ILOOP(instr)). Base 408MHz: 7.35ns.
void __attribute__((target("arm"))) isleep(u32 is)
{
asm volatile( "0:" "SUBS %[is_cnt], #1;" "BGT 0b;" : [is_cnt] "+r" (is));
}
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;
TMR(TIMER_TMR9_TMR_PCR) = TIMER_INTR_CLR;
}
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);
}