Direct register access to Timer

Is a direct access to the timer registers, e.g. TMR11 possible from bare metal applications? It looks like access is somehow restricted. Is the access secured by the SCR register? How can I modify them to be able to have direct access to the timer register?
My hardware is a Jetson AGX Orin Development Kit 32GB and the installed software is Jetson Linux version 36.2 DP.

What I have done so far is to follow the TRM and configure TMR11 (see attached code).
So I expected an interrupt after 1 second which I wanted to use to wait 1 second with assembler-function wfi.
Unfortunately I receive a write error exception whenever I set the ENABLE bit 31. I have also tried to read the microsecond timer register TSCUS. The result was zero every time.

The background is a university research to find out if it is possible to boot another OS before Linux and run it side by side with the provided Linux. This has been done years ago successfully with an old Jetson TK1 board.
I was able to start a bare metal application which is a very simple kernel. It is loaded by a uefi elf-bootloader that can load code on other processor cores (core 11 on CCPLEX in my case) in non-blocking mode. The kernel has a default assembler processor configuration (stack pointer, vector table with simple exception and interrupt handling, HCR and SCTLR register configuration) and jumps to main, where I write a counter value to a shared memory region in a loop.
The timer is needed to be able to write the counter on time based values and read these values in Linux to see if the dummy kernel is still running or not.

I can imagine that such approaches are not part of the scope of support, but I hope that answering my question might help other users who find themselves in a similar situation.

You can find a debug log file and part of source of source code from kernel in the attachments.

boot-2024-03-16_23-11.log (156.9 KB)

Best regards

Some register cannot be directly accessed. For the use-case, maybe you can use PWM. Please refer to the topics and try:
Unable to generate PWM with Nvidia Jetson AGX Orin Development Kit - #6 by KevinFFF
Using simple sometimes doesn't work

Hello DaneLLL,

Thanks for your reply.
Are there detailed information about which registers cannot be accessed directly?
The TRM describes many registers including timer and for my understanding it should be possible to use them, shouldn’t it?
I couldn’t find any information about any restrictions of access in the documentation except “SCR Protection”. But it is not described how to use SCR protected registers.

I just want to be sure I don’t make any mistakes. If you say that timer and/or SCR protected registers are not intended for customer use, I will take that information into account and forward it.

About your suggestion to try PWM: Does it mean, I can configure Pins for time based signals through a direct access to GPIO registers?

Best regards


Has anybody tried out to access NVIDIA registers directly from a baremetal application?
I was able to successfully access ARM registers for processor configuration.
But I still can’t read/write NVIDIA registers.

Maybe there is someone who knows how this could be done and shares information with me?
That would be great!

Due to security concern, the registers cannot be accessed directly. Please share detail about the use-case. Would like to know more information about the use-case and we can suggest next.

as I have written before, the use case is side-by-side running of Nvidia Linux with an AUTOSAR compliant OS (university research project).
I managed to boot into a baremetal application (represents AUTOSAR OS) from a self-written UEFI-Bootloader and could also boot into NVIDIA Linux immediately thereafter with the effect that both OS can run simultaneously on the hardware. At the moment the baremetal application just writes some values into shared memory which I can read from Linux.
But the next step is to manage the interrupts and timer of the system. In order to that I need direct access to the timer and interrupts to configure them manually and split them up to both OS.

Can anybody give suggestions how to access NVIDIA registers directly?

Please change like below for all offsets and try again.
tmr11_base_address = 0x02140000;
tke_top_timer_tmr11_tmrcr_0 = tmr11_base_address + 0xc0000;

top_tke_base_address = 0x02080000;
tke_top_timer_tmr11_tmrcr_0 = top_tke_base_address + 0xc0000;

I tried your suggested settings with no success!
I received a translation fault, second level (see attached log file).

boot-2024-04-18_01-16.log (153.3 KB)

I tried many settings in my bare metal environment and from my point of view the reason for not be able to access any of MMIO registers (including Timer register) could be one of the following:

  • SCR Protection blocks access to MMIO registers
  • Memory encryption blocks access to MMIO registers
  • Processors MMU needs special configuration of memory translation for MMIO registers

Can you please check and confirm or give further suggestions?

I have tried to reconfigure the MMU settings accroding the ARM documentation “Bare-metal Boot Code for ARMv8-A Processors”, but failed unfortunately.

Because I started my kernel from UEFI, I configured all in EL2, but EL1 didn’t work either.

I also tried to display the contents of the I/O register by using UEFI Shell command dmem 0x021400000, which unfortunately also failed.

Next I tried the boot code regarding MMU configuration of the ArmTrustedFirmware from official NVIDIA sources, which failed again.

So what could be reason for this behavior? Is it possible that I have to reconfigure the device tree?

Any ideas are appreciated!

I found a solution and would like to share it with anyone who is interested and may be facing a similar problem.

The main issue was that the memory mapped device registers mentioned were not configured in the address translation tables.
In the UEFI environment I am in EL2, in which the MMU and also the address translation tables from L0 to L3 have already been preconfigured by the system.
First I tried to reconfigure the MMU and mapped the entire memory space into new address translation tables.
To do this, however, all entries in the address translation tables from L0 to L3 as well as the TLB (Translation Lookaside Buffer) would have to be unvalidated and cleared, which in my case led to conflicts with the existing configuration and to recursive exceptions.

The solution was to look at the existing address translation tables starting from the address in TTBR0_EL2 and fill in the missing entries for device memory.

Below I give an example of configuring the console (UARTC) with the address 0xC280000 in L3 and granularity of 4KB.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.