Like my article on the SVC instruction, I intend to work with real hardware and summarize what I do and what I learn.
I am working with an RK3328 chip on an Orange Pi R1+ LTS board. I am using U-boot to network boot code I build. I have learned that the code runs at EL 2.
In the RK3328 we have a GIC-400, which corresponds to the GIC v2 specification. I see this device in all of my ARM boards, with one exception, which is the RK3399 which has a GIC-500 (corresponding to GIC v3).
I developed and satisfactory drive for the GIC-400 when I worked with the Allwinner H3 chip (which is aarch32). I intend to use that driver as a starting point for this work. I actually copied the driver from my Fir3 project (which is aarch64). I never got interrupts to work there, so I may simply be inheriting bugs and problems. I copied:
cp /u2/Projects/Fire3/Github/Timer/intcon_gic400.c gic.cA base address in this file needed to be changed. The sources for this project are: This project began by copying the files from my working SVC demo, adding gic.c, then getting it all to compile, calling gic_test(). So far it does not work.
I am double checking the GIC base addresses. The RK3328 TRM shows the base address for the GIC as a whole, but the CPU and DIST have different base addresses. In other systems I have seen the DIST is at offset 0 in this region, and the CPU is at offset 0x1000 -- but the gic document does not specify this. (And this is WRONG, see below.) It just says that the distributor and cpu interface base addresses are specified in the system memory map. The GIC chapter in the TRM is all but useless. The only piece of information in the single page is that it supports 128 hardware interrupts.
I take a look at the ATF sources and track down this file:
Projects/OrangePi/r1plus/sources/arm-trusted-firmware/plat/rockchip/rk3328/rk3328_def.hIn it, I find this:
#define GIC400_BASE 0xff810000 /* Base rk_platform compatible GIC memory map */ #define RK3328_GICD_BASE (GIC400_BASE + 0x1000) #define RK3328_GICC_BASE (GIC400_BASE + 0x2000) #define RK3328_GICR_BASE 0 /* no GICR in GIC-400 */Aha!! This should make a big difference. This information is nowhere present in the TRM.
Fixing these addresses does not yet get us results.
We try this first without setting VBAR_el2 (hoping that the vectors in U-Boot will catch the interrupt).
Then we try setting our own vectors, which worked for SVC and should report anything.
No results.
What the test is doing is to loop through all 16 SGI,
setting bits in the "sgi" register.
So we should see 16 interrupts, or at least the first one.
But we don't.
I discover that I need to call gic_cpu_init() along with gic_init().
This is because in a multicore system, each cpu needs to call this, whereas
gic_init() sets up the common registers in the distributor.
Still no results.
Is it possible that having 128 interrupts is important, and rearranges the registers?
I don't manage to find EL switching code in the ATF sources. No doubt it is there. I do find this in the U-boot sources:
Projects/OrangePi/r1plus/sources/u-boot/arch/arm/cpu/armv8/exception_level.c
/* Move into EL2 and keep running there */
armv8_switch_to_el2((uintptr_t)&non_secure_jmp, 0, 0, 0,
(uintptr_t)entry_non_secure, ES_TO_AARCH64);
The actual code is in transition.S and references a variety of macros.
The meat of things if found here in the macro armv8_switch_to_el2_m --
which is a full page of code. There is also a corresponding "to_el1" macro.
/u2/Projects/OrangePi/r1plus/sources/u-boot/arch/arm/include/asm/macro.hI may do this someday, but for now I am going to learn about interrupt routing between different EL levels and see if there is a simple way to reconfigure that at get interrupts at EL-2.
Easy enough now, but it stumped me several years ago and I laid my aarch64 projects aside until I was in the mood to focus on this for the week or so it took me to ramp up my memories of what I was doing.
The lesson is pretty basic, and something I have learned before. Don't be in a hurry. Don't assume too much. Take the time to read the documents and really understand things.
What gets in the way of doing just that is that there is so much to learn. I could for example get busy reading the 800 page PDF document on ATF (ARM trusted firmware). And I could get lost trying to really understand U-boot in detail. All these things are worthwhile, but you simply cannot dive down every rabbit hole. The trick is recognizing things that you really do need to take the time to work out.
A big help too is thinking. Many programmers spend too much time working and not enough time thinking. Working for a while, then taking time to think can be a big time saver.
Tom's Computer Info / tom@mmto.org