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
-include $(dep)
-%.d: %.c
- @echo 'gen dep $@ ...'
- @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
-
.PHONY: clean
clean:
rm -f $(obj) $(bin) $(elf) link.map
.PHONY: disasm
disasm: $(elf)
- $(toolprefix)objdump -d $<
+ $(toolprefix)objdump -D $<
.PHONY: install
install: $(bin)
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
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
SECTIONS {
+ .vect : {
+ * (.vect*);
+ }
+
. = 0x00008000;
_stacktop = .;
_kern_start = .;
#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 ( \
--- /dev/null
+#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();
+}
--- /dev/null
+#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_ */
--- /dev/null
+ .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
#include "rpi.h"
#include "contty.h"
#include "serial.h"
+#include "timer.h"
#include "video.h"
+#include "intr.h"
void dbgled(int x);
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();
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) {
#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"
-#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);
#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;
--- /dev/null
+#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_ */
.section .startup
.code 32
+ .global startup
startup:
@ stop all but one of the cores
mrc p15, 0, r0, c0, c0, 5
--- /dev/null
+#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);
+}
--- /dev/null
+#ifndef TIMER_H_
+#define TIMER_H_
+
+extern volatile unsigned long num_ticks;
+
+void timer_init(void);
+
+#endif /* TIMER_H_ */
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; i<prop->size / 4; i++) {
- printf(" %u", prop->data[i]);
- }
- putchar('\n');
}
if(!fb_pixels) {