From 1164bc17bc7c7c21714cf8bb3c320357c3a69b55 Mon Sep 17 00:00:00 2001 From: Eric Holland Date: Tue, 28 Jun 2016 17:06:07 -0700 Subject: [PATCH 01/12] [rpi3]64bit platform support --- arch/arm/arm/mp.c | 2 + arch/arm64/asm.S | 55 ++++ arch/arm64/mp.c | 4 +- arch/arm64/start.S | 6 + platform/bcm2837/gpio.c | 57 ++++ platform/bcm2837/include/platform/bcm2837.h | 203 ++++++++++++++ platform/bcm2837/include/platform/gic.h | 31 +++ platform/bcm2837/intc.c | 286 ++++++++++++++++++++ platform/bcm2837/platform.c | 169 ++++++++++++ platform/bcm2837/rules.mk | 48 ++++ platform/bcm2837/uart.c | 217 +++++++++++++++ project/rpi3-test.mk | 11 + target/rpi3/rules.mk | 9 + 13 files changed, 1096 insertions(+), 2 deletions(-) create mode 100644 platform/bcm2837/gpio.c create mode 100644 platform/bcm2837/include/platform/bcm2837.h create mode 100644 platform/bcm2837/include/platform/gic.h create mode 100644 platform/bcm2837/intc.c create mode 100644 platform/bcm2837/platform.c create mode 100644 platform/bcm2837/rules.mk create mode 100644 platform/bcm2837/uart.c create mode 100644 project/rpi3-test.mk create mode 100644 target/rpi3/rules.mk diff --git a/arch/arm/arm/mp.c b/arch/arm/arm/mp.c index 3e4fa95ef..a27a9206b 100644 --- a/arch/arm/arm/mp.c +++ b/arch/arm/arm/mp.c @@ -33,6 +33,8 @@ #elif PLATFORM_BCM2835 /* bcm2835 has a weird custom interrupt controller for MP */ extern void bcm2835_send_ipi(uint irq, uint cpu_mask); +#elif PLATFORM_BCM2837 +extern void bcm2835_send_ipi(uint irq, uint cpu_mask); #else #error need other implementation of interrupt controller that can ipi #endif diff --git a/arch/arm64/asm.S b/arch/arm64/asm.S index d60ca8486..e373d34a0 100644 --- a/arch/arm64/asm.S +++ b/arch/arm64/asm.S @@ -83,5 +83,60 @@ FUNCTION(arm64_el3_to_el1) eret +FUNCTION(arm64_elX_to_el1) + mrs x0, CurrentEL + + cmp x0, #(0b01 << 2) + bne .notEL1 + /* Already in EL1 */ + ret + +.notEL1: + cmp x0, #(0b10 << 2) + beq .inEL2 + + + /* set EL2 to 64bit */ + mrs x0, scr_el3 + orr x0, x0, #(1<<10) + msr scr_el3, x0 + + + adr x0, .Ltarget + msr elr_el3, x0 + + mov x0, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ + msr spsr_el3, x0 + b .confEL1 + +.inEL2: + adr x0, .Ltarget + msr elr_el2, x0 + mov x0, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ + msr spsr_el2, x0 + + + +.confEL1: + /* disable EL2 coprocessor traps */ + mov x0, #0x33ff + msr cptr_el2, x0 + + /* set EL1 to 64bit */ + mov x0, #(1<<31) + msr hcr_el2, x0 + + /* disable EL1 FPU traps */ + mov x0, #(0b11<<20) + msr cpacr_el1, x0 + + /* set up the EL1 bounce interrupt */ + mov x0, sp + msr sp_el1, x0 + + isb + eret + + .Ltarget: ret diff --git a/arch/arm64/mp.c b/arch/arm64/mp.c index 0760ed32e..5a813c516 100644 --- a/arch/arm64/mp.c +++ b/arch/arm64/mp.c @@ -30,8 +30,8 @@ #if WITH_DEV_INTERRUPT_ARM_GIC #include -#else -#error need other implementation of interrupt controller that can ipi +//#else +//#error need other implementation of interrupt controller that can ipi #endif #define LOCAL_TRACE 0 diff --git a/arch/arm64/start.S b/arch/arm64/start.S index 7fd7e3ec3..bede18eee 100644 --- a/arch/arm64/start.S +++ b/arch/arm64/start.S @@ -30,7 +30,13 @@ attr .req x27 .section .text.boot FUNCTION(_start) +.globl arm_reset +arm_reset: + #if WITH_KERNEL_VM + + bl arm64_elX_to_el1 + /* enable caches so atomics and spinlocks work */ mrs tmp, sctlr_el1 orr tmp, tmp, #(1<<12) /* Enable icache */ diff --git a/platform/bcm2837/gpio.c b/platform/bcm2837/gpio.c new file mode 100644 index 000000000..6bb9019ba --- /dev/null +++ b/platform/bcm2837/gpio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Adam Barth + * + * 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 + +#define NUM_PINS 54 +#define BITS_PER_REG 32 +#define BITS_PER_PIN 3 +#define PINS_PER_REG (BITS_PER_REG / BITS_PER_PIN) +#define GPIOREG(base, nr) (REG32(base) + (nr / BITS_PER_REG)) + +int gpio_config(unsigned nr, unsigned flags) +{ + unsigned mask = 0x7; + if (nr >= NUM_PINS || flags & ~mask) + return -EINVAL; + unsigned register_number = nr / PINS_PER_REG; + unsigned offset = (nr % PINS_PER_REG) * BITS_PER_PIN; + unsigned shifted_mask = mask << offset; + volatile uint32_t *reg = REG32(GPIO_GPFSEL0) + register_number; + *reg = (*reg & ~shifted_mask) | (flags << offset); + return 0; +} + +void gpio_set(unsigned nr, unsigned on) +{ + unsigned offset = nr % BITS_PER_REG; + *GPIOREG(on ? GPIO_GPSET0 : GPIO_GPCLR0, nr) = 1 << offset; +} + +int gpio_get(unsigned nr) +{ + unsigned offset = nr % BITS_PER_REG; + return (*GPIOREG(GPIO_GPLEV0, nr) & (1 << offset)) >> offset; +} diff --git a/platform/bcm2837/include/platform/bcm2837.h b/platform/bcm2837/include/platform/bcm2837.h new file mode 100644 index 000000000..bff557d80 --- /dev/null +++ b/platform/bcm2837/include/platform/bcm2837.h @@ -0,0 +1,203 @@ +/* + * 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 +/* Note: BCM2836/BCM2837 use different peripheral base than BCM2835 */ +#define BCM_PERIPH_BASE_PHYS (0x3f000000U) +#define BCM_PERIPH_SIZE (0x01100000U) +#define BCM_PERIPH_BASE_VIRT (0xffffffffc0000000ULL) + +#define MEMORY_APERTURE_SIZE ( 1024 * 1024 * 1024) + +/* 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 + +/* GPIO */ + +#define GPIO_GPFSEL0 (GPIO_BASE + 0x00) +#define GPIO_GPFSEL1 (GPIO_BASE + 0x04) +#define GPIO_GPFSEL2 (GPIO_BASE + 0x08) +#define GPIO_GPFSEL3 (GPIO_BASE + 0x0C) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPSET0 (GPIO_BASE + 0x1C) +#define GPIO_GPSET1 (GPIO_BASE + 0x20) +#define GPIO_GPCLR0 (GPIO_BASE + 0x28) +#define GPIO_GPCLR1 (GPIO_BASE + 0x2C) +#define GPIO_GPLEV0 (GPIO_BASE + 0x34) +#define GPIO_GPLEV1 (GPIO_BASE + 0x38) +#define GPIO_GPEDS0 (GPIO_BASE + 0x40) +#define GPIO_GPEDS1 (GPIO_BASE + 0x44) +#define GPIO_GPREN0 (GPIO_BASE + 0x4C) +#define GPIO_GPREN1 (GPIO_BASE + 0x50) +#define GPIO_GPFEN0 (GPIO_BASE + 0x58) +#define GPIO_GPFEN1 (GPIO_BASE + 0x5C) +#define GPIO_GPHEN0 (GPIO_BASE + 0x64) +#define GPIO_GPHEN1 (GPIO_BASE + 0x68) +#define GPIO_GPLEN0 (GPIO_BASE + 0x70) +#define GPIO_GPLEN1 (GPIO_BASE + 0x74) +#define GPIO_GPAREN0 (GPIO_BASE + 0x7C) +#define GPIO_GPAREN1 (GPIO_BASE + 0x80) +#define GPIO_GPAFEN0 (GPIO_BASE + 0x88) +#define GPIO_GPAFEN1 (GPIO_BASE + 0x8C) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK0 (GPIO_BASE + 0x98) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9C) diff --git a/platform/bcm2837/include/platform/gic.h b/platform/bcm2837/include/platform/gic.h new file mode 100644 index 000000000..92cf0ad90 --- /dev/null +++ b/platform/bcm2837/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/bcm2837/intc.c b/platform/bcm2837/intc.c new file mode 100644 index 000000000..baed72119 --- /dev/null +++ b/platform/bcm2837/intc.c @@ -0,0 +1,286 @@ +/* + * 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 + +#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 + 0x50) +#define INTC_LOCAL_MAILBOX_INT_CONTROL1 (ARM_LOCAL_BASE + 0x54) +#define INTC_LOCAL_MAILBOX_INT_CONTROL2 (ARM_LOCAL_BASE + 0x58) +#define INTC_LOCAL_MAILBOX_INT_CONTROL3 (ARM_LOCAL_BASE + 0x5c) + +#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) + +#define INTC_LOCAL_MAILBOX0_SET0 (ARM_LOCAL_BASE + 0x80) +#define INTC_LOCAL_MAILBOX0_SET1 (ARM_LOCAL_BASE + 0x90) +#define INTC_LOCAL_MAILBOX0_SET2 (ARM_LOCAL_BASE + 0xa0) +#define INTC_LOCAL_MAILBOX0_SET3 (ARM_LOCAL_BASE + 0xb0) + +#define INTC_LOCAL_MAILBOX0_CLR0 (ARM_LOCAL_BASE + 0xc0) +#define INTC_LOCAL_MAILBOX0_CLR1 (ARM_LOCAL_BASE + 0xd0) +#define INTC_LOCAL_MAILBOX0_CLR2 (ARM_LOCAL_BASE + 0xe0) +#define INTC_LOCAL_MAILBOX0_CLR3 (ARM_LOCAL_BASE + 0xf0) + +struct int_handler_struct { + int_handler handler; + void *arg; +}; + +static struct int_handler_struct int_handler_table[MAX_INT]; + +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, mask on all cpus + for (uint cpu = 0; cpu < 4; cpu++) { + 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, unmask for all cpus + for (uint cpu = 0; cpu < 4; cpu++) { + 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) +{ + 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].handler = handler; + int_handler_table[vector].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("cpu %u vector %u\n", cpu, vector); + + // dispatch the irq + enum handler_return ret = INT_NO_RESCHEDULE; + +#if WITH_SMP + if (vector == INTERRUPT_ARM_LOCAL_MAILBOX0) { + pend = *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu); + LTRACEF("mailbox0 clr 0x%x\n", pend); + + // ack it + *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu) = pend; + + if (pend & (1 << MP_IPI_GENERIC)) { + PANIC_UNIMPLEMENTED; + } + if (pend & (1 << MP_IPI_RESCHEDULE)) { + ret = mp_mbx_reschedule_irq(); + } + } else +#endif // WITH_SMP + if (vector == 0xffffffff) { + ret = INT_NO_RESCHEDULE; + } else if (int_handler_table[vector].handler) { + ret = int_handler_table[vector].handler(int_handler_table[vector].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 bcm2835_send_ipi(uint irq, uint cpu_mask) +{ + LTRACEF("irq %u, cpu_mask 0x%x\n", irq, cpu_mask); + + for (uint i = 0; i < 4; i++) { + if (cpu_mask & (1< +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void intc_init(void); +extern void arm_reset(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 = MEMORY_APERTURE_SIZE, + .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" + }, + + /* 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); + + + /* look for a flattened device tree just before the kernel */ + const void *fdt = (void *)KERNEL_BASE; + int err = fdt_check_header(fdt); + if (err >= 0) { + /* walk the nodes, looking for 'memory' */ + int depth = 0; + int offset = 0; + for (;;) { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0) + break; + + /* get the name */ + const char *name = fdt_get_name(fdt, offset, NULL); + if (!name) + continue; + + /* look for the 'memory' property */ + if (strcmp(name, "memory") == 0) { + printf("Found memory in fdt\n"); + int lenp; + const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); + if (prop_ptr && lenp == 0x10) { + /* we're looking at a memory descriptor */ + //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); + uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); + + /* trim size on certain platforms */ +#if ARCH_ARM + if (len > 1024*1024*1024U) { + len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ + printf("trimming memory to 1GB\n"); + } +#endif + + /* set the size in the pmm arena */ + arena.size = len; + } + } + } + } + + /* add the main memory arena */ + pmm_add_arena(&arena); + + /* reserve the first 64k of ram, which should be holding the fdt */ + struct list_node list = LIST_INITIAL_VALUE(list); + pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list); + +#if WITH_SMP + /* start the other cpus */ + uintptr_t sec_entry = (uintptr_t)&arm_reset; + sec_entry -= (KERNEL_BASE - MEMBASE); + for (uint i = 1; i <= 3; i++) { + *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; + } +#endif +} + +void platform_init(void) +{ + uart_init(); +} + +#define DEBUG_UART 1 + +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/bcm2837/rules.mk b/platform/bcm2837/rules.mk new file mode 100644 index 000000000..c01b3e70d --- /dev/null +++ b/platform/bcm2837/rules.mk @@ -0,0 +1,48 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +ARCH := arm64 +ARM_CPU := cortex-a53 +WITH_SMP := 1 +#LK_HEAP_IMPLEMENTATION ?= dlmalloc +WITH_CPP_SUPPORT=true + +MODULE_DEPS := \ + dev/timer/arm_generic \ + lib/cbuf \ + app/shell \ + app/tests \ + lib/fdt \ + +#lib/bio \ + lib/cbuf \ + lib/minip \ + dev/interrupt/arm_gic \ + dev/timer/arm_cortex_a9 + +MODULE_SRCS += \ + $(LOCAL_DIR)/gpio.c \ + $(LOCAL_DIR)/intc.c \ + $(LOCAL_DIR)/platform.c \ + $(LOCAL_DIR)/uart.c \ + +MEMBASE := 0x00000000 +MEMSIZE ?= 0x40000000 # 256MB +KERNEL_LOAD_OFFSET := 0x00080000 + + + +# put our kernel at 0x80000000 +#KERNEL_BASE = 0xFFFF000000080000 + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) \ + MMU_WITH_TRAMPOLINE=1 \ + ARM_ARCH_WAIT_FOR_SECONDARIES=1 + +LINKER_SCRIPT += \ + $(BUILDDIR)/system-onesegment.ld + +include make/module.mk diff --git a/platform/bcm2837/uart.c b/platform/bcm2837/uart.c new file mode 100644 index 000000000..2ae115ea8 --- /dev/null +++ b/platform/bcm2837/uart.c @@ -0,0 +1,217 @@ +/* + * 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) { + case 0: + return UART0_BASE; + default: + case 1: + return UART1_BASE; + } +} + + + +#define BIT(x) (1 << (x)) + +#define BCM2835_MU_BASE 0x3f215040 +#define BCM2835_MU_BASE2 0xffffffffc0215040ULL + +struct bcm283x_mu_regs { + uint32_t io; + uint32_t iir; + uint32_t ier; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +}; + +/* This actually means not full, but is named not empty in the docs */ +#define BCM283X_MU_LSR_TX_EMPTY BIT(5) +#define BCM283X_MU_LSR_RX_READY BIT(0) + +#define __arch_getl(a) (*(volatile unsigned int *)(a)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) +#define __arch_get32(a) (*(volatile uint32_t *)(a)) + +#define dmb() __asm__ __volatile__ ("" : : : "memory") +#define __iormb() dmb() +#define __iowmb() dmb() + +#define readl(c) ({ uint32_t __v = __arch_getl(c); __iormb(); __v; }) +#define writel(v,c) ({ uint32_t __v = v; __iowmb(); __arch_putl(__v,c); __v; }) + +static void bcm283x_mu_serial_putc(const char data) +{ + struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)BCM2835_MU_BASE; + + /* Wait until there is space in the FIFO */ + while (!(readl(®s->lsr) & BCM283X_MU_LSR_TX_EMPTY)) + ; + + /* Send the character */ + writel(data, ®s->io); +} + + +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++) { + size_t i =1; + // 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(1), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten + //} +} + +int uart_putc(int port, char c) +{ + + struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)BCM2835_MU_BASE2; + + /* Wait until there is space in the FIFO */ + while (!(readl(®s->lsr) & BCM283X_MU_LSR_TX_EMPTY)) + ; + + /* Send the character */ + writel(c, ®s->io); + + 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/rpi3-test.mk b/project/rpi3-test.mk new file mode 100644 index 000000000..4e7991bcd --- /dev/null +++ b/project/rpi3-test.mk @@ -0,0 +1,11 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +TARGET := rpi3 + +MODULES += \ + app/shell \ + app/stringtests \ + app/tests \ + lib/cksum \ + lib/debugcommands \ + diff --git a/target/rpi3/rules.mk b/target/rpi3/rules.mk new file mode 100644 index 000000000..264e217ff --- /dev/null +++ b/target/rpi3/rules.mk @@ -0,0 +1,9 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +GLOBAL_INCLUDES += \ + $(LOCAL_DIR)/include + +PLATFORM := bcm2837 + +#include make/module.mk + From edb702078104e8a1245a1b8a0120568a999f4762 Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Wed, 13 Jul 2016 15:02:48 -0700 Subject: [PATCH 02/12] [miniuart][uart][rpi3][bcm28xx] Miniuart Driver for Raspberry Pi 3 / BCM28XX --- platform/bcm2837/include/platform/bcm2837.h | 3 +- platform/bcm2837/miniuart.c | 176 ++++++++++++++++++++ platform/bcm2837/rules.mk | 2 +- 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 platform/bcm2837/miniuart.c diff --git a/platform/bcm2837/include/platform/bcm2837.h b/platform/bcm2837/include/platform/bcm2837.h index bff557d80..7493bee6c 100644 --- a/platform/bcm2837/include/platform/bcm2837.h +++ b/platform/bcm2837/include/platform/bcm2837.h @@ -47,7 +47,8 @@ #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 AUX_BASE (BCM_PERIPH_BASE_VIRT + 0x215000) +#define MINIUART_BASE (BCM_PERIPH_BASE_VIRT + 0x215040) #define EMMC_BASE (BCM_PERIPH_BASE_VIRT + 0x300000) #define SMI_BASE (BCM_PERIPH_BASE_VIRT + 0x600000) #define BSC1_BASE (BCM_PERIPH_BASE_VIRT + 0x804000) diff --git a/platform/bcm2837/miniuart.c b/platform/bcm2837/miniuart.c new file mode 100644 index 000000000..6206242a5 --- /dev/null +++ b/platform/bcm2837/miniuart.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016 Gurjant Kalsi + * + * 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. + */ + +// TODO(gkalsi): Unify the two UART codepaths and use the port parameter to +// select between the real uart and the miniuart. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RXBUF_SIZE 16 + +static cbuf_t uart_rx_buf; + +struct bcm283x_mu_regs { + uint32_t io; + uint32_t ier; + uint32_t iir; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +}; + +struct bcm283x_aux_regs { + uint32_t auxirq; + uint32_t auxenb; +}; + +#define AUX_IRQ_MINIUART (1 << 0) +#define AUX_ENB_MINIUART (1 << 0) + +#define MU_IIR_BYTE_AVAIL (1 << 2) // For reading +#define MU_IIR_CLR_XMIT_FIFO (1 << 2) // For writing. +#define MU_IIR_CLR_RECV_FIFO (1 << 1) + +#define MU_IIR_EN_RX_IRQ (1 << 0) // Enable the recv interrupt. + +#define MU_LSR_TX_EMPTY (1 << 5) + +static enum handler_return aux_irq(void *arg) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + volatile struct bcm283x_aux_regs *aux_regs = + (struct bcm283x_aux_regs *)AUX_BASE; + + // Make sure this interrupt is intended for the miniuart. + uint32_t auxirq = readl(&aux_regs->auxirq); + if ((auxirq & AUX_IRQ_MINIUART) == 0) { + return INT_NO_RESCHEDULE; + } + + bool resched = false; + + while (true) { + uint32_t iir = readl(&mu_regs->iir); + if ((iir & MU_IIR_BYTE_AVAIL) == 0) break; + + resched = true; + char ch = readl(&mu_regs->io); + cbuf_write_char(&uart_rx_buf, ch, false); + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +int uart_putc(int port, char c) +{ + // There's only one UART for now. + // TODO(gkalsi): Unify the two UART code paths using the port. + struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)MINIUART_BASE; + + /* Wait until there is space in the FIFO */ + while (!(readl(®s->lsr) & MU_LSR_TX_EMPTY)) + ; + + /* Send the character */ + writel(c, ®s->io); + + return 1; +} + +void uart_init(void) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + volatile struct bcm283x_aux_regs *aux_regs = + (struct bcm283x_aux_regs *)AUX_BASE; + + // Create circular buffer to hold received data. + cbuf_initialize(&uart_rx_buf, RXBUF_SIZE); + + // AUX Interrupt handler handles interrupts for SPI1, SPI2, and miniuart + // Interrupt handler must decode IRQ. + register_int_handler(INTERRUPT_AUX, &aux_irq, NULL); + + // Enable the Interrupt. + unmask_interrupt(INTERRUPT_AUX); + + writel(MU_IIR_CLR_RECV_FIFO | MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); + + // Enable the miniuart peripheral. This also enables Miniuart register + // access. It's likely that the VideoCore chip already enables this + // peripheral for us, but we hit the enable bit just to be sure. + writel(AUX_ENB_MINIUART, &aux_regs->auxenb); + + // Enable the receive interrupt on the UART peripheral. + writel(MU_IIR_EN_RX_IRQ, &mu_regs->ier); +} + +void uart_init_early(void) +{ +} + +int uart_getc(int port, bool wait) +{ + cbuf_t *rxbuf = &uart_rx_buf; + + char c; + if (cbuf_read_char(rxbuf, &c, wait) == 1) + return c; + + return -1; +} + +void uart_flush_tx(int port) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + writel(MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); +} + +void uart_flush_rx(int port) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + writel(MU_IIR_CLR_RECV_FIFO, &mu_regs->iir); +} + +void uart_init_port(int port, uint baud) +{ +} + + + diff --git a/platform/bcm2837/rules.mk b/platform/bcm2837/rules.mk index c01b3e70d..6aaccaac7 100644 --- a/platform/bcm2837/rules.mk +++ b/platform/bcm2837/rules.mk @@ -25,7 +25,7 @@ MODULE_SRCS += \ $(LOCAL_DIR)/gpio.c \ $(LOCAL_DIR)/intc.c \ $(LOCAL_DIR)/platform.c \ - $(LOCAL_DIR)/uart.c \ + $(LOCAL_DIR)/miniuart.c \ MEMBASE := 0x00000000 MEMSIZE ?= 0x40000000 # 256MB From 100133dc38720e8ca00e9012f32c5d9ee2a00d1b Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Wed, 13 Jul 2016 17:31:53 -0700 Subject: [PATCH 03/12] [BCM28xx] Roll BCM2836 and BCM2837 into a single platform. Have both RPi2 and RPi3 use the new BCM28XX platform. --- arch/arm/arm/mp.c | 6 +- platform/bcm28xx/gpio.c | 57 ++++ platform/bcm28xx/include/platform/bcm28xx.h | 210 ++++++++++++++ platform/bcm28xx/intc.c | 294 ++++++++++++++++++++ platform/bcm28xx/miniuart.c | 176 ++++++++++++ platform/bcm28xx/platform.c | 217 +++++++++++++++ platform/bcm28xx/rules.mk | 71 +++++ platform/bcm28xx/uart.c | 159 +++++++++++ target/rpi2/rules.mk | 2 +- target/rpi3/rules.mk | 2 +- 10 files changed, 1188 insertions(+), 6 deletions(-) create mode 100644 platform/bcm28xx/gpio.c create mode 100644 platform/bcm28xx/include/platform/bcm28xx.h create mode 100644 platform/bcm28xx/intc.c create mode 100644 platform/bcm28xx/miniuart.c create mode 100644 platform/bcm28xx/platform.c create mode 100644 platform/bcm28xx/rules.mk create mode 100644 platform/bcm28xx/uart.c diff --git a/arch/arm/arm/mp.c b/arch/arm/arm/mp.c index a27a9206b..71da3fd7d 100644 --- a/arch/arm/arm/mp.c +++ b/arch/arm/arm/mp.c @@ -30,10 +30,8 @@ #if WITH_DEV_INTERRUPT_ARM_GIC #include -#elif PLATFORM_BCM2835 -/* bcm2835 has a weird custom interrupt controller for MP */ -extern void bcm2835_send_ipi(uint irq, uint cpu_mask); -#elif PLATFORM_BCM2837 +#elif PLATFORM_BCM28XX +/* bcm28xx has a weird custom interrupt controller for MP */ extern void bcm2835_send_ipi(uint irq, uint cpu_mask); #else #error need other implementation of interrupt controller that can ipi diff --git a/platform/bcm28xx/gpio.c b/platform/bcm28xx/gpio.c new file mode 100644 index 000000000..49c31df93 --- /dev/null +++ b/platform/bcm28xx/gpio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Adam Barth + * + * 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 + +#define NUM_PINS 54 +#define BITS_PER_REG 32 +#define BITS_PER_PIN 3 +#define PINS_PER_REG (BITS_PER_REG / BITS_PER_PIN) +#define GPIOREG(base, nr) (REG32(base) + (nr / BITS_PER_REG)) + +int gpio_config(unsigned nr, unsigned flags) +{ + unsigned mask = 0x7; + if (nr >= NUM_PINS || flags & ~mask) + return -EINVAL; + unsigned register_number = nr / PINS_PER_REG; + unsigned offset = (nr % PINS_PER_REG) * BITS_PER_PIN; + unsigned shifted_mask = mask << offset; + volatile uint32_t *reg = REG32(GPIO_GPFSEL0) + register_number; + *reg = (*reg & ~shifted_mask) | (flags << offset); + return 0; +} + +void gpio_set(unsigned nr, unsigned on) +{ + unsigned offset = nr % BITS_PER_REG; + *GPIOREG(on ? GPIO_GPSET0 : GPIO_GPCLR0, nr) = 1 << offset; +} + +int gpio_get(unsigned nr) +{ + unsigned offset = nr % BITS_PER_REG; + return (*GPIOREG(GPIO_GPLEV0, nr) & (1 << offset)) >> offset; +} diff --git a/platform/bcm28xx/include/platform/bcm28xx.h b/platform/bcm28xx/include/platform/bcm28xx.h new file mode 100644 index 000000000..058a02d64 --- /dev/null +++ b/platform/bcm28xx/include/platform/bcm28xx.h @@ -0,0 +1,210 @@ +/* + * 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 +/* Note: BCM2836/BCM2837 use different peripheral base than BCM2835 */ +#define BCM_PERIPH_BASE_PHYS (0x3f000000U) +#define BCM_PERIPH_SIZE (0x01100000U) + +#if BCM2836 +#define BCM_PERIPH_BASE_VIRT (0xe0000000U) +#elif BCM2837 +#define BCM_PERIPH_BASE_VIRT (0xffffffffc0000000ULL) +#define MEMORY_APERTURE_SIZE (1024 * 1024 * 1024) +#else +#error Unknown BCM28XX Variant +#endif + +/* 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 AUX_BASE (BCM_PERIPH_BASE_VIRT + 0x215000) +#define MINIUART_BASE (BCM_PERIPH_BASE_VIRT + 0x215040) +#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 + +/* GPIO */ + +#define GPIO_GPFSEL0 (GPIO_BASE + 0x00) +#define GPIO_GPFSEL1 (GPIO_BASE + 0x04) +#define GPIO_GPFSEL2 (GPIO_BASE + 0x08) +#define GPIO_GPFSEL3 (GPIO_BASE + 0x0C) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPSET0 (GPIO_BASE + 0x1C) +#define GPIO_GPSET1 (GPIO_BASE + 0x20) +#define GPIO_GPCLR0 (GPIO_BASE + 0x28) +#define GPIO_GPCLR1 (GPIO_BASE + 0x2C) +#define GPIO_GPLEV0 (GPIO_BASE + 0x34) +#define GPIO_GPLEV1 (GPIO_BASE + 0x38) +#define GPIO_GPEDS0 (GPIO_BASE + 0x40) +#define GPIO_GPEDS1 (GPIO_BASE + 0x44) +#define GPIO_GPREN0 (GPIO_BASE + 0x4C) +#define GPIO_GPREN1 (GPIO_BASE + 0x50) +#define GPIO_GPFEN0 (GPIO_BASE + 0x58) +#define GPIO_GPFEN1 (GPIO_BASE + 0x5C) +#define GPIO_GPHEN0 (GPIO_BASE + 0x64) +#define GPIO_GPHEN1 (GPIO_BASE + 0x68) +#define GPIO_GPLEN0 (GPIO_BASE + 0x70) +#define GPIO_GPLEN1 (GPIO_BASE + 0x74) +#define GPIO_GPAREN0 (GPIO_BASE + 0x7C) +#define GPIO_GPAREN1 (GPIO_BASE + 0x80) +#define GPIO_GPAFEN0 (GPIO_BASE + 0x88) +#define GPIO_GPAFEN1 (GPIO_BASE + 0x8C) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK0 (GPIO_BASE + 0x98) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9C) diff --git a/platform/bcm28xx/intc.c b/platform/bcm28xx/intc.c new file mode 100644 index 000000000..5e78d42c2 --- /dev/null +++ b/platform/bcm28xx/intc.c @@ -0,0 +1,294 @@ +/* + * 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 + +#if defined (BCM2836) +#include +#elif defined (BCM2837) +#include +#else +#error Unknown BCM28XX Variant +#endif + + +#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 + 0x50) +#define INTC_LOCAL_MAILBOX_INT_CONTROL1 (ARM_LOCAL_BASE + 0x54) +#define INTC_LOCAL_MAILBOX_INT_CONTROL2 (ARM_LOCAL_BASE + 0x58) +#define INTC_LOCAL_MAILBOX_INT_CONTROL3 (ARM_LOCAL_BASE + 0x5c) + +#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) + +#define INTC_LOCAL_MAILBOX0_SET0 (ARM_LOCAL_BASE + 0x80) +#define INTC_LOCAL_MAILBOX0_SET1 (ARM_LOCAL_BASE + 0x90) +#define INTC_LOCAL_MAILBOX0_SET2 (ARM_LOCAL_BASE + 0xa0) +#define INTC_LOCAL_MAILBOX0_SET3 (ARM_LOCAL_BASE + 0xb0) + +#define INTC_LOCAL_MAILBOX0_CLR0 (ARM_LOCAL_BASE + 0xc0) +#define INTC_LOCAL_MAILBOX0_CLR1 (ARM_LOCAL_BASE + 0xd0) +#define INTC_LOCAL_MAILBOX0_CLR2 (ARM_LOCAL_BASE + 0xe0) +#define INTC_LOCAL_MAILBOX0_CLR3 (ARM_LOCAL_BASE + 0xf0) + +struct int_handler_struct { + int_handler handler; + void *arg; +}; + +static struct int_handler_struct int_handler_table[MAX_INT]; + +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, mask on all cpus + for (uint cpu = 0; cpu < 4; cpu++) { + 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, unmask for all cpus + for (uint cpu = 0; cpu < 4; cpu++) { + 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) +{ + 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].handler = handler; + int_handler_table[vector].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("cpu %u vector %u\n", cpu, vector); + + // dispatch the irq + enum handler_return ret = INT_NO_RESCHEDULE; + +#if WITH_SMP + if (vector == INTERRUPT_ARM_LOCAL_MAILBOX0) { + pend = *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu); + LTRACEF("mailbox0 clr 0x%x\n", pend); + + // ack it + *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu) = pend; + + if (pend & (1 << MP_IPI_GENERIC)) { + PANIC_UNIMPLEMENTED; + } + if (pend & (1 << MP_IPI_RESCHEDULE)) { + ret = mp_mbx_reschedule_irq(); + } + } else +#endif // WITH_SMP + if (vector == 0xffffffff) { + ret = INT_NO_RESCHEDULE; + } else if (int_handler_table[vector].handler) { + ret = int_handler_table[vector].handler(int_handler_table[vector].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 bcm2835_send_ipi(uint irq, uint cpu_mask) +{ + LTRACEF("irq %u, cpu_mask 0x%x\n", irq, cpu_mask); + + for (uint i = 0; i < 4; i++) { + if (cpu_mask & (1< +#include +#include +#include +#include +#include +#include +#include +#include + +#define RXBUF_SIZE 16 + +static cbuf_t uart_rx_buf; + +struct bcm283x_mu_regs { + uint32_t io; + uint32_t ier; + uint32_t iir; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +}; + +struct bcm283x_aux_regs { + uint32_t auxirq; + uint32_t auxenb; +}; + +#define AUX_IRQ_MINIUART (1 << 0) +#define AUX_ENB_MINIUART (1 << 0) + +#define MU_IIR_BYTE_AVAIL (1 << 2) // For reading +#define MU_IIR_CLR_XMIT_FIFO (1 << 2) // For writing. +#define MU_IIR_CLR_RECV_FIFO (1 << 1) + +#define MU_IIR_EN_RX_IRQ (1 << 0) // Enable the recv interrupt. + +#define MU_LSR_TX_EMPTY (1 << 5) + +static enum handler_return aux_irq(void *arg) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + volatile struct bcm283x_aux_regs *aux_regs = + (struct bcm283x_aux_regs *)AUX_BASE; + + // Make sure this interrupt is intended for the miniuart. + uint32_t auxirq = readl(&aux_regs->auxirq); + if ((auxirq & AUX_IRQ_MINIUART) == 0) { + return INT_NO_RESCHEDULE; + } + + bool resched = false; + + while (true) { + uint32_t iir = readl(&mu_regs->iir); + if ((iir & MU_IIR_BYTE_AVAIL) == 0) break; + + resched = true; + char ch = readl(&mu_regs->io); + cbuf_write_char(&uart_rx_buf, ch, false); + } + + return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; +} + +int uart_putc(int port, char c) +{ + // There's only one UART for now. + // TODO(gkalsi): Unify the two UART code paths using the port. + struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)MINIUART_BASE; + + /* Wait until there is space in the FIFO */ + while (!(readl(®s->lsr) & MU_LSR_TX_EMPTY)) + ; + + /* Send the character */ + writel(c, ®s->io); + + return 1; +} + +void uart_init(void) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + volatile struct bcm283x_aux_regs *aux_regs = + (struct bcm283x_aux_regs *)AUX_BASE; + + // Create circular buffer to hold received data. + cbuf_initialize(&uart_rx_buf, RXBUF_SIZE); + + // AUX Interrupt handler handles interrupts for SPI1, SPI2, and miniuart + // Interrupt handler must decode IRQ. + register_int_handler(INTERRUPT_AUX, &aux_irq, NULL); + + // Enable the Interrupt. + unmask_interrupt(INTERRUPT_AUX); + + writel(MU_IIR_CLR_RECV_FIFO | MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); + + // Enable the miniuart peripheral. This also enables Miniuart register + // access. It's likely that the VideoCore chip already enables this + // peripheral for us, but we hit the enable bit just to be sure. + writel(AUX_ENB_MINIUART, &aux_regs->auxenb); + + // Enable the receive interrupt on the UART peripheral. + writel(MU_IIR_EN_RX_IRQ, &mu_regs->ier); +} + +void uart_init_early(void) +{ +} + +int uart_getc(int port, bool wait) +{ + cbuf_t *rxbuf = &uart_rx_buf; + + char c; + if (cbuf_read_char(rxbuf, &c, wait) == 1) + return c; + + return -1; +} + +void uart_flush_tx(int port) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + writel(MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); +} + +void uart_flush_rx(int port) +{ + volatile struct bcm283x_mu_regs *mu_regs = + (struct bcm283x_mu_regs *)MINIUART_BASE; + writel(MU_IIR_CLR_RECV_FIFO, &mu_regs->iir); +} + +void uart_init_port(int port, uint baud) +{ +} + + + diff --git a/platform/bcm28xx/platform.c b/platform/bcm28xx/platform.c new file mode 100644 index 000000000..1b63500c3 --- /dev/null +++ b/platform/bcm28xx/platform.c @@ -0,0 +1,217 @@ +/* + * 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 + +#if BCM2836 +#include +#include + +/* 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 } +}; + +#define DEBUG_UART 0 + +#elif BCM2837 +#include +#include +#include + +/* 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 = MEMORY_APERTURE_SIZE, + .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" + }, + + /* null entry to terminate the list */ + { 0 } +}; + +#define DEBUG_UART 1 + +#else +#error Unknown BCM28XX Variant +#endif + +extern void intc_init(void); +extern void arm_reset(void); + + +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); + +#if BCM2837 + /* look for a flattened device tree just before the kernel */ + const void *fdt = (void *)KERNEL_BASE; + int err = fdt_check_header(fdt); + if (err >= 0) { + /* walk the nodes, looking for 'memory' */ + int depth = 0; + int offset = 0; + for (;;) { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0) + break; + + /* get the name */ + const char *name = fdt_get_name(fdt, offset, NULL); + if (!name) + continue; + + /* look for the 'memory' property */ + if (strcmp(name, "memory") == 0) { + printf("Found memory in fdt\n"); + int lenp; + const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); + if (prop_ptr && lenp == 0x10) { + /* we're looking at a memory descriptor */ + //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); + uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); + + /* trim size on certain platforms */ +#if ARCH_ARM + if (len > 1024*1024*1024U) { + len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ + printf("trimming memory to 1GB\n"); + } +#endif + + /* set the size in the pmm arena */ + arena.size = len; + } + } + } + } + +#endif + + /* add the main memory arena */ + pmm_add_arena(&arena); + +#if BCM2837 + /* reserve the first 64k of ram, which should be holding the fdt */ + struct list_node list = LIST_INITIAL_VALUE(list); + pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list); +#endif + +#if WITH_SMP + /* start the other cpus */ + uintptr_t sec_entry = (uintptr_t)&arm_reset; + sec_entry -= (KERNEL_BASE - MEMBASE); + for (uint i = 1; i <= 3; i++) { + *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; + } +#endif +} + +void platform_init(void) +{ + uart_init(); +} + +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/bcm28xx/rules.mk b/platform/bcm28xx/rules.mk new file mode 100644 index 000000000..07361f67e --- /dev/null +++ b/platform/bcm28xx/rules.mk @@ -0,0 +1,71 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +WITH_SMP := 1 +#LK_HEAP_IMPLEMENTATION ?= dlmalloc + +MODULE_DEPS := \ + dev/timer/arm_generic \ + lib/cbuf + + +#lib/bio \ + lib/cbuf \ + lib/minip \ + dev/interrupt/arm_gic \ + dev/timer/arm_cortex_a9 + +MODULE_SRCS += \ + $(LOCAL_DIR)/gpio.c \ + $(LOCAL_DIR)/intc.c \ + $(LOCAL_DIR)/platform.c \ + +MEMBASE := 0x00000000 + +GLOBAL_DEFINES += \ + ARM_ARCH_WAIT_FOR_SECONDARIES=1 + +LINKER_SCRIPT += \ + $(BUILDDIR)/system-onesegment.ld + +ifeq ($(TARGET),rpi2) +ARCH := arm +ARM_CPU := cortex-a7 +# put our kernel at 0x80000000 +KERNEL_BASE = 0x80000000 +KERNEL_LOAD_OFFSET := 0x00008000 +MEMSIZE ?= 0x10000000 # 256MB +SMP_CPU_ID_BITS := 8 +GLOBAL_DEFINES += \ + BCM2836=1 + +MODULE_SRCS += \ + $(LOCAL_DIR)/uart.c + +else ifeq ($(TARGET),rpi3) +ARCH := arm64 +ARM_CPU := cortex-a53 + +KERNEL_LOAD_OFFSET := 0x00080000 +MEMSIZE ?= 0x40000000 # 1GB + +GLOBAL_DEFINES += \ + MEMBASE=$(MEMBASE) \ + MEMSIZE=$(MEMSIZE) \ + MMU_WITH_TRAMPOLINE=1 \ + BCM2837=1 + +MODULE_SRCS += \ + $(LOCAL_DIR)/miniuart.c + +MODULE_DEPS += \ + app/shell \ + app/tests \ + lib/fdt + +WITH_CPP_SUPPORT=true + +endif + +include make/module.mk diff --git a/platform/bcm28xx/uart.c b/platform/bcm28xx/uart.c new file mode 100644 index 000000000..7ef0effb4 --- /dev/null +++ b/platform/bcm28xx/uart.c @@ -0,0 +1,159 @@ +/* + * 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/target/rpi2/rules.mk b/target/rpi2/rules.mk index 41ffb2ed2..fe10d50d7 100644 --- a/target/rpi2/rules.mk +++ b/target/rpi2/rules.mk @@ -3,7 +3,7 @@ LOCAL_DIR := $(GET_LOCAL_DIR) GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include -PLATFORM := bcm2835 +PLATFORM := bcm28xx #include make/module.mk diff --git a/target/rpi3/rules.mk b/target/rpi3/rules.mk index 264e217ff..fe10d50d7 100644 --- a/target/rpi3/rules.mk +++ b/target/rpi3/rules.mk @@ -3,7 +3,7 @@ LOCAL_DIR := $(GET_LOCAL_DIR) GLOBAL_INCLUDES += \ $(LOCAL_DIR)/include -PLATFORM := bcm2837 +PLATFORM := bcm28xx #include make/module.mk From 69d35fa55bdd03eb128515670f7553993be58871 Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Thu, 14 Jul 2016 12:37:26 -0700 Subject: [PATCH 04/12] [rpi3][bcm28xx][timer] Fix BCM2837 timer runing too fast. RPi3/BCM2837 timer was previously running too fast due to an improper multiplier in arm_generic_timer_init(...). Fixed by setting the multiplier to 0 and allowing the ARM generic timer code to determine the frequency and compute the appropriate multiplier. --- platform/bcm28xx/platform.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/bcm28xx/platform.c b/platform/bcm28xx/platform.c index 1b63500c3..eb81d085e 100644 --- a/platform/bcm28xx/platform.c +++ b/platform/bcm28xx/platform.c @@ -128,9 +128,9 @@ void platform_early_init(void) intc_init(); - arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000); - #if BCM2837 + arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 0); + /* look for a flattened device tree just before the kernel */ const void *fdt = (void *)KERNEL_BASE; int err = fdt_check_header(fdt); @@ -173,6 +173,10 @@ void platform_early_init(void) } } +#elif BCM2836 + arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000); +#else +#error Unknown BCM28XX Variant #endif /* add the main memory arena */ From 5e5e2ac50c00313aad6298ef1e13a02157384ad4 Mon Sep 17 00:00:00 2001 From: Eric Holland Date: Fri, 15 Jul 2016 10:27:42 -0700 Subject: [PATCH 05/12] [rpi3][bcm28xx][smp] fixes to bring up all cores --- arch/arm64/start.S | 5 +++++ platform/bcm28xx/platform.c | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/arm64/start.S b/arch/arm64/start.S index bede18eee..2faf63079 100644 --- a/arch/arm64/start.S +++ b/arch/arm64/start.S @@ -100,6 +100,11 @@ arm_reset: .Lnot_device: .Lmapping_size_loop: + ldr attr, =MMU_PTE_KERNEL_DATA_FLAGS + ldr tmp, =arm_reset + subs size, tmp, vaddr + b.hi .Lmem_type_done + ldr attr, =MMU_PTE_KERNEL_RO_FLAGS ldr tmp, =__rodata_start subs size, tmp, vaddr diff --git a/platform/bcm28xx/platform.c b/platform/bcm28xx/platform.c index eb81d085e..486249107 100644 --- a/platform/bcm28xx/platform.c +++ b/platform/bcm28xx/platform.c @@ -189,6 +189,17 @@ void platform_early_init(void) #endif #if WITH_SMP +#if BCM2837 + uintptr_t sec_entry = &arm_reset - KERNEL_ASPACE_BASE; + unsigned long long *spin_table = (void *)(KERNEL_ASPACE_BASE + 0xd8); + + for (uint i = 1; i <= 3; i++) { + spin_table[i] = sec_entry; + __asm__ __volatile__ ("" : : : "memory"); + arch_clean_cache_range(0xffff000000000000,256); + __asm__ __volatile__("sev"); + } +#else /* start the other cpus */ uintptr_t sec_entry = (uintptr_t)&arm_reset; sec_entry -= (KERNEL_BASE - MEMBASE); @@ -196,6 +207,7 @@ void platform_early_init(void) *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; } #endif +#endif } void platform_init(void) From bc5f276c02194c41af78df977b456d346d2a8aba Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Tue, 23 Aug 2016 12:35:14 -0700 Subject: [PATCH 06/12] [bcm2835][bcm2837] Removed BCM2835 and BCM2837 platforms in favor of BCM28xx unified platform. --- platform/bcm2835/gpio.c | 57 ---- platform/bcm2835/include/platform/bcm2835.h | 201 -------------- platform/bcm2835/include/platform/gic.h | 31 --- platform/bcm2835/intc.c | 286 -------------------- platform/bcm2835/platform.c | 128 --------- platform/bcm2835/rules.mk | 42 --- platform/bcm2835/uart.c | 159 ----------- platform/bcm2837/gpio.c | 57 ---- platform/bcm2837/include/platform/bcm2837.h | 204 -------------- platform/bcm2837/include/platform/gic.h | 31 --- platform/bcm2837/intc.c | 286 -------------------- platform/bcm2837/miniuart.c | 176 ------------ platform/bcm2837/platform.c | 169 ------------ platform/bcm2837/rules.mk | 48 ---- platform/bcm2837/uart.c | 217 --------------- 15 files changed, 2092 deletions(-) delete mode 100644 platform/bcm2835/gpio.c delete mode 100644 platform/bcm2835/include/platform/bcm2835.h delete mode 100644 platform/bcm2835/include/platform/gic.h delete mode 100644 platform/bcm2835/intc.c delete mode 100644 platform/bcm2835/platform.c delete mode 100644 platform/bcm2835/rules.mk delete mode 100644 platform/bcm2835/uart.c delete mode 100644 platform/bcm2837/gpio.c delete mode 100644 platform/bcm2837/include/platform/bcm2837.h delete mode 100644 platform/bcm2837/include/platform/gic.h delete mode 100644 platform/bcm2837/intc.c delete mode 100644 platform/bcm2837/miniuart.c delete mode 100644 platform/bcm2837/platform.c delete mode 100644 platform/bcm2837/rules.mk delete mode 100644 platform/bcm2837/uart.c diff --git a/platform/bcm2835/gpio.c b/platform/bcm2835/gpio.c deleted file mode 100644 index 2a0f2a0bf..000000000 --- a/platform/bcm2835/gpio.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016 Adam Barth - * - * 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 - -#define NUM_PINS 54 -#define BITS_PER_REG 32 -#define BITS_PER_PIN 3 -#define PINS_PER_REG (BITS_PER_REG / BITS_PER_PIN) -#define GPIOREG(base, nr) (REG32(base) + (nr / BITS_PER_REG)) - -int gpio_config(unsigned nr, unsigned flags) -{ - unsigned mask = 0x7; - if (nr >= NUM_PINS || flags & ~mask) - return -EINVAL; - unsigned register_number = nr / PINS_PER_REG; - unsigned offset = (nr % PINS_PER_REG) * BITS_PER_PIN; - unsigned shifted_mask = mask << offset; - volatile uint32_t *reg = REG32(GPIO_GPFSEL0) + register_number; - *reg = (*reg & ~shifted_mask) | (flags << offset); - return 0; -} - -void gpio_set(unsigned nr, unsigned on) -{ - unsigned offset = nr % BITS_PER_REG; - *GPIOREG(on ? GPIO_GPSET0 : GPIO_GPCLR0, nr) = 1 << offset; -} - -int gpio_get(unsigned nr) -{ - unsigned offset = nr % BITS_PER_REG; - return (*GPIOREG(GPIO_GPLEV0, nr) & (1 << offset)) >> offset; -} diff --git a/platform/bcm2835/include/platform/bcm2835.h b/platform/bcm2835/include/platform/bcm2835.h deleted file mode 100644 index f5192093b..000000000 --- a/platform/bcm2835/include/platform/bcm2835.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 - -/* GPIO */ - -#define GPIO_GPFSEL0 (GPIO_BASE + 0x00) -#define GPIO_GPFSEL1 (GPIO_BASE + 0x04) -#define GPIO_GPFSEL2 (GPIO_BASE + 0x08) -#define GPIO_GPFSEL3 (GPIO_BASE + 0x0C) -#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) -#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) -#define GPIO_GPSET0 (GPIO_BASE + 0x1C) -#define GPIO_GPSET1 (GPIO_BASE + 0x20) -#define GPIO_GPCLR0 (GPIO_BASE + 0x28) -#define GPIO_GPCLR1 (GPIO_BASE + 0x2C) -#define GPIO_GPLEV0 (GPIO_BASE + 0x34) -#define GPIO_GPLEV1 (GPIO_BASE + 0x38) -#define GPIO_GPEDS0 (GPIO_BASE + 0x40) -#define GPIO_GPEDS1 (GPIO_BASE + 0x44) -#define GPIO_GPREN0 (GPIO_BASE + 0x4C) -#define GPIO_GPREN1 (GPIO_BASE + 0x50) -#define GPIO_GPFEN0 (GPIO_BASE + 0x58) -#define GPIO_GPFEN1 (GPIO_BASE + 0x5C) -#define GPIO_GPHEN0 (GPIO_BASE + 0x64) -#define GPIO_GPHEN1 (GPIO_BASE + 0x68) -#define GPIO_GPLEN0 (GPIO_BASE + 0x70) -#define GPIO_GPLEN1 (GPIO_BASE + 0x74) -#define GPIO_GPAREN0 (GPIO_BASE + 0x7C) -#define GPIO_GPAREN1 (GPIO_BASE + 0x80) -#define GPIO_GPAFEN0 (GPIO_BASE + 0x88) -#define GPIO_GPAFEN1 (GPIO_BASE + 0x8C) -#define GPIO_GPPUD (GPIO_BASE + 0x94) -#define GPIO_GPPUDCLK0 (GPIO_BASE + 0x98) -#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9C) diff --git a/platform/bcm2835/include/platform/gic.h b/platform/bcm2835/include/platform/gic.h deleted file mode 100644 index d1e7c8ca7..000000000 --- a/platform/bcm2835/include/platform/gic.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 deleted file mode 100644 index 6bc2786dd..000000000 --- a/platform/bcm2835/intc.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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 - -#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 + 0x50) -#define INTC_LOCAL_MAILBOX_INT_CONTROL1 (ARM_LOCAL_BASE + 0x54) -#define INTC_LOCAL_MAILBOX_INT_CONTROL2 (ARM_LOCAL_BASE + 0x58) -#define INTC_LOCAL_MAILBOX_INT_CONTROL3 (ARM_LOCAL_BASE + 0x5c) - -#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) - -#define INTC_LOCAL_MAILBOX0_SET0 (ARM_LOCAL_BASE + 0x80) -#define INTC_LOCAL_MAILBOX0_SET1 (ARM_LOCAL_BASE + 0x90) -#define INTC_LOCAL_MAILBOX0_SET2 (ARM_LOCAL_BASE + 0xa0) -#define INTC_LOCAL_MAILBOX0_SET3 (ARM_LOCAL_BASE + 0xb0) - -#define INTC_LOCAL_MAILBOX0_CLR0 (ARM_LOCAL_BASE + 0xc0) -#define INTC_LOCAL_MAILBOX0_CLR1 (ARM_LOCAL_BASE + 0xd0) -#define INTC_LOCAL_MAILBOX0_CLR2 (ARM_LOCAL_BASE + 0xe0) -#define INTC_LOCAL_MAILBOX0_CLR3 (ARM_LOCAL_BASE + 0xf0) - -struct int_handler_struct { - int_handler handler; - void *arg; -}; - -static struct int_handler_struct int_handler_table[MAX_INT]; - -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, mask on all cpus - for (uint cpu = 0; cpu < 4; cpu++) { - 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, unmask for all cpus - for (uint cpu = 0; cpu < 4; cpu++) { - 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) -{ - 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].handler = handler; - int_handler_table[vector].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("cpu %u vector %u\n", cpu, vector); - - // dispatch the irq - enum handler_return ret = INT_NO_RESCHEDULE; - -#if WITH_SMP - if (vector == INTERRUPT_ARM_LOCAL_MAILBOX0) { - pend = *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu); - LTRACEF("mailbox0 clr 0x%x\n", pend); - - // ack it - *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu) = pend; - - if (pend & (1 << MP_IPI_GENERIC)) { - PANIC_UNIMPLEMENTED; - } - if (pend & (1 << MP_IPI_RESCHEDULE)) { - ret = mp_mbx_reschedule_irq(); - } - } else -#endif // WITH_SMP - if (vector == 0xffffffff) { - ret = INT_NO_RESCHEDULE; - } else if (int_handler_table[vector].handler) { - ret = int_handler_table[vector].handler(int_handler_table[vector].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 bcm2835_send_ipi(uint irq, uint cpu_mask) -{ - LTRACEF("irq %u, cpu_mask 0x%x\n", irq, cpu_mask); - - for (uint i = 0; i < 4; i++) { - if (cpu_mask & (1< -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void intc_init(void); -extern void arm_reset(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); - -#if WITH_SMP - /* start the other cpus */ - uintptr_t sec_entry = (uintptr_t)&arm_reset; - sec_entry -= (KERNEL_BASE - MEMBASE); - for (uint i = 1; i <= 3; i++) { - *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; - } -#endif -} - -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 deleted file mode 100644 index 6e863ee85..000000000 --- a/platform/bcm2835/rules.mk +++ /dev/null @@ -1,42 +0,0 @@ -LOCAL_DIR := $(GET_LOCAL_DIR) - -MODULE := $(LOCAL_DIR) - -ARCH := arm -ARM_CPU := cortex-a7 -WITH_SMP := 1 -SMP_CPU_ID_BITS := 8 - -MODULE_DEPS := \ - dev/timer/arm_generic \ - lib/cbuf - -#lib/bio \ - lib/cbuf \ - lib/minip \ - dev/interrupt/arm_gic \ - dev/timer/arm_cortex_a9 - -MODULE_SRCS += \ - $(LOCAL_DIR)/gpio.c \ - $(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 += \ - ARM_ARCH_WAIT_FOR_SECONDARIES=1 - -LINKER_SCRIPT += \ - $(BUILDDIR)/system-onesegment.ld - -include make/module.mk diff --git a/platform/bcm2835/uart.c b/platform/bcm2835/uart.c deleted file mode 100644 index 002c5de9c..000000000 --- a/platform/bcm2835/uart.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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/platform/bcm2837/gpio.c b/platform/bcm2837/gpio.c deleted file mode 100644 index 6bb9019ba..000000000 --- a/platform/bcm2837/gpio.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2016 Adam Barth - * - * 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 - -#define NUM_PINS 54 -#define BITS_PER_REG 32 -#define BITS_PER_PIN 3 -#define PINS_PER_REG (BITS_PER_REG / BITS_PER_PIN) -#define GPIOREG(base, nr) (REG32(base) + (nr / BITS_PER_REG)) - -int gpio_config(unsigned nr, unsigned flags) -{ - unsigned mask = 0x7; - if (nr >= NUM_PINS || flags & ~mask) - return -EINVAL; - unsigned register_number = nr / PINS_PER_REG; - unsigned offset = (nr % PINS_PER_REG) * BITS_PER_PIN; - unsigned shifted_mask = mask << offset; - volatile uint32_t *reg = REG32(GPIO_GPFSEL0) + register_number; - *reg = (*reg & ~shifted_mask) | (flags << offset); - return 0; -} - -void gpio_set(unsigned nr, unsigned on) -{ - unsigned offset = nr % BITS_PER_REG; - *GPIOREG(on ? GPIO_GPSET0 : GPIO_GPCLR0, nr) = 1 << offset; -} - -int gpio_get(unsigned nr) -{ - unsigned offset = nr % BITS_PER_REG; - return (*GPIOREG(GPIO_GPLEV0, nr) & (1 << offset)) >> offset; -} diff --git a/platform/bcm2837/include/platform/bcm2837.h b/platform/bcm2837/include/platform/bcm2837.h deleted file mode 100644 index 7493bee6c..000000000 --- a/platform/bcm2837/include/platform/bcm2837.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 -/* Note: BCM2836/BCM2837 use different peripheral base than BCM2835 */ -#define BCM_PERIPH_BASE_PHYS (0x3f000000U) -#define BCM_PERIPH_SIZE (0x01100000U) -#define BCM_PERIPH_BASE_VIRT (0xffffffffc0000000ULL) - -#define MEMORY_APERTURE_SIZE ( 1024 * 1024 * 1024) - -/* 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 AUX_BASE (BCM_PERIPH_BASE_VIRT + 0x215000) -#define MINIUART_BASE (BCM_PERIPH_BASE_VIRT + 0x215040) -#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 - -/* GPIO */ - -#define GPIO_GPFSEL0 (GPIO_BASE + 0x00) -#define GPIO_GPFSEL1 (GPIO_BASE + 0x04) -#define GPIO_GPFSEL2 (GPIO_BASE + 0x08) -#define GPIO_GPFSEL3 (GPIO_BASE + 0x0C) -#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) -#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) -#define GPIO_GPSET0 (GPIO_BASE + 0x1C) -#define GPIO_GPSET1 (GPIO_BASE + 0x20) -#define GPIO_GPCLR0 (GPIO_BASE + 0x28) -#define GPIO_GPCLR1 (GPIO_BASE + 0x2C) -#define GPIO_GPLEV0 (GPIO_BASE + 0x34) -#define GPIO_GPLEV1 (GPIO_BASE + 0x38) -#define GPIO_GPEDS0 (GPIO_BASE + 0x40) -#define GPIO_GPEDS1 (GPIO_BASE + 0x44) -#define GPIO_GPREN0 (GPIO_BASE + 0x4C) -#define GPIO_GPREN1 (GPIO_BASE + 0x50) -#define GPIO_GPFEN0 (GPIO_BASE + 0x58) -#define GPIO_GPFEN1 (GPIO_BASE + 0x5C) -#define GPIO_GPHEN0 (GPIO_BASE + 0x64) -#define GPIO_GPHEN1 (GPIO_BASE + 0x68) -#define GPIO_GPLEN0 (GPIO_BASE + 0x70) -#define GPIO_GPLEN1 (GPIO_BASE + 0x74) -#define GPIO_GPAREN0 (GPIO_BASE + 0x7C) -#define GPIO_GPAREN1 (GPIO_BASE + 0x80) -#define GPIO_GPAFEN0 (GPIO_BASE + 0x88) -#define GPIO_GPAFEN1 (GPIO_BASE + 0x8C) -#define GPIO_GPPUD (GPIO_BASE + 0x94) -#define GPIO_GPPUDCLK0 (GPIO_BASE + 0x98) -#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9C) diff --git a/platform/bcm2837/include/platform/gic.h b/platform/bcm2837/include/platform/gic.h deleted file mode 100644 index 92cf0ad90..000000000 --- a/platform/bcm2837/include/platform/gic.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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/bcm2837/intc.c b/platform/bcm2837/intc.c deleted file mode 100644 index baed72119..000000000 --- a/platform/bcm2837/intc.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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 - -#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 + 0x50) -#define INTC_LOCAL_MAILBOX_INT_CONTROL1 (ARM_LOCAL_BASE + 0x54) -#define INTC_LOCAL_MAILBOX_INT_CONTROL2 (ARM_LOCAL_BASE + 0x58) -#define INTC_LOCAL_MAILBOX_INT_CONTROL3 (ARM_LOCAL_BASE + 0x5c) - -#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) - -#define INTC_LOCAL_MAILBOX0_SET0 (ARM_LOCAL_BASE + 0x80) -#define INTC_LOCAL_MAILBOX0_SET1 (ARM_LOCAL_BASE + 0x90) -#define INTC_LOCAL_MAILBOX0_SET2 (ARM_LOCAL_BASE + 0xa0) -#define INTC_LOCAL_MAILBOX0_SET3 (ARM_LOCAL_BASE + 0xb0) - -#define INTC_LOCAL_MAILBOX0_CLR0 (ARM_LOCAL_BASE + 0xc0) -#define INTC_LOCAL_MAILBOX0_CLR1 (ARM_LOCAL_BASE + 0xd0) -#define INTC_LOCAL_MAILBOX0_CLR2 (ARM_LOCAL_BASE + 0xe0) -#define INTC_LOCAL_MAILBOX0_CLR3 (ARM_LOCAL_BASE + 0xf0) - -struct int_handler_struct { - int_handler handler; - void *arg; -}; - -static struct int_handler_struct int_handler_table[MAX_INT]; - -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, mask on all cpus - for (uint cpu = 0; cpu < 4; cpu++) { - 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, unmask for all cpus - for (uint cpu = 0; cpu < 4; cpu++) { - 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) -{ - 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].handler = handler; - int_handler_table[vector].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("cpu %u vector %u\n", cpu, vector); - - // dispatch the irq - enum handler_return ret = INT_NO_RESCHEDULE; - -#if WITH_SMP - if (vector == INTERRUPT_ARM_LOCAL_MAILBOX0) { - pend = *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu); - LTRACEF("mailbox0 clr 0x%x\n", pend); - - // ack it - *REG32(INTC_LOCAL_MAILBOX0_CLR0 + 0x10 * cpu) = pend; - - if (pend & (1 << MP_IPI_GENERIC)) { - PANIC_UNIMPLEMENTED; - } - if (pend & (1 << MP_IPI_RESCHEDULE)) { - ret = mp_mbx_reschedule_irq(); - } - } else -#endif // WITH_SMP - if (vector == 0xffffffff) { - ret = INT_NO_RESCHEDULE; - } else if (int_handler_table[vector].handler) { - ret = int_handler_table[vector].handler(int_handler_table[vector].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 bcm2835_send_ipi(uint irq, uint cpu_mask) -{ - LTRACEF("irq %u, cpu_mask 0x%x\n", irq, cpu_mask); - - for (uint i = 0; i < 4; i++) { - if (cpu_mask & (1< -#include -#include -#include -#include -#include -#include -#include -#include - -#define RXBUF_SIZE 16 - -static cbuf_t uart_rx_buf; - -struct bcm283x_mu_regs { - uint32_t io; - uint32_t ier; - uint32_t iir; - uint32_t lcr; - uint32_t mcr; - uint32_t lsr; - uint32_t msr; - uint32_t scratch; - uint32_t cntl; - uint32_t stat; - uint32_t baud; -}; - -struct bcm283x_aux_regs { - uint32_t auxirq; - uint32_t auxenb; -}; - -#define AUX_IRQ_MINIUART (1 << 0) -#define AUX_ENB_MINIUART (1 << 0) - -#define MU_IIR_BYTE_AVAIL (1 << 2) // For reading -#define MU_IIR_CLR_XMIT_FIFO (1 << 2) // For writing. -#define MU_IIR_CLR_RECV_FIFO (1 << 1) - -#define MU_IIR_EN_RX_IRQ (1 << 0) // Enable the recv interrupt. - -#define MU_LSR_TX_EMPTY (1 << 5) - -static enum handler_return aux_irq(void *arg) -{ - volatile struct bcm283x_mu_regs *mu_regs = - (struct bcm283x_mu_regs *)MINIUART_BASE; - volatile struct bcm283x_aux_regs *aux_regs = - (struct bcm283x_aux_regs *)AUX_BASE; - - // Make sure this interrupt is intended for the miniuart. - uint32_t auxirq = readl(&aux_regs->auxirq); - if ((auxirq & AUX_IRQ_MINIUART) == 0) { - return INT_NO_RESCHEDULE; - } - - bool resched = false; - - while (true) { - uint32_t iir = readl(&mu_regs->iir); - if ((iir & MU_IIR_BYTE_AVAIL) == 0) break; - - resched = true; - char ch = readl(&mu_regs->io); - cbuf_write_char(&uart_rx_buf, ch, false); - } - - return resched ? INT_RESCHEDULE : INT_NO_RESCHEDULE; -} - -int uart_putc(int port, char c) -{ - // There's only one UART for now. - // TODO(gkalsi): Unify the two UART code paths using the port. - struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)MINIUART_BASE; - - /* Wait until there is space in the FIFO */ - while (!(readl(®s->lsr) & MU_LSR_TX_EMPTY)) - ; - - /* Send the character */ - writel(c, ®s->io); - - return 1; -} - -void uart_init(void) -{ - volatile struct bcm283x_mu_regs *mu_regs = - (struct bcm283x_mu_regs *)MINIUART_BASE; - volatile struct bcm283x_aux_regs *aux_regs = - (struct bcm283x_aux_regs *)AUX_BASE; - - // Create circular buffer to hold received data. - cbuf_initialize(&uart_rx_buf, RXBUF_SIZE); - - // AUX Interrupt handler handles interrupts for SPI1, SPI2, and miniuart - // Interrupt handler must decode IRQ. - register_int_handler(INTERRUPT_AUX, &aux_irq, NULL); - - // Enable the Interrupt. - unmask_interrupt(INTERRUPT_AUX); - - writel(MU_IIR_CLR_RECV_FIFO | MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); - - // Enable the miniuart peripheral. This also enables Miniuart register - // access. It's likely that the VideoCore chip already enables this - // peripheral for us, but we hit the enable bit just to be sure. - writel(AUX_ENB_MINIUART, &aux_regs->auxenb); - - // Enable the receive interrupt on the UART peripheral. - writel(MU_IIR_EN_RX_IRQ, &mu_regs->ier); -} - -void uart_init_early(void) -{ -} - -int uart_getc(int port, bool wait) -{ - cbuf_t *rxbuf = &uart_rx_buf; - - char c; - if (cbuf_read_char(rxbuf, &c, wait) == 1) - return c; - - return -1; -} - -void uart_flush_tx(int port) -{ - volatile struct bcm283x_mu_regs *mu_regs = - (struct bcm283x_mu_regs *)MINIUART_BASE; - writel(MU_IIR_CLR_XMIT_FIFO, &mu_regs->iir); -} - -void uart_flush_rx(int port) -{ - volatile struct bcm283x_mu_regs *mu_regs = - (struct bcm283x_mu_regs *)MINIUART_BASE; - writel(MU_IIR_CLR_RECV_FIFO, &mu_regs->iir); -} - -void uart_init_port(int port, uint baud) -{ -} - - - diff --git a/platform/bcm2837/platform.c b/platform/bcm2837/platform.c deleted file mode 100644 index 233ed4f5e..000000000 --- a/platform/bcm2837/platform.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 -#include - -extern void intc_init(void); -extern void arm_reset(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 = MEMORY_APERTURE_SIZE, - .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" - }, - - /* 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); - - - /* look for a flattened device tree just before the kernel */ - const void *fdt = (void *)KERNEL_BASE; - int err = fdt_check_header(fdt); - if (err >= 0) { - /* walk the nodes, looking for 'memory' */ - int depth = 0; - int offset = 0; - for (;;) { - offset = fdt_next_node(fdt, offset, &depth); - if (offset < 0) - break; - - /* get the name */ - const char *name = fdt_get_name(fdt, offset, NULL); - if (!name) - continue; - - /* look for the 'memory' property */ - if (strcmp(name, "memory") == 0) { - printf("Found memory in fdt\n"); - int lenp; - const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); - if (prop_ptr && lenp == 0x10) { - /* we're looking at a memory descriptor */ - //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); - uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); - - /* trim size on certain platforms */ -#if ARCH_ARM - if (len > 1024*1024*1024U) { - len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ - printf("trimming memory to 1GB\n"); - } -#endif - - /* set the size in the pmm arena */ - arena.size = len; - } - } - } - } - - /* add the main memory arena */ - pmm_add_arena(&arena); - - /* reserve the first 64k of ram, which should be holding the fdt */ - struct list_node list = LIST_INITIAL_VALUE(list); - pmm_alloc_range(MEMBASE, 0x80000 / PAGE_SIZE, &list); - -#if WITH_SMP - /* start the other cpus */ - uintptr_t sec_entry = (uintptr_t)&arm_reset; - sec_entry -= (KERNEL_BASE - MEMBASE); - for (uint i = 1; i <= 3; i++) { - *REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry; - } -#endif -} - -void platform_init(void) -{ - uart_init(); -} - -#define DEBUG_UART 1 - -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/bcm2837/rules.mk b/platform/bcm2837/rules.mk deleted file mode 100644 index 6aaccaac7..000000000 --- a/platform/bcm2837/rules.mk +++ /dev/null @@ -1,48 +0,0 @@ -LOCAL_DIR := $(GET_LOCAL_DIR) - -MODULE := $(LOCAL_DIR) - -ARCH := arm64 -ARM_CPU := cortex-a53 -WITH_SMP := 1 -#LK_HEAP_IMPLEMENTATION ?= dlmalloc -WITH_CPP_SUPPORT=true - -MODULE_DEPS := \ - dev/timer/arm_generic \ - lib/cbuf \ - app/shell \ - app/tests \ - lib/fdt \ - -#lib/bio \ - lib/cbuf \ - lib/minip \ - dev/interrupt/arm_gic \ - dev/timer/arm_cortex_a9 - -MODULE_SRCS += \ - $(LOCAL_DIR)/gpio.c \ - $(LOCAL_DIR)/intc.c \ - $(LOCAL_DIR)/platform.c \ - $(LOCAL_DIR)/miniuart.c \ - -MEMBASE := 0x00000000 -MEMSIZE ?= 0x40000000 # 256MB -KERNEL_LOAD_OFFSET := 0x00080000 - - - -# put our kernel at 0x80000000 -#KERNEL_BASE = 0xFFFF000000080000 - -GLOBAL_DEFINES += \ - MEMBASE=$(MEMBASE) \ - MEMSIZE=$(MEMSIZE) \ - MMU_WITH_TRAMPOLINE=1 \ - ARM_ARCH_WAIT_FOR_SECONDARIES=1 - -LINKER_SCRIPT += \ - $(BUILDDIR)/system-onesegment.ld - -include make/module.mk diff --git a/platform/bcm2837/uart.c b/platform/bcm2837/uart.c deleted file mode 100644 index 2ae115ea8..000000000 --- a/platform/bcm2837/uart.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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) { - case 0: - return UART0_BASE; - default: - case 1: - return UART1_BASE; - } -} - - - -#define BIT(x) (1 << (x)) - -#define BCM2835_MU_BASE 0x3f215040 -#define BCM2835_MU_BASE2 0xffffffffc0215040ULL - -struct bcm283x_mu_regs { - uint32_t io; - uint32_t iir; - uint32_t ier; - uint32_t lcr; - uint32_t mcr; - uint32_t lsr; - uint32_t msr; - uint32_t scratch; - uint32_t cntl; - uint32_t stat; - uint32_t baud; -}; - -/* This actually means not full, but is named not empty in the docs */ -#define BCM283X_MU_LSR_TX_EMPTY BIT(5) -#define BCM283X_MU_LSR_RX_READY BIT(0) - -#define __arch_getl(a) (*(volatile unsigned int *)(a)) -#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) -#define __arch_get32(a) (*(volatile uint32_t *)(a)) - -#define dmb() __asm__ __volatile__ ("" : : : "memory") -#define __iormb() dmb() -#define __iowmb() dmb() - -#define readl(c) ({ uint32_t __v = __arch_getl(c); __iormb(); __v; }) -#define writel(v,c) ({ uint32_t __v = v; __iowmb(); __arch_putl(__v,c); __v; }) - -static void bcm283x_mu_serial_putc(const char data) -{ - struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)BCM2835_MU_BASE; - - /* Wait until there is space in the FIFO */ - while (!(readl(®s->lsr) & BCM283X_MU_LSR_TX_EMPTY)) - ; - - /* Send the character */ - writel(data, ®s->io); -} - - -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++) { - size_t i =1; - // 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(1), UART_CR) = (1<<8)|(1<<0); // tx_enable, uarten - //} -} - -int uart_putc(int port, char c) -{ - - struct bcm283x_mu_regs *regs = (struct bcm283x_mu_regs *)BCM2835_MU_BASE2; - - /* Wait until there is space in the FIFO */ - while (!(readl(®s->lsr) & BCM283X_MU_LSR_TX_EMPTY)) - ; - - /* Send the character */ - writel(c, ®s->io); - - 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) -{ -} - - - From c5b427333aec4118f30756d332b55ff607c77bd1 Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Tue, 23 Aug 2016 12:56:40 -0700 Subject: [PATCH 07/12] [bcm28xx][arm64][ipi] Fix IPI on non-GIC based BCM28xx --- arch/arm/arm/mp.c | 4 ++-- arch/arm64/mp.c | 13 +++++++++++-- platform/bcm28xx/intc.c | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/arch/arm/arm/mp.c b/arch/arm/arm/mp.c index 71da3fd7d..9320324ed 100644 --- a/arch/arm/arm/mp.c +++ b/arch/arm/arm/mp.c @@ -32,7 +32,7 @@ #include #elif PLATFORM_BCM28XX /* bcm28xx has a weird custom interrupt controller for MP */ -extern void bcm2835_send_ipi(uint irq, uint cpu_mask); +extern void bcm28xx_send_ipi(uint irq, uint cpu_mask); #else #error need other implementation of interrupt controller that can ipi #endif @@ -62,7 +62,7 @@ status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) /* filter out targets outside of the range of cpus we care about */ target &= ((1UL << SMP_MAX_CPUS) - 1); if (target != 0) { - bcm2835_send_ipi(ipi, target); + bcm28xx_send_ipi(ipi, target); } #endif diff --git a/arch/arm64/mp.c b/arch/arm64/mp.c index 5a813c516..8a8e6b168 100644 --- a/arch/arm64/mp.c +++ b/arch/arm64/mp.c @@ -30,8 +30,11 @@ #if WITH_DEV_INTERRUPT_ARM_GIC #include -//#else -//#error need other implementation of interrupt controller that can ipi +#elif PLATFORM_BCM28XX +/* bcm28xx has a weird custom interrupt controller for MP */ +extern void bcm28xx_send_ipi(uint irq, uint cpu_mask); +#else +#error need other implementation of interrupt controller that can ipi #endif #define LOCAL_TRACE 0 @@ -51,6 +54,12 @@ status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) LTRACEF("target 0x%x, gic_ipi %u\n", target, gic_ipi_num); arm_gic_sgi(gic_ipi_num, ARM_GIC_SGI_FLAG_NS, target); } +#elif PLATFORM_BCM2835 + /* filter out targets outside of the range of cpus we care about */ + target &= ((1UL << SMP_MAX_CPUS) - 1); + if (target != 0) { + bcm28xx_send_ipi(ipi, target); + } #endif return NO_ERROR; diff --git a/platform/bcm28xx/intc.c b/platform/bcm28xx/intc.c index 5e78d42c2..1509d1fa5 100644 --- a/platform/bcm28xx/intc.c +++ b/platform/bcm28xx/intc.c @@ -265,7 +265,7 @@ enum handler_return platform_fiq(struct arm_iframe *frame) PANIC_UNIMPLEMENTED; } -void bcm2835_send_ipi(uint irq, uint cpu_mask) +void bcm28xx_send_ipi(uint irq, uint cpu_mask) { LTRACEF("irq %u, cpu_mask 0x%x\n", irq, cpu_mask); From b6018454c0ac7f52886ac55442b2b797dda5d8a1 Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Tue, 23 Aug 2016 15:09:07 -0700 Subject: [PATCH 08/12] [bcm28xx] Fix arm/arm64 exception iframe warning --- platform/bcm28xx/intc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/bcm28xx/intc.c b/platform/bcm28xx/intc.c index 1509d1fa5..c1273ceb9 100644 --- a/platform/bcm28xx/intc.c +++ b/platform/bcm28xx/intc.c @@ -32,8 +32,10 @@ #if defined (BCM2836) #include +typedef struct arm_iframe arm_platform_iframe_t; #elif defined (BCM2837) #include +typedef struct arm64_iframe_long arm_platform_iframe_t; #else #error Unknown BCM28XX Variant #endif @@ -175,7 +177,7 @@ void register_int_handler(unsigned int vector, int_handler handler, void *arg) spin_unlock_irqrestore(&lock, state); } -enum handler_return platform_irq(struct arm_iframe *frame) +enum handler_return platform_irq(arm_platform_iframe_t *frame) { uint vector; uint cpu = arch_curr_cpu_num(); @@ -260,7 +262,7 @@ enum handler_return platform_irq(struct arm_iframe *frame) return ret; } -enum handler_return platform_fiq(struct arm_iframe *frame) +enum handler_return platform_fiq(arm_platform_iframe_t *frame) { PANIC_UNIMPLEMENTED; } From c6e2c28c86c60d063b8962c61625c72bce5ff31d Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Tue, 23 Aug 2016 15:15:43 -0700 Subject: [PATCH 09/12] [bcm28xx][arm64] Fix some type warnings. --- arch/arm64/mmu.c | 2 +- platform/bcm28xx/platform.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mmu.c b/arch/arm64/mmu.c index fcdd9d0c9..547db8d3c 100644 --- a/arch/arm64/mmu.c +++ b/arch/arm64/mmu.c @@ -650,7 +650,7 @@ void arch_mmu_context_switch(arch_aspace_t *aspace) if (TRACE_CONTEXT_SWITCH) TRACEF("ttbr 0x%llx, tcr 0x%llx\n", ttbr, tcr); - ARM64_TLBI(aside1, MMU_ARM64_USER_ASID << 48); + ARM64_TLBI(aside1, (uint64_t)MMU_ARM64_USER_ASID << 48); } else { tcr = MMU_TCR_FLAGS_KERNEL; diff --git a/platform/bcm28xx/platform.c b/platform/bcm28xx/platform.c index 486249107..1f5ab52c9 100644 --- a/platform/bcm28xx/platform.c +++ b/platform/bcm28xx/platform.c @@ -190,7 +190,7 @@ void platform_early_init(void) #if WITH_SMP #if BCM2837 - uintptr_t sec_entry = &arm_reset - KERNEL_ASPACE_BASE; + uintptr_t sec_entry = (uintptr_t)(&arm_reset - KERNEL_ASPACE_BASE); unsigned long long *spin_table = (void *)(KERNEL_ASPACE_BASE + 0xd8); for (uint i = 1; i <= 3; i++) { From 5c6554165e29b68ff079e3949f4d721792cae74e Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Tue, 23 Aug 2016 15:58:32 -0700 Subject: [PATCH 10/12] [squash] Fix typo in IPI code --- arch/arm/arm/mp.c | 2 +- arch/arm64/mp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/arm/mp.c b/arch/arm/arm/mp.c index 9320324ed..27647b220 100644 --- a/arch/arm/arm/mp.c +++ b/arch/arm/arm/mp.c @@ -58,7 +58,7 @@ status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) #endif arm_gic_sgi(gic_ipi_num, flags, target); } -#elif PLATFORM_BCM2835 +#elif PLATFORM_BCM28XX /* filter out targets outside of the range of cpus we care about */ target &= ((1UL << SMP_MAX_CPUS) - 1); if (target != 0) { diff --git a/arch/arm64/mp.c b/arch/arm64/mp.c index 8a8e6b168..e3584c855 100644 --- a/arch/arm64/mp.c +++ b/arch/arm64/mp.c @@ -54,7 +54,7 @@ status_t arch_mp_send_ipi(mp_cpu_mask_t target, mp_ipi_t ipi) LTRACEF("target 0x%x, gic_ipi %u\n", target, gic_ipi_num); arm_gic_sgi(gic_ipi_num, ARM_GIC_SGI_FLAG_NS, target); } -#elif PLATFORM_BCM2835 +#elif PLATFORM_BCM28XX /* filter out targets outside of the range of cpus we care about */ target &= ((1UL << SMP_MAX_CPUS) - 1); if (target != 0) { From 2072cfe8f1fb1cd33a32162dc995d79e8841fc53 Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Thu, 25 Aug 2016 15:50:52 -0700 Subject: [PATCH 11/12] [arm64] Backport changes from magenta --- arch/arm64/start.S | 43 +++++++++++++++++++++++++-------- arch/arm64/system-onesegment.ld | 13 +++++++--- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/arch/arm64/start.S b/arch/arm64/start.S index 2faf63079..5e8d89472 100644 --- a/arch/arm64/start.S +++ b/arch/arm64/start.S @@ -32,11 +32,9 @@ attr .req x27 FUNCTION(_start) .globl arm_reset arm_reset: - -#if WITH_KERNEL_VM - bl arm64_elX_to_el1 +#if WITH_KERNEL_VM /* enable caches so atomics and spinlocks work */ mrs tmp, sctlr_el1 orr tmp, tmp, #(1<<12) /* Enable icache */ @@ -75,6 +73,7 @@ arm_reset: add mmu_initial_mapping, mmu_initial_mapping, #:lo12:mmu_initial_mappings .Linitial_mapping_loop: +/* Read entry of mmu_initial_mappings (likely defined in platform.c) */ ldp paddr, vaddr, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_PHYS_OFFSET] ldp size, tmp, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET] @@ -85,7 +84,7 @@ arm_reset: str size, [mmu_initial_mapping, #__MMU_INITIAL_MAPPING_SIZE_OFFSET] .Lnot_dynamic: - /* if size == 0, end of list */ + /* if size == 0, end of list, done with initial mapping */ cbz size, .Linitial_mapping_done mov mapping_size, size @@ -93,16 +92,34 @@ arm_reset: tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_UNCACHED, .Lnot_uncached ldr attr, =MMU_INITIAL_MAP_STRONGLY_ORDERED b .Lmem_type_done + .Lnot_uncached: + /* is this memory mapped to device/peripherals? */ tbzmask tmp, MMU_INITIAL_MAPPING_FLAG_DEVICE, .Lnot_device ldr attr, =MMU_INITIAL_MAP_DEVICE b .Lmem_type_done .Lnot_device: +/* Determine the segment in which the memory resides and set appropriate + * attributes. In order to handle offset kernels, the following rules are + * implemented below: + * KERNEL_BASE to __code_start -read/write (see note below) + * __code_start to __rodata_start (.text) -read only + * __rodata_start to __data_start (.rodata) -read only, execute never + * __data_start to ..... (.data) -read/write + * + * The space below __code_start is presently left as read/write (same as .data) + * mainly as a workaround for the raspberry pi boot process. Boot vectors for + * secondary CPUs are in this area and need to be updated by cpu0 once the system + * is ready to boot the secondary processors. + * TODO: handle this via mmu_initial_mapping entries, which may need to be + * extended with additional flag types + */ .Lmapping_size_loop: ldr attr, =MMU_PTE_KERNEL_DATA_FLAGS - ldr tmp, =arm_reset + ldr tmp, =__code_start subs size, tmp, vaddr + /* If page is below the entry point (_start) mark as kernel data */ b.hi .Lmem_type_done ldr attr, =MMU_PTE_KERNEL_RO_FLAGS @@ -145,6 +162,10 @@ arm_reset: lsr index, vaddr, index_shift + +/* determine the type of page table entry to use given alignment and size + * of the chunk of memory we are mapping + */ .Lmap_range_one_table_loop: /* Check if current level allow block descriptors */ cmp index_shift, #MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT @@ -245,12 +266,14 @@ arm_reset: str tmp2, [page_table0, tmp, lsl #3] /* tt_trampoline[paddr index] = pt entry */ #if WITH_SMP - adr tmp, page_tables_not_ready + adrp tmp, page_tables_not_ready + add tmp, tmp, #:lo12:page_tables_not_ready str wzr, [tmp] b .Lpage_tables_ready .Lmmu_enable_secondary: - adr tmp, page_tables_not_ready + adrp tmp, page_tables_not_ready + add tmp, tmp, #:lo12:page_tables_not_ready .Lpage_tables_not_ready: ldr wtmp2, [tmp] cbnz wtmp2, .Lpage_tables_not_ready @@ -318,9 +341,9 @@ arm_reset: /* clear bss */ .L__do_bss: - /* clear out the bss */ - /* NOTE: relies on __bss_start and __bss_end being 8 byte aligned */ - ldr tmp, =__bss_start + /* clear out the bss excluding the stack and kernel translation table */ + /* NOTE: relies on __post_prebss_bss_start and __bss_end being 8 byte aligned */ + ldr tmp, =__post_prebss_bss_start ldr tmp2, =__bss_end sub tmp2, tmp2, tmp cbz tmp2, .L__bss_loop_done diff --git a/arch/arm64/system-onesegment.ld b/arch/arm64/system-onesegment.ld index 9cdaa8551..b750b10a7 100644 --- a/arch/arm64/system-onesegment.ld +++ b/arch/arm64/system-onesegment.ld @@ -9,6 +9,7 @@ SECTIONS /* text/read-only data */ /* set the load address to physical MEMBASE */ .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) { + __code_start = .; KEEP(*(.text.boot)) KEEP(*(.text.boot.vectab)) *(.text* .sram.text.glue_7* .gnu.linkonce.t.*) @@ -46,6 +47,10 @@ SECTIONS .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } __exidx_end = .; + .dummy_post_text : { + __code_end = .; + } + .rodata : ALIGN(4096) { __rodata_start = .; __fault_handler_table_start = .; @@ -94,10 +99,11 @@ SECTIONS } /* unintialized data (in same segment as writable data) */ - .bss : ALIGN(8) { + .bss : ALIGN(4096) { + __bss_start = .; KEEP(*(.bss.prebss.*)) . = ALIGN(8); - __bss_start = .; + __post_prebss_bss_start = .; *(.bss .bss.*) *(.gnu.linkonce.b.*) *(COMMON) @@ -105,7 +111,8 @@ SECTIONS __bss_end = .; } - . = ALIGN(8); + /* Align the end to ensure anything after the kernel ends up on its own pages */ + . = ALIGN(4096); _end = .; . = %KERNEL_BASE% + %MEMSIZE%; From 173046ecca6e8e23d2a650c697e216a4a93d9c5d Mon Sep 17 00:00:00 2001 From: Gurjant Kalsi Date: Thu, 25 Aug 2016 15:51:34 -0700 Subject: [PATCH 12/12] [squash] Use x4 as early scratch register in case args are passed in x0-x3 (changes as per code review). --- arch/arm64/asm.S | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm64/asm.S b/arch/arm64/asm.S index e373d34a0..bcd808b28 100644 --- a/arch/arm64/asm.S +++ b/arch/arm64/asm.S @@ -84,36 +84,36 @@ FUNCTION(arm64_el3_to_el1) eret FUNCTION(arm64_elX_to_el1) - mrs x0, CurrentEL + mrs x4, CurrentEL - cmp x0, #(0b01 << 2) + cmp x4, #(0b01 << 2) bne .notEL1 /* Already in EL1 */ ret .notEL1: - cmp x0, #(0b10 << 2) + cmp x4, #(0b10 << 2) beq .inEL2 /* set EL2 to 64bit */ - mrs x0, scr_el3 - orr x0, x0, #(1<<10) - msr scr_el3, x0 + mrs x4, scr_el3 + orr x4, x4, #(1<<10) + msr scr_el3, x4 - adr x0, .Ltarget - msr elr_el3, x0 + adr x4, .Ltarget + msr elr_el3, x4 - mov x0, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ - msr spsr_el3, x0 + mov x4, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ + msr spsr_el3, x4 b .confEL1 .inEL2: - adr x0, .Ltarget - msr elr_el2, x0 - mov x0, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ - msr spsr_el2, x0 + adr x4, .Ltarget + msr elr_el2, x4 + mov x4, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ + msr spsr_el2, x4