2 Copyright © 2015, The AROS Development Team. All rights reserved.
6 #include <aros/kernel.h>
7 #include <aros/symbolsets.h>
9 #include "kernel_base.h"
11 #include <proto/kernel.h>
12 #include <proto/exec.h>
15 #include <hardware/intbits.h>
19 #include "kernel_intern.h"
20 #include "kernel_debug.h"
21 #include "kernel_cpu.h"
22 #include "kernel_interrupts.h"
23 #include "kernel_intr.h"
24 #include "kernel_fb.h"
26 #include "exec_platform.h"
28 #define ARM_PERIIOBASE __arm_arosintern.ARMI_PeripheralBase
29 #include <hardware/bcm2708.h>
30 #include <hardware/bcm2708_boot.h>
31 #include <hardware/pl011uart.h>
33 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
35 #define IRQ_BANK1 0x00000100
36 #define IRQ_BANK2 0x00000200
42 extern void mpcore_trampoline();
43 extern uint32_t mpcore_end
;
44 extern uint32_t mpcore_pde
;
46 extern void cpu_Register(void);
47 extern void arm_flush_cache(uint32_t addr
, uint32_t length
);
49 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
51 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
52 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
54 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
56 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
58 void *trampoline_src
= mpcore_trampoline
;
59 void *trampoline_dst
= (void *)BOOTMEMADDR(bm_mctrampoline
);
60 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
61 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
67 bug("[KRN:BCM2708] Initialising Multicore System\n");
68 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
70 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
72 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
74 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
75 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
76 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
78 for (core
= 1; core
< 4; core
++)
80 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
81 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
83 __tls
= AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
84 __tls
->SysBase
= _sysBase
;
85 __tls
->KernelBase
= _kernelBase
;
86 __tls
->ThisTask
= NULL
;
87 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
88 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = __tls
;
90 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
91 D(bug("[KRN:BCM2708] %s: core #%d stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, core
, core_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2]));
92 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__
, core
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
94 arm_flush_cache((uint32_t)trampoline_dst
, 512);
95 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * core
))) = (uint32_t)trampoline_dst
;
97 if (__arm_arosintern
.ARMI_Delay
)
98 __arm_arosintern
.ARMI_Delay(10000000);
103 static void bcm2708_init_core(APTR _kernelBase
, APTR _sysBase
)
105 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
106 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
109 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
111 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
113 // enable FIQ mailbox interupt
114 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * (tmp
& 0x3)))) = (1 << 3);
117 static unsigned int bcm2807_get_time(void)
119 return *((volatile unsigned int *)(SYSTIMER_CLO
));
122 static void bcm2807_irq_init(void)
125 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
127 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
128 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
129 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
131 // aknowledge pending IRQ's
132 *(volatile unsigned int *)ARMIRQ_PEND
= *(volatile unsigned int *)ARMIRQ_PEND
;
133 *(volatile unsigned int *)GPUIRQ_PEND0
= *(volatile unsigned int *)GPUIRQ_PEND0
;
134 *(volatile unsigned int *)GPUIRQ_PEND1
= *(volatile unsigned int *)GPUIRQ_PEND1
;
137 static void bcm2807_irq_enable(int irq
)
139 int bank
= IRQ_BANK(irq
);
142 reg
= (unsigned int)IRQBANK_POINTER(bank
);
144 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
146 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
148 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
151 static void bcm2807_irq_disable(int irq
)
153 int bank
= IRQ_BANK(irq
);
156 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
158 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
160 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
162 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
165 static void bcm2807_irq_process()
167 unsigned int pendingarm
, pending0
, pending1
, irq
;
171 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
172 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
173 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
175 if (!(pendingarm
|| pending0
|| pending1
))
178 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm
));
179 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0
));
180 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1
));
182 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
184 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
186 if (pendingarm
& (1 << (irq
- (2 << 5))))
188 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
189 krnRunIRQHandlers(KernelBase
, irq
);
196 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
198 if (pending0
& (1 << (irq
- (0 << 5))))
200 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
201 krnRunIRQHandlers(KernelBase
, irq
);
208 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
210 if (pending1
& (1 << (irq
- (1 << 5))))
212 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
213 krnRunIRQHandlers(KernelBase
, irq
);
220 static void bcm2807_fiq_process()
224 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
226 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
230 static void bcm2708_toggle_led(int LED
, int state
)
232 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
235 APTR gpiofunc
= GPCLR1
;
237 if (LED
== ARM_LED_ACTIVITY
)
240 if (state
== ARM_LED_ON
)
243 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
247 // RasPi 1 only allows us to toggle the activity LED
249 *(volatile unsigned int *)GPCLR0
= (1 << 16);
251 *(volatile unsigned int *)GPSET0
= (1 << 16);
255 /* Use system timer 3 for our scheduling heartbeat */
256 #define VBLANK_TIMER 3
257 #define VBLANK_INTERVAL (1000000 / 50)
259 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
263 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
265 /* Aknowledge our timer interrupt */
266 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
268 /* Signal the Exec VBlankServer */
269 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
270 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
273 /* Refresh our timer interrupt */
274 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
275 stc
+= VBLANK_INTERVAL
;
276 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
278 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
281 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
283 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
284 struct IntrNode
*GPUTimerHandle
;
287 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
289 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
291 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
292 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
294 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
295 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
296 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
297 GPUTimerHandle
->in_type
= it_interrupt
;
298 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
300 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
302 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
304 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
305 stc
+= VBLANK_INTERVAL
;
306 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
307 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
309 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
312 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
314 return GPUTimerHandle
;
317 static inline void bcm2708_ser_waitout()
321 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
325 static void bcm2708_ser_putc(uint8_t chr
)
327 bcm2708_ser_waitout();
331 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
332 bcm2708_ser_waitout();
334 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
337 static int bcm2708_ser_getc(void)
339 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
340 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
345 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
347 void *bootPutC
= NULL
;
349 while(msg
->ti_Tag
!= TAG_DONE
)
354 bootPutC
= (void *)msg
->ti_Data
;
360 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
363 if (krnARMImpl
->ARMI_Family
== 7)
365 /* bcm2836 uses armv7 */
366 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
367 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_core
;
368 krnARMImpl
->ARMI_FIQProcess
= &bcm2807_fiq_process
;
371 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
373 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
374 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
375 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
377 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
378 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
379 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
380 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
382 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
383 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
384 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
385 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
387 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
392 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);