mirror of
https://github.com/CTCaer/hekate
synced 2024-12-22 11:21:23 +00:00
bdk: timer: add timer/watchdog driver
This commit is contained in:
parent
b65b2d7f71
commit
061e10152f
6 changed files with 192 additions and 66 deletions
7
Makefile
7
Makefile
|
@ -31,9 +31,10 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
|
||||||
# Hardware.
|
# Hardware.
|
||||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
bpmp.o ccplex.o clock.o di.o gpio.o i2c.o irq.o mc.o sdram.o \
|
bpmp.o ccplex.o clock.o di.o i2c.o irq.o timer.o \
|
||||||
pinmux.o pmc.o se.o smmu.o tsec.o uart.o \
|
mc.o sdram.o minerva.o \
|
||||||
fuse.o kfuse.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 \
|
sdmmc.o sdmmc_driver.o emmc.o sd.o emummc.o \
|
||||||
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
bq24193.o max17050.o max7762x.o max77620-rtc.o \
|
||||||
hw_init.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/hw_init.h>
|
||||||
#include <soc/i2c.h>
|
#include <soc/i2c.h>
|
||||||
#include <soc/pmc.h>
|
#include <soc/pmc.h>
|
||||||
|
#include <soc/timer.h>
|
||||||
#include <soc/t210.h>
|
#include <soc/t210.h>
|
||||||
#include <storage/sd.h>
|
#include <storage/sd.h>
|
||||||
#include <utils/util.h>
|
#include <utils/util.h>
|
||||||
|
|
||||||
#define USE_RTC_TIMER
|
#define USE_RTC_TIMER
|
||||||
|
|
||||||
extern volatile nyx_storage_t *nyx_str;
|
|
||||||
|
|
||||||
u8 bit_count(u32 val)
|
u8 bit_count(u32 val)
|
||||||
{
|
{
|
||||||
u8 cnt = 0;
|
u8 cnt = 0;
|
||||||
|
@ -103,51 +102,6 @@ u64 sqrt64(u64 num)
|
||||||
return square_root;
|
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)
|
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops)
|
||||||
{
|
{
|
||||||
for(u32 i = 0; i < num_ops; i++)
|
for(u32 i = 0; i < num_ops; i++)
|
||||||
|
@ -195,14 +149,14 @@ void panic(u32 val)
|
||||||
{
|
{
|
||||||
// Set panic code.
|
// Set panic code.
|
||||||
PMC(APBDEV_PMC_SCRATCH200) = val;
|
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)
|
// Disable SE.
|
||||||
usleep(1);
|
//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)
|
void power_set_state(power_state_t state)
|
||||||
|
@ -231,7 +185,7 @@ void power_set_state(power_state_t state)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POWER_OFF:
|
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);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_PWR_OFF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -246,7 +200,7 @@ void power_set_state(power_state_t state)
|
||||||
reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK;
|
reg |= MAX77620_ONOFFCNFG2_SFT_RST_WK;
|
||||||
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG2, reg);
|
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);
|
i2c_send_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_ONOFFCNFG1, MAX77620_ONOFFCNFG1_SFT_RST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,12 +89,6 @@ u64 sqrt64(u64 num);
|
||||||
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
void exec_cfg(u32 *base, const cfg_op_t *ops, u32 num_ops);
|
||||||
u32 crc32_calc(u32 crc, const u8 *buf, u32 len);
|
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 panic(u32 val);
|
||||||
void power_set_state(power_state_t state);
|
void power_set_state(power_state_t state);
|
||||||
void power_set_state_ex(void *param);
|
void power_set_state_ex(void *param);
|
||||||
|
|
|
@ -33,7 +33,8 @@ OBJS = $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
||||||
|
|
||||||
# Hardware.
|
# Hardware.
|
||||||
OBJS += $(addprefix $(BUILDDIR)/$(TARGET)/, \
|
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 \
|
fuse.o kfuse.o \
|
||||||
mc.o sdram.o minerva.o ramdisk.o \
|
mc.o sdram.o minerva.o ramdisk.o \
|
||||||
sdmmc.o sdmmc_driver.o emmc.o sd.o nx_emmc_bis.o \
|
sdmmc.o sdmmc_driver.o emmc.o sd.o nx_emmc_bis.o \
|
||||||
|
|
Loading…
Reference in a new issue