diff --git a/platform/bcm2835/include/platform/bcm2835.h b/platform/bcm2835/include/platform/bcm2835.h new file mode 100644 index 00000000..b44a0d2a --- /dev/null +++ b/platform/bcm2835/include/platform/bcm2835.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#define SDRAM_BASE 0 + +#define BCM_PERIPH_BASE_PHYS (0x3f000000U) +#define BCM_PERIPH_SIZE (0x01100000U) +#define BCM_PERIPH_BASE_VIRT (0xe0000000U) + +/* pointer to 'local' peripherals at 0x40000000 */ +#define BCM_LOCAL_PERIPH_BASE_VIRT (BCM_PERIPH_BASE_VIRT + 0x01000000) + +#define IC0_BASE (BCM_PERIPH_BASE_VIRT + 0x2000) +#define ST_BASE (BCM_PERIPH_BASE_VIRT + 0x3000) +#define MPHI_BASE (BCM_PERIPH_BASE_VIRT + 0x6000) +#define DMA_BASE (BCM_PERIPH_BASE_VIRT + 0x7000) +#define ARM_BASE (BCM_PERIPH_BASE_VIRT + 0xB000) +#define PM_BASE (BCM_PERIPH_BASE_VIRT + 0x100000) +#define PCM_CLOCK_BASE (BCM_PERIPH_BASE_VIRT + 0x101098) +#define RNG_BASE (BCM_PERIPH_BASE_VIRT + 0x104000) +#define GPIO_BASE (BCM_PERIPH_BASE_VIRT + 0x200000) +#define UART0_BASE (BCM_PERIPH_BASE_VIRT + 0x201000) +#define MMCI0_BASE (BCM_PERIPH_BASE_VIRT + 0x202000) +#define I2S_BASE (BCM_PERIPH_BASE_VIRT + 0x203000) +#define SPI0_BASE (BCM_PERIPH_BASE_VIRT + 0x204000) +#define BSC0_BASE (BCM_PERIPH_BASE_VIRT + 0x205000) +#define UART1_BASE (BCM_PERIPH_BASE_VIRT + 0x215000) +#define EMMC_BASE (BCM_PERIPH_BASE_VIRT + 0x300000) +#define SMI_BASE (BCM_PERIPH_BASE_VIRT + 0x600000) +#define BSC1_BASE (BCM_PERIPH_BASE_VIRT + 0x804000) +#define USB_BASE (BCM_PERIPH_BASE_VIRT + 0x980000) +#define MCORE_BASE (BCM_PERIPH_BASE_VIRT + 0x0000) + +#define ARMCTRL_BASE (ARM_BASE + 0x000) +#define ARMCTRL_INTC_BASE (ARM_BASE + 0x200) +#define ARMCTRL_TIMER0_1_BASE (ARM_BASE + 0x400) +#define ARMCTRL_0_SBM_BASE (ARM_BASE + 0x800) + +#define ARM_LOCAL_BASE (BCM_LOCAL_PERIPH_BASE_VIRT) + +/* interrupts */ +#define ARM_IRQ1_BASE 0 +#define INTERRUPT_TIMER0 (ARM_IRQ1_BASE + 0) +#define INTERRUPT_TIMER1 (ARM_IRQ1_BASE + 1) +#define INTERRUPT_TIMER2 (ARM_IRQ1_BASE + 2) +#define INTERRUPT_TIMER3 (ARM_IRQ1_BASE + 3) +#define INTERRUPT_CODEC0 (ARM_IRQ1_BASE + 4) +#define INTERRUPT_CODEC1 (ARM_IRQ1_BASE + 5) +#define INTERRUPT_CODEC2 (ARM_IRQ1_BASE + 6) +#define INTERRUPT_VC_JPEG (ARM_IRQ1_BASE + 7) +#define INTERRUPT_ISP (ARM_IRQ1_BASE + 8) +#define INTERRUPT_VC_USB (ARM_IRQ1_BASE + 9) +#define INTERRUPT_VC_3D (ARM_IRQ1_BASE + 10) +#define INTERRUPT_TRANSPOSER (ARM_IRQ1_BASE + 11) +#define INTERRUPT_MULTICORESYNC0 (ARM_IRQ1_BASE + 12) +#define INTERRUPT_MULTICORESYNC1 (ARM_IRQ1_BASE + 13) +#define INTERRUPT_MULTICORESYNC2 (ARM_IRQ1_BASE + 14) +#define INTERRUPT_MULTICORESYNC3 (ARM_IRQ1_BASE + 15) +#define INTERRUPT_DMA0 (ARM_IRQ1_BASE + 16) +#define INTERRUPT_DMA1 (ARM_IRQ1_BASE + 17) +#define INTERRUPT_VC_DMA2 (ARM_IRQ1_BASE + 18) +#define INTERRUPT_VC_DMA3 (ARM_IRQ1_BASE + 19) +#define INTERRUPT_DMA4 (ARM_IRQ1_BASE + 20) +#define INTERRUPT_DMA5 (ARM_IRQ1_BASE + 21) +#define INTERRUPT_DMA6 (ARM_IRQ1_BASE + 22) +#define INTERRUPT_DMA7 (ARM_IRQ1_BASE + 23) +#define INTERRUPT_DMA8 (ARM_IRQ1_BASE + 24) +#define INTERRUPT_DMA9 (ARM_IRQ1_BASE + 25) +#define INTERRUPT_DMA10 (ARM_IRQ1_BASE + 26) +#define INTERRUPT_DMA11 (ARM_IRQ1_BASE + 27) +#define INTERRUPT_DMA12 (ARM_IRQ1_BASE + 28) +#define INTERRUPT_AUX (ARM_IRQ1_BASE + 29) +#define INTERRUPT_ARM (ARM_IRQ1_BASE + 30) +#define INTERRUPT_VPUDMA (ARM_IRQ1_BASE + 31) + +#define ARM_IRQ2_BASE 32 +#define INTERRUPT_HOSTPORT (ARM_IRQ2_BASE + 0) +#define INTERRUPT_VIDEOSCALER (ARM_IRQ2_BASE + 1) +#define INTERRUPT_CCP2TX (ARM_IRQ2_BASE + 2) +#define INTERRUPT_SDC (ARM_IRQ2_BASE + 3) +#define INTERRUPT_DSI0 (ARM_IRQ2_BASE + 4) +#define INTERRUPT_AVE (ARM_IRQ2_BASE + 5) +#define INTERRUPT_CAM0 (ARM_IRQ2_BASE + 6) +#define INTERRUPT_CAM1 (ARM_IRQ2_BASE + 7) +#define INTERRUPT_HDMI0 (ARM_IRQ2_BASE + 8) +#define INTERRUPT_HDMI1 (ARM_IRQ2_BASE + 9) +#define INTERRUPT_PIXELVALVE1 (ARM_IRQ2_BASE + 10) +#define INTERRUPT_I2CSPISLV (ARM_IRQ2_BASE + 11) +#define INTERRUPT_DSI1 (ARM_IRQ2_BASE + 12) +#define INTERRUPT_PWA0 (ARM_IRQ2_BASE + 13) +#define INTERRUPT_PWA1 (ARM_IRQ2_BASE + 14) +#define INTERRUPT_CPR (ARM_IRQ2_BASE + 15) +#define INTERRUPT_SMI (ARM_IRQ2_BASE + 16) +#define INTERRUPT_GPIO0 (ARM_IRQ2_BASE + 17) +#define INTERRUPT_GPIO1 (ARM_IRQ2_BASE + 18) +#define INTERRUPT_GPIO2 (ARM_IRQ2_BASE + 19) +#define INTERRUPT_GPIO3 (ARM_IRQ2_BASE + 20) +#define INTERRUPT_VC_I2C (ARM_IRQ2_BASE + 21) +#define INTERRUPT_VC_SPI (ARM_IRQ2_BASE + 22) +#define INTERRUPT_VC_I2SPCM (ARM_IRQ2_BASE + 23) +#define INTERRUPT_VC_SDIO (ARM_IRQ2_BASE + 24) +#define INTERRUPT_VC_UART (ARM_IRQ2_BASE + 25) +#define INTERRUPT_SLIMBUS (ARM_IRQ2_BASE + 26) +#define INTERRUPT_VEC (ARM_IRQ2_BASE + 27) +#define INTERRUPT_CPG (ARM_IRQ2_BASE + 28) +#define INTERRUPT_RNG (ARM_IRQ2_BASE + 29) +#define INTERRUPT_VC_ARASANSDIO (ARM_IRQ2_BASE + 30) +#define INTERRUPT_AVSPMON (ARM_IRQ2_BASE + 31) + +/* ARM interrupts, which are mostly mirrored from bank 1 and 2 */ +#define ARM_IRQ0_BASE 64 +#define INTERRUPT_ARM_TIMER (ARM_IRQ0_BASE + 0) +#define INTERRUPT_ARM_MAILBOX (ARM_IRQ0_BASE + 1) +#define INTERRUPT_ARM_DOORBELL_0 (ARM_IRQ0_BASE + 2) +#define INTERRUPT_ARM_DOORBELL_1 (ARM_IRQ0_BASE + 3) +#define INTERRUPT_VPU0_HALTED (ARM_IRQ0_BASE + 4) +#define INTERRUPT_VPU1_HALTED (ARM_IRQ0_BASE + 5) +#define INTERRUPT_ILLEGAL_TYPE0 (ARM_IRQ0_BASE + 6) +#define INTERRUPT_ILLEGAL_TYPE1 (ARM_IRQ0_BASE + 7) +#define INTERRUPT_PENDING1 (ARM_IRQ0_BASE + 8) +#define INTERRUPT_PENDING2 (ARM_IRQ0_BASE + 9) +#define INTERRUPT_JPEG (ARM_IRQ0_BASE + 10) +#define INTERRUPT_USB (ARM_IRQ0_BASE + 11) +#define INTERRUPT_3D (ARM_IRQ0_BASE + 12) +#define INTERRUPT_DMA2 (ARM_IRQ0_BASE + 13) +#define INTERRUPT_DMA3 (ARM_IRQ0_BASE + 14) +#define INTERRUPT_I2C (ARM_IRQ0_BASE + 15) +#define INTERRUPT_SPI (ARM_IRQ0_BASE + 16) +#define INTERRUPT_I2SPCM (ARM_IRQ0_BASE + 17) +#define INTERRUPT_SDIO (ARM_IRQ0_BASE + 18) +#define INTERRUPT_UART (ARM_IRQ0_BASE + 19) +#define INTERRUPT_ARASANSDIO (ARM_IRQ0_BASE + 20) + +#define ARM_IRQ_LOCAL_BASE 96 +#define INTERRUPT_ARM_LOCAL_CNTPSIRQ (ARM_IRQ_LOCAL_BASE + 0) +#define INTERRUPT_ARM_LOCAL_CNTPNSIRQ (ARM_IRQ_LOCAL_BASE + 1) +#define INTERRUPT_ARM_LOCAL_CNTHPIRQ (ARM_IRQ_LOCAL_BASE + 2) +#define INTERRUPT_ARM_LOCAL_CNTVIRQ (ARM_IRQ_LOCAL_BASE + 3) +#define INTERRUPT_ARM_LOCAL_MAILBOX0 (ARM_IRQ_LOCAL_BASE + 4) +#define INTERRUPT_ARM_LOCAL_MAILBOX1 (ARM_IRQ_LOCAL_BASE + 5) +#define INTERRUPT_ARM_LOCAL_MAILBOX2 (ARM_IRQ_LOCAL_BASE + 6) +#define INTERRUPT_ARM_LOCAL_MAILBOX3 (ARM_IRQ_LOCAL_BASE + 7) +#define INTERRUPT_ARM_LOCAL_GPU_FAST (ARM_IRQ_LOCAL_BASE + 8) +#define INTERRUPT_ARM_LOCAL_PMU_FAST (ARM_IRQ_LOCAL_BASE + 9) +#define INTERRUPT_ARM_LOCAL_ZERO (ARM_IRQ_LOCAL_BASE + 10) +#define INTERRUPT_ARM_LOCAL_TIMER (ARM_IRQ_LOCAL_BASE + 11) + +#define MAX_INT INTERRUPT_ARM_LOCAL_TIMER + + diff --git a/platform/bcm2835/include/platform/gic.h b/platform/bcm2835/include/platform/gic.h new file mode 100644 index 00000000..d1e7c8ca --- /dev/null +++ b/platform/bcm2835/include/platform/gic.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include + +#define GICBASE(n) (CPUPRIV_BASE_PHYS) +#define GICC_OFFSET (0x0100) +#define GICD_OFFSET (0x1000) + + diff --git a/platform/bcm2835/intc.c b/platform/bcm2835/intc.c new file mode 100644 index 00000000..c86734f3 --- /dev/null +++ b/platform/bcm2835/intc.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOCAL_TRACE 0 + +/* global interrupt controller */ +#define INTC_PEND0 (ARMCTRL_INTC_BASE + 0x0) +#define INTC_PEND1 (ARMCTRL_INTC_BASE + 0x4) +#define INTC_PEND2 (ARMCTRL_INTC_BASE + 0x8) +#define INTC_FAST (ARMCTRL_INTC_BASE + 0xc) +#define INTC_ENABLE1 (ARMCTRL_INTC_BASE + 0x10) +#define INTC_ENABLE2 (ARMCTRL_INTC_BASE + 0x14) +#define INTC_ENABLE3 (ARMCTRL_INTC_BASE + 0x18) +#define INTC_DISABLE1 (ARMCTRL_INTC_BASE + 0x1c) +#define INTC_DISABLE2 (ARMCTRL_INTC_BASE + 0x20) +#define INTC_DISABLE3 (ARMCTRL_INTC_BASE + 0x24) + +/* per-cpu local interrupt controller bits. + * each is repeated 4 times, one per cpu. + */ +#define INTC_LOCAL_TIMER_INT_CONTROL0 (ARM_LOCAL_BASE + 0x40) +#define INTC_LOCAL_TIMER_INT_CONTROL1 (ARM_LOCAL_BASE + 0x44) +#define INTC_LOCAL_TIMER_INT_CONTROL2 (ARM_LOCAL_BASE + 0x48) +#define INTC_LOCAL_TIMER_INT_CONTROL3 (ARM_LOCAL_BASE + 0x4c) + +#define INTC_LOCAL_MAILBOX_INT_CONTROL0 (ARM_LOCAL_BASE + 0x40) +#define INTC_LOCAL_MAILBOX_INT_CONTROL1 (ARM_LOCAL_BASE + 0x44) +#define INTC_LOCAL_MAILBOX_INT_CONTROL2 (ARM_LOCAL_BASE + 0x48) +#define INTC_LOCAL_MAILBOX_INT_CONTROL3 (ARM_LOCAL_BASE + 0x4c) + +#define INTC_LOCAL_IRQ_PEND0 (ARM_LOCAL_BASE + 0x60) +#define INTC_LOCAL_IRQ_PEND1 (ARM_LOCAL_BASE + 0x64) +#define INTC_LOCAL_IRQ_PEND2 (ARM_LOCAL_BASE + 0x68) +#define INTC_LOCAL_IRQ_PEND3 (ARM_LOCAL_BASE + 0x6c) + +#define INTC_LOCAL_FIQ_PEND0 (ARM_LOCAL_BASE + 0x70) +#define INTC_LOCAL_FIQ_PEND1 (ARM_LOCAL_BASE + 0x74) +#define INTC_LOCAL_FIQ_PEND2 (ARM_LOCAL_BASE + 0x78) +#define INTC_LOCAL_FIQ_PEND3 (ARM_LOCAL_BASE + 0x7c) + +struct int_handler_struct { + int_handler handler; + void *arg; +}; + +static struct int_handler_struct int_handler_table[MAX_INT][SMP_MAX_CPUS]; + +static spin_lock_t lock = SPIN_LOCK_INITIAL_VALUE; + +status_t mask_interrupt(unsigned int vector) +{ + LTRACEF("vector %u\n", vector); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + if (vector >= INTERRUPT_ARM_LOCAL_CNTPSIRQ && vector <= INTERRUPT_ARM_LOCAL_CNTVIRQ) { + // local timer interrupts + uint cpu = arch_curr_cpu_num(); + uintptr_t reg = INTC_LOCAL_TIMER_INT_CONTROL0 + cpu * 4; + + *REG32(reg) &= (1 << (vector - INTERRUPT_ARM_LOCAL_CNTPSIRQ)); + } else if (/* vector >= ARM_IRQ1_BASE && */ vector < (ARM_IRQ0_BASE + 32)) { + uintptr_t reg; + if (vector >= ARM_IRQ0_BASE) + reg = INTC_DISABLE3; + else if (vector >= ARM_IRQ2_BASE) + reg = INTC_DISABLE2; + else + reg = INTC_DISABLE1; + + *REG32(reg) = 1 << (vector % 32); + } else { + PANIC_UNIMPLEMENTED; + } + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +status_t unmask_interrupt(unsigned int vector) +{ + LTRACEF("vector %u\n", vector); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + if (vector >= INTERRUPT_ARM_LOCAL_CNTPSIRQ && vector <= INTERRUPT_ARM_LOCAL_CNTVIRQ) { + // local timer interrupts + uint cpu = arch_curr_cpu_num(); + uintptr_t reg = INTC_LOCAL_TIMER_INT_CONTROL0 + cpu * 4; + + *REG32(reg) |= (1 << (vector - INTERRUPT_ARM_LOCAL_CNTPSIRQ)); + } else if (/* vector >= ARM_IRQ1_BASE && */ vector < (ARM_IRQ0_BASE + 32)) { + uintptr_t reg; + if (vector >= ARM_IRQ0_BASE) + reg = INTC_ENABLE3; + else if (vector >= ARM_IRQ2_BASE) + reg = INTC_ENABLE2; + else + reg = INTC_ENABLE1; + + *REG32(reg) = 1 << (vector % 32); + } else { + PANIC_UNIMPLEMENTED; + } + + spin_unlock_irqrestore(&lock, state); + + return NO_ERROR; +} + +void register_int_handler(unsigned int vector, int_handler handler, void *arg) +{ + uint cpu = arch_curr_cpu_num(); + + if (vector >= MAX_INT) + panic("register_int_handler: vector out of range %d\n", vector); + + spin_lock_saved_state_t state; + spin_lock_irqsave(&lock, state); + + int_handler_table[vector][cpu].handler = handler; + int_handler_table[vector][cpu].arg = arg; + + spin_unlock_irqrestore(&lock, state); +} + +enum handler_return platform_irq(struct arm_iframe *frame) +{ + uint vector; + uint cpu = arch_curr_cpu_num(); + + THREAD_STATS_INC(interrupts); + + // see what kind of irq it is + uint32_t pend = *REG32(INTC_LOCAL_IRQ_PEND0 + cpu * 4); + + pend &= ~(1 << (INTERRUPT_ARM_LOCAL_GPU_FAST % 32)); // mask out gpu interrupts + + if (pend != 0) { + // it's a local interrupt + LTRACEF("local pend 0x%x\n", pend); + vector = ARM_IRQ_LOCAL_BASE + ctz(pend); + goto decoded; + } + + // XXX disable for now, since all of the interesting irqs are mirrored into the other banks +#if 0 + // look in bank 0 (ARM interrupts) + pend = *REG32(INTC_PEND0); + LTRACEF("pend0 0x%x\n", pend); + pend &= ~((1<<8)|(1<<9)); // mask out bit 8 and 9 + if (pend != 0) { + // it's a bank 0 interrupt + vector = ARM_IRQ0_BASE + ctz(pend); + goto decoded; + } +#endif + + // look for VC interrupt bank 1 + pend = *REG32(INTC_PEND1); + LTRACEF("pend1 0x%x\n", pend); + if (pend != 0) { + // it's a bank 1 interrupt + vector = ARM_IRQ1_BASE + ctz(pend); + goto decoded; + } + + // look for VC interrupt bank 2 + pend = *REG32(INTC_PEND2); + LTRACEF("pend2 0x%x\n", pend); + if (pend != 0) { + // it's a bank 2 interrupt + vector = ARM_IRQ2_BASE + ctz(pend); + goto decoded; + } + + vector = 0xffffffff; + +decoded: + LTRACEF("vector %u\n", vector); + + // dispatch the irq + enum handler_return ret = INT_NO_RESCHEDULE; + if (int_handler_table[vector][cpu].handler) { + ret = int_handler_table[vector][cpu].handler(int_handler_table[vector][cpu].arg); + } else { + panic("irq %u fired on cpu %u but no handler set!\n", vector, cpu); + + } + + return ret; +} + +enum handler_return platform_fiq(struct arm_iframe *frame) +{ + PANIC_UNIMPLEMENTED; +} + +void intc_init(void) +{ + // mask everything + *REG32(INTC_DISABLE1) = 0xffffffff; + *REG32(INTC_DISABLE2) = 0xffffffff; + *REG32(INTC_DISABLE3) = 0xffffffff; +} + diff --git a/platform/bcm2835/platform.c b/platform/bcm2835/platform.c new file mode 100644 index 00000000..b8531ef1 --- /dev/null +++ b/platform/bcm2835/platform.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "platform_p.h" + +extern void intc_init(void); + +/* initial memory mappings. parsed by start.S */ +struct mmu_initial_mapping mmu_initial_mappings[] = { + /* 1GB of sdram space */ + { .phys = SDRAM_BASE, + .virt = KERNEL_BASE, + .size = MEMSIZE, + .flags = 0, + .name = "memory" }, + + /* peripherals */ + { .phys = BCM_PERIPH_BASE_PHYS, + .virt = BCM_PERIPH_BASE_VIRT, + .size = BCM_PERIPH_SIZE, + .flags = MMU_INITIAL_MAPPING_FLAG_DEVICE, + .name = "bcm peripherals" }, + + /* identity map to let the boot code run */ + { .phys = SDRAM_BASE, + .virt = SDRAM_BASE, + .size = 16*1024*1024, + .flags = MMU_INITIAL_MAPPING_TEMPORARY }, + + /* null entry to terminate the list */ + { 0 } +}; + +static pmm_arena_t arena = { + .name = "sdram", + .base = SDRAM_BASE, + .size = MEMSIZE, + .flags = PMM_ARENA_FLAG_KMAP, +}; + +void platform_init_mmu_mappings(void) +{ +} + +void platform_early_init(void) +{ + uart_init_early(); + + intc_init(); + + arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000); + + /* add the main memory arena */ + pmm_add_arena(&arena); +} + +void platform_init(void) +{ + uart_init(); +} + +#define DEBUG_UART 0 + +void platform_dputc(char c) +{ + if (c == '\n') + uart_putc(DEBUG_UART, '\r'); + uart_putc(DEBUG_UART, c); +} + +int platform_dgetc(char *c, bool wait) +{ + int ret = uart_getc(DEBUG_UART, wait); + if (ret == -1) + return -1; + *c = ret; + return 0; +} + diff --git a/platform/bcm2835/rules.mk b/platform/bcm2835/rules.mk new file mode 100644 index 00000000..62493bf5 --- /dev/null +++ b/platform/bcm2835/rules.mk @@ -0,0 +1,44 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +ARCH := arm +ARM_CPU := cortex-a7 +WITH_SMP := 0 + +MODULE_DEPS := \ + dev/timer/arm_generic \ + lib/cbuf + +#lib/bio \ + lib/cbuf \ + lib/minip \ + dev/interrupt/arm_gic \ + dev/timer/arm_cortex_a9 + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/include + +MODULE_SRCS += \ + $(LOCAL_DIR)/intc.c \ + $(LOCAL_DIR)/platform.c \ + $(LOCAL_DIR)/uart.c \ + +# default to no sdram unless the target calls it out +ZYNQ_SDRAM_SIZE ?= 0 + +MEMBASE := 0x00000000 +MEMSIZE ?= 0x10000000 # 256MB +KERNEL_LOAD_OFFSET := 0x00008000 # loaded 32KB into physical + +# put our kernel at 0x80000000 +KERNEL_BASE = 0x80000000 + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) + +LINKER_SCRIPT += \ + $(BUILDDIR)/system-onesegment.ld + +include make/module.mk diff --git a/platform/bcm2835/uart.c b/platform/bcm2835/uart.c new file mode 100644 index 00000000..5c3d5ab6 --- /dev/null +++ b/platform/bcm2835/uart.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* TODO: extract this into a generic PL011 driver */ + +/* PL011 implementation */ +#define UART_DR (0x00) +#define UART_RSR (0x04) +#define UART_TFR (0x18) +#define UART_ILPR (0x20) +#define UART_IBRD (0x24) +#define UART_FBRD (0x28) +#define UART_LCRH (0x2c) +#define UART_CR (0x30) +#define UART_IFLS (0x34) +#define UART_IMSC (0x38) +#define UART_TRIS (0x3c) +#define UART_TMIS (0x40) +#define UART_ICR (0x44) +#define UART_DMACR (0x48) + +#define UARTREG(base, reg) (*REG32((base) + (reg))) + +#define RXBUF_SIZE 16 +#define NUM_UART 1 + +static cbuf_t uart_rx_buf[NUM_UART]; + +static inline uintptr_t uart_to_ptr(unsigned int n) +{ + switch (n) { + default: + case 0: return UART0_BASE; + } +} + +static enum handler_return uart_irq(void *arg) +{ + bool resched = false; + uint port = (uint)arg; + uintptr_t base = uart_to_ptr(port); + + /* read interrupt status and mask */ + uint32_t isr = UARTREG(base, UART_TMIS); + + if (isr & ((1<<6) | (1<<4))) { // rtmis, rxmis + UARTREG(base, UART_ICR) = (1<<4); + cbuf_t *rxbuf = &uart_rx_buf[port]; + + /* while fifo is not empty, read chars out of it */ + while ((UARTREG(base, UART_TFR) & (1<<4)) == 0) { + char c = UARTREG(base, UART_DR); + cbuf_write_char(rxbuf, c, false); + + resched = true; + } + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +void uart_init(void) +{ + for (size_t i = 0; i < NUM_UART; i++) { + // create circular buffer to hold received data + cbuf_initialize(&uart_rx_buf[i], RXBUF_SIZE); + + // assumes interrupts are contiguous + register_int_handler(INTERRUPT_VC_UART + i, &uart_irq, (void *)i); + + // clear all irqs + UARTREG(uart_to_ptr(i), UART_ICR) = 0x3ff; + + // set fifo trigger level + UARTREG(uart_to_ptr(i), UART_IFLS) = 0; // 1/8 rxfifo, 1/8 txfifo + + // enable rx interrupt + UARTREG(uart_to_ptr(i), UART_IMSC) = (1<<6)|(1<<4); // rtim, rxim + + // enable receive + UARTREG(uart_to_ptr(i), UART_CR) |= (1<<9); // rxen + + // enable interrupt + unmask_interrupt(INTERRUPT_VC_UART + i); + } +} + +void uart_init_early(void) +{ + for (size_t i = 0; i < NUM_UART; i++) { + UARTREG(uart_to_ptr(i), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten + } +} + +int uart_putc(int port, char c) +{ + uintptr_t base = uart_to_ptr(port); + + /* spin while fifo is full */ + while (UARTREG(base, UART_TFR) & (1<<5)) + ; + UARTREG(base, UART_DR) = c; + + return 1; +} + +int uart_getc(int port, bool wait) +{ + cbuf_t *rxbuf = &uart_rx_buf[port]; + + char c; + if (cbuf_read_char(rxbuf, &c, wait) == 1) + return c; + + return -1; +} + +void uart_flush_tx(int port) +{ +} + +void uart_flush_rx(int port) +{ +} + +void uart_init_port(int port, uint baud) +{ +} + + diff --git a/project/rpi2-test.mk b/project/rpi2-test.mk new file mode 100644 index 00000000..c71a7e7c --- /dev/null +++ b/project/rpi2-test.mk @@ -0,0 +1,11 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +TARGET := rpi2 + +MODULES += \ + app/shell \ + app/stringtests \ + app/tests \ + lib/cksum \ + lib/debugcommands \ + diff --git a/target/rpi2/rules.mk b/target/rpi2/rules.mk new file mode 100644 index 00000000..41ffb2ed --- /dev/null +++ b/target/rpi2/rules.mk @@ -0,0 +1,9 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/include + +PLATFORM := bcm2835 + +#include make/module.mk +