From: John Tsiombikas Date: Sat, 14 Nov 2020 08:10:49 +0000 (+0200) Subject: interrupts, timers, under construction X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=rpikern;a=commitdiff_plain;h=574147e84aafb61db3cf8b595d2a12ce5ba160de;ds=sidebyside interrupts, timers, under construction --- diff --git a/Makefile b/Makefile index b4aa3a5..bb0b2bc 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ endif warn = -pedantic -Wall dbg = -g inc = -Isrc -Isrc/libc -gccopt = -marm -fno-pic -ffreestanding -nostdinc -ffast-math -fno-math-errno +gccopt = -marm -fno-pic -ffreestanding -nostdinc -ffast-math -fno-math-errno -MMD #arch = -mcpu=arm1176jzf-s arch = -mcpu=cortex-a7 @@ -37,10 +37,6 @@ $(elf): $(obj) -include $(dep) -%.d: %.c - @echo 'gen dep $@ ...' - @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ - .PHONY: clean clean: rm -f $(obj) $(bin) $(elf) link.map @@ -55,7 +51,7 @@ run: $(elf) .PHONY: disasm disasm: $(elf) - $(toolprefix)objdump -d $< + $(toolprefix)objdump -D $< .PHONY: install install: $(bin) diff --git a/doc/notes.md b/doc/notes.md index 5a372d8..30dc050 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -1,5 +1,8 @@ Raspberry Pi2 notes =================== + +Memory access ordering +---------------------- Accessing different peripherals migh return results out of order. See bcm2835 spec section 1.3. Use memory barriers as follows: - place write barrier before the first write to a peripheral @@ -10,6 +13,12 @@ Multiple accesses to the same peripheral in a row do not require barriers. Interrupt handlers should have a read barrier before their first read, and end with a write barrier. +Cache coherency +--------------- +Two types of cache management: + - cache cleaning (write-back caches) + - cache invalidation (all caches) + Cache clean and invalidate operations are also needed before the GPU can see our command buffers... see: https://github.com/rsta2/uspi/blob/38eaff4f715643a9/lib/synchronize.c diff --git a/rpikern.ld b/rpikern.ld index 3843a15..ddec699 100644 --- a/rpikern.ld +++ b/rpikern.ld @@ -1,4 +1,8 @@ SECTIONS { + .vect : { + * (.vect*); + } + . = 0x00008000; _stacktop = .; _kern_start = .; diff --git a/src/asm.h b/src/asm.h index 425a8ee..fc1075d 100644 --- a/src/asm.h +++ b/src/asm.h @@ -1,8 +1,8 @@ #ifndef ASM_H_ #define ASM_H_ -#define enable_intr() asm volatile ("cpsie i") -#define disable_intr() asm volatile ("cpsid i") +#define enable_intr() asm volatile ("cpsie if") +#define disable_intr() asm volatile ("cpsid if") #define mem_barrier() asm volatile ("dmb" ::: "memory") #define delay(x) asm volatile ( \ diff --git a/src/intr.c b/src/intr.c new file mode 100644 index 0000000..f9b0f1f --- /dev/null +++ b/src/intr.c @@ -0,0 +1,51 @@ +#include "rpi.h" +#include "rpi_ioreg.h" +#include "asm.h" + +void enable_arm_irq(int irq) +{ + mem_barrier(); + if(irq == IRQ_TIMER) { + IRQ_FIQCTL_REG = IRQ_FIQCTL_SELARM(IRQ_TIMER) | IRQ_FIQCTL_ENABLE; + } else { + IRQ_ENABLE0_REG |= 1 << irq; + } + mem_barrier(); +} + +void disable_arm_irq(int irq) +{ + mem_barrier(); + if(irq == IRQ_TIMER) { + IRQ_FIQCTL_REG = 0; + } else { + IRQ_ENABLE0_REG &= ~(1 << irq); + } + mem_barrier(); +} + +void enable_gpu_irq(int irq) +{ + mem_barrier(); + if(irq == IRQ_GPU_TIMER1) { + IRQ_FIQCTL_REG = IRQ_FIQCTL_SELGPU(IRQ_GPU_TIMER1) | IRQ_FIQCTL_ENABLE; + } else if(irq < 32) { + IRQ_ENABLE1_REG |= 1 << irq; + } else { + IRQ_ENABLE2_REG |= 1 << (irq - 32); + } + mem_barrier(); +} + +void disable_gpu_irq(int irq) +{ + mem_barrier(); + if(irq == IRQ_GPU_TIMER1) { + IRQ_FIQCTL_REG = 0; + } else if(irq < 32) { + IRQ_ENABLE1_REG &= ~(1 << irq); + } else { + IRQ_ENABLE2_REG &= ~(1 << (irq - 32)); + } + mem_barrier(); +} diff --git a/src/intr.h b/src/intr.h new file mode 100644 index 0000000..c3e7284 --- /dev/null +++ b/src/intr.h @@ -0,0 +1,10 @@ +#ifndef INTR_H_ +#define INTR_H_ + +void enable_arm_irq(int irq); +void disable_arm_irq(int irq); + +void enable_gpu_irq(int irq); +void disable_gpu_irq(int irq); + +#endif /* INTR_H_ */ diff --git a/src/intrasm.s b/src/intrasm.s new file mode 100644 index 0000000..4ef2cd0 --- /dev/null +++ b/src/intrasm.s @@ -0,0 +1,28 @@ + .code 32 + + .section .vect + .extern startup +intr_vector: + b startup + b intr_entry_undef + b intr_entry_swi + b intr_entry_iabort + b intr_entry_dabort + b intr_entry_irq + + @ FIQ entry point used for timer interrupts + .extern num_ticks +intr_entry_fiq: + ldr r9, =num_ticks + ldr r8, [r9] + add r8, #1 + str r8, [r9] + subs pc, lr, #4 + + .text +intr_entry_undef: +intr_entry_swi: +intr_entry_iabort: +intr_entry_dabort: +intr_entry_irq: + subs pc, lr, #4 diff --git a/src/main.c b/src/main.c index 8bab5a1..18ed725 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,9 @@ #include "rpi.h" #include "contty.h" #include "serial.h" +#include "timer.h" #include "video.h" +#include "intr.h" void dbgled(int x); @@ -30,9 +32,13 @@ int main(void) printf("Main RAM base: %x, size: %u bytes\n", rpi_mem_base, rpi_mem_size); printf("Video RAM base: %x, size: %u bytes\n", rpi_vmem_base, rpi_vmem_size); + timer_init(); video_init(); + enable_intr(); + printf("Going interactive\n"); + for(;;) { while(ser_pending()) { int c = getchar(); @@ -99,6 +105,9 @@ static void cmdrun(char *cmd) cur_y -= 10; video_scroll(cur_x, cur_y); + } else if(strcmp(cmd, "ticks") == 0) { + printf("%lu\n", num_ticks); + } else if(strcmp(cmd, "help") == 0) { printf("help not implemented yet\n"); } else if(strcmp(cmd, "ver") == 0) { diff --git a/src/rpi.c b/src/rpi.c index 68f07e6..ec18e96 100644 --- a/src/rpi.c +++ b/src/rpi.c @@ -1,70 +1,12 @@ #include #include #include "rpi.h" +#include "rpi_ioreg.h" #include "sysctl.h" #include "asm.h" #include "serial.h" #include "debug.h" -#define IOREG(offs) (*(volatile uint32_t*)(rpi_iobase | offs)) - -/* System timer */ -#define STM_CTL_REG IOREG(0x3000) -#define STM_STAT_REG STM_CTL_REG -#define STM_LCNT_REG IOREG(0x3004) -#define STM_HCNT_REG IOREG(0x3008) -#define STM_CMP0_REG IOREG(0x300c) -#define STM_CMP1_REG IOREG(0x3010) -#define STM_CMP2_REG IOREG(0x3014) -#define STM_CMP3_REG IOREG(0x3018) - -#define STMCTL_M0 1 -#define STMCTL_M1 2 -#define STMCTL_M2 4 -#define STMCTL_M3 8 - -/* TIMER */ -#define TM_LOAD_REG IOREG(0xb400) -#define TM_VALUE_REG IOREG(0xb404) -#define TM_CTL_REG IOREG(0xb408) -#define TM_ICLR_REG IOREG(0xb40c) -#define TM_IRAW_REG IOREG(0xb410) -#define TM_IMSK_REG IOREG(0xb414) -#define TM_RELOAD_REG IOREG(0xb418) -#define TM_PREDIV_REG IOREG(0xb41c) -#define TM_COUNT_REG IOREG(0xb420) - -#define TMCTL_23BIT 0x000002 -#define TMCTL_DIV16 0x000004 -#define TMCTL_DIV256 0x000008 -#define TMCTL_DIV1 0x00000c -#define TMCTL_IEN 0x000020 -#define TMCTL_EN 0x000080 -#define TMCTL_DBGHALT 0x000100 -#define TMCTL_CNTEN 0x000200 - -#define TMCTL_PRESCALER(x) (((uint32_t)(x) & 0xff) << 16) - -/* watchdog */ -#define PM_RSTC_REG IOREG(0x10001c) -#define PM_WDOG_REG IOREG(0x100024) - -#define PM_PASSWD 0x5a000000 -#define PMRSTC_WRCFG_FULL_RESET 0x00000020 -#define PMRSTC_WRCFG_CLEAR 0xffffffcf - -/* MAILBOX */ -#define MBOX_READ_REG IOREG(0xb880) -#define MBOX_POLL_REG IOREG(0xb890) -#define MBOX_SENDER_REG IOREG(0xb894) -#define MBOX_STATUS_REG IOREG(0xb898) -#define MBOX_CFG_REG IOREG(0xb89c) -#define MBOX_WRITE_REG IOREG(0xb8a0) - -/* the full bit is set when there's no space to append messages */ -#define MBOX_STAT_FULL 0x80000000 -/* the empty bit is set when there are no pending messages to be read */ -#define MBOX_STAT_EMPTY 0x40000000 static int detect(void); diff --git a/src/rpi.h b/src/rpi.h index 57a1cf7..6f5e37f 100644 --- a/src/rpi.h +++ b/src/rpi.h @@ -26,6 +26,9 @@ #define RPI_TAG_GETFBPITCH 0x040008 #define RPI_TAG_SETFBOFFS 0x048009 #define RPI_TAG_GETFBOFFS 0x040009 +/* NOTE: for every new tag added, a new entry needs to be added to the tag + * buffer size struct in rpi.c + */ struct rpi_prop_header { uint32_t size; diff --git a/src/rpi_ioreg.h b/src/rpi_ioreg.h new file mode 100644 index 0000000..aca3a9f --- /dev/null +++ b/src/rpi_ioreg.h @@ -0,0 +1,133 @@ +#ifndef RPI_IOREG_H_ +#define RPI_IOREG_H_ + +#include "rpi.h" + +#define IOREG(offs) (*(volatile uint32_t*)(rpi_iobase | offs)) + +/* System timer */ +#define STM_CTL_REG IOREG(0x3000) +#define STM_STAT_REG STM_CTL_REG +#define STM_LCNT_REG IOREG(0x3004) +#define STM_HCNT_REG IOREG(0x3008) +#define STM_CMP0_REG IOREG(0x300c) +#define STM_CMP1_REG IOREG(0x3010) +#define STM_CMP2_REG IOREG(0x3014) +#define STM_CMP3_REG IOREG(0x3018) + +#define STMCTL_M0 1 +#define STMCTL_M1 2 +#define STMCTL_M2 4 +#define STMCTL_M3 8 + +/* TIMER */ +#define TM_LOAD_REG IOREG(0xb400) +#define TM_VALUE_REG IOREG(0xb404) +#define TM_CTL_REG IOREG(0xb408) +#define TM_ICLR_REG IOREG(0xb40c) +#define TM_IRAW_REG IOREG(0xb410) +#define TM_IMSK_REG IOREG(0xb414) +#define TM_RELOAD_REG IOREG(0xb418) +#define TM_PREDIV_REG IOREG(0xb41c) +#define TM_COUNT_REG IOREG(0xb420) + +#define TMCTL_23BIT 0x000002 +#define TMCTL_DIV16 0x000004 +#define TMCTL_DIV256 0x000008 +#define TMCTL_DIV1 0x00000c +#define TMCTL_IEN 0x000020 +#define TMCTL_EN 0x000080 +#define TMCTL_DBGHALT 0x000100 +#define TMCTL_CNTEN 0x000200 + +#define TMCTL_PRESCALER(x) (((uint32_t)(x) & 0xff) << 16) + +/* watchdog */ +#define PM_RSTC_REG IOREG(0x10001c) +#define PM_WDOG_REG IOREG(0x100024) + +#define PM_PASSWD 0x5a000000 +#define PMRSTC_WRCFG_FULL_RESET 0x00000020 +#define PMRSTC_WRCFG_CLEAR 0xffffffcf + +/* MAILBOX */ +#define MBOX_READ_REG IOREG(0xb880) +#define MBOX_POLL_REG IOREG(0xb890) +#define MBOX_SENDER_REG IOREG(0xb894) +#define MBOX_STATUS_REG IOREG(0xb898) +#define MBOX_CFG_REG IOREG(0xb89c) +#define MBOX_WRITE_REG IOREG(0xb8a0) + +/* the full bit is set when there's no space to append messages */ +#define MBOX_STAT_FULL 0x80000000 +/* the empty bit is set when there are no pending messages to be read */ +#define MBOX_STAT_EMPTY 0x40000000 + +/* IRQ */ +#define IRQ_PENDING0_REG IOREG(0xb200) +#define IRQ_PENDING1_REG IOREG(0xb204) +#define IRQ_PENDING2_REG IOREG(0xb208) +#define IRQ_FIQCTL_REG IOREG(0xb20c) +#define IRQ_ENABLE1_REG IOREG(0xb210) +#define IRQ_ENABLE2_REG IOREG(0xb214) +#define IRQ_ENABLE0_REG IOREG(0xb218) +#define IRQ_DISABLE1_REG IOREG(0xb21c) +#define IRQ_DISABLE2_REG IOREG(0xb220) +#define IRQ_DISABLE0_REG IOREG(0xb224) + +#define IRQ_TIMER 0 +#define IRQ_MBOX 1 +#define IRQ_DOORB0 2 +#define IRQ_DOORB1 3 +#define IRQ_GPU0HLT 4 +#define IRQ_GPU1HLT 5 +#define IRQ_ILL1 6 +#define IRQ_ILL0 7 + +#define IRQ_GPU_TIMER0 0 +#define IRQ_GPU_TIMER1 1 +#define IRQ_GPU_TIMER2 2 +#define IRQ_GPU_TIMER3 3 +#define IRQ_GPU_AUX 29 +#define IRQ_GPU_I2C_SPI_SLV 43 +#define IRQ_GPU_PWA0 45 +#define IRQ_GPU_PWA1 46 +#define IRQ_GPU_SMI 48 +#define IRQ_GPU_GPIO0 49 +#define IRQ_GPU_GPIO1 50 +#define IRQ_GPU_GPIO2 51 +#define IRQ_GPU_GPIO3 52 +#define IRQ_GPU_I2C 53 +#define IRQ_GPU_SPI 54 +#define IRQ_GPU_PCM 55 +#define IRQ_GPU_UART 57 + +/* IRQ_PENDING0_REG flags (pending basic interrupts) */ +#define IRQ_PEND0_TIMER 0x0000001 +#define IRQ_PEND0_MBOX 0x0000002 +#define IRQ_PEND0_DOORB0 0x0000004 +#define IRQ_PEND0_DOORB1 0x0000008 +#define IRQ_PEND0_GPU0HLT 0x0000010 +#define IRQ_PEND0_GPU1HLT 0x0000020 +#define IRQ_PEND0_ILL1 0x0000040 +#define IRQ_PEND0_ILL0 0x0000080 +#define IRQ_PEND0_PEND2 0x0000100 +#define IRQ_PEND0_PEND1 0x0000200 +#define IRQ_PEND0_GPU_IRQ7 0x0000400 +#define IRQ_PEND0_GPU_IRQ9 0x0000800 +#define IRQ_PEND0_GPU_IRQ10 0x0001000 +#define IRQ_PEND0_GPU_IRQ18 0x0002000 +#define IRQ_PEND0_GPU_IRQ19 0x0004000 +#define IRQ_PEND0_GPU_I2C 0x0008000 +#define IRQ_PEND0_GPU_SPI 0x0010000 +#define IRQ_PEND0_GPU_PCM 0x0020000 +#define IRQ_PEND0_GPU_IRQ56 0x0040000 +#define IRQ_PEND0_GPU_UART 0x0080000 +#define IRQ_PEND0_GPU_IRQ62 0x0100000 + +/* IRQ_FIQCTL_REG */ +#define IRQ_FIQCTL_SELGPU(x) (x) +#define IRQ_FIQCTL_SELARM(x) ((x) + 64) +#define IRQ_FIQCTL_ENABLE 0x80 + +#endif /* RPI_IOREG_H_ */ diff --git a/src/startup.s b/src/startup.s index 3feac3d..587ab95 100644 --- a/src/startup.s +++ b/src/startup.s @@ -3,6 +3,7 @@ .section .startup .code 32 + .global startup startup: @ stop all but one of the cores mrc p15, 0, r0, c0, c0, 5 diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..7df21bb --- /dev/null +++ b/src/timer.c @@ -0,0 +1,10 @@ +#include "timer.h" +#include "rpi_ioreg.h" +#include "intr.h" + +volatile unsigned long num_ticks; + +void timer_init(void) +{ + enable_gpu_irq(IRQ_GPU_TIMER1); +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..1ca31e2 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,8 @@ +#ifndef TIMER_H_ +#define TIMER_H_ + +extern volatile unsigned long num_ticks; + +void timer_init(void); + +#endif /* TIMER_H_ */ diff --git a/src/video.c b/src/video.c index 9f56e9c..a0c7bed 100644 --- a/src/video.c +++ b/src/video.c @@ -40,38 +40,27 @@ int video_init(void) while((prop = rpi_prop_next())) { switch(prop->id) { case RPI_TAG_SETFBPHYS: - printf(" setfbphys"); fb_width = prop->data[0]; fb_height = prop->data[1]; break; case RPI_TAG_SETFBVIRT: - printf(" setfbvirt"); scr_width = prop->data[0]; scr_height = prop->data[1]; break; case RPI_TAG_SETFBDEPTH: - printf(" setfbdepth"); fb_depth = prop->data[0]; break; case RPI_TAG_ALLOCFB: - printf(" allocfb"); fb_pixels = (void*)(prop->data[0] & 0x3fffffff); fb_size = prop->data[1]; break; default: - printf(" tag %x", prop->id); break; } - - printf(" %08x (%u bytes):", prop->res, prop->size); - for(i=0; isize / 4; i++) { - printf(" %u", prop->data[i]); - } - putchar('\n'); } if(!fb_pixels) {