interrupts, timers, under construction
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 14 Nov 2020 08:10:49 +0000 (10:10 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 14 Nov 2020 08:10:49 +0000 (10:10 +0200)
15 files changed:
Makefile
doc/notes.md
rpikern.ld
src/asm.h
src/intr.c [new file with mode: 0644]
src/intr.h [new file with mode: 0644]
src/intrasm.s [new file with mode: 0644]
src/main.c
src/rpi.c
src/rpi.h
src/rpi_ioreg.h [new file with mode: 0644]
src/startup.s
src/timer.c [new file with mode: 0644]
src/timer.h [new file with mode: 0644]
src/video.c

index b4aa3a5..bb0b2bc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ endif
 warn = -pedantic -Wall
 dbg = -g
 inc = -Isrc -Isrc/libc
 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
 
 #arch = -mcpu=arm1176jzf-s
 arch = -mcpu=cortex-a7
 
@@ -37,10 +37,6 @@ $(elf): $(obj)
 
 -include $(dep)
 
 
 -include $(dep)
 
-%.d: %.c
-       @echo 'gen dep $@ ...'
-       @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
-
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin) $(elf) link.map
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin) $(elf) link.map
@@ -55,7 +51,7 @@ run: $(elf)
 
 .PHONY: disasm
 disasm: $(elf)
 
 .PHONY: disasm
 disasm: $(elf)
-       $(toolprefix)objdump -d $<
+       $(toolprefix)objdump -D $<
 
 .PHONY: install
 install: $(bin)
 
 .PHONY: install
 install: $(bin)
index 5a372d8..30dc050 100644 (file)
@@ -1,5 +1,8 @@
 Raspberry Pi2 notes
 ===================
 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
 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.
 
 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
 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
index 3843a15..ddec699 100644 (file)
@@ -1,4 +1,8 @@
 SECTIONS {
 SECTIONS {
+       .vect : {
+               * (.vect*);
+       }
+
        . = 0x00008000;
        _stacktop = .;
        _kern_start = .;
        . = 0x00008000;
        _stacktop = .;
        _kern_start = .;
index 425a8ee..fc1075d 100644 (file)
--- a/src/asm.h
+++ b/src/asm.h
@@ -1,8 +1,8 @@
 #ifndef ASM_H_
 #define ASM_H_
 
 #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 ( \
 #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 (file)
index 0000000..f9b0f1f
--- /dev/null
@@ -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 (file)
index 0000000..c3e7284
--- /dev/null
@@ -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 (file)
index 0000000..4ef2cd0
--- /dev/null
@@ -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
index 8bab5a1..18ed725 100644 (file)
@@ -8,7 +8,9 @@
 #include "rpi.h"
 #include "contty.h"
 #include "serial.h"
 #include "rpi.h"
 #include "contty.h"
 #include "serial.h"
+#include "timer.h"
 #include "video.h"
 #include "video.h"
+#include "intr.h"
 
 void dbgled(int x);
 
 
 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);
 
        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();
 
        video_init();
 
+       enable_intr();
+
        printf("Going interactive\n");
        printf("Going interactive\n");
+
        for(;;) {
                while(ser_pending()) {
                        int c = getchar();
        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);
 
                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) {
        } else if(strcmp(cmd, "help") == 0) {
                printf("help not implemented yet\n");
        } else if(strcmp(cmd, "ver") == 0) {
index 68f07e6..ec18e96 100644 (file)
--- a/src/rpi.c
+++ b/src/rpi.c
@@ -1,70 +1,12 @@
 #include <stdio.h>
 #include <stdarg.h>
 #include "rpi.h"
 #include <stdio.h>
 #include <stdarg.h>
 #include "rpi.h"
+#include "rpi_ioreg.h"
 #include "sysctl.h"
 #include "asm.h"
 #include "serial.h"
 #include "debug.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);
 
 
 static int detect(void);
 
index 57a1cf7..6f5e37f 100644 (file)
--- 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
 #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;
 
 struct rpi_prop_header {
        uint32_t size;
diff --git a/src/rpi_ioreg.h b/src/rpi_ioreg.h
new file mode 100644 (file)
index 0000000..aca3a9f
--- /dev/null
@@ -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_ */
index 3feac3d..587ab95 100644 (file)
@@ -3,6 +3,7 @@
        .section .startup
        .code 32
 
        .section .startup
        .code 32
 
+       .global startup
 startup:
        @ stop all but one of the cores
        mrc p15, 0, r0, c0, c0, 5
 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 (file)
index 0000000..7df21bb
--- /dev/null
@@ -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 (file)
index 0000000..1ca31e2
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef TIMER_H_
+#define TIMER_H_
+
+extern volatile unsigned long num_ticks;
+
+void timer_init(void);
+
+#endif /* TIMER_H_ */
index 9f56e9c..a0c7bed 100644 (file)
@@ -40,38 +40,27 @@ int video_init(void)
        while((prop = rpi_prop_next())) {
                switch(prop->id) {
                case RPI_TAG_SETFBPHYS:
        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:
                        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:
                        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:
                        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:
                        fb_pixels = (void*)(prop->data[0] & 0x3fffffff);
                        fb_size = prop->data[1];
                        break;
 
                default:
-                       printf(" tag %x", prop->id);
                        break;
                }
                        break;
                }
-
-               printf(" %08x (%u bytes):", prop->res, prop->size);
-               for(i=0; i<prop->size / 4; i++) {
-                       printf(" %u", prop->data[i]);
-               }
-               putchar('\n');
        }
 
        if(!fb_pixels) {
        }
 
        if(!fb_pixels) {