diff options
author | Eric Holland <hollande@google.com> | 2016-06-28 17:06:07 -0700 |
---|---|---|
committer | Gurjant Kalsi <me@gurjantkalsi.com> | 2016-08-23 12:28:13 -0700 |
commit | 1164bc17bc7c7c21714cf8bb3c320357c3a69b55 (patch) | |
tree | 7c2dd2e7b0b744014aefbf6cfc0f8c15b522d214 /platform | |
parent | d90cb4e7c6340539838f06307e0680470e6eb8a8 (diff) | |
download | common-1164bc17bc7c7c21714cf8bb3c320357c3a69b55.tar.gz |
[rpi3]64bit platform support
Diffstat (limited to 'platform')
-rw-r--r-- | platform/bcm2837/gpio.c | 57 | ||||
-rw-r--r-- | platform/bcm2837/include/platform/bcm2837.h | 203 | ||||
-rw-r--r-- | platform/bcm2837/include/platform/gic.h | 31 | ||||
-rw-r--r-- | platform/bcm2837/intc.c | 286 | ||||
-rw-r--r-- | platform/bcm2837/platform.c | 169 | ||||
-rw-r--r-- | platform/bcm2837/rules.mk | 48 | ||||
-rw-r--r-- | platform/bcm2837/uart.c | 217 |
7 files changed, 1011 insertions, 0 deletions
diff --git a/platform/bcm2837/gpio.c b/platform/bcm2837/gpio.c new file mode 100644 index 00000000..6bb9019b --- /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 <dev/gpio.h> +#include <errno.h> +#include <platform/bcm2837.h> +#include <reg.h> + +#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 00000000..bff557d8 --- /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 00000000..92cf0ad9 --- /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 <platform/bcm2837.h> + +#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 00000000..baed7211 --- /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 <trace.h> +#include <assert.h> +#include <err.h> +#include <bits.h> +#include <arch/arm64.h> +#include <kernel/spinlock.h> +#include <kernel/thread.h> +#include <kernel/mp.h> +#include <platform/interrupts.h> +#include <platform/bcm2837.h> + +#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<<i)) { + LTRACEF("sending to cpu %u\n", i); + *REG32(INTC_LOCAL_MAILBOX0_SET0 + 0x10 * i) = (1 << irq); + } + } +} + +void intc_init(void) +{ + // mask everything + *REG32(INTC_DISABLE1) = 0xffffffff; + *REG32(INTC_DISABLE2) = 0xffffffff; + *REG32(INTC_DISABLE3) = 0xffffffff; + +#if WITH_SMP + // unable mailbox irqs on all cores + for (uint i = 0; i < 4; i++) { + *REG32(INTC_LOCAL_MAILBOX_INT_CONTROL0 + 0x4 * i) = 0x1; + } +#endif +} + diff --git a/platform/bcm2837/platform.c b/platform/bcm2837/platform.c new file mode 100644 index 00000000..233ed4f5 --- /dev/null +++ b/platform/bcm2837/platform.c @@ -0,0 +1,169 @@ +/* + * 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 <reg.h> +#include <err.h> +#include <debug.h> +#include <trace.h> +#include <libfdt.h> + +#include <dev/uart.h> +#include <arch.h> +#include <arch/arm64.h> +#include <arch/arm64/mmu.h> +#include <lk/init.h> +#include <kernel/vm.h> +#include <kernel/spinlock.h> +#include <dev/timer/arm_generic.h> +#include <platform.h> +#include <platform/interrupts.h> +#include <platform/bcm2837.h> + +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 00000000..c01b3e70 --- /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 00000000..2ae115ea --- /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 <reg.h> +#include <stdio.h> +#include <trace.h> +#include <lib/cbuf.h> +#include <kernel/thread.h> +#include <platform/interrupts.h> +#include <platform/debug.h> +#include <platform/bcm2837.h> + +/* 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) +{ +} + + + |