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);
59 struct cpu_ipidata
*bcm2708_cpuipid
[4] = { 0, 0, 0, 0};
62 static void bcm2708_init(APTR _kernelBase
, APTR _sysBase
)
64 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
65 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
67 KrnSpinInit(&startup_lock
);
69 D(bug("[KRN:BCM2708] %s()\n", __PRETTY_FUNCTION__
));
71 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
73 void *trampoline_src
= mpcore_trampoline
;
74 void *trampoline_dst
= (void *)BOOTMEMADDR(bm_mctrampoline
);
75 uint32_t trampoline_length
= (uintptr_t)&mpcore_end
- (uintptr_t)mpcore_trampoline
;
76 uint32_t trampoline_data_offset
= (uintptr_t)&mpcore_pde
- (uintptr_t)mpcore_trampoline
;
79 uint32_t *core_fiq_stack
;
83 bug("[KRN:BCM2708] Initialising Multicore System\n");
84 D(bug("[KRN:BCM2708] %s: Copy SMP trampoline from %p to %p (%d bytes)\n", __PRETTY_FUNCTION__
, trampoline_src
, trampoline_dst
, trampoline_length
));
86 bcopy(trampoline_src
, trampoline_dst
, trampoline_length
);
88 D(bug("[KRN:BCM2708] %s: Patching data for trampoline at offset %d\n", __PRETTY_FUNCTION__
, trampoline_data_offset
));
90 asm volatile ("mrc p15, 0, %0, c2, c0, 0":"=r"(tmp
));
91 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[0] = tmp
; // pde
92 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[1] = (uint32_t)cpu_Register
;
94 for (core
= 1; core
< 4; core
++)
96 core_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
97 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&core_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
99 core_fiq_stack
= (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
100 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4] = (uint32_t)&core_fiq_stack
[1024-sizeof(IPTR
)];
102 __tls
= (tls_t
*)AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
103 __tls
->SysBase
= _sysBase
;
104 __tls
->KernelBase
= _kernelBase
;
105 __tls
->ThisTask
= NULL
;
106 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
107 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = (uint32_t)__tls
;
109 D(bug("[KRN:BCM2708] %s: Attempting to wake core #%d\n", __PRETTY_FUNCTION__
, core
));
110 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]));
111 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]));
112 D(bug("[KRN:BCM2708] %s: core #%d tls @ 0x%p\n", __PRETTY_FUNCTION__
, core
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
114 arm_flush_cache((uint32_t)trampoline_dst
, 512);
116 /* Lock the startup spinlock */
117 KrnSpinLock(&startup_lock
, SPINLOCK_MODE_WRITE
);
119 /* Wake up the core */
120 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * core
))) = (uint32_t)trampoline_dst
;
123 * Try to obtain spinlock again.
124 * This should put this core to sleep since the locked was already obtained. Once the core startup
125 * is ready, it will call KrnSpinUnLock too
127 KrnSpinLock(&startup_lock
, SPINLOCK_MODE_WRITE
);
128 KrnSpinUnLock(&startup_lock
);
133 static void bcm2708_init_core(APTR _kernelBase
, APTR _sysBase
)
135 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
136 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
137 struct cpu_ipidata
*core_ipidata
;
140 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
142 D(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
144 /* Clear all pending FIQ sources on mailboxes */
145 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
146 *((uint32_t *)(BCM2836_MAILBOX1_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
147 *((uint32_t *)(BCM2836_MAILBOX2_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
148 *((uint32_t *)(BCM2836_MAILBOX3_CLR0
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
150 #if defined(__AROSEXEC_SMP__)
151 if ((core_ipidata
= (struct cpu_ipidata
*)AllocMem(sizeof(struct cpu_ipidata
), MEMF_CLEAR
)) != NULL
)
153 bcm2708_cpuipid
[(tmp
& 0x3)] = core_ipidata
;
155 // enable FIQ mailbox interupt
156 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * (tmp
& 0x3)))) = 0x10;
161 static unsigned int bcm2807_get_time(void)
163 return *((volatile unsigned int *)(SYSTIMER_CLO
));
166 static void bcm2807_irq_init(void)
169 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
171 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
172 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
173 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
176 static void bcm2807_send_ipi(uint32_t ipi
, uint32_t ipi_data
, uint32_t cpumask
)
179 for (i
= 0; i
< 4; i
++)
181 #if defined(__AROSEXEC_SMP__)
182 if ((cpumask
& (1 << i
)) && bcm2708_cpuipid
[i
])
184 /* TODO: check which mailbox is available and use it */
185 bcm2708_cpuipid
[i
]->ipi_data
[0] = ipi_data
;
186 *((uint32_t *)(BCM2836_MAILBOX0_SET0
+ (0x10 * i
))) = ipi
;
192 static void bcm2807_irq_enable(int irq
)
194 int bank
= IRQ_BANK(irq
);
197 reg
= (unsigned int)IRQBANK_POINTER(bank
);
199 DIRQ(bug("[KRN:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
201 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
203 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
206 static void bcm2807_irq_disable(int irq
)
208 int bank
= IRQ_BANK(irq
);
211 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
213 DIRQ(bug("[KRN:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
215 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
217 DIRQ(bug("[KRN:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
220 static void bcm2807_irq_process()
222 unsigned int pendingarm
, pending0
, pending1
, irq
;
226 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
227 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
228 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
230 if (!(pendingarm
|| pending0
|| pending1
))
233 DIRQ(bug("[KRN:BCM2708] PendingARM %08x\n", pendingarm
));
234 DIRQ(bug("[KRN:BCM2708] Pending0 %08x\n", pending0
));
235 DIRQ(bug("[KRN:BCM2708] Pending1 %08x\n", pending1
));
237 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
239 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
241 if (pendingarm
& (1 << (irq
- (2 << 5))))
243 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
244 krnRunIRQHandlers(KernelBase
, irq
);
251 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
253 if (pending0
& (1 << (irq
- (0 << 5))))
255 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
256 krnRunIRQHandlers(KernelBase
, irq
);
263 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
265 if (pending1
& (1 << (irq
- (1 << 5))))
267 DIRQ(bug("[KRN:BCM2708] Handling IRQ %d ..\n", irq
));
268 krnRunIRQHandlers(KernelBase
, irq
);
275 static void bcm2807_fiq_process()
277 uint32_t tmp
, fiq
, fiq_data
;
280 asm volatile (" mrc p15, 0, %0, c0, c0, 5 " : "=r" (tmp
));
282 DFIQ(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, (tmp
& 0x3)));
284 fiq
= *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * (tmp
& 0x3))));
286 DFIQ(bug("[KRN:BCM2708] %s: Core #%d FIQ %x\n", __PRETTY_FUNCTION__
, (tmp
& 0x3), fiq
));
290 for (i
=0; i
< 4; i
++)
292 if (fiq
& (0x10 << i
))
294 fiq_data
= *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4*i
+ (16 * (tmp
& 0x3))));
295 DFIQ(bug("[KRN:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__
, i
, fiq_data
));
296 #if defined(__AROSEXEC_SMP__)
297 if (bcm2708_cpuipid
[(tmp
& 0x3)])
298 handle_ipi(fiq_data
, bcm2708_cpuipid
[(tmp
& 0x3)]->ipi_data
[0]);
300 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4*i
+ (16 * (tmp
& 0x3)))) = 0xffffffff;
306 static void bcm2708_toggle_led(int LED
, int state
)
308 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
311 APTR gpiofunc
= GPCLR1
;
313 if (LED
== ARM_LED_ACTIVITY
)
316 if (state
== ARM_LED_ON
)
319 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
323 // RasPi 1 only allows us to toggle the activity LED
325 *(volatile unsigned int *)GPCLR0
= (1 << 16);
327 *(volatile unsigned int *)GPSET0
= (1 << 16);
331 /* Use system timer 3 for our scheduling heartbeat */
332 #define VBLANK_TIMER 3
333 #define VBLANK_INTERVAL (1000000 / 50)
335 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
339 DTIMER(bug("[KRN:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
341 /* Aknowledge our timer interrupt */
342 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
344 /* Signal the Exec VBlankServer */
345 if (SysBase
&& (SysBase
->IDNestCnt
< 0)) {
346 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
349 /* Refresh our timer interrupt */
350 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
351 stc
+= VBLANK_INTERVAL
;
352 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
354 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
357 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
359 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
360 struct IntrNode
*GPUTimerHandle
;
363 DTIMER(bug("[KRN:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
365 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
367 DTIMER(bug("[KRN:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
368 DTIMER(bug("[KRN:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
370 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
371 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
372 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
373 GPUTimerHandle
->in_type
= it_interrupt
;
374 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
376 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
378 DTIMER(bug("[KRN:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
380 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
381 stc
+= VBLANK_INTERVAL
;
382 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
383 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
385 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
388 DTIMER(bug("[KRN:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
390 return GPUTimerHandle
;
393 static inline void bcm2708_ser_waitout()
397 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
401 static void bcm2708_ser_putc(uint8_t chr
)
403 bcm2708_ser_waitout();
407 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
408 bcm2708_ser_waitout();
410 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
413 static int bcm2708_ser_getc(void)
415 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
416 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
421 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
423 void *bootPutC
= NULL
;
425 while(msg
->ti_Tag
!= TAG_DONE
)
430 bootPutC
= (void *)msg
->ti_Data
;
436 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
439 if (krnARMImpl
->ARMI_Family
== 7)
441 /* bcm2836 uses armv7 */
442 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
443 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_core
;
444 krnARMImpl
->ARMI_FIQProcess
= &bcm2807_fiq_process
;
445 krnARMImpl
->ARMI_SendIPI
= &bcm2807_send_ipi
;
448 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
450 krnARMImpl
->ARMI_GetTime
= &bcm2807_get_time
;
451 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
452 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
454 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
455 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
456 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
457 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
459 krnARMImpl
->ARMI_IRQInit
= &bcm2807_irq_init
;
460 krnARMImpl
->ARMI_IRQEnable
= &bcm2807_irq_enable
;
461 krnARMImpl
->ARMI_IRQDisable
= &bcm2807_irq_disable
;
462 krnARMImpl
->ARMI_IRQProcess
= &bcm2807_irq_process
;
464 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
469 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);