2 Copyright © 2015, The AROS Development Team. All rights reserved.
6 #include <aros/types/spinlock_s.h>
7 #include <aros/kernel.h>
8 #include <aros/symbolsets.h>
10 #include "kernel_base.h"
12 #include <proto/kernel.h>
13 #include <proto/exec.h>
16 #include <hardware/intbits.h>
20 #include "kernel_intern.h"
21 #include "kernel_debug.h"
22 #include "kernel_cpu.h"
23 #include "kernel_interrupts.h"
24 #include "kernel_intr.h"
25 #include "kernel_fb.h"
27 #include "exec_platform.h"
29 #define ARM_PERIIOBASE __arm_arosintern.ARMI_PeripheralBase
30 #include <hardware/bcm2708.h>
31 #include <hardware/bcm2708_boot.h>
32 #include <hardware/pl011uart.h>
34 #define IRQBANK_POINTER(bank) ((bank == 0) ? GPUIRQ_ENBL0 : (bank == 1) ? GPUIRQ_ENBL1 : ARMIRQ_ENBL)
36 #define IRQ_BANK1 0x00000100
37 #define IRQ_BANK2 0x00000200
44 extern void mpcore_trampoline();
45 extern uint32_t mpcore_end
;
46 extern uint32_t mpcore_pde
;
47 extern spinlock_t startup_lock
;
49 extern void cpu_Register(void);
50 extern void arm_flush_cache(uint32_t, uint32_t);
51 #if defined(__AROSEXEC_SMP__)
52 extern void handle_ipi(uint32_t, uint32_t);
55 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
57 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
58 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
60 KrnSpinInit(&startup_lock
);
62 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
64 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
66 void *trampoline_src
= mpcore_trampoline
;
67 void *trampoline_dst
= (void *)BOOTMEMADDR(bm_mctrampoline
);
68 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
69 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
72 uint32_t *core_fiq_stack
;
76 bug("[KRN:BCM2708] Initialising Multicore System\n");
77 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
79 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
81 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
83 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
84 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
85 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
87 for (core
= 1; core
< 4; core
++)
89 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
90 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
92 core_fiq_stack
= (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
93 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4] = (uint32_t)&core_fiq_stack
[1024-sizeof(IPTR
)];
95 __tls
= AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
96 __tls
->SysBase
= _sysBase
;
97 __tls
->KernelBase
= _kernelBase
;
98 __tls
->ThisTask
= NULL
;
99 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
100 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = __tls
;
102 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
103 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]));
104 D(bug("[KRN:BCM2708] %s: core #%d fiq stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, core
, core_fiq_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4]));
105 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__
, core
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
107 arm_flush_cache((uint32_t)trampoline_dst
, 512);
109 /* Lock the startup spinlock */
110 KrnSpinLock(&startup_lock
, SPINLOCK_MODE_WRITE
);
112 /* Wake up the core */
113 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * core
))) = (uint32_t)trampoline_dst
;
116 * Try to obtain spinlock again.
117 * This should put this core to sleep since the locked was already obtained. Once the core startup
118 * is ready, it will call KrnSpinUnLock too
120 KrnSpinLock(&startup_lock
, SPINLOCK_MODE_WRITE
);
121 KrnSpinUnLock(&startup_lock
);
126 static void bcm2708_init_core(APTR _kernelBase
, APTR _sysBase
)
128 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
129 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
132 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
134 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
136 /* Clear all pending FIQ sources on mailboxes */
137 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
138 *((uint32_t *)(BCM2836_MAILBOX1_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
139 *((uint32_t *)(BCM2836_MAILBOX2_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
140 *((uint32_t *)(BCM2836_MAILBOX3_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
142 // enable FIQ mailbox interupt
143 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * (tmp
& 0x3)))) = 0x10;
146 static unsigned int bcm2807_get_time(void)
148 return *((volatile unsigned int *)(SYSTIMER_CLO
));
151 static void bcm2807_irq_init(void)
154 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
156 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
157 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
158 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
161 static void bcm2807_send_ipi(uint32_t msg
, uint32_t cpumask
)
164 for (i
= 0; i
< 4; i
++)
166 if (cpumask
& (1 << i
))
168 *((uint32_t *)(BCM2836_MAILBOX0_SET0
+ (0x10 * i
))) = msg
;
173 static void bcm2807_irq_enable(int irq
)
175 int bank
= IRQ_BANK(irq
);
178 reg
= (unsigned int)IRQBANK_POINTER(bank
);
180 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
182 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
184 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
187 static void bcm2807_irq_disable(int irq
)
189 int bank
= IRQ_BANK(irq
);
192 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
194 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
196 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
198 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
201 static void bcm2807_irq_process()
203 unsigned int pendingarm
, pending0
, pending1
, irq
;
207 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
208 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
209 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
211 if (!(pendingarm
|| pending0
|| pending1
))
214 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm
));
215 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0
));
216 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1
));
218 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
220 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
222 if (pendingarm
& (1 << (irq
- (2 << 5))))
224 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
225 krnRunIRQHandlers(KernelBase
, irq
);
232 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
234 if (pending0
& (1 << (irq
- (0 << 5))))
236 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
237 krnRunIRQHandlers(KernelBase
, irq
);
244 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
246 if (pending1
& (1 << (irq
- (1 << 5))))
248 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
249 krnRunIRQHandlers(KernelBase
, irq
);
256 static void bcm2807_fiq_process()
258 uint32_t tmp
, fiq
, fiq_data
;
261 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
263 DFIQ(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
265 fiq
= *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * (tmp
& 0x3))));
267 DFIQ(bug("[KRN:BCM2708] %s: Core #%d FIQ %x\n", __PRETTY_FUNCTION__
, (tmp
& 0x3), fiq
));
271 for (i
=0; i
< 4; i
++)
273 if (fiq
& (0x10 << i
))
275 fiq_data
= *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4*i
+ (16 * (tmp
& 0x3))));
276 DFIQ(bug("[KRN:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__
, i
, fiq_data
));
277 #if defined(__AROSEXEC_SMP__)
278 handle_ipi(fiq_data
, NULL
);
280 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4*i
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
286 static void bcm2708_toggle_led(int LED
, int state
)
288 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
291 APTR gpiofunc
= GPCLR1
;
293 if (LED
== ARM_LED_ACTIVITY
)
296 if (state
== ARM_LED_ON
)
299 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
303 // RasPi 1 only allows us to toggle the activity LED
305 *(volatile unsigned int *)GPCLR0
= (1 << 16);
307 *(volatile unsigned int *)GPSET0
= (1 << 16);
311 /* Use system timer 3 for our scheduling heartbeat */
312 #define VBLANK_TIMER 3
313 #define VBLANK_INTERVAL (1000000 / 50)
315 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
319 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
321 /* Aknowledge our timer interrupt */
322 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
324 /* Signal the Exec VBlankServer */
325 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
326 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
329 /* Refresh our timer interrupt */
330 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
331 stc
+= VBLANK_INTERVAL
;
332 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
334 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
337 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
339 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
340 struct IntrNode
*GPUTimerHandle
;
343 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
345 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
347 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
348 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
350 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
351 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
352 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
353 GPUTimerHandle
->in_type
= it_interrupt
;
354 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
356 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
358 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
360 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
361 stc
+= VBLANK_INTERVAL
;
362 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
363 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
365 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
368 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
370 return GPUTimerHandle
;
373 static inline void bcm2708_ser_waitout()
377 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
381 static void bcm2708_ser_putc(uint8_t chr
)
383 bcm2708_ser_waitout();
387 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
388 bcm2708_ser_waitout();
390 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
393 static int bcm2708_ser_getc(void)
395 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
396 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
401 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
403 void *bootPutC
= NULL
;
405 while(msg
->ti_Tag
!= TAG_DONE
)
410 bootPutC
= (void *)msg
->ti_Data
;
416 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
419 if (krnARMImpl
->ARMI_Family
== 7)
421 /* bcm2836 uses armv7 */
422 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
423 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_core
;
424 krnARMImpl
->ARMI_FIQProcess
= &bcm2807_fiq_process
;
425 krnARMImpl
->ARMI_SendIPI
= &bcm2807_send_ipi
;
428 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
430 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
431 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
432 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
434 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
435 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
436 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
437 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
439 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
440 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
441 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
442 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
444 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
449 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);