aboutsummaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorGurjant Kalsi <me@gurjantkalsi.com>2016-07-13 17:31:53 -0700
committerGurjant Kalsi <me@gurjantkalsi.com>2016-08-23 12:28:28 -0700
commit100133dc38720e8ca00e9012f32c5d9ee2a00d1b (patch)
treebb1192a046fd5674b92ab22581d56743f9451ad4 /platform
parentedb702078104e8a1245a1b8a0120568a999f4762 (diff)
downloadcommon-100133dc38720e8ca00e9012f32c5d9ee2a00d1b.tar.gz
[BCM28xx] Roll BCM2836 and BCM2837 into a single platform. Have both RPi2 and RPi3 use the new BCM28XX platform.
Diffstat (limited to 'platform')
-rw-r--r--platform/bcm28xx/gpio.c57
-rw-r--r--platform/bcm28xx/include/platform/bcm28xx.h210
-rw-r--r--platform/bcm28xx/intc.c294
-rw-r--r--platform/bcm28xx/miniuart.c176
-rw-r--r--platform/bcm28xx/platform.c217
-rw-r--r--platform/bcm28xx/rules.mk71
-rw-r--r--platform/bcm28xx/uart.c159
7 files changed, 1184 insertions, 0 deletions
diff --git a/platform/bcm28xx/gpio.c b/platform/bcm28xx/gpio.c
new file mode 100644
index 00000000..49c31df9
--- /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 <dev/gpio.h>
+#include <errno.h>
+#include <platform/bcm28xx.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/bcm28xx/include/platform/bcm28xx.h b/platform/bcm28xx/include/platform/bcm28xx.h
new file mode 100644
index 00000000..058a02d6
--- /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 00000000..5e78d42c
--- /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 <trace.h>
+#include <assert.h>
+#include <err.h>
+#include <bits.h>
+#include <kernel/spinlock.h>
+#include <kernel/thread.h>
+#include <kernel/mp.h>
+#include <platform/interrupts.h>
+#include <platform/bcm28xx.h>
+
+#if defined (BCM2836)
+#include <arch/arm.h>
+#elif defined (BCM2837)
+#include <arch/arm64.h>
+#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<<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/bcm28xx/miniuart.c b/platform/bcm28xx/miniuart.c
new file mode 100644
index 00000000..b8f229be
--- /dev/null
+++ b/platform/bcm28xx/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 <assert.h>
+#include <kernel/thread.h>
+#include <lib/cbuf.h>
+#include <platform/bcm28xx.h>
+#include <platform/debug.h>
+#include <platform/interrupts.h>
+#include <reg.h>
+#include <stdio.h>
+#include <trace.h>
+
+#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(&regs->lsr) & MU_LSR_TX_EMPTY))
+ ;
+
+ /* Send the character */
+ writel(c, &regs->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 00000000..1b63500c
--- /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 <reg.h>
+#include <err.h>
+#include <debug.h>
+#include <trace.h>
+
+#include <dev/uart.h>
+#include <arch.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/bcm28xx.h>
+
+#if BCM2836
+#include <arch/arm.h>
+#include <arch/arm/mmu.h>
+
+/* 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 <libfdt.h>
+#include <arch/arm64.h>
+#include <arch/arm64/mmu.h>
+
+/* 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 00000000..07361f67
--- /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 00000000..7ef0effb
--- /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 <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/bcm28xx.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) {
+ 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)
+{
+}
+
+