mirror of
https://github.com/CTCaer/hekate.git
synced 2024-12-24 21:16:19 +00:00
bdk: timer: add timer/watchdog driver
This commit is contained in:
parent
b65b2d7f71
commit
061e10152f
7
Makefile
7
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 \
|
||||
|
114
bdk/soc/timer.c
Normal file
114
bdk/soc/timer.c
Normal file
@ -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 <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 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);
|
||||
}
|
62
bdk/soc/timer.h
Normal file
62
bdk/soc/timer.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
// 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
|
@ -24,14 +24,13 @@
|
||||
#include <soc/hw_init.h>
|
||||
#include <soc/i2c.h>
|
||||
#include <soc/pmc.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <storage/sd.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user