Compare commits
6 Commits
wip/irqopt
...
wip/rpi3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f803955e33 | ||
|
|
62b5860502 | ||
|
|
5e10f58e8b | ||
|
|
804258ec63 | ||
|
|
ced5502d58 | ||
|
|
dc6e6247d2 |
@@ -30,8 +30,8 @@
|
||||
|
||||
#if WITH_DEV_INTERRUPT_ARM_GIC
|
||||
#include <dev/interrupt/arm_gic.h>
|
||||
#elif PLATFORM_BCM2835
|
||||
/* bcm2835 has a weird custom interrupt controller for MP */
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
|
||||
#if WITH_DEV_INTERRUPT_ARM_GIC
|
||||
#include <dev/interrupt/arm_gic.h>
|
||||
#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
|
||||
|
||||
@@ -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 */
|
||||
@@ -94,6 +100,11 @@ FUNCTION(_start)
|
||||
.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
|
||||
|
||||
57
platform/bcm2837/gpio.c
Normal file
57
platform/bcm2837/gpio.c
Normal file
@@ -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;
|
||||
}
|
||||
204
platform/bcm2837/include/platform/bcm2837.h
Normal file
204
platform/bcm2837/include/platform/bcm2837.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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)
|
||||
31
platform/bcm2837/include/platform/gic.h
Normal file
31
platform/bcm2837/include/platform/gic.h
Normal file
@@ -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)
|
||||
|
||||
|
||||
286
platform/bcm2837/intc.c
Normal file
286
platform/bcm2837/intc.c
Normal file
@@ -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
|
||||
}
|
||||
|
||||
176
platform/bcm2837/miniuart.c
Normal file
176
platform/bcm2837/miniuart.c
Normal file
@@ -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/bcm2837.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(®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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
169
platform/bcm2837/platform.c
Normal file
169
platform/bcm2837/platform.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
48
platform/bcm2837/rules.mk
Normal file
48
platform/bcm2837/rules.mk
Normal file
@@ -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)/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
|
||||
217
platform/bcm2837/uart.c
Normal file
217
platform/bcm2837/uart.c
Normal file
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
57
platform/bcm28xx/gpio.c
Normal file
57
platform/bcm28xx/gpio.c
Normal file
@@ -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;
|
||||
}
|
||||
210
platform/bcm28xx/include/platform/bcm28xx.h
Normal file
210
platform/bcm28xx/include/platform/bcm28xx.h
Normal file
@@ -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)
|
||||
294
platform/bcm28xx/intc.c
Normal file
294
platform/bcm28xx/intc.c
Normal file
@@ -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
|
||||
}
|
||||
|
||||
176
platform/bcm28xx/miniuart.c
Normal file
176
platform/bcm28xx/miniuart.c
Normal file
@@ -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(®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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
233
platform/bcm28xx/platform.c
Normal file
233
platform/bcm28xx/platform.c
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
#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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif BCM2836
|
||||
arm_generic_timer_init(INTERRUPT_ARM_LOCAL_CNTPNSIRQ, 1000000);
|
||||
#else
|
||||
#error Unknown BCM28XX Variant
|
||||
#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
|
||||
#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);
|
||||
for (uint i = 1; i <= 3; i++) {
|
||||
*REG32(ARM_LOCAL_BASE + 0x8c + 0x10 * i) = sec_entry;
|
||||
}
|
||||
#endif
|
||||
#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;
|
||||
}
|
||||
|
||||
71
platform/bcm28xx/rules.mk
Normal file
71
platform/bcm28xx/rules.mk
Normal file
@@ -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
|
||||
159
platform/bcm28xx/uart.c
Normal file
159
platform/bcm28xx/uart.c
Normal file
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
11
project/rpi3-test.mk
Normal file
11
project/rpi3-test.mk
Normal file
@@ -0,0 +1,11 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
TARGET := rpi3
|
||||
|
||||
MODULES += \
|
||||
app/shell \
|
||||
app/stringtests \
|
||||
app/tests \
|
||||
lib/cksum \
|
||||
lib/debugcommands \
|
||||
|
||||
@@ -3,7 +3,7 @@ LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR)/include
|
||||
|
||||
PLATFORM := bcm2835
|
||||
PLATFORM := bcm28xx
|
||||
|
||||
#include make/module.mk
|
||||
|
||||
|
||||
9
target/rpi3/rules.mk
Normal file
9
target/rpi3/rules.mk
Normal file
@@ -0,0 +1,9 @@
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR)/include
|
||||
|
||||
PLATFORM := bcm28xx
|
||||
|
||||
#include make/module.mk
|
||||
|
||||
Reference in New Issue
Block a user