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("[Kernel: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 *cpu_fiq_stack
;
83 bug("[Kernel:BCM2708] Initialising Multicore System\n");
84 D(bug("[Kernel: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("[Kernel: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 (cpu
= 1; cpu
< 4; cpu
++)
96 cpu_stack
= (uint32_t *)AllocMem(AROS_STACKSIZE
*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
97 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2] = (uint32_t)&cpu_stack
[AROS_STACKSIZE
-sizeof(IPTR
)];
99 cpu_fiq_stack
= (uint32_t *)AllocMem(1024*sizeof(uint32_t), MEMF_CLEAR
); /* MEMF_PRIVATE */
100 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4] = (uint32_t)&cpu_fiq_stack
[1024-sizeof(IPTR
)];
103 #if defined(__AROSEXEC_SMP)
104 __tls
= (tls_t
*)AllocMem(sizeof(tls_t
) + sizeof(struct cpu_ipidata
), MEMF_CLEAR
); /* MEMF_PRIVATE */
106 __tls
= (tls_t
*)AllocMem(sizeof(tls_t
), MEMF_CLEAR
); /* MEMF_PRIVATE */
108 __tls
->SysBase
= _sysBase
;
109 __tls
->KernelBase
= _kernelBase
;
110 __tls
->ThisTask
= NULL
;
111 arm_flush_cache(((uint32_t)__tls
) & ~63, 512);
112 ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3] = (uint32_t)__tls
;
114 D(bug("[Kernel:BCM2708] %s: Attempting to wake CPU #%02d\n", __PRETTY_FUNCTION__
, cpu
));
115 D(bug("[Kernel:BCM2708] %s: CPU #%02d Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, cpu
, cpu_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[2]));
116 D(bug("[Kernel:BCM2708] %s: CPU #%02d FIQ Stack @ 0x%p (sp=0x%p)\n", __PRETTY_FUNCTION__
, cpu
, cpu_fiq_stack
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[4]));
117 D(bug("[Kernel:BCM2708] %s: CPU #%02d TLS @ 0x%p\n", __PRETTY_FUNCTION__
, cpu
, ((uint32_t *)(trampoline_dst
+ trampoline_data_offset
))[3]));
119 arm_flush_cache((uint32_t)trampoline_dst
, 512);
121 /* Lock the startup spinlock */
122 KrnSpinLock(&startup_lock
, NULL
, SPINLOCK_MODE_WRITE
);
124 /* Wake up the cpu */
125 *((uint32_t *)(BCM2836_MAILBOX3_SET0
+ (0x10 * cpu
))) = (uint32_t)trampoline_dst
;
128 * Try to obtain spinlock again.
129 * This should put this cpu to sleep since the locked was already obtained. Once the cpu startup
130 * is ready, it will call KrnSpinUnLock too
132 KrnSpinLock(&startup_lock
, NULL
, SPINLOCK_MODE_WRITE
);
133 KrnSpinUnLock(&startup_lock
);
138 static void bcm2708_init_cpu(APTR _kernelBase
, APTR _sysBase
)
140 struct ExecBase
*SysBase
= (struct ExecBase
*)_sysBase
;
141 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
142 #if defined(__AROSEXEC_SMP__)
143 tls_t
*__tls
= TLS_PTR_GET();
145 int cpunum
= GetCPUNumber();
147 D(bug("[Kernel:BCM2708] %s(#%02d)\n", __PRETTY_FUNCTION__
, cpunum
));
149 /* Clear all pending FIQ sources on mailboxes */
150 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ (16 * cpunum
))) = 0xffffffff;
151 *((uint32_t *)(BCM2836_MAILBOX1_CLR0
+ (16 * cpunum
))) = 0xffffffff;
152 *((uint32_t *)(BCM2836_MAILBOX2_CLR0
+ (16 * cpunum
))) = 0xffffffff;
153 *((uint32_t *)(BCM2836_MAILBOX3_CLR0
+ (16 * cpunum
))) = 0xffffffff;
155 #if defined(__AROSEXEC_SMP__)
156 bcm2708_cpuipid
[cpunum
] = (unsigned int)__tls
+ sizeof(tls_t
);
157 D(bug("[Kernel:BCM2708] %s: CPU #%02d IPI data @ 0x%p\n", __PRETTY_FUNCTION__
, cpunum
, bcm2708_cpuipid
[cpunum
]));
159 // enable FIQ mailbox interupt
160 *((uint32_t *)(BCM2836_MAILBOX_INT_CTRL0
+ (0x4 * cpunum
))) = 0x10;
164 static unsigned int bcm2708_get_time(void)
166 return *((volatile unsigned int *)(SYSTIMER_CLO
));
169 static void bcm2708_irq_init(void)
172 // *(volatile unsigned int *)ARMFIQ_CTRL = 0;
174 *(volatile unsigned int *)ARMIRQ_DIBL
= ~0;
175 *(volatile unsigned int *)GPUIRQ_DIBL0
= ~0;
176 *(volatile unsigned int *)GPUIRQ_DIBL1
= ~0;
179 static void bcm2708_send_ipi(uint32_t ipi
, uint32_t ipi_data
, uint32_t cpumask
)
183 for (cpu
= 0; cpu
< 4; cpu
++)
185 #if defined(__AROSEXEC_SMP__)
186 if ((cpumask
& (1 << cpu
)) && bcm2708_cpuipid
[cpu
])
188 /* TODO: check which mailbox is available and use it */
189 bcm2708_cpuipid
[cpu
]->ipi_data
[mbno
] = ipi_data
;
190 *((uint32_t *)(BCM2836_MAILBOX0_SET0
+ 4 * mbno
+ (0x10 * cpu
))) = ipi
;
196 static void bcm2708_irq_enable(int irq
)
198 int bank
= IRQ_BANK(irq
);
201 reg
= (unsigned int)IRQBANK_POINTER(bank
);
203 DIRQ(bug("[Kernel:BCM2708] Enabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
205 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
207 DIRQ(bug("[Kernel:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
210 static void bcm2708_irq_disable(int irq
)
212 int bank
= IRQ_BANK(irq
);
215 reg
= (unsigned int)IRQBANK_POINTER(bank
) + 0x0c;
217 DIRQ(bug("[Kernel:BCM2708] Disabling irq %d [bank %d, reg 0x%p]\n", irq
, bank
, reg
));
219 *((volatile unsigned int *)reg
) = IRQ_MASK(irq
);
221 DIRQ(bug("[Kernel:BCM2708] irqmask=%08x\n", *((volatile unsigned int *)reg
)));
224 static void bcm2708_irq_process()
226 unsigned int pendingarm
, pending0
, pending1
, irq
;
230 pendingarm
= *((volatile unsigned int *)(ARMIRQ_PEND
));
231 pending0
= *((volatile unsigned int *)(GPUIRQ_PEND0
));
232 pending1
= *((volatile unsigned int *)(GPUIRQ_PEND1
));
234 if (!(pendingarm
|| pending0
|| pending1
))
237 DIRQ(bug("[Kernel:BCM2708] PendingARM %08x\n", pendingarm
));
238 DIRQ(bug("[Kernel:BCM2708] Pending0 %08x\n", pending0
));
239 DIRQ(bug("[Kernel:BCM2708] Pending1 %08x\n", pending1
));
241 if (pendingarm
& ~(IRQ_BANK1
| IRQ_BANK2
))
243 for (irq
= (2 << 5); irq
< ((2 << 5) + 8); irq
++)
245 if (pendingarm
& (1 << (irq
- (2 << 5))))
247 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq
));
248 krnRunIRQHandlers(KernelBase
, irq
);
255 for (irq
= (0 << 5); irq
< ((0 << 5) + 32); irq
++)
257 if (pending0
& (1 << (irq
- (0 << 5))))
259 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq
));
260 krnRunIRQHandlers(KernelBase
, irq
);
267 for (irq
= (1 << 5); irq
< ((1 << 5) + 32); irq
++)
269 if (pending1
& (1 << (irq
- (1 << 5))))
271 DIRQ(bug("[Kernel:BCM2708] Handling IRQ %d ..\n", irq
));
272 krnRunIRQHandlers(KernelBase
, irq
);
279 static void bcm2708_fiq_process()
281 int cpunum
= GetCPUNumber();
282 uint32_t fiq
, fiq_data
;
285 DFIQ(bug("[Kernel:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, cpunum
));
287 fiq
= *((uint32_t *)(BCM2836_FIQ_PEND0
+ (0x4 * cpunum
)));
289 DFIQ(bug("[Kernel:BCM2708] %s: CPU #%02d FIQ %x\n", __PRETTY_FUNCTION__
, cpunum
, fiq
));
293 for (mbno
=0; mbno
< 4; mbno
++)
295 if (fiq
& (0x10 << mbno
))
297 fiq_data
= *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4 * mbno
+ (16 * cpunum
)));
298 DFIQ(bug("[Kernel:BCM2708] %s: Mailbox%d: FIQ Data %08x\n", __PRETTY_FUNCTION__
, mbno
, fiq_data
));
299 #if defined(__AROSEXEC_SMP__)
300 if (bcm2708_cpuipid
[cpunum
])
301 handle_ipi(fiq_data
, bcm2708_cpuipid
[cpunum
]->ipi_data
[0]);
303 *((uint32_t *)(BCM2836_MAILBOX0_CLR0
+ 4 * mbno
+ (16 * cpunum
))) = 0xffffffff;
309 static void bcm2708_toggle_led(int LED
, int state
)
311 if (__arm_arosintern
.ARMI_PeripheralBase
== (APTR
)BCM2836_PERIPHYSBASE
)
314 APTR gpiofunc
= GPCLR1
;
316 if (LED
== ARM_LED_ACTIVITY
)
319 if (state
== ARM_LED_ON
)
322 *(volatile unsigned int *)gpiofunc
= (1 << (pin
-32));
326 // RasPi 1 only allows us to toggle the activity LED
328 *(volatile unsigned int *)GPCLR0
= (1 << 16);
330 *(volatile unsigned int *)GPSET0
= (1 << 16);
334 /* Use system timer 3 for our scheduling heartbeat */
335 #define VBLANK_TIMER 3
336 #define VBLANK_INTERVAL (1000000 / 50)
338 static void bcm2708_gputimer_handler(unsigned int timerno
, void *unused1
)
342 DTIMER(bug("[Kernel:BCM2708] %s(%d)\n", __PRETTY_FUNCTION__
, timerno
));
344 /* Aknowledge our timer interrupt */
345 *((volatile unsigned int *)(SYSTIMER_CS
)) = 1 << timerno
;
347 /* Signal the Exec VBlankServer */
348 if (SysBase
&& (IDNESTCOUNT_GET
/*SysBase->IDNestCnt*/ < 0)) {
349 core_Cause(INTB_VERTB
, 1L << INTB_VERTB
);
352 /* Refresh our timer interrupt */
353 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
354 stc
+= VBLANK_INTERVAL
;
355 *((volatile unsigned int *)(SYSTIMER_C0
+ (timerno
* 4))) = stc
;
357 DTIMER(bug("[BCM2708] %s: Done..\n", __PRETTY_FUNCTION__
));
360 static APTR
bcm2708_init_gputimer(APTR _kernelBase
)
362 struct KernelBase
*KernelBase
= (struct KernelBase
*)_kernelBase
;
363 struct IntrNode
*GPUTimerHandle
;
366 DTIMER(bug("[Kernel:BCM2708] %s(%012p)\n", __PRETTY_FUNCTION__
, KernelBase
));
368 if ((GPUTimerHandle
= AllocMem(sizeof(struct IntrNode
), MEMF_PUBLIC
|MEMF_CLEAR
)) != NULL
)
370 DTIMER(bug("[Kernel:BCM2708] %s: IntrNode @ 0x%p:\n", __PRETTY_FUNCTION__
, GPUTimerHandle
));
371 DTIMER(bug("[Kernel:BCM2708] %s: Using GPUTimer %d for VBlank\n", __PRETTY_FUNCTION__
, VBLANK_TIMER
));
373 GPUTimerHandle
->in_Handler
= bcm2708_gputimer_handler
;
374 GPUTimerHandle
->in_HandlerData
= (void *)VBLANK_TIMER
;
375 GPUTimerHandle
->in_HandlerData2
= KernelBase
;
376 GPUTimerHandle
->in_type
= it_interrupt
;
377 GPUTimerHandle
->in_nr
= IRQ_TIMER0
+ VBLANK_TIMER
;
379 ADDHEAD(&KernelBase
->kb_Interrupts
[IRQ_TIMER0
+ VBLANK_TIMER
], &GPUTimerHandle
->in_Node
);
381 DTIMER(bug("[Kernel:BCM2708] %s: Enabling Hardware IRQ.. \n", __PRETTY_FUNCTION__
));
383 stc
= *((volatile unsigned int *)(SYSTIMER_CLO
));
384 stc
+= VBLANK_INTERVAL
;
385 *((volatile unsigned int *)(SYSTIMER_CS
)) = (1 << VBLANK_TIMER
);
386 *((volatile unsigned int *)(SYSTIMER_C0
+ (VBLANK_TIMER
* 4))) = stc
;
388 ictl_enable_irq(IRQ_TIMER0
+ VBLANK_TIMER
, KernelBase
);
391 DTIMER(bug("[Kernel:BCM2708] %s: Done.. \n", __PRETTY_FUNCTION__
));
393 return GPUTimerHandle
;
396 static inline void bcm2708_ser_waitout()
400 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_TXFF
) == 0) break;
404 static void bcm2708_ser_putc(uint8_t chr
)
406 bcm2708_ser_waitout();
410 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = '\r';
411 bcm2708_ser_waitout();
413 *(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
) = chr
;
416 static int bcm2708_ser_getc(void)
418 if ((*(volatile uint32_t *)(PL011_0_BASE
+ PL011_FR
) & PL011_FR_RXFE
) == 0)
419 return (int)*(volatile uint32_t *)(PL011_0_BASE
+ PL011_DR
);
424 static IPTR
bcm2708_probe(struct ARM_Implementation
*krnARMImpl
, struct TagItem
*msg
)
426 void *bootPutC
= NULL
;
428 while(msg
->ti_Tag
!= TAG_DONE
)
433 bootPutC
= (void *)msg
->ti_Data
;
439 if (krnARMImpl
->ARMI_Platform
!= 0xc42)
442 if (krnARMImpl
->ARMI_Family
== 7)
444 /* bcm2836 uses armv7 */
445 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2836_PERIPHYSBASE
;
446 krnARMImpl
->ARMI_InitCore
= &bcm2708_init_cpu
;
447 krnARMImpl
->ARMI_FIQProcess
= &bcm2708_fiq_process
;
448 krnARMImpl
->ARMI_SendIPI
= &bcm2708_send_ipi
;
451 krnARMImpl
->ARMI_PeripheralBase
= (APTR
)BCM2835_PERIPHYSBASE
;
453 krnARMImpl
->ARMI_GetTime
= &bcm2708_get_time
;
454 krnARMImpl
->ARMI_InitTimer
= &bcm2708_init_gputimer
;
455 krnARMImpl
->ARMI_LED_Toggle
= &bcm2708_toggle_led
;
457 krnARMImpl
->ARMI_SerPutChar
= &bcm2708_ser_putc
;
458 krnARMImpl
->ARMI_SerGetChar
= &bcm2708_ser_getc
;
459 if ((krnARMImpl
->ARMI_PutChar
= bootPutC
) != NULL
)
460 krnARMImpl
->ARMI_PutChar(0xFF); // Clear the display
462 krnARMImpl
->ARMI_IRQInit
= &bcm2708_irq_init
;
463 krnARMImpl
->ARMI_IRQEnable
= &bcm2708_irq_enable
;
464 krnARMImpl
->ARMI_IRQDisable
= &bcm2708_irq_disable
;
465 krnARMImpl
->ARMI_IRQProcess
= &bcm2708_irq_process
;
467 krnARMImpl
->ARMI_Init
= &bcm2708_init
;
472 ADD2SET(bcm2708_probe
, ARMPLATFORMS
, 0);